Android 启动过程Activity 启动源码分析 ( AMS -> ActivityThreadAMS 线程阶段 二 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 启动过程Activity 启动源码分析 ( AMS -> ActivityThreadAMS 线程阶段 二 )相关的知识,希望对你有一定的参考价值。
前言
上一篇博客 【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) {
// 开启新的 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 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 {
@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
159
159 消息 ;
/**
* 定义{@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 -> ActivityThreadAMS 线程阶段 二 )的主要内容,如果未能解决你的问题,请参考以下文章
Android 启动过程Activity 启动源码分析 ( ActivityThread -> Activity主线程阶段 一 )
Android 启动过程Activity 启动源码分析 ( AMS -> ActivityThreadAMS 线程阶段 二 )
Android 启动过程Activity 启动源码分析 ( AMS -> ActivityThreadAMS 线程阶段 )
Android 启动过程Activity 启动源码分析 ( ActivityThread -> Activity主线程阶段 二 )