前言
相信在看過我前面幾篇分析 Android 系統原始碼文章的知道,基本上每一篇文章都會涉及到 AMS 知識,那麼 AMS 主要的作用是幹嘛的,在這幾篇文章中充當什麼角色,當時也沒有具體說明,那麼這一篇文章將來全面分析 AMS, 在閱讀本篇文章之前,建議先看一下我下面的幾篇文章,這樣有助於快速理解並進入狀態。
Android 8.0 原始碼分析 (一) SystemServer 程式啟動
Android 8.0 原始碼分析 (二) Launcher 啟動
Android 8.0 原始碼分析 (三) 應用程式程式建立到應用程式啟動的過程
Android 8.0 原始碼分析 (四) Activity 啟動
Android 8.0 原始碼分析 (五) Service 啟動
Android 8.0 原始碼分析 (六) BroadcastReceiver 啟動
Android 8.0 原始碼分析 (七) ContentProvider 啟動
Android 8.0 原始碼分析 (八) ActivityManagerService
Android 8.0 原始碼分析 (九) WindowManager
Android 8.0 原始碼分析 (十) WindowManagerService 的視窗管理
下面我們先從 AMS 啟動來一步一步往下分析
AMS 啟動過程
AMS 啟動是在 SystemServer 程式中啟動的,關於 SystemServer 程式的啟動我們在講解系統原始碼的第一篇文章已經講過,這裡就直接從它的 main 函式入口分析,程式碼如下:
//SystemServer.java
/**
* 這裡的 main 函式 主要是 zygote 通過反射呼叫
*/
public static void main(String[] args) {
new SystemServer().run();
}
複製程式碼
main 方法裡面初始化了 SystemServer 物件並呼叫了本身的 run 方法,程式碼如下:
//SystemServer.java
private void run() {
try {
...//程式碼部分省略
/**
* 建立 主執行緒的訊息 Looper
*/
Looper.prepareMainLooper();
/**
* 1. 載入動態庫 libandroid_servers .so
*/
System.loadLibrary("android_servers");
...//程式碼部分省略
/**
* 建立系統級別的 Context
*/
createSystemContext();
/**
* 2. 建立 SystemServiceManager 它會對系統服務進行建立、啟動和生命週期管理
*/
mSystemServiceManager = new SystemServiceManager(mSystemContext);
mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
} finally {
}
// Start services.
try {
traceBeginAndSlog("StartServices");
/**
* 3. SystemServiceManager啟動了 AMS 、PowerMS、PackageMS 等服務
*/
startBootstrapServices();
/**
* 4. 啟動了 DropBoxManagerService、BatteryService、UsageStatsService 和 WebViewUpdateService
*/
startCoreServices();
/**
* 5. 啟動了CameraService、AlarmManagerService、VrManagerService 等服務。
*/
startOtherServices();
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
throw ex;
} finally {
traceEnd();
}
...//程式碼省略
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
複製程式碼
其實這裡的 run 方法在講解 SystemServer 的時候已經講解,這裡我們們就再來學習一遍,就相當於複習了,下面根據小點來大概總結下 run 方法:
- 在註釋 1 處載入了動態庫
libandroid_servers.so
檔案; - 在註釋 2 處建立 SystemServiceManager ,它會對系統的服務進行建立、啟動和生命週期管理;
- 在註釋 3 處的
startBootstrapServices
方法中,通過註釋 2 建立好的 SystemServiceManager 來啟動 ActivityManagerService 、PowerManagerService、PackageManagerService 等服務。 - 在註釋 4 處的
startCoreServices
方法中則啟動了 DropBoxManagerService、BatteryServices、UsageStatsService、WebViewUpdateService 等服務。 - 在註釋 5 處的
startOtherServices
方法中啟動了 CameraService、AlarmManagerService、VrManagerService 等服務。
在註釋 3,4,5 中啟動的服務均為 SystemService
服務,從當中的方法可以看出,官方把這些服務分為了 3 個大類,分別是引導服務、核心服務和其它服務。這裡我們啟動了許多的系統服務,我們並不會一一去介紹它們,我們的主要任務還是瞭解引導服務中的 AMS 是如何啟動的,請看下面程式碼:
//SystemService.java
private void startBootstrapServices() {
...//省略部分程式碼
//1.
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
...
}
複製程式碼
在註釋 1 處呼叫了 SystemServiceManager 的 startService 方法,該方法的引數 AMS.Lifecyle.class; 下面我們看下 SystemServiceManager 的 startService 實現,如下程式碼:
//SystemServiceManager.java
public void startService(@NonNull final SystemService service) {
//1. 將服務新增進開啟服務的總容器中
mServices.add(service);
// Start it.
long time = System.currentTimeMillis();
try {
//2.
service.onStart();
} catch (RuntimeException ex) {
...//省略部分程式碼
}
}
複製程式碼
傳入 SystemService 型別的 service 物件的值為 AMS.Lifecycle.class 。在註釋 1 處將 service 物件新增到 ArrayList 型別的 mServices 中來完成註冊。在註釋 2 處呼叫 service 的 onStart 方法來啟動 service 物件,這個 service 物件具體指的是什麼呢? 我們接著往下看,Lifecycle 是 AMS 的內部類,程式碼如下:
//AMS.java
public static final class Lifecycle extends SystemService {
private final ActivityManagerService mService;
public Lifecycle(Context context) {
super(context);
//1.
mService = new ActivityManagerService(context);
}
@Override
public void onStart() {
//2.
mService.start();
}
public ActivityManagerService getService() {
//3.
return mService;
}
}
複製程式碼
上面的程式碼需要結合 SystemServiceManager 的 startService 來分析。註釋 1 在 Lifecycle 物件建立的時候會初始化 AMS 例項。當呼叫 SystemService 型別的 service 服務的 onStart 方法會執行註釋 2 的 AMS start 方法,最後註釋 3 得到的就是 AMS 例項物件了,AMS 啟動就完成了。
AMS 與應用程式程式
在 SystemServer 中講到了 ZygoteInit main方法是開起 Java 框架的入口,在 main 中會建立一個 Server 端的 Socket , 這個 Socket 用來等待 AMS 請求 Zygote 程式建立一個新的子程式的任務。那麼要啟動一個應用程式首先就要保證應用程式的應用程式必須存在。在啟動一個應用程式元件的前提就會先檢查這個應用程式所需要依附的程式是否存在,如果不存在就會在 AMS 建立一個本地 Socket 連線 Zygote 的服務端 Socket ,傳送建立需要啟動程式的資訊給 Zygote ,這裡就以為常用的 Activity 啟動為例,來分析 AMS 與應用程式程式的關係,Activity 在啟動過程中會呼叫 ActivityStackSupervisor#startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig)
方法,下面請看原始碼具體實現:
//ActivityStackSupervisor.java
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
/**
* 1. 獲取即將啟動的 Activity 所在的應用程式程式
*/
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.getStack().setLaunchTime(r);
/**
* 2. 判斷要啟動的 Activity 所在的應用程式程式如果已經執行的話,就會呼叫註釋 3
*/
if (app != null && app.thread != null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
mService.mProcessStats);
}
/**
* 3. 如果已經正在執行呼叫 realStartActivityLocked 函式
*/
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
}
/**
* 4,如果啟動 Activity 所需要的程式不存在,就呼叫 AMS startProcessLocked 方法通知下去需要建立程式的任務
*/
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
複製程式碼
我們直接看上面 註釋 1,2,4 的程式碼,首先獲取需要啟動的 Activity 所在的程式是否存在,如果存在就繼續下發啟動 Activity 的任務,如果不存在執行註釋 4 通知 AMS 需要建立新的程式的任務資訊。最後會在 ZygoteProcess#zygoteSendArgsAndGetResult( ZygoteState zygoteState, ArrayList<String> args)
方法中,以 Socket 方式通知 zygote 程式來建立新的子程式任務,程式碼如下:
//ZygoteProcess.java
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
try {
int sz = args.size();
for (int i = 0; i < sz; i++) {
if (args.get(i).indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx("embedded newlines not allowed");
}
}
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;
writer.write(Integer.toString(args.size()));
writer.newLine();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
//將啟動程式的資訊通知給 zygote 程式
writer.write(arg);
writer.newLine();
}
writer.flush();
...
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}
複製程式碼
zygote 程式收到 AMS 傳送過來的訊息,最後會通過 zygote 的nativeForkAndSpecialize
native 方法來建立新的子程式,建立好了之後會以反射的方式來呼叫應用程式程式的入口 ActivityThread#main
到這裡 AMS 與應用程式程式的關係也講完了,下面我們分析 AMS 中重要的幾個類。
AMS 重要的資料結構
AMS 涉及到了很多資料結構,這一節我們來分析一下 ActivityRecord、TaskRecord 和 ActivityStack, 為什麼要學習它們呢?因為它們和應用開發關聯較大,是 Activity 任務棧模型的基礎。
1. 解析 ActivityRecord
ActivityRecord 在講解 Activity 啟動的時候,我們已經見過它了,它的作用就是記錄 Activity 的所有資訊,是在 Activity 啟動的時候建立,具體是在 ActivityStarter 的 startActivity 方法中被建立的,下面我們看一下它內部結構:
成員名稱 | 型別 | 說明 |
---|---|---|
service | ActivityManagerService | AMS 的引用 |
Info | ActivityInfo | Activity 中程式碼和 AndroidManifes 設定的節點資訊,比如 launchMode |
launchedFromPackage | String | 啟動 Activity 的包名 |
taskAffinity | String | Activity 希望歸屬的棧 |
Task | TaskRecord | ActivityRecord 所在的 TaskRecord |
App | ProcessRecord | ActivityRecord 所在的應用程式程式 |
tate | ActivityState | 當前 Activity 的狀態 |
icon | Int | Activity 的圖示資源識別符號 |
theme | Int | Activity 的主題資源識別符號 |
從上面表格可以看出 ActivityRecord 的作用,其內部儲存了 Activity 的所有資訊,包括 AMS 的引用、AndroidManifes 節點資訊、Activity 狀態、Activity 資源資訊和 Activity 程式相關資訊等,需要注意的是其中包含該 ActivityRecord 所在的 TaskRecord ,這就將 ActivityRecord 和 TaskRecord 關聯在一起,它們是 Activity 任務棧模型的重要成員,我們接著來檢視 TaskRecord.
2. 解析 TaskRecord
TaskRecord 用來描述一個 Activity 任務棧,其內部也有很多的成員變數,這裡挑出一些重要成員變數進行介紹
成員名稱 | 型別 | 說明 |
---|---|---|
taskId | Int | 任務棧的唯一識別符號 |
affinity | String | 任務棧的傾向性 |
intent | Intent | 啟動這個任務棧的 Intent |
mActivities | ArrayList | 按照歷史順序排列的 Activity 記錄 |
mStack | ActivityStack | 當前歸屬的 ActivityStack |
mService | ActivityManagerService | AMS 的引用 |
從上面表格中可以發現 TaskRecord 的作用。其內部儲存了任務棧的所有資訊,包括任務棧的唯一識別符號、任務棧的傾向性、任務棧中的 Activity 記錄和 AMS 的引用等,需要注意的是其中含有 ActivityStack, 也就是當前 Activity 任務棧所歸屬的 ActivityStack, 我們接著來檢視 ActivityStack.
3. 解析 ActivityStack
ActivityStack 是一個管理類,用來管理系統所有 Activity ,其內部維護了 Activity 的所有狀態,特殊狀態的 Activity 以及和 Activity 相關的列表等資料。ActivityStack 是由 ActivityStackSupervisor 來進行管理的,而 ActivityStackSupervisor 在 AMS 的構造方法中被建立,如下所示:
//AMS.java
public ActivityManagerService(Context systemContext) {
...
mStackSupervisor = createStackSupervisor();
...
}
protected ActivityStackSupervisor createStackSupervisor() {
return new ActivityStackSupervisor(this, mHandler.getLooper());
}
複製程式碼
- ActivityStack 的例項型別
在 ActivityStackSupervisor 中有多種 ActivityStack 例項,如下所示:
//ActivityStackSupervisor.java
public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener {
...
/** 用來儲存 Launcher APP 的所有的 Activity */
ActivityStack mHomeStack;
/** 表示當前正在接收輸入或啟動下一個 Activity 的所有 Activity. */
ActivityStack mFocusedStack;
/** 表示此前接收輸入的所有的 Activity */
private ActivityStack mLastFocusedStack;
...
}
複製程式碼
通過上面成員變數,我們知道這裡提供了 3 種 ActivityStack,分別為 mHomeStack、mFocusedStack、mLastFocusedStack。通過 ActivityStackSupervisor 提供了獲取上述 ActivityStack 的方法,程式碼如下:
//ActivityStackSupervisor.java
ActivityStack getFocusedStack() {
return mFocusedStack;
}
ActivityStack getLastStack() {
return mLastFocusedStack;
}
複製程式碼
- ActivityState
在 ActivityStack 中通過列舉儲存了 Activity 的所有的狀態,如下所示:
enum ActivityState {
INITIALIZING,
RESUMED,
PAUSING,
PAUSED,
STOPPING,
STOPPED,
FINISHING,
DESTROYING,
DESTROYED
}
複製程式碼
通過名稱我們可以很輕易知道這些狀態所代表的意義。
- 特殊狀態的 Activity
在 ActivityStack 中定義了一些特殊狀態的 Activity, 如下所示:
/**
* 正在暫停的 Activity
*/
ActivityRecord mPausingActivity = null;
/**
* 上一個已經暫停的 Activity
*/
ActivityRecord mLastPausedActivity = null;
/**
* 最近一次沒有歷史記錄的 Activity
*/
ActivityRecord mLastNoHistoryActivity = null;
/**
* 已經 resume 的 Activity
*/
ActivityRecord mResumedActivity = null;
/**
* 傳遞給 convertToTranslucent 方法的最上層的 Activity
*/
ActivityRecord mTranslucentActivityWaiting = null;
複製程式碼
可以看到這些特殊狀態型別都是 ActivityRecord, ActivityRecord 是用來記錄所有的 Activity 資訊。
-
維護的 ArrayList
在 ActivityStack 中維護了很多 ArrayList ,這些 ArrayList 中的元素型別主要有 ActivityRecord 和 TaskRecord, 如下所示:
ArrayList 元素型別 說明 mTaskHisttory TaskRecord 所有沒有被銷燬的 Activity 任務棧 mLRUActivities ActivityRecord 正在執行的 Activity ,列表中的第一個條目是最近最少使用的 Activity mNoAnimActivities ActivityRecord 不考慮轉換動畫的 Activity mValidateAppTokens TaskGroup 用於與視窗管理器驗證應用令牌 ActivityStack 維護了元素型別為 TaskRecord 的列表,這樣 ActivityStack 和 TaskRecord 就有了關聯, Activity 任務棧儲存在 ActivityStack 中。AMS 重要的資料結構 ActivityRecord、TaskRecord 和 ActivityStack 就講到這裡下面開始分析 Activity 棧。
Activity 棧管理
我們平時做應用開發都知道 Activity 是放入在 Activity 任務棧中的,有了任務棧,系統和開發者就能夠更好地應用和管理 Activity,來完成各種業務邏輯,這一小節我們就來學習 Activity 棧管理相關的知識:
Activity 任務棧模型
下面先以一張圖來看一下 Activity 任務棧模型的重要組成部分
ActivityRecord 用來記錄一個 Activity 的所有資訊,TaskRecord 中包含了一個或多個 ActivityRecord ,TaskRecord 用來表示 Activity 的任務棧,用來管理棧中的 ActivityRecord , ActivityStack 又包含了一個或多個 TaskRecord, 它是 TaskRecord 管理者。Activity 棧管理就是建立在 Activity 任務棧模型之上的,有了棧管理,我們可以對應用程式進行操作,應用可以用自身應用中以及其他應用的 Activity ,節省了資源。
Launch Mode
LaunchMode 相信大家都不陌生,用於設定 Activity 的啟動方式,無論是哪種啟動方式,所啟動的 Activity 都會位於 Activity 的棧頂。下面來介紹 LaunchMode 啟動模式:
- standerd:預設模式,每次啟動 Activity 都會建立一個新的 Activity 例項。
- singleTop: 如果要啟動的 Activity 已經在棧頂,則不會重新建立 Activity, 同時該 Activity 的 onNewIntent 方法會被呼叫。如果要啟動的 Activity 不在棧頂,則會重新建立該 Activity 的例項。
- singleTask: 如果要啟動的 Activity 已經存在棧中,那麼該 Activity 不會重新建立例項,它會將存在棧中的 Activity 出棧,同時該 Activity 的 onNewIntent 方法會被呼叫。如果要啟動的 Activity 不在棧中,則會重新建立該 Activity 例項。如果要啟動的 Activity 不在棧中並且該 棧 也不存在,那麼首先要建立一個新棧,然後建立該 Activity 例項並壓入到新棧中。
- singleInstance: 和 singleTask 基本類似,不同的是啟動 Activity 時,首先要建立一個新棧,然後建立該 Activity 例項並壓入新棧中,新棧中只會存在著一個 Activity 例項。
Intent 的 FLAG
在 Intent 中定義了很多 flag ,其中有幾個可以設定 Activity 的啟動方式,如果 LaunchMode 和 Flag 設定的 Activity 的啟動方式有衝突,則以 Flag 設定的為準。
- FLAG_ACTIVITY_SINGLE_TOP: 和 LaunchMode 中的 singleTop 效果一致。
- FLAG_ACTIVITY_NEW_TASK: 和 LauncheMode 中的 singleTask 效果一致。
- FLAG_ACTIVITY_CLEAR_TOP: 在 LaunchMode 中沒有與此對應的模式,如果要啟動的 Activity 已經存在於棧中,則將所有位於它上面的 Activity 出棧。singleTask 預設具有此標記位的效果。
除了上述這三個 FLAG , 還有一些 FLAG 對我們分析棧管理有些幫組。
- FLAG_ACTIVITY_NO_HISTORY: Activity 一旦退出,就不會存在於棧中。同樣地,也可以在 AndroidManifest.xml 中設定 andorid: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_CREATE_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 與 allowTaskReparenting 配合。如果 allowTaskReparenting 為 true, 說明 Activity 具有轉移的能力。
接下來根據原始碼來檢視 taskAffinity,在 ActivityStackSupervistor 的 findTaskLocked 方法用於找到 Activity 最匹配的棧,最終會呼叫 ActivityStack 的 findTaskLocked 方法:
//ActivityStack.java
void findTaskLocked(ActivityRecord target, FindTaskResult result) {
Intent intent = target.intent;
ActivityInfo info = target.info;
ComponentName cls = intent.getComponent();
...
/**
* 1. 遍歷 TaskRecord 列表,它用於儲存沒有被銷燬的棧
*/
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
/**
* 2. 得到某一個棧的資訊
*/
final TaskRecord task = mTaskHistory.get(taskNdx);
...
/**
* 3. 將棧的 taskAffinity 和目標 Activity 的 taskAffinity 作對比,如果相同,則將 FindTaskResult 的 matchedByRootAffinity 屬性設定為 true 說明找到了匹配的棧
*/
} else if (!isDocument && !taskIsDocument
&& result.r == null && task.rootAffinity != null) {
if (task.rootAffinity.equals(target.taskAffinity)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
result.r = r;
result.matchedByRootAffinity = true;
}
} else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
}
}
複製程式碼
上面程式碼主要先遍歷 TaskRecord 列表(它用於儲存沒有被銷燬的棧),然後列表中的 TaskRecord 的 rootAffinity 挨個與 目標 Activity 的 taskAffinity 做比較,如果相同,則將 FindTaskResult 的 matchedByRootAffinity 屬性設定為 true ,說明找到了匹配的棧。
AMS 到這裡就分析完了,不知道大家有沒有收穫!
總結
本篇文章主要介紹了 AMS 啟動、AMS 資料結構、Activity 棧管理等知識,在瞭解 AMS 之前建議先去把我之前分析的四大元件和 SystemServer 原始碼建議先過一篇,因為它們都會涉及到 AMS 知識,如果都理解了前面的知識,相信看完這篇文章你會有更多的收穫!
感謝你的閱讀,謝謝!
參考
- 《Android 進階解密》