特别声明:本系列文章LiAnLab.org著作权所有,转载请注明出处。作者系LiAnLab.org资深Android技术顾问吴赫老师。本系列文章交流与讨论:@宋宝华Barry
libbinder – Binder的Native实现
出于性能和代码统一性的角度考虑,Binder IPC并不Java和Native环境里各实现一次,而只是分别在不同的执行环境里提供使用的接口。使用Binder的Java代码,通过一些使用Binder的Java类之后,必须会走入到Native环境,将具体的分发的工作交给执行效率更高的Native代码。
最后这些接口都将被统一到一个统一的Binder交互环境,这一环境可以被称为Binder环境,而Binder IPC通信的过程,最终是在libbinder这样一种库文件里实现,最终会通过libbinder.so提供到Android系统里。
libbinder是由C++编写的,这便Binder传输在实现上也具备面向对象的特点,这种能力不仅给Java环境里的概念映射提供了方便,同时,也使在Native环境里也以面向对象的方向来使用Binder进行多种环境的互相通信提供了一种机制。于是,直接使用libbinder提供的编程接口,也可以编写Native环境里的System Service,由C++语言直接给Java语言提供服务端实现,这就得到了NativeService。
对于libbinder的使用,可以还是先从Java环境的Binder类开始分析。
Java环境如何访问到libbinder
在对于Java环境的Remote Service分析时,我们可以看到Binder在Java环境里的表现形式,除去只作为接口类的IInterface、IBinder,实际上在Android系统里,只会使用一个Binder基类来托管一个远程对象。从交互过程来看,使用某个Binder上托管的对象,都可以通过Binder之上搭建的IPC消息“桥”进行互通过,在实现上,一个通过继承的Binder的对象,分别将在发送端产生Proxy部分,而在接收端生成Stub部分。这样的Binder通过IInterface将对象暴露出来之后,发送端就可以使用这一引用找到Proxy,通过Proxy对象的transact()方法发送,而接收端对应的也使用同一IInterface,通过其上onTransact()回调接收。这样便构成了交互的能力。
但从Java环境里,实际上,我们根本不知道是如何处理完成的,我们跟踪所有的Binder相关的Java实现,也不看不出来。比如,我们在客户端经常会使用这样的方法来写Proxy端方法:
- public IBinder getService(String name) throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IServiceManager.descriptor);
- data.writeString(name);
- mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
- IBinder binder = reply.readStrongBinder();
- reply.recycle();
- data.recycle();
- return binder;
- }
这种Proxy端的大部分代码,都可以在Java源代码里跟踪到其具体实现,但mRemote.transact()这行,则没有跟踪代码到具体是如何完成Binder通信的,我们前面只是说这一行便是送数据从BinderIPC通道上发送了出去,但并没有解释如何发送出去的。
这就会涉及到Binder的“跨界”实现,Binder这种特殊跨进程对象,实际上会映射到三层环境里,Kernel层,C/C++层,Java层。其中Kernel的Binder驱动是提供跨进程实现的基础,能够支持访问Binder驱动只有C/C++层,Java层则必须要通过JNI访问到C/C++层。Java语言实现里并不会支持任何对于底层操作系统功能,因为这样势必会破坏Java在各平台之上直接运行能力,但Java语言又将访问几乎所有的操作系统功能,这些都得通过JNI整合到Java环境的。在JNI编程这种限制之下,如果Binder对象在Java环境里保持一份、C++环境一份,则将加大开发与维护的开销。于是在Android世界里,JNI层一般都很薄(甚至大部分还很难理解),尽可能将代码集中在C++层实现,这样保持了实现上的简洁,同时还收获了执行上的更高的效率。
我们的Binder.java实现了IBinder接口类,于是它拥有如下的结构:
- public class Binder implements IBinder {
- public static final native int getCallingPid();
- public static final native int getCallingUid();
- public static final int getOrigCallingUid();
- private static final native int getOrigCallingUidNative();
- public static final int getOrigCallingUser();
- public static final native long clearCallingIdentity();
- public static final native void restoreCallingIdentity(long token);
- public static final native void setThreadStrictModePolicy(int policyMask);
- public static final native int getThreadStrictModePolicy();
- public static final native void flushPendingCommands();
- public static final native void joinThreadPool();
- public Binder() {
- init();
- ...
- }
- public void attachInterface(IInterface owner, Stringdescriptor) ;
- public String getInterfaceDescriptor();
- public boolean pingBinder() ;
- public boolean isBinderAlive();
- public IInterface queryLocalInterface(Stringdescriptor);
- protected boolean onTransact(int code, Parcel data, Parcel reply,
- int flags) throws RemoteException;
- public void dump(FileDescriptor fd, String[] args);
- protected void dump(FileDescriptor fd, PrintWriter fout,String[] args);
- public final boolean transact(int code, Parcel data, Parcel reply,
- int flags) throws RemoteException;
- public void linkToDeath(DeathRecipient recipient, int flags) ;
- public boolean unlinkToDeath(DeathRecipient recipient, int flags);
- protected void finalize() throws Throwable {
- destroy();
- }
- private native final void init();
- private native final void destroy();
- private boolean execTransact(int code, int dataObj, int replyObj,
- int flags) {
- res = onTransact(code, data, reply,flags);
- return res;
- }
- }
作为一个继承至IBinder接口的类,Binder这个类势必要实现所有的接口方法。但比较特殊的是Binder类的构造方法Binder()会调用到一个init()方法,析构方法finalize()会调用到一个destroy()方法,这两个方法并不是由Java实现,而是被标识为native的JNI实现的方法。另外需要注意到的是,Binder类本身实现了transact()与onTransact()收发两端的代码,但只是进程类的直接交互,并不会进程间的Binder交互。
另外,我们在同一Binder.java类里,还可以找到另一个BinderProxy类的定义,在这一类里会使用一个native标识的transact()方法。虽然在源代码里找不到任何使用这一类的地方,但从命名方式上来看,这一类应该会是被创建的默认的Proxy端。BinderProxy.java的定义如下:
- final class BinderProxy implements IBinder {
- public native boolean pingBinder();
- public native boolean isBinderAlive();
- public IInterface queryLocalInterface(Stringdescriptor);
- public native String getInterfaceDescriptor() throws RemoteException;
- public native boolean transact(int code, Parcel data, Parcel reply,
- int flags) throws RemoteException;
- public native void linkToDeath(DeathRecipient recipient,int flags)
- throws RemoteException;
- public native boolean unlinkToDeath(DeathRecipient recipient,int flags);
- public void dump(FileDescriptor fd, String[] args) throws RemoteException;
- public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException;
- BinderProxy() {
- mSelf = new WeakReference(this);
- }
- @Override
- protected void finalize() throws Throwable {
- destroy();
- }
- private native final void destroy();
- private static final void sendDeathNotice(DeathRecipient recipient) {
- recipient.binderDied();
- }
- final private WeakReference mSelf;
- private int mObject;
- private int mOrgue;
- }
对于Framework层实现,其基本功能都是通过frameworks/base/core/jni目录里,可以找到所有JNI实现。对应于Java环境里Binder实现,我们可以找到frameworks/base/core/jni/android_util_Binder.cpp。可以在这一JNI实现里看到,实际上所有基于Binder的交互,会通过javaObjectForIBinder()方法基于IBinder引用来创建或是找到对应的Java对象,通过ibinderForJavaObject()通过Java对象找到IBinder引用:
- jobject javaObjectForIBinder(JNIEnv* env, constsp<IBinder>& val)
- {
- if (val == NULL) return NULL;
- if(val->checkSubclass(&gBinderOffsets)) {
- jobject object = static_cast<JavaBBinder*>(val.get())->object();
- LOGDEATH("objectForBinder%p: it's our own %p!\n", val.get(), object);
- return object;
- }
- AutoMutex _l(mProxyLock);
- jobject object = (jobject)val->findObject(&gBinderProxyOffsets); 1
- if (object != NULL) {
- jobject res = env->CallObjectMethod(object,gWeakReferenceOffsets.mGet); 2
- if(res != NULL) {
- ALOGV("objectForBinder%p: found existing %p!\n", val.get(), res);
- return res;
- }
- LOGDEATH("Proxyobject %p of IBinder %p no longer in working set!!!", object, val.get());
- android_atomic_dec(&gNumProxyRefs);
- val->detachObject(&gBinderProxyOffsets);
- env->DeleteGlobalRef(object);
- }
- object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor); 3
- if (object != NULL) {
- LOGDEATH("objectForBinder%p: created new proxy %p !\n", val.get(), object);
- env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());
- val->incStrong(object);
- jobject refObject = env->NewGlobalRef(
- env->GetObjectField(object,gBinderProxyOffsets.mSelf));
- val->attachObject(&gBinderProxyOffsets, refObject,
- jnienv_to_javavm(env),proxy_cleanup);
- sp<DeathRecipientList> drl = new DeathRecipientList;
- drl->incStrong((void*)javaObjectForIBinder);
- env->SetIntField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jint>(drl.get()));
- android_atomic_inc(&gNumProxyRefs);
- incRefsCreated(env);
- }
- return object;
- }
在javaObjectForIBinder()方法里,1先会通过传入的IBinder引用,来查找是否已经存在所需要使用的BinderProxy对象;2如果存在,则通过BinderProxy的WeakReference引用,然后返回该引用;3如果没有,则在后面会创建这一BinderProxy对象。除去这几行,实际上其他代码都是在进行引用计数的维护。而在3代码的操作里之后,调用incRefsCreated()方法,于是又会索引到另一个BinderInternal对象,使用其ForceGc()方法。
而对于Binder类本身,我们也会看到其init()的native实现,
- static void android_os_Binder_init(JNIEnv* env, jobject obj)
- {
- JavaBBinderHolder* jbh = new JavaBBinderHolder();
- if (jbh == NULL) {
- jniThrowException(env, "java/lang/OutOfMemoryError",NULL);
- return;
- }
- jbh->incStrong((void*)android_os_Binder_init);
- env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);
- }
有了这三部分的代码,我们的Java环境里的Binder,便与Native态的Binder结合到一起了,最终会得到如下所示的即有Java,也有C++代码的复杂关系:
在Java环境里,某个Binder对象的IBinder引用,则可以通过javaObjectForIBinder()创建或是取得某个已有的BinderProxy对象,BinderProxy对象的transact()是以JNI的方式实现的,于是有可能进一步通过它来构建底层的Binder交互。同时,Java环境里的Binder对象,会通过init()方法来为该对象创建JavaBBinderHolder,从而使自己被映射到Native环境里的Binder(在Native环境里叫BBinder),最终将两个环境里的Binder对象被映射到一起。
在这时不光需要完成Binder的实现由Java层转入Native层,更重要是需要一种机制,可以使Native态发生的变动,再回到Java层。Java语言环境本身提供自动垃圾回收机制,我们需要将Binder对象能够自动地被Java的GC所管理,同时,我们大部分使用Binder通信的代码还是Java写的,我们需要能够在合适的状态点回调到Javag玩意。JavaBBinderHolder本身只是JavaBBinder的包装类,在JavaBBinder之上再包装上引用计数(继承Refbase),于是同时使用一个能处理GC的BinderInternal便可以自动处理。另外,值得注意的是Java环境里的Binder类,Binder类提供一个不常见的private的execTransact()方法,这其实就是Binder环境的回调,JNI代码在执行Native环境的onTransact()方法时,会通过回调Java环境里的execTransact()方法,从而回调到Java里实现的onTransact()方法。于是,Java环境里的Binder,实际上只是一层封装,直正的Binder通讯是由底层来完成的,由Android系统里使用C++编写的一个libBinder库来完成,如下所示:
libbinder的构成
实现了从Java环境到Native实现的Binder环境之间的交互之后,还需要可以在多个范围内完成对象的映射。Binder这个概念在Java环境里大量使用了面向对象的重构技巧,尽可能实现通用操作,而只预留出来需要定制的接口。于是,我们为了支持给Java环境提供的灵活功能,在Native层的Binder,也需要具备面向对象的能力。综合这两种需求,我们得到了frameworks/base/libs/binder目录里,用C++实现的libbinder(在Android 4.1里,为了更好地兼容NDK被移到frameworks/native/libs/binder)。当然,C++跟Java的分析方式则有不同,C++的头文件与实现,跟C一样,是分开的,从头文件更容易分析其构成,与实现对应,一般我们都可以在同级目录里找到头文件,libbinder的头文件位于frameworks/base/include/binder。
出于跟Java层代码进行不同语言空间的映射之用,C++实现的Binder库也会与Java环境里的Binder概念有着互通之处。
- IInterface.h,定义IInterface接口类。与Java的IInterface接口类对应,用于通过统一的asBinder()接口方法返回IBinder引用。但与Java环境不同,C++环境里需要提供Binder通信实现,于是IInterface类,在内部被进一步拆分成BpInterface(Proxy端对象)、BnInterface(Stub端对象)两个模板,从而使用不同模板参数,可以使用对同一IInterface接口的访问,得到不同功能实现。
- IBinder.h,定义IBinder接口类。与Java环境的IBinder对应,提供Binder引用,并定义Binder对象所应实现的方法。跟Java环境一样,IBinder对象会是分别引用到Proxy对象或是Stub对象,通过localBinder()方法返回Binder Stub端的BBinder对象,或是通过remoteBinder()方法返回Binder Proxy端的BpBinder对象。但与Java环境不同,C++环境里没有标准的自动化内存管理(GabageCollection),于是会内置一个DeathRecipient类,通过Refbase来进行垃圾管理,就像我们前面分析JNI部分,这一管理内容,最终会通过BinderInternal类回调到Java的自动化内存管理。
- Binder.h,定义BBinder类与BpRefBase类。BBinder类与Java环境里的Binder类对应,是Binder的Stub实现,通过onTransact()回调方法接收与处理Binder事件。但它更属于Binder通讯的基础类,并不会被直接使用,系统只会通过BBinder类的派生类进行通信,所以它的类名是BBinder,Base Binder的意思。BBinder里维护了Extras对象,可在线程完全情况下访问到BpBinder里实现的objectManager,从而自动管理Proxy对象。BpRefBase类,用于通过IBinder引用来找到合适的BpBinder类,进一步被应用于BpInterface模板类。
- BpBinder.h,定义BpBinder类。与Java环境里的Stub.Proxy对象对应,是Binder的Proxy端实现。作为Proxy端,又是Binder最底层的封装,这一类的本质作用只是提供一个transact()方法,从而给上层封装的RPC请求提供最终的Binder通信接口。与此同时,BpBinder创建的对象,必须与BBinder加入绑定,于是也提供objectManager类,用于提供Proxy端的对象管理,但与BBinder使用单一objectManager对象不同,这里存在多重映射的可能性,在Proxy对象里的objectManager会以队列形式被管理。
- Parcel.h,定义Parcel类。虽然概念上与Java里实现序列化的Parcel类是对应的,也提供同样的操作方法。但在实现上,Native环境里的Parcel是提供Java环境里的Parcel概念的一种基础,所有的Parcel的read|write_*()系列的方法,底层全是由Native代码来实现具体的读写操作。这也是基于Binder的RPC操作的基础,我们进行进程间的方法调用时,都会基于Parcel来完成参数与返回值的序列化,然后再通过Binder进行传输。最终,所有通过实现Parcelable方法得到的对象,都将在传递时被映射到Binder驱动所需要的一种平滑过的对象结构,被存入一种叫flat_binder_object的变量里,从而可以以线性空间的方式保存并传输。
上面的这些基本类,便构成了Binder通信的基础。通过这些基本类,不但完成了Java环境与Binder的Native在实现上的概念统一,两种环境里的对象都有一一对应的关系。而且这些概念上也通过JNI被关联到一起,Java环境里的Binder最终会通过底层的Binder类来进行操作,而底层Binder对象,则会通过RefBase嵌入到Java环境的垃圾回收池。libBinder便拥有了如下所示的构成:
但此时,我们还是没有解决最核心的问题,这些在Native环境里进行Binder通信封装的类,如何操作Binder驱动来达到通信的目的。在libbinder的实现里,我们都会通过两个专门的类来完成真正的Binder消息的读写操作,ProcessState与IPCThreadState,因为此时已经是全系统唯一的概念了,则不会提供Java代码的映射,只由C++代码来实现。
- ProcessState.h,定义ProcessState类。正如这个类的名字所表述的,这个类的作用就是维护与IPC相关的进程状态,对于任一使用Binder的进程而言,进程空间里只会有一个ProcessState对象。Binder通信与其他的IPC机制不同,其他的IPC基本上都是基于文件描述符fd来标识出不同的通信过程,而Binder在整个传输过程里都是以进程为单位来进行传输。Binder通信在传输时虽然也会使用/dev/binder的文件描述符,但只是用于与驱动通信,IPC消息只以进程为单位进行传输,并且也可以通过binder知道进程是否还处于存活状态,从而可以实现整个系统的垃圾回收。
- IPCThreadState.h,定义类IPCThreadState。这个类描述以线程为基础的IPC传输状态,Binder通信的读写过程便在这个类里完成。在Binder提供底层的跨进程通信能力之后,基于其上建立通信过程,可以以单线程循环方式完成,也可以使用多线程。如果使用单线程,在处理某个大数据量的消息的收发过程里容易发生阻塞,数据传递的效率降低,同时也会使底层的Binder驱动承载的压力变大。如果使用简单多线程,有线程则创建线程加以接收处理,则又产生线程维护开销,并引发多线程编程失控。在IPCThreadState类的实现里,是以线程池的方式来维护Binder的通信请求,对于/dev/binder设备的读写请求都是通过线程方式并行执行的IPCThreadState的线程对象来完成,但并非总是创建,而只是通过IPCThreadState的self()方法取回一个合适的实例来进行处理。
多了这两个与Binder进行通信的基本类之后,libbinder的构成便进一步被扩大,但此时已经可以完成Binder通信,并提供对上层的封装功能了。于是,从Binder通信的功能上来看,libbinder的构成实际上是如下如示的样子:
在libbinder的构成里,ProcessState,只是一个用于描述进程状态的类,于是并不直接跟Binder通信。但Binder驱动会在ProcessState对象里被打开,对于进程来说,Binder的使用实例是唯一的,被保存到mDriverFD里。同时,由Binder派生出来的远程对象,也会在ProcessState里通过getContextObject()和setContextObject()来维护。最后,对于进程当前的线程池环境,也是通过ProcessState对象来维护。
至于IPCThreadState类,则实现上会复杂一些,所有的Binder命令,最终都会通过一个IPCThreadState来进行处理。一个IPCThreadState对象,就是通过talkWitheDriver()方法来循环地操作ProcessState的mDriverFD,完成Binder驱动的实际读写操作。所有命令的发送操作,都是通过IPCThreadState的transact()方法来完成,而Binder驱动返回过来的消息,会通过executeCommand()回调到具体的onTransact()实现。
综合libbinder的实现,与Java环境的Remote Service,最终得到的Binder通信便是如下的流程:
Remote Service的访问者,也就是应用程序进程,会使用Stub.Proxy对象来调用transact()方法,而Proxy对象本身会在使用里创建一个BinderProxy对象,并调用这一BinderProxy对象的transact()方法。而Java环境里的BinderProxy对象的使用,会在libbinder里创建BpBinder与之对应,BinderProxy的transact()本身是使用JNI实现的,会调用BpBinder的transact()实现。这时,在BpBinder的transact()方法里,Binder命令便会经由IPCThreadState对象的transact()、waiteForResponse()、talkWithDriver(),写入当当前进程维护的mDriverFD,也就是Binder驱动里。
Remote Service则是Binder命令的接收与处理者,会一直在自己的ProcessState对象维护的mDriverFD上监听,Remote Service则都使用joinThreadPool()来创建监听Binder的线程。当Binder命令过来之后,监听的IPCThreadState对象会从talkWithDriver()方法里返回,读回相应的命令,然后调用executeCommand()方便处理这一命令。在executeCommand()方法里,当接收到交互请求(命令是BR_TRANSACTION)时,会调用Binder命令里指定BBinder对象的transact()方法。此时,因为Java环境里Binder对象,在JNI实现里会自动创建JavaBBinder类,于是BBinder对象的transact()方法,会通过JavaBBinder的onTransact()回调到Java环境里Binder对象的execTransact()方法,然后再调用到最终的RemoteService里实现的onTransact()方法。
当然,前面通过aidl编程也可以看出,虽然底层实现上如此复杂,九转十八弯才得到了这样的远程调用,但对于编程使用却异常简单,只是需要简单地使用一个Stub对象即可,所有的底层操作都将系统封装掉了,在aidl编程时甚至都不知道有Proxy对象,全由aidl自动生成。这便是Android的优点之一,无论底层多么复杂,但上层都是很简单的接口。而对于系统设计的一个可借鉴之处是,当我们把这套逻辑封装得非常易于编程时,对于底层的改进也将更加平滑,因为用户并不知道底层发生了怎样的变动,仍使用同样的编程方式进行调用。
这种方式,绕来绕去的,不太容易理解,Java环境与Native环境的互相穿越,也容易迷失方向。这是否有必要呢?如果没有Java,这种复杂逻辑是没有理由的,复杂便会效率低下。而且在整个Binder概念的实现上,大量使用面向对象技巧,即便是在C++实现的部分,也会通过虚拟继承来实现访问上的灵活性,在嵌入式环境里使用虚拟继承来进行动态访问,本身就是低效之源。但是,因为有了Java语言的需求,这样设计就很合理了。通过Binder,不但完成了Binder在Java环境与Native环境的成功映射,在Java环境的Binder概念之下通过机器代码实现了高效安全的Binder通信,更进一步的好处是,Binder被托管到了Java虚拟机的自动化垃圾回收机制里。假设Android并没有选择Java语言,而是选择了另一种支持垃圾回收的编程语言,我们只需要简单地将Java态的绑定,也就是Binder概念相关的Java类、JNI实现实现一次即可。
至此,基本上libbinder的基本功能便已经完备了,可以支持上层的基于Binder传递对象、使用IBinder引用来进行调用远程进程中的方法、以及通过Parcel来传递复杂对象的功能。
除了基本功能之外,libbinder里还会实现一些C++环境里的辅助类:
- 实现在C++环境里的ServiceManager类,从而在C++环境里可以直接调用getService()方法取得其他System Service
- 实现IMemory接口方法,从而可以灵活实现多种内存共享方式
libbinder里实现的ServiceManager
ServiceManager本身就是Native Service的一个典型的例子,Java环境里编程会使用ServiceManager,调用到SystemServer里实现的系统功能。而整个Android系统各个组成部分也会不停地进行交互,Native Service之间也会进行相互调用。我们可以看到servicemanager是一个C语言写的独立进程,Stub端的功能便会由这一servicemanager进程来完成,于是从Binder领域来说,所有以面向对象实现的ServiceManager类,只需要提供Proxy功能。
以Native Service方式来提供ServiceManager功能,则是一个跟我们的前面的ITask很类似一种实现。出于代码完整性角度考虑,在IServiceManager里也提供了BnServiceManager的实现,但由于没有将这一Service加入到IPCThreadState里,于是只是空的实现。
在frameworks/native/include/binder/IServiceManager.h定义了以Native方式实现的Service,
- namespace android {
- class IServiceManager: publicIInterface 1
- {
- public:
- DECLARE_META_INTERFACE(ServiceManager); 2
- virtual sp<IBinder> getService( const String16& name) const = 0; 3
- virtual sp<IBinder> checkService( const String16& name) const = 0;
- virtual status_t addService( const String16&name,
- constsp<IBinder>& service,
- bool allowIsolated =false) = 0;
- virtual Vector<String16> listServices() =0;
- enum { 4
- GET_SERVICE_TRANSACTION=
- IBinder::FIRST_CALL_TRANSACTION,
- CHECK_SERVICE_TRANSACTION,
- ADD_SERVICE_TRANSACTION,
- LIST_SERVICES_TRANSACTION,
- };
- };
- sp<IServiceManager> defaultServiceManager();
- template<typename INTERFACE>
- status_t getService(const String16& name, sp<INTERFACE>* outService) 5
- {
- const sp<IServiceManager> sm = defaultServiceManager();
- if(sm != NULL) {
- *outService = interface_cast<INTERFACE>(sm->getService(name));
- if((*outService) != NULL) return NO_ERROR;
- }
- return NAME_NOT_FOUND;
- }
- boolcheckCallingPermission(const String16& permission); 6
- boolcheckCallingPermission(const String16& permission,
- int32_t*outPid, int32_t* outUid);
- bool checkPermission(const String16&permission, pid_t pid, uid_t uid);
- class BnServiceManager: publicBnInterface<IServiceManager> 7
- {
- public:
- virtual status_t onTransact(uint32_t code,
- const Parcel&data,
- Parcel*reply,
- uint32_t flags = 0);
- };
- }; // namespace android
- IServiceManager这一接口类,继承自IInterface
- 进入IServiceManager的类定义部分,就会通过DECLARE_META_INTERFACE来完成通用部分的定义。
- 定义所需要的接口方法,所有接口方法必然会是纯虚方法。
- 定义IServiceManager所支持的Binder命令,跟Java环境里的ServiceManager类一致,支持四种命令,分别对应到第3步里定义的四个接口方法。并且跟其他Native Service一样,Binder命令都是从IBinder::FIRST_CALL_TRANSACTION开始。
- 这里使用了C++的多态,一般的getService()是直接通过一个Service的名字来取回一个IBinder实现,通过返回的IBinder引用是否为NULL来判断是否成功完成调用。而在这里定义的getService()方法,进一步封装了一次,可以返回一个调用的状态值,并且会直接通过interface_cast()宏来确保Proxy对象被创建。
- checkCallingPermission()、checkPermission()相当于IServiceManager里提供的一层Proxy功能,这部分的功能是由IPermissionController.cpp来提供,而这部分功能并不适合暴露出来,于是会透过IServiceManager将权限检测功能提供出来。
- 出于实现上的统一性考虑,在这里也会提供BnServiceManager的实现。
有了这个IServiceManager接口类的定义,在IServiceManager实现就跟
- sp<IServiceManager>defaultServiceManager() 1
- {
- if(gDefaultServiceManager != NULL) return gDefaultServiceManager;
- {
- AutoMutex _l(gDefaultServiceManagerLock);
- if(gDefaultServiceManager == NULL) {
- gDefaultServiceManager = interface_cast<IServiceManager>(
- ProcessState::self()->getContextObject(NULL)); 2
- }
- }
- returngDefaultServiceManager;
- }
- …
- class BpServiceManager : public BpInterface<IServiceManager> 3
- {
- public:
- BpServiceManager(const sp<IBinder>& impl)
- : BpInterface<IServiceManager>(impl)
- {
- }
- …
- virtualsp<IBinder> checkService( const String16& name) const 4
- {
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeString16(name);
- remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
- return reply.readStrongBinder();
- }
- …
- IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager"); 5
- …
- }
- defaultServiceManager(),每个进程都需要通过getService()来取回RemoteService,所以必然需要调用到defaultServiceManager()来取回一个IServiceManager的Proxy对象。
- 在defaultServiceManager()里使用了Singleton模式,对于某个进程只会创建一个唯一的IServiceManager的Proxy实例。值得注意的是getContextObject()会通过一个handle变量来取得一个IBinder引用,然后再通过interface_cast()转换成IServiceManager接口类。getContextObject()方法的参数会是整型的handle,handle的值会随着不同Service的引用,每使用一个,handle的值便会加1,这样每个进程空间会拥有各自不同的handle值,使得基于Binder通信的安全变高,不容易简单地抓取Binder命令来分析程序的行为。这里使用的handle值为0,于是对于每个进程,handle为0的Service都会是IServiceManager。
- 实现IServiceManager的Proxy类,于是实现上便会继承自BpInterface的模板。
- 跟Java环境的ServiceManager一致,getService()内部也会是调用checkService()来取得Service的IBinder引用。所有的Proxy端方法,都使用统一的模式,就是将调用的方法转换成Binder命令,然后发送出去。
- IMPLEMENT_META_INTERFACE()宏,会实现通用部分的代码,同时也会设定特定的descriptor。
通过这样的方式,最终就得到了简单而且高效的,并且与ServiceManager.java实现并行的ServiceManager的Proxy端。
通过libbinder灵活使用内存
在我们传统的Unix/Linux编程环境里,为了保持进程之间的互相独立性,都是用户进程空间里的内容互相独立,使用不同的内存映射,内核空间便会共享同一份内容,使用同一份内存映射。这样的情况下,如果需要在进程之间传递数据,必然是先通过copy_from_user()系统调用从用户空间先拷贝到内核空间,然后再在另一个进程空间里通过copy_from_user()系统调用从内核空间拷贝回用户空间。这种方式就保证了不同进程可以传递数据,同时进程之间互相不会有干扰,任一进程出错,对另一进程完全没有影响,因为进程空间本身是独立的。在Linux内核之上,任何IPC机制都采用了这种实现,Binder也不例外。比如Remote Service,在任一交互过程里,数据始终会有三份,内核一份、进程空间各一份拷贝:
但这种方式比较低效,多次内存拷贝会造成内存的开销,同时由于copy_from_user()和copy_to_user()系统调用,会造成计算上的开销。假设已经确定内存的传递时一方只读,此时就可以改进内存的使用,在发生内存写请求的进程里,仍然使用copy_from_user(),而读取内存的部分,则不再使用copy_to_user(),而是通过mmap()直接映射一段内存到自己的进程空间内,这样只会发生一次内存拷贝。
最后,还有一种可能性,所有进程都共享同一块内存区域,不管内存里保存的内容发生了任何改变,所有进程都应该见得到。这种使用在Linux编程里也很普遍,但一般只用于驱动访问,很少被用于IPC进程间通信。这种使用情境下,如果所共享的页源自于用户空间,则难以保证在物理分配上的连续性,更重要的是不要求,如果承载内存页的进程挂掉,则所有涉及交互的进程都不得不挂掉,所以内存页要在内核空间里。同时,在内核态则需要有一定的实体存放这样的页面映射引用,IPC机制并不支持这样的页面映射管理。但Binder IPC不受限于此,Binder驱动实际上只是一个基于内存映射的虚拟字符设备,于是可以天然地在传输过程里使用内存页的映射功能。于是,又有了第三种使用内存页的方式,就是灵活地内存映射功能:
如上所示,内存页实际上是在使用时通过内核态来分配的,内存只在内核态有一份拷贝,所有的用户进程都只通过mmap()系统调用来引用这样的页。但是这样的方式会引发内存管理上的混乱,内核空间的页面在分配上的优先级要远大于用户空间,而且必须以连续物理页来分配,也容易造成内存使用上的失控。于是,Android在原有的内存管理机制上拓展出来两种“特殊”内存管理机制,准确地说是共享内存的实现机制,pmem和ashmem,这两种机制可以将内核里内存分配机制暴露到用户态来操作。Pmem是一种预留出来一段物理内存供用户态分配连续物理内存来使用,而ashmem则是Android对原有的Shared Memory(共享内存机制)的一种改进,这两种机制我们后台再详细。虽然这种共享内存方式本身跟Binder机制没有关系的,并非由Binder IPC来实现这样共享功能,但得益于Binder通信与Java垃圾回收的绑定,于是Binder为这种内存共享提供了自动的内存管理功能。
- IMemory.h,定义两个基于IBinder的远程类,生成两个远程接口类,IMemory与IMemoryHeap,分别用于使用内存和分配内存。这是Android在系统设计上灵活性的一种体现,我们也知道IBinder是提供远程引用的,对于内存使用两个基于IBinder的接口类,则意味着申请内存与分配内存可分别由单独进程来提供。试想一下,比如一个照相机应用程序,通过IMemory接口向mediaserver进程申请内存,但在mediaserver进程里发出内存申请之后,则会由负责显示的surfaceflinger来负责分配所需要的空间。这样复杂的供给关系,只取决于代码如何实现,也不受限于进程空间,而且不会影响效率,因为无论多少进程交互,在底层实际上还是只有一份拷贝。当然,同时使用IMemory与IMemoryHeap远程接口,并不一定要发生在多进程环境里,当两个接口都在同一进程空间里提供Proxy与Stub时,实际上只是多绕了一层Binder IPC,但还是当前进程空间内,也不影响效率。另外,这两个接口类,出于性能的考虑,会是以Native Service的方式来提供。
- MemoryDealer.h,定义一个默认的分配内存的MemoryDealer类。在这一类里内置了一个最简化的列表式内存管理算法,这样需要提供内存分配部分,可以使用这一类来创建内存空间,并通过IMemoryHeap共享出去。
- MemoryBase.h,通过MemoryBase类来提供IMemory接口类的Stub端实现。MemoryBase会通过getMemory()的远程方法来返回一个IMemoryHeap实例,同时也会是MemoryDealer的操作对象。命名为Base,就说明这会是该类型的基类定义,如果有其他使用IMemory接口的地方可以继承该类,再派出生新的特性。
- MemoryHeapBase.h,通过MemoryHeapBase类来实现IMemoryHeap接口类的Stub端。在这个类里实现可用于远程共享的堆空间分配,如果不用于远程共享,则直接使用malloc()即可,IMemoryHeap接口相当于是远程实现的malloc(),new()等操作方法。在这一方法里会定义一些基本的Heap分配操作,根据不同的应用情境分配不同类型的内存(基于文件的、匿名空间等)。
- MemoryHeapPmem.h,实现基于Pmem机制并实现IMemoryHeap接口的MemoryHeapHmem类。如果有特殊内存堆的使用需求,则可以通过MemoryHeadBase类派生出新的MemoryHead类,比如在MemoryHeapPmem。所有的的特殊
最终,针对内存的分配与使用,在底层也会灵活地组织起来,在内存使用“食物链”最上流的使用内存的部分,只需要调用MemoryBase对象的getMemory()接口方法,这一请求会通过IMemory接口转发到能处理该请求的另一进程。而getMemory()又会返回一个IMemoryHeap引用,这样会自动地又将请求分发到可以处理这一IMemoryHeap分配的进程来处理内存分配。于是,在libbinder实现里针对跨进程的内存使用与分配,又可以得到如下的关系图:
![](https://img-my.csdn.net/uploads/201210/18/1350566403_7256.png)
有了IMemory这样的接口类之后,在Android系统里就可以更灵活地定义不同的内存使用方法。