2013年9月24日星期二

Binder in Java

 

Android in Native layer implements Binder inter-process communication , but the upper Framework application development and implementation are Java, using Java layer once again achieved is certainly unreasonable , Java through JNI calls Native Code, so Binder reuse through JNI implementation in Native layer is a logical thing.

 

Registration Service

 

in the Init process init2 stage , the system starts up ServerThread, will start in ServerThread many system services implemented in Java , for example PowerService:

 
  
power = new PowerManagerService(); 
ServiceManager.addService(Context.POWER_SERVICE, power);
 
 

New Server -side entities , then the ServiceManager registered , the surface is from the code and Native layer Binder same. PowerManagerService inherited from the Java layer Binder class :

 
  
public final class PowerManagerService extends IPowerManager.Stub 
public interface IPowerManager extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements android.os.IPowerManager {
 
 

In order to invoke when the new PowerManagerService constructor Binder , Binder 's constructor calls the init (), init is a native method , perform the JNI android_os_Binder_init:

 
  
static void android_os_Binder_init(JNIEnv* env, jobject obj) 
{
JavaBBinderHolder
* jbh = new JavaBBinderHolder();
if (jbh == NULL) {
jniThrowException(env,
"java/lang/OutOfMemoryError", NULL);
return;
}
ALOGV(
"Java Binder %p: acquiring first ref on holder %p", obj, jbh);
jbh
->incStrong((void*)android_os_Binder_init);
env
->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);
}
 
 

in android_os_Binder_init, created a JavaBBinderHolder right corner , and the pointer stored in the obj that Binder 's gBinderOffsets.mObject domain and gBinderOffsets.mObject it is what ? Look at its definition :

 
  
static struct bindernative_offsets_t 
{
jclass mClass;
jmethodID mExecTransact;
jfieldID mObject;
} gBinderOffsets;
 
 

in AndroidRuntine :: startReg will call register_android_os_Binder, register_android_os_Binder calls int_register_android_os_Binder other function to create Java layer Binder, BinderProxy, BinderInternal, Log , etc. with Native layer mappings. For example, in int_register_android_os_Binder will GetMethodID through JNI standard methods such as initialization gBinderOffsets:

 
  
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);
gBinderOffsets.mExecTransact
= env->GetMethodID(clazz, "execTransact", "(IIII)Z");
assert(gBinderOffsets.mExecTransact);

gBinderOffsets.mObject
= env->GetFieldID(clazz, "mObject", "I");
assert(gBinderOffsets.mObject);

return AndroidRuntime::registerNativeMethods(
env, kBinderPathName,
gBinderMethods, NELEM(gBinderMethods));
}
 
 

in android_os_Binder_init the new one JavaBBinderHolder, JavaBBinderHolder new one JavaBBinder saved to its own members in wp mBinder .

 

JavaBBinder inherited from Native layer BBinder, and the Java layer Binder object ( here ie PowerManagerService) saved to the members of the mObject in and through the object () method returns .

 

Now we find , JavaBinder, BinderBBinderHolder, JavaBBinder exist between the referential relationship :

 

PowerManagerService.mObject-> JavaBBinderHolder
JavaBBinderHolder.mBinder-> JavaBBinder
JavaBBinder.mObject-> PowerManagerService

 

Binder is a Client-Server type of IPC, PowerManagerService belong Server side , we know from the Native Binder , Client through BpBinder via Binder Driver, BBinder with Serverr communication , PowerManagerService through JavaBBinderHolder reference JavaBBinder, while JavaBBinder inherited from BBinder, comply with the conditions of the Server , Server entity there, the next step is to ServiceManager registered by the following method :

 
  
ServiceManager.addService(Context.POWER_SERVICE,power);

// In ServiceManager
public static void addService(String name, IBinder service) {
try {
getIServiceManager().addService(name, service,
false);
}
catch (RemoteException e) {
Log.e(TAG,
"error in addService", e);
}
}

private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
sServiceManager
= ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
 
 

BinderInternal.getContextObject is a Native methods , call JNIandroid_os_BinderInternal_getContextObject:

 
  
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz) 
{
sp
<IBinder> b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b);
}
 
 

ProcessState :: self () -> getContextObject very familiar with, in Binder in Native you can know that this call returns new BpBinder (0).

 

javaObjectForIBinder role is , create a new Java layer BinderProxy object, Native layer BpBinder saved to BinderProxy.mObject, and BinderProxy weak references through attachObject saved to Native layer BpBinder ( member mObjects in ) , so Java layer the BinderProxy with Native layer BpBinder can reference each other up . Java layer BinderProxy its representation in Native layer mapping between the same class as also in register_android_os_Binder Binder created .

 

above the red part of it is equivalent to :

 
  
gServiceManager = ServiceManagerNative.asInterface(new BinderProxy());
 
 

ServiceManagerNative inherited from IServiceManager with the Java layer Binder class , BinderProxy can reference BpBinder. asInterface like Native Binder in interface_cast of , asInterface implementation can be simplified to :

 
  
return new ServiceManagerProxy(obj);
 
 

obj is BinderProxy object. ServiceManagerProxy directly to this BinderProxy object stored in the member mRemote in and through asBinder returned.

 

ServiceManagerProxy while achieving IServiceManager, and its name shows , ServiceManagerProxy as ServiceManager in the Client -side proxy , look it addService implementation :

 
  
public void addService(String name, IBinder service, boolean allowIsolated) 
throws RemoteException {
Parcel data
= Parcel.obtain();
Parcel reply
= Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
data.writeStrongBinder(service);
data.writeInt(allowIsolated
? 1 : 0);
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply,
0);
reply.recycle();
data.recycle();
}
 
 

writeStrongBinder Native methods are calling android_os_Parcel_writeStrongBinder, in android_os_Parcel_writeStrongBinder convert the Java Parcel Native Parcel (Native Parcel pointer stored in the Java Parcel member variable ) , and then call the following statement :

 
  
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
 
 

sp ibinderForJavaObject (JNIEnv * env, jobject obj) obj return under JavaBBinder or Native BpBinder, where incoming obj is PowerManagerService, return JavaBBinder. The next call mRemote.transact, mRemote is BinderProxy objects.

 

BinderProxy Native methods of transact is calling JNIandroid_os_BinderProxy_transact, in android_os_BinderProxy_transact by :

 
  
IBinder* target = (IBinder*) env->GetIntField(obj, gBinderProxyOffsets.mObject);
...
status_t err = target->transact(code, *data, reply, flags);
 
 Get to BinderProxy

saved BpBinder, then call BpBinder of transact, and Native Binder here on the same call flow , Native ServiceManager will register our Service, here is PowerManagerService.

 

be registered Service

 

Service to ServiceManager already registered, then how do we get the registered Service, or more precisely, how to get the registered Service agents do ?

 

Think back to us is how to obtain the APK system services :

 
  
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
 
 

look getSystemService realization , located ContextImpl in :

 
  
    @Override 
public Object getSystemService(String name) {
ServiceFetcher fetcher
= SYSTEM_SERVICE_MAP.get(name);
return fetcher == null ? null : fetcher.getService(this);
}

registerService(POWER_SERVICE,
new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b
= ServiceManager.getService(POWER_SERVICE);
IPowerManager service = IPowerManager.Stub.asInterface(b);
return new
PowerManager(ctx.getOuterContext(),
service, ctx.mMainThread.getHandler());

}});
 
 

1. ServiceManager.getService get IBinder object

 

with ServiceManager.addService Like , ServiceManager.getService first obtain a ServiceManagerProxy object, and then call its getService method :

 
  
    public IBinder getService(String name) throws RemoteException { 
...
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply,
0);
IBinder binder
= reply.readStrongBinder();
...
return binder;
}
 
 

mRemote is BinderProxy objects, internal references BpBinder, call BinderProxy of Native methods transact with Binder Communications , and then through readStrongBinder () reads the data returned an IBinder object.

 

readStrongBinder by javaObjectForIBinder returned BinderProxy object , as already mentioned .

 

2. Through asInterface will get IBinder object into IPowerManager object

 

IPowerManager.Stub.asInterface can be simplified to :

 
  
return new android.os.IPowerManager.Stub.Proxy(obj);
 
 

Proxy just passed parameters (BinderProxy) saved to the members of the mRemote and through asBinder returned.

 

Proxy Stub are IPowerManager.aidl compiled with the generated classes are located in IPowerManager.java . About aidl lot of information online .

 

3. IPowerManager objects are not exposed to the outside , and construct a PowerManager package IPowerManager returned.

 

PowerManager just IPowerManager stored in a member variable , PowerManager save the BinderProxy, BinderProxy cited Native BpBinder, you can communicate with the Server .

 

Server Client -side response to the request

 

Server receives a request from Client calls BBinder of transact processing requests , transact calls the virtual function onTransact, JavaBBinder inherited from BBinder, it will call the JavaBBinder :: onTransact, in JavaBBinder :: onTransact has the following one : < / p>  

  
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact, code, (int32_t)&data, (int32_t)reply, flags);
 
 

reverse call through JNI Java class methods . Earlier we know , Java implementation in Service , Service object , JavaBBinderHolder, JavaBBinder exist between the reference relationship , JavaBBinder members mObject references in Java Service object , such as here PowerManagerService, and in int_register_android_os_Binder through

 
  
gBinderOffsets.mExecTransact  = env->GetMethodID(clazz, "execTransact", "(IIII)Z");
 
 The Service is execTransact

method ( in fact, Binder method ) stored in the gBinderOffsets.mExecTransact in which to JavaBBinder :: onTransact will call Binder.execTransact. In Binder.execTransact call the onTransact, namely the implementation subclass Stub class onTransact method, onTransact value , in accordance with code executes the corresponding method is ultimately call the Service class ( inherited from Stub) in the corresponding method.

 

Summary

 

Java layer through JNI layer utilizes Native Binder, registered in the JNI function will create the Java layer Binder, BinderProxy, BinderProxy other classes and Native layer mappings. Java Layer Service inherited from the Java layer entity Binder class, class initialization Binder created when a JavaBBinderHolder as JavaBBinder container , JavaBBinder inherited from BBinder, Java layer Binder class reference JavaBBinderHolder, JavaBBinderHolder references JavaBBinder, JavaBBinder inherited from BBinder and reference Java layer the Binder class , these three reference each other , so that the Java layer Service entity can BBinder communicate with the driver .

 

process to the Java layer ServiceManager Send GET_SERVICE request, and then to the Native layer through JNI ServiceManager request service , Native layer ServiceManager return the requested service agent for you BpBinder, through javaObjectForIBinder function into the Native BbBinder Java layer corresponding BinderProxy, then through aidl generated Stub class asInterface method BinderProxy closed to the requested service proxy object , the proxy object references BinderProxy, BinderProxy internal preserved Native layer BpBinder, so that you can communicate with the driver .

 

When Server receives a request Client 's transact through BBinder call Server service , BBinder of transact call virtual functions onTransact, this will be transferred BBinder subclass JavaBBinder of onTransact, while JavaBinder :: onTransact through reverse JNI calls to Java layer Binder class execTransact, Binder.execTransact call onTransact ie Stub subclass of onTransact, then call the Service entity class code value ( inherited from Stub) corresponding method.

没有评论:

发表评论