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

Source: Internet
Author: User
Tags goto

advocate

When the service is often referred to as remote, the aidl is used to set an interface for service and client use, which in fact is 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 calling interface for the service. Now that 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 of all. Asinterface () will go to query whether the incoming IBinder object has localinterface, here 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. 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 when passing 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 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 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 article of this proposition, 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. The IBinder object is 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 the native encapsulation. So we just need to see the 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) {f        Lat_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;            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. Assume that the passed IBinder is a local IBinder object for the service. Then the IBinder object is of type Bbinder. Therefore, 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 side packages the method invocation parameters into parcel. will be sent to the kernel's binder module, 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 treatment. We can draw the following conclusions:
1. IBinder Local object reference (Binder_type_binder type) passed between different processes. In the kernel will be converted to proxy (Binder_type_handle type, now only to change its type, in the IBinder receiver will be based on its type into a proxy);
2. The ibinder is sent to the binder module because there is only a different inter-process pass. So ibinder in the process of multi-level transfer. There are 2 possible processes a--> process b--> process A, process a--> process b--> process C. The 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 identify the IBinder local objects between the same processes in the binder IPC communication process, assuming that they are not passed through different processes. Then IBinder will not be passed to the kernel's binder module. So it has been a local object for IBinder. Assumptions are passed between processes, even through the passing of more processes. The only final goal is the component of the same process, and 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 client and service are in the same process. Asinterface the input of the 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 needs 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, the beginning of this article will draw the proposition of such a conclusion.

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.