AMS相关重要概念

AMS的源码量非常大,因此对AMS中的概念理解非常重要,对于AMS中的成员变量的理解,非常有助于源码的阅读,否则在阅读源码过程中会显得非常晦涩,先对这些概念有个大致认知,后续在看源码时,可以当做手册阅读该篇文章

在源码8.0中,Binder的方式不再是手动写Proxy而是通过AIDL来生成的,所以你在源码中找不到Proxy的话是正常的
记住两点即可:

  1. IXXX.Stub.asInterface 获取的就是客户端对象
  2. 直接实现IXXX.Stub 的就是服务端

不同启动流程

根据启动流程分为三种

  1. 通过Launcher点击app创建新进程,称为 根Activity组件的启动流程
  2. 点击app后进入app,在app中的startActivity操作,称之为 子Activity组件在进程内的启动流程
  3. 在app中,可能出现跳转到其他进程的app的Activity,称之为 子Activity组件在新进程中的启动流程

后续会分别讲解这三种

类结构

ProcessRecord

ProcessRecord(进程数据类)
文件位于 \frameworks\base\services\core\java\com\android\server\am 中
记录一个进程中的信息

变量作用 主要包含
进程文件信息 也就是与该进程对应的APK文件的内部信息,比如
ApplicationInfo info;
String processName;
ArrayMap<String, ProcessStats.ProcessStateHolder> pkgList;//保存该进程中所有的apk文件包名
该进程的内存状态信息 这些信息用于Linux系统的OOM情况的处理,内存不够用时,优先杀掉优先级低的进程
int maxAdj;
int curAdj;//adj的的含义为 调整值
进程中包含的Activity,Provider,Service等 ArrayList<ActivityRecord> activities//进程中所有运行的Activity
final ArraySet<ServiceRecord> services

ActivityRecord

ActivityRecord,ActivityStack的管理对象,每个Activity在AMS对应一个ActivityRecord,来记录Activity的状态以及其他的管理信息

变量作用 主要包含
环境信息 该Activity的工作环境,比如属于哪个Package,所在的进程名称、文件路径、数据路径、图标、主题等,这些信息基本都是固定的
运行状态信息 比如idle、stop、finishing等状态,一般为boolean类型

TaskRecord

TaskRecord,AMS抽象出来的一个“任务”的概念,是记录ActivityRecord的栈,一个“Task”包含若干个ActivityRecord。AMS用TaskRecord确保Activity启动和退出的顺序

变量名称 描述
int taskId 每一个任务的标识
int userId 任务的创建者ID
Intent inteit 创建该任务时对应的Intent
int numActivties 该任务中Activity的数量
ArrayList<ActivityRecord> mActivities 任务中的Activity列表
ActivityStack mStack 任务中的当前的栈信息

ActivityStack

ActivityStack是一个管理类,用来管理系统所有Activity的各种状态,其内部维护了TaskRecord的列表,因此从Activity任务栈这一角度来说,ActivityStack也可以理解为Activity堆栈。它由ActivityStackSupervisor来进行管理的,而ActivityStackSupervisor在AMS中的构造方法中被创建。

ActivityThread

ActivityThread,App的真正入口,主线程
系统每当启动一个应用程序进程时,都会加载一个ActivityThread,并保存在Activity类的成员变量 mMainThread

ApplicationThread

ApplicationThread,用来实现ActivityManagerService与ActivityThread之间的交互。在ActivityManagerService需要管理相关Application中的Activity的生命周期时,通过ApplicationThread的代理对象与ActivityThread通讯。

ApplicationThreadProxy

ApplicationThreadProxy,是ApplicationThread在服务器端的代理,负责和客户端的ApplicationThread通讯。AMS就是通过该代理与ActivityThread进行通信的

Instrumentation

Instrumentation,每一个应用程序只有一个Instrumentation对象,每个Activity内都有一个对该对象的引用。Instrumentation可以理解为应用进程的管家,ActivityThread要创建或暂停某个Activity时,都需要通过Instrumentation来进行具体的操作

对应代码

1
2
3
4
5
public ActivityManagerService(Context systemContext) {
...
mStackSupervisor = new ActivityStackSupervisor(this);
...
}

ActivityStarter

ActivityStarter是Android 7.0新加入的类,它是加载Activity的控制类,会收集所有的逻辑来决定如何将Intent和Flags转换为Activity,并将Activity和Task以及Stack相关联

AMS中的重要调度相关变量

ActivityStack的实例类型

ActivityStackSupervisor中有多种ActivityStack实例

1
2
3
4
5
6
7
public final class ActivityStackSupervisor implements DisplayListener {
...
ActivityStack mHomeStack;
ActivityStack mFocusedStack;
private ActivityStack mLastFocusedStack;
...
}
  • mHomeStack用来存储Launcher App的所有Activity
    • mFocusedStack表示当前正在接收输入或启动下一个Activity的所有Activity
    • mLastFocusedStack表示此前接收输入的所有Activity

ActivityState

ActivityStack中通过枚举存储了Activity的所有的状态

1
2
3
4
5
6
7
8
9
10
11
enum ActivityState {
INITIALIZING,
RESUMED,
PAUSING,
PAUSED,
STOPPING,
STOPPED,
FINISHING,
DESTROYING,
DESTROYED
}

特殊状态的Activity

  • ActivityRecord mPausingActivity = null;//正在暂停的Activity
  • ActivityRecord mLastPausedActivity = null;//上一个已经暂停的Activity
  • ActivityRecord mLastNoHistoryActivity = null;//最近一次没有历史记录的Activity
  • ActivityRecord mResumedActivity = null;//已经Resume的Activity
  • ActivityRecord mLastStartedActivity = null;//最近一次启动的Activity
  • ActivityRecord mTranslucentActivityWaiting = null;//传递给convertToTranslucent方法的最上层的Activity

startActivity 流程图

维护的 ArrayList

ActivityStack中维护了很多ArrayList,这些ArrayList中的元素类型主要有ActivityRecord和TaskRecord,其中TaskRecord用来记录Activity的Task

ArrayList<TaskRecord> mTaskHistory = new ArrayList<>()

最为重要的内部变量,保存了所有正在运行的Activity. TaskRecord 中保存有ActivityRecord

ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>()

基于LRU算法的最近使用的Activity列表

ArrayList<ActivityRecord> mNoAnimActivities = new ArrayList<>()

不考虑转换动画的Activity

ActivityStarter中的 ArrayList

ArrayList<PendingActivityLaunch> mPendingActivityLaunches = new ArrayList<>()

当AMS内部没有准备好时,如果客户进程请求启动某个Activity,那么会暂时被保存到该变量中

这种情况一般发生于系统启动时

Activity栈概念

从Activity任务栈的角度来说,一个或多个ActivityRecord会组成一个TaskRecord,TaskRecord用来记录Activity的栈,而ActivityStack包含了一个或多个TaskRecord

Launch Mode

  • standerd:默认模式,每次启动Activity都会创建一个新的Activity实例
  • singleTop:如果要启动的Activity已经在栈顶,则不会重新创建Activity,同时该Activity的onNewIntent方法会被调用。如果要启动的Activity不在栈顶,则会重新创建该Activity的实例
  • singleTask:
    • 如果要启动的Activity已经存在于它想要归属的栈中,那么不会创建该Activity实例,将栈中位于该Activity之上的所有的Activity出栈,同时该Activity的onNewIntent方法会被调用
    • 如果要启动的Activity不存在于它想要归属的栈中,并且该栈存在,则会重新创建该Activity的实例
    • 如果要启动的Activity想要归属的栈不存在,则首先要创建一个新栈,然后创建该Activity实例并压入到新栈中
  • singleInstance:和singleTask基本类似,不同的是启动Activity时,首先要创建在一个新栈,然后创建该Activity实例并压入新栈中,新栈中只会存在这一个Activity实例

Intent的FLAG

  • FLAG_ACTIVITY_SINGLE_TOP:和Launch Mode中的singleTop效果是一样的。
  • FLAG_ACTIVITY_NEW_TASK:和Launch Mode中的singleTask效果是一样的。
  • FLAG_ACTIVITY_CLEAR_TOP:Launch Mode中没有与此对应的模式,如果要启动的Activity已经存在于栈中,则将所有位于它上面的Activity出栈。singleTask默认具有此标记位的效果
  • FLAG_ACTIVITY_NO_HISTORY:Activity一旦退出,就不会存在于栈中。同样的,也可以在AndroidManifest.xml中设置“android:noHistory”。
  • FLAG_ACTIVITY_MULTIPLE_TASK:需要和FLAG_ACTIVITY_NEW_TASK一同使用才有效果,系统会启动一个新的栈来容纳新启动的Activity.
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:Activity不会被放入到“最近启动的Activity”列表中。
  • FLAG_ACTIVITY_BROUGHT_TO_FRONT:这个标志位通常不是由应用程序中的代码设置的,而是Launch Mode为singleTask时,由系统自动加上的。
  • FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY:这个标志位通常不是由应用程序中的代码设置的,而是从历史记录中启动的(长按Home键调出)。
  • FLAG_ACTIVITY_CLEAR_TASK:需要和FLAG_ACTIVITY_NEW_TASK一同使用才有效果,用于清除与启动的Activity相关栈的所有其他Activity

taskAffinity

我们可以在AndroidManifest.xml设置android:taskAffinity,用来指定Activity希望归属的栈, 默认情况下,同一个应用程序的所有的Activity都有着相同的taskAffinity

taskAffinity在下面两种情况时会产生效果

  • taskAffinity与FLAG_ACTIVITY_NEW_TASK或者singleTask配合。如果新启动Activity的taskAffinity和栈的taskAffinity相同(栈的taskAffinity取决于根Activity的taskAffinity)则加入到该栈中。如果不同,就会创建新栈
  • taskAffinity与allowTaskReparenting配合。如果allowTaskReparenting为true,说明Activity具有转移的能力。拿此前的邮件为例,当社交应用启动了发送邮件的Activity,此时发送邮件的Activity是和社交应用处于同一个栈中。如果发送邮件的Activity的allowTaskReparenting设置为true,此后邮件程序所在的栈位于前台,这个时候发送邮件的Activity就会由社交应用的栈中转移到与它更亲近的邮件程序(taskAffinity相同)所在的栈中

参考博客 老罗 , liuwangshu