IBinder the form of passing an object between processes (i)

Source: Internet
Author: User
Tags goto stub

advocate

When the service is often referred to as remote, use the AIDL to set an interface for service and client use. This is actually the IPC communication using the binder mechanism.

After the client bind service succeeds. The system am invokes the callback function onserviceconnected passes the service's ibinder to the client, and the client obtains the service's calling interface by calling the Aidl generated Asinterface () method. At this point a bind process is over. We can invoke the service's method remotely on the client side. Like what

            public void onserviceconnected (ComponentName className,                    ibinder service) {                Msecondaryservice = ISecondary.Stub.asInterface (service);            }

Let's look at the definition of Aidl generated asinterface ()

public static com.example.android.apis.app.ISecondary asinterface (Android.os.IBinder obj) {if ((Obj==null)) {return null;} Android.os.IInterface iin = (android.os.IInterface) obj.querylocalinterface (descriptor); if ((Iin!=null) && ( Iin instanceof Com.example.android.apis.app.ISecondary)) {return (com.example.android.apis.app.ISecondary) iin);} return new Com.example.android.apis.app.ISecondary.Stub.Proxy (obj);


First, Asinterface () will go to query whether the incoming IBinder object has Localinterface, where the localinterface refers to the incoming IBinder is the service itself reference or proxy.
1. When the Asinterface input ibinder is a reference to the server (binder type). The reference is returned directly. The method that calls the server at this point does not communicate with the IPC. But the direct function call;
2. When the Asinterface input ibinder is the agent (Binderproxy type) of the server, it is necessary to create a proxy for the server and return it. The method that calls the server at this point is IPC communication.



So what are the conditions for both of these situations to happen? Here we give the answer first. Then go deep into the code to study 2 different situations.
1. When the client and service are in the same process, Asinterface's input ibinder is a reference to the server;
2. When client and service are in different processes. The Asinterface input IBinder is the proxy for the server.

Before studying the implementation code, let's start by introducing the state changes that IBinder uses to communicate between IPC processes, in fact this is the core of our article. Understanding this mechanism, we will be very easy to understand the principle of the proposition that we mentioned above.



Model


The IBinder is passed as a reference in the IPC communication. May confuse some people, IBinder is not the IPC communication medium? How can it be passed as a reference, which is a bit of a narrow understanding. Take the IPC for the native layer. The client obtains the interface of the service side from the SM (Service Manager), the interface is also the IBinder type at the same time, when the C/s ends require duplex communication, That is, the so-called service side need to call the client side of the method, it is necessary for the client through the aforementioned interface to the client side of the IBinder to pass to the service.


This is especially true for the service of the Java application layer. As this proposition of this article. We will analyze the following. First of all, to introduce the original rational knowledge.
Binder IPC Communication, Binder is the medium of communication, parcel is the content of communication. method during a remote invocation, its parameters are packaged in parcel form to be passed. IBinder objects are no exception, let's take a look at the Writestrongbinder () in the parcel class (because the Java layer and native layer methods are corresponding. The Java layer is just a native package, so we just need to see native.

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

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) {                 LOGE ("null proxy");            }            const INT32_T handle = Proxy? Proxy->handle (): 0;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBsp Obj.type = binder_type_handle;            Obj.handle = handle;            Obj.cookie = NULL;        } else {            Obj.type = binder_type_binder;            Obj.binder = local-> Getweakrefs ();            Obj.cookie = local;        }   } else {        Obj.type = binder_type_binder;        Obj.binder = null;         Obj.cookie = null;   }        return Finish_flatten_binder (Binder, obj, out);}

The above code is divided into the following 2 cases
1. Assuming that the IBinder is the local IBinder object of the service, then the IBinder object is of type Bbinder, so the above local is not NULL, so BINDER type is binder_type_binder.
2. If the IBinder object Proxy IBinder object is passed, then the binder TYPE is binder_type_handle.

After the client has packaged the method invocation parameters into parcel, it sends the binder module to the kernel, so we will analyze the processing of the binder module of the kernel below.

function Binder_transaction () in KERNEL/DRIVERS/STAGING/ANDROID/BINDER.C


Switch (fp->type) {        case binder_type_binder:       & Nbsp;case binder_type_weak_binder: {            struct binder_ref *ref;& nbsp;           struct binder_node *node = Binder_get_node (proc, Fp->binder );            if (node = = NULL) {        & nbsp;       node = Binder_new_node (proc, Fp->binder, Fp->cookie);                 if (node = = NULL) {                     return_error = br_failed_reply;                     goto err_binder_new_node_failed;                } &nbsP              node->min_priority = fp->flags & Flat_binder _flag_priority_mask;                node->accept_ FDS =!! (Fp->flags & Flat_binder_flag_accepts_fds);            }             if (Fp->cookie! = Node->cookie) {                 binder_user_error ("Binder:%d:%d sending u%p"     & nbsp;                "node%d, cookie mismatch%p! =%p\n",  & nbsp                  proc->pid, Thread->pid,                     fp->binder, node- >debug_id,                    fp->cookie, Node->cookie);                 goto err_binder_get_ref_for_node_failed;            }            ref = Binder_get_ref_for_node ( Target_proc, node);            if (ref = = NULL) {                 return_error = br_failed_reply;                goto err_binder_get_ref_for_node_failed;             }            if (fp->type = = Binder_ Type_binder)                 fp->type = binder_type_ handle;            else                fp->type = binder_type_weak_handle;             fp->handle = ref->desc;             binder_inc_ref (ref, Fp->type = = binder_type_handle,                        &thread->todo);             binder_debug (binder_debug_transaction,                      "        node%d u %p, ref%d desc%d\n ",                      node->debug_id, Node->ptr, ref->debug_id,                     ref->desc);        } break;        case binder_type_handle:        case Binder_type_weak_handle: {            struct binder_ref *ref = Binder_get _ref (proc, fp->handle);            if (ref = = NULL) {                binder_user_error ("Binder:%d:%d got"                      "Transaction with invalid"                       "Handle,%ld\n", proc-> pid,                    thread->pid, Fp->handle);                return_error = br_failed_ reply;                goto err_binder_get_ref_failed;            }             if (Ref->node->proc = = Target_proc) {                if (fp->type = = binder_type_handle)                     fp->type = binder_type_binder;                 else                    fp->type = binder_type_weak_binder;                fp->binder = ref->node->ptr;                fp->cookie = ref->node->cookie;                binder_inc_node (ref->node, Fp->type = = Binder_type_binder, 0, NULL);                binder_ Debug (binder_debug_transaction,                                  ref%d desc%d, node%d u%p\n ", & nbsp;                         ref->debug_id, Ref->desc, ref->node->debug_id,                         ref->node->ptr);             } else {               & Nbsp;struct binder_ref *new_ref;                new_ref = Binder_get_ref_for_node (Target_proc, Ref->node);                if (new_ref = = NULL) {           & nbsp;        return_error = br_failed_reply;                     goto err_binder_get_ref_for_node_failed;                }                fp->handle = new_ref->desc;                 binder_inc_ref (new_ref, Fp->type = = Binder_type_handle, NULL);       & nbsp;        binder_debug (binder_debug_transaction,                         "         ref%d desc%d, ref%d desc%d (node%d) \ n ",                         ref->debug _id, Ref->desc, new_ref->debug_id,                          New_ref->desc, ref->node->debug_id);             }        } break;

The above code is also divided into 2 different branches:
1. When the IBinder type is binder_type_binder. The binder TYPE value is binder_type_handle;
2. When the IBinder type is binder_type_handle, it is inferred that the IBinder entity is defined by the process (that is, the server that the IBinder represents is defined) and the target process (that is, the target process that IBinder is passed) is the same. Assuming the same, convert the IBinder TYPE to Binder_type_binder, making it a reference to the IBinder local object at the same time.
Through the above processing, we can draw the following conclusions:
1. IBinder local Object references (Binder_type_binder types) passed between different processes are converted to proxies in the kernel (the Binder_type_handle type, which is now merely changing its type. The IBinder receiver will be converted to an agent according to its type;
2. The ibinder is sent to the binder module because there is only a different inter-process pass. So ibinder in the process of multistage transfer, there are the following 2 possible processes a--> process b--> process A, process a--> process b--> process C; its corresponding ibinder type is binder_type_binder--> Binder_type_handle-->binder_type_binder,binder_type_binder-->binder_type_handle-->binder_type_handle.
Based on the above conclusions. We will be clear on the binder IPC communication process, the same process between the IBinder local objects. Assuming that it is not passed through a different process, the IBinder is not passed to the kernel's binder module, so it is always the local object of the IBinder, and is assumed to pass between processes, even through the passing of more processes. The only final goal is the component of the same process. Then the IBinder object he gets is the local object.







Apply model

Understanding the above model, we look back at the very beginning of the proposition the conclusion is very good understanding
1. When the client and service are in the same process, Asinterface's input ibinder is a reference to the server;
2. When the client and service are in different processes, the Asinterface input ibinder is the proxy for the server.

If a component (such as a acitivity) is in process A, it needs to bind a service, and the service is in process B. Let's take a brief look at the bind process.
1. Process A sends a BIND request to AM (process System_server) and sends the callback serviceconnection to AM (also an interface (iserviceconnection) passed to AM, since am and a are duplex communication, So a needs to provide ibinder to AM).
2. Am starts process B and creates a service. Process B passes the service's IBinder object to Am,am and passes it through iserviceconnection to process a.

So the delivery path for the service's IBinder object is: Process b--> process System_server (AM)---process A.


Applying the model surface, this article begins with a proposition that concludes.

Shows a simple way to understand bind a service this process


IBinder the form of passing an object between processes (i)

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.