Activity啟動流程分析

我們來看一下 startActivity 過程的具體流程。在手機桌面應用中點擊某一個 icon 之後,實際上最終就是通過 startActivity 去打開某一個 Activity 頁面。我們知道 Android 中的一個 App 就相當於一個進程,所以 startActivity 操作中還需要判斷,目標 Activity 的進程是否已經創建,如果沒有,則在顯示 Activity 之前還需要將進程 Process 提前創建出來。假設是從 ActivityA 跳轉到另一個 App 中的 ActivityB,過程如下圖所示:

 

 

 

整個 startActivity 的流程分為 3 大部分,也涉及 3 個進程之間的交互:

  • ActivityA –> ActivityManagerService(簡稱 AMS)
  • ActivityManagerService –> ApplicationThread
  • ApplicationThread –> Activity

ActivityA –> ActivityManagerService 階段

這一過程並不複雜,用一張圖表示具體過程如下:

 

接下來看下源碼中做了哪些操作。

Activity 的 startActivity方法

@Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

最終調用了 startActivityForResult 方法,傳入的 -1 表示不需要獲取 startActivity 的結果。

 

Activity 的 startActivityForResult

具體代碼如下所示:

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

startActivityForResult 也很簡單,調用 Instrumentation.execStartActivity 方法。剩下的交給 Instrumentation 類去處理。

解釋說明:

  • Instrumentation 類主要用來監控應用程序與系統交互。
  • 代碼中的mMainThread 是 ActivityThread 類型,ActivityThread 可以理解為一個進程,在這就是 A 所在的進程。
  • 通過 mMainThread 獲取一個 ApplicationThread 的引用,這個引用就是用來實現進程間通信的,具體來說就是 AMS 所在系統進程通知應用程序進程進行的一系列操作。

Instrumentation 的 execStartActivity

方法如下:

try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            int result = ActivityTaskManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;

通過ActivityTaskManager.getService()獲取獲取ATMS的服務代理,跨進程調用ATMS的startActivity方法,下一步就ATMS內部startActivityAsUser()方法處理。

 

int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
            boolean validateIncomingUser) {
        enforceNotIsolatedCaller("startActivityAsUser");

        userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
                Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

        // TODO: Switch to user app stacks here.
        return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setMayWait(userId)
                .execute();

    }

經過多個方法的調用,最終通過 obtainStarter 方法獲取了 ActivityStarter 類型的對象,然後調用其 execute 方法。在 execute 方法中,會再次調用其內部的 startActivityMayWait 方法。

ActivityStarter 的 startActivityMayWait

ActivityStarter 這個類看名字就知道它專門負責一個 Activity 的啟動操作。它的主要作用包括解析 Intent、創建 ActivityRecord、如果有可能還要創建 TaskRecord。startActivityMayWait 方法的部分實現如下:

private int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, int requestRealCallingPid, int requestRealCallingUid,
            Intent intent, String resolvedType, IVoiceInteractionSession voiceSession,
            IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, WaitResult outResult,
            Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
            int userId, TaskRecord inTask, String reason,
            boolean allowPendingRemoteAnimationRegistryLookup,
            PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
        // Refuse possible leaked file descriptors
        if (intent != null && intent.hasFileDescriptors()) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }
        ...
ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
0 /* matchFlags */,
computeResolveFilterUid(
callingUid, realCallingUid, mRequest.filterCallingUid));
if (rInfo == null) {
UserInfo userInfo = mSupervisor.getUserInfo(userId);
if (userInfo != null && userInfo.isManagedProfile()) {
// Special case for managed profiles, if attempting to launch non-cryto aware
// app in a locked managed profile from an unlocked parent allow it to resolve
// as user will be sent via confirm credentials to unlock the profile.
UserManager userManager = UserManager.get(mService.mContext);
boolean profileLockedAndParentUnlockingOrUnlocked = false;
long token = Binder.clearCallingIdentity();
try {
UserInfo parent = userManager.getProfileParent(userId);
profileLockedAndParentUnlockingOrUnlocked = (parent != null)
&& userManager.isUserUnlockingOrUnlocked(parent.id)
&& !userManager.isUserUnlockingOrUnlocked(userId);
} finally {
Binder.restoreCallingIdentity(token);
}
if (profileLockedAndParentUnlockingOrUnlocked) {
rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
computeResolveFilterUid(
callingUid, realCallingUid, mRequest.filterCallingUid));
}
}
}
// Collect information about the target of the Intent.
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
...
 

從上圖可以看出獲取目標 Activity 信息的操作由 mSupervisor 來實現,它是 ActivityStackSupervisor 類型,從名字也能猜出它主要是負責 Activity 所處棧的管理類。

resolveIntent 中實際上是調用系統 PackageManagerService 來獲取最佳 Activity。有時候我們通過隱式 Intent 啟動 Activity 時,系統中可能存在多個 Activity 可以處理 Intent,此時會彈出一個選擇框讓用戶選擇具體需要打開哪一個 Activity 界面,就是此處的邏輯處理結果。

在 startActivityMayWait 方法中調用了一個重載的 startActivity 方法,而最終會調用的 ActivityStarter 中的 startActivityUnchecked 方法來獲取啟動 Activity 的結果。

ActivityStarter 的 startActivityUnchecked

解釋說明:

  • 圖中 1 處計算啟動 Activity 的 Flag 值。
  • 注釋 2 處處理 Task 和 Activity 的進棧操作。
  • 注釋 3 處啟動棧中頂部的 Activity。

computeLaunchingTaskFlags 方法具體如下:

 

 

 這個方法的主要作用是計算啟動 Activity 的 Flag,不同的 Flag 決定了啟動 Activity 最終會被放置到哪一個 Task 集合中。

  • 圖中 1 處 mInTask 是 TaskRecord 類型,此處為 null,代表 Activity 要加入的棧不存在,因此需要判斷是否需要新建 Task。
  • 圖中 2 處的 mSourceRecord 的類型 ActivityRecord 類型,它是用來描述「初始 Activity」,什麼是「初始 Activity」呢?比如 ActivityA 啟動了ActivityB,ActivityA 就是初始 Activity。當我們使用 Context 或者 Application 啟動 Activity 時,此 SourceRecord 為 null。
  • 圖中 3 處表示初始 Activity 如果是在 SingleInstance 棧中的 Activity,這種需要添加 NEW_TASK 的標識。因為 SingleInstance 棧只能允許保存一個 Activity。
  • 圖中 4 處表示如果 Launch Mode 設置了 singleTask 或 singleInstance,則也要創建一個新棧。

 

ActivityStackSupervisor 的 startActivityLocked

 

 

 方法中會調用 insertTaskAtTop 方法嘗試將 Task 和 Activity 入棧。如果 Activity 是以 newTask 的模式啟動或者 TASK 堆棧中不存在該 Task id,則 Task 會重新入棧,並且放在棧的頂部。需要注意的是:Task 先入棧,之後才是 Activity 入棧,它們是包含關係。

這裡一下子湧出了好幾個概念 Stack、Task、Activity,其實它們都是在 AMS 內部維護的數據結構,可以用一張圖來描述它們之間的關係。

 

ActivityStack 的 resumeFocusedStackTopActivityLocked

 

 

 

經過一系列調用,最終代碼又回到了 ActivityStackSupervisor 中的 startSpecificActivityLocked 方法。

ActivityStackSupervisor 的 startSpecificActivityLocked

 

 

解釋說明:

  • 圖中 1 處根據進程名稱和 Application 的 uid 來判斷目標進程是否已經創建,如果沒有則代表進程未創建。
  • 圖中 2 處調用 AMS 創建 Activity 所在進程。

不管是目標進程已經存在還是新建目標進程,最終都會調用圖中紅線標記的 realStartActivityLocked 方法來執行啟動 Activity 的操作。

 ActivityStackSupervisor 的 realStartActivityLocked

 

 

這個方法在 android-27 和 android-28 版本的區別很大,從 android-28 開始 Activity 的啟動交給了事務(Transaction)來完成。

  • 圖中 1 處創建 Activity 啟動事務,並傳入 app.thread 參數,它是 ApplicationThread 類型。在上文 startActivity 階段已經提過 ApplicationThread 是為了實現進程間通信的,是 ActivityThread 的一個內部類。
  • 圖中 2 處執行 Activity 啟動事務。

Activity 啟動事務的執行是由 ClientLifecycleManager 來完成的,具體代碼如下:

 

 

 可以看出實際上是調用了啟動事務 ClientTransaction 的 schedule 方法,而這個 transaction 實際上是在創建 ClientTransaction 時傳入的 app.thread 對象,也就是 ApplicationThread。如下所示:

 

 解釋說明:

  • 這裡傳入的 app.thread 會賦值給 ClientTransaction 的成員變量 mClient,ClientTransaction 會調用 mClient.scheduleTransaction(this) 來執行事務。
  • 這個 app.thread 是 ActivityThread 的內部類 ApplicationThread,所以事務最終是調用 app.thread 的 scheduleTransaction 執行。

到這為止 startActivity 操作就成功地從 AMS 轉移到了另一個進程 B 中的 **ApplicationThread **中,剩下的就是 AMS 通過進程間通信機制通知 ApplicationThread 執行 ActivityB 的生命周期方法。

 

ApplicationThread -> Activity

剛才我們已近分析了 AMS 將啟動 Activity 的任務作為一個事務 ClientTransaction 去完成,在 ClientLifecycleManager 中會調用 ClientTransaction的schedule() 方法,如下:

public void schedule() throws RemoteException {
        mClient.scheduleTransaction(this);
    }

而 mClient 是一個 IApplicationThread 接口類型,具體實現是 ActivityThread 的內部類 ApplicationThread。因此後續執行 Activity 生命周期的過程都是由 ApplicationThread 指導完成的,scheduleTransaction 方法如下:

 

 可以看出,這裡還是調用了ActivityThread 的 scheduleTransaction 方法。但是這個方法實際上是在 ActivityThread 的父類 ClientTransactionHandler 中實現,具體如下:

 

 調用 sendMessage 方法,向 Handler 中發送了一個 EXECUTE_TRANSACTION 的消息,並且 Message 中的 obj 就是啟動 Activity 的事務對象。而這個 Handler 的具體實現是 ActivityThread 中的 mH 對象。具體如下:

最終調用了事務的 execute 方法,execute 方法如下:

 

 

 在 executeCallback 方法中,會遍歷事務中的 callback 並執行 execute 方法,這些 callbacks 是何時被添加的呢?

還記得 ClientTransaction 是如何創建被創建的嗎?重新再看一遍:

 

 

 在創建 ClientTransaction 時,通過 addCallback 方法傳入了 Callback 參數,從圖中可以看出其實是一個 LauncherActivityItem 類型的對象。

LaunchActivityItem 的 execute()

 

終於到了跟 Activity 生命周期相關的方法了,圖中 client 是 ClientTransationHandler 類型,實際實現類就是 ActivityThread。因此最終方法又回到了 ActivityThread。

ActivityThread 的 handleLaunchActivity

這是一個比較重要的方法,Activity 的生命周期方法就是在這個方法中有序執行,具體如下:

 

解釋說明:

  • 圖中 1 處初始化 Activity 的 WindowManager,每一個 Activity 都會對應一個「窗口」。
  • 圖中 2 處調用 performLaunchActivity 創建並顯示 Activity。
  • 圖中 3 處通過反射創建目標 Activity 對象。
  • 圖中 4 處調用 attach 方法建立 Activity 與 Context 之間的聯繫,創建 PhoneWindow 對象,並與 Activity 進行關聯操作。
  • 圖中 5 處通過 Instrumentation 最終調用 Activity 的 onCreate 方法。

至此,目標 Activity 已經被成功創建並執行生命周期方法。

 

總結

詳細查看了 Activity 的啟動在源碼中的實現流程(不同版本sdk源碼還是挺大變化的,自己可以去查看)。這一過程主要涉及 3 個進程間的通信過程:

1》首先進程 A 通過 Binder 調用 AMS 的 startActivity 方法。
2》然後 AMS 通過一系列的計算構造目標 Intent,然後在 ActivityStack 與 ActivityStackSupervisor 中處理 Task 和 Activity 的入棧操作。
3》最後 AMS 通過 Binder 機制,調用目標進程中 ApplicationThread 的方法來創建並執行 Activity 生命周期方法,實際上 ApplicationThread 是 ActivityThread 的一個內部類,它的執行最終都調用到了 ActivityThread 中的相應方法。

————來自拉勾教育筆記