最近学习了柯元旦所著《Android内核剖析》之AMS原理篇章,结合自己的理解以及对源码的分析,记录一下学习心得,AMS代码非常多,而且和Application以及Activity之间的交互也相对繁杂,这里学习大致的主干流程,之后有时间会再去细看。
AMS的功能
AMS的功能可以概述为以下三个:
首先来看看这个统一调度各个应用程序之间的activity,可以把AMS理解成一个管理员,管理着手机里面的所有应用程序,每当一个应用程序想要启动activity,都要先报告AMS,AMS认为该应用程序可以启动,那么就通知该应用程序去执行启动activity操作,当应用程序启动完毕,也要报告AMS,AMS会记录对应的进程以及对应的activity,以便对activity进行管理和调控,例如内存不足时选择杀死某些优先级的activity。
既然应用程序启动activity需要AMS的调控,那么我们就来看看activity的启动过程以及过程中,AMS如何对应用程序加以调度,并且和应用程序之间进行交互的。
Activity的启动入口是startActivityForResult(),startActivity()其实也是调用了startActivityForResult(),那么就从这个入口去看看具体的启动流程吧;
activity的启动流程
activity的启动流程大概总结为:
启动Activity B -> 当前有正在显示的activity吗 -> 有就先pause() -> B的进程存在吗 -> 不存在则创建 -> B进程启动指定的Activity
首先来看一下这个过程的具体流程图,其实就是上面流程简介的具体化:
现在从源码开始,一步一步的去看看具体的startActivity()的执行流程:
一.首先是startActivity的调用流程
从Activity中调用了startActivity()之后,经过一系列跳转,会执行到Instrument的execStartActivity()方法中,这个Instrumentation是什么呢?可以说它是应用进程的管家,监控着应用进程与系统的所有交互,所有的创建、暂停、停止activity,都是通过它去发起的,它可以统计所有的开销。
那么再来看看execStartActivity()方法的内部实现:
/**
* 1.先看看比较重要的参数的意义:
* @param who: 当前的执行了startActivity的activity对象
* @param contextThread :当前activity 的主线程,即是ApplicationThread对象
* @param token:用于鉴定启动activity的对象
* @param target:需要被启动的activity 对象
**/
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
...
//...省略关于ActivityMonitor测试工具类的部分
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
/**
* 2.看到这里,我们发现Instrumentation将启动activity的工作交给了AMS,这里就
* 涉及到了IPC调用了,IPC调用是同步的,而startActivity()是在主线程中调用的
* 那么这里会导致主线程阻塞吗?
* 答案是不会的,由于AMS内部执行startActivity()是异步的,所以会在很短时间内
* 返回,然后最后再通过回调Activity的onActivityResult(),所以需要在这个方法
* 中传入一个Token,即是Activity的标识
**/
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
再来看下在AMS中是如何去实现这个startActivity的流程的,在AMS中经过一系列的调用,最终会调用如下startActivityAsUser()方法:
/**
* 1.来看一下重要参数的含义:
* @param caller :指的是ApplicationThread,代表当前要启动activity的主线程
* @param callingPackage:发起startActivity的进程包名
* @param resultTo:Activity传来的token变量,对应的是AMS的ActivityRecord,AMS通过来识
* 别客户端进程的Activity
*
**/
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,