《深入理解Android 卷III》第二章 深入理解Java Binder和MessageQueue

Posted gccbuaa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《深入理解Android 卷III》第二章 深入理解Java Binder和MessageQueue相关的知识,希望对你有一定的参考价值。

《深入理解android 卷III》即将公布。作者是张大伟。此书填补了深入理解Android Framework卷中的一个主要空白,即Android Framework中和UI相关的部分。在一个特别讲究颜值的时代。本书分析了Android 4.2中WindowManagerService、ViewRoot、Input系统、StatusBar、Wallpaper等重要“颜值绘制/处理”模块

注意,此处连载的节选是出版社未排版的内容。

第2章 深入理解Java Binder和MessageQueue

本章主要内容:

·  介绍Binder系统的Java层框架

·  介绍MessageQueue

本章所涉及的源码文件名称及位置:

·  IBinder.java

frameworks/base/core/java/android/os/IBinder.java

·  Binder.java

frameworks/base/core/java/android/os/Binder.java

·  BinderInternal.java

frameworks/base/core/java/com/android/intenal/os/BinderInternal.java

·  android_util_Binder.cpp

frameworks/base/core/jni/android_util_Binder.cpp

·  SystemServer.java

frameworks/base/services/java/com/android/servers/SystemServer.java

·  ActivityManagerService.java

frameworks/base/services/java/com/android/servers/ActivityManagerService.java

·  ServiceManager.java

frameworks/base/core/java/android/os/ServiceManager.java

·  ServcieManagerNative.java

frameworks/base/core/java/android/os/ServcieManagerNative.java

·  MessageQueue.java

frameworks/base/core/java/android/os/MessageQueue.java

·  android_os_MessageQueue.cpp

frameworks/base/core/jni/android_os_MessageQueue.cpp

·  Looper.cpp

frameworks/base/native/android/Looper.cpp

·  Looper.h

frameworks/base/include/utils/Looper.h

·  android_app_NativeActivity.cpp

frameworks/base/core/jni/android_app_NativeActivity.cpp

2.1 概述

由于本书所介绍的内容主要是以Java层的系统服务为主,因此Binder相关的应用在本书中比比皆是。

而MessageQueue作为Android中重要的任务调度工具,它的使用也是随处可见。所以本书有必要对这两个工具有所介绍。依据邓凡平的允许与推荐,本章由卷II第2章升级到4.2.2而来,并且添加了对AIDL相关的知识点的分析。

以本章作为本书Android分析之旅的开篇,将重点关注两个基础知识点,它们是:

·  Binder系统在Java世界是怎样布局和工作的。

·  MessageQueue的新职责。

先来分析Java层中的Binder。

建议 读者先阅读《深入理解Android:卷I》(以下简称“卷I”)的第6章“深入理解Binder”。网上有样章可下载。

2.2 Java层中的Binder分析

2.2.1 Binder架构总览

假设读者读过卷I第6章“深入理解Binder”。相信就不会对Binder架构中代表Client的Bp端及代表Server的Bn端感到陌生。Java层中Binder实际上也是一个C/S架构,并且其在类的命名上尽量保持与Native层一致。因此可觉得,Java层的Binder架构是Native层Binder架构的一个镜像。Java层的Binder架构中的成员如图2-1所看到的。


图 2 - 1 Java层中的Binder家族

由图2-1可知:

·   系统定义了一个IBinder接口类以及DeathRecepient接口。

·  Binder类和BinderProxy类分别实现了IBinder接口。当中Binder类作为服务端的Bn的代表,而BinderProxy作为client的Bp的代表。

·  系统中还定义一个BinderInternal类。

该类是一个仅供Binder框架使用的类。它内部有一个GcWatcher类,该类专门用于处理和Binder相关的垃圾回收。

·  Java层相同提供一个用于承载通信数据的Parcel类。

注意 IBinder接口类中定义了一个叫FLAG_ONEWAY的整型,该变量的意义非常重要。当client利用Binder机制发起一个跨进程的函数调用时,调用方(即client)通常会堵塞。直到服务端返回结果。这样的方式和普通的函数调用是一样的。

可是在调用Binder函数时,在指明了FLAG_ONEWAY标志后。调用方仅仅要把请求发送到Binder驱动就可以返回,而不用等待服务端的结果,这就是一种所谓的非堵塞方式。在Native层中,涉及的Binder调用基本都是堵塞的。可是在Java层的framework中。使用FLAG_ONEWAY进行Binder调用的情况非常多,以后经常会碰到。

思考 使用FLAG_ONEWAY进行函数调用的程序在设计上有什么特点?这里简单分析一下:对于使用FLAG_ONEWAY的函数来说,client仅向服务端发出了请求,可是并不能确定服务端是否处理了该请求。

所以。client通常会向服务端注冊一个回调(相同是跨进程的Binder调用),一旦服务端处理了该请求,就会调用此回调来通知client处理结果。当然,这样的回调函数也大多採用FLAG_ONEWAY的方式。

2.2.2 初始化Java层Binder框架

尽管Java层Binder系统是Native层Binder系统的一个Mirror,但这个Mirror终归还需借助Native层Binder系统来开展工作,即Mirror和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;

    ......

    return0;

}

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

1. 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)

{

    jclassclazz;

   //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函数的实现

    returnAndroidRuntime::registerNativeMethods(

                            env,kBinderPathName,

                            gBinderMethods,NELEM(gBinderMethods));

}

从上面代码可知。gBinderOffsets对象保存了和Binder类相关的某些在JNI层中使用的信息。

它们将用来在JNI层对Java层的Binder对象进行操作。

execTransact()函数以及mObject成员的用途将在2.2.3节介绍。

建议 假设读者对JNI不是非常清楚。可參阅卷I第2章“深入理解JNI”。

2. BinderInternal类的初始化

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

[android_util_Binder.cpp-->int_register_android_os_BinderInternal()]

static intint_register_android_os_BinderInternal(JNIEnv* env)

{

   jclassclazz;

   // 依据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函数的实现

   returnAndroidRuntime::registerNativeMethods(

                         env,kBinderInternalPathName,

                        gBinderInternalMethods, NELEM(gBinderInternalMethods));

}

int_register_android_os_BinderInternal的工作内容和int_register_android_os_Binder的工作内容相似:

·  获取一些实用的methodID和fieldID。这表明JNI层一定会向上调用Java层的函数。

·  注冊相关类中native函数的实现。

3. BinderProxy类的初始化

int_register_android_os_BinderProxy完毕了BinderProxy类的初始化工作,代码稍显复杂。例如以下所看到的:

[android_util_Binder.cpp-->int_register_android_os_BinderProxy()]

static intint_register_android_os_BinderProxy(JNIEnv* env)

{

    jclassclazz;

  

    // ① 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函数的实现

    returnAndroidRuntime::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怎样响应client的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系统上的全部Service。成为一个Service的首要条件是先在SM中注冊。以下来看Java层的Service是怎样向SM注冊的。

1. 向ServiceManager注冊服务

(1)创建ServiceManagerProxy

向SM注冊服务的函数叫addService。其代码例如以下:

[ServiceManager.java-->ServiceManager.addService()]

public static void addService(String name, IBinderservice) {

    try {

        //getIServiceManager返回什么

       getIServiceManager().addService(name, service);

    }

    ......

}

首先须要搞清楚getIServiceManager()方法返回的是一个什么对象呢?參考事实上现:

[ServiceManager.java-->ServiceManager.getIServiceManager()]

private static IServiceManagergetIServiceManager() {

    ......

    // 调用asInterface。传递的參数类型为IBinder       

   sServiceManager = ServiceManagerNative.asInterface(

                       BinderInternal.getContextObject());

    returnsServiceManager;

}

asInterface()方法的參数为BinderInternal.getContextObject()的返回值。于是这个简短的方法中有两个内容值得讨论:BinderInternal.getContextObject()以及asInterface()。

BinderInternal.getContextObject()方法是一个native的函数,參考事实上现:

[android_util_Binder.cpp-->android_os_BinderInternal_getContextObject()]

static jobjectandroid_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)

{

    /* 以下这句代码在卷I第6章具体分析过。它将返回一个BpProxy对象,当中

      NULL(即0,用于标识目的端)指定Proxy通信的目的端是ServiceManager*/

   sp<IBinder> b = ProcessState::self()->getContextObject(NULL);

    // 由Native对象创建一个Java对象,以下分析该函数

    returnjavaObjectForIBinder(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, constsp<IBinder>& val)

{

    //mProxyLock是一个全局的静态CMutex对象

   AutoMutex _l(mProxyLock);

 

    /* val对象实际类型是BpBinder。读者可自行分析BpBinder.cpp中的findObject函数。

      事实上,在Native层的BpBinder中有一个ObjectManager,它用来管理在Native BpBinder

      上创建的Java BpBinder对象。以下这个findObject用来推断gBinderProxyOffsets

      是否已经保存在ObjectManager中。

假设是。那就须要删除这个旧的object */

    jobjectobject = (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);

    }

    returnobject;

}

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(IBinderobj)

{

    ......// 以obj为參数。创建一个ServiceManagerProxy对象

    returnnew 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, IBinderservice)

                           throwsRemoteException {

    Parceldata = Parcel.obtain();

    Parcelreply = 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 jbooleanandroid_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_terr = target->transact(code, *data, reply, flags);

    ......

    signalExceptionForError(env,obj, err);

    returnJNI_FALSE;

}

看了上面的代码会发现,Java层的Binder终于还是要借助Native的Binder进行通信的。

说明 从架构的角度看,在Java中搭建了一整套框架,如IBinder接口,Binder类和BinderProxy类。可是从通信角度看,不论架构的编写採用的是Native语言还是Java语言,仅仅要把请求传递到Binder驱动就能够了,所以通信的目的是向binder发送请求和接收回复。

在这个目的之上,考虑到软件的灵活性和可扩展性。于是编写了一个架构。

反过来说,也能够不使用架构(即没有使用不论什么接口、派生之类的东西)而直接和binder交互,比如ServiceManager作为Binder的一个核心程序。就是直接读取/dev/binder设备。获取并处理请求。从这一点上看,Binder的目的虽是简单的(即打开binder设备,然后读请求和写回复)。可是架构是复杂的(编写各种接口类和封装类等)。

我们在研究源码时。一定要先搞清楚目的。实现仅仅只是是达到该目的的一种手段和方式。脱离目的的实现,如缘木求鱼。非常easy偏离事物本质。

在对addService进行分析时曾提示writeStrongBinder是一个特别的函数。那么它特别在哪里呢?以下将给出解释。

(3)三人行之Binder、JavaBBinderHolder和JavaBBinder

ActivityManagerService从ActivityManagerNative类派生,并实现了一些接口。当中和Binder的相关的仅仅有这个ActivityManagerNative类。其原型例如以下:

[ActivityManagerNative.java-->ActivityManagerNative]

public abstract class ActivityManagerNative

                          extends Binder

                          implementsIActivityManager

ActivityManagerNative从Binder派生,并实现了IActivityManager接口。以下来看ActivityManagerNative的构造函数:

[ActivityManagerNative.java-->ActivityManagerNative.ActivityManagerNative()]

public ActivityManagerNative() {

   attachInterface(this, descriptor);// 该函数非常easy,读者可自行分析

}

而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此时还是ActivityManagerService

data.writeStrongBinder(service);

writeStrongBinder会做一个替换工作,以下是它的native代码实现:

[android_util_Binder.cpp-->android_os_Parcel_writeStrongBinder()]

static voidandroid_os_Parcel_writeStrongBinder(JNIEnv* env,

                                               jobject clazz, jobject object)

{

    /*parcel是一个Native的对象,writeStrongBinder的真正參数是

     ibinderForJavaObject()的返回值*/

    conststatus_t err = parcel->writeStrongBinder(

                                   ibinderForJavaObject(env, object));

}

[android_util_Binder.cpp-->ibinderForJavaObject()]

sp<IBinder> 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);

    }

   returnNULL;

}

依据上面的介绍会发现,addService实际加入到Parcel的并非AMS本身,而是一个叫JavaBBinder的对象。

正是将它终于传递到Binder驱动。

读者此时easy想到,Java层中全部的Binder相应的都是这个JavaBBinder。当然。不同的Binder对象相应不同的JavaBBinder对象。

图2-2展示了Java Binder、JavaBBinderHolder和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了。

建议 对此有更好的解释的读者,最好还是与大家分享一下。

2. 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函数

    jbooleanres = env->CallBooleanMethod(mObject,

                    gBinderOffsets.mExecTransact,code,

                   (int32_t)&data, (int32_t)reply, flags);

    ......

    returnres != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;

}

就本例而言,上面代码中的mObject就是ActivityManagerService,如今调用它的execTransact()方法,该方法在Binder类中实现。具体代码例如以下:

[Binder.java-->Binder.execTransact()]

private boolean execTransact(int code, intdataObj, int replyObj,int flags) {

    Parceldata = Parcel.obtain(dataObj);

    Parcelreply = Parcel.obtain(replyObj);

    booleanres;

    try {

        //调用onTransact函数,派生类能够又一次实现这个函数,以完毕业务功能

        res= onTransact(code, data, reply, flags);

    } catch{ ... }

   reply.recycle();

   data.recycle();

    returnres;

}

ActivityManagerNative类实现了onTransact函数。代码例如以下:

[ActivityManagerNative.java-->ActivityManagerNative.onTransact()]

public boolean onTransact(int code, Parcel data,Parcel reply, int flags)

           throws RemoteException {

    switch(code) {

    caseSTART_ACTIVITY_TRANSACTION:

    {

       data.enforceInterface(IActivityManager.descriptor);

       IBinder b = data.readStrongBinder();

       ......

        //再由ActivityManagerService实现业务函数startActivity

        intresult = startActivity(app, intent, resolvedType,

                   grantedUriPermissions, grantedMode, resultTo, resultWho,

                   requestCode, onlyIfNeeded, debug, profileFile,

                   profileFd, autoStopProfiler);

       reply.writeNoException();

       reply.writeInt(result);

       return true;

    }

    .... // 处理其它请求的case

    }

}

由此能够看出。JavaBBinder仅是一个传声筒。它本身不实现不论什么业务函数。其工作是:

·  当它收到请求时,仅仅是简单地调用它所绑定的Java层Binder对象的exeTransact。

·  该Binder对象的exeTransact调用其子类实现的onTransact函数。

·  子类的onTransact函数将业务又派发给其子类来完毕。

请读者务必注意当中的多层继承关系。

通过这样的方式。来自client的请求就能传递到正确的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 {

    intfoo(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 extendsandroid.os.IInterface {

    /*② aidl工具生成了一个继承自IMyServer接口的抽象类IMyServer.Stub。这个抽象类实现了

      Bn端通过onTransact()方法接收来自Bp端的请求的代码。

本例中的foo()方法在这个类中

      会被定义成一个抽象方法。由于aidl工具根不知道foo()方法是做什么的。它仅仅能在onTransact()

      中得知Bp端希望对foo()方法进行调用。所以Stub类是抽象的。 */

    publicstatic 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所提供的接口

    publicint 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 {

    intfoo(String str) {

        // 做点什么都能够

        returnstr.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.IMyServerasInterface(

       android.os.IBinder obj) {

    ......

    // 创建一个IMyServer.Stub.Proxy。

当中參数obj将会被保存为Proxy类的mRemote成员。

    return new com.understanding.samples.IMyServer.Stub.Proxy(obj);

}

可见,AIDL使得构建一个Binder服务的工作大大地简化了。

2.2.5 Java层Binder架构总结

图2-4展示了Java层的Binder架构。


图 2 - 4 Java层Binder架构

依据图2-4可知:

q  对于代表client的BinderProxy来说,Java层的BinderProxy在Native层相应一个BpBinder对象。凡是从Java层发出的请求,首先从Java层的BinderProxy传递到Native层的BpBinder,继而由BpBinder将请求发送到Binder驱动。

q  对于代表服务端的Service来说,Java层的Binder在Native层有一个JavaBBinder对象。

前面介绍过,全部Java层的Binder在Native层都相应为JavaBBinder。而JavaBBinder仅起到中转作用。即把来自client的请求从Native层传递到Java层。

q  系统中依旧仅仅有一个Native的ServiceManager。

至此,Java层的Binder架构已介绍完毕。从前面的分析能够看出,Java层Binder非常依赖Native层的Binder。

建议想进一步了解Binder的读者们,要深入了解这一问题,有必要阅读卷I的第6章“深入理解Binder”。

2.3 心系两界的MessageQueue

卷I第5章介绍过。MessageQueue类封装了与消息队列有关的操作。

在一个以消息驱动的系统中。最重要的两部分就是消息队列和消息处理循环。在Andrid 2.3曾经,仅仅有Java世界的居民有资格向MessageQueue中加入消息以驱动Java世界的正常运转,但从Android 2.3開始,MessageQueue的核心部分下移至Native层,让Native世界的居民也能利用消息循环来处理他们所在世界的事情。

因此如今的MessageQueue心系Native和Java两个世界。

2.3.1 MessageQueue的创建

如今来分析MessageQueue是怎样跨界工作的。其代码例如以下:

[MessageQueue.java-->MessageQueue.MessageQueue()]

MessageQueue() {

    nativeInit();//构造函数调用nativeInit,该函数由Native层实现

}

nativeInit()方法的真正实现为android_os_MessageQueue_nativeInit()函数,其代码例如以下:

[android_os_MessageQueue.cpp-->android_os_MessageQueue_nativeInit()]

static voidandroid_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {

    // NativeMessageQueue是MessageQueue在Native层的代表

    NativeMessageQueue* nativeMessageQueue = newNativeMessageQueue();

    ......

    // 将这个NativeMessageQueue对象设置到Java层保存

    android_os_MessageQueue_setNativeMessageQueue(env,obj,

                                                         nativeMessageQueue);

}

nativeInit函数在Native层创建了一个与MessageQueue相应的NativeMessageQueue对象,其构造函数例如以下:

[android_os_MessageQueue.cpp-->NativeMessageQueue::NativeMessageQueue()]

NativeMessageQueue::NativeMessageQueue() {

    /* 代表消息循环的Looper也在Native层中呈现身影了。依据消息驱动的知识,一个线程会有一个

      Looper来循环处理消息队列中的消息。以下一行的调用就是取得保存在线程本地存储空间

     (Thread Local Storage)中的Looper对象 */

    mLooper= Looper::getForThread();

    if (mLooper == NULL) {

        /* 如为第一次进来,则该线程没有设置本地存储,所以须先创建一个Looper,然后再将其保存到

          TLS中,这是非经常见的一种以线程为单位的单例模式*/

        mLooper = new Looper(false);

        Looper::setForThread(mLooper);

    }

}

Native的Looper是Native世界中參与消息循环的一位重要角色。

尽管它的类名和Java层的Looper类一样,但此二者事实上并无不论什么关系。

这一点以后还将具体分析。

2.3.2 提取消息

当一切准备就绪后,Java层的消息循环处理,也就是Looper会在一个循环中提取并处理消息。消息的提取就是调用MessageQueue的next()方法。当消息队列为空时。next就会堵塞。MessageQueue同一时候支持Java层和Native层的事件,那么其next()方法该怎么实现呢?具体代码例如以下:

[MessagQueue.java-->MessageQueue.next()]

final Message next() {

    int pendingIdleHandlerCount = -1;

    int nextPollTimeoutMillis = 0;

 

    for (;;) {

        ......

        // mPtr保存了NativeMessageQueue的指针。调用nativePollOnce进行等待

        nativePollOnce(mPtr,nextPollTimeoutMillis);

        synchronized (this) {

            final long now = SystemClock.uptimeMillis();

            // mMessages用来存储消息,这里从当中取一个消息进行处理

            final Message msg = mMessages;

            if (msg != null) {

                final long when = msg.when;

                if (now >= when) {

                    mBlocked = false;

                    mMessages = msg.next;

                    msg.next = null;

                    msg.markInUse();

                    return msg; // 返回一个Message给Looper进行派发和处理

               } else {

                    nextPollTimeoutMillis = (int) Math.min(when- now,

                                                  Integer.MAX_VALUE);

                }

            } else {

                nextPollTimeoutMillis = -1;

            }

            ......

            /* 处理注冊的IdleHandler,当MessageQueue中没有Message时,

           Looper会调用IdleHandler做一些工作,比如做垃圾回收等  */

           ......

           pendingIdleHandlerCount = 0;

            nextPollTimeoutMillis = 0;

        }

    }

}

看到这里,可能会有人觉得这个MessageQueue非常easy,不就是从曾经在Java层的wait变成如今Native层的wait了吗?可是事情本质比表象要复杂得多,来思考以下的情况:

nativePollOnce()返回后,next()方法将从mMessages中提取一个消息。

也就是说。要让nativePollOnce()返回,至少要加入一个消息到消息队列。否则nativePollOnce()只是是做了一次无用功罢了。

假设nativePollOnce()将在Native层等待,就表明Native层也能够投递Message,可是从Message类的实现代码上看,该类和Native层没有建立不论什么关系。

那么nativePollOnce()在等待什么呢?

对于上面的问题,相信有些读者心中已有了答案:nativePollOnce()不仅在等待Java层来的Message,实际上还在Native还做了大量的工作。

以下我们来分析Java层投递Message并触发nativePollOnce工作的正常流程。

1. 在Java层投递Message以上是关于《深入理解Android 卷III》第二章 深入理解Java Binder和MessageQueue的主要内容,如果未能解决你的问题,请参考以下文章

《深入理解Android 卷III》第四章 深入理解WindowManagerService

《深入理解Android 卷III》第六章 深入理解控件(ViewRoot)系统

《深入理解Android2》读书笔记

深入理解php内核 编写扩展_III- 资源

Android 编程好书推荐

Android 编程好书推荐