AndroidNativeBinder

freakingtux edited this page Feb 23, 2012 · 7 revisions

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.

I = Interface defines an object that will be accessible over binder B = Base implementation Bn = Base native (local object implementation) Bp = 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 implementationAn 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

- 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).

HOWEVER, IInterface objects are not currently a unique identity — basically IMyInterface.asInterface() will always return a new instance of the interface (proxy) every time you call it. So when comparing objects, always be sure to call IInterface.asBinder() and compare the underlying IBinder objects.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.