引言
Android的插件化目前可谓是百花齐放,从最早的《Android内核剖析》中柯元旦对于插件化的简单示例,到任玉刚的DynamicLoadApk,再到360的DroidPlugin,以及阿里的Atlas。虽然它们的实现方式有差异,但也有很多的共同点。要想理解它们的原理,需要一些预备知识。建议把本篇Blog与Java服务框架分析结合起来看。
1.绑定服务获取的对象的真相
AIDL的使用就不啰嗦了,不懂的可以看我的Blog Android中的跨进程通信方法实例及特点分析(一):AIDL Service.其中aidl定义如下:
|
|
生成的IData.java如下:
|
|
显然,IData.Stub提供了一个本地的抽象类,而IData.Stub.Proxy则提供了一个代理类,它们都实现了IData这个接口。
而真正的Service提供者只需要继承IData.Stub,如下:
|
|
其中mBinder对象实现了IData.Stub()这个抽象类.
RoomService是作为Android Service呈现,它在Manifest中的声明如下:
|
|
注意RoomService的action为”com.aidl.service.room”,这个在Context.bindService()时需要用到.
而Client中绑定服务的代码如下:
|
|
我们从mData=IData.Stub.asInterface(binder)入手,看看返回的mData到底是什么对象。
其中IData.Stub.asInterface的代码如下:
|
|
Debug会发现obj其实是BinderProxy对象(至于为什么是BinderProxy对象,在后面讲到ActivityManagerNative时会分析),而BinderProxy的部分代码如下:
|
|
显然,BinderProxy对象的queryLocalInterface()返回null,所以IData.Stub.asInterface()会调用return new com.android.service.IData.Stub.Proxy(obj);生成IData.Stub.Proxy对象,其中obj为BinderProxy对象。
所以mData其实是一个IData.Stub.Proxy对象。所以调用mData.getRoomNum()时其实调用的是IData.Stub.Proxy的getRoomNum()方法:
|
|
那么为什么在Client端调用mData.getRoomNum()就能获取到RoomService提供的服务,就需要分析bindService()的过程了。
2.bindService()完整过程剖析
Activity基础自ContextThemeWrapper,而ContextThemeWrapper又继承自ContextWrapper,ContextWrapper中bindService()的操作是由ContextImpl对象完成的。代码如下:
|
|
显然最终会调用到ActivityManagerNative.getDefault().bindService()方法,而ActivityManagerNative.getDefault()是什么呢?
它其实是一个单例对象,代码如下:
|
|
其中的gDefault就是单例对象,它的定义如下:
|
|
其中ServiceManager.getService(“activity”);返回的是一个BinderProxy对象,并且该对象中的mObject对应native层的一个BpBinder对象,详细分析见我的Blog Java服务框架分析.
而asInterface方法如下:
|
|
到这里可以发现,其实ActivityManagerNative与前面的IData.Stub非常类似,事实上也是如此,ActivityManagerNative对应的代理类是ActivityManagerProxy,而真正实现ActivityManagerNative的类是AcitivityManagerService。所以这里其实生成了一个ActivityManagerProxy对象,而ActivityManagerProxy的构造方法如下:
|
|
所以ActivityManagerProxy中的mRemote是一个BinderProxy对象,而且该对象中的mObject对应native层的一个BpBinder对象,该BpBinder中含有ActivityManagerService注册在context_manager的句柄(handle).注意native层管理binder节点的是context_manager而不是ServiceManager,ServiceManager严格说来只是管理Java层服务的一个代理对象而已,而context_manager既管理Java层服务也管理native层服务。
再回到ContextImpl中,ActivityManagerNative.getDefault().bindService()其实是调用ActivityManagerProxy对象的bindService()方法,代码如下:
|
|
其中mRemote是BinderProxy对象,这里其实就是调用BinderProxy.transact()方法:
|
|
显然,transactNative是个native方法,它对应的android_util_Binder.cpp中的android_os_BinderProxy_transact()方法:
|
|
其中的target就是BinderProxy对象中的BpBinder对象,而data,reply对应Java层的data,replay对象。
而BpBinder::transact()方法如下:
|
|
后面就是IPCThreadState与驱动交互的过程了,由于不是本文的重点,而且在之前的Blog分析过,就不展开了。感兴趣的童鞋可以看我之前与Binder有关的Blog,简单的说,就是通过Binder Driver实现跨进程通信,最后在用户进程中调用到ActivityManagerService的binderService()方法。
ActivityManagerService.bindService()代码如下:
|
|
之后的调用比较多,但其实分析起来并不难,就不展开了,有兴趣的童鞋可以看看老罗的这篇分析:Android应用程序绑定服务(bindService)的过程源代码分析
最后会调用到LoadedApk的内部类ServiceDispatcher中doConnected()方法:
|
|
可以看到这里回调了mConnection.onServiceConnected()方法,而其中的的service就是通过Binder机制获取的BinderProxy对象,这个BinderProxy对象中的mObject对应的BpBinder中含有RoomService注册在context_manager中的句柄(handle).之后通过它就可以实现跨进程调用。
3.系统服务获取过程
其实刚刚我们在分析的过程中就涉及到了ActivityManagerService的获取过程,可以发现Java层的系统服务与我们自己实现的AIDL Service非常类似,有一个接口(如IActivityManager),一个Stub类(如ActivityManagerNative)和一个代理类(如ActivityManagerProxy),以及真正提供服务的类(如ActivityManagerService).
下面分析在Context子类(如Activity,Service)中getSystemService()是如何获取系统服务的。
以Activity.getSystemService()为例,其实最终调用的是ContextImpl中的getSystemService()方法:
|
|
其中SYSTEM_SERVICE_MAP是在registerService()时填充进去的,下面是ContextImpl中registerService的部分代码:
|
|
显然,以getSystemService(ALARM_SERVICE)为例,最终返回的对象是AlarmManager对象。
从它的注册过程可见,获取SystemService的步骤为:
|
|
虽然表现形式上有些不一致,但是大致都是这个步骤。其中ServiceManager中的getService()方法如下:
|
|
老套路,这里getIServiceManager()返回一个ServiceManagerProxy对象,只不过这个ServiceManagerProxy对象比较特殊,它的成员mRemote虽然还是BinderProxy对象,但是这个BinderProxy对象中的mObject对应的是BpBinder中的handle是context_manager而不是某个用户注册的服务。
在Java服务框架分析这篇Blog中进行了很详细的分析,这里就不展开了。
4.结语
ServiceManager是一个重要的Hook点,所以本文进行了较详细的分析,为了避免篇幅过长,还有一些东西在涉及到时在讲解。