Binder
Android Binder is a IPC mechanism that allows one process to invoke a function in another process and exchange data. It consists of three parts:
- Kernel Driver (
/dev/binder
) - Per-process userspace native code
- Per-process userspace Java code (e.g.,
android.os.Binder
)
From an App perspective, the client can either obtain the server binder handle
(IBinder
) in two ways:
- App -> System Service: ServiceManager. ServiceManager is available in both C++ and Java (while the C++ API is mainly intended for system components). It allows system_server to register system services, so other apps can get their handle.
- App -> App: ActivityManagerService. This is mainly used for the
bindService
API, which the AMS starts the target service specified by the given ComponentName and returns the handle (android.app.Service#onBind
) to the client.
The client can call a function using the android.os.Binder#transact()
method.
This specifies an action code, function arguments in Parcel, and optional return
Parcel. Parcel is Android's IPC serialization / deserialization mechanism.
The server is get called from android.os.Binder#onTransact()
, with the
provided data. The server can then do whatever they want and return a value.
Exceptions are also supported (but limited?).
The server can check the client's UID and PID to enforce permissions. A usual design pattern is to call PackageManagerService APIs to query if the given app UID has required permissions, and throw exceptions if not.
Peers can also link the binder to depth, such that when the other end get killed, the peer gets notified.
Writing binder function codes can be troublesome, so Android uses a AIDL, a DSL, to generate Java code for both the client side and server side. AIDL is heavily used in both AOSP (for defining system services) and user apps.
For a comprehensive understanding of Binder, take a look at gityuan.com.
Created: November 5, 2023