《深入理解Android:卷III A》一一2.2Java层中的Binder分析

    xiaoxiao2023-07-13  144

    本节书摘来华章计算机出版社《深入理解Android:卷III A》一书中的第2章,第2.2节,作者:张大伟 更多章节内容可以访问云栖社区“华章计算机”公众号查看。1

    2.2Java层中的Binder分析

    2.2.1Binder架构总览如果读者读过卷I的第6章,相信就不会对Binder架构中代表Client的Bp端及代表Server的Bn端感到陌生。Java层中Binder实际上也是一个C/S架构,而且其在类的命名上尽量保持与Native层一致,因此可认为,Java层的Binder架构是Native层Binder架构的一个镜像。Java层的Binder架构中的成员如图2-1所示。由图2-1可知:

    图 2-1Java层中的Binder家族系统定义了一个IBinder接口类以及DeathRecepient接口。Binder类和BinderProxy类分别实现了IBinder接口。其中Binder类作为服务端的Bn的代表,而BinderProxy作为客户端的Bp的代表。系统中还定义了一个BinderInternal类。该类是一个仅供Binder框架使用的类。它内部有一个GcWatcher类,该类专门用于处理和Binder相关的垃圾回收。Java层同样提供一个用于承载通信数据的Parcel类。IBinder接口类中定义了一个叫FLAG_ONEWAY的整型变量,该变量的意义非常重要。当客户端利用Binder机制发起一个跨进程的函数调用时,调用方(即客户端)一般会阻塞,直到服务端返回结果。这种方式和普通的函数调用是一样的。但是在调用Binder函数时,在指明了FLAG_ONEWAY标志后,调用方只要把请求发送到Binder驱动即可返回,而不用等待服务端的结果,这就是一种所谓的非阻塞方式。在Native层中,涉及的Binder调用基本都是阻塞的,但是在Java层的framework中,使用FLAG_ONEWAY进行Binder调用的情况非常多,以后经常会碰到。使用FLAG_ONEWAY进行函数调用的程序在设计上有什么特点?这里简单分析一下:对使用FLAG_ONEWAY的函数来说,客户端仅向服务端发出请求,但是并不能确定服务端是否处理了该请求。所以,客户端一般会向服务端注册一个回调(同样是跨进程的Binder调用),一旦服务端处理了该请求,就会调用此回调来通知客户端处理结果。当然,这种回调函数也大多采用FLAG_ONEWAY的方式。2.2.2初始化Java层Binder框架虽然Java层Binder系统是Native层Binder系统的一个镜像,但这个镜像终归还需借助Native层Binder系统来开展工作,即镜像和Native层Binder有着千丝万缕的关系,一定要在Java层Binder正式工作之前建立这种关系。下面分析Java层Binder框架是如何初始化的。在Android系统中,在Java初创时期,系统会提前注册一些JNI函数,其中有一个函数专门负责搭建Java Binder和Native Binder交互关系,该函数是register_android_os_Binder,代码如下:[android_util_Binder.cpp-->register_android_os_Binder()]int register_android_os_Binder(JNIEnv* env){

    // 初始化Java Binder类和Native层的关系 if (int_register_android_os_Binder(env) < 0) return -1; // 初始化Java BinderInternal类和Native层的关系 if (int_register_android_os_BinderInternal(env) < 0) return -1; // 初始化Java BinderProxy类和Native层的关系 if (int_register_android_os_BinderProxy(env) < 0) return -1; ...... return 0;

    }据上面的代码可知,register_android_os_Binder函数完成了Java Binder架构中最重要的三个类的初始化工作。

    Binder类的初始化int_register_android_os_Binder函数完成了Binder类的初始化工作,代码如下:

    [android_util_Binder.cpp-->int_register_android_os_Binder()]static int int_register_android_os_Binder(JNIEnv* env){

    jclass clazz; //kBinderPathName为Java层中Binder类的全路径名,“android/os/Binder“ clazz = env->FindClass(kBinderPathName); /* gBinderOffSets是一个静态类对象,它专门保存Binder类的一些在JNI层中使用的信息, 如成员函数execTranscat的methodID,Binder类中成员mObject的fildID */ gBinderOffsets.mClass = (jclass) env->NewGlobalRef(clazz); gBinderOffsets.mExecTransact = env->GetMethodID(clazz, "execTransact", "(IIII)Z"); gBinderOffsets.mObject = env->GetFieldID(clazz, "mObject", "I"); // 注册Binder类中native函数的实现 return AndroidRuntime::registerNativeMethods( env, kBinderPathName, gBinderMethods, NELEM(gBinderMethods));

    }由上面代码可知,gBinderOffsets对象保存了和Binder类相关的某些在JNI层中使用的信息。它们将用来在JNI层对Java层的Binder对象进行操作。execTransact()函数以及mObject成员的用途将在2.2.3节介绍。如果读者对JNI不是很清楚,可参阅卷I第2章“深入理解JNI”。

    BinderInternal类的初始化下一个初始化的类是BinderInternal,其代码在int_register_android_os_BinderInternal函数中。

    [android_util_Binder.cpp-->int_register_android_os_BinderInternal()]static int int_register_android_os_BinderInternal(JNIEnv* env){ jclass clazz; // 根据BinderInternal的全路径名找到代表该类的jclass对象。全路径名为 // “com/android/internal/os/BinderInternal” clazz = env->FindClass(kBinderInternalPathName); //gBinderInternalOffsets也是一个静态对象,用来保存BinderInternal类的一些信息 gBinderInternalOffsets.mClass = (jclass) env->NewGlobalRef(clazz); // 获取forceBinderGc的methodID gBinderInternalOffsets.mForceGc

    = env->GetStaticMethodID(clazz, "forceBinderGc", "()V");

    // 注册BinderInternal类中native函数的实现 return AndroidRuntime::registerNativeMethods(

    env, kBinderInternalPathName, gBinderInternalMethods, NELEM(gBinderInternalMethods));

    }int_register_android_os_BinderInternal的工作内容和int_register_android_os_Binder的工作内容类似:获取一些有用的methodID和fieldID。这表明JNI层一定会向上调用Java层的函数。注册相关类中native函数的实现。

    BinderProxy类的初始化int_register_android_os_BinderProxy完成了BinderProxy类的初始化工作,代码稍显复杂,如下所示:

    [android_util_Binder.cpp -->int_register_android_os_BinderProxy()]static int int_register_android_os_BinderProxy(JNIEnv* env){

    jclass clazz; // ① gWeakReferenceOffsets用来和WeakReference类打交道 clazz = env->FindClass("java/lang/ref/WeakReference"); gWeakReferenceOffsets.mClass = (jclass) env->NewGlobalRef(clazz); // 获取WeakReference类get函数的MethodID gWeakReferenceOffsets.mGet= env->GetMethodID(clazz, "get", "()Ljava/lang/Object;"); // ② gErrorOffsets用来和Error类打交道 clazz = env->FindClass("java/lang/Error"); gErrorOffsets.mClass = (jclass) env->NewGlobalRef(clazz); // ③ gBinderProxyOffsets用来和BinderProxy类打交道 clazz = env->FindClass(kBinderProxyPathName); gBinderProxyOffsets.mClass = (jclass) env->NewGlobalRef(clazz); gBinderProxyOffsets.mConstructor= env->GetMethodID(clazz, "<init>", "()V"); ...... //获取BinderProxy的一些信息 // ④ gClassOffsets用来和Class类打交道 clazz = env->FindClass("java/lang/Class"); gClassOffsets.mGetName =env->GetMethodID(clazz, "getName", "()Ljava/lang/String;"); // 注册BinderProxy native函数的实现 return AndroidRuntime::registerNativeMethods(env, kBinderProxyPathName,gBinderProxyMethods, NELEM(gBinderProxyMethods));

    }据上面代码可知,int_register_android_os_BinderProxy函数除了初始化BinderProxy类外,还获取了WeakReference类和Error类的一些信息。看来BinderProxy对象的生命周期会委托WeakReference来管理,所以JNI层会获取该类get函数的MethodID。至此,Java Binder几个重要成员的初始化已完成,同时在代码中定义了几个全局静态对象,分别是gBinderOffsets、gBinderInternalOffsets和gBinderProxyOffsets。框架的初始化其实就是提前获取一些JNI层的使用信息,如类成员函数的MethodID、类成员变量的fieldID等。这项工作是必需的,因为它能节省每次使用时获取这些信息的时间。当Binder调用频繁时,这些时间累积起来还是不容小觑的。另外,这个过程中所创建的几个全局静态对象为JNI层访问Java层的对象提供了依据。而在每个初始化函数中所执行的registerNativeMethods()方法则为Java层访问JNI层打通了道路。换句话说,Binder初始化的工作就是通过JNI建立起Native Binder与Java Binder之间互相通信的桥梁。下面通过一个例子来分析Java Binder的工作流程。2.2.3窥一斑,可见全豹乎这个例子源自ActivityManagerService,我们试图通过它揭示Java层Binder的工作原理。先来描述一下该例子的分析步骤:首先分析AMS如何将自己注册到ServiceManager。然后分析AMS如何响应客户端的Binder调用请求。本例的起点是setSystemProcess,其代码如下所示:[ActivityManagerService.java-->ActivityManagerService.setSystemProcess()]public static void setSystemProcess() { try {

    ActivityManagerService m = mSelf; // 将ActivityManagerService服务注册到ServiceManager中 ServiceManager.addService("activity", m);......

    } catch { ... } return;}上面所示代码行的目的是将ActivityManagerService服务(以后简称AMS)加到ServiceManager中。在整个Android系统中有一个Native的ServiceManager(以后简称SM)进程,它统筹管理Android系统上的所有服务。成为一个服务的首要条件是先在SM中注册。下面来看Java层的服务是如何向SM注册的。

    向ServiceManager注册服务(1)创建ServiceManagerProxy

    向SM注册服务的函数叫addService,其代码如下:[ServiceManager.java-->ServiceManager.addService()]public static void addService(String name, IBinder service) {

    try { // getIServiceManager返回什么 getIServiceManager().addService(name, service); } ......

    }首先需要搞清楚getIServiceManager()方法返回的是一个什么对象?参考其实现:[ServiceManager.java-->ServiceManager.getIServiceManager()]private static IServiceManager getIServiceManager() {

    ...... // 调用asInterface,传递的参数类型为IBinder sServiceManager = ServiceManagerNative.asInterface( BinderInternal.getContextObject()); return sServiceManager;

    }asInterface()方法的参数为BinderInternal.getContextObject()的返回值。于是这个简短的方法中有两个内容值得讨论:BinderInternal.getContextObject()以及asInterface()。BinderInternal.getContextObject()方法是一个native函数,参考其实现:[android_util_Binder.cpp-->android_os_BinderInternal_getContextObject()]static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz){

    /* 下面这句代码在卷I第6章详细分析过,它将返回一个BpProxy对象,其中 NULL(即0,用于标识目的端)指定Proxy通信的目的端是ServiceManager */ sp<IBinder> b = ProcessState::self()->getContextObject(NULL); // 由Native对象创建一个Java对象,下面分析该函数 return javaObjectForIBinder(env, b);

    }可见,Java层的ServiceManager需要在Native层获取指向Native进程中ServiceManager的BpProxy。这个BpProxy不能由Java层的ServiceManager直接使用,于是android_os_BinderInteral_getContextObject()函数通过javaObjectForIBinder()函数将创建一个封装了这个BpProxy的一个Java对象并返回给调用者。ServiceManager便可以通过这个Java对象实现对BpProxy的访问。参考这个Java对象的创建过程:[android_util_Binder.cpp-->javaObjectForIBinder()]jobject javaObjectForIBinder(JNIEnv* env, const sp& val){

    // mProxyLock是一个全局静态CMutex对象 AutoMutex _l(mProxyLock); /* val对象实际类型是BpBinder,读者可自行分析BpBinder.cpp中的findObject函数。 事实上,在Native层的BpBinder中有一个ObjectManager,它用来管理在Native BpBinder上 创建的Java BpBinder对象。下面这个findObject用来判断gBinderProxyOffsets是否已经 保存在ObjectManager中。如果是,那就需要删除这个旧的对象*/ jobject object = (jobject)val->findObject(&gBinderProxyOffsets); if (object != NULL) { jobject res = env->CallObjectMethod(object, gWeakReferenceOffsets.mGet); android_atomic_dec(&gNumProxyRefs); val->detachObject(&gBinderProxyOffsets); env->DeleteGlobalRef(object); } // ① 创建一个新的BinderProxy对象,并将它注册到Native BpBinder对象的ObjectManager中 object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor); if (object != NULL) { /* ② 把Native层的BpProxy的指针保存到BinderProxy对象的成员字段mObject中。 于是BinderProxy对象的Native方法可以通过mObject获取BpProxy对象的指针。 这个操作是将BinderProxy与BpProxy联系起来的纽带 */ env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get()); val->incStrong(object); jobject refObject = env->NewGlobalRef( env->GetObjectField(object, gBinderProxyOffsets.mSelf)); /* 将这个新创建的BinderProxy对象注册(attach)到BpBinder的ObjectManager中,同时 注册一个回收函数proxy_cleanup。当BinderProxy对象撤销(detach)的时候,该函数会 被调用,以释放一些资源。读者可自行研究proxy_cleanup函数*/ val->attachObject(&gBinderProxyOffsets, refObject, jnienv_to_javavm(env), proxy_cleanup); // DeathRecipientList保存了一个用于死亡通知的list sp<DeathRecipientList> drl = new DeathRecipientList; drl->incStrong((void*)javaObjectForIBinder); //将死亡通知list和BinderProxy对象联系起来 env->SetIntField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jint>(drl.get())); // 增加该Proxy对象的引用计数 android_atomic_inc(&gNumProxyRefs); /* 下面这个函数用于垃圾回收。创建的Proxy对象一旦超过200个,该函数将调用BinderInter 类的ForceGc做一次垃圾回收 */ incRefsCreated(env); } return object;

    }BinderInternal.getContextObject的代码有点多,简单整理一下,可知该函数完成了以下两个工作:创建了一个Java层的BinderProxy对象。通过JNI,该BinderProxy对象和一个Native的BpProxy对象挂钩,而该BpProxy对象的通信目标就是ServiceManager。接下来讨论asInterface()方法,大家还记得在Native层Binder中那个著名的interface_cast宏吗?在Java层中,虽然没有这样的宏,但是定义了一个类似的函数asInterface。下面来分析ServiceManagerNative类的asInterface函数,其代码如下:[ServiceManagerNative.java-->ServiceManagerNative.asInterface()]static public IServiceManager asInterface(IBinder obj){

    ...... // 以obj为参数,创建一个ServiceManagerProxy对象 return new ServiceManagerProxy(obj);

    }上面代码和Native层interface_cast宏非常类似,都是以一个BpProxy对象为参数构造一个和业务相关的Proxy对象,例如这里的ServiceManagerProxy对象。ServiceManagerProxy对象的各个业务函数会将相应请求打包后交给BpProxy对象,最终由BpProxy对象发送给Binder驱动以完成一次通信。实际上BpProxy也不会直接和Binder驱动交互,真正和Binder驱动交互的是IPCThreadState。(2)addService函数分析现在来分析ServiceManagerProxy的addService函数,其代码如下:[ServcieManagerNative.java-->ServiceManagerProxy.addService()]public void addService(String name, IBinder service)

    throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IServiceManager.descriptor); data.writeString(name); // 注意下面这个writeStrongBinder函数,后面我们会详细分析它 data.writeStrongBinder(service); /* mRemote实际上就是BinderProxy对象,调用它的transact,将封装好的请求数据发送出去 */ mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0); reply.recycle(); data.recycle();

    }BinderProxy的transact是一个native函数,其实现函数的代码如下所示:[android_util_Binder.cpp-->android_os_BinderProxy_transact()]static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,

    jint code, jobject dataObj, jobject replyObj, jint flags)

    {

    ...... // 从Java的Parcel对象中得到作为参数的Native的Parcel对象 Parcel* data = parcelForJavaObject(env, dataObj); if (data == NULL) { return JNI_FALSE; } // 得到一个用于接收回复的Parcel对象 Parcel* reply = parcelForJavaObject(env, replyObj); if (reply == NULL && replyObj != NULL) { return JNI_FALSE; } // 从Java的BinderProxy对象中得到之前已经创建好的那个Native的BpBinder对象 IBinder* target = (IBinder*) env->GetIntField(obj, gBinderProxyOffsets.mObject); ...... // 通过Native的BpBinder对象将请求发送给ServiceManager status_t err = target->transact(code, *data, reply, flags); ...... signalExceptionForError(env, obj, err); return JNI_FALSE;

    }看了上面的代码你会发现,Java层的Binder最终还是要借助Native的Binder进行通信的。从架构的角度看,在Java中搭建了一整套框架,如IBinder接口、Binder类和BinderProxy类。但是从通信角度看,不论架构的编写采用的是Native语言还是Java语言,只要把请求传递到Binder驱动就可以了,所以通信的目的是向binder发送请求和接收回复。在这个目的之上,考虑到软件的灵活性和可扩展性,于是编写了一个架构。反过来说,也可以不使用架构(即没有使用任何接口、派生之类的东西)而直接和binder交互,例如ServiceManager作为Binder的一个核心程序,就是直接读取/dev/binder设备,获取并处理请求。从这一点上看,Binder的目的虽然简单(即打开binder设备,然后读请求和写回复),但是架构复杂(编写各种接口类和封装类等)。我们在研究源码时,一定要先搞清楚目的。实现只不过是达到该目的的一种手段和方式。脱离目的的实现,如缘木求鱼,很容易偏离事物本质。在对addService进行分析时曾提示writeStrongBinder是一个特别的函数。那么它特别在哪里呢?下面将给出解释。(3)三人行之Binder、JavaBBinderHolder和JavaBBinderActivityManagerService从ActivityManagerNative类派生,并实现了一些接口,其中和Binder相关的只有这个ActivityManagerNative类,其原型如下:[ActivityManagerNative.java-->ActivityManagerNative]public abstract class ActivityManagerNative

    extends Binder implements IActivityManager

    ActivityManagerNative从Binder派生,并实现了IActivityManager接口。下面来看ActivityManagerNative的构造函数:[ActivityManagerNative.java-->ActivityManagerNative.ActivityManagerNative()]public ActivityManagerNative() {

    attachInterface(this, descriptor);// 该函数很简单,读者可自行分析

    }而ActivityManagerNative父类的构造函数则是Binder的构造函数:[Binder.java-->Binder.Binder()]public Binder() {

    init();

    }Binder构造函数会调用native的init函数,其实现的代码如下:[android_util_Binder.cpp-->android_os_Binder_init()]static void android_os_Binder_init(JNIEnv* env, jobject obj){

    // 创建一个JavaBBinderHolder对象 JavaBBinderHolder* jbh = new JavaBBinderHolder(); bh->incStrong((void*)android_os_Binder_init); // 将这个JavaBBinderHolder对象保存到Java Binder对象的mObject成员中 env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);

    }从上面代码可知,Java的Binder对象将和一个Native的JavaBBinderHolder对象相关联。那么,JavaBBinderHolder是何方神圣呢?其定义如下:[android_util_Binder.cpp-->JavaBBinderHolder]class JavaBBinderHolder : public RefBase{public:

    sp<JavaBBinder> get(JNIEnv* env, jobject obj) { AutoMutex _l(mLock); sp<JavaBBinder> b = mBinder.promote(); if (b == NULL) { // 创建一个JavaBBinder,obj实际上是Java层中的Binder对象 b = new JavaBBinder(env, obj); mBinder = b; } return b; } ......

    private:

    Mutex mLock; wp<JavaBBinder> mBinder;

    };从派生关系上可以发现,JavaBBinderHolder仅从RefBase派生,所以它不属于Binder家族。Java层的Binder对象为什么会和Native层的一个与Binder家族无关的对象绑定呢?仔细观察JavaBBinderHolder的定义可知:JavaBBinderHolder类的get函数中创建了一个JavaBBinder对象,这个对象就是从BnBinder派生的。那么,这个get函数是在哪里调用的?答案在下面这句代码中://其中,data是Parcel对象,service此时还是ActivityManagerServicedata.writeStrongBinder(service);writeStrongBinder会做一个替换工作,下面是它的native代码实现:[android_util_Binder.cpp-->android_os_Parcel_writeStrongBinder()]static void android_os_Parcel_writeStrongBinder(JNIEnv* env,

    jobject clazz, jobject object)

    {

    /* parcel是一个Native的对象,writeStrongBinder的真正参数是 ibinderForJavaObject()的返回值 */ const status_t err = parcel->writeStrongBinder( ibinderForJavaObject(env, object));

    }[android_util_Binder.cpp-->ibinderForJavaObject()]sp ibinderForJavaObject(JNIEnv* env, jobject obj){

    /* 如果Java的obj是Binder类,则首先获得JavaBBinderHolder对象,然后调用它的get()函数。 而这个get将返回一个JavaBBinder */ if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) { JavaBBinderHolder* jbh = (JavaBBinderHolder*)env->GetIntField(obj, gBinderOffsets.mObject); return jbh != NULL ? jbh->get(env, obj) : NULL; } // 如果obj是BinderProxy类,则返回Native的BpBinder对象 if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) { return (IBinder*) env->GetIntField(obj, gBinderProxyOffsets.mObject); }

    return NULL;}根据上面的介绍会发现,addService实际添加到Parcel的并不是AMS本身,而是一个叫JavaBBinder的对象。而最终传递到Binder驱动的正是这个JavaBBinder对象。读者此时容易想到,Java层中所有的Binder对应的都是这个JavaBBinder。当然,不同的Binder对象对应不同的JavaBBinder对象。图2-2展示了Java Binder、JavaBBinderHolder和JavaBBinder的关系。从图2-2可知:Java层的Binder通过mObject指向一个Native层的JavaBBinderHolder对象。Native层的JavaBBinderHolder对象通过mBinder成员变量指向一个Native的JavaBBinder对象。Native的JavaBBinder对象又通过mObject变量指向一个Java层的Binder对象。为什么不直接让Java层的Binder对象指向Native层的JavaBBinder对象呢?由于缺乏设计文档,这里不便妄加揣测,但从JavaBBinderHolder的实现上来分析,估计和垃圾回收(内存管理)有关,因为JavaBBinderHolder中的mBinder对象的类型被定义成弱引用wp了。对此有更好的解释的读者,不妨与大家分享一下。

    ActivityManagerService响应请求初见JavaBBinde时,多少有些吃惊。回想一下Native层的Binder架构:虽然在代码中调用的是Binder类提供的接口,但其对象却是一个实际的服务端对象,例如MediaPlayerService对象、AudioFlinger对象。

    而在Java层的Binder架构中,JavaBBinder却是一个和业务完全无关的对象。那么,这个对象如何实现不同业务呢?为回答此问题,我们必须查看它的onTransact函数。当收到请求时,系统会调用这个函数。关于这个问题,建议读者阅读卷I第6章“深入理解Binder”。[android_util_Binder.cpp-->JavaBBinder::onTransact()]virtual status_t onTransact(

    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)

    {

    JNIEnv* env = javavm_to_jnienv(mVM); IPCThreadState* thread_state = IPCThreadState::self(); ....... // 调用Java层Binder对象的execTranscat函数 jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,code, (int32_t)&data, (int32_t)reply, flags); ...... return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;

    }就本例而言,上面代码中的mObject就是ActivityManagerService,现在调用它的exec-Transact()方法,该方法在Binder类中实现,具体代码如下:[Binder.java-->Binder.execTransact()]private boolean execTransact(int code, int dataObj, int replyObj,int flags) {

    Parcel data = Parcel.obtain(dataObj); Parcel reply = Parcel.obtain(replyObj); boolean res; try { //调用onTransact函数,派生类可以重新实现这个函数,以完成业务功能 res = onTransact(code, data, reply, flags); } catch { ... } reply.recycle(); data.recycle(); return res;

    }ActivityManagerNative类实现了onTransact函数,代码如下:[ActivityManagerNative.java-->ActivityManagerNative.onTransact()]public boolean onTransact(int code, Parcel data, Parcel reply, int flags)

    throws RemoteException { switch (code) { case START_ACTIVITY_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder b = data.readStrongBinder(); ...... //再由ActivityManagerService实现业务函数startActivity int result = startActivity(app, intent, resolvedType, grantedUriPermissions, grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler); reply.writeNoException(); reply.writeInt(result); return true; } .... // 处理其他请求的情况 }

    }由此可以看出,JavaBBinder仅是一个传声筒,它本身不实现任何业务函数,其工作是:当它收到请求时,只是简单地调用它所绑定的Java层Binder对象的exeTransact。该Binder对象的exeTransact调用其子类实现的onTransact函数。子类的onTransact函数将业务又派发给其子类来完成。请读者务必注意其中的多层继承关系。通过这种方式,来自客户端的请求就能传递到正确的Java Binder对象了。图2-3展示AMS响应请求的整个流程。在图2-3中,右上角的大方框表示AMS对象,其中的虚线箭头表示调用子类重载的函数。

    图2-3 AMS响应请求的流程2.2.4理解AIDL经过上一节的介绍,你已经明白在Java层Binder的架构中,Bp端可以通过BinderProxy的transact()方法与Bn端发送请求,而Bn端通过继承Binder类重写onTransact()接收并处理来自Bp端的请求。这个结构非常清晰而且简单,但是实现起来却颇为烦琐。于是Android提供了AIDL语言以及AIDL解释器自动生成一个服务的Bn端,即Bp端用于处理Binder通信的代码。AIDL的语法与定义一个Java接口的语法非常相似。为了避免业务实现对分析的干扰,本节通过一个最简单的例子对AIDL的原理进行介绍。[IMyServer.aidl]package com.understanding.samples;interface IMyServer {

    int foo(String str);

    }IMyServer.aidl定义了一个名为IMyServer的Binder服务,并提供了一个可以跨Binder调用的接口foo()。可以通过aidl工具将其解析为一个实现了Bn端及Bp端通过Binder进行通信的Java源代码。具体命令如下:aidl com/understanding/samples/IMyServer.aidl生成的IMyServer.java可以在com/understanding/samples/文件夹下找到。读者可以阅读aidl有关的文档了解此工具的详细功能。[IMyServer.java-->IMyServer]package com.understanding.samples;/* ① 首先,IMyServer.aidl被解析为一个Java接口IMyServer。这个接口定义了AIDL文件中所定义 的接口foo() */public interface IMyServer extends android.os.IInterface {

    /* ② aidl工具生成了一个继承自IMyServer接口的抽象类IMyServer.Stub。这个抽象类实现了Bn 端通过onTransact()方法接收来自Bp端的请求的代码。本例中的foo()方法在这个类中会被定义 成一个抽象方法。因为aidl工具根本不知道foo()方法是做什么的,它只能在onTransact()中得知Bp端希 望对foo()方法进行调用,所以Stub类是抽象的 */ public static abstract class Stub extends android.os.Binder implements com.understanding.samples.IMyServer { ...... // Stub类的其他实现 /* onTransact()根据code的值选择调用IMyServer接口中的不同方法。本例中 TRANSACTION_foo意味着需要通过调用foo()方法完成请求 */ public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { ...... case TRANSACTION_foo: { ...... // 从data中读取参数_arg0 // Stub类的子类需要实现foo()方法 int _result = this.foo(_arg0); ...... // 向reply中写入_result return true; } } return super.onTransact(code, data, reply, flags); } /* ③ aidl工具还生成了一个继承自IMyServer接口的类Proxy,它是Bp端的实现。与Bn端的Stub 类不同,它实现了foo()函数。因为foo()函数在Bp端的实现是确定的,即将参数存储到Parcel 中,然后执行transact()方法将请求发送给Bn端,然后从reply中读取返回值并返回给调 用者 */ private static class Proxy implements com.understanding.samples.IMyServer { ...... // Proxy类的其他实现 public int foo(java.lang.String str) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { ...... // 将参数str写入参数_data // mRemote就是指向IMyServer Bn端的BinderProxy mRemote.transact(Stub.TRANSACTION_foo, _data, _reply, 0); ......// 从_replay中读取返回值_result } finally { ...... } return _result; } } // TRANSACTION_foo常量用于定义foo()方法的code static final int TRANSACTION_foo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); } // 声明IMyServer所提供的接口 public int foo(java.lang.String str) throws android.os.RemoteException;

    }可见一个AIDL文件被aidl工具解析之后会有三个产物:IMyServer接口。它仅仅用来在Java中声明IMyServer.aidl中所声明的接口。IMyServer.Stub类。这个继承自Binder类的抽象类实现了Bn端与Binder通信相关的代码。IMyServer.Stub.Proxy类。这个类实现了Bp端与Binder通信相关的代码。在完成aidl的解析之后,为了实现一个Bn端,开发者需要继承IMyServer.Stub类并实现其抽象方法。如下所示:class MyServer extends IMyServer.Stub {

    int foo(String str) { // 做点什么都可以 return str.length(); }

    }于是每一个MyServer类的实例,都具有了作为Bn端的能力。典型的做法是将MyServer类的实例通过ServiceManager.addService()将其注册为一个系统服务,或者在一个Android标准Service的onBind()方法中将其作为返回值使之可以被其他进程访问。另外,也可以通过Binder调用将其传递给另外一个进程,使之成为一个跨进程的回调对象。那么Bp端将如何使用IMyServer.Proxy呢?在Bp端所在进程中,一旦获取了IMyServer的BinderProxy(通过ServiceManager.getService()、onServiceConnected()或者其他方式),就可以通过如下方式获得一个IMyServer.Proxy:// 其中binderProxy就是通过ServiceManager.getService()获取的IMyServer remote = IMyServer.Stub.asInterface(binderProxy);remote.foo(“Hello AIDL!”);IMyServer.Stub.asInterface()的实现如下:[IMyServer.java-->IMyServer.Stub.asInterface()]public static com.understanding.samples.IMyServer asInterface(

    android.os.IBinder obj) { ...... // 创建一个IMyServer.Stub.Proxy,其中参数obj将会被保存为Proxy类的mRemote成员 return new com.understanding.samples.IMyServer.Stub.Proxy(obj);

    }可见,AIDL使得构建一个Binder服务的工作大大简化了。2.2.5Java层Binder架构总结图2-4展示了Java层的Binder架构。根据图2-4可知:对代表客户端的BinderProxy来说,Java层的BinderProxy在Native层对应一个BpBinder对象。凡是从Java层发出的请求,首先从Java层的BinderProxy传递到Native层的BpBinder,继而由BpBinder将请求发送到Binder驱动。对代表服务端的Service来说,Java层的Binder在Native层有一个JavaBBinder对象。前面介绍过,所有Java层的Binder在Native层都对应为JavaBBinder,而JavaBBinder仅起到中转作用,即把来自客户端的请求从Native层传递到Java层。系统中依然只有一个Native的ServiceManager。

    图2-4Java层Binder架构至此,Java层的Binder架构已介绍完毕。从前面的分析可以看出,Java层的Binder非常依赖Native层的Binder。建议想进一步了解Binder的读者要深入了解这一问题,有必要阅读卷I的第6章。

    相关资源:敏捷开发V1.0.pptx
    最新回复(0)