Android implements Binder communication between processes on the Native layer, but the development of upper-layer applications and Framework implementation are both Java. It is unreasonable to implement it again at the Java layer, java can call Native Code through JNI. Therefore, the implementation of using JNI to reuse the Binder at the Native layer is a logical task.
Register Service
In the init2 phase of the Init process, the system starts ServerThread, which will start many system services implemented in Java, such as PowerService:
power =
Create a Server entity and register it with ServiceManager. The code is similar to the Native layer Binder. PowerManagerService inherits the Binder class from the Java layer:
PowerManagerService IPowerManager Stub android.os.Binder android.os.IPowerManager {
When new PowerManagerService is used, the Binder constructor is called. The Binder constructor calls init (). init is the native method and JNI android_ OS _Binder_init is executed:
android_os_Binder_init(JNIEnv** jbh = (jbh =="java/lang/OutOfMemoryError""Java Binder %p: acquiring first ref on holder %p"->incStrong((*->SetIntField(obj, gBinderOffsets.mObject, (
In android_ OS _Binder_init, A JavaBBinderHolder is created and its pointer is saved in the gBinderOffsets. mObject domain of obj, that is, Binder. What is gBinderOffsets. mObject? Let's take a look at its definition:
In AndroidRuntine: starregulatory, register_android_ OS _Binder and register_android_ OS _Binder call functions such as handler to establish mappings between the Java layer Binder, BinderProxy, BinderInternal, Log, and Native layer. For example, in int_register_android_ OS _Binder, gBinderOffsets will be initialized using the JNI standard method GetMethodID and so on:
int_register_android_os_Binder(JNIEnv*= env->== NULL, = (jclass) env->= env->GetMethodID(clazz, , = env->GetFieldID(clazz, ,
In android_ OS _Binder_init, a new JavaBBinderHolder is added, and JavaBBinderHolder new is saved to its member wp <JavaBBinder> mBinder.
JavaBBinder inherits from the BBinder of the Native layer, saves the Binder object (PowerManagerService) of the Java layer to the member mObject, and returns it through the object () method.
Now we find that JavaBinder, BinderBBinderHolder, and JavaBBinder have mutual references:
PowerManagerService. mObject-> JavaBBinderHolder
JavaBBinderHolder. mBinder-> JavaBBinder
JavaBBinder. mObject-> PowerManagerService
Binder is a Client-Server type IPC. PowerManagerService belongs to the Server end. We know from Native Binder that the Client communicates with Serverr through BpBinder through Binder Driver and BBinder, powerManagerService uses JavaBBinderHolder to reference JavaBBinder, while JavaBBinder inherits from BBinder, which meets the Server's conditions. If the Server entity is ready, register with ServiceManager. Use the following method:
(sServiceManager !=
BinderInternal. getContextObject is a Native method that calls JNIandroid_ OS _BinderInternal_getContextObject:
jobject android_os_BinderInternal_getContextObject(JNIEnv*<IBinder> b = ProcessState::self()->
ProcessState: self ()-> getContextObject is very familiar. You can know in Binder in Native that new BpBinder (0) is returned for this call ).
The role of javaObjectForIBinder is to create a BinderProxy object on the Java layer and save the BpBinder on the Native layer to BinderProxy. and save the weak reference of BinderProxy to the BpBinder (member mObjects) at the Native layer through attachObject. In this way, BinderProxy at the Java layer and BpBinder at the Native layer can be referenced to each other. The bining between the BinderProxy of the Java layer and its representation in the Native layer is also established in register_android_ OS _Binder like the Binder class.
The red part above is equivalent:
gServiceManager = ServiceManagerNative.asInterface( BinderProxy());
ServiceManagerNative inherits from the Binder class of IServiceManager and Java layer. BinderProxy can reference BpBinder. AsInterface is like interface_cast in Native Binder. The asInterface implementation can be simplified:
ServiceManagerProxy(obj);
Obj is the BinderProxy object. ServiceManagerProxy directly saves the BinderProxy object in the member mRemote and returns it through asBinder.
ServiceManagerProxy implements IServiceManager at the same time. It can be seen from its name that ServiceManagerProxy acts as the proxy of ServiceManager on the Client side. Let's take a look at its addService implementation:
addService(String name, IBinder service, == data.writeInt(allowIsolated ? 1 : 0 reply.recycle(); data.recycle(); }
WriteStrongBinder is the Native method, which calls callback. In android_ OS _Parcel_writeStrongBinder, convert Java Parcel to Native Parcel (the Native Parcel pointer is saved in the member variable of Java Parcel), and then calls the following statement:
status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, ));
Sp <IBinder> ibinderForJavaObject (JNIEnv * env, jobject obj) returns JavaBBinder or Native BpBinder Based on obj. The input obj here is PowerManagerService and JavaBBinder is returned. Next, mRemote. transact is called, and mRemote is the object of BinderProxy.
The transact of BinderProxy is the Native method. JNIandroid_ OS _BinderProxy_transact is called and passed in android_ OS _BinderProxy_transact:
IBinder* target = (IBinder*) env->GetIntField(obj, gBinderProxyOffsets.mObject);
...
status_t err = target->transact(code, *data, reply, flags);
Get the BpBinder saved in BinderProxy, and then call the BpBinder's transact. Here it is the same as the call process of Native Binder. Native ServiceManager will register our Service, where it is PowerManagerService.
Get registered Service
The Service has been registered with ServiceManager. How can we obtain the registered Service or, more accurately, obtain the agent of the registered Service?
Recall how we got system services in APK:
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
Let's take a look at the implementation of getSystemService, which is located in ContextImpl:
= fetcher == ? : fetcher.getService( }});
1. ServiceManager. getService obtains the IBinder object.
Like ServiceManager. addService, ServiceManager. getService first obtains the ServiceManagerProxy object and then calls its getService method:
IBinder getService(String name) 0=
MRemote is a BinderProxy object that references BpBinder internally. It calls the Native method of BinderProxy to communicate with the Binder, and then reads the returned data through readStrongBinder (), an IBinder object.
In readStrongBinder, The BinderProxy object is returned through javaObjectForIBinder, as mentioned earlier.
2. Convert the obtained IBinder object to an IPowerManager object through asInterface.
IPowerManager. Stub. asInterface can be simplified:
android.os.IPowerManager.Stub.Proxy(obj);
Proxy only saves the passed parameter (BinderProxy) to the member mRemote and returns it through asBinder.
Both Proxy and Stub are classes generated after IPowerManager. aidl compilation and are located in IPowerManager. java. There is a lot of information about aidl online.
3. The IPowerManager object is not exposed externally. A PowerManager encapsulation IPowerManager is constructed to return the result.
PowerManager only saves IPowerManager in the member variable, and saves BinderProxy in PowerManager. BinderProxy references Native BpBinder to communicate with the Server.
Server responds to Client requests
After the Server receives the Client request, it will call the BBinder's transact Processing request. The transact will call the virtual function onTransact, And the JavaBBinder inherits from the BBinder. Therefore, it will call JavaBBinder: onTransact in JavaBBinder :: onTransact has the following sentence:
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact, code, (int32_t)&data, (int32_t)reply, flags);
The Java class method is called through JNI in reverse order. As we know before, in the Service implemented in Java, Service objects, JavaBBinderHolder, and JavaBBinder have mutual references. The JavaBBinder member mObject references Service objects in Java, such as PowerManagerService, in addition, in int_register_android_ OS _Binder
gBinderOffsets.mExecTransact = env->GetMethodID(clazz, , );
The execTransact method of Service (actually the Binder method) is saved in gBinderOffsets. mExecTransact, and binder.exe cTransact is called in JavaBBinder: ontransact. OnTransact is called in binder.exe cTransact, And the onTransact method of the execution subclass is Stub class. In onTransact, the corresponding method is executed based on the code value, and finally the Service class is called (inherited from Stub).
Summary
The Java layer uses Native-layer Binder through JNI. During JNI function registration, the ing between classes such as Java-layer Binder, BinderProxy, and BinderProxy and Native layer is established. The Java-layer Service entity inherits from the Java-layer Binder class. During the Binder class initialization, A JavaBBinderHolder is created as the JavaBBinder container. JavaBBinder inherits from BBinder. the Java-layer Binder class references JavaBBinderHolder, javaBBinderHolder references JavaBBinder. JavaBBinder inherits from BBinder and references the Java-layer Binder class. These three references each other, so that the Service entity of the Java layer can communicate with the driver through BBinder.
The process sends a GET_SERVICE request to the ServiceManager agent at the Java layer, and then requests the service from ServiceManager at the Native layer through JNI. The ServiceManager at the Native layer returns the request service proxy to your BpBinder, use the javaObjectForIBinder function to convert the BbBinder of Native to the BinderProxy corresponding to the Java layer, and then use the Stub class asInterface method generated by aidl to close the BinderProxy to the proxy object of the requested service, this proxy object references BinderProxy. BinderProxy stores the BpBinder on the Native layer, so that it can communicate with the driver.
When the Server receives a Client request, it will call the Server Service through the BBinder's transact. The BBinder's transact calls the virtual function onTransact, which will be transferred to the onTransact of the JavaBBinder subclass of BBinder, while JavaBinder: ontransactwill be called via jni to exectransactof the Java-layer binderclass. binder.exe cTransact calls onTransact of the class Stub, and then calls the corresponding method of the Service object class (inherited from Stub) based on the code value.