一、缘由
网上有很多关于AIDL原理的讲述,但一直有个疑问是binder为什么在service端是stub,而客户端拿到就变成BinerProxy?网上讲了很多,但一到这个地方就一笔带过,所以决定自己研究下。
二、首先简述下AIDL使用流程
1.创建AIDL文件
AIDL文件会在build下生成java文件。如下:
在service中创建binder,实现stub并在service的onBind()中返回如下:
在另一个进程中绑定
单步调试看下传过来的binder
可以看到客户端是BinderProxy类型。
三、分析service绑定流程寻找stub在何处被转化成了binderProxy
要找到从哪里转化必须分析service绑定流程,
从bindService函数起
ContextWrapper.java中
我们知道是装饰模式,实现在ContextImpl.java中
调用bindServiceCommon函数
可以看到这个ActivityManagerNative.getDefault().bindService,通过代理实际上调用了ActivityManagerService.java的bindService函数
继续bindServiceLocked函数,太长截取关键代码
调用了bringUpServiceLocked函数,继续
调用了realStartServiceLodcked函数
调用了scheduleCreateService和requestServiceBindingsLocked,猜想这两个函数就是创建service和bindservice,成功后肯定回调service的onCreate和onBind。
此处又用到了代理,实际上实现函数在ActivityThread.java中,我关心的是onBind回调,所以直接看scheduleBindService这个函数
又用了个message,继续
终于找到了,通过调用service的onBind函数拿到了Binder,此时binder还是stub类。紧接着通过代理调用了ActivityManagerService的publishService函数,看到binder是直接作为参数传进去的。
参数继续传,继续跟踪
binder没做处理,直接回调了c.conn.connected。在一开始ContextImpl.java的bindServiceCommon函数中做了一些准备工作,就是创建这个回调类。此处调用到了
继续
继续
在doConnected中调用了ServiceConnection类的onServiceConnected函数,就是我们在客户端写的绑定回调。流程结束,不过问题没解决,参数binder始终没变,哪里捣鬼?
从handleBindService拿到binder开始起,此时还是服务端service进程,和ActivityManagerService交互,将binder交给了ActivityManagerService,ActivityManagerService又交给客户端回调onServiceConnected。
刚才分析时遇到ActivityManagerNative.getDefault(),由于也是binder通信,直接找到了实现ActivityManagerService进行分析。
这里有两点:
1.我们写的service和ActivityManagerService通过binder进行传输。
2.传输时的又有一个binder作为参数。这个binder是我们写的service和client通信用的binder。
重新分析下ActivityManagerNative.getDefault().publishService( data.token, data.intent, binder);
在ActivityManagerNative定义了Proxy端操作
Parcel类型,通过writeStrongBinder将binder写入,分析Parcel.java
private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
调到了jni了,在android_os_Parcel.cpp中
ibinderForJavaObject将binder转化为C++层对应得binder,也就是JavaBBinderHolder,JavaBBinderHolder是个装饰类,里面有JavaBBinder,而JavaBBinder继承BBinder。最后通过Parcel.java中的writeStrongBinder写入到binder驱动中。
writeStrongBinder调用flatten_binder
flatten_binder区分了情况本地binder将type置为BINDER_TYPE_BINDER
我们当然在研究跨进程的binder,所以此处置为BINDER_TYPE_HANDLE,并创建了BpBinder类。BpBinder就是BinderProxy在C++层的对应类。分析到此处大致明白,读取binder的时候肯定是找到BpBinder,进而找到BinderProxy,返回给了ActivityManagerService。
看下怎们读取的
看ActivityManagerService如何拿到传过来的binder,类似
通过readStrongBinder拿到binder,然后调用了publishService()函数给客户端。看jni对应的函数
此处终于明白了,parcel->readStrongBinder()找到BpBinder,javaObjectForIBinder()返回对应的BinderProxy给ActivityManagerService。
如下
之前写的时候置位了,是BINDER_TYPE_HANDLE
在getStrongProxyForHandle中判断BpBinder是否存在,直接找到或创建并返回。
再看javaObjectForIBinder()
通过对应关系找到BinderProxy,如果找不到就创建BinderProxy,并将BinderProxy和BpBinder建立对应关系。gBinderProxyOffsets即jni调用java的BinderProxy类。如下
所以在ActivityManagerService拿到binder的时候,这个binder已经是BinderProxy,后面给到客户端回调onServiceConnected函数。
分析完毕。
四,小结
一开始有这个疑问还是由于对binder的结构了解不深入。总结两点。
(1)Binder分为java层Binder和C++层Binder。Android代码中使用binder的方式很灵活,可以不关心C++层层Binder,直接通过java层Binder封装使用,即本例讨论的AIDL方式。可以在C++直接创建BBbinder和BpBinder来进行通信,比如深入理解android中讲到的MediaServer。当然也可以一侧使用java,另一侧使用C。更直接的可能直接通过ioctl方式直接写入binder驱动都可能。不了解binder的结构就发现各种资料讲解的都不一样,其实只是这几种使用方式的排列组合。只要了解一点,BinderProxy对应BpBinder,Binder对应BBinder的关系就不会错。
(2)系统service都在SystemServer进行注册,系统service的binder都是通过SystemServer查找拿到。SystemServer负责返回给客户端代理对象即BinderProxy。匿名binder,即本例讨论的AIDL,在和ActivityManagerService传输的过程中进行转化。binder作为对象被传输,具体就是通过writeStrongBinder和readStrongBinder。