原文链接
Android binder(S)
A key part of Android is the Binder mechanism.
A bit of history/background
The Android binder mechanism was originally based on the OpenBinder project. As you can read
here Dianne Hackborn open sourced a project called
OpenBinder when she left PalmSource. If you read the OpenBinder documentation that can be found
here you will find
similarities with how binder works in Android. The current binder in Android is incompatible
with the original binder implementation still key information can be found at
Binder IPC mechanism .
The documentation on this page is an atempt at documenting how binder really works on Android
Warning
This page has not been reviewed and probably does contains many errors.
The kernel view
- Binder is a linux-kernel module that can send messages between userland processes(using IOCTL’s)
- A program using binder can send serialized messages. This serialized message can contain basic types but also include
local pointers. Pointers are accompanied with meta-data about it being a pointers. - A program using binder can read serialized messages.
- It is possible to request a more permanent “handle” object by acquiring this from binder (ref counting).
- The binder kernel module is able to translate local object pointers with handles and can keep track of those handles
- There is no real client or server at this stage the process calling is waiting in a IOCLT for results and the process
being called will wake-up from the IOCTL it was calling and it can also happen that a process will call itself.
(TODO is this really true? How about threading are message queued?) (
TODO the kernel module does contain threading information like MAX THREAD) how does this work?
Most programs do not directly use this operational mode but one of them talking at this level is the service manager.
frameworks/base/cmds/servicemanager/binder.c and frameworks/base/cmds/servicemanager/service_manager.c show the real
guts of the binder framework (including requesting a reference to a binder object)
The kernel drivers
- The kernel module accepts module options allowing it to be more verbose
the module parameter is called debug_mask and in an unsigned int. It’s value can be determined
by looking the binder source code: drivers/staging/android/binder.c
enum {
BINDER_DEBUG_USER_ERROR = 1U << 0,
BINDER_DEBUG_FAILED_TRANSACTION = 1U << 1,
BINDER_DEBUG_DEAD_TRANSACTION = 1U << 2,
BINDER_DEBUG_OPEN_CLOSE = 1U << 3,
BINDER_DEBUG_DEAD_BINDER = 1U << 4,
BINDER_DEBUG_DEATH_NOTIFICATION = 1U << 5,
BINDER_DEBUG_READ_WRITE = 1U << 6,
BINDER_DEBUG_USER_REFS = 1U << 7,
BINDER_DEBUG_THREADS = 1U << 8,
BINDER_DEBUG_TRANSACTION = 1U << 9,
BINDER_DEBUG_TRANSACTION_COMPLETE = 1U << 10,
BINDER_DEBUG_FREE_BUFFER = 1U << 11,
BINDER_DEBUG_INTERNAL_REFS = 1U << 12,
BINDER_DEBUG_BUFFER_ALLOC = 1U << 13,
BINDER_DEBUG_PRIORITY_CAP = 1U << 14,
BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 15,
};
contains proc debugging entries :
state
stats
transactions
transaction_log
failed_transaction_log
Sample “low level” scenario
- The Service opens the binder kernel module ( file open “/dev/binder” )
- It registers a thread pool for callbacks (ioctl bcSET_THREAD_ENTRY , *createNewThread, void * data)) (This is no
longer true for binder in android is it?) - The service performs a transaction using a special “known” remote reference “0” (handle) to the IServiceManager to map
itself with a name
- The client opens the binder kernel module ( file open “/dev/binder” )
- It is requests a handle to the service by calling a method from the the IServiceManager
- It is creates a transaction to the Service to call the service (ioctl BINDER_WRITE_READ)
- It response to the transaction
The CPP view
The cpp layer of binder eases development of binder code. It makes use of smart pointers and threading and in general
abstracts many of the details of obtaining handles to object.
Overview of the critical classes
There are a few critical classes the IInterface,IBinder,BBinder,BnInterface and BpInterface. The first letter(s) of
the class tell something about them. I as in Interface , B as in Base class, Bn as in Base native and Bp as in Base
proxy.
The IInterface class defines an object that can represent itself as a binder object. in a pure native implementation
there will be two implementation of this interface. One Proxy implementation that will represent the client end and one
native implementation that will convert binder calls to method calls on the “server”.
class IInterface extends RefBase
+ asBinder()
+ onAsBinder();
The IBinder class (frameworks/base/include/binder/IBinder.h) defines a class that is intended to be use to implement
binder services it declares the transac method to perform the binder transactions
and the attach/detach object to implement reference counting (of bound objects?) in userland.
class IBinder extends RefBase
+ transac(core , parcel in , parcel out, flags)
+ attachObject (id,object)
+ detachObject (id )
The BBinder class is the standard implementation of IBinder for a IInterface object using binder as communication
mechanism (IBinder and IInterface objects don’t actually need to use binder)
class BBinder implements IBinder
+ getInterfaceDescriptor() // string representing the name of the service interface
The remaining binder related classes in the framework are BnInterface and and BpInterface
The BnInterface is used to implement the native end of an IInterface
class BnInterface extends BBinder
+ queryLocalInterface(descriptor)
the BpInterface is used to implement Proxy classes
class BpInterface extends BpRefBase
+ onAsBinder();
+ remote() IBinder (declared in BpRefBase)
If you want more information on how to implement native binder services you are encouraged to read the code of
Android-HelloWorldService
binder threading
The basic programming model followed when developing a binder service is to spawn threads for incoming requests
and perform outgoing request directly.
Specifically, each process has a pool of “binder threads” which sit there waiting for incoming IPCs from other process.
When an IPC is dispatched to your process, one of these threads comes out of the pool to process it.
Backtrace on idling
__ioctl () at bionic/libc/arch-arm/syscalls/__ioctl.S:15
15 ldmfd sp!, {r4, r7}
(gdb) bt
#0 __ioctl () at bionic/libc/arch-arm/syscalls/__ioctl.S:15
#1 0xafd26a6c in ioctl (fd=<value optimized out>, request=16) at bionic/libc/bionic/ioctl.c:41
#2 0xa8215fa4 in android::IPCThreadState::talkWithDriver (this=0xa470, doReceive=true) at
frameworks/base/libs/binder/IPCThreadState.cpp:791
#3 0xa8216980 in android::IPCThreadState::joinThreadPool (this=0xa470, isMain=true) at
frameworks/base/libs/binder/IPCThreadState.cpp:446
#4 0x0000869e in main (argc=<value optimized out>, argv=<value optimized out>) at
mycomp/Android-HelloWorldService/helloworld/main_helloworldservice.cpp:27
Backtrace on a incomming request
#0 android::HelloWorldService::hellothere (this=0xa760, str=0xac20 "fun") at
mycomp/Android-HelloWorldService/libhelloworldservice/src/helloworldservice.cpp:3
#1 0x80003654 in android::HelloWorldService::onTransact (this=0xa760, code=<value optimized out>,
data=<value optimized out>, reply=0xbe9e5ae8, flags=17) at m
#2 0xa821359e in android::BBinder::transact (this=0xa764, code=1, data=..., reply=0xbe9e5ae8, flags=17) at
frameworks/base/libs/binder/Binder.cpp:107
#3 0xa82167bc in android::IPCThreadState::executeCommand (this=0xa470, cmd=<value optimized out>)
at frameworks/base/libs/binder/IPCThreadState.cpp:1012
#4 0xa821699e in android::IPCThreadState::joinThreadPool (this=0xa470, isMain=true) at
frameworks/base/libs/binder/IPCThreadState.cpp:457
#5 0x0000869e in main (argc=<value optimized out>, argv=<value optimized out>) at
mycomp/Android-HelloWorldService/helloworld/main_helloworldservice.cpp:27
The service manager service.
frameworks/base/cmds/servicemanager/service_manager.c
The Java layer on top
An Overview of the Java binder implementation
Android Service , Activities and Intent
Android Services Activities and Intent follow many of the principles found in the Native binder implementation
and they can make use of the available remoting facilities. It in important however to understand that there are big
differences.
First of all Service and Activities do not register themself to the IServiceManager the Only component that is actually
registered to the IServicemManager is the ActivityManager himelf. This Activity manager enhances the lower binder
implementation by providing process lifecycle.
IActivityManager → publishService usefull as counter part of bindService?
ActivityThread.java → really calles the onBind of a service
more stuff I found
-
Quoting the essential stuff ( from the open binder documentation)
The Binder communicates between processes using a small custom kernel module. This is used instead of
standard Linux IPC facilities so that we can efficiently model our IPC operations as “thread migration”.
That is, an IPC between processes looks as if the thread instigating the IPC has hopped over to the destination process
to execute the code there, and then hopped back with the result.
The Binder IPC mechanism itself, however, is not actually implemented using thread migration. Instead, the Binder’s
user-space code maintains a pool of available threads in each process, which are used to process incoming IPCs and
execute local events in that process. The kernel module emulates a thread migration model by propagating thread
priorities across processes as IPCs are dispatched and ensuring that, if an IPC recurses back into an originating
process, the IPC is handled by its originating thread.
In addition to IPC itself, the Binder’s kernel module is also responsible for tracking object references across
processes. This involves mapping from remote object references in one process to the real object in its host process,
and making sure that objects are not destroyed as long as other processes hold references on them.
Also read
- Android services in the android framework group and
- threading in the android-developers group.
- Hackborn about connecting to a binder c++ service
- An IBinder object represents a unique handle, which will be
maintained across IPCs. That is, if you have an IBinder that you send
from process A to process B, and at any point process B sends that
object back to process A, then process A will receive the exact same
IBinder object it originally sent. This is another part of
maintaining consistency with a local call, and can be very useful for
implementing things like tokens that are sent around, since there is
no way for a process to spoof them (and you can use
IBinder.linkToDeath() to be informed when the process hosting a token
as gone away).