Android10 客戶端事務管理ClientLifecycleManager源碼解析

正文

在Android 10 App啟動分析之Activity啟動篇(二)一文中,簡單地介紹瞭Activity的生命周期管理器是如何調度Activity進入onCreate生命周期的流程。這篇文章,我們將詳細地分析framework中activity的生命周期管理功能,從更宏觀的角度來更全面地瞭解生命周期及相關事務的工作原理。

生命周期管理是google在Android 9才引入的設計,在Android 9之前,activity 存在生命周期的概念,但並無生命周期管理這一說法。為瞭方便生命周期的切換以及相關業務的管理,google采用瞭事務的思想,將生命周期抽象為客戶端事務的一部分來統一管理。下圖是客戶端事務管理完整的UML圖:

相關類說明:

  • ClientLifecycleManager: 客戶端事務管理類,包括且不限於處理Activity生命周期轉換事務,同時也包括 與客戶端相關的其他事務處理。
  • ClientTransaction:事務集類,一個事務集可以存放一系列Callback事務及一個生命周期事務。
  • TransactionExecutor:事務執行器,讓事務以正確的順序執行。
  • BaseClientRequest :事務的抽象類,定義瞭preExecuteexecutepostExecute三個接口,分別代表事務執行前、執行中、執行後三個階段的回調方法。
  • ActivityLifecycleItem:abstract class,Activity生命周期事務類,其子類有DestroyActivityItemPauseActivityItemStopActivityItemResumeActivityItem,表示具體的activity生命周期轉換事務。
  • ClientTransactionItem:abstract class,客戶端事務類,ActivityLifecycleItem是它的子類之一。除此之外,還有如下內置的客戶端事務:
Transaction Name Desc
ConfigurationChangeItem App configuration 改變的消息
WindowVisibilityItem Window可見性發生改變的消息
MoveToDisplayItem Activity 移動到不同的顯示設備的消息
MultiWindowModeChangeItem 多窗口模式改變的消息
ActivityConfigurationChangeItem Activity configuration 改變的回調
PipModeChangeItem 畫中畫模式改變的消息
ActivityResultItem Activity result的回調
NewIntentItem New intent消息
TopResumedActivityChangeItem Top resumed activity 改變的回調
ActivityRelaunchItem 重啟Activity的回調
LaunchActivityItem 請求啟動一個Activity

ClientLifecycleManager

ClientLifecycleManagerActivityTaskManagerService中初始化瞭唯一的實例,所有的事務操作,必須通過ATMS中的實例來發起。如: mService.getLifecycleManager().scheduleTransaction(clientTransaction);

ClientLifecycleManager的源碼如下:

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();
        }
    }
    void scheduleTransaction(@NonNull IApplicationThread client, @NonNull IBinder activityToken,
            @NonNull ActivityLifecycleItem stateRequest) throws RemoteException {
        final ClientTransaction clientTransaction = transactionWithState(client, activityToken,
                stateRequest);
        scheduleTransaction(clientTransaction);
    }
    void scheduleTransaction(@NonNull IApplicationThread client, @NonNull IBinder activityToken,
            @NonNull ClientTransactionItem callback) throws RemoteException {
        final ClientTransaction clientTransaction = transactionWithCallback(client, activityToken,
                callback);
        scheduleTransaction(clientTransaction);
    }
    void scheduleTransaction(@NonNull IApplicationThread client,
            @NonNull ClientTransactionItem callback) throws RemoteException {
        final ClientTransaction clientTransaction = transactionWithCallback(client,
                null /* activityToken */, callback);
        scheduleTransaction(clientTransaction);
    }
    private static ClientTransaction transactionWithState(@NonNull IApplicationThread client,
            @NonNull IBinder activityToken, @NonNull ActivityLifecycleItem stateRequest) {
        final ClientTransaction clientTransaction = ClientTransaction.obtain(client, activityToken);
        clientTransaction.setLifecycleStateRequest(stateRequest);
        return clientTransaction;
    }
    private static ClientTransaction transactionWithCallback(@NonNull IApplicationThread client,
            IBinder activityToken, @NonNull ClientTransactionItem callback) {
        final ClientTransaction clientTransaction = ClientTransaction.obtain(client, activityToken);
        clientTransaction.addCallback(callback);
        return clientTransaction;
    }
}

可以看到,ClientLifecycleManager對外暴露瞭三種事務調度方法:一是 直接調度一個事務集(ClientTransaction);二是調度一個 Lifecycle事務; 三是調用一個Callback事務(ps:除LifeCycle以外的事務,都屬於Callback事務)。實際上,無論是Lifecycle事務還是Callback事務,它們都被封裝成瞭事務集的形式,並通過ClientTransaction中的schedule方法去進一步處理。

ClientTransaction

ClientTransaction裡的schedule方法非常簡單,代碼如下所示:

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

上述代碼片段中的mClient到底指的是什麼?

從源碼的角度來看,mClient 是 ApplicationThread的一個實例。而 ApplicationThread 是ActivityThread的一個內部類,作為ActivityThread 與外部溝通的橋梁。所有的事務集最終都會被派發到ActivityThread中統一處理。

ActivityThread.java
   void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
    }

ActivityThread裡首先調用瞭ClientTransaction中的preExecute方法,代碼片段如下:

    public void preExecute(android.app.ClientTransactionHandler clientTransactionHandler) {
        if (mActivityCallbacks != null) {
            final int size = mActivityCallbacks.size();
            for (int i = 0; i < size; ++i) {
                mActivityCallbacks.get(i).preExecute(clientTransactionHandler, mActivityToken);
            }
        }
        if (mLifecycleStateRequest != null) {
            mLifecycleStateRequest.preExecute(clientTransactionHandler, mActivityToken);
        }
    }

可以看到,ClientTransaction先調用瞭 所有註冊的Callback事務的preExecute方法,然後調用瞭唯一的LifeCycle事務的preExecute方法。

在完成所有事務的preExecute邏輯後,ActivityThread發送瞭一條ActivityThread.H.EXECUTE_TRANSACTION的message,內容如下:

   mTransactionExecutor.execute(transaction);
   if (isSystem()) {
      transaction.recycle();
   }

接下來由TransactionExecutor負責後續的邏輯處理。

TransactionExecutor

 public void execute(ClientTransaction transaction) {
        final IBinder token = transaction.getActivityToken();
        if (token != null) {
            final Map<IBinder, ClientTransactionItem> activitiesToBeDestroyed =
                    mTransactionHandler.getActivitiesToBeDestroyed();
            final ClientTransactionItem destroyItem = activitiesToBeDestroyed.get(token);
            if (destroyItem != null) {
                if (transaction.getLifecycleStateRequest() == destroyItem) {
                    // It is going to execute the transaction that will destroy activity with the
                    // token, so the corresponding to-be-destroyed record can be removed.
                    activitiesToBeDestroyed.remove(token);
                }
                if (mTransactionHandler.getActivityClient(token) == null) {
                    // The activity has not been created but has been requested to destroy, so all
                    // transactions for the token are just like being cancelled.
                    Slog.w(TAG, tId(transaction) + "Skip pre-destroyed transaction:\n"
                            + transactionToString(transaction, mTransactionHandler));
                    return;
                }
            }
        }
        executeCallbacks(transaction);
        executeLifecycleState(transaction);
        mPendingActions.clear();
    }

execute中有一段對DestroyActivityItem特殊處理的邏輯,不太重要,我們忽略它。

我們分別來看一下executeCallbacksexecuteLifecycleState兩個方法。

 public void executeCallbacks(ClientTransaction transaction) {
        final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
        if (callbacks == null || callbacks.isEmpty()) {
            return;
        }
        final IBinder token = transaction.getActivityToken();
        ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
        // In case when post-execution state of the last callback matches the final state requested
        // for the activity in this transaction, we won't do the last transition here and do it when
        // moving to final state instead (because it may contain additional parameters from server).
        final ActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest();
        final int finalState = finalStateRequest != null ? finalStateRequest.getTargetState()
                : UNDEFINED;
        // Index of the last callback that requests some post-execution state.
        final int lastCallbackRequestingState = lastCallbackRequestingState(transaction);
        final int size = callbacks.size();
        for (int i = 0; i < size; ++i) {
            final ClientTransactionItem item = callbacks.get(i);
            if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item);
            final int postExecutionState = item.getPostExecutionState();
            final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
                    item.getPostExecutionState());
            if (closestPreExecutionState != UNDEFINED) {
                cycleToPath(r, closestPreExecutionState, transaction);
            }
            item.execute(mTransactionHandler, token, mPendingActions);
            item.postExecute(mTransactionHandler, token, mPendingActions);
            if (r == null) {
                // Launch activity request will create an activity record.
                r = mTransactionHandler.getActivityClient(token);
            }
            if (postExecutionState != UNDEFINED && r != null) {
                // Skip the very last transition and perform it by explicit state request instead.
                final boolean shouldExcludeLastTransition =
                        i == lastCallbackRequestingState && finalState == postExecutionState;
                cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction);
            }
        }
    }

上述代碼主要做瞭以下幾件事:

  • 獲取事務集的target lifecycle。
  • 獲取事務集中最後一次Activity生命周期轉換的Callback索引。
  • 遍歷所有的Callback事務。
  • 獲取Callback事務的結束狀態值,如結束狀態值為onResume,檢查Activity當前狀態,判斷當前的就近狀態(onStart/onPause),並將activity轉換到就近狀態。
  • 執行Callback事務的execute和postExecute邏輯。
  • 跳過最後一個狀態轉換,改為通過顯式狀態變換去執行。

google這段邏輯寫的極為繁雜囉嗦,讓人吐槽的點實在太多瞭,但還是要在此講一下它是怎麼設計的,源碼中又哪裡糟點。

首先是事務集的target lifecycle,它指的是事務集中唯一的Lifecycle事務(如果存在的話)的狀態,表示事務集執行完畢後,Activity最終的生命周期狀態。

第二點,事務集中最後一次Activity生命周期轉換的Callback索引,這句話是什麼含義呢?

Callback事務中有這麼一個方法,getPostExecutionState,它表示在當前Callback事務執行完畢後Activity所需處於的生命周期狀態,為方便敘述,下文稱其為結束狀態。將Callback事務列表從後向前遍歷,如果當前事務存在結束狀態(即getPostExecutionState的值不為UNDEFINED),且與上一個結束狀態相同,記錄下此時事務在列表中的索引值,直到當前結束狀態與上一個狀態不同為止。此時,上一個事務的索引值即為事務集中最後一次Activity生命周期轉換的Callback索引

假如某事務集有這樣一組Callback事務——ConfigurationChangeItem、NewIntentItem、ConfigurationChangeItem、NewIntentItem。其中ConfigurationChangeItem的結束狀態為UNDEFINED,NewIntentItem的結束狀態為ON_RESUME。

我們從後向前開始遍歷:

  • 最後一個事務為 NewIntentItem,結束狀態為ON_RESUME,記錄下此時的索引值 3。
  • 倒數第二個事務為 ConfigurationChangeItem,不存在結束狀態,跳過。
  • 倒數第三個事務為 NewIntentItem,結束狀態為ON_RESUME,上一個結束狀態同樣也是 ON_RESUME,更新索引值 為 1。
  • 倒數第四個事務為 ConfigurationChangeItem,不存在結束狀態,跳過。

因此,此事務集中最後一次Activity生命周期轉換的Callback索引 為1。至於這個索引值有什麼意義呢,待會再解釋。

然而,這段設計中還是有幾點需要吐槽一下:

  • google官方在註釋中舉例的 事務是 Configuration – ActivityResult – Configuration – ActivityResult , 並且說明ActivityResult 的結束狀態為RESUMED。讓我們看看ActivityResultItem的源碼:
public class ActivityResultItem extends ClientTransactionItem {
    @UnsupportedAppUsage
    private List<ResultInfo> mResultInfoList;
    /* TODO(b/78294732)
    @Override
    public int getPostExecutionState() {
        return ON_RESUME;
    }*/
}

Excuse me? TODO state!! 實際上,這個TODO 一直拖到android 13 才被加上,en~~~~。

  • 設計歸設計,到android13 為止,framework裡從來沒有過一個事務集裡綁定多個Callback事務的用法,所以 這段邏輯設計的並沒有什麼用。

第四點,如果Callback事務的結束狀態為ON_RESUME,則判斷當前Activity狀態是更靠近ON_START狀態還是ON_PAUSE狀態,並將activity狀態轉換到就近狀態(ON_START or ON_PAUSE)。

這裡判斷當前Activity狀態更靠近ON_START還是ON_PAUSE,采用的是路徑長度比較法。framework中為Activity定義瞭九種狀態,具體如下:

    public static final int UNDEFINED = -1;
    public static final int PRE_ON_CREATE = 0;
    public static final int ON_CREATE = 1;
    public static final int ON_START = 2;
    public static final int ON_RESUME = 3;
    public static final int ON_PAUSE = 4;
    public static final int ON_STOP = 5;
    public static final int ON_DESTROY = 6;

狀態之間的轉換路徑如下表所示:

上表中置灰的單元格,表示不存在或禁止的狀態轉換,而單元格中A ~ B 這種寫法 表示 從 A到 B狀態之間的中間所有狀態,如: start 狀態為 PRE_CREATE , finish 狀態為 DESTROY ,在上表中狀態轉換路徑為 create ~ destroy,表示 activity從 PRE_CREATE 狀態轉換到 DESTROY 狀態,需要經歷 create、start 、 resume 、pause 、stop 、 detroy ,即create到destroy之間所有的生命周期變換的過程。同時,我們也稱 create~destroy 是 PRE_CREATE到DESTROY狀態路徑,它的路徑長度為6。

如何判斷當前生命周期是更靠近ON_START還是ON_PAUSE?我們舉個例子來看一下,假如當前的生命周期為ON_STOP,由上述狀態路徑表可知,從ON_STOP狀態轉換到ON_START狀態的路徑為restart、start,長度為2;而由ON_STOP狀態轉換到ON_PAUSE狀態的路徑為restart、start~pause,長度為4。因此,當前activity的狀態更靠近ON_START。

在路徑長度算法的代碼裡,google給凡是路徑中含有destroy狀態的長度,賦予瞭一段懲罰長度,讓它的長度增加瞭10,具體代碼如下:

  public int getClosestOfStates(ActivityClientRecord r, int[] finalStates) {
        if (finalStates == null || finalStates.length == 0) {
            return UNDEFINED;
        }
        final int currentState = r.getLifecycleState();
        int closestState = UNDEFINED;
        for (int i = 0, shortestPath = Integer.MAX_VALUE, pathLength; i < finalStates.length; i++) {
            getLifecyclePath(currentState, finalStates[i], false /* excludeLastState */);
            pathLength = mLifecycleSequence.size();
            if (pathInvolvesDestruction(mLifecycleSequence)) {
		//路徑中含有destroy狀態,增加懲罰長度
                pathLength += DESTRUCTION_PENALTY;
            }
            if (shortestPath > pathLength) {
                shortestPath = pathLength;
                closestState = finalStates[i];
            }
        }
        return closestState;
    }

然而我們可以看一下表格中finish state為 START 和 PAUSE的兩列,所有的路徑中都不包含 destroy 狀態,所以這個懲罰長度的意義何在?

第五步開始,正式執行 事務的execute和postExecute邏輯。這裡要談一下,為什麼執行結束狀態為 ON_RESUME的事務時,先要在第四步將 狀態切換到 ON_START 或 ON_RESUME後,然後才開始去執行事務的邏輯呢?

在Android 10中,結束狀態為 ON_RESUME 的事務隻有 NewIntentItem,其 excute 方法代碼片段如下:

NewIntentItem.java
    public void execute(ClientTransactionHandler client, ActivityClientRecord r,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent");
        client.handleNewIntent(r, mIntents);
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }

它最終會調用到 activity的performNewIntent方法。

可以看到在這個過程中並沒有涉及到生命周期狀態的轉換。因此,google這段邏輯的意圖是:在執行最終狀態為ON_RESUME的事務時,先將activity生命周期狀態轉換到ON_RESUME的臨近狀態,即ON_START或ON_PAUSE狀態,然後再去執行事務,最後在事務執行完畢後,將activity的狀態真正地切換到ON_RESUME。

第六步,跳過最後一個狀態轉換,改為通過顯式狀態變換去執行。

這裡做瞭一個判斷,如果事務組最後一次最終狀態與事務集的生命周期狀態相同,跳過此事務的最終狀態的轉換,改由 LifeCycle事務去執行狀態轉換。

然而,我們來看這樣一組事務,ConfigurationChangeItem、NewIntentItem、ConfigurationChangeItem、NewIntentItem,雖然實際編碼中並不會寫出這樣一組事務,但仍可以用來吐槽一下google的這段代碼邏輯:

由第二步可知,上述的的事務組最後一次activity狀態轉換的Callback索引為 1。

final boolean shouldExcludeLastTransition =
                        i == lastCallbackRequestingState && finalState == postExecutionState;
cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction);

可以看到,在第二個事務,activity並不會切換到ON_RESUME狀態。

然而這段代碼最大的問題是,這個判斷並不能達成顯式狀態變換的目標,因為在第四個事務時 activity會被切換到ON_REUSME的目標狀態。

有讀者可能會提出異議瞭,作者你舉的這個例子是屬於特例,代碼中不可能這麼寫。 然而,如果不需要考慮這種特殊情況的話,第二步的索引值計算又有什麼作用呢?

executeLifecycleState

這個方法是對事務集中的LifeCycle事務的處理,其代碼具體如下:

  private void executeLifecycleState(ClientTransaction transaction) {
      ...
        // Cycle to the state right before the final requested state.
        cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction);
        // Execute the final transition with proper parameters.
        lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
        lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
    }

可以看到,cycleToPath是將activity切換到目標生命周期狀態的關鍵方法:

  private void cycleToPath(ActivityClientRecord r, int finish, boolean excludeLastState,
            ClientTransaction transaction) {
        final int start = r.getLifecycleState();
        final IntArray path = mHelper.getLifecyclePath(start, finish, excludeLastState);
        performLifecycleSequence(r, path, transaction);
    }

getLifecyclePath是獲取狀態路徑的方法,關於狀態路徑在上文中已經有所介紹。

  private void performLifecycleSequence(ActivityClientRecord r, IntArray path,
            ClientTransaction transaction) {
        final int size = path.size();
        for (int i = 0, state; i < size; i++) {
            state = path.get(i);
            switch (state) {
                case ON_CREATE:
                    mTransactionHandler.handleLaunchActivity(r, mPendingActions,
                            null /* customIntent */);
                    break;
                case ON_START:
                    mTransactionHandler.handleStartActivity(r, mPendingActions,
                            null /* activityOptions */);
                    break;
                case ON_RESUME:
                    mTransactionHandler.handleResumeActivity(r, false /* finalStateRequest */,
                            r.isForward, "LIFECYCLER_RESUME_ACTIVITY");
                    break;
                case ON_PAUSE:
                    mTransactionHandler.handlePauseActivity(r, false /* finished */,
                            false /* userLeaving */, 0 /* configChanges */, mPendingActions,
                            "LIFECYCLER_PAUSE_ACTIVITY");
                    break;
                case ON_STOP:
                    mTransactionHandler.handleStopActivity(r, 0 /* configChanges */,
                            mPendingActions, false /* finalStateRequest */,
                            "LIFECYCLER_STOP_ACTIVITY");
                    break;
                case ON_DESTROY:
                    mTransactionHandler.handleDestroyActivity(r, false /* finishing */,
                            0 /* configChanges */, false /* getNonConfigInstance */,
                            "performLifecycleSequence. cycling to:" + path.get(size - 1));
                    break;
                case ON_RESTART:
                    mTransactionHandler.performRestartActivity(r, false /* start */);
                    break;
                default:
                    throw new IllegalArgumentException("Unexpected lifecycle state: " + state);
            }
        }
    }
}

獲取到狀態路徑後,開始遍歷路徑,按順序依次切換路徑中的activity生命周期狀態,直到到達目標狀態為止。

在達到目標路徑後,會調用Lifecycle事務的excute方法。這裡會再一次調用切換到目標狀態的邏輯,不過實際狀態切換時,源碼裡做瞭狀態判重的操作,並不會造成任何不良的影響。

以上就是Android10 客戶端事務管理ClientLifecycleManager源碼解析的詳細內容,更多關於Android10 客戶端事務管理的資料請關註WalkonNet其它相關文章!

推薦閱讀: