一 概述
AMS 也即 ActivityManagerService 是 Android framework 的三大核心功能之一(其他两个是 View,WindowManagerService),它的代码庞大(约2万行),逻辑纷繁,主要负责系统中四大组件的启动、切换、调度及应用程序进程的管理和调度等工作。对于这样庞大复杂的代码,我们应该从它的功能角度出发,分析它的每个功能对应的代码逻辑,逐个突破。
AMS 是运行在 SystemServer 进程中众多服务中的一个(如:PackageManagerService,WindowManagerService 等),这些服务分别运行在不同的线程中.其他进程需要通过 Binder 机制来和 ActivityManagerService 跨进程通信,一个应用进程在和 ActivityManagerService 交互的过程中,还涉及到 ActivityThread,ApplicationThread 等类的交互,下面将介绍这几个类的相关概念,以及他们之间的交互模型。
二 ActivityThread和ApplicationThread
ActivityThread 类代表的就是 Android 应用程序进程中的主线程,注意它代表主线程而不是说它就是一个 Thread 线程类,因为系统在创建完一个新应用程序进程后,会在这个进程的主线程中调用 ActivityThread 类的 main 函数来初始化这个进程,在这个 main 函数里会执行一个 loop 循环使当前主线程进入消息循环,所以我们称 Android 应用程序进程的入口函数是 ActivityThread 类的 main 函数,也就是说一个ActivityThread 类对应于一个应用程序进程。
public final class ActivityThread extends ClientTransactionHandler {
......
final ApplicationThread mAppThread = new ApplicationThread();
final Looper mLooper = Looper.myLooper();
final H mH = new H();
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
......
final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
......
Application mInitialApplication;
final ArrayList<Application> mAllApplications
= new ArrayList<Application>();
......
final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders
= new ArrayMap<IBinder, ProviderClientRecord>();
......
private class ApplicationThread extends IApplicationThread.Stub {
......
}
......
}
ActivityThread 中有几个重要的实例变量需要简要介绍下,成员变量 mActivities 包含了当前进程中所有的 Activity 组件信息,注意集合中不是简单的保存 Activity 实例,而是将每个 Activity 实例对应的相关数据封装成一个 ActivityClientRecord 保存起来,内部保存了很多 Activity 相关的数据,其中当然也有其对应的 Activity 实例。同样的,mServices 保存的是当前进程中所有的 Service 组件信息,不过就是直接存放的当前 Service 的信息,没有封装。mLocalProviders 保存的是当前进程中所有的 ContentProvider 组件信息。这些集合都有一个 IBinder 类型的 Key,其作用也就是显而易见的,即为了进行 IPC 调用,这个 IBinder 类型的 Key 作为一个唯一标识使用,通过这个 Key 可以在 AMS 中找到其对应的组件信息记录。
mAppThread 是 ApplicationThread 类型的变量,它是 ActivityThread 的内部类,也是一个 Binder 类型的对象,也就是说可以作为服务端实现跨进程通信。那么,在应用进程中的 ActivityThread 通过 Binder 机制和系统进程中的 AMS 通信时,使用的就是 ApplicationThread 对象来作为应用进程的服务端,接收 AMS 的指令并将指令发送给 ActivityThread 执行,所以它是 ActivityThread 与 AMS 跨进程通信的桥梁。因为 ApplicationThread 对象会被 Binder 线程调用,而 ActivityThread 是运行在主线程中的,所以 ApplicationThread 会通过 mH 对象发送消息给主线处理。
三 AMS主要相关类
3.1 ProcessRecord
一个 APK 文件运行时会对应一个进程, 当然, 多个 APK 文件也可以运行在同一个进程中。ProcessRecord 正是记录一个进程中的相关信息, 该类中内部变量可分为三个部分,主要信息包括:该进程对应的 APK 文件的内部信息,该进程的内存状态信息,以及该进程中包含的所有 Activity、Provider、Service 等组件信息。
class ProcessRecord implements WindowProcessListener {
......
final ApplicationInfo info; //进程中第一个APK包信息
......
final String processName;
......
// List of packages running in the process
final ArrayMap<String, ProcessStats.ProcessStateHolder> pkgList = new ArrayMap<>();
......
IApplicationThread thread;
......
int pid;
......
final ArraySet<BroadcastRecord> curReceivers = new ArraySet<BroadcastRecord>();
......
// all ServiceRecord running in this process
final ArraySet<ServiceRecord> services = new ArraySet<>();
......
final ArrayMap<String, ContentProviderRecord> pubProviders = new ArrayMap<>();
}
3.2 TaskRecord
在 Android 中,每一件事可以被看作是一个 Task,一个 Task 又可以被细分成多个子步骤,每个子步骤可以被看作是一个 Activity。这个 Activity 既可以是本程序进程中的 Activity,也可以是其他程序进程中的的 Activity,这种基于组件的设计,弱化了进程的概念,通过重用 Activity 可以节省一定的开销,同时也为用户提供了一致的界面和用户体验。比如,你在自己的程序中想发邮件,你就可以定义一个具有 “send” 动作的 Intent,并且传入一些数据,如对方邮箱地址、邮件内容等,然后就会有系统的 Activity 被打开,发送完邮件,点击返回仍然还是会回到你的应用程序当中,这让用户看起来好像刚才那个编写邮件的 Activity 就是你的应用程序当中的一部分。所以说,即使有很多个 Activity 分别都是来自于不同应用程序的,Android 系统仍然可以将它们无缝地结合到一起,之所以能实现这一点,就是因为这些 Activity 都是存在于一个相同的任务 (Task) 当中的,用数据结构 TaskRecord 表示。
Task 中有一个 ActivityRecord 的集合 mActivities,它是以 Stack 的方式来管理其中的 Activity,所以,具有相同 Task 的 Activity 会放在同一个集合中(也叫回退栈), 先启动的 Activity 成为栈底成员,最后启动的 Activity 将作为栈顶成员显示在界面上。当有多个 Task 时,Android 系统只支持一个处于前台的 Task,其余的 Task 均处于后台,这些后台 Task 内部 Activity 保持顺序不变,用户可以一次将整 个Task 挪到后台或置为前台。比如,当用户在 Home 界面上点击了一个应用的图标时,这个应用的任务就会被转移到前台。如果这个应用目前并没有任何一个任务的话(说明这个应用最近没有被启动过),系统就会去创建一个新的任务,并且将该应用的主 Activity 放入到返回栈当中。如果用户一直地按 Back 键,这样返回栈中的 Activity 会一个个地被移除,直到最终返回到主屏幕。当返回栈中所有的 Activity 都被移除掉的时候,对应的任务也就不存在了。用过 Android 手机的同学应该知道,长按 Home 键,系统会弹出近期 Task 列表,使用户能快速在多个 Task 间切换。
下面我们用一个例子来说明这种管理方式。
上图中显示了用户在手机中的3个任务,A:短信,B:拍照,C:邮件,每一个任务在 Android 中是用一个 Task 来表示。每一个 Task 中包含许多不同的界面显示给用户,其中每一个界面,我们都可以看做是一个 Activity。我们从上图中可以看到,邮件 Task 复用了短信和拍照中的 Activity A1 和 B2。这其实很容易理解,这种设计既节省了内存开销,而且保证同一功能界面每次展示给用户都是相同的,保证了用户体验的一致性。在 Android 中要实现上面这样的一套管理机制,需要设计一些数据结构来支持,涉及到的数据结构有:ActivityRecord,TaskRecord,ActivityStack,ActivityDisplay,ActivityStackSupervisor 和 ProcessRecord,我们先用一张图来描述这些数据结构之间的关系,然后在分别对它们进行说明。
class TaskRecord extends ConfigurationContainer {
......
final int taskId; // Unique identifier for this task.
String affinity; // The affinity name for this task, or null; may change identity.
......
/** List of all activities in the task arranged in history order */
final ArrayList<ActivityRecord> mActivities;
/** Current stack. Setter must always be used to update the value. */
private ActivityStack mStack;//当前任务的管理者
......
}
TaskRecord 的 affinity 属性是第一次创建这个 Task 时指定的值,可以把他当作这个 Task 的名字,Activity 所在的 Task 可以通过 AndroidManifest.xml 中 标签中的 android:taskAffinity=“xxx” 来指定,通常不去主动设置一个 Activity 的 taskAffinity 属性,那么 taskAffinity 的值缺省使用包名。所以,同一个应用中所有的 Activity 的 taskAffinity 属性值默认都是相同的,都是包名.所以在应用中使用 FLAG_ACTIVITY_NEW_TASK 标志去启动一个本应用中的一个 Activity,也不会创建一个新的 Task,除非这个 Activity 额外指定了不同的 taskAffinity 属性值。
mActivities 表示当前栈中管理的所有 ActivityRecord.
mStack 表示当前 TaskRecord 所属的 ActivityStack。TaskRecord 除了要维护管理它包含的 Activ