在Android的圈子里,一直有一个声音,那就是:要学会看Android源码。在前期,android开发者比较缺乏阶段,似乎大家也没那么重视,但随着时间的发展,Android开发者早已供大于求,需要具备的技能也不在仅限于应用开发,还需要对Android运行机制原理有一个深度的了解,从而更好的为项目服务。所以,阅读Android源码,也就成为Android开发人员必须要做的事。
在阅读Android源码时,我们发现,Android系统中跨进程通信主要就是Binder。关于Binder跨进程通信原理,我已写过一篇文章Binder通信机制原理解析,想了解的同学可以看一下。其中也有说到为什么Andorid系统跨进程通信要使用Binder。在Android系统中多数服务如ActivitManagerService,WindowManagerService,PackageManagerService等都是通过Binder进行通信的,在阅读源码时,我们会时时与其打交道,所以本篇博文主要是想梳理一下Andorid源码中常见的Binder跨进程通信的方式,以便自己在读源码时,可以更好的理解。
在Binder通信机制原理解析博文中,我们说到Binder跨进程通信方式有两种,分别为AIDL方式、注册服务方式。AIDL方式在开发中是我们经常使用的方式,这里将会采用对比的方式来解析系统服务的Binder跨进程通信。
一、常用AIDL方式
1.aidl接口创建
以aidl为后缀创建一个接口类。如
项目编译时,系统会自动生成相对应的java文件,如
抽象类Stub相当于服务端,代理类Proxy相当于客户端。抽象类Stub继承于Binder,代理类Proxy依赖于IBinder接口。
2.AIDL的使用
AIDL的使用是以Service为载体,进而实现跨进程通信。我们知道Android的四大组件,在Androidmanifest中注册的时候可以通过android:process来指定组件所在的进程,当组件间不在同进程时,就需要跨进程通信了。AIDLService代码如下:
|
|
其中mBinder通过匿名内部类的形式初始化了Stub抽象类,进而AIDLService也就变成了Server端。当AIDLService与项目不在同一进程时,其他组件想与其通信,就必须要跨进程通信了。我们来看Activity与AIDLService通信,如
Activity通过bindService的方式,建立与AIDLService服务的联系。这中间主要是通过ServiceConnection这个接口,我们来看一下注释中的核心代码,IMainService.Stub.asInterface(service),这里我们再来看一下,aidl接口生成的java类的asInterface方法。
|
|
这里主要判断IBinder是否是跨进程,如果不是就返回本身,如果是则返回代理类Proxy,从而进行跨进程通信。具体Binder是怎么跨进程通信的,可以参考我的博文Binder通信机制原理解析。最后运行程序,结果如下
这里跨进程通信AIDL方式就讲解完了,AIDL方式源码地址:https://github.com/awenzeng/AndroidCodeLibrary,欢迎star,fork。
二、注册服务方式
Android的各种系统服务在Android系统启动的时候就也会启动和注册,具体启动流程,可以参考Android应用程序入口源码解析,这篇博文中有介绍,想了解的同学可以看一下。系统服务启动和注册流程具体如下:
通过此图,我想大家对系统服务的启动流程已有一个大概认识。各种系统服务启动后,都会在ServiceManager进行注册备注,以方便应用进程调用,这ServiceManager相当于各种系统服务的大管家。另外,Andorid的各种系统服务都运行在system_server进程中,应用进程想要获取系统服务,就需要与system_server进程通信,Binder在其中就起着桥梁的作用。
Android系统中服务大约有八十多个,我们也没必要一一分析,遇到相关服务时,再进一步分析就好。本篇博文主要是针对跨进程通信(IPC),所以也主要分析Andorid源码中常见的通过Binder通信的C/S端,来加深对Android源码的理解。常见的Android源码Binder通信C/S端有:
- ActivityManagerService(AMS),ActivityManagerNative(AMN),ActivityManagerProxy(AMP)
- ApplicationThread(AT),ApplicationThreadNative(ATN),ApplicationThreadProxy(ATP)
1.AMS跨进程通信
首先我们来看一下ActivityManagerNative源码,如下
从此源码来看,这与我们AIDL方式的接口生成的java代码很像,抽象类ActivityManagerNative就相当于抽象类Stub,代理类ActivityManagerProxy就相当于代理类Proxy,所以抽象类AMN就相当于Server端,代理类ActivityManagerProxy就相当于Client端。我们再来看一下ActivityManagerService类
可以看出ActivityManagerService继承至ActivityManagerNative,所以ActivityManagerService也是Server端,类似AIDL方式的AIDLService。我们再来看看ActivityManagerService的获取,在ActivityManagerNative源码中
|
|
主要通过一个静态方法ActivityManagerNative.getDefault()获取,而gDefault就是一个单例,从注释1:ServiceManager.getService(“activity”),我们知主要就是从大管家ServiceManager中获取ActivityManagerService服务,但由于AMS是在不同的进程,所以通过asInterface()获取代理类ActivityManagerProxy来进行Binder跨进程通信。通过调用代理类AMP中的方法,然后跨进程通信,从而调用AMS中的相关方法。
到这里ActivitManagerService的Binder跨进程通信方式就简单介绍完了。
对于AMS,我不得不提一下,因为Android中四大组件Activity、Service、BroadcastReceiver和ContentProvider启动和使用都与其有关,可以说Andorid系统中比较重要的一个类。
2.ApplicationThread跨进程通信
同样的,首先我们先来看一下ApplicationThreadNative此类,源码如下
Binder跨进程通信定义方式,差不多都一样,ApplicationThread跨进程通信也和AIDL方式类似。其中抽象类ApplicationThreadNative为Server端,代理类ApplicationThreadProxy为Client端。我们再来看ApplicationThread类,通过阅读源码,我们知ApplicationThread是ActivityThread中内部类,这里我们也来看看ApplicationThread的源码
可以发现,ApplicationThread继承至ApplicationThreadNative,所以ApplicationThread也是AT跨进程通信的Server端,这里与AIDL的调用方式类似,通过一定的转换获取到代理类ApplicationThreadProxy,从而进行跨进程通信。
ApplicationThread跨进程通信方式,在Android系统中还是比较重要的,它主要与AMS跨进程通信一起使用,当ActivityManagerService执行完响应的操作后,再通过跨进程通信方式与应用进程通信(ApplicationThread是在应用进程中),从而对Andorid的四大组件进行调度,Activity,Service等的启动及生命周期,也就是通过AMS跨进程通信和AT跨进程通信实现的。这点在阅读Activity及Service启动源码的时候,会接触的比较频繁。
到这里,我想说的就说完了。
注:源码采用android-4.1.1_r1版本,建议下载源码然后自己走一遍流程,这样更能加深理解。