Andorid Binder inter-process communication --- Java Interface source code

Source: Internet
Author: User
Tags mremote

This article is based on the source code Scenario Analysis of the Android system, by Luo shengyang

I. Architecture code:

~ /Android/frameworks/base/core/java/android/OS

---- IInterface. java (Interface)

---- IServiceManager. java (IServiceManager)

---- IBinder. java (IBinder)

---- Binder. java (BinderProxy, Binder)

---- ServiceManagerNative. java (ServiceManagerProxy, ServiceManagerNative)

---- ServiceManager. java (ServiceManager)

~ /Android/frameworks/base/core/jni

---- Android_util_Binder.cpp



Test code: (refer to two articles on implementing the hardware access service and developing Android applications to use the hardware Access Service)

~ /Android/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/OS

---- IFregService. java

~ /Android/frameworks/base/services/java/com/android/server

---- FregService. java

~ /Android/packages/experimental/Freg

---- Src ---- shy/luo/freg ---- Freg. java


The uml class diagram is as follows:



Ii. Source Code Analysis <喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4KPHA + kernel/By9OyvP63w87Kt/7O8UZyZWdTZXJ2aWNlo6zI58/Co7o8L3A + kernel = "brush: java;" >@ Override public void run () {....................................... ........................................ ............ try {Slog. I (TAG, "Freg Service"); ServiceManager. addService ("freg", new FregService ();} catch (Throwable e) {Slog. e (TAG, "Failure starting Freg Service", e );}The addService method of ServiceManager is called. The implementation is as follows:

~ /Android/frameworks/base/core/java/android/OS

---- ServiceManager. java

public final class ServiceManager {......private static IServiceManager sServiceManager;......private static IServiceManager getIServiceManager() {if (sServiceManager != null) {return sServiceManager;}// Find the service managersServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());return sServiceManager;}......        public static void addService(String name, IBinder service) {               try {                     getIServiceManager().addService(name, service);               } catch (RemoteException e) {                     Log.e(TAG, "error in addService", e);               }        }        ......}

1. System process: the process of obtaining the Java remote interface of Service Manager

If the static member variable sServiceManager has not been created, call the ServiceManagerNative. asInterface function to create the variable. Before calling the ServiceManagerNative. asInterface function, you must first obtain a BinderProxy object through the BinderInternal. getContextObject function.

Let's take a look at the implementation of BinderInternal. getContextObject :~ /Android/frameworks/base/core/java/com/android/internal/OS

---- BinderInternal. java

public class BinderInternal {....../*** Return the global "context object" of the system.  This is usually* an implementation of IServiceManager, which you can use to find* other services.*/public static final native IBinder getContextObject();......}

Here we can see that BinderInternal. getContextObject is a JNI method, which is implemented as follows:

~ /Android/frameworks/base/core/jni

---- Android_util_Binder.cpp

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz){    sp
  
    b = ProcessState::self()->getContextObject(NULL);    return javaObjectForIBinder(env, b);}
  
The familiar ProcessState: self ()-> getContextObject function returns a BpBinder object whose handle value is 0, that is, the following statement:

sp
  
    b = ProcessState::self()->getContextObject(NULL);
  
Equivalent:
sp
  
    b = new BpBinder(0);
  

Before calling the javaObjectForIBinder function, we will first introduce jni loading.



Let's take a look at the definitions of two variables: gBinderOffsets and gBinderProxyOffsets.

First, let's look at the definition of gBinderOffsets:

~ /Android/frameworks/base/core/jni

---- Android_util_Binder.cpp

static struct bindernative_offsets_t{    // Class state.    jclass mClass;    jmethodID mExecTransact;    // Object state.    jfieldID mObject;} gBinderOffsets;

To put it simply, the gBinderOffsets variable is used to record information about the Binder class in the second class diagram above. It is initialized in the int_register_android_ OS _Binder FUNCTION OF THE JNI method registered with the Binder class:

~ /Android/frameworks/base/core/jni

---- Android_util_Binder.cpp

Const char * const kBinderPathName = "android/OS/Binder"; static int int_register_android_ OS _Binder (JNIEnv * env) {jclass clazz; clazz = env-> FindClass (kBinderPathName ); LOG_FATAL_IF (clazz = NULL, "Unable to find class android. OS. binder "); gBinderOffsets. mClass = (jclass) env-> NewGlobalRef (clazz); // reference the Binder class gBinderOffsets of the java layer. mExecTransact = env-> GetMethodID (clazz, "execTransact", "(IIII) Z"); // reference the execTransact method assert (gBinderOffsets) of the java-layer Binder class. mExecTransact); gBinderOffsets. mObject = env-> GetFieldID (clazz, "mObject", "I"); // reference the mObject attribute assert (gBinderOffsets. mObject); return AndroidRuntime: registerNativeMethods (env, kBinderPathName, gBinderMethods, NELEM (gBinderMethods ));}


Let's take a look at the definition of gBinderProxyOffsets:

~ /Android/frameworks/base/core/jni

---- Android_util_Binder.cpp

static struct binderproxy_offsets_t{    // Class state.    jclass mClass;    jmethodID mConstructor;    jmethodID mSendDeathNotice;    // Object state.    jfieldID mObject;    jfieldID mSelf;} gBinderProxyOffsets;
To put it simply, gBinderProxyOffsets is used to record the BinderProxy class information in the first figure above. It is initialized in the int_register_android_ OS _BinderProxy FUNCTION OF THE JNI METHOD OF THE BinderProxy Class Registered:

~ /Android/frameworks/base/core/jni

---- Android_util_Binder.cpp

Const char * const kBinderProxyPathName = "android/OS/BinderProxy"; static int int_register_android_ OS _BinderProxy (JNIEnv * env) {jclass clazz ;.......... clazz = env-> FindClass (kBinderProxyPathName); LOG_FATAL_IF (clazz = NULL, "Unable to find class android. OS. binderProxy "); gBinderProxyOffsets. mClass = (jclass) env-> NewGlobalRef (clazz); // reference the BinderProxy class gBinderProxyOffsets. mConstructor = env-> GetMethodID (clazz ,"
  
   
"," () V "); // reference the constructor of the BinderProxy class ..... gBinderProxyOffsets. mSendDeathNotice = env-> GetStaticMethodID (clazz, "sendDeathNotice", "(Landroid/OS/IBinder $ DeathRecipient;) V "); // reference the sendDeathNotice method of the BinderProxy class ..... gBinderProxyOffsets. mObject = env-> GetFieldID (clazz, "mObject", "I"); // references the mObject attribute of the BinderProxy class ..... gBinderProxyOffsets. mSelf = env-> GetFieldID (clazz, "mSelf", "Ljava/lang/ref/WeakReference;"); // references the mSelf attribute of the BinderProxy class ...... return AndroidRuntime: registerNativeMethods (env, kBinderProxyPathName, gBinderProxyMethods, NELEM (gBinderProxyMethods ));}
  

Let's take a look at the definition of gWeakReferenceOffsets:

~ /Android/frameworks/base/core/jni

---- Android_util_Binder.cpp

static struct weakreference_offsets_t{                                                                      jclass mClass;                                                                                                     jmethodID mGet; } gWeakReferenceOffsets;  
GWeakReferenceOffsets are also initialized in the int_register_android_ OS _BinderProxy function, as shown below:

~ /Android/frameworks/base/core/jni

---- Android_util_Binder.cpp

Const char * const kBinderProxyPathName = "android/OS/BinderProxy"; static int int_register_android_ OS _BinderProxy (JNIEnv * env) {jclass clazz; clazz = env-> FindClass ("java/lang/ref/WeakReference ");...... gWeakReferenceOffsets. mClass = (jclass) env-> NewGlobalRef (clazz); // references the WeakReference class gWeakReferenceOffsets. mGet = env-> GetMethodID (clazz, "get", "() Ljava/lang/Object ;"); // reference the get method of the WeakReference class ............... return AndroidRuntime: registerNativeMethods (env, kBinderProxyPathName, gBinderProxyMethods, NELEM (gBinderProxyMethods ));}


The following describes javaObjectForIBinder, which converts the BpBinder object into a BinderProxy object:

~ /Android/frameworks/base/core/jni

---- Android_util_Binder.cpp

Jobject javaObjectForIBinder (JNIEnv * env, const sp
  
   
& Val) {if (val = NULL) return NULL; if (val-> checkSubclass (& gBinderOffsets) {// One of our own! Jobject object = static_cast
   
    
(Val. get ()-> object ();........ return object;} // For the rest of the function we will hold this lock, to serialize // looking/creation of Java proxies for native Binder proxies. autoMutex _ l (mProxyLock); // Someone else's... do we know about it? Jobject object = (jobject) val-> findObject (& gBinderProxyOffsets); // check whether a BinderProxy object if (object! = NULL) {// If any returned result is a WeakReference object pointing to the BinderProxy object, that is, a weak reference object jobject res = env-> CallObjectMethod (object, gWeakReferenceOffsets. mGet); // The BinderProxy object pointed to by the weak reference object may be invalid. Therefore, you need to check its validity, the method is to call its member function get to obtain a strongly referenced object. If (res! = NULL) {// if it is not NULL ...... return res; // return directly }..... android_atomic_dec (& gNumProxyRefs); // if it is NULL val-> detachObject (& gBinderProxyOffsets ); // unbind it from an invalid BinderProxy object. env-> DeleteGlobalRef (object); // Delete the global reference of the weak reference object.} object = env-> NewObject (gBinderProxyOffsets. mClass, gBinderProxyOffsets. mConstructor); // create a BinderProxy object if (object! = NULL ){....... env-> SetIntField (object, gBinderProxyOffsets. mObject, (int) val. get (); // BinderProxy. the mObject member variable records the address val-> incStrong (object) of The BpBinder object; // the native object needs to hold a weak reference back to The // proxy, so we can retrieve the same proxy if it is still active. jobject refObject = env-> NewGlobalRef (env-> GetObjectField (object, gBinderProxyOffsets. mSelf); // obtain the member variable mSelf (weak reference object of BinderProxy) in BinderProxy, and then create a global reference object to reference it val-> attachObject (& gBinderProxyOffsets, refObject, jnienv_to_javavm (env), proxy_cleanup); // put it in BpBinder. You can call BpBinder in the previous step when you need to use it next time :: findObj retrieved it. // Note that a new object reference has been created. android_atomic_inc (& gNumProxyRefs); incRefsCreated (env);} return object ;}
   
  
The member function checkSubclass of the Binder proxy object directs to a Binder proxy object or a JavaBBinder object.

The member function checkSubclass of the Binder proxy object is implemented by its parent class IBinder, as shown below:

~ /Android/base/libs/binder

---- Binder. cpp

bool IBinder::checkSubclass(const void* /*subclassID*/) const{    return false;}
The findObject, detachObject, and attachObject of the BpBinder class are not described here. For details, see "scenario analysis of the source code of Android system" by Luo shengyang.

After executing javaObjectForIBinder, the system first returns to the static member function getContextObject of the BinderInternal class, and then returns the static member function getIServiceManager of the ServiceManager class,

Now that we have obtained a BinderProxy object, we will call the static member function asInterface of the ServiceManagerNative class to encapsulate it into a ServiceManagerProxy object.

The static member function asInterface of the ServiceManagerNative class is implemented as follows:

~ /Android/frameworks/base/core/java/android/OS

---- ServiceManagerNative. java

Public abstract class ServiceManagerNative ...... {...... static public IServiceManager asInterface (IBinder obj) // BinderProxy {if (obj = null) {return null;} IServiceManager in = (IServiceManager) obj. queryLocalInterface (descriptor); if (in! = Null) {return in;} return new ServiceManagerProxy (obj); // create a java proxy object for Service Manager }......}
Return to ServiceManager. getIServiceManager, and return from the following statement:
sServiceManager = ServiceManagerNative.asInterface(new BinderProxy());
Equivalent:

sServiceManager = new ServiceManagerProxy(new BinderProxy());


2. System Processes encapsulate inter-process communication data
Run the following command:

GetIServiceManager (). addService (name, service); // The name is freg, and the service is new FregService ()
Let's take a look at the FregService creation process:

new FregService();
This statement calls the constructor of the FregService class, And the FregService class inherits from the IFregService. stub class, IFregService. the Stub class inherits the Binder class. Therefore, the constructor of the Binder class is called:

~ /Android/frameworks/base/core/java/android/OS

---- Binder. java

public class Binder implements IBinder {......private int mObject;......public Binder() {init();......}private native final void init();......}
Here, a JNI method init is called to initialize this Binder object. The implementation is as follows:

~ /Android/frameworks/base/core/jni

---- Android_util_Binder.cpp

Static void android_ OS _Binder_init (JNIEnv * env, jobject clazz) {JavaBBinderHolder * jbh = new JavaBBinderHolder (env, clazz); // create a JavaBBinderHolder object jbh .... jbh-> incStrong (clazz); env-> SetIntField (clazz, gBinderOffsets. mObject, (int) jbh); // Save the address of this object to the mObject member variable of the preceding Binder class}
It actually only does one thing, that is, to create a JavaBBinderHolder object jbh, and then save the address of this object to the mObject member variable of the preceding Binder class, which will be used later.


Start execution:

GetIServiceManager (). addService (name, service); // The name is freg, and the service is new FregService ()
The getIServiceManager function has been analyzed before. It returns the IServiceManager interface of the ServiceManagerProxy object. Therefore, go to ServiceManagerProxy. addService to see:

~ /Android/frameworks/base/core/java/android/OS

---- ServiceManagerNative. java

class ServiceManagerProxy implements IServiceManager {public ServiceManagerProxy(IBinder remote) {mRemote = remote;}......public void addService(String name, IBinder service)throws RemoteException {Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IServiceManager.descriptor);//android.os.IServiceManagerdata.writeString(name);//fregdata.writeStrongBinder(service);//new FregService()mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);reply.recycle();data.recycle();}......private IBinder mRemote;}
Here we are concerned about how to write the parameter service to the data Parcel object:
data.writeStrongBinder(service);
Let's take a look at the implementation of the Parcel. writeStrongBinder function:
public final class Parcel {....../*** Write an object into the parcel at the current dataPosition(),* growing dataCapacity() if needed.*/public final native void writeStrongBinder(IBinder val);//new FregService()......}
The writeStrongBinder function is a JNI method, which is implemented as follows:

~ /Android/frameworks/base/core/jni

---- Android_util_Binder.cpp

Static void Merge (JNIEnv * env, jobject clazz, jobject object) // clazz Is Parcel, and object is new FregService () {Parcel * parcel = parcelForJavaObject (env, clazz ); // obtain the if (Parcel! = NULL) {const status_t err = parcel-> writeStrongBinder (ibinderForJavaObject (env, object); if (err! = NO_ERROR) {jniThrowException (env, "java/lang/OutOfMemoryError", NULL );}}}
The implementation of ibinderForjavaObject is as follows:

~ /Android/frameworks/base/core/jni

---- Android_util_Binder.cpp

Sp
  
   
IbinderForJavaObject (JNIEnv * env, jobject obj) {if (obj = NULL) return NULL; if (env-> IsInstanceOf (obj, gBinderOffsets. mClass) {JavaBBinderHolder * jbh = (JavaBBinderHolder *) env-> GetIntField (obj, gBinderOffsets. mObject); // here, the mObject member variable of the obj object is forcibly converted to the JavaBBinderHolder object return jbh! = NULL? Jbh-> get (env): NULL;} if (env-> IsInstanceOf (obj, gBinderProxyOffsets. mClass) {return (IBinder *) env-> GetIntField (obj, gBinderProxyOffsets. mObject);} LOGW ("ibinderForJavaObject: % p is not a Binder object", obj); return NULL ;}
  
The FregService object was created before. It was used to create a JavaBBinderHolder object on the JNI layer when calling the parent class Binder of FregService, then save the object address in the mObject member variable of the Binder class. Therefore, the mObject member variable of the obj object is forcibly converted to the JavaBBinderHolder object.
At this point, the homework of this function has not been completed yet, and the last key step is left:

return jbh != NULL ? jbh->get(env) : NULL;
Let's take a look at the implementation of the get function of the JavaBBinderHolder class:

class JavaBBinderHolder : public RefBase{......JavaBBinderHolder(JNIEnv* env, jobject object): mObject(object){......}......sp
  
    get(JNIEnv* env){AutoMutex _l(mLock);sp
   
     b = mBinder.promote();if (b == NULL) {b = new JavaBBinder(env, mObject);mBinder = b;......}return b;}......jobject         mObject;wp
    
      mBinder;};
    
   
  
Not complete.










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.