Android Binder Learning One: Key concepts

Source: Internet
Author: User

To understand the Android code, first understand the binder mechanism. The binder mechanism is also an elusive piece of Android, documenting the important concepts and implementations of binder as a memo. Part of the content from the Internet, if there is infringement, please timely inform.

1.binder Communication Mechanism Overview

Binder communication is a kind of client-server communication structure,
1. On the surface, the client makes a direct call to the server by acquiring a proxy interface for the server;
2. In fact, the method defined in the proxy interface corresponds to the method defined in server one by one;
3.client calls a method in a proxy interface, the method of the proxy interface packages the parameters passed by the client into a parcel object;
4. The proxy interface sends the parcel to the binder driver in the kernel.
5.server reads the request data from the binder driver, and if it is sent to itself, unpack the parcel object, process and return the result;
6. The entire invocation process is a synchronous process, where the client blocks while the server is processing.

2. Why Use binder Communication

Linux has pipelines, System V Ipc,socket and other interprocess communication mechanisms, so why use a new binder communication mechanism in Android?

First, reliability. On mobile devices, Client-server-based communication is often used to achieve internal communication between the Internet and devices. Currently the Linux support IPC includes traditional pipelines, System V IPC, i.e. Message Queuing/shared memory/semaphore, and only the socket supports the Client-server communication mode. The Android system provides developers with a rich interface for interprocess communication, media playback, sensors, and wireless transmission. These features are managed by different servers. Development is only concerned with building the client of your application and the server's communication to use this service. There is no doubt that the complexity of the system is increased by erecting a set of protocols at the bottom to achieve client-server communication. It is difficult to guarantee the reliability of this complex environment on mobile phones with limited resources.

Second, transmission performance. Sockets are mainly used for inter-process communication across the network and for inter-process communication on the native, but with low transmission efficiency and high overhead. Message Queuing and pipelines use storage-forwarding, where the data is copied from the sender's buffer to a buffer in the kernel, and then copied from the kernel buffer to the receiver buffer, with a process of at least two copies. Although shared memory does not need to be copied, control is complex. Compare the number of copies of data in various IPC ways. Shared memory: 0 times. Binder:1 times. socket/Pipe/Message queue: 2 times.

Ipc Number of copies of data
Shared memory 0
Binder 1
socket/Pipeline/Message Queuing 2

Third, security. Android is an open platform, so it's important to ensure that your application is secure. Android assigns Uid/pid to each of the installed apps, where the UID of the process can be used to authenticate process identities. Traditional only by the user in the data package to fill in uid/pid, so unreliable, easy to use by malicious programs. And we asked the kernel to add a reliable UID.

For these reasons, Android needs to establish a new IPC mechanism to meet the system's requirements for communication, transmission performance and security, which is binder. Binder based on the Client-server communication mode, the transfer process only one copy, for sending the Uid/pid identity, both support real name binder and anonymous binder support, high security.

3.service Manager

As the name implies, Service Manager is a process that manages the service under Android, which is itself a service, There are some differences between the service and the service in Init.rc, the service in init.rc is a process, and the service here may not be a separate process. Each service must be registered with SM prior to use, and each client should first check with SM for the presence of the service before using the service, and return the service to the client if it exists. Handle Here is the key code for the main function in SM:

int main (int argc, char **argv) {    struct binder_state *bs;    BS = Binder_open (128*1024);    if (!bs) {        Aloge ("Failed to open binder driver\n");        return-1;    }    if (Binder_become_context_manager (BS)) {        Aloge ("Cannot become context Manager (%s) \ n", Strerror (errno));        return-1;    }    ......    The value of Svcmgr_handle is 0    svcmgr_handle = binder_service_manager;    Binder_loop (BS, Svcmgr_handler);    return 0;}

The main tasks in SM are as follows:

    • Opens the binder device and maps 128k of memory to the application space.
    • The value of the specified Svcmgr_handle is 0, and when the client communicates with SM, it is necessary to first create a proxy binder of handle 0.
    • Binder_become_context_manager informs Binder driver that SM is the context manager.
    • Binder_loop is a dead loop, the inside of the constant read binder whether there is data, if there is data, then parse, for Br_transaction, will call Svcmgr_handler to deal with.
    • SM maintains a svclist to store service information. A new service needs to register the add to this list with SM, and the client requests that the requested service be found in Svclist. A service consists of two important messages, handle and name. Both add and get match according to name.

The following image shows a brief description of the relationship between SM and binder driver:

From the above, the service will be used as a client to the SM registration before use; To use a service, you need to get the handle of the service to SM and then invoke the method provided by the service through handle.

4.ProcessState

Processstate is designed in a single-case pattern. Each process uses the binder mechanism to maintain a processstate instance that describes the binder state of the current process when it communicates with binder.
Processstate has the following 2 main functions:
1. Create a thread that is responsible for communicating with the binder module in the kernel, which is called the pool thread;
2. Create a Bpbinder object for the specified handle and manage all Bpbinder objects in the process.

4.1 Pool Thread

In the binder IPC, all processes start a thread that is responsible for direct communication with the BD (Binder driver), which is the non-stop read and write BD, the implementation body of this thread is a Ipcthreadstate object, and this type is described below.

Here's how the Pool thread starts:
Processstate::self ()->startthreadpool ();

4.2 Bpbinder Get

The main function of the bpbinder is to be responsible for the client sending the call request data to BD. It is the core object of client-side binder communication, and by calling the Transact function to send the requested data to the BD, its constructor is as follows:

Bpbinder (int32_t handle);

Through the Bpbinder constructor, Bpbinder will record the handle of the server in the current communication, and when there is data sent, it will notify the sending target of the BD data processstate to obtain the Bpbinder object by the following way:

Processstate::self ()->getcontextobject (handle);

In this process, processstate will maintain a bpbinder vector mhandletoobject, whenever processstate create a Bpbinder instance, go back to query Mhandletoobject, If the corresponding handle already has a binder pointer, it is no longer created, otherwise the binder is created and inserted into the mhandletoobject.
The Bpbinder instance created by Processstate, typically constructs a client-side proxy interface as a parameter, in the form of bpinterface, such as when communicating with SM, The client creates a proxy interface, Bpservicemanager.

5.IPCThreadState

Ipcthreadstate is also designed in a single-case pattern. Because each process maintains only one processstate instance, and Processstate only launches a pool thread, that is, each process only launches a pool thread, Therefore, each process requires only one ipcthreadstate.

The actual contents of the Pool thread are:

Ipcthreadstate::self ()->jointhreadpool ();

Processstate There are 2 parcel members, Min and Mout,pool thread will constantly query BD whether there is data readable, if it is read out and saved to Min, while constantly checking mout whether there is data to be sent to BD, if there is, The content is written to the BD, in a nutshell, the data read from the BD is saved to Min, and the data to be written to the BD is saved in the Mout.

The Bpbinder instance generated in Processstate writes data to MOUT by invoking the Transact function of ipcthreadstate, so that the sending process of the client side of the binder IPC process is clear.

Ipcthreadstate has two important functions, the Talkwithdriver function is responsible for reading and writing data from the BD, and the ExecuteCommand function is responsible for parsing and executing the data in min.

6. Main base class 6.1 base class IInterface

Provides an interface to the server side, and its subclasses declare all the methods that the service can implement;

6.2 Base class IBinder

Bbinder and Bpbinder are ibinder subclasses, so it can be seen that IBinder defines the Binder IPC communication protocol, Bbinder and Bpbinder in the framework of the Agreement and the operation of the collection, the establishment of a basic binder IPC mechanism.

6.3 Base class Bprefbase

Bprefbase is responsible for managing the Bpbinder instances that are currently available, after the client receives the required Bpbinder from the query Sm.

7. Two interface Classes 7.1 bpinterface

If the client wants to use the binder IPC to communicate, it will first query from the SM and get the server-side service Bpbinder, on the client side, this object is considered the server side of the remote agent. In order to enable the client to invoke a remote server,server like a local call, it is necessary to provide an interface to the client, on the basis of which the client creates a bpinterface, using this object, The client application can invoke the server-side method directly as if it were called locally. Instead of having to care about specific binder IPC implementations.

Here's a look at Bpinterface's prototype:

Class Bpinterface:public Bpinterface<iinterface>

Follow the inheritance and look up.

Template<typename interface>
Class Bpinterface:public INTERFACE, public bprefbase

Bpinterface respectively inherit from interface, and Bprefbase;

Bpinterface both implement local operations for each method in the service, and send the parameters of each method to BD in parcel form. such as Bpservicemanager's

Virtual status_t addService (const string16& name, Const sp<ibinder>& service) {    Parcel data, reply;    Data.writeinterfacetoken (Iservicemanager::getinterfacedescriptor ());    DATA.WRITESTRING16 (name);    Data.writestrongbinder (service);    status_t err = remote ()->transact (add_service_transaction, data, &reply);    return err = = No_error? Reply.readexceptioncode (): Err;}

At the same time, Bpbinder as its own member to manage, the bpbinder stored in Mremote, Bpservicemanager by calling Bprefbase remote () to obtain bpbinder pointers.

7.2 Bninterface

When defining the service on the Android native side, each service inherits from Bninterface (interface is the service name). The Bninterface type defines a ontransact function that is responsible for unpacking the received parcel and executing the client-side request method.

Follow the succession of bninterface and look up,
Class Bninterface:public Bninterface<iinterface>

IInterface is a common interface class for client-side proxy interface Bpinterface and server-side bninterface, and the purpose of this common interface class is to ensure consistency of service method at both ends of C-s.

Look up again.
Class Bninterface:public INTERFACE, public bbinder

At the same time we found the Bbinder type, what is this type for? Since each service can be regarded as a binder, the operation and state maintenance of the true server-side binder is implemented by inheriting from Bbinder. Visible Bbinder is the essence of service as binder.

So what is the difference between Bbinder and Bpbinder?

In fact, the difference is very simple, Bpbinder is the client side created for message sending agent, and Bbinder is the server side to receive the message channel. Viewing the respective code reveals that although both types have transact methods, the Bpbinder Transact method is to send a message to the Ipcthreadstate instance informing them that a message is sent to the BD While Bbinder is the Bnservice function that passes the Ipcthreadstate instance to its subclass Ontransact by Bbinder's Transact method when it receives the BD message, the server-side operation is performed.

8.Parcel

Parcel is the most basic communication unit in the binder IPC, which stores parameters for function calls between c-s. But parcel can only store basic data types, and if they are complex data types, they need to be split into basic data types for storage when stored.

Simple parcel Read and write no longer introduced, the following emphasis on 2 functions.

8.1 Writestrongbinder

This happens when a service call Add_service adds itself to the SM, as follows (IServiceManager.cpp):

Virtual status_t addService (const string16& name, const sp<ibinder>& service,            bool allowisolated)    {        Parcel data, reply;        Data.writeinterfacetoken (Iservicemanager::getinterfacedescriptor ());        DATA.WRITESTRING16 (name);        Data.writestrongbinder (service);        Data.writeint32 (allowisolated 1:0);        status_t err = remote ()->transact (add_service_transaction, data, &reply);        return err = = No_error? Reply.readexceptioncode (): Err;    }

where Writestrongbinder (Parcel.cpp) is as follows:

status_t Parcel::writestrongbinder (const sp<ibinder>& val) {    return Flatten_binder (processstate:: Self (), Val, this);}

Then look at Flatten_binder:

status_t flatten_binder (const sp<processstate>&/*proc*/, const sp<ibinder>& Binder, Parcel* out) {    Flat_binder_object obj; Obj.flags = 0x7f |    Flat_binder_flag_accepts_fds;        if (binder! = NULL) {IBinder *local = Binder->localbinder ();            if (!local) {Bpbinder *proxy = Binder->remotebinder ();            if (proxy = = null) {Aloge ("null proxy"); } Const int32_t handle = proxy?            Proxy->handle (): 0;            Obj.type = Binder_type_handle; Obj.binder = 0;            /* Don ' t pass uninitialized stack data to a remote process */obj.handle = handle;        Obj.cookie = 0;            } else {obj.type = Binder_type_binder;            Obj.binder = reinterpret_cast<uintptr_t> (Local->getweakrefs ());        Obj.cookie = reinterpret_cast<uintptr_t> (local);        }} else {obj.type = Binder_type_binder;        Obj.binder = 0; Obj.cookie =0; } return Finish_flatten_binder (binder, obj, out);}

The AddService parameter is a bninterface type pointer, and Bninterface inherits from Bbinder:

bbinder* Bbinder::localbinder ()    {        return this;    }

So the binder type written to parcel is Binder_type_binder, and in SM, when the binder type of the service is not binder_type_handle, SM will not add this service to the Svclist, However, it is clear that each service is added successfully, AddService the binder type received by BINDER_TYPE_BINDER,SM at the beginning of the transfer is Binder_type_handle, So what happened in the process? The problem is this, in Binder driver (BINDER.C) by the following code:

static void Binder_transaction (struct binder_proc *proc,                   struct binder_thread *thread,                   struct binder_ Transaction_data *tr, int reply) {..... ..... ..... ..... ..................    if (Fp->type = = binder_type_binder)        fp->type = Binder_type_handle;    else        fp->type = binder_type_weak_handle;    Fp->handle = Ref->desc, ..... ............................

As we have known before, SM just saved the handle and name of the server binder, then how to get the service binder when the client needs to communicate with a service? Keep looking at Readstrongbinder.

8.2 Readstrongbinder

When the server side receives a call request from the client, if a binder needs to be returned, the binder can be sent to the BD, and when the Ipcthreadstate instance receives the returned parcel, The client can use this function to read the binder returned by the server.

Sp<ibinder> Parcel::readstrongbinder () const{    sp<ibinder> val;    Unflatten_binder (Processstate::self (), *this, &val);    return Val;}

See Unflatten_binder again:

status_t unflatten_binder (const sp<processstate>& proc,    const parcel& in, sp<ibinder>* out) {    Const flat_binder_object* flat = In.readobject (false);    if (flat) {        switch (flat->type) {case            binder_type_binder:                *out = reinterpret_cast<ibinder*> ( Flat->cookie);                Return Finish_unflatten_binder (NULL, *flat, in);            Case Binder_type_handle:                *out = Proc->getstrongproxyforhandle (flat->handle);                Return Finish_unflatten_binder (                    static_cast<bpbinder*> (Out->get ()), *flat, in);        }    }    return bad_type;}

It is found that if the binder type returned by the server is Binder_type_binder, which is to return a binder reference, the binder is obtained directly; if the binder type returned by the server is Binder_type_ Handle, that is, the server returns only the binder handle, then you need to recreate a bpbinder to return to the client.

As you can see from the code above, the binder for SM's saved service is just a handle, while the client builds the agent binder to communicate with the server by getting this handle to SM.

Incidentally, here is a special case where both sides of the binder communication can be either client or server. That is, the binder communication at this time is a half-duplex communication. In this case, the process of operation will be more complex than the case of a single job, but the basic principle is the same, interested in analyzing the examples of MediaPlayer and Mediaplayerservice.

These are some of the more important points involved in binder communication. The concrete implementation of binder requires a look at the code of Binder driver.

Android Binder Learning One: Key concepts

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.