ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

瞧一瞧API30时Activity启动流程有何不同~,移动端开发技术路线

2022-01-26 19:02:04  阅读:175  来源: 互联网

标签:transaction 启动 调用 有何 开发技术 boolean Activity null final


final IBinder resultTo = request.resultTo;
// 省略其他检查代码
// 检查权限等
boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
requestCode, callingPid, callingUid, callingPackage, callingFeatureId,
request.ignoreTargetSecurity, inTask != null, callerApp, resultRecord, resultStack);
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,
callingPackage);
// 省略其他检查及设置状态代码
// 创建ActivityRecord,注意此处callerApp为 对 IApplicationThread的封装
final ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, callingFeatureId, intent, resolvedType, aInfo,
mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode,
request.componentSpecified, voiceSession != null, mSupervisor, checkedOptions,
sourceRecord);
mLastStartActivityRecord = r;
// 省略代码
mService.onStartActivitySetDidAppSwitch();
mController.doPendingActivityLaunches(false);

mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
restrictedBgActivity, intentGrants);

if (request.outActivity != null) {
request.outActivity[0] = mLastStartActivityRecord;
}

return mLastStartActivityResult;
}

executeRequest 做了基本的启动检查,创建包含IApplicationThread对象的Activity的表示类ActivityRecord(历史堆栈中的一个条目,表示一个活动),并最终调用 startActivityUnchecked() 方法,startActivityUnchecked()中主要调用 startActivityInner() 方法:

{@link com.android.server.wm.ActivityStarter}
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity, NeededUriGrants intentGrants) {
// 省略代码
// 计算是否有一个现有的任务可用于加载Activity。
final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
final boolean newTask = targetTask == null;
// 省略以下代码:
// 以下判断主要针对目标Activity
// 判断是否正在栈顶
// 判断并执行是否可以栈顶复用
// 判断并执行是否需要开启新栈
// 判断并执行是否移动到栈顶(singleTask弹栈)
// =====
// 操作目标Activity栈,启动模式、转场动画相关逻辑
mTargetStack.startActivityLocked(mStartActivity, topStack.getTopNonFinishingActivity(),
newTask, mKeepCurTransition, mOptions);
if (mDoResume) {
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
if (!mTargetStack.isTopActivityFocusable()
|| (topTaskActivity != null && topTaskActivity.isTaskOverlay()
&& mStartActivity != topTaskActivity)) {
// 如果该活动是不可调焦的,我们不能恢复它,但仍然希望确保它在开始时可见(这也将触发进入动画)。
// 这方面的一个例子是PIP活动。同样,我们不希望在一个任务中恢复当前有覆盖的活动,因为开始的活动只是需要在可见的暂停状态,直到覆盖被删除。
// 传递{@code null}作为start参数可以确保所有活动都是可见的。
mTargetStack.ensureActivitiesVisible(null /* starting /,
0 /
configChanges */, !PRESERVE_WINDOWS);
// 继续并告诉窗口管理器为这个活动执行应用程序过渡,因为应用程序过渡不会通过resume通道触发。
mTargetStack.getDisplay().mDisplayContent.executeAppTransition();
} else {
// 如果目标堆栈之前不是可调焦的(该堆栈上之前的top运行活动不可见),那么之前任何将该堆栈移动到该堆栈的调用都不会更新被调焦的堆栈。
// 如果现在启动新的活动允许任务堆栈可调焦,那么请确保我们现在相应地更新已调焦的堆栈。
if (mTargetStack.isTopActivityFocusable()
&& !mRootWindowContainer.isTopDisplayFocusedStack(mTargetStack)) {
mTargetStack.moveToFront(“startActivityInner”);
}
mRootWindowContainer.resumeFocusedStacksTopActivities(
mTargetStack, mStartActivity, mOptions);
}
}
mRootWindowContainer.updateUserStack(mStartActivity.mUserId, mTargetStack);

// 当活动启动时,立即更新最近任务列表
mSupervisor.mRecentTasks.add(mStartActivity.getTask());
mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),
mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetStack);

return START_SUCCESS;
}

由于这里代码较长,故忽略了大量代码,我们对这个方法的功能做一个简单的总结:

  • 根据当前栈的情况,判断目标Activity入栈操作:是否需要新栈,是否栈顶复用,是否弹栈等
  • 转场动画相关操作
  • 判断目标活动是否可获得焦点,执行对应操作

那么,在判断目标活动是否可获得焦点的分支里,我们启动的activity自然是需要焦点(可见可操作)的,所以我们主要关注mRootWindowContainer.resumeFocusedStacksTopActivities(mTargetStack, mStartActivity, mOptions);.

RootWindowContainer.resumeFocusedStacksTopActivities()

{@link com.android.server.wm.RootWindowContainer}
boolean resumeFocusedStacksTopActivities(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {

if (!mStackSupervisor.readyToResume()) {
return false;
}

boolean result = false;
// 如果目标在栈顶展示区域,则调用(状态模式)ResumeActivityItem执行resume操作
if (targetStack != null && (targetStack.isTopStackInDisplayArea()
|| getTopDisplayFocusedStack() == targetStack)) {
result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}

for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
// 省略展示区域相关判断及计算
if (!resumedOnDisplay) {
// 在没有有效活动的情况下(例如,设备刚刚启动或启动程序崩溃),可能什么都没有恢复显示。
// 显式地请求集中堆栈中的top活动的resume将确保至少home活动被启动和恢复,并且不会发生递归。
final ActivityStack focusedStack = display.getFocusedStack();
if (focusedStack != null) {
result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
} else if (targetStack == null) {
result |= resumeHomeActivity(null /* prev */, “no-focusable-task”,
display.getDefaultTaskDisplayArea());
}
}
}

return result;
}

观察上述代码,主要做了以下事情:

  • 如果目标已展示在栈顶可见区域,则执行resume
  • 如果不存在有效的活动(崩溃或首次启动),则启动首页
  • 如果存在有效活动(存在有焦点的栈),继续执行启动流程

此处,我们以存在有效活动为条件,继续关注启动流程,跟进resumeTopActivityUncheckedLocked();

ActivityStack.resumeTopActivityUncheckedLocked()

{@link com.android.server.wm.ActivityStack}
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mInResumeTopActivity) {
// (如果在栈顶可见),甚至不要开始递归.
return false;
}

boolean result = false;
try {
// 防止递归。
mInResumeTopActivity = true;
result = resumeTopActivityInnerLocked(prev, options);

// 当恢复top活动时,可能需要暂停top活动(例如,返回锁屏。
// 我们在{@link #resumeTopActivityUncheckedLocked}中取消了正常的暂停逻辑,因为顶部活动在结束时恢复。我们在这里再次调用{@link ActivityStackSupervisor# checkreadyforsleepplocked}来确保任何必要的暂停逻辑发生。
// 在不考虑锁屏的情况下,活动将被显示,对{@link ActivityStackSupervisor# checkreadyforsleepplocked}的调用被跳过。
final ActivityRecord next = topRunningActivity(true /* focusableOnly */);
if (next == null || !next.canTurnScreenOn()) {
checkReadyForSleep();
}
} finally {
mInResumeTopActivity = false;
}

return result;
}

观察代码,这里主要做了防止递归调用的措
施,以及调用了resumeTopActivityInnerLocked()方法,代码较长,此处将做忽略和拆解:

{@link com.android.server.wm.ActivityStack}
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
// 忽略部分判断
if (!hasRunningActivity) {
// 栈里没有活动了,我们去别的地方看看。
// 备注:注意,此处可能会出现递归调用,即会调用前面的流程:RootWindowContainer.resumeFocusedStacksTopActivities()
// 这里也是前序流程中防范递归的原因
return resumeNextFocusableActivityWhenStackIsEmpty(prev, options);
}
// 省略大量代码
// 执行栈中其他activity的pause操作
// 我们正在启动下一个活动,因此告诉窗口管理器前一个活动将很快被隐藏。这样它就可以知道在计算所需的屏幕方向时忽略它。
if (next.attachedToProcess()) {
// 更新进程信息
// 检查特殊场景,例如半透明Activity等
}else {
// 哎呀,需要重新启动这个Activity!
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else {
if (SHOW_APP_STARTING_PREVIEW) {
next.showStartingWindow(null /* prev /, false / newTask /,
false /
taskSwich */);
}
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
}
if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next);
mStackSupervisor.startSpecificActivity(next, true, true);
}

return true;
}

代码比较长,其中大部分的操作在上述代码的注释中有说明,此处不做过多关注,我们看到与startActivity()有关的代码为mStackSupervisor.startSpecificActivity(next, true, true), 我们来看一下它的作用是什么。

ActivityStackSupervisor.startSpecificActivity()

Supervisor :主管。这个类字面意思是活动栈的主管,它的作用从注释中可以了解到:

  • 将与层次结构相关的东西移动到RootWindowContainer
  • 将与活动生命周期相关的东西移动到一个新的类ActivityLifeCycler中
  • 移动接口事物到ActivityTaskManagerService。
  • 所有其他的小事情到其他文件。

void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
// Is this activity’s application already running?
// 真是个糟糕的注释,让我想起了偶尔会遇到的一个报错 ┗|`O′|┛
final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);

boolean knownToBeDead = false;
// 如果applicationThread存在,则执行真实的启动Activity
if (wpc != null && wpc.hasThread()) {
try {
realStartActivityLocked(r, wpc, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "

  • r.intent.getComponent().flattenToShortString(), e);
    }

// 如果抛出了死对象异常——重新启动应用程序。
knownToBeDead = true;
}

r.notifyUnknownVisibilityLaunchedForKeyguardTransition();

final boolean isTop = andResume && r.isTopRunningActivity();
// 若applicationThread不存在,将启动新的进程
mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? “top-activity” : “activity”);
}

上述代码中,主要做了三次校验:

  • 若目标ApplicationThread对象存在,则继续执行启动流程
  • 若启动流程执行失败,则重启应用程序
  • 若目标ApplicationThread对象不存在,则启动新的进程;此流程暂不做关注,可自行跟进,最终会调用ActivityManagerService.startProcessLocked()及后续ZygoteProcess相关方法。

ActivityStackSupervisor.realStartActivityLocked()

ActivityStackSupervisor.realStartActivityLocked()基本算得上启动流程中相当重要的一部分了,基本算得上是调用链的结束,后续将执行目标ActivityThread执行Launch操作,故单独做一小节讲述。

{@link com.android.server.wm.ActivityStackSupervisor}
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException {

if (!mRootWindowContainer.allPausedActivitiesComplete()) {
// 当有活动暂停时,我们跳过开始任何新的活动,直到暂停完成。
// 注意:对于在暂停状态下启动的活动,我们也会这样做,因为它们首先会被恢复,然后在客户端暂停。
// 思考:那么,你会担心当此启动未成功吗?可还记得。我们启动流程其实包含递归操作,如果此次中断,不代表后续就不再执行启动操作了。
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
“realStartActivityLocked: Skipping start of r=” + r

  • " some activities pausing…");
    return false;
    }

// 省略大量代码

// 因为我们可能会在系统进程中启动一个活动,所以这可能不会跨越创建新配置的绑定器接口。因此,我们必须总是在这里创建一个新的配置。

final MergedConfiguration mergedConfiguration = new MergedConfiguration(
proc.getConfiguration(), r.getMergedOverrideConfiguration());
r.setLastReportedConfiguration(mergedConfiguration);

logIfTransactionTooLarge(r.intent, r.getSavedState());

// 创建活动启动事务。
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);

final DisplayContent dc = r.getDisplay().mDisplayContent;
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode®, 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, proc.getReportedProcState(),
r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
r.assistToken, r.createFixedRotationAdjustmentsIfNeeded()));

// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);

// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);

// 再次省略大量代码
// 设置活动状态后,执行OOM评分,使流程可以更新为最新状态。
proc.onStartActivity(mService.mTopProcessState, r.info);
//如果需要,启动新版本设置屏幕。我们在启动初始化的activity(即home)之后做这个操作,这样它就有机会在后台初始化自己,使切换回它更快,看起来更好。
if (mRootWindowContainer.isTopDisplayFocusedStack(stack)) {
mService.getActivityStartController().startSetupActivity();
}

// 更新我们绑定到的任何可能关心其客户端是否有活动的服务。
if (r.app != null) {
r.app.updateServiceConnectionActivities();
}

return true;
}

从上述代码及注释我们可知,realStartActivityLocked的主要功能是:

  • 若有正在pause的活动,等待它操作完毕
  • 创建 LaunchActivityItem (启动Activity的策略/状态)并封装成事务
  • 执行启动Activity的事务
  • 更新进程信息及其他相关服务

那么,我们知道activity启动流程的最后两步即是:创建 LaunchActivityItem 及执行 ClientTransaction,这里我们分两各部分介绍,先介绍 ClientTransaction 的调用流程,再介绍 LaunchActivityItem 是什么。

执行LaunchActivityItem事务

ActivityStackSupervisor.realStartActivityLocked()中调用的mService.getLifecycleManager().scheduleTransaction(clientTransaction);实际是ClientLifecycleManager.scheduleTransaction():

{@link com.android.server.wm.ClientLifecycleManager}
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
final IApplicationThread client = transaction.getClient();
transaction.schedule();
if (!(client instanceof Binder)) {
// 如果client不是Binder的实例——它是一个远程调用,此时可以安全地回收对象。
// 在ActivityThread的客户端上执行事务后,用于本地调用的所有对象都将被回收。
transaction.recycle();
}
}

这里主要调用了ClientTransaction.schedule():

{@link android.app.servertransaction.ClientTransaction}
/** Target client. */
private IApplicationThread mClient;

public void schedule() throws RemoteException {
mClient.scheduleTransaction(this);
}

由代码可知,这里调用了IApplicationThread.scheduleTransaction()。这里的IApplicationThread来源于ClientTransaction.obtain()入参,向前追溯则是通过ActivityRecorder获取的,实际是前述启动流程中传递的caller【此处描述可能不够严谨,如有错误请评论或联系作者】。

这里我们首先应该找到 IApplicationThread的实现,如果你对ActivityThread有一定了解的话,可以知道其内部类 ApplicationThread 实现了 IApplicationThread.Stub:

{@link android.app.ActivityThread}

public final class ActivityThread extends ClientTransactionHandler {

private class ApplicationThread extends IApplicationThread.Stub {
// 忽略其他代码
@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
ActivityThread.this.scheduleTransaction(transaction);
}
}
}

public abstract class ClientTransactionHandler {

// Schedule phase related logic and handlers.

/** Prepare and schedule transaction for execution. */
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
}

class H extends Handler {

public void handleMessage(Message msg) {
switch (msg.what) {
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
if (isSystem()) {
// 系统进程内部的客户端事务在客户端循环,而不是在ClientLifecycleManager中循环,以避免在此消息被处理之前被清除。
transaction.recycle();
}
// TODO(lifecycler): Recycle locally scheduled transactions.
break;
}
}
}

那么,调用IApplicationThread.scheduleTransaction(),实际上是向ActivityThread.H发送了Message,而后ActivityThread.H处理消息并调用了mTransactionExecutor.execute(transaction):

{@link android.app.servertransaction.TransactionExecutor}
public void execute(ClientTransaction transaction) {
// 忽略代码

executeCallbacks(transaction);

executeLifecycleState(transaction);
TODO(lifecycler): Recycle locally scheduled transactions.
break;
}
}
}

那么,调用IApplicationThread.scheduleTransaction(),实际上是向ActivityThread.H发送了Message,而后ActivityThread.H处理消息并调用了mTransactionExecutor.execute(transaction):

{@link android.app.servertransaction.TransactionExecutor}
public void execute(ClientTransaction transaction) {
// 忽略代码

executeCallbacks(transaction);

executeLifecycleState(transaction);

标签:transaction,启动,调用,有何,开发技术,boolean,Activity,null,final
来源: https://blog.csdn.net/m0_65322636/article/details/122707231

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有