Android U WMS: 屏幕旋转动画(2) app 侧 activity relaunch

735 阅读28分钟

一直以来,我关注的重点都是在服务端端,而对于 app 端,我只是做简单的了解,并不会深入分析。但是,在一次面试中,有一个 app 面试官一直问我 app 侧的细节,我的回答是轻描淡写,而内心的独白是,这关我服务端鸟事? 在痛定思痛后,我决定在 app 端出手。

出于篇幅的限制,Android U WMS : 屏幕旋转动画(1) 并没有对 app 端进行分析,其中涉及2件 app 端的事情

  1. app 进程是如何收到配置,以及如何更新配置。
  2. relaunch activity 是如何实现的。

生命周期控制机制

古人云,工欲善其事必先利其器,要想知道服务端如何控制 app 端组件的生命周期,首先得了解这个控制机制。

服务端控制 app 组件生命周期的数据,都是包装在一个事务类 ClientTransaction 中,如下

// ClientTransaction.java

/**
 * A container that holds a sequence of messages, which may be sent to a client.
 * This includes a list of callbacks and a final lifecycle state.
 */
public class ClientTransaction implements Parcelable, ObjectPoolItem {

    /** A list of individual callbacks to a client. */
    private List<ClientTransactionItem> mActivityCallbacks;

    /**
     * Final lifecycle state in which the client activity should be after the transaction is
     * executed.
     */
    private ActivityLifecycleItem mLifecycleStateRequest;

}

从注释可以看出,它有两个重要的数据,一个是回调列表 mActivityCallbacks,一个是生命周期请求 mLifecycleStateRequest。这两个数据,都能控制组件的生命周期,但是要细说它们有什么差别呢,只能用实际的例子,在分析中去体会。

回调的类型是 ClientTransactionItem,生命周期请求的类型是 ActivityLifecycleItem,看看相关的类图

classDiagram

BaseClientRequest <|.. ClientTransactionItem
ClientTransactionItem <|-- ConfigurationChangeItem
ClientTransactionItem <|-- LaunchActivityItem
ClientTransactionItem <|-- ActivityTransactionItem

ActivityTransactionItem <|-- ActivityLifecycleItem
ActivityLifecycleItem <|-- StartActivityItem
ActivityLifecycleItem <|-- ResumeActivityItem
ActivityLifecycleItem <|-- PauseActivityItem
ActivityLifecycleItem <|-- StopActivityItem
ActivityLifecycleItem <|-- DestroyActivityItem
ActivityTransactionItem <|-- ActivityRelaunchItem
ActivityTransactionItem <|-- ActivityConfigurationChangeItem


class BaseClientRequest {
<<interface>>
default void preExecute() 
void execute()
default void postExecute()
}

class ClientTransactionItem {
<<abstract>>
int getPostExecutionState()
}

class ActivityTransactionItem {
<<abstract>>
abstract void execute()
}


class ActivityLifecycleItem {
<<abstract>>
abstract int getTargetState()
}

虽然,这个类关系图,并不完整。但是我只想借此表明一件事,从 ActivityLifecycleItem 继承的类,都是生命周期请求类型,其他的都是回调类型。

既然知道了 ClientTransaction 的数据结构,那么,现在来看下 app 端,是如何处理这个事务类的

public final class ActivityThread extends ClientTransactionHandler
        implements ActivityThreadInternal {
    
    private class ApplicationThread extends IApplicationThread.Stub {
        
        public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
            // 这个方法由基类ClientTransactionHandler实现
            ActivityThread.this.scheduleTransaction(transaction);
        }
    }
 }
public abstract class ClientTransactionHandler {

    void scheduleTransaction(ClientTransaction transaction) {
        // 执行事务前的准备
        transaction.preExecute(this);
        // 执行事务
        // 最终由 TransactionExecutor#execute() 执行
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
    }
    
}

原来是先调用 ClientTransaction#preExecute() 做执行前的准备,就是调用所有回调以及生命周期请求的 preExecute() 方法,如下

// ClientTransaction.java

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);
    }
}

执行前的准备工作完成后,然后通过一个消息执行事务,最终消息由如下函数处理

// TransactionExecutor.java

public void execute(ClientTransaction transaction) {
    if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Start resolving transaction");

    final IBinder token = transaction.getActivityToken();
    if (token != null) {
        // 处理 activity 即将被 destroy 的情况 ...
    }

    if (DEBUG_RESOLVER) Slog.d(TAG, transactionToString(transaction, mTransactionHandler));

    // 1. 执行事务中所有回调
    executeCallbacks(transaction);
    
    // 2. 执行事务中的生命周期状态请求
    executeLifecycleState(transaction);
    
    // 3. 清除 mPendingActions
    mPendingActions.clear();
    if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "End resolving transaction");
}

事务的执行,有很清晰的三步,先执行回调,再执行生命周期请求,最后清理 mPendingActions。

注意,mPendingActions 永远不会被设置为 null,一般来说(我也不是非常肯定),在执行回调的过程中,会保存一些数据到 mPendingActions 中。然后,在执行生命周期请求的时候,会执行 mPendingActions 中保存的数据。在后面的分析中,即将看到,onSaveInstanceState() 和 onRestoreInstanceState() 是如何通过 mPendingActions 成对地执行的。

执行回调

// TransactionExecutor.java

public void executeCallbacks(ClientTransaction transaction) {
    // 获取回调的集合
    final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
    
    if (callbacks == null || callbacks.isEmpty()) {
        return;
    }

    // acitivity token
    final IBinder token = transaction.getActivityToken();
    // 根据 activity token 匹配 Activity 的数据
    ActivityClientRecord r = mTransactionHandler.getActivityClient(token);

    // 获取生命周期请求
    final ActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest();
    // 获取生命周期请求定义的最终生命周期状态
    final int finalState = finalStateRequest != null ? finalStateRequest.getTargetState()
            : UNDEFINED;
    
    // 回调可以通过 getPostExecutionState() 定义了一个生命周期状态,当执行回调的时候,必须同时把生命周期状态执行到这个请求的状态
    // 这里是获取最后一个定义了生命周期状态的回调的索引
    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();
        
        
        // 1. 如果回调通过  getPostExecutionState() 定义了一个生命周期状态
        // 那么先把 activity 的生命周期执行到  getPostExecutionState() 定义的前一个生命周期状态
        if (item.shouldHaveDefinedPreExecutionState()) {
            final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
                    item.getPostExecutionState());
            if (closestPreExecutionState != UNDEFINED) {
                cycleToPath(r, closestPreExecutionState, transaction);
            }
        }

        // 2. 执行回调的 execute() 和 postExecute()
        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);
        }

        // 3. 如果回调的 getPostExecutionState() 不等于生命周期请求定义的最终生命周期状态
        // 那么,把 activity 的生命周期执行到 getPostExecutionState() 定义的状态
        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);
        }
    }
}

执行回调的过程,主要就是执行回调的 execute() 和 postExecute()。但是回调也会通过 getPostExecutionState() 定义一个生命周期状态,当回调执行完成时,组件的生命周期状态也必须执行到这个状态。但是,由于大部分回调类都不实现 getPostExecutionState(),因此本文省略这一部分的分析,我相信在做的各位,完全可以自行分析。

执行生命周期请求

private void executeLifecycleState(ClientTransaction transaction) {
    // 获取生命周期请求
    final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
    if (lifecycleItem == null) {
        return;
    }

    // 获取 activity token
    final IBinder token = transaction.getActivityToken();
    // 根据 activity token 匹配 activity 数据
    final ActivityClientRecord r = mTransactionHandler.getActivityClient(token);

    if (r == null) {
        return;
    }

    // Cycle to the state right before the final requested state.
    // 1. 把 activity 的生命周期执行到 最终生命周期状态 的前一个状态
    // 第二个参数 lifecycleItem.getTargetState() 代表 activity 最终要执行到的生命周期
    cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction);

    // Execute the final transition with proper parameters.
    // 3. 执行生命周期请求的 execute() 和 postExecute()
    lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
    lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
}

生命周期请求 ActivityLifecycleItem 通过 getTargetState() 定义了 activity 最终要执行到的生命周期状态。但是,在执行生命周期请求的时候,先把 activity 生命周期执行到 最终生命周期状态 的前一个状态,然后再执行生命周期请求的 execute() 和 postExecute()。在 execute() 中,会把 activity 生命周期执行到 最终生命周期的状态。

来看下 cycleToPath() 是如何把 activity 的生命周期执行到 最终生命周期状态 的前一个状态

// TransactionExecutor.java

private void cycleToPath(ActivityClientRecord r, int finish, boolean excludeLastState,
        ClientTransaction transaction) {
    // 获取 activity 当前生命周期状态
    final int start = r.getLifecycleState();
    
    // 1. 获取要执行的生命周期路径
    // start 定义了生命周期的起始状态,此时是 activity 的当前生命周期状态
    // finish 定义了生命周期的最终状态,它由生命周期请求定义
    // excludeLastState 此时为 true,表示排除最终生命周期状态
    final IntArray path = mHelper.getLifecyclePath(start, finish, excludeLastState);
    
    // 2. 执行生命周期路径中的各种生命周期
    performLifecycleSequence(r, path, transaction);
}

start 和 finish 分别表示 activity 当前生命周期状态 以及 生命周期请求定义的最终生命周期状态,根据这两个状态,首先计算出需要执行的生命周期路径。然而,这个计算过程的代码,虽然很简单,但是如果没有实例进行分析,就感觉很晦涩难懂。我举个例子就明白了,如果 activity 当前生命周期状态是 resume,请求的生命周期状态是 destroy,那么要执行的生命周期路径是 pause->stop->destroy。此时,参数 excludeLastState 为 true,那么会排除最后一个生命周期 destroy,从而得到的生命周期路径为 pause->stop。

得到生命周期路径后,依次执行路径上生命周期,代码很简单,如下

// TransactionExecutor.java

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,
                        Context.DEVICE_ID_INVALID, null /* customIntent */);
                break;
            case ON_START:
                mTransactionHandler.handleStartActivity(r, mPendingActions,
                        null /* activityOptions */);
                break;
            case ON_RESUME:
                mTransactionHandler.handleResumeActivity(r, false /* finalStateRequest */,
                        r.isForward, false /* shouldSendCompatFakeFocus */,
                        "LIFECYCLER_RESUME_ACTIVITY");
                break;
            case ON_PAUSE:
                mTransactionHandler.handlePauseActivity(r, false /* finished */,
                        false /* userLeaving */, 0 /* configChanges */,
                        false /* autoEnteringPip */, 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);
        }
    }
}

发送配置给进程

了解了组件的生命周期控制机制后,那么就先以 app进程 如何收到以及处理配置 为例,来小试牛刀。

在上一篇文章的案例中,启动的是 HelloWorld app 的 MainActivity。那么,HelloWorld app 进程,是如何收到配置的呢? 当服务端马上要通知 app 端启动 Activity 时,会把 ActivityRecord 与进程进行绑定,然后进程就监听了 ActivityRecord 的配置改变,如下

// ActivityRecord.java

void setProcess(WindowProcessController proc) {
    // ActivityRecord#app 保存进程
    app = proc;
    
    final ActivityRecord root = task != null ? task.getRootActivity() : null;
    if (root == this) {
        task.setRootProcess(proc);
    }
    
    // 进程保存 ActivityRecord
    proc.addActivityIfNeeded(this);
    
    // ...
}

在 WMS 中, 由 WindowProcessController 代表一个 app 进程。因此,在 ActvityRecord 绑定进程的时候,ActivityRecord#app 保存的就是 WPC(WindowProcessController 的简称) 对象。同时,WPC 也保存了 ActivityRecord,并注册了 ActivityRecord 配置改变的监听器,如下

// WindowProcessController.java

void addActivityIfNeeded(ActivityRecord r) {
    setLastActivityLaunchTime(r);
    if (mActivities.contains(r)) {
        return;
    }
    
    // 用一个集合保存 ActivityRecord
    mActivities.add(r);
    
    mHasActivities = true;
    
    if (mInactiveActivities != null) {
        mInactiveActivities.remove(r);
    }
    
    // 监听Activity配置改变
    updateActivityConfigurationListener();
}

private void updateActivityConfigurationListener() {
    if (!mIsActivityConfigOverrideAllowed) {
        return;
    }

    for (int i = mActivities.size() - 1; i >= 0; i--) {
        final ActivityRecord activityRecord = mActivities.get(i);
        if (!activityRecord.finishing) {
            // 监听配置改变
            registerActivityConfigurationListener(activityRecord);
            return;
        }
    }

    unregisterActivityConfigurationListener();
}

void registerActivityConfigurationListener(ActivityRecord activityRecord) {
    if (activityRecord == null || activityRecord.containsListener(this)
            // Check for the caller from outside of this class.
            || !mIsActivityConfigOverrideAllowed) {
        return;
    }
    unregisterConfigurationListeners();
    mConfigActivityRecord = activityRecord;
    // 向 ActivityRecord 注册配置改变的监听器
    activityRecord.registerConfigurationChangeListener(this);
}
// ActivityRecord.java

void registerConfigurationChangeListener(ConfigurationContainerListener listener) {
    // 由基类实现
    registerConfigurationChangeListener(listener, true /* shouldDispatchConfig */);
}

// 基类 ConfigurationContainer 实现配置改变监听器的注册
void registerConfigurationChangeListener(ConfigurationContainerListener listener,
        boolean shouldDispatchConfig) {
    if (mChangeListeners.contains(listener)) {
        return;
    }
    
    // 用一个集合保存配置改变的监听器
    mChangeListeners.add(listener);
    
    // shouldDispatchConfig 此时为 true,这里会立即发送有一次配置给进程
    if (shouldDispatchConfig) {
        listener.onRequestedOverrideConfigurationChanged(mResolvedOverrideConfiguration);
        listener.onMergedOverrideConfigurationChanged(mMergedOverrideConfiguration);
    }
}

根据前面一篇文章的配置更新流程的分析可知,当 WC 配置更新时,会把相应配置发送给监听者,如下

// ConfigurationContainer.java

public void onConfigurationChanged(Configuration newParentConfig) {
    mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration);
    resolveOverrideConfiguration(newParentConfig);
    
    mFullConfiguration.setTo(newParentConfig);
    mFullConfiguration.windowConfiguration.unsetAlwaysOnTop();
    mFullConfiguration.updateFrom(mResolvedOverrideConfiguration);

    onMergedOverrideConfigurationChanged();

    // 当 mResolvedOverrideConfiguration 改变时,通知监听者
    if (!mResolvedTmpConfig.equals(mResolvedOverrideConfiguration)) {
        for (int i = mChangeListeners.size() - 1; i >= 0; --i) {
            mChangeListeners.get(i).onRequestedOverrideConfigurationChanged(
                    mResolvedOverrideConfiguration);
        }
    }
    
    // 无论 mMergedOverrideConfiguration 是否改变,都会通知监听者
    for (int i = mChangeListeners.size() - 1; i >= 0; --i) {
        mChangeListeners.get(i).onMergedOverrideConfigurationChanged(
                mMergedOverrideConfiguration);
    }
    
    for (int i = getChildCount() - 1; i >= 0; --i) {
        dispatchConfigurationToChild(getChildAt(i), mFullConfiguration);
    }
}

对于我们分析的屏幕旋转的案例来说,ActivityRecord 的 requested override config,以及 resolved override config ,都是 EMTPY(注意,不是 null)。因此,当 ActivityRecord 配置改变的,只有 merged override config 是发送给监听者的。WPC此时会收到 ActivityRecord 的 merged override config,如下

// WindowProcessController.java

public void onMergedOverrideConfigurationChanged(Configuration mergedOverrideConfig) {
    // 由处理 requested override config 的函数,来处理 merged override config
    super.onRequestedOverrideConfigurationChanged(mergedOverrideConfig);
}

// ConfigurationContainer.java
public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
    // 1.更新 requested override config
    updateRequestedOverrideConfiguration(overrideConfiguration);
    // Update full configuration of this container and all its children.
    final ConfigurationContainer parent = getParent();
    // 2. 处理 config changes
    // 注意,WPC 没有 parent,此时参数为 Configuration.EMPTY
    onConfigurationChanged(parent != null ? parent.getConfiguration() : Configuration.EMPTY);
}

WPC 使用处理 requested override config 的函数,来处理 merged override config 的。看来,对于 WPC 来说,requested overide config 和 merged override config 是一样的。

WPC 先利用 ActivityRecord 的 merged override config 更新自己的 requested override config( mRequestedOverrideConfiguration ),然后再调用自己复写的 onConfigurationChanged() 来更新其他配置,如下

// WindowProcessController.java

// 参数 newGlobalConfig 为 EMTPTY
public void onConfigurationChanged(Configuration newGlobalConfig) {
    // 1. 通过基类逻辑处理配置更新
    super.onConfigurationChanged(newGlobalConfig);

    boolean topActivityDeviceChanged = false;
    int deviceId = getTopActivityDeviceId();
    if (deviceId != mLastTopActivityDeviceId) {

    }
    
    // 2. 获取更新后的 full config
    final Configuration config = getConfiguration();
    
    if (mLastReportedConfiguration.equals(config) & !topActivityDeviceChanged) {

    }

    if (mPauseConfigurationDispatchCount > 0) {

    }

    // 3. 分发最新的 full config
    dispatchConfiguration(config);
}

// 分发 full config
void dispatchConfiguration(Configuration config) {
    mHasPendingConfigurationChange = false;
    if (mThread == null) {

    }

    config.seq = mAtm.increaseConfigurationSeqLocked();
    
    // 4.更新 mLastReportedConfiguration
    setLastReportedConfiguration(config);

    // 配置不会发送给缓存进程
    if (mRepProcState >= CACHED_CONFIG_PROC_STATE) {
        // ...
    }
    
    // 5. 把 full config 发送给进程
    scheduleConfigurationChange(mThread, config);
}

// full config 发送给进程
private void scheduleConfigurationChange(IApplicationThread thread, Configuration config) {
    ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending to proc %s new config %s", mName,
            config);

    mHasCachedConfiguration = false;
    try {
        // 6. 通知 app 端配置改变
        mAtm.getLifecycleManager().scheduleTransaction(thread,
                ConfigurationChangeItem.obtain(config, mLastTopActivityDeviceId));
    } catch (Exception e) {
        Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change: " + mOwner, e);
    }
}

WPC 先通过基类函数处理配置更新,根据前面一片文章的分析,它更新了 resolved override config, full config, merged override config 。然后 WPC 会把更新后的 full config,包装到 ConfigurationChangeItem,发送给 app。

由于 WPC 没有 parent,调用 onConfigurationChanged() 更新配置时,传入的 global config 是 EMPTY。因此,对于 WPC 来说,它的 resolved override config , full config , merged override cofig 都是一样的。

根据前面对机制的分析,只需要看看 ConfigurationChangeItem 实现的方法,即可知道 app 端如何处理的

// ConfigurationChangeItem.java

public class ConfigurationChangeItem extends ClientTransactionItem {

    @Override
    public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
        CompatibilityInfo.applyOverrideScaleIfNeeded(mConfiguration);
        // 1. 保存即将更新的配置
        client.updatePendingConfiguration(mConfiguration);
    }

    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        // 2. 处理配置改变
        client.handleConfigurationChanged(mConfiguration, mDeviceId);
    }
}    

app 端,先执行 ConfigurationChangeItem#preExecute() ,保存即将更新的配置,其实就是使用 ConfigurationController#mPendingConfigurationActivityThread#mPendingConfiguration 保存服务端发送过来的配置,如下

// ActivityThread.java

public void updatePendingConfiguration(Configuration config) {
    // 先更新 mConfigurationController.mPendingConfiguration
    final Configuration updatedConfig =
            mConfigurationController.updatePendingConfiguration(config);
    
    // 再更新 ActivityThread#mPendingConfiguration
    if (updatedConfig != null) {
        mPendingConfiguration = updatedConfig;
    }
}

然后 app 端处理配置改变,如下

// ActivityThread.java

public void handleConfigurationChanged(Configuration config, int deviceId) {
    // 交给 ConfigurationController 处理配置更新
    mConfigurationController.handleConfigurationChanged(config);
    
    // ...
}
// ConfigurationController.java

void handleConfigurationChanged(@NonNull Configuration config) {
    handleConfigurationChanged(config, null /* compat */);
}

// compat 为 null
void handleConfigurationChanged(@Nullable Configuration config,
        @Nullable CompatibilityInfo compat) {
    int configDiff;
    boolean equivalent;

    // ...

    synchronized (mResourcesManager) {
        // 1. 获取要处理的最新配置,保存到 config 中
        // 根据前面分析,mPendingConfiguration 保存了服务端下发的配置
        if (mPendingConfiguration != null) {
            // mPendingConfiguration 与 config 此时是一样的
            if (!mPendingConfiguration.isOtherSeqNewer(config)) {
                
            }
            mPendingConfiguration = null;
        }
        if (config == null) {
            return;
        }

        
        // 这里是检测 public 配置是否改变
        equivalent = mConfiguration != null && (0 == mConfiguration.diffPublicOnly(config));

        final Application app = mActivityThread.getApplication();
        final Resources appResources = app.getResources();
        // 2.根据配置更新资源
        mResourcesManager.applyConfigurationToResources(config, compat);
        updateLocaleListFromAppContext(app.getApplicationContext());

        if (mConfiguration == null) {
            mConfiguration = new Configuration();
        }

        // 没有任何配置改变,不需要处理
        // compat 此时为 null
        if (!mConfiguration.isOtherSeqNewer(config) && compat == null) {
            return;
        }
        
        // 3. 根据服务端发过来的配置,更新 ConfigurationController#mConfiguration
        configDiff = mConfiguration.updateFrom(config);
        config = applyCompatConfiguration();

        HardwareRenderer.sendDeviceConfigurationForDebugging(config);

        if ((systemTheme.getChangingConfigurations() & configDiff) != 0) {
        }

        if (systemUiTheme != null
                && (systemUiTheme.getChangingConfigurations() & configDiff) != 0) {
        }
    }

    // 4. 获取进程中,实现了ComponentCallbacks2接口的非UI组件,并回调它们的 onConfigurationChanged()
    final ArrayList<ComponentCallbacks2> callbacks =
            mActivityThread.collectComponentCallbacks(false /* includeUiContexts */);
    freeTextLayoutCachesIfNeeded(configDiff);
    if (callbacks != null) {
        final int size = callbacks.size();
        for (int i = 0; i < size; i++) {
            ComponentCallbacks2 cb = callbacks.get(i);
            if (!equivalent) {
                performConfigurationChanged(cb, config);
            }
        }
    }
}

ConfigurationController 检测到服务端下发的配置,与自己保存的配置,有差异时。会先更新 ConfigurationController#mConfiguration ,然后通知实现了 ComponentCallbacks2 接口的非UI组件,并调用它们的 onConfigurationChanged()。

那么,哪些组件会收到配置改变呢? 如下

// ActivityThread.java

// includeUiContexts 为 false
public ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeUiContexts) {
    ArrayList<ComponentCallbacks2> callbacks
            = new ArrayList<ComponentCallbacks2>();

    synchronized (mResourcesManager) {
        // 1. 保存所有 Application
        final int NAPP = mAllApplications.size();
        for (int i=0; i<NAPP; i++) {
            callbacks.add(mAllApplications.get(i));
        }
        
        // includeUiContexts 为 false,不收集 Activity
        if (includeUiContexts) {
            for (int i = mActivities.size() - 1; i >= 0; i--) {

            }
        }
        
        // 2. 保存所有 Service,但是排除 WindowProviderService
        final int NSVC = mServices.size();
        for (int i=0; i<NSVC; i++) {
            final Service service = mServices.valueAt(i);
            // If {@code includeUiContext} is set to false, WindowProviderService should not be
            // collected because WindowProviderService is a UI Context.
            if (includeUiContexts || !(service instanceof WindowProviderService)) {
                callbacks.add(service);
            }
        }
    }
    
    // 3. 保存所有的 ContentProvider
    synchronized (mProviderMap) {
        final int NPRV = mLocalProviders.size();
        for (int i=0; i<NPRV; i++) {
            callbacks.add(mLocalProviders.valueAt(i).mLocalProvider);
        }
    }

    return callbacks;
}

原来,当 app 进程收到配置改变时,只有 Application,Service,ContentProvider 的 onConfigurationChanged() 收到配置改变。但是,不包括 Activity。

relaunch activity

app 进程收到新配置时,没有把配置发送给 Activity,那么 Activity 的配置是何时更新的?

这就涉及到 app 开发的基础知识了,如果 Activity 在 AndroidManifest 中声明的 android:configChanges 覆盖了服务端的配置改变,那么表示 Activity 能自己处理配置改变。因此,服务端会把配置直接发送给 Activity,Activity 通过 onConfigurationChanged() 收到新配置。而如果 android:configChanges 不能覆盖服务端的配置改变,那么 activity 就会发生 relaunch,activity realunch 后,自然会获取到新配置。

当前分析的屏幕旋转的案例,没有为 MainActivity 声明 android:configChanges。因此,当发生屏幕旋转的时候, MainActivity 会发生 relaunch。根据前面文章的分析,服务端通知 app 端 relaunch activity 的代码如下

// ActivityRecord.java

void relaunchActivityLocked(boolean preserveWindow) {
    // ...

    try {
        // ...
        
        // mPendingRelaunchCount + 1 ,标记 activity 正在重启
        startRelaunching();
        
        // 创建一个回调 ActivityRelaunchItem
        // 参数 configChangeFlags 保存的是需要 app 端处理的配置
        final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults,
                pendingNewIntents, configChangeFlags,
                new MergedConfiguration(getProcessGlobalConfiguration(),
                        getMergedOverrideConfiguration()),
                preserveWindow);
        
        // 创建一个生命周期请求 ResumeActivityItem
        final ActivityLifecycleItem lifecycleItem;
        if (andResume) {
            lifecycleItem = ResumeActivityItem.obtain(isTransitionForward(),
                    shouldSendCompatFakeFocus());
        } else {
            // ...
        }
        
        // ClientTransaction 保存回调以及生命周期请求
        final ClientTransaction transaction = ClientTransaction.obtain(app.getThread(), token);
        transaction.addCallback(callbackItem);
        transaction.setLifecycleStateRequest(lifecycleItem);
        
        // 通知 app 端 relaunch activity
        mAtmService.getLifecycleManager().scheduleTransaction(transaction);
    } 
    
    // ...
}

根据前面 生命周期控制机制 的分析,首先会执行 ActivityRelaunchItem 和 ResumeActivityItem 的 preExecute(),然后执行回调 ActivityRelaunchItem 的 execute() 和 postExecute(),最后执行生命周期请求 ResumeActivityItem 的 execute() 和 postExecute()。

本文出于方便的目的,把 ActivityRelaunchItem 和 ResumeActivityItem 的 preExecute() 分开分析,因为这对结果并不会造成实际的影响,但是读者一定要注意,这俩的 preExecute() 是一起执行的。

下面分两部分,分别分析 ActivityRelaunchItem 回调,和 ResumeActivityItem 生命周期 的执行过程。

执行回调 ActivityRelaunchItem

回调 ActivityRelaunchItem,从严格的意义上讲,它才是控制 activity relaunch 的,来看下它实现的方法

// ActivityRelaunchItem.java

public class ActivityRelaunchItem extends ActivityTransactionItem {

    @Override
    public void preExecute(ClientTransactionHandler client, IBinder token) {
        // 1. 准备一个 relaunch activity 数据
        mActivityClientRecord = client.prepareRelaunchActivity(token, mPendingResults,
                mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow);
    }

    @Override
    public void execute(ClientTransactionHandler client, ActivityClientRecord r,
            PendingTransactionActions pendingActions) {
        // 2. 根据 relaunch activity 的数据,处理 relaunch activity
        // mActivityClientRecord 就是第1步准备的 relaunch activity 的数据
        client.handleRelaunchActivity(mActivityClientRecord, pendingActions);
    }

    @Override
    public void postExecute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        // 3. 通知服务端 relaunch activity 完成
        final ActivityClientRecord r = getActivityClientRecord(client, token);
        client.reportRelaunch(r);
    }

回调 ActivityRelaunchItem 实现的 relaunch activity 的过程

  1. 先准备一个 relaunch activity 数据,代表正在 relaunch 的 activity。参考【准备 relaunch activity 数据
  2. 根据准备的 relaunch activity 数据,处理 activity relaunch。参考【relaunch activity
  3. 通知服务端 activity relaunch 完成。参考【通知服务端 relaunch 完成

准备 relaunch activity 数据

// ActivityThread.java

public ActivityClientRecord prepareRelaunchActivity(IBinder token,
        List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
        int configChanges, MergedConfiguration config, boolean preserveWindow) {
    ActivityClientRecord target = null;
    boolean scheduleRelaunch = false;

    synchronized (mResourcesManager) {
        // 假设当前正在重启的 activity
        for (int i=0; i<mRelaunchingActivities.size(); i++) {
            
        }

        // 1.创建 ActivityClientRecord,并保存重启需要的数据
        if (target == null) {
            if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: target is null");
            target = new ActivityClientRecord();
            target.token = token;
            target.pendingResults = pendingResults;
            target.pendingIntents = pendingNewIntents;
            target.mPreserveWindow = preserveWindow;
            
            // 2.集合保存正在重启的 activity
            mRelaunchingActivities.add(target);
            
            // 表示正在调度 activity relaunch
            scheduleRelaunch = true;
        }
        // 保存的是 global config
        target.createdConfig = config.getGlobalConfiguration();
        // 保存的是 override config
        target.overrideConfig = config.getOverrideConfiguration();
        // 保存的是改变的配置
        target.pendingConfigChanges |= configChanges;
    }

    return scheduleRelaunch ? target : null;
}

所谓的准备一个 relaunch activity 数据,实际上就是创建一个 ActivityClientRecord 对象,把服务端传入的数据包装起来。另外,用一个集合 mRelaunchingActivities 保存了这个 ActivityClientRecord 对象。

relaunch activity

// ActivityThread.java

// tmp 是一个正在 relaunch 的 activity 数据
// pendingActions 来自于 TransactionExecutor#mPendingActions
public void handleRelaunchActivity(ActivityClientRecord tmp,
        PendingTransactionActions pendingActions) {
    unscheduleGcIdler();
    mSomeActivitiesChanged = true;

    int configChanges = 0;

    synchronized (mResourcesManager) {
        int N = mRelaunchingActivities.size();
        IBinder token = tmp.token;
        tmp = null;
        
        // 1. 检测 tmp 所指向的 activity 是否正在重启
        for (int i=0; i<N; i++) {
            // 在准备 relaunch activity 数据时,mRelaunchingActivities 保存了正在了 relaunch 的 activity 数据
            ActivityClientRecord r = mRelaunchingActivities.get(i);
            if (r.token == token) {
                tmp = r;
                configChanges |= tmp.pendingConfigChanges;
                mRelaunchingActivities.remove(i);
                i--;
                N--;
            }
        }

        if (tmp == null) {
            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Abort, activity not relaunching!");
            return;
        }

        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Relaunching activity "
                + tmp.token + " with configChanges=0x"
                + Integer.toHexString(configChanges));
    }

    
    // 此时没有需要处理的配置
    Configuration changedConfig = mConfigurationController.getPendingConfiguration(
            true /* clearPending */);
    mPendingConfiguration = null;
    if (tmp.createdConfig != null) {
        final Configuration config = mConfigurationController.getConfiguration();
        // 此时,config 和 tmp.createdConfig 是一样的
        if (config == null
                || (tmp.createdConfig.isOtherSeqNewer(config)
                        && config.diff(tmp.createdConfig) != 0)) {
            
        }
    }

    if (DEBUG_CONFIGURATION) Slog.v(TAG, "Relaunching activity "
            + tmp.token + ": changedConfig=" + changedConfig);

    if (changedConfig != null) {
        
    }

    // 2. 根据正在relaunch的activity数据中的token,匹配正在运行的 Activity 数据
    ActivityClientRecord r = mActivities.get(tmp.token);
    if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handling relaunch of " + r);
    if (r == null) {
        return;
    }
    // 保存改变的配置
    r.activity.mConfigChangeFlags |= configChanges;
    // 目前为 false
    r.mPreserveWindow = tmp.mPreserveWindow;
    // 标记 activity 的配置正在改变
    r.activity.mChangingConfigurations = true;

    // 3. 继续处理 activity relaunch
    // 参数 tmp.startsNotResumed 为 false
    handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents,
            pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity");
}

简单来说,这里是先确认有正在 relaunch 的 activity 数据,然后根据这个数据中的 token 匹配 app 进程中正在运行的 activity 数据,最后利用匹配到的 activity 数据,来执行 relaunch

// ActivityThread.java

private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges,
        List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents,
        PendingTransactionActions pendingActions, boolean startsNotResumed,
        Configuration overrideConfig, String reason) {
    // Preserve last used intent, it may be set from Activity#setIntent().
    final Intent customIntent = r.activity.mIntent;
    
    // Need to ensure state is saved.
    // 1. 执行 pause activity  和 stop activity,并保存状态
    if (!r.paused) {
        performPauseActivity(r, false, reason, null /* pendingActions */);
    }
    if (!r.stopped) {
        // 第二个参数为 true,表示要保存状态
        callActivityOnStop(r, true /* saveState */, reason);
    }
    
    // 2. 执行 destroy activity
    handleDestroyActivity(r, false, configChanges, true, reason);

    // 3. 更新一些 activity 数据
    // activity 已经 destroy了
    // 因此清理 ActivityClientRecord 中的 activity 以及 window 数据
    r.activity = null;
    r.window = null;
    r.hideForNow = false;
    
    if (pendingResults != null) {
        
    }
    if (pendingIntents != null) {
        
    }
    r.startsNotResumed = startsNotResumed;//false
    // 这里保存的是服务端 ActivityRecord 的 merge override config
    r.overrideConfig = overrideConfig;

    // 3. 执行 launch actvity
    // 这里会创建 Actvity 对象,并调用 Activity#onCreate()
    // 注意,pendingActions 会保存一些数据
    handleLaunchActivity(r, pendingActions, mLastReportedDeviceId, customIntent);
}

这里就是真正实现 relaunch activity 的地方

  1. 执行 pause activity 和 stop activity ,并且还会调用 onSaveInstanceState() 保存 Activity 状态。严格来说,这里并没有完整地执行 pause activity 和 stop activity 流程,因为一个完整的生命周期的执行流程是 handleXXXActivity() -> performXXXActivity() -> callActivityOnXXX()。参考【pause activity
  2. 执行 destroy activity。参考【destroy activity
  3. 既然 activity 已经 destroy 了,那么就清理 ActivityClientRecord#activity 和 ActivityClientRecord#window,因为它们分别指向一个 Activity 对象,以及 Activity 对象所绑定的 Window。同时也使用了 ActivityClientController#overrideConfig 保存了服务端 ActivityRecord 的 merged override config。
  4. 执行 launch activity 去创建一个新的 Activity。既然 destroy activity 后, ActivityClientRecord#activity 以及 ActivityClientRecord#window 被清理,那么当重新创建一个 Activity 后,这些数据就必须被重新填充。参考【launch activity

pause activity

// ActivityThread.java

// pendingActions 为 null
private Bundle performPauseActivity(ActivityClientRecord r, boolean finished, String reason,
        PendingTransactionActions pendingActions) {
    if (r.paused) {
        
    }

    if (finished) {

    }

    // 1.H 版本之前,在 onPause() 之前调用 onSaveInstanceState()
    final boolean shouldSaveState = !r.activity.mFinished && r.isPreHoneycomb();
    if (shouldSaveState) {
        callActivityOnSaveInstanceState(r);
    }

    // 2. 执行下一步的 pause activity。主要是执行 Activity#onPause()
    performPauseActivityIfNeeded(r, reason);

    // Notify any outstanding on paused listeners
    ArrayList<OnActivityPausedListener> listeners;
    synchronized (mOnPauseListeners) {
        listeners = mOnPauseListeners.remove(r.activity);
    }
    int size = (listeners != null ? listeners.size() : 0);
    for (int i = 0; i < size; i++) {
        listeners.get(i).onPaused(r.activity);
    }

    // 此时参数 pendingActions 为 null
    final Bundle oldState = pendingActions != null ? pendingActions.getOldState() : null;
    if (oldState != null) {
       
    }

    return shouldSaveState ? r.state : null;
}

relaunch activity 的 pause activity 流程,除了调用 Activity#onPause() 以外,如果 app 的 target SDK 版本低于 H(Android 11)版本,还会在调用 onPause() 之前,调用 onSaveInstanceState()。

stop actvity

// ActivityThread.java

private void callActivityOnStop(ActivityClientRecord r, boolean saveState, String reason) {
    // 1.H 版本之后,P 版本之前,在 onStop() 之前调用 onSaveInstanceState()
    final boolean shouldSaveState = saveState && !r.activity.mFinished && r.state == null
            && !r.isPreHoneycomb();
    final boolean isPreP = r.isPreP();
    if (shouldSaveState && isPreP) {
        callActivityOnSaveInstanceState(r);
    }

    try {
        // 2. activity 执行 stop
        r.activity.performStop(r.mPreserveWindow, reason);
    } catch (SuperNotCalledException e) {}

    // 状态切换到 ON_STOP
    r.setState(ON_STOP);
    
    // 3. P 版本之后,在 onStop() 之后调用 onSaveInstanceState()
    if (shouldSaveState && !isPreP) {
        callActivityOnSaveInstanceState(r);
    }
}

relaunch activity 的 stop activity 流程,会调用 Activity#onStop(),同时也会执行 onSaveInstanceState()。 如果 target SDK 版本,大于 H 版本,小于 P 版本,那么 onSaveInstanceState() 会在 onStop() 之前执行,如果大于 P 版本,那么会在 onStop() 之后执行。

现在来看下 onSaveInstanceState() 到底是如何保存数据的,如下

// ActivityThread.java

private void callActivityOnSaveInstanceState(ActivityClientRecord r) {
    r.state = new Bundle();
    r.state.setAllowFds(false);
    // android:persistableMode 设置为 persistAcrossReboots
    if (r.isPersistable()) {
        r.persistentState = new PersistableBundle();
        // 调用 onSaveInstanceState() 把数据保存到 r.state 和 r.persistentState 中
        mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
                r.persistentState);
    } else {
        // 调用 onSaveInstanceState(),只把数据保存到 r.state 中
        mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
    }
}

如果 Activity 在 AndroidManifest.xml 中声明了 android:persistableMode 属性值为 persistAcrossReboots,那么会调用 onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) 会把状态保存到 r.state 和 r.persistentState 中。否则,会调用 onSaveInstanceState(Bundle outState), 只会把数据保存到 r.state 中。

可能有人很好奇,android:persistableMode 设置为 persistAcrossReboots,有什么作用?如果服务端通过一个生命周期请求 StopActivityItem ,使 Activity 进入 onStop() 状态。那么,在执行 StopActivityItem#postExecute() 时,会把数据上报给服务端保存。当系统重启前(非异常重启),服务端会把数据保存到文件中。当重启后,如果再创建这个 Activity,服务端会把数据下发给 app 端,这样就达到恢复数据的目的。

现在来看下 activity 执行 stop 的流程

// Actiivty.java

final void performStop(boolean preserveWindow, String reason) {
    if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "performStop:"
                + mComponent.getClassName());
    }
    mDoReportFullyDrawn = false;
    mFragments.doLoaderStop(mChangingConfigurations /*retain*/);
    // Disallow entering picture-in-picture after the activity has been stopped
    mCanEnterPictureInPicture = false;
    if (!mStopped) {
        dispatchActivityPreStopped();
        if (mWindow != null) {
            mWindow.closeAllPanels();
        }

        // 1. 更新 ViewRootImpl 的 stopped 状态
        // 其实是为了销毁BBQ以及硬件渲染资源
        if (!preserveWindow && mToken != null && mParent == null) {
            WindowManagerGlobal.getInstance().setStoppedState(mToken, true);
        }

        mFragments.dispatchStop();
        mCalled = false;
        final long startTime = SystemClock.uptimeMillis();
        
        // 2. 调用 Activity#onStop()
        mInstrumentation.callActivityOnStop(this);
        
        final long duration = SystemClock.uptimeMillis() - startTime;
        EventLogTags.writeWmOnStopCalled(mIdent, getComponentName().getClassName(), reason,
                duration);

        // 这里应该是关闭 Loader 管理的 Cursor
        synchronized (mManagedCursors) {
            final int N = mManagedCursors.size();
            for (int i=0; i<N; i++) {
                ManagedCursor mc = mManagedCursors.get(i);
                if (!mc.mReleased) {
                    mc.mCursor.deactivate();
                    mc.mReleased = true;
                }
            }
        }
        mStopped = true;
        dispatchActivityPostStopped();
    }
    mResumed = false;
    Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}

Activity 执行 stop,会调用 Activity#onStop(),并且还有一个与窗口有关的操作,就是第1步,它会通知 ViewRootImpl 更新 stopped 状态,并且销毁一些资源,如下

// WindowManagerGlobal.java

// token 此时为 activity token
public void setStoppedState(IBinder token, boolean stopped) {
    ArrayList<ViewRootImpl> nonCurrentThreadRoots = null;
    synchronized (mLock) {
        int count = mViews.size();
        for (int i = count - 1; i >= 0; i--) {
            if (token == null || mParams.get(i).token == token) {
                // 找到 activity token 绑定的 ViewRootImpl
                ViewRootImpl root = mRoots.get(i);

                if (root.mThread == Thread.currentThread()) {
                    // ViewRootImpl 切换窗口的 stopped 状态
                    root.setWindowStopped(stopped);
                } else {
                    
                }
                // 切换子窗口(例如,PopupWindow)的 ViewRootImpl 的 stopped 状态
                setStoppedState(root.mAttachInfo.mWindowToken, stopped);
            }
        }
    }
    if (nonCurrentThreadRoots != null) {
        
    }
}
// ViewRootImpl.java

// stopped 为 true
void setWindowStopped(boolean stopped) {
    checkThread();
    if (mStopped != stopped) {
        // 更新 stopped 状态
        mStopped = stopped;
        
        final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
        if (renderer != null) {
            if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped);
            // 停止硬件渲染 surface
            renderer.setStopped(mStopped);
        }
        if (!mStopped) {

        } else {
            if (renderer != null) {
                // 销毁硬件渲染资源
                renderer.destroyHardwareResources(mView);
            }

            if (mSurface.isValid()) {
                if (mSurfaceHolder != null) {
                    
                }

                // 通知监听者 surface 被销毁,SurfaceView 就是其中一个监听者
                notifySurfaceDestroyed();
            }

            // 销毁 BBQ 以及 surface
            destroySurface();
        }
    }
}

private void destroySurface() {
    if (mBoundsLayer != null) {
        mBoundsLayer.release();
        mBoundsLayer = null;
    }

    // 释放 surface
    mSurface.release();
    mSurfaceControl.release();

    // destroy BBQ
    if (mBlastBufferQueue != null) {
        mBlastBufferQueue.destroy();
        mBlastBufferQueue = null;
    }

    // 硬件渲染不在关联 BBQ 以及 surface
    if (mAttachInfo.mThreadedRenderer != null) {
        mAttachInfo.mThreadedRenderer.setSurfaceControl(null, null);
    }
}

ThreadedRender, BlastBufferQueue,SurfaceControl,Surface,都是与窗口相关,这些东西不是三言两语能讲得清楚的。但是,我们只需要知道,在 Activity stop 期间,会销毁这些资源就够了。

destroy activity

// ActivityThread.java

public void handleDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges,
        boolean getNonConfigInstance, String reason) {
    // 1.主要是调用 Activity#onDestroy()
    performDestroyActivity(r, finishing, configChanges, getNonConfigInstance, reason);
    
    cleanUpPendingRemoveWindows(r, finishing);
    WindowManager wm = r.activity.getWindowManager();
    View v = r.activity.mDecor;
    if (v != null) {
        if (r.activity.mVisibleFromServer) {
            mNumVisibleActivities--;
        }
        
        // 这里获取的是 ViewRootImpl#mWindow,这个称之为 window token
        IBinder wtoken = v.getWindowToken();

        if (r.activity.mWindowAdded) {
            if (r.mPreserveWindow) {
            
            } else {
                final ViewRootImpl viewRoot = v.getViewRootImpl();
                if (viewRoot != null) {
                    viewRoot.setActivityConfigCallback(null);
                }
                // 2.通过 window manager,移除 DecorView
                // 其实就是移除 activity 主窗口
                wm.removeViewImmediate(v);
            }
        }
        if (wtoken != null && r.mPendingRemoveWindow == null) {
            // 3. 移除 window token 相关的窗口
            // 这些窗口就是子窗口,例如 PopupWindow
            WindowManagerGlobal.getInstance().closeAll(wtoken,
                    r.activity.getClass().getName(), "Activity");
        } else if (r.mPendingRemoveWindow != null) {
        
        }
            
    }
    
    if (r.mPendingRemoveWindow == null) {
        // 4. 移除 activity token 相关的窗口
        // 通过 Activity#getWindowManger() 添加的窗口,使用的都是 activity token
        WindowManagerGlobal.getInstance().closeAll(r.token,
                r.activity.getClass().getName(), "Activity");
    }


    // ..
}

relaunch activity 的 destroy activity

  1. 调用 Activity#onDestroy()
  2. 通过 WindowManager 移除 DecorView,其实就是移除 Activity 的主窗口,最终会通知服务端移除窗口。
  3. 移除子窗口。
  4. 移除 activity token 相关的窗口。

这里介绍下一些窗口使用的 token

  1. Activity 自己的窗口,使用的是 activity token。
  2. 通过 Activity#getWindowManger() 添加的窗口,使用的也是 activity token。
  3. 像 PopupWindow 这样的子窗口,使用的是 Activity 的 ViewRootImpl#mWindow 作为 token,WMS 通过这个 token 识别父窗口。

主要来看下第2步,通过 WindowManager 移除 DecorView

// WindowManagerImpl.java

public void removeViewImmediate(View view) {
    mGlobal.removeView(view, true);
}
public void removeView(View view, boolean immediate) {
    if (view == null) {
        throw new IllegalArgumentException("view must not be null");
    }

    synchronized (mLock) {
        // 通过 DecorView 找到对应的 index
        int index = findViewLocked(view, true);
        View curView = mRoots.get(index).getView();
        
        // 根据 index 移除 DecorView
        removeViewLocked(index, immediate);
        if (curView == view) {
            return;
        }
        throw new IllegalStateException("Calling with view " + view
                + " but the ViewAncestor is attached to " + curView);
    }
}

private void removeViewLocked(int index, boolean immediate) {
    // 根据 index 找到 ViewRootImpl
    ViewRootImpl root = mRoots.get(index);

    // 此时获取的是 DecorView
    View view = root.getView();
    if (root != null) {
        root.getImeFocusController().onWindowDismissed();
    }

    // ViewRootImpl 立即移除
    // 参数 immediate 为 true
    boolean deferred = root.die(immediate);
    
    if (view != null) {
        // DecorView 不在与 ViewRootImpl 关联
        view.assignParent(null);
        if (deferred) {
            mDyingViews.add(view);
        }
    }
}
// ViewRootImpl.java

boolean die(boolean immediate) {
    // 假设 ViewRootImpl 当前并没有处于 traversal 中
    if (immediate && !mIsInTraversal) {
        doDie();
        return false;
    }

    // ...
}

void doDie() {
    checkThread();
    if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
    synchronized (this) {
        if (mRemoved) {
            return;
        }
        mRemoved = true;
        mOnBackInvokedDispatcher.detachFromWindow();
        if (mAdded) {
            // 1. 窗口分离
            // 销毁资源,通知服务端移除窗口,等等
            dispatchDetachedFromWindow();
        }
        if (mAdded && !mFirst) {
            // dispatchDetachedFromWindow() 已经执行过
            destroyHardwareRenderer();
            if (mView != null) {
                int viewVisibility = mView.getVisibility();
                boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
                if (mWindowAttributesChanged || viewVisibilityChanged) {
                    
                }
                // dispatchDetachedFromWindow() 已经执行过
                destroySurface();
            }
        }

        mInsetsController.onControlsChanged(null);
        mAdded = false;
        AnimationHandler.removeRequestor(this);
    }
    if (mActiveSurfaceSyncGroup != null) {
        mActiveSurfaceSyncGroup.markSyncReady();
        mActiveSurfaceSyncGroup = null;
    }
    if (mHasPendingTransactions) {
        mPendingTransaction.apply();
    }

    // 2. 通知 WindowManagerGlobal 移除 View
    WindowManagerGlobal.getInstance().doRemoveView(this);
}

destroy activity 通过 WindowManager 移除 DecorView

  1. 窗口分离。 app 侧会销毁一些资源,例如 ThreadedRenderer,然后通知服务端移除窗口。
  2. 通知 WindowManagerGlobal 移除 View。WindowManagerGlobal 有三个集合 mViews, mRoots, mParams 保存 View 的相关的数据,而这里就是从这些集合中移除数据。

我们看下第1步,窗口分离做了什么

// ViewRootImpl.java

void dispatchDetachedFromWindow() {
    // ...

    if (mView != null && mView.mAttachInfo != null) {
        // 通知 listener onWindowDetached()
        mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);

        // 通知 DecorView 从窗口分离,DecorView 以及 chidlren 都清理 mAttachInfo
        mView.dispatchDetachedFromWindow();
    }
    
    // ...

    // 销毁 ThreadedRenderer
    destroyHardwareRenderer();

    // DecorView 的 parent 设置为 null
    mView.assignParent(null);
    // 清理 ViewRootImp#mView 为 null
    mView = null;
    mAttachInfo.mRootView = null;

    destroySurface();

    if (mInputQueueCallback != null && mInputQueue != null) {
        mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
        mInputQueue.dispose();
        mInputQueueCallback = null;
        mInputQueue = null;
    }
    
    try {
        // 通知服务端移除窗口
        mWindowSession.remove(mWindow);
    } catch (RemoteException e) {
    }
    
    // Dispose receiver would dispose client InputChannel, too. That could send out a socket
    // broken event, so we need to unregister the server InputChannel when removing window to
    // prevent server side receive the event and prompt error.
    if (mInputEventReceiver != null) {
        mInputEventReceiver.dispose();
        mInputEventReceiver = null;
    }
    unregisterListeners();
    unscheduleTraversals();
}

在 stop activity 流程,已经销毁了资源,所以在 destroy activity 的窗口分离过程,主要是通知 WMS 移除窗口,销毁输入事件管道,等等。

launch activity

// ActivityThread.java

public Activity handleLaunchActivity(ActivityClientRecord r,
        PendingTransactionActions pendingActions, int deviceId, Intent customIntent) {
    // ...

    // 1.创建并初始化 Activity,并调用 Activity#onCreate()
    final Activity a = performLaunchActivity(r, customIntent);

    if (a != null) {
        r.createdConfig = new Configuration(mConfigurationController.getConfiguration());
        reportSizeConfigurations(r);
        
        // 2. pendingActions 保存数据
        // pendingActions 永远不为 null
        if (!r.activity.mFinished && pendingActions != null) {
            // r.state 保存的是 onSaveInstanceState() 保存的状态
            // 注意,只
            pendingActions.setOldState(r.state);
            // 表示后面要调用 onRestoreInstanceState()
            pendingActions.setRestoreInstanceState(true);
            // 表示后面要调用 onPostCreate()
            pendingActions.setCallOnPostCreate(true);
        }
    } else {
        
    }

    return a;
}

根据前面机制的分析,pendingActions 来自于 TransactionExecutor#mPendingActions ,它永远不为 null。它保存了 onSaveInstanceState() 的返回的数据, 但是只保存了 ActivityClientRecord#state,并没有保存 ActivityClientRecord#persistentState ,然后标记后面需要调用 onSaveInstanceState() 和 onPostCreate()。

继续看下 performLaunchActivity()

// ActivityThread.java

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    // ...

    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        // 1.通过反射创建 Activity
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        // ...
    } catch (Exception e) {}

    try {
        // ...

        if (activity != null) {
            // ...

            // 2. attach activity
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.referrer, r.voiceInteractor, window, r.activityConfigCallback,
                    r.assistToken, r.shareableActivityToken);

            // ...

            // 3. 重新填充 ActivityClientRecord#activity
            r.activity = activity;
            
            // 3.调用 Activity#onCreate()
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            
            // ...
        }
        
        r.setState(ON_CREATE);

    } catch (SuperNotCalledException e) {}

    return activity;
}

Launch activity 大致过程

  1. 通过反射创建一个 Activity 对象。
  2. attach Activity。Activity 对象保存数据,然后最重要的就是创建 Window。
  3. 执行 Activity#onCreate()。在这个方法里,调用 setContentView() 设置一个 View 到 PhoneWindow 中,这个实现过程,我相信在座的各位都明白。

来看下 attach activity 过程

// Activity.java

final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor,
        Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
        IBinder shareableActivityToken) {
    // ...

    // 1. 创建 PhoneWindow
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    // 控制 window 的回调,例如,进入 PIP,进入/退出自由浮窗
    mWindow.setWindowControllerCallback(mWindowControllerCallback);
    // 事件分发的回调
    mWindow.setCallback(this);
    // 窗口消息的回调,Activity 接受这个回调,执行finish activity
    mWindow.setOnWindowDismissedCallback(this);
    
    // ...

    //2. PhoneWindow 设置 WindowManager
    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    
    // ...

    // Activity 保存的 WindowManager 实际的类型是 WindowManagerImpl
    mWindowManager = mWindow.getWindowManager();

    // ...
}

attach actvity,主要是给 Activity 创建一个 Window ,即 PhoneWindow。另外,还有一个很重要的事情,就是从 Activity 获取的 WindowManager 到底是什么类型,来看下给 PhoneWindow 设置 WindowManager 到底是什么,因为这关乎到从 Activity 获取到的 WindowManager 到底是什么

// Window.java

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
        boolean hardwareAccelerated) {
    mAppToken = appToken;
    mAppName = appName;
    mHardwareAccelerated = hardwareAccelerated;
    if (wm == null) {
        wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    }
    // 获取的 window 系统服务,返回的就是 WindowManagerImpl
    // 而这里,又重新窗机爱你一个 WindowManagerImpl,只多包装了一个参数,那就是 PhoneWindow
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}

// WindowManagerImpl.java

public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
    // 把传入的参数 parentWindow,包装到 WindowManagerImpl
    // parentWindow 是 PhoneWindow
    return new WindowManagerImpl(mContext, parentWindow, mWindowContextToken);
}

Activity 和 PhoneWindow 关联的 WindowManager 的类型为 WindowManagerImpl,它与从系统服务中获取的 WindowManagerImpl 不同的地方在于,它保存了 Activity 创建的 PhoneWindow。

那么 WindowManagerImpl 使用 PhoneWindow 做什么呢? 当通过 Activity#getWindowManager() 添加一个 View(即窗口)时,如果没有在 LayoutParams 中指定 token,那么 WindowManagerGlobal#addView() 函数,会利用 PhoneWindow#adjustLayoutParamsForSubWindow() 来添加 token。

通知服务端 relaunch 完成

// ActivityClientController.java

public void activityRelaunched(IBinder token) {
    final long origId = Binder.clearCallingIdentity();
    synchronized (mGlobalLock) {
        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
        if (r != null) {
            // 由 ActivityRecord finish relaunch
            r.finishRelaunching();
        }
    }
    Binder.restoreCallingIdentity(origId);
}
// ActivityRecord.java

void finishRelaunching() {
    mLetterboxUiController.setRelaunchingAfterRequestedOrientationChanged(false);
    mTaskSupervisor.getActivityMetricsLogger().notifyActivityRelaunched(this);

    if (mPendingRelaunchCount > 0) {
        // mPendingRelaunchCount - 1
        mPendingRelaunchCount--;
        if (mPendingRelaunchCount == 0 && !isClientVisible()) {

        }
    } else {

    }

    final Task rootTask = getRootTask();
    if (rootTask != null && rootTask.shouldSleepOrShutDownActivities()) {

    }
}

服务端在通知 app 端 relaunch activity 之前,会把 mPendingRelaunchCount + 1。

现在,服务端收到 app relaunch 完成的消息后,主要就是把 mPendingRelaunchCount 减 1。

那么,现在 mPendingRelaunchCount 为 0,表示 activity 重启完成,这个状态是非常重要的,它会被 shell transition 用来检测窗口是否重绘完成。

执行生命周期请求 ResumeActivityItem

// ResumeActivityItem.java

public class ResumeActivityItem extends ActivityLifecycleItem {

    @Override
    public void preExecute(ClientTransactionHandler client, IBinder token) {
        if (mUpdateProcState) {
            client.updateProcessState(mProcState, false);
        }
    }

    @Override
    public void execute(ClientTransactionHandler client, ActivityClientRecord r,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
        // 1. resume activity
        client.handleResumeActivity(r, true /* finalStateRequest */, mIsForward,
                mShouldSendCompatFakeFocus, "RESUME_ACTIVITY");
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }

    @Override
    public void postExecute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        ActivityClient.getInstance().activityResumed(token, client.isHandleSplashScreenExit(token));
    }
}    

preExecute() 和 postExecute() 可以忽略,而 execute() 执行的就是 resume activity 流程。

start activity

根据前面对 ActivityRelaunchItem 的分析,activity 的生命周期最终执行到了 onCreate()。现在执行生命周期请求 ResumeActivityItem,最终需要把生命周期执行到 onResume()。根据 生命周期控制机制 的分析,需要先执行 onStart() 生命周期,如下

// TransactionExecutor.java

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_START:
                mTransactionHandler.handleStartActivity(r, mPendingActions,
                        null /* activityOptions */);
                break;
           
        }
    }
}
// ActivityThread.java

public void handleStartActivity(ActivityClientRecord r,
        PendingTransactionActions pendingActions, ActivityOptions activityOptions) {
    final Activity activity = r.activity;
    
    // ...

    // 1.执行 Activity#onStart()
    activity.performStart("handleStartActivity");
    r.setState(ON_START);

    if (pendingActions == null) {
        return;
    }
    
    // 2. 执行 onRestoreInstanceState()
    // pendingActions 在 launch activity 中保存了这个数据
    if (pendingActions.shouldRestoreInstanceState()) {
        if (r.isPersistable()) {
            if (r.state != null || r.persistentState != null) {
                mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                        r.persistentState);
            }
        } else if (r.state != null) {
            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
        }
    }

    // 3. 执行 onPostCreate()
    // pendingActions 在 launch activity 中保存了这个数据
    if (pendingActions.shouldCallOnPostCreate()) {
        activity.mCalled = false;
        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "onPostCreate");
        if (r.isPersistable()) {
            mInstrumentation.callActivityOnPostCreate(activity, r.state,
                    r.persistentState);
        } else {
            mInstrumentation.callActivityOnPostCreate(activity, r.state);
        }
        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
    }

    // 由于 Activity 刚刚重建,此时 r.activity.mDecor 还为 null,因此这里什么也做
    // DecorView 现在还保存 PhoneWindow#mDecor 中
    updateVisibility(r, true /* show */);
    mSomeActivitiesChanged = true;
}

执行 start activity ,除了会调用 Activity#onStart() 以外,还会根据 pendingActions 保存的参数,分别执行 Activity#onRestoreInstanceState() 和 Activity#onPostCreate()。根据 launch activity 章节的分析,pendingActions 确实保存过这些数据。

resume activity

// ActivityThread.java

public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
        boolean isForward, boolean shouldSendCompatFakeFocus, String reason) {
    // ...

    // 1. 执行 resume activity 
    if (!performResumeActivity(r, finalStateRequest, reason)) {
        return;
    }
    
    // ...

    final Activity a = r.activity;

    // ...

    if (r.window == null && !a.mFinished && willBeVisible) {
        // 把 Activity 创建的 PhoneWindow,保存到 ActivityClientRecord#window 
        r.window = r.activity.getWindow();

        View decor = r.window.getDecorView();
        // DecorView 可见性设置为 INVISIBLE
        decor.setVisibility(View.INVISIBLE);
        
        ViewManager wm = a.getWindowManager();
        WindowManager.LayoutParams l = r.window.getAttributes();

        // AcivityClientRecord#mDecor 此时才保存了 PhoneWindow 中创建的 DecorView
        a.mDecor = decor;
        
        // 窗口类型为 TYPE_BASE_APPLICATION
        l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
        l.softInputMode |= forwardBit;
        if (r.mPreserveWindow) {
            
        }
        if (a.mVisibleFromClient) {
            if (!a.mWindowAdded) {
                a.mWindowAdded = true;
                // 2.通过 WindowManager 添加 DecorView
                wm.addView(decor, l);
            } else {
                
            }
        }
    } else if (!willBeVisible) {
        
    }

    cleanUpPendingRemoveWindows(r, false /* force */);

    if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
        if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward);
        ViewRootImpl impl = r.window.getDecorView().getViewRootImpl();
        
        // ...
        
        // 此时 mVisibleFromServer 才为 true
        r.activity.mVisibleFromServer = true;
        mNumVisibleActivities++;
        if (r.activity.mVisibleFromClient) {
            // 这里把 DecorView 的可见性设置为 VISIBLE
            r.activity.makeVisible();
        }

        if (shouldSendCompatFakeFocus) {

        }
    }

    // IdleHandler 中会用到 mNewActivities
    mNewActivities.add(r);
    if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);
    
    // 3.向消息队列中添加 IdleHandler
    Looper.myQueue().addIdleHandler(new Idler());
}

执行 resume activity,关注三个点

  1. 执行 Activity#onResume()。
  2. 通过 WindowManager 添加 DecorView。ViewRootImpl 会向 WMS 添加窗口,然后 relayout surface,最后对 DecorView 进行 measure,layout,draw,等等。
  3. 向消息队列中添加一个 IdleHandler。当消息队列中没有消息执行,马上要进入阻塞的时候,会执行 IdleHandler。而 IdleHandler 会通知服务端 activity 处理 idle 状态。WMS 会关心这个 idle 状态的,至于有什么用,等分析到的时候就知道了。

结束

其实,我本来不打算发表这篇文章的,因为琐碎的细节太多,导致分析不能面面俱到,从而会浪费篇幅以及我的写作时间。但是,出于长远考虑,尤其出于窗口层面的考虑,我有选择性得删除了一些内容,旨在更清晰的表达 Activity 生命周期流程是怎么执行的,以及如何与 WMS 相关的操作,希望对各位有所帮助。