前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Android 启动过程】Activity 启动源码分析 ( AMS -> ActivityThread、AMS 线程阶段 二 )

【Android 启动过程】Activity 启动源码分析 ( AMS -> ActivityThread、AMS 线程阶段 二 )

作者头像
韩曙亮
发布2023-03-29 16:57:09
1.1K0
发布2023-03-29 16:57:09
举报
文章被收录于专栏:韩曙亮的移动开发专栏

文章目录

前言

上一篇博客 【Android 启动过程】Activity 启动源码分析 ( AMS -> ActivityThread、AMS 线程阶段 ) 分析的分支是启动 Activity 时 , 没有 Activity 对应的进程 , 需要先调用 Zygote 启动相应进程 , 然后再启动 Activity , 属于冷启动 ;

本篇博客补充下 " 热启动 " 的流程 ;

一、热启动与冷启动选择


ActivityStackSupervisor.startSpecificActivityLocked 方法中 , 判定要启动的 Activity 是否存在 , 决定要使用冷启动还是热启动 ;

如果启动时 , 发现已经存在 Activity 对应进程 , 那么执行下面的热启动方法 :

代码语言:javascript
复制
				// 如果启动 Activity 时 , 发现进程存在 , 则直接启动 Activity , 热启动
                realStartActivityLocked(r, app, andResume, checkConfig);

如果启动时 , 发现不存在 Activity 对应进程 , 那么执行下面的冷启动方法 :

代码语言:javascript
复制
		// 如果启动 Activity 时 , 发现进程不存在 , 则启动进程, 然后再启动 Activity , 冷启动 
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);

ActivityStackSupervisor.startSpecificActivityLocked 方法代码 :

代码语言:javascript
复制
public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener,
        RecentTasks.Callbacks {
    void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // 此活动的应用程序是否已在运行?
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        getLaunchTimeTracker().setLaunchTime(r);

        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
                    // 如果它是一个标记为在多个进程中运行的平台组件,请不要添加此项,
                    // 因为它实际上是框架的一部分,因此在进程中作为单独的apk进行跟踪没有意义。
                    app.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode,
                            mService.mProcessStats);
                }
				
				// 如果启动 Activity 时 , 发现进程存在 , 则直接启动 Activity , 热启动
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }

            // 如果抛出了死对象异常,则通过fall-through重新启动应用程序。
        }

		// 如果启动 Activity 时 , 发现进程不存在 , 则启动进程, 然后再启动 Activity , 冷启动 
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }
}

完整代码参考 /frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java ;

二、AMS 进程中执行的相关操作


ActivityStackSupervisor.realStartActivityLocked 启动 Activity ;

最终调用 mService.getLifecycleManager().scheduleTransaction(clientTransaction) 方法 , 启动相关 Activity 启动事物 ;

ActivityStackSupervisor.realStartActivityLocked 相关代码如下 :

代码语言:javascript
复制
public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener,
        RecentTasks.Callbacks {
    final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
                                          boolean andResume, boolean checkConfig) throws RemoteException {

        if (!allPausedActivitiesComplete()) {
            // 当有活动暂停时,我们将跳过开始任何新活动,直到暂停完成。
            // 注意:对于在暂停状态下启动的活动,我们也会这样做,因为它们将首先恢复,然后在客户端暂停。
            if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
                    "realStartActivityLocked: Skipping start of r=" + r
                            + " some activities pausing...");
            return false;
        }

        final TaskRecord task = r.getTask();
        final ActivityStack stack = task.getStack();

        beginDeferResume();

        try {
            r.startFreezingScreenLocked(app, 0);

            // 安排启动时间以收集有关慢速应用程序的信息。
            r.startLaunchTickingLocked();

            r.setProcess(app);

            if (getKeyguardController().isKeyguardLocked()) {
                r.notifyUnknownVisibilityLaunched();
            }

            // 让窗口管理器根据新的活动顺序重新评估屏幕方向。
            // 注意,这样做的结果是,它可以使用新的方向调用activity manager。
            // 我们不关心这一点,因为活动当前未运行,所以我们只是重新启动它。
            if (checkConfig) {
                // 推迟恢复,因为我们将很快启动新活动。
                // 我们不希望在确保配置和尝试恢复重点堆栈的顶级活动的同时,重复启动同一记录。
                ensureVisibilityAndConfig(r, r.getDisplayId(),
                        false /* markFrozenIfConfigChanged */, true /* deferResume */);
            }

            if (r.getStack().checkKeyguardVisibility(r, true /* shouldBeVisible */,
                    true /* isTop */)) {
                // 仅当基于keyguard状态允许活动可见时,我们才将可见性设置为true。
                // 这样可以避免在窗口管理器中将此设置为运动状态,
                // 而由于以后的调用而取消该设置,以确保将可见性设置回false的可见活动。
                r.setVisibility(true);
            }

            try {

                // 下面的代码是启动 Activity 的核心代码

                // Create activity launch transaction.
                final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
                        r.appToken);
                clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                        System.identityHashCode(r), r.info,
                        // TODO: Have this take the merged configuration instead of separate global
                        // and override configs.
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                        r.persistentState, results, newIntents, mService.isNextTransitionForward(),
                        profilerInfo));

                // 设置所需的最终状态。配置生命周期
                final ActivityLifecycleItem lifecycleItem;
                if (andResume) {
                    // 开启新的 Activity
                    lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
                } else {
                    // 终止 Activity
                    lifecycleItem = PauseActivityItem.obtain();
                }
                clientTransaction.setLifecycleStateRequest(lifecycleItem);

                // 安排事务。
                mService.getLifecycleManager().scheduleTransaction(clientTransaction);

                // 上面的代码是启动 Activity 的核心代码


            } catch (RemoteException e) {
            }
        } finally {
            endDeferResume();
        }

        return true;

    }
}

完整代码参考 /frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java ;

mService.getLifecycleManager().scheduleTransaction(clientTransaction) 中调用了 ClientLifecycleManager.scheduleTransaction , 在该方法中调用了传入参数 ClientTransaction transactionschedule() 方法 ;

代码语言:javascript
复制
        // 此处直接调用传入参数的 schedule 方法
        transaction.schedule();

ClientLifecycleManager.scheduleTransaction 方法如下 :

代码语言:javascript
复制
/**
 * 该类能够组合多个客户端生命周期转换请求和/或回调,并将它们作为单个事务执行。
 *
 * @see ClientTransaction
 */
class ClientLifecycleManager {
    /**
     * 安排一个事务,该事务可能包括多个回调和一个生命周期请求。
     * @param transaction 客户端事务项的序列。
     * @throws RemoteException
     *
     * @see ClientTransaction
     */
    void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        final IApplicationThread client = transaction.getClient();
        // 此处直接调用传入参数的 schedule 方法
        transaction.schedule();
        if (!(client instanceof Binder)) {
            // 如果客户机不是Binder的实例,则它是一个远程调用,
            // 此时可以安全地回收该对象。
            // 在ActivityThread中的客户端上执行事务后,将回收用于本地调用的所有对象。
            transaction.recycle();
        }
    }
}

完整代码参考 /frameworks/base/services/core/java/com/android/server/am/ClientLifecycleManager.java ;

调用的是 IApplicationThread mClient 成员的 scheduleTransaction 方法 , 该成员类型 IApplicationThread 是 ActivityThread 的内部类 ;

代码语言:javascript
复制
/**
 * 一种容器,它保存一系列消息,这些消息可以发送给客户机。这包括回调列表和最终生命周期状态。
 *
 * @see com.android.server.am.ClientLifecycleManager
 * @see ClientTransactionItem
 * @see ActivityLifecycleItem
 * @hide
 */
public class ClientTransaction implements Parcelable, ObjectPoolItem {
    /** Target client. */
    private IApplicationThread mClient;
    /**
     * 在事务初始化后安排事务。它将发送给客户,其所有单独部分将按以下顺序应用:
     * 1. 客户端调用{@link#preExecute(ClientTransactionHandler)},
     *      这将触发在实际调度回调和生命周期状态请求的事务之前需要完成的所有工作。
     * 2. 已计划事务消息。
     * 3. 客户端调用{@link TransactionExecutor#execute(ClientTransaction)},
     *      它执行所有回调和必要的生命周期转换。
     */
    public void schedule() throws RemoteException {
        mClient.scheduleTransaction(this);
    }
}

完整代码参考 /frameworks/base/core/java/android/app/servertransaction/ClientTransaction.java ;

三、通过 Binder 机制转到 ActivityThread 中执行的操作


通过 Binder 机制 , 调用 ActivityThread 的内部类 IApplicationThreadscheduleTransaction 方法 ; 这样就进入到了 ActivityThread 主线程中 , 在该主线程中执行相关源码 ;

代码语言:javascript
复制
/**
 * 它管理应用程序进程中主线程的执行、调度和执行活动、广播以及活动管理器请求的其他操作。
 *
 * {@hide}
 */
public final class ActivityThread extends ClientTransactionHandler {
    private class ApplicationThread extends IApplicationThread.Stub {
        @Override
        public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
            ActivityThread.this.scheduleTransaction(transaction);
        }
    }
}

完整代码参考 /frameworks/base/core/java/android/app/ActivityThread.java ;

上述方法最终执行的是 ActivityThread.this.scheduleTransaction(transaction) , ActivityThread 继承了 ClientTransactionHandler 方法 ,

ClientTransactionHandler 中定义的 scheduleTransaction 方法中 , 主要是发出了 ActivityThread.H.EXECUTE_TRANSACTION

159

消息 ;

代码语言:javascript
复制
/**
 * 定义{@link android.app.servertransaction.ClientTransaction}或其项可以在客户端上执行的操作。
 * @hide
 */
public abstract class ClientTransactionHandler {

    // 安排与阶段相关的逻辑和处理程序。

    /** 准备并安排事物执行。 */
    void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
    }

}

完整代码参考 /frameworks/base/core/java/android/app/ClientTransactionHandler.java ;


总结

本博客分析的源码对应分支 AMS -> ActivityThread ( ApplicationThread ) 分支 , Activity 的热启动 ;

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-09-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 前言
  • 一、热启动与冷启动选择
  • 二、AMS 进程中执行的相关操作
  • 三、通过 Binder 机制转到 ActivityThread 中执行的操作
  • 总结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档