Android进阶解密:探访AMS家族

本文作者 刘望舒

资深开发工程师,Android进阶二部曲《Android进阶之光》《Android进阶解密》的作者,公众号“刘望舒”的作者,CSDN人气博主。他在博客中构建了“Android相关原创知识体系”,该体系全面且深入并广获好评。他拥有近10年的开发经验和多年的技术管理经验,对Android框架层及应用层开发有着独到、深入的理解。

AMS处理的逻辑多而复杂,因此AMS并不是“孤军奋战”,而是有一些类和它“共同奋战”,这些类会帮助AMS完成相关逻辑,AMS和这些“共同奋战”的类就被称为AMS家族。Android 7.0和Android 8.0对于AMS相关部分的处理有较大的区别,为了更好地理解AMS家族,这里将分别介绍Android 7.0和Android 8.0的AMS家族。

Android 7.0的AMS家族

ActivityManager是一个和AMS相关联的类,它主要对运行中的Activity进行管理,这些管理工作并不是由ActivityManager来处理的,而是交由AMS来处理的。一般而言,ActivityManager 中的方法是会通过ActivityManagerNative(下面简称AMN)的getDefault方法来得到ActivityManagerProxy(下面简称 AMP ),通过 AMP 就可以和AMN进行通信,而AMN是一个抽象类,它将功能交由它的子类AMS来处理,因此,AMP就是AMS的代理类。AMS作为系统服务,很多API是不会暴露给ActivityManager的,因此ActivityManager并不算是AMS家族的一份子。为了讲解AMS家族,这里以Android 7.0的Activity启动过程来举例,在Activity的启动过程中会调用Instrumentation的execStartActivity方法,如下所示:

在execStartActivity方法中会调用AMN的getDefault方法来获取 AMS 的代理类 AMP ,接着调用了 AMP 的startActivity方法。下面先来查看AMN的getDefault方法做了什么,如下所示:

在getDefault方法中调用了gDefault的get方法,接着往下看,gDefault是一个Singleton类。在注释1处得到名为“activity”的Service引用,也就是IBinder类型的AMS的引用。然后在注释2处将它封装成AMP类型对象,并将它保存到 gDefault 中,此后调用 AMN 的getDefault方法就会直接获得AMS的代理对象AMP。注释2处的asInterface方法如下所示:

android.app.IActivityManager为注释1处的descriptor值,注释1处的代码主要用来查询本地进程是否有IActivityManager接口的实现。如果有,则返回;如果没有,就在注释2处将IBinder类型的AMS引用封装成AMP,AMP的构造方法如下所示:

在 AMP 的构造方法中,将 AMS 的引用赋值给变量mRemote,这样在AMP中就可以使用AMS了。其中IActivityManager是一个接口,AMN和AMP都有这个接口,用于实现代理模式以及 Binder 通信。再回到Instrumentation的execStartActivity方法,来查看AMP的startActivity方法,AMP是AMN的内部类,代码如下所示:

首先将传入的参数写入Parcel类型的data中。在注释1处,通过IBinder类型对象mRemote(AMS的引用)向服务器端的 AMS 发送一个进程间通信请求,类型则为START_ACTIVITY_TRANSACTION。那么服务器端AMS就会从Binder线程池中读取客户端发来的数据,最终会调用AMN的onTransact方法,如下所示:

在onTransact方法中会调用AMS的startActivity方法,如下所示:

startActivity方法最后会返回startActivityAsUser方法,如下所示:

startActivityAsUser方法最后会返回ActivityStarter的startActivityMayWait方法,这一调用过程已经脱离了本节要介绍的AMS家族的范畴,因此这里不做赘述了,具体的调用过程,则可以查看 4.1.2 节的内容。在Activity的启动过程中提到AMP、AMN和AMS,它们共同组成了AMS家族的主要部分,如图1所示。

图1 Android 7.0 AMS家族

AMP是AMN的内部类,都实现了IActivityManager接口,这样它们就可以实现代理模式,具体来讲就是远程代理:AMP和AMN是运行在两个进程中的,AMP是Client端,AMN则是Server端,而Server端中具体的功能都是由AMN的子类AMS来实现的。因此AMP就是AMS在Client端的代理类。AMN又实现了Binder类,这样AMP和AMS就可以通过Binder来进行进程间通信。ActivityManager通过AMN的getDefault方法得到AMP,通过 AMP 我们就可以和AMS进行通信。除ActivityManager以外,有些想要与AMS进行通信的类也需要通过AMP,如图2所示。

图2 AMP和AMS进行通信

从图2看出,除ActivityManager外, ContextImpl如果想要和AMS进行通信也需要先经过AMP。

Android 8.0的AMS家族

Android 8.0的AMS家族与Android 7.0有一些区别,为了更好地理解这些区别,我们仍旧以Activity启动过程来举例,只不过现在系统版本是Android 8.0,在Activity的启动过程中会调用Instrumentation的execStartActivity方法,如下所示:

ActivityManager的getService方法,如下所示:

IActivityManagerSingleton 是一个Singleton类,getService方法调用了它的get方法。在注释1处得到名为“activity”的Service引用,也就是IBinder类型的AMS的引用。接着,我们可在注释2处将它转换成IActivityManager类型的对象。注意,这段代码采用AIDL。IActivityManager.java类是由AIDL工具在编译时自动生成,IActivityManager.aidl的文件路径为frameworks/base/core/java/android/app/IActivityManager.aidl。要实现进程间通信,服务器端(也就是AMS)只需要继承IActivityManager.Stub类并实现相应的方法就可以了。采用AIDL后就不需要使用AMS的代理类AMP了,因此Android 8.0去掉了AMP,代替它的是IActivityManager,它是AMS在本地的代理。让我们再一次回到 Instrumentation 的execStartActivity方法,在注释1处实际上调用的是AMS的execStartActivity方法。剩下的调用过程就不再介绍了,我们来查看Android 8.0的AMS家族,如图3所示。

图3 Android 8.0 AMS家族

对比图3和图1,可以发现Android 8.0 AMS家族要简单得多,ActivityManager 的 getService 方法会得到 IActivityManager。正因如此,AMS只需要继承IActivityManager.Stub类,就可以方便地和ActivityManager实现进程间通信了。

————

本文节选自《Android进阶解密》一书。作为“Android进阶系列”的第二部,本书是继畅销书《Android进阶之光》之后,刘望舒的又一力作!本书基于Android 8.0,将系统源码和应用开发结合讲解,帮助读者融会贯通,破解Android应用开发进阶秘密。阅读原文将带你抢先一睹这本由安卓名家何红辉、徐宜生 、何俊林、潘辰星、周泰良、杨强、Tamic及安卓巴士技术社区联袂力荐的烫手新书。

  • 内容简介:本书是一本Android进阶书籍,主要针对Android 8.0系统源码并结合应用开发相关知识进行介绍。本书共分为17章,从3个方面来组织内容。第一方面介绍Android应用开发所需要掌握的系统源码知识,第二方面介绍JNI、ClassLoader、Java虚拟机、DVM&ART虚拟机和Hook等技术,第三方面介绍热修复原理、插件化原理、绘制优化和内存优化等与应用开发相关的知识点。3个方面有所关联并形成一个知识体系,从而使Android开发者能通过阅读本书达到融会贯通的目的。本书适合有一定基础的Android应用开发工程师、Android系统开发工程师和对Android系统源码感兴趣的读者阅读。

原文发布于微信公众号 - 前沿技墅(Edge-Book)

原文发表时间:2018-10-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏人工智能LeadAI

实时Android语音对讲系统架构

本文属于Android局域网内的语音对讲项目(https://github.com/yhthu/intercom)系列,《通过UDP广播实现Android局域网...

1.3K4
来自专栏Android中高级开发

Android开发之漫漫长途 XI——从I到X的小结

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索...

1202
来自专栏函数式编程语言及工具

Akka(12): 分布式运算:Cluster-Singleton-让运算在集群节点中自动转移

  在很多应用场景中都会出现在系统中需要某类Actor的唯一实例(only instance)。这个实例在集群环境中可能在任何一个节点上,但保证它是唯一的。Ak...

3997
来自专栏Android 研究

APK安装流程详解14——PMS中的新安装流程上(拷贝)补充

mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACK...

2991
来自专栏颇忒脱的技术博客

Servlet 3.1 Async IO分析

Servlet Async Processing提供了一种异步请求处理的手段(见我的另一篇文章Servlet 3.0 异步处理详解),能够让你将Http thr...

1503
来自专栏潇涧技术专栏

App Launch Time Measurement

关于应用启动时间测量的分析已经有不少不错的文章做了总结,下面是比较好的几篇: 1.Android性能优化典范-第6季 2.测量Activity 的启动时间 ...

1132
来自专栏向治洪

Android 应用安装过程分析

在之前的文章中,我们对PakageManagerService启动流程分析 做了简单的介绍,并对PMS系统的启动流程做了详细的解析。上面只是说到了Android...

7069
来自专栏为数不多的Android技巧

Android 插件化原理解析——Hook机制之AMS&PMS

在前面的文章中我们介绍了DroidPlugin的Hook机制,也就是代理方式和Binder Hook;插件框架通过AOP实现了插件使用和开发的透明性。在讲述Dr...

1311
来自专栏ACM小冰成长之路

HDU-5559-Frog and String

ACM模版 描述 ? 题解 丧心病狂的构造题!!! ? Ps. 截图来自 JeraKrs’s blog。 代码 #include <cstdio> #inclu...

1855
来自专栏Ryan Miao

Jackson序列化LocalDate与Springboot集成

Java8的date API一经推出便广受好评,今日也准备用一用,然后就用出问题了。基本用法见https://www.cnblogs.com/woshimrf/...

1661

扫码关注云+社区

领取腾讯云代金券