理解Binder RPC机制

来源:互联网 发布:js轮播图代码 编辑:程序博客网 时间:2024/05/18 19:35

Understanding Android Internals – Binder RPC Mechanism

February 14,2014charlesz2014Leave a comment

Binder Services are ubiquitous on an Android device; In the framework stack,  probably every shared resources is managed by a service which is hosted by a certain dedicated host. Many developers like me may have the curiosity to demystify this device-wide IPC mechanism. In this post, we will discuss the binder infrastructure. In the next post, we will cover the binder programming interface.

·        Component View


The kernel binder driver is the system component in the IPC mechanism. Its function is to bridges a service and its clients anddispatch service requests from client to the service and reply back. It exists in the form ofa kernel characterdriver, thus supports file operations as follows 


staticconst struct file_operations binder_fops = {
.owner= THIS_MODULE,
.poll= binder_poll,
.unlocked_ioctl= binder_ioctl,
.mmap= binder_mmap,
.open= binder_open,
.flush= binder_flush,
.release= binder_release,
};

 

binder_open() allocates a distinct binder_proc structure to represents the process who operates on the driver. The service host process has at least one and the client process is allocated one when it opens the driver as well, note that they are not drawn in the diagram.

 

binder_ioctl () implements almost all the binder API. Below listed the IOCTL codes.

#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, int64_t)
#define BINDER_SET_MAX_THREADS _IOW('b', 5, size_t)
#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, int)
#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, int)
#define BINDER_THREAD_EXIT _IOW('b', 8, int)
#define BINDER_VERSION _IOWR('b', 9, struct binder_version)

 

Among them,  BINDER_WRITE_READ and BINDER_SET_CONTEXT_MGR bear the most significance.  The BINDER_SET_CONTEXT_MGR is used by the service manager to notify the binder driver its role.

In the first BINDER_WRITE_READ call from either service process or client process, a struct binder_node instance will be generated.

The binder API, along with the Binder protocol is defined in the binder.h under same the same folder in the kernel, and a copy is available in bionic/libc/kernel/common/linux/binder.h.

IPCThreadState is responsible for communicating with binder driver and ProcessState stores all the persistent parameters (not the data!) for communicating with binder driver.

Parcel is responsible for marshaling and unmarshalling arguments in a RPC call.

In parcel layer and below, other than no service objects nor client objects are recognizable, but localIBinder pointers  and handles to remote IBinders.

BBinder and BpBinder distinguishes reference to the service objects and client side proxy.

The BnInterface is a subclass of both BBinder and IInterface (to be discussed in part II).  A service will override theBBinder::onTransact() to handle service-specific command code.

A service host process may sustain multiple services. It runs one or two thread querying the binder driver to

Service Manager is a special service which provides directory service for registering and querying service interfaces. A service must be added to the service over the well-known IServiceManager interface before servicing clients. A client must query Service Manager by service name to obtain the service handle to submit service request.

However, how can a client know the service handle to the Service Manager. Android binder service solves this chick and egg problem with a trick.The service manager is assigned an alias handle null. When the driver a transaction request with null handle, it referencesto the IServiceManager node.

·        Messaging

Unlike direct local function call, Binder RPC is built upon reliable synchronous messaging with RPC call forming a transaction, and a client-server model is assumed.

The remote service host process opens the binder driver, waiting for transaction request. An IPCThreadState object handles the driver interaction transparently.

To establishes a connection with the service, the client opens the binder driver(again handled by an IPCThreadStateobject transparently) and queries ServiceManager to obtain a target service binder handle, wraps it in the BpBinder reference object subsequently as shown below.


Each RPC call is assigned an operation code distinct in the service interface, and all input argument are packed into the data parcel, if a reply is expected, the reference to the reply parcel is also provisioned. Given that, the RPC can be converted to a generic transact call on the BpBinder reference object as shown here.


The remote->transact() call definition is quoted here as well. The optional flags parameter is usually ignored.


IPCThreadState::transact is the final function which translates the RPC into a transaction message namely, struct binder_write_read struct instance, and passes it to binder through a ioctl call with request code BINDER_WRITE_READ (defined in binder.h). Due to the size of this post, I won’t elaborate the how driver routes the transaction message to the IBinder node and waits until the service has processed the call to return.

Within the service process, when the transaction message is retrieved, IPCThreadState extracts the data Parcel into the buffer Parcel and the reply parcel if it is there.




The highlighted line shows that the generic BBinder::transaction is invoked.   [注: 如本文之前所述,service端重载BBinder::onTransact()方法,根据不同的command code来执行不同的业务逻辑]


Pay attention to the highlighted onTransact() function,  this virtual function in BBinder will be overridden by upper BnInterface subclasses, in the command code handling in the service, it will call the corresponding service function to run the RPC call, any return parameters will be passed to the reply Parcel, then conveyed to the origin.

OK, we are finished with this part. It is complicated isn’it ? But far less convoluted than the actual source code! 




0 0
原创粉丝点击