关于匿名binder的传输原理总结。

一、缘由

网上有很多关于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。

你可能感兴趣的:(关于匿名binder的传输原理总结。)