The form of IBinder objects passing between processes (i)

Source: Internet
Author: User
Tags stub

Proposition

When the service is often called remotely, we often use the Aidl to set an interface for service and client use, which is in fact the IPC communication using the binder mechanism. When the client bind service succeeds, the system am invokes the callback function onserviceconnected passes the service's ibinder to the client, and the client then calls the Aidl generated Asinterface () Method gets the invocation interface of the service, at which point a bind process is over, and 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, then the method calling server does not communicate with the IPC, but rather a 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, at which point the method calling the server communicates with IPC.

So what are the conditions for both of these situations to happen? Here we give the answer first, and then go 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 the 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 above.



Model


IBinder as a reference in the IPC communication, may confuse some people, IBinder is not the IPC communication medium? How can be passed as a reference, so that the understanding is a little narrow, take the native layer of the IPC, the client from the SM (Service Manager) to obtain the service side of the interface, This 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 to pass the client's ibinder to the service through the aforementioned interface.
The Java application layer of the service is more so, such as this proposition, the following we will analyze, 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 object is no exception, we look at the Parcel Class Writestrongbinder () (Because the Java layer and native layer method is the corresponding, Java layer is just native encapsulation, so we just need to see the native can) ,

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) Similarly, 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 (binder_type_handle type, now only changing their type, The IBinder receiver will be converted to an agent according to its type;
2. Because only a different process transfer will send IBinder to the Binder module, IBinder in the process of multi-level delivery, there are 2 possible processes a--> process b--> process A, process a--> process b--> process C and 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 these conclusions, we will be clear that the binder IPC communication process, the same process of IBinder local objects, assuming not pass through different processes, then IBinder will not be passed to the kernel binder module, so it has been ibinder local objects , assuming that passing through the process, even through the process of more than one pass, only the final goal is the component of the same process, then he gets the IBinder object 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, we'll 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 need to provide ibinder to AM);
2. Am starts process B and creates the service, and process B passes the service's IBinder object to Am,am and passes 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 above model, we can draw the conclusion of the most starting proposition in this paper.

Easy to understand the process of giving a service in bind


The form of IBinder objects passing 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.