Android10 客户端事务管理ClientLifecycleManager源码解析

这篇文章主要介绍了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 NameDesc
ConfigurationChangeItemApp configuration 改变的消息
WindowVisibilityItemWindow可见性发生改变的消息
MoveToDisplayItemActivity 移动到不同的显示设备的消息
MultiWindowModeChangeItem多窗口模式改变的消息
ActivityConfigurationChangeItemActivity configuration 改变的回调
PipModeChangeItem画中画模式改变的消息
ActivityResultItemActivity result的回调
NewIntentItemNew intent消息
TopResumedActivityChangeItemTop 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 

可以看到,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 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 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 

上述代码主要做了以下几件事:

  • 获取事务集的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 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  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 

获取到状态路径后,开始遍历路径,按顺序依次切换路径中的activity生命周期状态,直到到达目标状态为止。

在达到目标路径后,会调用Lifecycle事务的excute方法。这里会再一次调用切换到目标状态的逻辑,不过实际状态切换时,源码里做了状态判重的操作,并不会造成任何不良的影响。

以上就是Android10 客户端事务管理ClientLifecycleManager源码解析的详细内容,更多关于Android10 客户端事务管理的资料请关注0133技术站其它相关文章!

以上就是Android10 客户端事务管理ClientLifecycleManager源码解析的详细内容,更多请关注0133技术站其它相关文章!

赞(0) 打赏
未经允许不得转载:0133技术站首页 » 移动