【Android 启动过程】Activity 启动源码分析 ( AMS -> ActivityThread、AMS 线程阶段 二 )
文章目录
- 前言
- 一、热启动与冷启动选择
- 二、AMS 进程中执行的相关操作
- 三、通过 Binder 机制转到 ActivityThread 中执行的操作
- 总结
前言
上一篇博客 【Android 启动过程】Activity 启动源码分析 ( AMS -> ActivityThread、AMS 线程阶段 ) 分析的分支是启动 Activity
时 , 没有 Activity
对应的进程 , 需要先调用 Zygote 启动相应进程 , 然后再启动 Activity , 属于冷启动 ;
本篇博客补充下 " 热启动 " 的流程 ;
一、热启动与冷启动选择
在 ActivityStackSupervisor.startSpecificActivityLocked
方法中 , 判定要启动的 Activity 是否存在 , 决定要使用冷启动还是热启动 ;
如果启动时 , 发现已经存在 Activity 对应进程 , 那么执行下面的热启动方法 :
// 如果启动 Activity 时 , 发现进程存在 , 则直接启动 Activity , 热启动realStartActivityLocked(r, app, andResume, checkConfig);
如果启动时 , 发现不存在 Activity 对应进程 , 那么执行下面的冷启动方法 :
// 如果启动 Activity 时 , 发现进程不存在 , 则启动进程, 然后再启动 Activity , 冷启动 mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,"activity", r.intent.getComponent(), false, false, true);
ActivityStackSupervisor.startSpecificActivityLocked
方法代码 :
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
相关代码如下 :
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) {// 开启新的 ActivitylifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());} else {// 终止 ActivitylifecycleItem = 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 transaction
的 schedule()
方法 ;
// 此处直接调用传入参数的 schedule 方法transaction.schedule();
ClientLifecycleManager.scheduleTransaction
方法如下 :
/*** 该类能够组合多个客户端生命周期转换请求和/或回调,并将它们作为单个事务执行。** @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 的内部类 ;
/*** 一种容器,它保存一系列消息,这些消息可以发送给客户机。这包括回调列表和最终生命周期状态。** @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
的内部类 IApplicationThread
的 scheduleTransaction
方法 ; 这样就进入到了 ActivityThread 主线程中 , 在该主线程中执行相关源码 ;
/*** 它管理应用程序进程中主线程的执行、调度和执行活动、广播以及活动管理器请求的其他操作。** {@hide}*/
public final class ActivityThread extends ClientTransactionHandler {private class ApplicationThread extends IApplicationThread.Stub {@Overridepublic 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
159159159 消息 ;
/*** 定义{@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 的热启动 ;
【Android 启动过程】Activity 启动源码分析 ( AMS -> ActivityThread、AMS 线程阶段 二 )相关推荐
- Activity启动过程——10.0源码分析
对于一个activity,注意不是根activity,它的启动流程往往是通过创建intent,通过startActivity()的方式启动的,我们跟踪的就是安卓10.0这部分的启动流程. 在windo ...
- Android shortcut的使用及源码分析
Android shortcut的使用及源码分析 最近遇到了一个切换国家码后部分应用的shortcut未更新的问题,就学习了shortcut的相关知识,在这里分享一下我了解的知识,希望能对大家有帮助. ...
- Android Q 10.1 KeyMaster源码分析(二) - 各家方案的实现
写在之前 这两篇文章是我2021年3月初看KeyMaster的笔记,本来打算等分析完KeyMaster和KeyStore以后再一起做成一系列贴出来,后来KeyStore的分析中断了,这一系列的文章就变 ...
- 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 二 )
Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...
- 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 )
Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...
- 【Android 插件化】VirtualApp 源码分析 ( 启动应用源码分析 | HomePresenterImpl 启动应用方法 | VirtualCore 启动插件应用最终方法 )
文章目录 一.启动应用源码分析 1.HomeActivity 启动应用点击方法 2.HomePresenterImpl 启动应用方法 3.VirtualCore 启动插件应用最终方法 一.启动应用源码 ...
- 详述 Spring MVC 启动流程及相关源码分析
文章目录 Web 应用部署初始化过程(Web Application Deployement) Spring MVC 启动过程 Listener 的初始化过程 Filter 的初始化 Servlet ...
- apollo源码启动服务,apollo源码分析
文章目录 1.下载APOLLO源码 2.执行Sql脚本 3.启动项目 3.1 启动ConfigServiceApplication 3.2 启动apollo-assembly 3.3 启动 apoll ...
- Android服务函数远程调用源码分析
在Android服务查询完整过程源码分析中介绍了客户进程向ServiceManager进程查询服务的完整过程,ServiceManager进程根据服务名称在自身维护的服务链表中查找ServiceMan ...
- 【Android 插件化】VirtualApp 源码分析 ( 添加应用源码分析 | LaunchpadAdapter 适配器 | 适配器添加元素 | PackageAppData 元素 )
文章目录 一.添加应用源码分析 1.LaunchpadAdapter 适配器 2.适配器添加元素 3.PackageAppData 元素 一.添加应用源码分析 1.LaunchpadAdapter 适 ...
最新文章
- 有了这个 IDEA的兄弟,你还用 Navicat 吗?全家桶不香吗?
- python3爬虫实例-python3.7简单的爬虫实例详解
- 计算机网络常见问题总结
- Spring MVC:使用基于Java的配置创建一个简单的Controller
- 微课|中学生可以这样学Python(例5.10):字符串编码与加密
- javascript 数组过滤重复对象
- Linux系统安全保护措施
- JAVA遇上HTML-----JSP 篇基本概念
- Hibernate之复合主键映射
- win10禁止自动更新
- 《期货基础知识》期权交易入门知识
- LeetCode-初级算法-有效的数独 ( java )
- 初创网络游戏公司运维遇到问题
- NBU:1651 Red packet(二分)【好】
- 基于YOLOv3的车辆号牌定位
- node联合echarts简单实现疫情地图
- 无人机巡检智能一体化解决方案
- matlab emi滤波器设计,基于Matlab-GUI的EMI滤波器设计
- 深度评测 Amazfit跃我GTR 3 Pro 和小米color 2选哪个
- 【这些题我一拿到手就会】C指针和数组试题详解(上)
热门文章
- [原] Android持续优化 - 提高流畅度
- linux常用性能分析命令详解#TOP
- 活动目录系列之十:活动目录数据库的维护
- ASP.NET 2.0 – 如何巢状化GridView控件
- Hdu 1029 Ignatius and the Princess IV
- IPC之哲学家进餐问题
- Java学习个人备忘录之线程间的通信
- [原创] 为什么模除的时候一般建议选择素数来除?比如说hashtable的桶数会取一个素数...
- Spring Boot由jar包转成war包
- 事务中SET XACT_ABORT各种用法