前言

Binder机制和Handler机制是Android中的两大核心机制,是理解Android系统的基础和关键。本文以AMS为例,简单分析下实名Binder的工作过程。

一、Binder相关的基础概念

在Android中的Binder机制中,主要涉及四部分系统组件,分别是ServiceManager、Binder驱动、Client、Server,其中Client、Server、ServiceManager运行在各自的用户空间中,Binder驱动运行在内核空间中。

  • ServiceManger(SM): 负责注册管理所有的系统Server,并为Client提供查询Server的功能,SM更像是Server和Client中间的一个中介。而SM、Server、Client这三个组件都是运行在各自独立的进程中的。所以这三者之间的通信也是进程间的通信,而且也是采用的Binder机制来进行进程间通信的。在这个通信的过程中,ServiceManger除了要管理各种Server,同时自己也充当着Server的角色。
  • Server: Server通过SM的远程接口,将自己的Binder服务注册到SM中,然后将服务启动起来,同时会启动Binder线程池,等待客户端请求。
  • Client: Client通过SM的远程接口,获取到在SM中相对应的远程Server代理对象进行通信。
  • Binder驱动: Binder驱动是整个Binder通信机制的核心,进程间的数据交换就是通过它来完成的。如果Client要将数据传递给Server,正常情况下,Client把数据从自己的进程空间拷贝到内核空间,然后在从内核空间拷贝到Server的进程空间,这样Server就拿到了Client传递的数据,但是这个过程进行了两次内存拷贝。而通过Binder驱动,同一个物理页面,一方面映射到Server进程虚拟地址空间,另一方面又映射到内核虚拟地址空间。这样,只需要Client把要传递的数据拷贝到内核空间中,然后将拷贝到内核空间的数据同时映射到Server进程虚拟地址空间和内核虚拟地址空间,这样Server和内核就可以共享该数据了,一次内存拷贝就可以了。

这里需要说明一点,并不是所有的Binder服务都会注册到SM中的,像AMS、WMS、PMS这些系统的Binder服务是会注册到SM中并受SM管理的,而像我们开发者平常通过binderService的方式创建的Binder服务是不会注册到SM中的。这些需要注册到SM中的Binder服务称之为实名Binder,不需要注册到SM中的Binder服务称之为匿名Binder,匿名Binder的传递和使用是需要依赖于实名Binder的。本文以AMS为例,来学习下实名Binder,匿名Binder会在下篇文章中结合通过Aidl和binderService创建的Binder服务来具体分析。

上图描述了应用程序客户端调用AMS进行Binder进程间通信的一个大概流程,要注意一点,AMS和SM的通信也是进程间通信的一个过程,服务的注册过程是一次IPC调用,这里图中就忽略了该过程:

  • 首先一个进程向驱动申请成为SM,驱动同意之后,该进程就是SM进程,SM会创建一张表来记录和管理所有向它注册的Binder服务。
  • AMS通过SM的addService方法注册到SM中(这也是一个进程间通信的过程,先不考虑),这样,AMS就添加到SM的服务列表中了。
  • Client需要调用AMS中的方法的时候,会先到SM中查询AMS,查询到AMS的信息后,将AMS的代理对象返回给客户端,然后客户端就可以通过这个代理对象调用AMS里面的方法了。
    这里需要注意,客户端拿到的AMS对象并不是服务端的AMS对象本身,而是在经过Binder驱动的时候产生了一个跟AMS功能完全一致的代理对象,这个代理对象只是服务端对象的一个影子,它具备服务端本地对象的所有能力,但是它没有具体的功能实现,它只是包装了一些参数和返回值相关数据,最终的方法实现还是要转交给服务端的AMS对象进行处理的。

二、 AMS注册到SM的过程

Android系统启动的时候会启动SyetemServer进程,该进程的程序执行入口是SystemServer类的main方法,源码如下:

public static void main(String[] args) {    new SystemServer().run();}

上述方法中调用了SystemServer的run方法,看下run方法的关键代码:

private void run() {..................try {       traceBeginAndSlog("StartServices");              //注释1 开启系统服务       startBootstrapServices();       startCoreServices();       startOtherServices();       SystemServerInitThreadPool.shutdown();        } catch (Throwable ex) {       Slog.e("System", "******************************************");       Slog.e("System", "************ Failure starting system services", ex);       throw ex;   } finally {       traceEnd();   }..................}

在注释1处会开启系统服务,跟进去startBootstrapServices()方法:

private void startBootstrapServices() {    //注释2 创建ActivityManagerService    mActivityManagerService = mSystemServiceManager.startService(              ActivityManagerService.Lifecycle.class).getService();        traceBeginAndSlog("SetSystemProcess");  //注释3 调用了AMS的setSystemProcess方法      mActivityManagerService.setSystemProcess();      traceEnd();}

在注释2处创建了AMS对象,在注释3处调用了AMS的setSystemProcess方法,下面跟到AMS里看下setSystemProcess方法:

public void setSystemProcess() {//注释4 ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,                 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);                 }

在注释4处,通过ServiceManager.addService方法将AMS注册到了ServiceManager中,第一个参数是SM注册表里对应的字符串key,Context.ACTIVITY_SERVICE的值是"activity",第二个参数this是AMS对象本身,由于AMS向SM的注册过程也是跨进程的,所以SM的注册表里存储的value是AMS的信息而不是AMS对象本身,这样当客户端需要使用AMS的时候,就可以从SM的注册表里通过字符串key(“activity”)查询到相对应的AMS服务信息了,然后在经过Binder驱动为客户端创建一个AMS的代理对象返回给客户端,这样客户端就可以通过这个代理对象去调用AMS中的方法了,其他Binder服务的通信过程同理。

三、客户端是如何使用AMS服务的

在平常开发的应用程序中,有很多地方都会跟AMS打交道,其中四大组件的运行就需要依赖于AMS服务,平时通过ActivityManager调用的方法其内部都是通过调用AMS的服务来具体实现的,由于应用程序和AMS是在两个不同的进程中,所以应用程序调用AMS服务的过程是跨进程的,这里以获取应用程序运行的任务栈为例,来学习一下应用程序客户端是如何调用AMS服务的:

ActivityManager activityManager = (android.app.ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);List listInfos = activityManager.getRunningTasks(20);

上面这段代码应该很熟悉,通过context的getSystemService方法获取到ActivityManager对象,然后调用ActivityManager的getRunningTasks方法,ActivityManager就是一个壳,它的存在避免了AMS直接暴露给应用程序,而是通过对外提供的ActivityManager来操作AMS,这样更安全,下面看下ActivityManager的getRunningTasks方法:

@Deprecatedpublic List getRunningTasks(int maxNum)       throws SecurityException {   try {//注释5       return getService().getTasks(maxNum);   } catch (RemoteException e) {       throw e.rethrowFromSystemServer();   }}

在注释5处调用了getService()的getTasks方法,那么这个getService是什么呢?跟下这个方法的代码:

public static IActivityManager getService() {//注释6    return IActivityManagerSingleton.get();}private static final Singleton IActivityManagerSingleton =        new Singleton() {            @Override            protected IActivityManager create() {//注释7                final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);                final IActivityManager am = IActivityManager.Stub.asInterface(b);                return am;            }       };

在注释6处可以看到,getService方法的返回值就是IActivityManagerSingleton.get()方法的返回值,结合注释7处可以知道这个返回值就是am对象,在注释7处通过调用ServiceManager的getService方法查询出AMS的信息并转换为代理对象am。这个am对象是IActivityManager类型的,而IActivityManager是个aidl,根据aidl的规则和原理,可以知道远程服务的具体实现一定是IActivityManager.Stub的实现类,而AMS实现了IActivityManager.Stub,所以AMS是远程服务的具体实现。这里需要说明一点,Binder服务并不是我们Android中四大组件中的Service,而是能被客户端访问并具有Binder通信能力的一个功能类(比如AMS/WMS/PMS这些)。下面是AMS的继承关系源码:

//AMS继承并实现了IActivityManager.Stubpublic class ActivityManagerService extends IActivityManager.Stub        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {..................................}

我们可以类比自己写的aidl,当我们的应用程序需要向AMS发起通信的时候,会通过IActivityManager的Proxy的transact方法发起binder通信,然后IActivityManager的Stub的onTransact方法会接收到客户端发送的远程通信请求,最终会调用到Stub的具体实现类AMS中相对应的方法进行处理,这样整个进程间通信过程就完成了,具体aidl内部的工作流程在下篇匿名Binder中,结合自己定义的aidl进行学习和梳理。

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. Python list sort方法的具体使用
  3. python list.sort()根据多个关键字排序的方法实现
  4. Tabhost中Activity绑定Service
  5. android bluetooth
  6. android:onClick都做了什么
  7. Android(安卓)AsyncTask
  8. Android(安卓)SDK23以上(包括23)无法使用httpclient的处理方法
  9. android 属性android:visibility及 view的setVisibility方法值的

随机推荐

  1. android 调用分享
  2. ssssss
  3. Android Camera怎样打开关闭闪光灯
  4. android listview 与 一般多线程配合产生
  5. Android Audio代码分析2 - 函数getMinBuf
  6. Android Hander的使用
  7. Android状态栏上添加按钮(程序部分)
  8. [centos] 安装 ANDROID SDK
  9. Android实现红包雨动画效果
  10. BUG回忆录