内容出自Android内核剖析书
AmS 所 供的主要功能:
- 统一调度各应用程序的 Activity。应用程序要运行 Activity,会首先 给 AmS,然后由 AmS决定该 Activity 是否可以启动,如果可以,AmS 再通知应用程序运行指定的 Activity。换 话说, 运行 Activity 是各应用进程的“内 ”,AmS 并不 ,但是 AmS 必须知道各应用进程都运行 了哪些 Activity。
- 内存管理。Android 方声称,Activity 出后,其所在的进程并不会被立即 ,从而下 在 启动该 Activity 时能 启动 度。这些 Activity 只有当系统内存 张时, 会被自动 , 应用程序不用关 这个问题。而这些正是在 AmS 中完成的。
- 进程管理。AmS 向外 供了查 系统正在运行的进程信息的 API。这些都比较简单。 下面就根据这些功能点,来分析 AmS 的代码。
Activity调度机制
在 Android 中,Activity 调度的基本思 是这样的:各应用进程要启动新的 Activity 或者停止当前 的 Activity,都要首先 给 AmS,而不能“ 自处理”。AmS 在内部为所有应用进程都做了 ,当AmS 接到启动或停止的 时,首先更新内部 ,然后再通知相应客户进程运行或者停止指定的 Activity。由于 AmS内部有所有Activity的 ,也就理所当然地能 调度这些Activity,并根据Activity 和系统内存的 态自动 后 的 Activity。
具体来讲,启动一个 Activity 有以下几种方式。
- 在应用程序中调用 startActivity()启动指定的 Activity。
- 在 Home 程序中单 一个应用图标,启动新的 Activity。
- 按“Back”键,结 当前 Activity,自动启动上一个 Activity。
- 按“Home”键,显示出当前任务列表,从中 一个启动。
这四种启动方式的主体处理流程都会按照第一种启动方式运行,后面三种方式只是在前端消息处理上各有不同 。
AmS的几个重要概念
AmS 中定义了几个重要的数据类,分别用来保存进程(Process)、活动(Activity)和任务(Task)。
ProcessRecord
该类framework/base/services/java/com/android/server/am/ 下,该 最后的 am 代表 Activity Manager,和 AmS 有关的重要类都在该目 下。
一个 APK 文件运行时会对应一个进程,当然,多个 APK 文件也可以运行在同一个进程中。 ProcessRecord 正是 一个进程中的相关信息,该类中内部变量可分为三个部分, 先不用 具 体某个变量如何被使用,而只需要先了解它们的作用.
HistoryRecord
AmS 中使用 HistoryRecord 数据类来保存每个 Activity 的信息,有些读者可能 ,Activity 本身也 是一个类 ,为什么还要用 HistoryRecord 来保存 Activity 的信息,而不直接使用 Activity 呢?因为, Activity 是具体的功能类,这就好比每一个读者都是一个 Activity,而“ 校”要为每一个读者建立一 个 案,这些 案中并不包含每个读者具体的 习能力,而只是 生的 信息、 名、出生 、 关系等。HistoryRecord 正是 AmS 为每一个 Activity 建立的 案,该数据类中的变量主要包含两部分
需要注意,HistoryRecord 类也是一个 Binder,它基于 IApplicationToken.Stub 类,因此,可以被 IPC 调用,一般是在 WmS 中进行该对象的 IPC 调用。
TaskRecord
AmS 中使用任务的 确保 Activity 启动和 出的顺序。比如以下启动流程,A、B、C 分别代表 三个应用程序,数字 1、2、3 分别代表该应用中的 Activity。
A1 A2 A3 B1 B2 C1 C2,此时应该处于 C2,如果 AmS 中没有任务的 ,此时 要从 C2 启动 B1,那么会存在以下两个问题:
- 虽然程序上是要启动 B1,但是用户可能期望启动 B2,因为 B1 和 B2 是两个关联的 Activity,并 且 B2 已经运行于 B1 之后。如何 供给程序员一种 , 然指定启动 B1,但如果 B2 已经运 行,那么就启动 B2。
- 假设已经成功从 C2 转到 B2,此时如果用户按“Back”键,是应该回到 B1 呢,还是应该回到 C2?
任务 的引入正是为了解决以上两个问题,HistoryRecord 中包含一个 int task 变量,保存该 Activity 所属哪个任务,程序员可以使用 Intent.FLAG_NEW_TASK 标识 AmS 为启动的 Activity 重 新创建一个 Task。
有了 Task 的 后,以上情况将会是这样的:
然程序明确指定从 C2 启动到 B1,程序员可以在 intent 的 FLAG 中添加 NEW_TASK 标识,从而 使得 AmS 会判断 B1 是否已经在 mHistory 中。如果在,则 到 B1 所在的 Task,并从该 Task 中的最上 面的 Activity 处运行,此处也就是 B2。当然,如果程序的确要启动 B1,那么就不要使用 NEW_TASk 标识,使用的话,mHistory 中会有两个 B1 , 属于不同的 Task。
需要注意的是,TaskRecord 中并没有该任务中所包含的 Activity 列表,比如 ArrayList 或者 HistoryRecord[]之类的变量,这意 着不能直接通过任务 id 到其所包含的 Activity。要 到这个 目的,可以 AmS 中 mHistory 中的全部 HistroyRecord,然后根据每一个 HistoryRecord 中的 TaskRecord task 变量确定是否属于指定的任务。
AmS 中的一些重要调度相关的变量
要了解 AmS 调度、管理系统中的 Activity 的 节,必须了解 AmS 中定义的重要内部变量。要一下 了解这些变量的使用时机并 易事,因此,本节仅简要说明一些变量的作用,至于具体使用的时机,要 结 调度的具体过程了解。
系统常量
- static final int MAX_ACTIVITIES = 20;
系统只能有一个 Activity 处于执行 态,对于 执行 态的 Activity,AmS 会在内部暂时缓存起来, 而不是立即 ,但如果后 的 Activity 数目 过该常量,则会 制 一些 先 较 的 Activity, 所谓的“ 先 ”的规则见第 10.2 节。
- static final int MAX_RECENT_TASKS = 20;
AmS 会 最近启动的 Activity,但只 20 个, 过该常量后,AmS 会 最 的 Activity。
- static final int PAUSE_TIMEOUT = 500;
当 AmS 通知应用进程暂停指定的 Activity 时,AmS 的 是有 的,因为只有 500 ,如果应 用进程在该常量时间内还没有暂停,AmS 会 制暂停关 该 Activity。这就是为什么在应用程序设计时, 不能在 onPause()中做过多事情的原因。
- static final int LAUNCH_TIMEOUT = 10*1000;
当 AmS 通知应用进程启动(Launch)某个 Activity 时,如果 过 10s,AmS 就会放 。
- static final int PROC_START_TIMEOUT = 10*1000;
当 AmS 启动某个客户进程后,客户进程必须在 10 之内 AmS 自己已经启动,否则 AmS 会 认为指定的客户进程不存在。
等待序列
由于 AmS 用 Service 机制运作,所有的客户进程要做什么事情,都要先请求 AmS,因此,AmS 内部必须有一些消息序列保存这些请求,并按顺序依 进行相应的操作。
- final ArrayList mHistory = new ArrayList();
这是最最重要的内部变量,该变量保存了所有正在运行的 Activity,所谓正在运行是指该 HistoryRecord 的 finishing 态为 true。比如当前和用户 的 Activity 属于正在运行,从 A1 启动到 A2, 管 A1 看不见了,但是依然是正在运行,从 A2 按“Home”键回到 面,A2 也是正在运行,但如果 从 A2 按“Back”键回到 A1,A2 就不是正在运行 态了,它会从 mHistory 中 除 。
- private final ArrayList mLRUActivities = new ArrayList();
LRU 代表 Latest Recent Used,即最近所用的 Activity 列表,它不像 mHistory 仅保存正在运行的 Activity,mLRUActivities 会保存所有过去启动过的 Activity。
- final ArrayListmPendingActivityLaunches = new ArrayList();
当 AmS 内部还没有 好时,如果客户进程请求启动某个 Activity,那么会被暂时保存到该变量 中,这也就是 Pending 的含义。这种情况一般发生在系统启动时,系统进程会查 系统中所有属性为 Persisitant 的客户进程,此时由于 AmS 也正在启动,因此,会暂时保存这些请求。
- final ArrayList mStoppingActivities = new ArrayList();
在 AmS 的设计中,有这样一个理 : 先启动,其 再停止。即当用户请求启动 A2 时,如果 A1 正在运行,AmS 首先会暂停 A1,然后启动 A2,当 A2 启动后再停止 A1。在这个过程中,A1 会被 时 保存到 mStoppingActivities 中,知道 A2 启动后并处于 时,再回过头来停止 mStoppingActivities 中 保存的 HistoryRecord 列表。
- final ArrayList mFinishingActivities = new ArrayList();
和 mStoppingActivities 有点类似,当 AmS 认为某个 Activity 已经处于 finish 态时,不会立即 该 Activity,而是会保存到该变量中,直到 过系统设定的 线后, 去回收该变量中的 Activity。
当前不同状态的HistroryRecord
- HistoryRecord mPausingActivity = null;
正在暂停的 Activity,该变量只有在暂停某个 Activity 时 有值,代表正在暂停的 Activity。
- HistoryRecord mResumedActivity = null;
当前正在运行的 Activity,这里的正在运行并不见得一定是正在与用户 。比如当用户请求执行 A2 时,当前正在运行 A1,此时 AmS 会首先暂停 A1,而在暂停的过程中,AmS 会通知 WmS 暂停获 取用户消息,而此时 mResumedActivity 依然是 A1。
- HistoryRecord mFocusedActivity = null;
这里的Focus并 是正在和用户 ,而是AmS通知WmS应该和用户 的Activity,而在 WmS 正处理这个消息之前,用户还是不能和Activity 。
- HistoryRecord mLastPausedActivity = null; 上一 暂停的 Activity。