Android Java binder Communication Mechanism

Source: Internet
Author: User

The binder system can run in the android native environment, but cannot run in the Java Virtual Machine. Therefore, to use binder communication in the Java environment, you need to call some JNI native functions (/android_runtime/android_util_binder.cpp)

 

Get iservicemanager

The servicemanager. Java file manages all services at the Java layer. To call any function in servicemanager. Java, you must first obtain the iservicemanager interface.

Private Static iservicemanager getiservicemanager () {<br/> If (sservicemanager! = NULL) {<br/> return sservicemanager; <br/>}</P> <p> // find the Service Manager <br/> sservicemanager = servicemanagernative. asinterface (binderinternal. getcontextobject (); <br/> return sservicemanager; <br/>}< br/>

Binderinternal. getcontextobject is defined as android_ OS _binderinternal_getcontextobject.
JNI native function. By calling the binder system of the C ++ layer, it can obtain an ibinder (actually it is directed to the bpservicemanager of the c ++ layer), and then call javaobjectforibinder, you can create a Java class to replace the ibinder object in C ++.

Static jobject initialize (jnienv * ENV, jobject clazz) <br/>{< br/> sp <ibinder> B = processstate: Self ()-> getcontextobject (null ); <br/> return javaobjectforibinder (ENV, B); <br/>}< br/>

Javaobjectforibinder first judges whether the object is a service provider or a service user. In getiservicemanager, this object is a service user, so it will replace the ibinder object in the C ++ environment with a new Java binderproxy object.

Jobject javaobjectforibinder (jnienv * ENV, const sp <ibinder> & Val) <br/>{< br/> Object = env-> newobject (gbinderproxyoffsets. mclass, gbinderproxyoffsets. mconstructor); <br/> If (object! = NULL) {<br/> logv ("objectforbinder % P: created new % P! /N ", Val. get (), object); <br/> // The proxy holds a reference to the native object. <br/> env-> setintfield (object, gbinderproxyoffsets. mobject, (INT) Val. get (); <br/> Val-> incstrong (object ); </P> <p> // The native object needs to hold a weak reference back to the <br/> // proxy, so we can retrieve the same proxy if it is still active. <br/> jobject refobject = env-> newglobalref (<br/> env-> getobjectfield (object, gbinderproxyoffsets. mself); <br/> Val-> attachobject (& gbinderproxyoffsets, refobject, <br/> jnienv_to_javavm (ENV), proxy_cleanup ); </P> <p> // note that a new object reference has been created. <br/> android_atomic_inc (& gnumproxyrefs); <br/> increfscreated (ENV); <br/>}</P> <p> return object; <br/>}< br/>

Now we have a Java binderproxy object. Servicemanagernative. asinterface will create a new servicemanagerproxy in the binderproxy object.

Static public iservicemanager asinterface (ibinder OBJ) <br/>{< br/> return New servicemanagerproxy (OBJ); <br/>}< br/>

Therefore, calling getiservicemanager will eventually return a servicemanagerproxy instance.

 

Create a service

When creating a Java service object (derived from binder), The init native function android_ OS _binder_init will be called (See Binder. Java ). Here it will create a new javabbinderhoder, which may not be used at present, but will be used later.

Static void android_ OS _binder_init (jnienv * ENV, jobject clazz) <br/>{< br/> javabbinderholder * jbh = new javabbinderholder (ENV, clazz ); <br/> If (jbh = NULL) {<br/> jnithrowexception (ENV, "Java/lang/outofmemoryerror", null); <br/> return; <br/>}< br/> logv ("Java binder % P: acquiring first ref on holder % P", clazz, jbh ); <br/> jbh-> incstrong (clazz); <br/> env-> setintfield (clazz, gbinderoffsets. mobject, (INT) jbh); <br/>}< br/>

 

Add service rpc call

Any Java-layer service should call the iservicemanager. addservice API function to register its own service. Iservicemanager. addservice is actually the servicemanagerproxy. addservice function.

Public void addservice (string name, ibinder Service) <br/> throws RemoteException {<br/> parcel DATA = parcel. obtain (); <br/> parcel reply = parcel. obtain (); <br/> data. writeinterfacetoken (iservicemanager. descriptor); <br/> data. writestring (name); <br/> data. writestrongbinder (service); <br/> mremote. transAct (add_service_transaction, Data, reply, 0); <br/> reply. recycle (); <br/> data. recycle (); <br/>}< br/>

When servicemanagerproxy. addservice is called, the service object in Java is written to the parcel container, and finally called the native function android_ OS _parcel_writerstrongbinder.

Static void android_ OS _parcel_writestrongbinder (jnienv * ENV, jobject clazz, jobject object) <br/>{< br/> parcel * parcel = parcelforjavaobject (ENV, clazz ); <br/> If (parcel! = NULL) {<br/> const status_t err = parcel-> writestrongbinder (ibinderforjavaobject (ENV, object); <br/> If (Err! = No_error) {<br/> jnithrowexception (ENV, "Java/lang/outofmemoryerror", null ); <br/>}< br/>

Android_ OS _parcel_writestrongbinder calls ibinderforjavaobject to generate a javabbinderholder object. Its function is equivalent to the ibinder object in the C ++ layer.

Sp <ibinder> ibinderforjavaobject (jnienv * ENV, jobject OBJ) <br/>{< br/> If (OBJ = NULL) return NULL; </P> <p> If (env-> isinstanceof (OBJ, gbinderoffsets. mclass) {<br/> javabbinderholder * jbh = (javabbinderholder *) <br/> env-> getintfield (OBJ, gbinderoffsets. mobject); <br/> return jbh! = NULL? Jbh-> get (ENV): NULL; <br/>}</P> <p> If (env-> isinstanceof (OBJ, gbinderproxyoffsets. mclass) {<br/> return (ibinder *) <br/> env-> getintfield (OBJ, gbinderproxyoffsets. mobject); <br/>}</P> <p> logw ("ibinderforjavaobject: % P is not a binder object", OBJ); <br/> return NULL; <br/>}< br/>

Javabbinderholder will eventually create a new javabbinder instance.

Sp <javabbinder> get (jnienv * env) <br/>{< br/> automutex _ L (mlock); <br/> sp <javabbinder> B = mbinder. promote (); <br/> If (B = NULL) {<br/> B = new javabbinder (ENV, mobject); <br/> mbinder = B; <br/> logv ("creating javabinder % P (Refs % P) for object % P, weakcount = % d/N", <br/> B. get (), B-> getweakrefs (), mobject, B-> getweakrefs ()-> getweakcount ()); <br/>}</P> <p> return B; <br/>}< br/>

Javabbinder object is derived from bbinder. After calling ibinderforjavaobject, Android has created a C ++ layer bbinder object in the service class of the Java layer.

 

Then, servicemanagerproxy calls the binderproxy JNI native function android_ OS _binderproxy_transact to implement PRC calls between Java and C ++. In this function, the ibinder object in C ++ (actually the bpservicemanager object mentioned earlier) corresponds to the binderproxy in Java, which was originally stored in javaobjectforibinder.

Static jboolean android_ OS _binderproxy_transact (jnienv * ENV, jobject OBJ, <br/> jint code, jobject dataobj, <br/> jobject replyobj, jint flags) <br/> {<br/> ibinder * target = (ibinder *) <br/> env-> getintfield (OBJ, gbinderproxyoffsets. mobject); <br/> If (target = NULL) {<br/> jnithrowexception (ENV, "Java/lang/illegalstateexception", "binder has been finalized! "); <Br/> return jni_false; <br/>}</P> <p> status_t err = target-> transact (Code, * data, reply, flags ); <br/> If (ERR = no_error) {<br/> return jni_true; <br/>} else if (ERR = unknown_transaction) {<br/> return jni_false; <br/>}</P> <p> signalexceptionforerror (ENV, OBJ, err); <br/> return jni_false; <br/>}< br/>

So far, android can send rpc calls at the Java layer to the C ++ layer. RPC calls will be handled by the service_manager process. The processing of the C ++ layer will not be discussed in this article. If you are interested, please refer to the author's article about the principles of the C ++ layer binder system.

 

Get isensorservice

The only way to obtain an interface is by calling the iservicemanager. getservice function. The process is similar to calling iservicemanager. addservice. Java servicemanagerproxy sends rpc to the bpservicemanager at the C ++ layer, and bpservicemanager sends the call to the service_manager process. Bpservicemanager is executed. The returned C ++ layer ibinder object is actually a bpbinder instance.

Virtual sp <ibinder> getservice (const string16 & name) const <br/>{< br/> unsigned N; <br/> for (n = 0; n <5; N ++) {<br/> sp <ibinder> SVC = checkservice (name); <br/> If (SVC! = NULL) return SVC; <br/> Logi ("waiting for sevice % s... /n ", string8 (name ). string (); <br/> sleep (1); <br/>}< br/> return NULL; <br/>}</P> <p> virtual sp <ibinder> checkservice (const string16 & name) const <br/>{< br/> parcel data, reply; <br/> data. writeinterfacetoken (iservicemanager: getinterfacedescriptor (); <br/> data. writestring16 (name); <br/> remote ()-> transact (check_service_transaction, Data, & reply); <br/> return reply. readstrongbinder (); <br/>}< br/>

 

After receiving the transact, servicemanagerproxy calls the android_ OS _parcel_readstrongbinder function of JNI native. This function calls the javaobjectforibinder function to create a Java object for the returned C ++ ibinder object.

Static jobject android_ OS _parcel_readstrongbinder (jnienv * ENV, jobject clazz) <br/>{< br/> parcel * parcel = parcelforjavaobject (ENV, clazz); <br/> If (parcel! = NULL) {<br/> return javaobjectforibinder (ENV, parcel-> readstrongbinder (); <br/>}< br/> return NULL; <br/>}< br/>

Javaobjectforibinder judges whether the object belongs to the service provider or service user. Here, this object is a service user. Therefore, it will create a new Java binderproxy object to represent the ibinder object in C ++. In this way, we obtain a Java binderproxy object. Then, isensorservice. stub. asinterface will create an isensorservice. stub. Proxy in the binderproxy object.

/** <Br/> * cast an ibinder object into an isensorservice interface, <br/> * generating a proxy if needed. <br/> */<br/> Public static android. hardware. isensorservice asinterface (Android. OS. ibinder OBJ) <br/>{< br/> If (OBJ = NULL) {<br/> return NULL; <br/>}< br/> android. hardware. isensorservice in = (Android. hardware. isensorservice) obj. querylocalinterface (descriptor); <br/> If (in! = NULL) {<br/> return in; <br/>}< br/> return new android. hardware. isensorservice. stub. proxy (OBJ); <br/>}< br/>

In this way, we obtain an isensorservice. stub. Proxy instance.

 

Isensorservice. reportaccurary RPC call

This is equivalent to calling isensorservice. stub. Proxy. reportaccuracy. Its code is automatically generated using the aidl language. It calls the JNI native function android_ OS _binderproxy_transact of binderproxy to distribute RPC calls in Java to C ++. In this way, Android completes the RPC call between Java and C ++.

 

Handle isensorservice. reportaccuracy RPC calls

RPC calls are processed by the javabbinder object in the C ++ layer. The javabbinder object is created when iservicemanager. addservice is called.

Virtual status_t ontransact (<br/> uint32_t code, const parcel & Data, parcel * reply, uint32_t flags = 0) <br/>{< br/> jnienv * Env = javavm_to_jnienv (MVM); </P> <p> jboolean res = env-> callbooleanmethod (mobject, gbindersets offsets. mexectransact, <br/> Code, (int32_t) & data, (int32_t) reply, flags); <br/> jthrowable excep = env-> exceptionoccurred (); <br/> If (excep) {<br/> report_exception (ENV, excep, <br /> "*** Uncaught remote exception! "<Br/>" (exceptions are not yet supported into SS processes .) "); <br/> res = jni_false; </P> <p>/* clean up JNI local ref -- We don't return to Java */<br/> env-> deletelocalref (excep ); <br/>}< br/>

Javabbinder calls functions at the Java layer through JNI. This example is binder.exe cutetransact.

Private Boolean exectransact (INT code, int dataobj, int replyobj, <br/> int flags) {<br/> parcel DATA = parcel. obtain (dataobj); <br/> parcel reply = parcel. obtain (replyobj); <br/> // theoretically, we shocould call transact, which will call ontransact, <br/> // but all that does is rewind it, and we just got these from an IPC, <br/> // so we'll call it directly. <br/> Boolean res; <br/> try {<br/> res = ontransact (Code, Data, reply, flags); <br/>} catch (RemoteException E) {<br/> reply. writeexception (E); <br/> res = true; <br/>} catch (runtimeexception e) {<br/> reply. writeexception (E); <br/> res = true; <br/>}< br/> reply. recycle (); <br/> data. recycle (); <br/> return res; <br/>}< br/>

Finally, binder.exe cutetransact will call isensorservice. ontransact. Isensorservice. ontransact calls sensorservice. reportaccuracy to perform actual work.

 

Original reprint address: http://blog.chinaunix.net/space.php? Uid = 20564848 & Do = Blog & id = 73517

First written by Steve Guo, please keep the mark if forwarding.

Related Article

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.