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

简介:

本节书摘来华章计算机出版社《深入理解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可知:

image
图 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架构中最重要的三个类的初始化工作。

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

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”。

  1. 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函数的实现。

  1. 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注册的。

  1. 向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和JavaBBinder
ActivityManagerService从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此时还是ActivityManagerService
data.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了。
对此有更好的解释的读者,不妨与大家分享一下。

  1. 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对象,其中的虚线箭头表示调用子类重载的函数。
image

图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。
image

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

相关文章
|
19天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第3天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin的兴起,其在Android开发中的地位逐渐上升,但关于其与Java在性能方面的对比,尚无明确共识。本文通过深入分析并结合实际测试数据,探讨了Kotlin与Java在Android平台上的性能表现,揭示了在不同场景下两者的差异及其对应用性能的潜在影响,为开发者在选择编程语言时提供参考依据。
|
28天前
|
搜索推荐 Android开发 iOS开发
安卓与iOS系统的用户界面设计对比分析
本文通过对安卓和iOS两大操作系统的用户界面设计进行对比分析,探讨它们在设计理念、交互方式、视觉风格等方面的差异及各自特点,旨在帮助读者更好地理解和评估不同系统的用户体验。
19 1
|
1月前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【2月更文挑战第30天】 随着Kotlin成为开发Android应用的首选语言,开发者社区对于其性能表现持续关注。本文通过深入分析与基准测试,探讨Kotlin与Java在Android平台上的性能差异,揭示两种语言在编译效率、运行时性能和内存消耗方面的具体表现,并提供优化建议。我们的目标是为Android开发者提供科学依据,帮助他们在项目实践中做出明智的编程语言选择。
|
12天前
|
Java 调度
Java中常见锁的分类及概念分析
Java中常见锁的分类及概念分析
15 0
|
12天前
|
Java
Java中ReentrantLock中tryLock()方法加锁分析
Java中ReentrantLock中tryLock()方法加锁分析
12 0
|
27天前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
在开发高性能的Android应用时,选择合适的编程语言至关重要。近年来,Kotlin因其简洁性和功能性受到开发者的青睐,但其性能是否与传统的Java相比有所不足?本文通过对比分析Kotlin与Java在Android平台上的运行效率,揭示二者在编译速度、运行时性能及资源消耗方面的具体差异,并探讨在实际项目中如何做出最佳选择。
17 4
|
29天前
|
人工智能 监控 算法
java智慧城管源码 AI视频智能分析 可直接上项目
Java智慧城管源码实现AI视频智能分析,适用于直接部署项目。系统运用互联网、大数据、云计算和AI提升城市管理水平,采用“一级监督、二级指挥、四级联动”模式。功能涵盖AI智能检测(如占道广告、垃圾处理等)、执法办案、视频分析、统计分析及队伍管理等多个模块,利用深度学习优化城市管理自动化和智能化,提供决策支持。
208 4
java智慧城管源码 AI视频智能分析 可直接上项目
|
12天前
|
Java
Java中关于ConditionObject的signal()方法的分析
Java中关于ConditionObject的signal()方法的分析
21 4
|
12天前
|
Java
Java中关于ConditionObject的分析
Java中关于ConditionObject的分析
17 3
|
16天前
|
设计模式 缓存 安全
分析设计模式对Java应用性能的影响,并提供优化策略
【4月更文挑战第7天】本文分析了7种常见设计模式对Java应用性能的影响及优化策略:单例模式可采用双重检查锁定、枚举实现或对象池优化;工厂方法和抽象工厂模式可通过对象池和缓存减少对象创建开销;建造者模式应减少构建步骤,简化复杂对象;原型模式优化克隆方法或使用序列化提高复制效率;适配器模式尽量减少使用,或合并多个适配器;观察者模式限制观察者数量并使用异步通知。设计模式需根据应用场景谨慎选用,兼顾代码质量和性能。