--- title: 'AndroidThread - App 進程' disqus: kyleAlien --- AndroidThread - App 進程 === ## OverView of Content 進程(Process)的概念是,程序的運行實例(簡單理解:一個應用就是一個進程) 線程(Thread)是 CPU 調度的基礎單位 這裡還會涉及到 [**Android Handler**](https://hackmd.io/7fBX6uEtQt6AzCpuBWTHMQ?view) 有在另外一篇文章說過 [TOC] ## 概述 一個應用的入口一般來說都是 main 函數(一切的起源),main 函數主要也做了這些事 1. 初始化 比如 Window 環境下就要創建窗口、像系統申請資源 2. **進入死循環** 若在循環中接收到事件則處理,**一直到這個應用進程退出** 一般來說我們會透過 IDE + SDK 開發程序,這相對的會簡單許多,就像是 Android **若是你不了解其中內容你會以為 4 大零組件(Activity、Server、ContentProvider、Broadcast)就是進程** ### AndroidManifest * 從 AndroidManifest.xml 中就可以看到啟動 Activity 的足跡 ```xml= <!-- 四大零組件只是組成 Application 的一部分 --> <application android:name=".application.BwingApplication" android:allowBackup="false" android:icon="@mipmap/ic_launcher" android:label="@string/app_name"> <activity android:name=".ui.activity.boot.BootActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> ``` * **若非特別聲明,所有個組件都運行在當前進程** > Server 就滿常運行在其他進程 ## 觀察 - 進程&線程 一個應用進程一次只會啟動一個線程 ? 主要進程由哪個進程啟動 * 切換到 debug 模式,並且開啟 [**線程監聽欄位**](https://developer.android.com/studio/debug#startdebug) * 使用 `Thread.activeCount()` 也可以看到當前線程的數量 ### 啟動 Acitivty - [ActivityThread](https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:fakeandroid/srcs/android/app/ActivityThread.java) * 啟動入口 Activity,並觀察 Threads 列表 ```java= public class BootActivity extends BaseActivity { private static final String TAG = BootActivity.class.getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { // 斷點設定在 super.onCreate super.onCreate(savedInstanceState); } } ``` > ![](https://i.imgur.com/WnW4kDQ.png) * 從上圖 `Thread stack` 可以發現幾件事情 1. [**ActivityThread**](https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:fakeandroid/srcs/android/app/ActivityThread.java):除了 MainThread 之外還會啟動其他線程;而 **==MainThread 由 ZygoteInit 啟動== (`com.android.internal.os`),經過一系列的調用後才會到 Activity** ```java= // ActivityThread.java public static void main(String[] args) { ... // 主線程才能調用該函數 Looper.prepareMainLooper(); ... ActivityThread thread = new ActivityThread(); thread.attach(false, startSeq); // 主線程對應的 Thread if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } // End of event ActivityThreadMain. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } ``` 2. 另外啟動了 4 個 BinderThread 用於與 Binder 通訊 (留到另外一個章節在說) > ![](https://i.imgur.com/POiHFWZ.png) ### 啟動 Server * 創建一個簡單的 Server,並將它啟動,再來觀察線程的狀態,是否也會有許多線程 ```java= public class TimedTaskService extends Service { @Override public void onCreate() { // 斷點設定在 super.onCreate super.onCreate(); } } ``` > ![reference link](https://i.imgur.com/DHa1Q9j.png) * 從上面可以發現 1. **Server 也是由 ==ZygoteInit 啟動==** (`com.android.internal.os`),啟動流程與 Activity 一致,都是由 **Activity Thread 啟動** > ![](https://i.imgur.com/EKjVFDn.png) 2. **Binder 線程並不是 Activity 獨有,Server 也啟動了 4 個 Binder 線程** > ![](https://i.imgur.com/x8gaAgy.png) ### 啟動兩個 Activity * 啟動 另一個 Activity (LobbyActivity) 並且不結束 BootActivity (也就是將 BootActivity 壓入 Activity 棧中) ```java= // 第一個 Activity public class BootActivity extends BaseActivity { private static final String TAG = BootActivity.class.getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = new Intent(this, LobbyActivity.class); startActivity(intent); } } //---------------------------------------------------------------------- // 第二個 Activity public class LobbyActivity extends BaseActivity { private static final String TAG = LobbyActivity.class.getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { // 斷點設定在 super.onCreate super.onCreate(savedInstanceState); } } ``` > ![](https://i.imgur.com/v1FHWJP.png) * 上圖可以發現幾個現象 1. LobbyActivity 被執行時,**MainThread (ActivityThread) 仍只有一個 (當前應用的 ActivityThread 號碼為 8186)** > ![](https://i.imgur.com/Rv1Xc0N.png) 2. 上一個 BootActivity 暫時退出運行 3. Binder 線程數量相同 > ![](https://i.imgur.com/5pmam03.png) ### 2 個 Activity 相同進程 - 證明 * 證明 BootActivity、LobbyActivity 在同一個進程 ```java= // 第一個 Activity public class BootActivity extends BaseActivity { private static final String TAG = BootActivity.class.getSimpleName(); public static int TEST = 1; // Default = 1 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = new Intent(this, LobbyActivity.class // 在啟動 LobbyActivity 之前修改 TEST 為 2,若是不同進程,則 LobbyActivity 就不能取到改變後 TEST 的數值 TEST = 2; Log.w("TEST_PROCESS" , "BootActivity TEST value: " + TEST); startActivity(intent); } } // 第二個 Activity public class LobbyActivity extends BaseActivity { private static final String TAG = LobbyActivity.class.getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.w("TEST_PROCESS" , "BootActivity TEST value: " + BootActivity.TEST); } } ``` * 以下可以證明,這兩個 Activity 是運行在同一個進程 1. 在啟動 LobbyActivity 之前修改 TEST 為 2; 若是不同進程,則 LobbyActivity 就會只會拿到初始值,也就是 1 > ![](https://i.imgur.com/pi8be89.png) 2. 從 Logcat 可以輸出查看:PID(Process id)、TID (Thread id) 也是相同的 > Locat 格式:29806(pid)-2986(Thread id),[**參考 stackoverflow**](https://stackoverflow.com/questions/41607956/explanation-about-logcat) :::success * 補充 也可以讓不同 APK 包裡面的組件運行在相同的進程當中,這樣不同組件還可以相互分享資源 ::: ## [ActivityThread](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/app/ActivityThread.java) 概述 對於一個應用來說,ActivityThread#main 就是 App 的進入口 :::success * 誰呼叫 ActivityThread#main ? Zygote 服務 fork 出一個新的 App 進程後,就會 **透過反射呼叫到 `ActivityThread #main` 方法**,詳細可以參考 [**Zygote 分析**](https://hackmd.io/Yw1s2x32QoqawvOsW039ZA?view#Zygote-%E9%80%B2%E7%A8%8B) ::: ```java= // ActivityThread.java // final 類 public final class ActivityThread extends ClientTransactionHandler implements ActivityThreadInternal { public static void main(String[] args) { ... Looper.prepareMainLooper(); ... // 創建一個 ActivityThread 對象 ActivityThread thread = new ActivityThread(); // @ 之後分析 attach 方法 thread.attach(false, startSeq); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } ... Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } } ``` ### ActivityThread - 創建 [Looper](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/Looper.java) & Handler * MainLooper 與一般的 prepare 差不多,只差在 **ActivityThread 有對 Main Looper 的管理** 1. **主線程的 Looper 不可以退出,並把它存在靜態變量中** 2. 任何線程都可以透過 getMainLooper() 取得 Main Looper 對象 3. Main Looper 也可以隨時取得當前線程的 Looper ```java= // ActivityThread.java public final class ActivityThread { private static Looper sMainLooper; static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); public static void prepareMainLooper() { // 1. 該 Looper 不允許退出 // @ 追蹤 prepare 方法 prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); // myLooper 可以透過 TheadLocal 獲得 Looper 對象 } } private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { // 如果 Looper 已經創建過,則拋出錯誤 // 一個 thread 對應一個 Looper throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); } // 2. 取得 Main Looper 對象 public static Looper getMainLooper() { synchronized (Looper.class) { return sMainLooper; } } // 3. 隨時取得當前線程的 Looper public static @Nullable Looper myLooper() { return sThreadLocal.get(); } } ``` * ActivityThread 的 Handler 是使用內部類 H class,創建處理消息的對象 ```java= // ActivityThread.java public final class ActivityThread { // 建構 Handler final H mH = new H(); class H extends Handler { @Override public void handleMessage(Message msg) { // 為各種消息做不同處理 switch (msg.what) { ... } } } final Handler getHandler() { return mH; } } ``` * 循環處理消息 [**Looper**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/Looper.java) 的 `loop` 方法,這邊要注意一下 `loop` 是 **靜態方法,所以只能訪問靜態的數據** :::info Looper 主要的工作就是從 MessageQueue 中取得消息,並分發給相關的負責人(Handler),**若消息隊列為空,它就很可能會進入睡眠,並讓出 CPU 資源** ::: ```java= // Looper.java public static void loop() { // 由於是靜態函數,所以必須透過 myLooper 來獲取 Loop 對象 final Looper me = myLooper(); ... // 每個 Looper 內都有一個 MessageQueue 對象 final MessageQueue queue = me.mQueue; ... // 開始無限倫循 for (;;) { Message msg = queue.next(); // 若沒有下一個訊息則會阻塞(wait) if (msg == null) { // 若當前隊列中沒有 msg 則說明該線程準備要退出了 return; // 跳出無限循環迴圈 } ... try { // target 就是 Handler,到了這裡就開始分發訊息 // 在這裡就是將消息發送給 H class msg.target.dispatchMessage(msg); ... } ... msg.recycleUnchecked(); // 消除處理完畢,回收 } } ``` * Binder IPC 事件就會透過 Handler 將消息傳送到 Main Thread 中 > ![](https://i.imgur.com/6WP186P.png) ### [ActivityThread](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/app/ActivityThread.java) - 呼叫 AMS 啟動 Activity 從 ActivtyThread#**attach** 方法開始分析 ```java= // ActivtyThread.java // main 呼叫 attach 方法 private void attach(boolean system, long startSeq) { if (!system) { // 取得 AMS 通訊代理 final IActivityManager mgr = ActivityManager.getService(); try { // 呼叫 AMS#attachApplication 方法 mgr.attachApplication(mAppThread, startSeq); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } ... 省略部份 } else { ... SystemService 進程才會走到這 } ... } ``` * 這裡從 AMS 開始會接觸到許多類,先看類的功能、關係再追蹤程式碼 * 先看看類的簡介 | 類 | 概述 | 說明 | | -------- | -------- | - | | IApplicationThread | 使用者接口 | 作為 App 應用的服務端,讓系統服務回調 | | ActivtyManagerService | 系統服務 | 使用者訪問的入口 | | ActivityTaskManagerInternal | 抽象類 | 定義 ActivityTask 的相關方法 | | LocalService | ActivityTaskManagerService內 部類 | 實際上會調用 ActivityTaskManagerService 服務 | | RootWindowContainer | Window 容器 | | | ActivityTaskManagerService | 系統服務 | Task 管理服務 | | ActivityTaskSupervisor | - | 負責與 `ActivityTaskManagerService` 通訊 | | ClientLifecycleManager | 管理使用者端生命週期 | | | ClientTransaction | AIDL 傳輸類 | 內部存有使用者 `IApplicationThread` 接口 | * AMS 相關類的 UML > ![](https://i.imgur.com/mNlTF3k.png) * ActivtyThread#attach 主要會分為 SystemService 呼叫、一般 App 呼叫(目前是這個情況),一般 App 又會透過 Binder 代理呼叫 [**AMS**](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java)#`attachApplication` 方法 1. AMS#**attachApplication** 方法:我們主要看 `attachApplicationLocked` 方法,這個方法很長主要有兩個重點 * IApplicationThread#**binderApplication** 方法:IApplicationThread 是由最一開始 App 進程傳入,該方法 **主要目的是將 App 的 ==ApplicationThread 與 ActiivtyThreadServer 綁定==** * [**ActivityTaskManagerInternal**](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java)#**attachApplication** 方法:**啟動 App 的 Activity** ```java= // ActivityManagerService.java public ActivityTaskManagerInternal mAtmInternal; @Override public final void attachApplication(IApplicationThread thread, long startSeq) { // 判斷是否有返回的 IApplicationThread if (thread == null) { throw new SecurityException("Invalid application interface"); } synchronized (this) { int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); attachApplicationLocked(thread, callingPid, // 呼叫者 pid callingUid, // 呼叫者 uid startSeq); Binder.restoreCallingIdentity(origId); } } private boolean attachApplicationLocked(@NonNull IApplicationThread thread, int pid, int callingUid, long startSeq) { ProcessRecord app; // 取得該 App 訊息 ... 省略部份 try { ... 省略部份 if (app.getIsolatedEntryPoint() != null) { ... } else if (instr2 != null) { // 與 AMS 綁定 thread.bindApplication(processName, appInfo, providerList, instr2.mClass, profilerInfo, instr2.mArguments, instr2.mWatcher, instr2.mUiAutomationConnection, testMode, /*省略部份參數*/ ); } else { // 與 AMS 綁定 thread.bindApplication(processName, appInfo, providerList, null, profilerInfo, /*省略部份參數*/); } ... 省略部份 } /* 省略 catch */ if (normalMode) { try { // @ 追蹤 attachApplication 方法 didSomething = mAtmInternal.attachApplication(app.getWindowProcessController()); } /* 省略 catch */ } ... 省略部份 return true; } ``` > ![](https://i.imgur.com/xY8eg4O.png) 2. 分析 ActivityTaskManagerService#attachApplication 方法:ActivityTaskManagerInternal 是一個抽象類,它的實做在 [**ActivityTaskManagerService**](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java) :::info 在這裡 ActivityTaskManagerService 的功能就是與 RootWindowContainer 通訊的橋樑 ::: ```java= // ActivityTaskManagerService.java public class ActivityTaskManagerService extends IActivityTaskManager.Stub { RootWindowContainer mRootWindowContainer; final ActivityTaskManagerInternal mInternal; public ActivityTaskManagerService(Context context) { ... mInternal = new LocalService(); } final class LocalService extends ActivityTaskManagerInternal { ... 省略其他方法 @Override public boolean attachApplication(WindowProcessController wpc) throws RemoteException { synchronized (mGlobalLockWithoutBoost) { ... 省略 trace try { // @ 追蹤 attachApplication 方法 return mRootWindowContainer.attachApplication(wpc); } /* 省略 finally */ } } } } ``` 3. [**RootWindowContainer**](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java)#attachApplication:取得裝置上目前所有的螢幕,並遍歷 `DisplayContent` 下所有的 rootTask ```java= // RootWindowContainer.java ActivityTaskSupervisor mTaskSupervisor; boolean attachApplication(WindowProcessController app) throws RemoteException { boolean didSomething = false; for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { mTmpRemoteException = null; mTmpBoolean = false; // Set to true if an activity was started. // 取得要顯示的螢幕 DisplayContent final DisplayContent display = getChildAt(displayNdx); // 遍歷該 DisplayContent 中所有的 RootTasks display.forAllRootTasks(rootTask -> { // 錯誤 if (mTmpRemoteException != null) { return; } // 不可建就忽略 if (rootTask.getVisibility(null /* starting */) == TASK_FRAGMENT_VISIBILITY_INVISIBLE) { return; } // 在這裡會回調 // @ 追蹤 startActivityForAttachedApplicationIfNeeded 方法 final PooledFunction c = PooledLambda.obtainFunction( // 重點 RootWindowContainer::startActivityForAttachedApplicationIfNeeded, this, PooledLambda.__(ActivityRecord.class), app, rootTask.topRunningActivity() ); rootTask.forAllActivities(c); c.recycle(); }); if (mTmpRemoteException != null) { throw mTmpRemoteException; } didSomething |= mTmpBoolean; } if (!didSomething) { ensureActivitiesVisible(null, 0, false /* preserve_windows */); } return didSomething; } private boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r, WindowProcessController app, ActivityRecord top) { ... 省略部份 try { // @ 追蹤 realStartActivityLocked 方法 if (mTaskSupervisor.realStartActivityLocked(r, app, top == r && r.getTask().canBeResumed(r) /*andResume*/, true /*checkConfig*/)) { mTmpBoolean = true; } } /* 省略 catch */ return false; } ``` > ![](https://i.imgur.com/Dxronik.png) 4. ActivityTaskSupervisor#realStartActivityLocked:真正啟動 Activity,已最終結果來說,AMS 系統服務會透過 App 傳入的 `IApplicationThread` 回掉到 App 端 ```java= // ActivityTaskSupervisor.java final ActivityTaskManagerService mService; boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc, boolean andResume, boolean checkConfig) throws RemoteException { // 檢查是否全部都完成 Paused if (!mRootWindowContainer.allPausedActivitiesComplete()) { ... log 訊息 return false; } final Task task = r.getTask(); final Task rootTask = task.getRootTask(); ... try { r.startFreezingScreenLocked(proc, 0); // 啟動較慢的 App 訊息 r.startLaunchTickingLocked(); // 設定 ActivityRecord 的 proc r.setProcess(proc); // Ensure activity is allowed to be resumed after process has set. if (andResume && !r.canResumeByCompat()) { andResume = false; } ... 省略部份 // 如果進程是第一次啟動活動,則將控制器發送到客戶端 // 所以客戶端可以保存從活動中獲取控制器的綁定 事務 服務。 final IActivityClientController activityClientController = proc.hasEverLaunchedActivity() ? null : mService.mActivityClientController; r.launchCount++; r.lastLaunchTime = SystemClock.uptimeMillis(); // 紀錄啟動時間 proc.setLastActivityLaunchTime(r.lastLaunchTime); ...log 訊息 ... 省略部份 try { if (!proc.hasThread()) { throw new RemoteException(); } List<ResultInfo> results = null; List<ReferrerIntent> newIntents = null; if (andResume) { // We don't need to deliver new intents and/or set results if activity is going // to pause immediately after launch. results = r.results; newIntents = r.newIntents; } ...log, event 訊息 if (r.isActivityTypeHome()) { // 如果是 HomeActivity,就替換 Task 的底部 updateHomeProcess(task.getBottomMostActivity().app); } .. 省略部份 // Create activity launch transaction. // 取得覆用的 ClientTransaction final ClientTransaction clientTransaction = ClientTransaction.obtain( proc.getThread(), r.appToken); final boolean isTransitionForward = r.isTransitionForward(); // 之後到 Client 端會使用到這個 call back clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent), System.identityHashCode(r), r.info, /* 省略部分參數*/ ); // Set desired final state. final ActivityLifecycleItem lifecycleItem; if (andResume) { lifecycleItem = ResumeActivityItem.obtain(isTransitionForward); } else { lifecycleItem = PauseActivityItem.obtain(); } clientTransaction.setLifecycleStateRequest(lifecycleItem); // ActivityTaskManagerService == mService // @ 分析 scheduleTransaction 方法 mService.getLifecycleManager().scheduleTransaction(clientTransaction); ... 省略部份 } /* 省略 catch */ } /* 省略 finally */ ... 省略部份 return true; } // ------------------------------------------------------------- // ActivityTaskManagerService.java public class ActivityTaskManagerService extends IActivityTaskManager.Stub { private final ClientLifecycleManager mLifecycleManager; ... ClientLifecycleManager getLifecycleManager() { return mLifecycleManager; } } // ------------------------------------------------------------- // ClientLifecycleManager.java class ClientLifecycleManager { void scheduleTransaction(ClientTransaction transaction) throws RemoteException { final IApplicationThread client = transaction.getClient(); transaction.schedule(); if (!(client instanceof Binder)) { // If client is not an instance of Binder - it's a remote call and at this point it is // safe to recycle the object. All objects used for local calls will be recycled after // the transaction is executed on client in ActivityThread. transaction.recycle(); } } } // ------------------------------------------------------------- // ClientTransaction.java // AIDL 可傳送類 public class ClientTransaction implements Parcelable, ObjectPoolItem { private IApplicationThread mClient; public void schedule() throws RemoteException { // 呼叫到 Client 端 mClient.scheduleTransaction(this); } } ``` > ![](https://i.imgur.com/MaJ5n63.png) ### [ActivityThread](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/app/ActivityThread.java) - scheduleTransaction 處理 AMS 資料 到這一步後,代表 AMS 準備啟動 Activity,它會透過最開始對 AMS 傳入的 `IApplicationThread` 來進行回調,並處理 AMS 傳入的 `ClientTransaction` ```java= // ActivityThread.java public final class ActivityThread extends ClientTransactionHandler implements ActivityThreadInternal { private class ApplicationThread extends IApplicationThread.Stub { @Override public void scheduleTransaction(ClientTransaction transaction) throws RemoteException { // @ 追蹤 scheduleTransaction ActivityThread.this.scheduleTransaction(transaction); } } } ``` ActivityThread 相關類 UML > ![](https://i.imgur.com/bbshAko.png) * ActivityThread 繼承 ClientTransactionHandler 類:該用來處理 Binder AMS IPC 回傳的 `ClientTransaction` 對象,並定義 Handler 發送訊息的接口 ```java= // ClientTransactionHandler.java public abstract class ClientTransactionHandler { void scheduleTransaction(ClientTransaction transaction) { transaction.preExecute(this); // 傳輸 EXECUTE_TRANSACTION sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction); } // 由 ActivityThread 實作 abstract void sendMessage(int what, Object obj); } ``` * 回到 ActivityThread 類,它會實做 ClientTransactionHandler#sendMessage 方法,並 **透過 Handler 將消息帶回到 Main Thread** | Handler's what | obj | | -------- | -------- | | `H.EXECUTE_TRANSACTION` | `ClientTransaction` | ```java= // ActivityThread.java final H mH = new H(); // what => H.EXECUTE_TRANSACTION // obj => ClientTransaction void sendMessage(int what, Object obj) { sendMessage(what, obj, 0, 0, false); } private void sendMessage(int what, Object obj, int arg1) { sendMessage(what, obj, arg1, 0, false); } private void sendMessage(int what, Object obj, int arg1, int arg2) { sendMessage(what, obj, arg1, arg2, false); } private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) { ... debug 訊息 Message msg = Message.obtain(); msg.what = what; msg.obj = obj; msg.arg1 = arg1; msg.arg2 = arg2; // 異步消息 if (async) { msg.setAsynchronous(true); } mH.sendMessage(msg); } ``` * 查看 Handler 如何處理 `EXECUTE_TRANSACTION` 訊息: 1. 透過 TransactionExecutor#execute 處理 `ClientTransaction` 對象 ```java= // ActivityThread.java private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this); class H extends Handler { public static final int EXECUTE_TRANSACTION = 159; public void handleMessage(Message msg) { switch (msg.what) { case EXECUTE_TRANSACTION: final ClientTransaction transaction = (ClientTransaction) msg.obj; // @ 追蹤 execute 方法 mTransactionExecutor.execute(transaction); if (isSystem()) { transaction.recycle(); } break; } } } ``` 2. 判斷 ClientTransaction 訊息:處理 AMS 傳給 App 的 `ClientTransaction` 物件,並呼叫 AMS 傳入的 ClientTransaction 的 callback :::info * 從這裡可以看出 Destory 的 Activity 是否真的移除(或是說移除的時機),是由 AMS 決定 ::: ```java= // TransactionExecutor.java private ClientTransactionHandler mTransactionHandler; public void execute(ClientTransaction transaction) { ... debug 訊息 final IBinder token = transaction.getActivityToken(); if (token != null) { // 取得已安排被 destory 的 activity final Map<IBinder, ClientTransactionItem> activitiesToBeDestroyed = mTransactionHandler.getActivitiesToBeDestroyed(); // 檢查該請求是否是 destory final ClientTransactionItem destroyItem = activitiesToBeDestroyed.get(token); if (destroyItem != null) { if (transaction.getLifecycleStateRequest() == destroyItem) { // 它將執行將銷毀活動的事務 token, // 因此可以刪除對應的待銷毀記錄。 activitiesToBeDestroyed.remove(token); } if (mTransactionHandler.getActivityClient(token) == null) { ... debug 訊息 return; } } } ... log 訊息 // @ 追蹤 executeCallbacks executeCallbacks(transaction); executeLifecycleState(transaction); mPendingActions.clear(); ... debug 訊息 } ``` 3. 執行 ClientTransaction's Callback:執行 ClientTransaction#**execute** 方法 ```java= // TransactionExecutor.java private ClientTransactionHandler mTransactionHandler; public void executeCallbacks(ClientTransaction transaction) { final List<ClientTransactionItem> callbacks = transaction.getCallbacks(); if (callbacks == null || callbacks.isEmpty()) { // No callbacks to execute, return early. return; } ...debug 訊息 final IBinder token = transaction.getActivityToken(); ActivityClientRecord r = mTransactionHandler.getActivityClient(token); ... 省略部份 final int size = callbacks.size(); for (int i = 0; i < size; ++i) { final ClientTransactionItem item = callbacks.get(i); ...省略部份 // 執行 callback item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); ... 省略部份 } } ``` > ![](https://i.imgur.com/Q9CfGXT.png) ### [ActivityThread](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/app/ActivityThread.java) - 回調 ClientTransactionItem ActivityThread 會回調 `ClientTransactionItem`,而 `ClientTransactionItem` 是在 `ActivityTaskSupervisor` 創建(跟 App 不同進程) * 回顧 AMS 設定 Call Back 的時機 ```java= // Create activity launch transaction. 取得覆用的 ClientTransaction final ClientTransaction clientTransaction = ClientTransaction.obtain( proc.getThread(), r.appToken); // 設定 call back 是 LaunchActivityItem ! clientTransaction.addCallback( LaunchActivityItem.obtain(new Intent(r.intent), System.identityHashCode(r), r.info, /* 省略部分參數*/ ); // Set desired final state. final ActivityLifecycleItem lifecycleItem; if (andResume) { lifecycleItem = ResumeActivityItem.obtain(isTransitionForward); } else { lifecycleItem = PauseActivityItem.obtain(); } clientTransaction.setLifecycleStateRequest(lifecycleItem); ``` * 從上面的簡單回顧我們可以知道 app 進程回調的對象是 [**LaunchActivityItem**](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java) 類,調用的方法是 ClientTransactionItem#`execute` ```java= // LaunchActivityItem.java public class LaunchActivityItem extends ClientTransactionItem { @Override public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { // 創建 ActivityClientRecord ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo, /* 省略部份參數 */); // @ 追蹤 handleLaunchActivity 方法 client.handleLaunchActivity(r, pendingActions, null /* customIntent */); } } ``` > ![](https://i.imgur.com/oEG6Gmm.png) ### performLaunchActivity - 執行 onCreate * ActivityThread 繼承於 ClientTransactionHandler,所以 `handleLaunchActivity` 方法也由 ActivityThread 實做,該**方法的重點是 `performLaunchActivity`** ```java= // ActivityThread.java public final class ActivityThread extends ClientTransactionHandler implements ActivityThreadInternal { @Override public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) { ... 省略部份 // @ 追蹤 performLaunchActivity 方法 final Activity a = performLaunchActivity(r, customIntent); ... 省略部份 return a; } } ``` * ActivityThread#performLaunchActivity 方法會分為幾個階段,最終會呼叫到 Activity#onCreate 方法 1. 取得 ActivityInfo、ComponentName、PackageInfo ```java= // ActivityThread.java private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ActivityInfo aInfo = r.activityInfo; if (r.packageInfo == null) { r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE); } ComponentName component = r.intent.getComponent(); if (component == null) { component = r.intent.resolveActivity( mInitialApplication.getPackageManager()); r.intent.setComponent(component); } if (r.activityInfo.targetActivity != null) { component = new ComponentName(r.activityInfo.packageName, r.activityInfo.targetActivity); } } ``` 2. 創建 Activity 還有其對應的 ContextImpl 對象 ```java= // ActivityThread.java private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ActivityInfo aInfo = r.activityInfo; ... ContextImpl appContext = createBaseContextForActivity(r); Activity activity = null; try { java.lang.ClassLoader cl = appContext.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); ... 省略部份 } /* 省略 catch */ ... } ``` 3. 從 LoadedApk 取得 Application 對象、呼叫 Activity#attach 方法,透過 Instrumentation#callActivityOnCreate 呼叫到 Activity#onCreate 方法 ```java= // ActivityThread.java Instrumentation mInstrumentation; private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ActivityInfo aInfo = r.activityInfo; ... try { Application app = r.packageInfo.makeApplication(false, mInstrumentation); ... 省略部份 if (activity != null) { ... 省略部份 // Context 把 Activity 包裝起來 appContext.setOuterContext(activity); // 呼叫 Activity#attach 方法 activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, /* 省略部份參數 */); ... 省略部份 if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } ... } r.setState(ON_CREATE); } /* 省略 catch */ return activity; } ``` * 最後我們來看 Instrumentation#callActivityOnCreate 是如何呼叫到 Activity#onCreate 方法 ```java= // Instrumentation.java public void callActivityOnCreate(Activity activity, Bundle icicle) { prePerformCreate(activity); // @ 追蹤 performCreate 方法 activity.performCreate(icicle); postPerformCreate(activity); } // ------------------------------------------------------------ // Activity.java final void performCreate(Bundle icicle) { performCreate(icicle, null); } final void performCreate(Bundle icicle, PersistableBundle persistentState) { ... 省略部份 if (persistentState != null) { onCreate(icicle, persistentState); } else { // @ 追蹤 onCreate onCreate(icicle); } ... 省略部份 } @MainThread @CallSuper protected void onCreate(@Nullable Bundle savedInstanceState) { ... 到這一步就進入我們最常見的 onCreate } ``` 加上 Activity、Instrumentation 類,再次整理 UML > ![](https://i.imgur.com/QXI21ML.png) ## Appendix & FAQ :::info ::: ###### tags: `Android Framework` `Java 多線程`