公司网站要备案么,wordpress 幻灯代码,报告查一查,网页设计需要学什么软件忽然有一天#xff0c;我想要做一件事#xff1a;去代码中去验证那些曾经被“灌输”的理论。 – 服装… 忽然有一天我想要做一件事去代码中去验证那些曾经被“灌输”的理论。 – 服装学院的IT男 本篇已收录于Activity短暂的一生系列 欢迎一起学习讨论Android应用开发或者WMS VWJB6995 Q707409815 正文
由于篇幅原因整个启动流程分为以下3篇进行分析
Activity启动流程-1
Activity启动流程-2
Activity启动流程-3
Activity 的启动流程无论是 APP 开发还是 FrameWork 开发都是必须要熟悉的一个流程。
FrameWork 中有很多重要的流程都是在 Activity 启动过程中触发的不过当前还是以分析 Activity 启动主流程为主当然对于一些关键方法还是会着重介绍这样以后如果有遇到相关问题的修改可以通过这篇文章找到具体代码位置然后根据具体的问题分析修改。
启动 Activity 的方式有很多当前以在 Launcher 点击“电话”图标启动应用场景进行分析。
1. 整体介绍
1.1 一级框图 对于Activity的启动流程来说可以分为3个模块
SourceActivity执行 startActivity 方法的 Activity 也就是发起请求的Activity 当前是 Launcher 的 Activity 。
TargetActivity被启动的 Activity 当前就是“电话”应用在清单文件配置的MainActivity
AMS: 不仅仅是指 AMS 这一个类而是指在这个过程中 system_service 进程参与处理的相关类
举个例子以在公司的工作流程来说 Launcher 模块的开发在处理一个 bug但是涉及到了通话那么他需要找到通讯组的同事来处理这个问题。但公司很大他并不知道通讯模块是谁负责更不知道这个问题需要交给通讯组具体的哪个同事处理那么他只需要将自己的要求向公司领导管理着汇报需要通讯组的同事处理这个问题。
当前例子设计到 launcher 和通讯2个模块的开发人员还涉及到公司的管理者。在Activity 启动也是如此 对于 SourceActivity、TargetActivity 来说他们并不知道对方模块的业务所以这一流程需要AMS来做管理。
并且这3个模块也对应3个进程当前案例来说分别为Launcher 进程电话进程system_service 进程。 图中AMS 对 Launcher 多了一个返回箭头的原因是 Launcher 肯定是需要执行 pause 的但执行 pause 的时机 Launcher 自身无法控制只能由 AMS 控制。 1.2 总体流程 这里有4个阶段以4个颜色表示同时还涉及到3个进程。
第一阶段 由 Launcher 进程发起启动 Activity 的请求 AMS 处理创建对应的 ActivityRecord 和 Task 并挂载到窗口层级树中 AMS 触发 Launcher 的 pause 流程 AMS 触发电话应用进程的创建
第二阶段 Launcher 执行完 pause pause 流程完成后触发 AMS 启动 TargetActivity
第三阶段 创建应用进程 应用进程创建好后会向 AMS 进行绑定并触发 AMS 启动 TargetActivity
第四阶段 AMS 触发 realStartActivityLocked 方法试图应用启动 Activity 如果还有 Activity 没有执行完 pause 逻辑则 realStartActivityLocked 会 return 如果应用 Activity 都执行完了 pause 则触发 TargetActivity 的启动并将生命周期会执行到 onResume
注意其中第23阶段几乎是同时开始的并且 ASM 通知 Launcher 执行 pause 和通过 Zygote 创建进程是异步操作不知道各自执行的顺序。
但是看的出来最终都是会执行到 realStartActivityLocked 方法来试图启动 TargetActivity 为什么说是“试图启动”启动呢
一共就有2种可能: completePause 先执行完 进程先创建完
假设第一种情况 Launcher 先执行完 completePause 来到 ActivityTaskSupervisor::startSpecificActivity 方法这个时候进程还没创建完毕则不会执行 ActivityTaskSupervisor::realStartActivityLocked 而是会再触发进程创建当然之前已经触发过来这次触发不会真的再创建进行了。
然后会由阶段三的流程创建好进程走到 ActivityTaskSupervisor::realStartActivityLocked 在这个方法里会判断是不是执行完 pause 了那当前这个情况肯定是满足的 所以会触发启动 TargetActivity 。
假设第二种情况 阶段三创建进程先执行完走到 ActivityTaskSupervisor::realStartActivityLocked 方法但是发现 pause 还没执行玩所以就 return 了。 然后等 completePause 流程来到 ActivityTaskSupervisor::startSpecificActivity 方法时这次发现进程已经创建好了则一次执行后续逻辑触发启动 TargetActivity 。
也就是说不管阶段二三谁先执行完都会试图启动 TargetActivity 而成功启动必须有2个条件 进程创建完毕 launcher执行完pause
也就说说这2个阶段后执行过来的流程才能正式启动 TargetActivity 。
2. 阶段一桌面点击图标启动应用
2.1 流程概览
这一阶段调用比较简单堆栈如下 整理后如下
ItemClickHandler::onClickItemClickHandler::onClickAppShortcutItemClickHandler::startAppShortcutOrInfoActivityQuickstepLauncher::startActivitySafelyLauncher::startActivitySafelyAppLauncher::startActivitySafelyBaseQuickstepLauncher::getActivityLaunchOptions -- 构建 Option 参数Activity::startActivity -- 共用启动Activity流程Activity::startActivityActivity::startActivityActivity::startActivityForResultInstrumentation::execStartActivityActivityTaskManagerService::startActivity -- 跨进程画成时序图
其实我们正常通过 startActivity 传递 Intent 启动 Activity 的流程也是一样的最终都会调到 Instrumentation::execStartActivity 然后开始跨进程与 AMS 通信。 只不过这边多了一些 Launcher 自己的处理这边只需要对 BaseQuickstepLauncher::getActivityLaunchOptions 有个印象即可这个方法会构建 ActivityOptions 对象包含了一些启动参数比如远端动画的 RemoteAnimationAdapter 。
前面的流程就不看了执行从 Activity::startActivityForResult 开始看代码流程。
2.2 SourceActivity 端处理
SourceActivity 发起启动 Activity 的逻辑相对简单无论哪种参数的 Activity::startActivity 方法最终都是调到 Activity::startActivityForResult 方法。 然后在 Instrumentation 最后的处理最后跨进程传递到 system_service 进程中。
# Activity.javapublic void startActivityForResult(RequiresPermission Intent intent, int requestCode,Nullable Bundle options) {if (mParent null) {options transferSpringboardActivityOptions(options);Instrumentation.ActivityResult ar mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);......}......}
# Instrumentation.javapublic ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {......// 当前应用进程处理结束开始传递给 ActivityTaskManagerServiceint result ActivityTaskManager.getService().startActivity(whoThread,who.getOpPackageName(), who.getAttributionTag(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()), token,target ! null ? target.mEmbeddedID : null, requestCode, 0, null, options);// 对跨进程启动的结果做checkcheckStartActivityResult(result, intent);......}Instrumentation::checkStartActivityResult 这个方法有一些常见的报错比如常见的未在 AndroidManifest.xml 注册 Activity 的报错就在这。
# Instrumentationpublic static void checkStartActivityResult(int res, Object intent) {if (!ActivityManager.isStartResultFatalError(res)) {return;}switch (res) {case ActivityManager.START_INTENT_NOT_RESOLVED:case ActivityManager.START_CLASS_NOT_FOUND: // 未在AndroidManifest.xml注册if (intent instanceof Intent ((Intent)intent).getComponent() ! null)throw new ActivityNotFoundException(Unable to find explicit activity class ((Intent)intent).getComponent().toShortString() ; have you declared this activity in your AndroidManifest.xml , or does your intent not match its declared intent-filter?);throw new ActivityNotFoundException(No Activity found to handle intent);case ActivityManager.START_PERMISSION_DENIED:throw new SecurityException(Not allowed to start activity intent);case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:throw new AndroidRuntimeException(FORWARD_RESULT_FLAG used while also requesting a result);case ActivityManager.START_NOT_ACTIVITY:throw new IllegalArgumentException(PendingIntent is not an activity);case ActivityManager.START_NOT_VOICE_COMPATIBLE:throw new SecurityException(Starting under voice control not allowed for: intent);case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION:throw new IllegalStateException(Session calling startVoiceActivity does not match active session);case ActivityManager.START_VOICE_HIDDEN_SESSION:throw new IllegalStateException(Cannot start voice activity on a hidden session);case ActivityManager.START_ASSISTANT_NOT_ACTIVE_SESSION:throw new IllegalStateException(Session calling startAssistantActivity does not match active session);case ActivityManager.START_ASSISTANT_HIDDEN_SESSION:throw new IllegalStateException(Cannot start assistant activity on a hidden session);case ActivityManager.START_CANCELED:throw new AndroidRuntimeException(Activity could not be started for intent);default:throw new AndroidRuntimeException(Unknown error code res when starting intent);}}3. 阶段一 : system_service 处理
3.1 流程概述
对于 system_service 来说它收到了启动 Activity 的请求那么它要做的就是启动 TargetActivity 。
要实现这个目的我整理了大概要做以下几件事 解析请求参数 想要启动 Activity 最起码得知道具体是哪个 Activity 吧当然还有其他很多参数比如是谁发起的请求requestCode等等这些参数都是应用端带过来的。system_service 的第一件事肯定是解析这些参数这些参数将被解析存放在一个叫 Request 对象中。 处理窗口层级树相关逻辑 虽然是启动 Activity 但是肯定涉及到窗口操作所以这一步也是必须的 触发 SourceActivity 执行pause 逻辑 需要显示新的 TargetActivity 那之前的 SourceActivity 肯定要执行 pause 逻辑的 触发创建进程 当前场景是冷启动那启动 TargetActivity 前必须要保证其所在的进程已经存在
在 Instrumentation::execStartActivity 里就开始触发跨进程通信了剩下的逻辑就在 system_service 进程中执行了。
这部分缩略版的的调用链如下
ActivityTaskManagerService::startActivityActivityTaskManagerService::startActivityAsUserActivityTaskManagerService::startActivityAsUserActivityStartController::obtainStarterActivityStarter::executeActivityStarter$Request::resolveActivity -- 解析启动请求参数ActivityStarter::executeRequest -- 3.3 创建ActivityRecordActivityStarter::startActivityUncheckedActivityStarter::startActivityInner -- 3.4 关键函数startActivityInnerActivityStarter::getOrCreateRootTask -- 3.4.1 创建或者拿到Task ActivityStarter::setNewTask -- 3.4.2 将Task与activityRecord 绑定Task::moveToFront --3.4.3 移动Task到栈顶RootWindowContainer::resumeFocusedTasksTopActivities --3.4.4 显示ActivityTask::resumeTopActivityUncheckedLockedTask::resumeTopActivityInnerLockedTaskFragment::resumeTopActivity -- 显示顶层ActivityTaskDisplayArea::pauseBackTasks -- pause LauncherActivity ActivityTaskManagerService::startProcessAsync -- 创建“电话”进程时序图
流程来到 ActivityTaskManagerService::startActivity 经过2次简单的跳转会执行 ActivityTaskManagerService::startActivityAsUser 方法。 这个方法比较重要在这里会构建一个 ActivityStartController 根据类名可以知道这个类是控制 Activity 启动。
3.2 启动请求参数的构建
代码如下
# ActivityTaskManagerServiceprivate int startActivityAsUser(IApplicationThread caller, String callingPackage,Nullable String callingFeatureId, Intent intent, String resolvedType,IBinder resultTo, String resultWho, int requestCode, int startFlags,ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {......// 返回的是ActivityStartControllerreturn getActivityStartController().obtainStarter(intent, startActivityAsUser).setCaller(caller).setCallingPackage(callingPackage).setCallingFeatureId(callingFeatureId).setResolvedType(resolvedType).setResultTo(resultTo).setResultWho(resultWho).setRequestCode(requestCode).setStartFlags(startFlags).setProfilerInfo(profilerInfo).setActivityOptions(bOptions).setUserId(userId).execute();}ActivityStartController getActivityStartController() {return mActivityStartController;}ActivityStartController::obtainStarter 返回的是 ActivityStarter 对象。
而 ActivityStarter 这个类名看着就是处理启动 Activity 的一个类它做的是就是解析调用者传递的参数构建出一个 Request 然后开始执行后续的启动 Activity 逻辑。
# ActivityStartController// 返回ActivityStarterActivityStarter obtainStarter(Intent intent, String reason) {return mFactory.obtain().setIntent(intent).setReason(reason);}所以在 ActivityTaskManagerService::startActivityAsUser 方法中的 build 模式其实是对 ActivityStarter 对象做构建最终调用其 execute 方法。 在内容最终执行了 ActivityStarter::executeRequest 方法下面只以 setCallingPackage 这一个方法看一下是怎么把参数设置到 Request 中的。
# ActivityStarter// 启动Activity的请求Request mRequest new Request();// 设置调用者包名ActivityStarter setCallingPackage(String callingPackage) {mRequest.callingPackage callingPackage;return this;}// 设置ActivityInfoActivityStarter setActivityInfo(ActivityInfo info) {mRequest.activityInfo info;return this;}int execute() {......// 如果 mRequest 中没有 Activity 相关信息if (mRequest.activityInfo null) {// 解析请求数据mRequest.resolveActivity(mSupervisor);}......// 执行启动Activity请求res executeRequest(mRequest);......}build 模式会把参数设置到 mRequest 中但是并没有看到调用 ActivityStarter::setActivityInfo 所以在执行 ActivityStarter::execute 的时候 “mRequest.activityInfo”是 null 。 所以这里又分2步 解析获取 activityInfo 执行后续启动逻辑
3.2.1 activityInfo 的解析
ActivityStarter$RequestResolveInfo resolveInfo;ActivityInfo activityInfo;void resolveActivity(ActivityTaskSupervisor supervisor) {......// 解析resolveInforesolveInfo supervisor.resolveIntent(intent, resolvedType, userId,0 /* matchFlags */,computeResolveFilterUid(callingUid, realCallingUid, filterCallingUid),realCallingPid);......// 解析activityInfo activityInfo supervisor.resolveActivity(intent, resolveInfo, startFlags,profilerInfo);......}TargetActivity 所在的进程包名和 TargetActivity 的完整路径都在 activityInfo 中这个解析方法也是一个核心点当前分析主流程就不细看了。 现在 mRequest 中就包含了启动 TargetActivity 的所有数据就可以继续后面的启动流程了。
3.3 创建ActivityRecord
ActivityStarter::executeRequest 是一个需要注意的方法因为内部会创建 ActivityRecord 对象而这个 ActivityRecord 对象持有 token 这个 token 就是以后分析其他逻辑一直会出现的 token 。也可以说是 system_service 中一个 Activity 的唯一标识。
应用进程中的 Activity 在 AMS 的代表就是 ActivityRecord 。
# ActivityStarterprivate int executeRequest(Request request) {......// 包名在这ActivityInfo aInfo request.activityInfo;ResolveInfo rInfo request.resolveInfo;......if (err ActivityManager.START_SUCCESS) {// 重点* 1. 打印创建 ActivityRecord 日志request.logMessage.append(START u).append(userId).append( {).append(intent.toShortString(true, true, true, false)).append(} with ).append(launchModeToString(launchMode)).append( from uid ).append(callingUid);if (callingUid ! realCallingUid realCallingUid ! Request.DEFAULT_REAL_CALLING_UID) {request.logMessage.append( (realCallingUid).append(realCallingUid).append());}}......// 重点* 2. 构造出一个ActivityRecordfinal ActivityRecord r new ActivityRecord.Builder(mService).setCaller(callerApp).setLaunchedFromPid(callingPid).setLaunchedFromUid(callingUid).setLaunchedFromPackage(callingPackage).setLaunchedFromFeature(callingFeatureId).setIntent(intent).setResolvedType(resolvedType).setActivityInfo(aInfo).setConfiguration(mService.getGlobalConfiguration()).setResultTo(resultRecord).setResultWho(resultWho).setRequestCode(requestCode).setComponentSpecified(request.componentSpecified).setRootVoiceInteraction(voiceSession ! null).setActivityOptions(checkedOptions).setSourceRecord(sourceRecord).build();......// 重点* 3. 继续执行startActivityUncheckedmLastStartActivityResult startActivityUnchecked(r, sourceRecord, voiceSession,request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,inTask, inTaskFragment, restrictedBgActivity, intentGrants);......}3个注意点 虽然是个日志但是也很关键一般分析日志看启动了哪个 Activity 就搜“START u” 打印的地方就在这。另外发现 U 版本上这一块还做了改变。 构建出一个 ActivityRecord 对象 继续主流程 主要看第二点 ActivityRecord 是怎么创建的。
# ActivityRecordprivate ActivityRecord(ActivityTaskManagerService _service, ......) {// 调用父类创建 Tokensuper(_service.mWindowManager, new Token(), TYPE_APPLICATION, true,null /* displayContent */, false /* ownerCanManageAppTokens */);......packageName info.applicationInfo.packageName;.....}这里的重点其实就是创建了一个匿名 Token 然后传递到了父类的构建方法 ActivityRecord 的父类是 WindowToken 。
# WindowTokenprotected WindowToken(WindowManagerService service, IBinder _token, int type,boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens) {this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens,false /* roundedCornerOverlay */, false /* fromClientToken */, null /* options */);}protected WindowToken(WindowManagerService service, IBinder _token, int type,boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens,boolean roundedCornerOverlay, boolean fromClientToken, Nullable Bundle options) {super(service);// token 赋值token _token;windowType type;mOptions options;......if (dc ! null) {// 挂载到窗口树dc.addWindowToken(token, this);}}将 ActivityRecord 创建的匿名 保存在了 token 对象这个 token 就是 Activity 在 system_service 里唯一标识符。 普通的 WindowToken 在这里会挂载的窗口层级树但是 DisplayContent::addWindowToken 方法内部对 ActivityRecord 做了判断。也就是说 ActivityRecord 刚创建好后是不会挂载到窗口树上的当前流程后面是要介绍 ActivityRecord 是怎么挂载到层级树上的。 ActivityRecord 创建好后继续走主流程根据前面的分析下一步是执行 ActivityStarter::startActivityUnchecked 不过这个方法也没做啥主要是调用了 ActivityStarter::startActivityInner 这个方法是流程的关键点。
3.4 窗口层级树处理
ActivityStarter::startActivityInner 是 Activity 启动流程最重要的函数之一这里涉及到【窗口层级树】相关知识上一小节说了 ActivityRecord 创建好后并不会和 WindowToken 一样挂载到层级树中而是需要单独处理本小节就是看这一块是如何处理的。
先看看正常在 Launcher 界面时和启动“电话”后的层级树对比。 这里首先多了3个东西 Task 上一步创建的 ActivityRecord WindowState。
另外这个 Task 还移动到了DefaultTaskDisplayArea的最顶部,这里涉及到的操作如下 创建 Task ActivityRecord 挂在到这个 Task 下 将这个 Task 移动到最上面
至于最下面的那个 546fce2 为什么是 WindowState 对象又是怎么挂在到 ActivityRecord 上的这个属于窗口显示第一步-addWindow流程当前就不单独分析了。
继续看主流程代码
# ActivityStarter// The task that the last activity was started into. We currently reset the actual start// activitys task and as a result may not have a reference to the task in all casesprivate Task mTargetTask;int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,int startFlags, boolean doResume, ActivityOptions options, Task inTask,TaskFragment inTaskFragment, boolean restrictedBgActivity,NeededUriGrants intentGrants) {......// computeTargetTask内部会根据具体条件返回Task比如标志位FLAG_ACTIVITY_NEW_TASK 就需要重新创建Task // 这里reusedTask为 null因为是新启动的应用所以computeTargetTask也找不到task最终也为nullfinal Task targetTask reusedTask ! null ? reusedTask : computeTargetTask();// 那么newTask为true 表示需要新建一个taskfinal boolean newTask targetTask null;// 同样为nullmTargetTask targetTask;......if (mTargetRootTask null) {// 重点* 1. 创建Task 23mTargetRootTask getOrCreateRootTask(mStartActivity, mLaunchFlags, targetTask,mOptions);}if (newTask) {// taskToAffiliate 为nullfinal Task taskToAffiliate (mLaunchTaskBehind mSourceRecord ! null)? mSourceRecord.getTask() : null;// 重点* 2. 将需要启动的ActivityRecord与 新创建的Task 进行绑定setNewTask(taskToAffiliate);} else if (mAddingToTask) {addOrReparentStartingActivity(targetTask, adding to task);}if (!mAvoidMoveToFront mDoResume) {// 重点* 3. 移动到栈顶 mTargetRootTask.getRootTask().moveToFront(reuseOrNewTask, targetTask);......}......if (mDoResume) {......// 重点*4. task 处理完后需要将task顶部的Activity显示resume // mTransientLaunch 一般为默认值 falsemRootWindowContainer.resumeFocusedTasksTopActivities(mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);}......}创建 Task 我们知道 ActivityRecord 需要挂载到一个 Task 下虽然这里调用的方法名是 getOrCreateRootTask获取或者创建Task但是当前场景肯定是创建一个热启动是获取。另外 Task 创建的时候就会挂载到层级树中也就是会挂载到DefaultTaskDisplayArea 下 将 ActivityRecord 挂载到创建的 Task 下 上一小节没做的事在这里就完成了挂载 移动 Task 到栈顶 因为这个新启动的 Activity 需要显示所以需要将它所在的 Task 移到容器顶部。 不过当前场景建好就已经是栈顶了其实这一步没做什么这点后面代码会分析 显示顶部的 Activity 窗口层级的处理好了就可以处理显示逻辑了这里后续的逻辑会触发 Activity 的启动
3.4.1 获取Task–getOrCreateRootTask
调用链
ActivityStarter::getOrCreateRootTaskRootWindowContainer::getOrCreateRootTaskRootWindowContainer::getOrCreateRootTaskTaskDisplayArea::getOrCreateRootTaskTaskDisplayArea::getOrCreateRootTaskTask::Build ---创建Task开始看代码
# ActivityStarterprivate Task getOrCreateRootTask(ActivityRecord r, int launchFlags, Task task,ActivityOptions aOptions) {final boolean onTop (aOptions null || !aOptions.getAvoidMoveToFront()) !mLaunchTaskBehind;final Task sourceTask mSourceRecord ! null ? mSourceRecord.getTask() : null;return mRootWindowContainer.getOrCreateRootTask(r, aOptions, task, sourceTask, onTop,mLaunchParams, launchFlags);} onTop 表示是否要移到到当前栈顶那肯定是要的新启动的 Activity 当前要在最上面这里 aOptions 为 null 所以为 true sourceTask 表示从哪里启动的当前 Launcher 所在的 Task 就是 sourceTask
然后开始获取一个 Task 如果没有就新建一个。
# RootWindowContainerTask getOrCreateRootTask(Nullable ActivityRecord r, Nullable ActivityOptions options,Nullable Task candidateTask, boolean onTop) {return getOrCreateRootTask(r, options, candidateTask, null /* sourceTask */, onTop,null /* launchParams */, 0 /* launchFlags */);}Task getOrCreateRootTask(Nullable ActivityRecord r,Nullable ActivityOptions options, Nullable Task candidateTask,Nullable Task sourceTask, boolean onTop,Nullable LaunchParamsController.LaunchParams launchParams, int launchFlags) {......final int activityType resolveActivityType(r, options, candidateTask);if (taskDisplayArea ! null) {if (canLaunchOnDisplay(r, taskDisplayArea.getDisplayId())) {// 重点*1. 传递到TaskDisplayAreareturn taskDisplayArea.getOrCreateRootTask(r, options, candidateTask,sourceTask, launchParams, launchFlags, activityType, onTop);} else {taskDisplayArea null;}}......}经过同名方法调用后逻辑进入到 TaskDisplayArea::getOrCreateRootTask 。
# TaskDisplayAreaTask getOrCreateRootTask(int windowingMode, int activityType, boolean onTop,Nullable Task candidateTask, Nullable Task sourceTask,Nullable ActivityOptions options, int launchFlags) {if(....) {// 拿到之前创建的Taskreturn candidateTask.getRootTask();}......// 第一次显示所以是新建Taskreturn new Task.Builder(mAtmService).setWindowingMode(windowingMode).setActivityType(activityType).setOnTop(onTop).setParent(this) // 主要这个this被设置为Parent。所以直接挂载到了DefaultTaskDisplayArea下.setSourceTask(sourceTask).setActivityOptions(options).setLaunchFlags(launchFlags).build();}看方法名是获取或创建 Task 当前流程是新启动的 Activity 所以需要创建 Task 。如果是以默认启动方式打开应用内的另一个 Activity 就走的是上面的 “return candidateTask.getRootTask();” 设置的 parent 就是层级结构树应用所在的名为“DefaultTaskDisplayArea”的 TaskDisplayArea 接下来就是真正触发Task的创建。
# Task# Task.BuilderTask build() {if (mParent ! null mParent instanceof TaskDisplayArea) {validateRootTask((TaskDisplayArea) mParent);}......// 重点* 1. 创建taskfinal Task task buildInner();task.mHasBeenVisible mHasBeenVisible;// Set activity type before adding the root task to TaskDisplayArea, so home task can// be cached, see TaskDisplayArea#addRootTaskReferenceIfNeeded().if (mActivityType ! ACTIVITY_TYPE_UNDEFINED) {task.setActivityType(mActivityType);}// 重点* 2. 入栈 这里的 mOnTop 为trueif (mParent ! null) {if (mParent instanceof Task) {final Task parentTask (Task) mParent;parentTask.addChild(task, mOnTop ? POSITION_TOP : POSITION_BOTTOM,(mActivityInfo.flags FLAG_SHOW_FOR_ALL_USERS) ! 0);} else {mParent.addChild(task, mOnTop ? POSITION_TOP : POSITION_BOTTOM);}}// Set windowing mode after attached to display area or it abort silently.if (mWindowingMode ! WINDOWING_MODE_UNDEFINED) {task.setWindowingMode(mWindowingMode, true /* creating */);}// 返回return task;}// 创建Task buildInner() {return new Task(mAtmService, mTaskId, mIntent, mAffinityIntent, mAffinity,mRootAffinity, mRealActivity, mOrigActivity, mRootWasReset, mAutoRemoveRecents,mAskedCompatMode, mUserId, mEffectiveUid, mLastDescription, mLastTimeMoved,mNeverRelinquishIdentity, mLastTaskDescription, mLastSnapshotData,mTaskAffiliation, mPrevAffiliateTaskId, mNextAffiliateTaskId, mCallingUid,mCallingPackage, mCallingFeatureId, mResizeMode, mSupportsPictureInPicture,mRealActivitySuspended, mUserSetupComplete, mMinWidth, mMinHeight,mActivityInfo, mVoiceSession, mVoiceInteractor, mCreatedByOrganizer,mLaunchCookie, mDeferTaskAppear, mRemoveWithTaskOrganizer);}3.4.1.1 小结
最后描述一下最后创建的2个重点部分 看到通过 buildInner 创建了一个 Task而 buildInner 也很简单粗暴通过各个变量直接 new 出一个 Task 对象。 mParent 不为 null 是因为在创建的时候 setParentthis,当前的这个 this 就是 getDefaultTaskDisplayArea 返回的。就是 37层的第二层应用 Activity 存在的DefaultTaskDisplayArea
在 RootWindowContainer::getOrCreateRootTask 体现。 注意 log 里的 #17 的这个 Task 与前面的层级结构树新增的 Task 是对应的上的。而且this DefaultTaskDisplayArea 说明也确实是往 DefaultTaskDisplayArea 里添加了。 另外 log 里 index 为3结合最上面的前后对比说明也的往顶部添加。
3.4.2 ActivityRecord挂载到Task–setNewTask
调用链 ActivityStarter::setNewTaskActivityStarer::addOrReparentStartingActivity
主流程代码
# ActivityStarerprivate void setNewTask(Task taskToAffiliate) {// 为truefinal boolean toTop !mLaunchTaskBehind !mAvoidMoveToFront;// 就是mTargetRootTask,也就是刚刚创建的Taskfinal Task task mTargetRootTask.reuseOrCreateTask(mNewTaskInfo ! null ? mNewTaskInfo : mStartActivity.info,mNewTaskIntent ! null ? mNewTaskIntent : mIntent, mVoiceSession,mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);task.mTransitionController.collectExistenceChange(task);// ActivityRecord的挂载addOrReparentStartingActivity(task, setTaskFromReuseOrCreateNewTask);// 需要注意这里的日志打印ProtoLog.v(WM_DEBUG_TASKS, Starting new activity %s in new task %s,mStartActivity, mStartActivity.getTask());// mLaunchTaskBehind 为false所以taskToAffiliate 为null if (taskToAffiliate ! null) {mStartActivity.setTaskToAffiliateWith(taskToAffiliate);}}这里的 Task 和 mTargetRootTask 是同一个对象然后进入 ActivityStarer::addOrReparentStartingActivity 。
# ActivityStarerprivate void addOrReparentStartingActivity(NonNull Task task, String reason) {// newParent task 都是刚刚创建的TaskTaskFragment newParent task;......if (mStartActivity.getTaskFragment() null|| mStartActivity.getTaskFragment() newParent) {// 重点 将 ActivityRecord挂在到新创建的Task中并且是顶部newParent.addChild(mStartActivity, POSITION_TOP);} else {mStartActivity.reparent(newParent, newParent.getChildCount() /* top */, reason);}}这里的逻辑涉及到的 Task 就是上一步创建的 Task 而 mStartActivity 则是“电话”在之前逻辑创建的 ActivityRecord 。
setNewTask的堆栈信息如下 另外这段逻辑里有个 ProtoLog 打印日志如下 3.4.2.1 小结
结合逻辑分析 堆栈信息 ProtoLog 可以确认 ActivityStarer::setNewTask 做的事情就是将 ActivityRecord 挂在到 Task 中而且在顶部。
3.4.3 移动Task到容器顶部–moveToFront
这里提一下这个 moveToFront 方法因为前面创建 Task 并添加到 DefaultTaskDisplayArea 时是往顶部添加后面将 ActivityRecord 挂在到 Task 也是挂在到其顶部。所以这个函数其实没有什么实际操作。但是对于其他场景这里也是一个重点方法。
调用链
Task::moveToFrontTask::moveToFrontInnerTaskDisplayArea::positionChildAtTaskDisplayArea::positionChildTaskAtActivityTaskSupervisor::updateTopResumedActivityIfNeededActivityRecord::onTopResumedActivityChanged --触发TopResumedActivityChangeItem主流程代码
首先确定一个问题需要移动到顶部的是哪个 Task 这个 Task 所在的是在哪个哪个容器 在 ActivityStarter::startActivityInner 的时候调用的是这段代码
// targetTask 当前场景为null
mTargetRootTask.getRootTask().moveToFront(reuseOrNewTask, targetTask);已知 mTargetRootTask 是新创建给“电话”用的 Task, 而 mTargetRootTask.getRootTask() 返回值当前场景是 mTargetRootTask 本身。
# Taskvoid moveToFront(String reason, Task task) {if (!isAttached()) {return;}mTransitionController.recordTaskOrder(this);final TaskDisplayArea taskDisplayArea getDisplayArea();if (!isActivityTypeHome() returnsToHomeRootTask()) {// Make sure the root home task is behind this root task since that is where we// should return to when this root task is no longer visible.taskDisplayArea.moveHomeRootTaskToFront(reason returnToHome);}final Task lastFocusedTask isRootTask() ? taskDisplayArea.getFocusedRootTask() : null;if (task null) {// 当前场景为null所以会赋值成新建的 Task 也就是 mTargetRootTask 也就是电话的 Tasktask this;}// 这里调用 getParent 就是 DefaultTaskDisplayArea 了。// 把当前的 Task 移动到 DefaultTaskDisplayArea 的最前面task.getParent().positionChildAt(POSITION_TOP, task, true /* includingParents */);taskDisplayArea.updateLastFocusedRootTask(lastFocusedTask, reason);}再回答一下问题移动的是新建的电话 Task 它的父容器是 DefaultTaskDisplayArea 所以是把这个 Task 移动到 DefaultTaskDisplayArea 的最前面。 mTargetRootTask.getRootTask 返回的是顶部的 Task, 当前 Task 上一层是 TaskDisplayArea 类型 name为DefaultTaskDisplayArea 而 mTargetRootTask.getParent 返回的父容器(不限制是 Task)则是 name 为 DefaultTaskDisplayArea 的 TaskDisplayArea。 getRootTask 和 getParent 的区别可以自行去源码中看看 到这里AMS已经将需要的 ActivityRecord 和 Task 创建并且挂载到层级树中接下来将是需要处理 TargetActivity 启动和显示逻辑了
3.4.4 显示Activity–resumeFocusedTasksTopActivities
首先看方法名目的需要显示一个栈顶的 Activity 那说的不就是 TargetActivity 嘛TargetActivity 的 ActivityRecord 已经创建并且移动到栈顶了。 前面该做的也都做好了现在也确实是时候处理显示逻辑这部分流程由 RootWindowContainer::resumeFocusedTasksTopActivities 执行调用链如下
RootWindowContainer::resumeFocusedTasksTopActivitiesTask::resumeTopActivityUncheckedLockedTask::resumeTopActivityInnerLockedTaskFragment::resumeTopActivity TaskDisplayArea::pauseBackTasks -- pause LauncherActivity WindowContainer::forAllLeafTaskTaskFragment::forAllLeafTaskFragmentsTaskFragment::startPausingTaskFragment::startPausingTaskFragment::schedulePauseActivity --构建 PauseActivityItem这里是触发暂停launchActivityTaskManagerService::startProcessAsync -- 创建“电话”进程重点方法在 TaskFragment::resumeTopActivity 开始处理先简单看一下前面的调用是怎么样的。
# RootWindowContainer// 第四个参数为 falseboolean resumeFocusedTasksTopActivities(Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,boolean deferPause) {......if (targetRootTask ! null (targetRootTask.isTopRootTaskInDisplayArea()|| getTopDisplayFocusedRootTask() targetRootTask)) {result targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,deferPause);}......}
# Taskboolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options,boolean deferPause) {......if (isLeafTask()) {if (isFocusableAndVisible()) {someActivityResumed resumeTopActivityInnerLocked(prev, options, deferPause);}}......}private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,boolean deferPause) {......// deferPause falseresumed[0] topFragment.resumeTopActivity(prev, options, deferPause);......}由于篇幅原因下面的 TaskFragment::resumeTopActivity 流程放在下一篇。