首页 > 代码库 > Android系统篇之----解读AMS远端服务调用机制以及Activity的启动流程

Android系统篇之----解读AMS远端服务调用机制以及Activity的启动流程

一、为何本文不介绍Hook系统的AMS服务

在之前一篇文章中已经讲解了 Android中Hook系统服务,以及拦截具体方法的功能了,按照流程本文应该介绍如何Hook系统的AMS服务拦截应用的启动流程操作,但是本文并不会,因为在介绍这个知识点之前,还有一件大事要做,那就是得先分析一下Android中应用的启动流程,如果这个流程不搞清楚的话,后面没办法Hook的,因为你都找不到Hook点,当然Hook代理对象倒是很容易获得,如果没有Hook点,是没办法后续的操作的,所以得先把流程分析清楚了,当然现在关于应用的启动流程的知识已经烂大街了,但是每个人都有不同的分析方式和总结方式,我始终相信我的分析流程是最清晰最有用的。


二、Android中应用的启动流程分析

下面就先来看一下Activity的启动流程,分析启动流程其实很简单,我们直接看源码即可,我们一般在启动Activity的时候都是使用系统的一个方法startActivity操作的,关于这个方法通过跟进代码是在ContextImpl.java中:

技术分享

这里用到了mMainThread变量去执行的操作,再看看这个变量:

技术分享

的确是ActivityThread类,这个类我们在之前分析源码的时候多次提到它了,他是一个应用非常关键的一个类,首先他是一个应用的主线程,其次就是他也是一个程序的入口的地方:

技术分享

后面会介绍这个入口main方法什么时候会执行,下面继续看ActivityThread中的getInstrumentation方法:

技术分享

其实是获取到Instrumentation类型,其实这个类相当于启动Activity的中间者,启动Activity中间都是由它来操作的:

技术分享

看到又调用了ActivityManagerNative.getDefault方法去启动activity了。去看看ActivityManagerNative类:

技术分享

看到这里就有点明白了吧,其实ActivityManagerNative类就是远端服务的中间者Stub类,其实名字不叫Stub罢了,以后其实只要看到是继承了Binder类和实现了AIDL接口类型的就是Stub类,不要关心类名了。看到他的asInterface方法的时候也是和之前的其他系统服务都是类似的,而这里的本地端代理是ActivityManagerProxy类。

下面继续看他的getDefault方法实现,是通过变量gDefault获取的:

技术分享

在这里可以看到了,其实gDefalut借助Singleton实现的单例模式,而在内部可以看到先从ServiceManager中获取到AMS远端服务的Binder对象,然后使用asInterface方法转化成本地化对象,其实就是ActivityManagerProxy对象。然后我们在看看上面调用了startActivityAsUser方法,其实就是调用了ActivityManagerProxy对象的这个方法:

技术分享

这里其实ActivityManagerProxy对象中的方法最终都会调用远端服务Binder对象的transact方法,然后会转接到远端服务中间者ActivityManagerNative的onTransact方法中:

技术分享

这里看到会回调IActivityManager接口中的startActivityAsUser方法,而这个具体实现一般都是在远端服务中的,这里我们可以猜想应该是叫做ActivityManagerService中:

技术分享

有一层调用了,这里是ActivityStackSupervisor类了,这里就不在细分了,最终会在他内部又会调用到ActivityTask类中,又多了一层,然后会调用到ActivityManagerService中的startProcessLocked方法,这里就会执行一段命令:

技术分享

看到了,其实在这个过程之前还有一个操作就是通知Zygote进程需要启动一个新的应用进程,然后执行命令执行ActivityThread的入口方法main,所以这个main方法其实就是一个应用进程的入口方法了,下面就继续分析main方法中都干了什么:

技术分享

在main方法中,调用了自身的attach方法:

技术分享

这里又要回到ActivityManagerService中了,然后又会调用ActivityStackSupervisor中的realStartActivityLocked方法:

技术分享

而在这个方法中,会调用ProcessRecord类型的thread变量的scheduleLaunchActivity方法,而这个thread变量是IApplicationThread类型的:

技术分享

哎,这里看到了IApplicationThread可以想到,这里可能又是一次远端通信了:

技术分享

哎,果然是,不过这里看到这些方法会意外的发现,大部分都是和Activity的生命周期相关的,那么可以猜想这个通信应该是操作Activity的生命周期的,在去看一下远端服务的中间者实现了ApplicationThreadNative:

技术分享

的确,这里的实现机制都是类似的,那么我们在上面了解了AMS的整个通信机制之后,应该知道具体的服务端实现应该是ApplicationThread中,全局搜索一下,这个类尽然是定义在ActivityThread中的:

技术分享

的确,这里是远端的具体方法实现,那么咋们找一下scheduleLaunchActivity方法:

技术分享

最终会调用ActivityThread中的发送消息的方法:

技术分享

然后会调用ActivityThread中全局的Handler类型mH发送消息

技术分享

那么咋们直接去看看消息处理逻辑:

技术分享

继续看这个方法的实现:

技术分享

使用performLaunchActivity构造出一个Activity了:

技术分享

在performLaunchActivity方法中还会构造一个Application出来,继续看:

技术分享

最终又调用了Instrumentation的newActivity方法:

技术分享

好吧,居然在这里构造了一个Activity实例出来了,以前使用Activity的时候,一直好奇这个Activity什么时候创建出来的,这样找到地方了。

然后依然在ActivityManagerService中调用了Activity的生命周期方法:

技术分享

当然,其他的回调方法就不在一一列举了,比如Application中的几个回调方法像内存低的时候,程序异常的时候的回调也都在这里。


三、流程总结

到了这里我们就大致分析完了Android中的Activity启动流程了,从过程中看,还是非常复杂的,其实分析完了之后会发现,自己都有点迷糊了,但是一定要自己一边分析一边记录,下面就是我呕心沥血整理的一张流程图(图片很大,可以下载下来查看高清原图):

技术分享

对照这张图,下面就从头到尾精简的总结狠心知识点:

第一、AMS通信机制分析

首选通过ContextImpl类中的startActivity方法,进入到了Instrumentation类中的execStartActivity方法,然后进入到了ActivityManagerNative中的方法startActivity,到这里就出现第一个转折点和重点了,那就是AMS远端服务架构:

技术分享

在这个过程中,我们在上一篇分析系统中的剪切板服务的时候,这里分析就不难了,主要有四个对象:

1、IActivityManager:这个是远端服务AIDL协议接口类型,定义了很多方法

2、ActivityManagerProxy:这个是本地端中间者对象,也就是我们应用实际操作的本地化对象,他一般是由ActivityManagerNative的asInterface方法获取到的。在这个方法中会实现IActivityManager接口的所有方法,而在具体的方法中会使用远端服务的Binder对象方法transact发送命令给远端中间者。

3、ActivityManagerNative:这个是远端中间者对象,也就是我们之前分析的Stub类,只是不知道为何AMS中不叫这个名称了,所以这里以后分析系统服务源码的时候,应该看到如果继承Binder类同时实现了IXXX接口,那么这个类就是远端服务的中间者,他主要有两个功能,一个是可以将远端服务的Binder对象转化成本地实际对象,还有一个就是可以接受本地端中间者也就是Proxy对象发送的命令,在onTransact方法中做处理,而在这个方法中其实会回调IActivityManager接口中指定的方法,而具体的接口方法实现则是在ActivityManagerService中

4、ActivityManagerService:这个是远端服务中具体方法实现的类,在这里就是真正的逻辑处理了,而这个类是运行在系统服务进程中的,也就是system_server中。

从上面的流程可以看到,Android中的服务大部分都符合这个规则:

IXXX是AIDL接口类型定义逻辑方法

XXXProxy是本地端代理对象,也是给应用操作的实际对象

XXXNative/XXX$Stub是远端服务的中间者对象,主要用来处理应用发送过来的命令处理工作

XXXService是最终的服务逻辑实现方法的地方,运行在远端进程中


第二、Activity栈机制分析

过了第一个转折点之后,我们可以直接去ActivityManagerService中查看具体方法实现逻辑,在这里会出现多层调用,主要是ActivityStackSupervisor类和ActivityStack类,这两个类主要是用来处理Activity栈信息的,因为在启动Activity的时候都会涉及到启动模式,那么这里肯定要处理好应用的Activity栈信息,这里也就是那四种经典的启动模式实现的逻辑的地方,感兴趣的同学可以仔细分析源码。同时在这个过程中出现了几个重要类型:

1》ActivityStack这个是管理本应用中所有Activity的栈结构。
2》ActivityRecord这个是记录当前Activity的信息的,比如在哪进程中ProcessState,当前的状态CurentState等,和Activity是一一对应的。
3》Task这个记录所有Activity的信息的,这里不会区分是哪个应用的Activity了。而这个Task就是我们经常讲到的那个Activity启动模式中的singleTask模式在启动一个Activity的时候就会另外启动一个Task。

4》ProcessRecord这个类记录的是一个进程中的信息,因为一个应用中可能会包含多个进程。


第三、创建和启动应用进程

过了Activity栈信息处理之后,会回到ActivityManagerService中的startProcessLocked方法,在这个方法中干了一件最重要的事,那就是启动应用进程了,当然在这之前还有一步就是向Zygote进程发送请求创建应用进程,启动应用进程其实就是调用Process类执行ActivityThread类,这样就会执行这个类的main函数入口,到这里我们的应用进程就算起来了,然后在看看ActivityThread中的main函数中干了什么呢?


第四、Activity生命周期进程通信机制分析

分析到ActivityThread的main函数中,发现也是一件最重要的事就是attach操作,这个操作主要是绑定一些信息的,首先得绑定Application操作吧,然后跟进方法实现,最后在ActivityStackSupervisor类的realStartActivityLocked方法中调用了ApplicationThread的scheduleLaunchActivity方法,好了,这里就要出现一个转折点了,就是又要出现一个AIDL通信机制了:

技术分享

这个过程其实和上面的AMS通信机制是差不多的,但是这里的对象变了,是ApplicationThread类了,而这通信机制主要是为了Activity的生命周期服务的,上面的AMS通信机制是为了Activity启动服务,两者分开操作也算是比较清晰了,但是我们在这里可以看到,这里的服务端和客户端通信的角色会发生变化了:

在AMS通信中,应用作为客户端会发送指令给服务端处理

在ApplicationThread通信中,应用会作为服务端介绍来自服务端的指令

所以会发现在ActivityManagerService这个服务端类中调用的对象其实是ApplicationThreadProxy对象的。

那具体处理指令的远端是在应用进程中,也就是ApplicationThread类,这个类是在ActivityThread中实现的。


第五、分析Activity的构造和生命周期方法

了解了ApplicationThread通信机制之后,可以去类中看看具体的生命周期方法调用逻辑了,里面处理还是比较简单的,是利用ActivityThread中的Handler变量作为消息发送和处理,然后在调用指定方法即可,最终会发现通过Instrumentation类中的newActivity方法构造一个Activity实例对象,然后启动Activity的处理。然后后续会调用Activity的生命周期方法了。


到这里我们就非常清晰的说明了Activity的启动流程了,这里最关键的点就是要理解Android中的系统服务远端调用机制和Binder机制即可,弄清楚通信中那几个类对象和具体关系。而这里比较复杂的会出现了两个进程通信操作:

技术分享

同时在这个过程中我们发现了Activity启动的过程中栈的处理,几种Activity的启动模式的具体逻辑处理等信息。在这个分析过程中刚开始你会觉得系统这么设计真是够复杂的,但是当你真的理解了,会发现这个设计真的很清晰的。AMS进程通信是为了处理Activity启动工作,ApplicationThread进程通信是为了处理Activity的生命周期工作。


四、总结

Android中了解了Activity启动流程之后,后面我们就可以开始Hook掉系统的AMS服务,拦截Activity的启动方法以及各种生命周期方法了,从而能够达到我们想要的目的。作为一个Android开发者到最后都会避免不了这个Activity启动流程的梳理工作,虽然网上的知识点已经烂大街了,但是真正自己去实践分析效果是截然不同的,所以一定要静下心来自己去分析一遍流程,收获还是非常大的。


更多内容:点击这里

关注微信公众号,最新技术干货实时推送

技术分享
技术分享

Android系统篇之----解读AMS远端服务调用机制以及Activity的启动流程