Android11 Acvitity启动流程1-ActivityStarter:

一、回顾

在学习Android app开发的时候,最先要学习的就是关于Activity的启动方式,Task和Back Stack的知识。因此在学习framework如何管理启动的activity之前,有必要回顾一下。

1.1.Task和Back Stack

Google官方文档里有这么一篇文档《Understand Tasks and Back Stack》https://developer.android.com/guide/components/activities/tasks-and-back-stack

1.1.1定义:

在这篇文章的开头就给task和Back Stack下了定义:

  • Task: A task is a collection of activities that users interact with when performing a certain job.
  • Stack: The activities are arranged in a stack—the back stack—in the order in which each activity is opened.

1.1.2举例说明:

For example, an email app might have one activity to show a list of new messages. When the user selects a message, a new activity opens to view that message. This new activity is added to the back stack. If the user presses the Back button, that new activity is finished and popped off the stack.

1.1.3图示:


Figure 1. A representation of how each new activity in a task adds an item to the back stack. When the user presses the Back button, the current activity is destroyed and the previous activity resumes.

When the current activity starts another, the new activity is pushed on the top of the stack and takes focus. The previous activity remains in the stack, but is stopped. When an activity stops, the system retains the current state of its user interface. When the user presses the Back button, the current activity is popped from the top of the stack (the activity is destroyed) and the previous activity resumes (the previous state of its UI is restored). Activities in the stack are never rearranged, only pushed and popped from the stack—pushed onto the stack when started by the current activity and popped off when the user leaves it using the Back button. As such, the back stack operates as a “last in, first out” object structure. Figure 1 visualizes this behavior with a timeline showing the progress between activities along with the current back stack at each point in time.

1.1.4Task切换

A task is a cohesive unit that can move to the “background” when users begin a new task or go to the Home screen, via the Home button. While in the background, all the activities in the task are stopped, but the back stack for the task remains intact—the task has simply lost focus while another task takes place, as shown in figure 2. A task can then return to the “foreground” so users can pick up where they left off. Suppose, for example, that the current task (Task A) has three activities in its stack—two under the current activity. The user presses the Home button, then starts a new app from the app launcher. When the Home screen appears, Task A goes into the background. When the new app starts, the system starts a task for that app (Task B) with its own stack of activities. After interacting with that app, the user returns Home again and selects the app that originally started Task A. Now, Task A comes to the foreground—all three activities in its stack are intact and the activity at the top of the stack resumes. At this point, the user can also switch back to Task B by going Home and selecting the app icon that started that task (or by selecting the app’s task from the Recents screen).


Figure 2. Two tasks: Task B receives user interaction in the foreground, while Task A is in the background, waiting to be resumed.

1.1.5进一步理解:

英文task的意思是“任务,工作”。所以,可以从用户使用场景来理解Google设计task的目的:
例如:接着上面说过的那个例子:用户打开email应用程序查看电子邮件。当查阅某一封邮件详情时,会启动一个新的activity来显示。

这时候用户对当前字体大小不满意。点击email这个应用设置进入设置页,email的设置直接启动了系统Settings的字体设置页面。
这个时候有三个activity:

  • email首页
  • email详情页
  • Settings字体设置页

这三个页面是一件事情或一份工作,用来完成用户的查看邮件和设置字符的任务。所以,当用户点back 键时,回退到email详情页是最合理的。
当用户想干中别的事情,比如听音乐,这又会是一个新的task任务,关于听音乐应用的页面都会在这个task里。

这时候就有两个task:

  • 查看邮件task
  • 听音乐task

当用户再次点击email应用程序时,查看邮件task里的所有activity就会整体切到前台。听音乐task里的所有activity就会整体切到后台。

1.2 Activity的启动方式(launchMode)

由于Activity的启动方式有很多,增加了分析问题的复杂度,因此我们只考虑启动方式为standard和 Intent flags为FLAG_ACTIVITY_NEW_TASK的情况。

1.2.1standard启动方式

It is a the default mode. The system creates a new instance of the activity in the task from which it was started and routes the intent to it. The activity can be instantiated multiple times, each instance can belong to different tasks, and one task can have multiple instances.

上面Figure 1 就展示的standard的启动方式。
另外还要注意standard的启动方式在一个task里一个Activity可以被实例化多次。如下图:

Figure 3. A single activity is instantiated multiple times.

1.2.2 FLAG_ACTIVITY_NEW_TASK

When starting an activity, you can modify the default association of an activity to its task by including flags in the intent that you deliver to startActivity().

FLAG_ACTIVITY_NEW_TASK:Start the activity in a new task. If a task is already running for the activity you are now starting, that task is brought to the foreground with its last state restored and the activity receives the new intent in onNewIntent().

二、通过adb dumpsys 信息来说明

2.1 demo

我写了一个demo,程序里实现了三个Activity:

  1. MainActivity
  2. ActivityA
  3. ActivityB

启动流程是:

  • 点击桌面图标启动MainActivity
  • MainActivity再启动ActivityA
    • startActivity(new Intent(MainActivity.this,ActivityA.class));
  • ActivityA再启动ActivityB
    • startActivity(new Intent(ActivityA.this,ActivityB.class));
  • ActivityB启动ActivityA后,再用FLAG_ACTIVITY_NEW_TASK的方式启动系统Settings的设置wifi界面
    • Intent intent1 = new Intent(“android.settings.WIRELESS_SETTINGS”);
      intent1.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
      startActivity(intent1);

图示:

2.2 dumpsys 信息

这个流程中framework是怎么设计实现的呢?我们先看看adb dumpsys activity的信息:

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):Stack #29: type=standard mode=fullscreenisSleeping=falsemBounds=Rect(0, 0 - 0, 0)mResumedActivity: ActivityRecord{b9474dc u0 com.android.settings/.Settings$NetworkDashboardActivity t29}* Task{7f8f9e5 #29 visible=true type=standard mode=fullscreen translucent=false A=1000:com.android.settings U=0 StackId=29 sz=1}mBounds=Rect(0, 0 - 0, 0)mMinWidth=-1 mMinHeight=-1userId=0 effectiveUid=1000 mCallingUid=u0a201 mUserSetupComplete=true mCallingPackage=com.tblenovo.wufl2.startactivitydemo mCallingFeatureId=nullaffinity=1000:com.android.settingsintent={act=android.settings.WIRELESS_SETTINGS flg=0x10000000 cmp=com.android.settings/.Settings$NetworkDashboardActivity}mActivityComponent=com.android.settings/.Settings$NetworkDashboardActivityautoRemoveRecents=false isPersistable=true activityType=1rootWasReset=false mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLEActivities=[ActivityRecord{b9474dc u0 com.android.settings/.Settings$NetworkDashboardActivity t29}]askedCompatMode=false inRecents=true isAvailable=truemRootProcess=ProcessRecord{66202c8 23153:com.android.settings/1000}taskId=29 stackId=29mHasBeenVisible=truemResizeMode=RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION mSupportsPictureInPicture=false isResizeable=truelastActiveTime=102874561 (inactive for 0s)Hist #0: ActivityRecord{b9474dc u0 com.android.settings/.Settings$NetworkDashboardActivity t29}Intent { act=android.settings.WIRELESS_SETTINGS flg=0x10000000 cmp=com.android.settings/.Settings$NetworkDashboardActivity }ProcessRecord{66202c8 23153:com.android.settings/1000}Stack #28: type=standard mode=fullscreenisSleeping=falsemBounds=Rect(0, 0 - 0, 0)* Task{19ea3e1 #28 visible=false type=standard mode=fullscreen translucent=true A=10201:com.tblenovo.wufl2.startactivitydemo U=0 StackId=28 sz=4}mBounds=Rect(0, 0 - 0, 0)mMinWidth=-1 mMinHeight=-1userId=0 effectiveUid=u0a201 mCallingUid=u0a67 mUserSetupComplete=true mCallingPackage=com.tblenovo.launcher mCallingFeatureId=nullaffinity=10201:com.tblenovo.wufl2.startactivitydemointent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.tblenovo.wufl2.startactivitydemo/.MainActivity}mActivityComponent=com.tblenovo.wufl2.startactivitydemo/.MainActivityautoRemoveRecents=false isPersistable=true activityType=1rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLEActivities=[ActivityRecord{fcb430 u0 com.tblenovo.wufl2.startactivitydemo/.MainActivity t28}, ActivityRecord{46b0e08 u0 com.tblenovo.wufl2.startactivitydemo/.ActivityA t28}, ActivityRecord{71d295a u0 com.tblenovo.wufl2.startactivitydemo/.ActivityB t28}, ActivityRecord{1dcb3ae u0 com.tblenovo.wufl2.startactivitydemo/.ActivityA t28}]askedCompatMode=false inRecents=true isAvailable=truemRootProcess=ProcessRecord{c21db8c 23079:com.tblenovo.wufl2.startactivitydemo/u0a201}taskId=28 stackId=28mHasBeenVisible=truemResizeMode=RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION mSupportsPictureInPicture=false isResizeable=truelastActiveTime=102813374 (inactive for 61s)Hist #3: ActivityRecord{1dcb3ae u0 com.tblenovo.wufl2.startactivitydemo/.ActivityA t28}Intent { cmp=com.tblenovo.wufl2.startactivitydemo/.ActivityA }Hist #2: ActivityRecord{71d295a u0 com.tblenovo.wufl2.startactivitydemo/.ActivityB t28}Intent { cmp=com.tblenovo.wufl2.startactivitydemo/.ActivityB }ProcessRecord{c21db8c 23079:com.tblenovo.wufl2.startactivitydemo/u0a201}Hist #1: ActivityRecord{46b0e08 u0 com.tblenovo.wufl2.startactivitydemo/.ActivityA t28}Intent { cmp=com.tblenovo.wufl2.startactivitydemo/.ActivityA }ProcessRecord{c21db8c 23079:com.tblenovo.wufl2.startactivitydemo/u0a201}Hist #0: ActivityRecord{fcb430 u0 com.tblenovo.wufl2.startactivitydemo/.MainActivity t28}Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.tblenovo.wufl2.startactivitydemo/.MainActivity bnds=[12,690][368,979] }ProcessRecord{c21db8c 23079:com.tblenovo.wufl2.startactivitydemo/u0a201}

2.2.1 dumpsys中的关键信息

从上面的adb dumpsys activity信息中可以解析出下面几个关键信息:

  1. Stack有两个:编号为28,29
  2. Stack 28里存放着我写的demo的Activity
  3. Stack 29里存放着Settings wifi设置Activity
  4. 有两个Task 分别为28,29。Task28属于Stack 28, Task 29属于Stack 29
  5. Task 28里有一个Activity:
Activities=[ActivityRecord{b9474dc u0 com.android.settings/.Settings$NetworkDashboardActivity t29}]
  1. Task 29里有四个Activity:
Activities=[ActivityRecord{fcb430 u0 com.tblenovo.wufl2.startactivitydemo/.MainActivity t28}, ActivityRecord{46b0e08 u0 com.tblenovo.wufl2.startactivitydemo/.ActivityA t28}, ActivityRecord{71d295a u0 com.tblenovo.wufl2.startactivitydemo/.ActivityB t28}, ActivityRecord{1dcb3ae u0 com.tblenovo.wufl2.startactivitydemo/.ActivityA t28}]
  1. 每个Activity的实现类为ActivityRecord,其中ActivityA有两个ActivityRecord,分别为ActivityRecord:46b0e08和ActivityRecord:1dcb3ae
  2. Task 28的信息里有一个
ProcessRecord{c21db8c 23079:com.tblenovo.wufl2.startactivitydemo/u0a201}
  1. Task 29的信息里有一个
ProcessRecord{66202c8 23153:com.android.settings/1000}

2.3 相关类

  • Stack
  • Task
  • ActivityRecord
  • ProcessRecord

三、具体实现

下面我们就看一看framework是怎么让上面的demo工作起来的。

3.1调试方法

####3.1.1 单编模块
如果要分析framework的相关源码,最好的方法就是加log。能单独编译framework模块,然后adb push到真机上是最快速的。
调度ActivityManagerService相关的功能,通常会修改下面两个目录:

  • frameworks/base

    • m --skip-make framework-minus-apex #android 11
  • frameworks/base/services
    • m --skip-make services

3.1.2 log调用栈信息

if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,new RuntimeException(“here”).fillInStackTrace());

3.2启动从Activity.java开始

startActivity(new Intent(ActivityA.this,ActivityB.class));的流程从Activity.jav开始。

Activity.java
public class Activity extends ContextThemeWrapperimplements LayoutInflater.Factory2,Window.Callback, KeyEvent.Callback,OnCreateContextMenuListener, ComponentCallbacks2,Window.OnWindowDismissedCallback,AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {@Overridepublic void startActivity(Intent intent) {this.startActivity(intent, null);}public 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);}...}
}

从上面的代码可以看出,流程从Activity.java的startActivityForResult()方法调到了Instrumentation.java的execStartActivity()方法。

Instrumentation.java
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {...try {intent.migrateExtraStreamToClipData(who);intent.prepareToLeaveProcess(who);int result = ActivityTaskManager.getService().startActivity(whoThread,who.getBasePackageName(), who.getAttributionTag(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()), token,target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);checkStartActivityResult(result, intent);} catch (RemoteException e) {throw new RuntimeException("Failure from system", e);}return null;}

从上面的代码可以看出,流程从Instrumentation.java的execStartActivity()调到了ActivityTaskManagerService.java的startActivity()方法。

ActivityTaskManagerService.java
public int startActivityAsUser(IApplicationThread caller, String callingPackage,String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,Bundle bOptions, int userId) {return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,true /*validateIncomingUser*/);}private 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) {assertPackageMatchesCallingUid(callingPackage);enforceNotIsolatedCaller("startActivityAsUser");userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");// TODO: Switch to user app stacks here.return 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();
}

3.3 Token

在这个流程中,要注意Activity.java的mToken,传到Instrumentation.java的token,然后到了ActivityTaskManagerService.java传给了resultTo。
以上面的ActivityA启动ActivityB(startActivity(new Intent(ActivityA.this,ActivityB.class)); )为例,通过加log发现这个resultTo就是

resultTo=Token{fa0eb6d ActivityRecord
{28da3a2 u0 com.tblenovo.wufl2.startactivitydemo/.ActivityA t102}}。

也就是说在ActivityA启动ActivityB这种情况下,token是ActivityA它自己。从resultTo的命名就能猜到用于返回结果。

上面流程相关类有

  • ActivityStartController
  • ActivityStarter
  • ActivityTaskManagerService.javaActivityTaskManagerService.java的getActivityStartController().obtainStarter()方法得到一个ActivityStart。并马上给ActivityStart设置了参数,然后调ActivityStart的execute()方法。

3.4 ActivityStarter

3.4.1ActivityStarter这个类的作用

咱们来想想ActivityStarter这个类的作用:

  1. 下面是ActivityStarter的注释。大概意思:它是一个用于解释如何启动一个Activity的控制器。这个类集中了所有的逻辑,这些逻辑用于决定一个intent和flags应该如何被传进一下Activity(肯定是被启动的activity)。这个类包含了相关联的task还有stack。
/*** Controller for interpreting how and then launching an activity.** This class collects all the logic for determining how an intent and flags should be turned into* an activity and associated task and stack.*/
  1. 从ActivityStarter里的Request内部类的命名还有成员变量(activityInfo,resolveInfo,resultTo,)就不难看出:ActivityStarter的一个任务是在启动activity之前把所有信息都准备全。
    我们可以想像一下,在上面例子中ActivityA启动ActivityB时,只用了一行代码:startActivity(new Intent(ActivityA.this,ActivityB.class)); 参数信息只有三个Intent,context和ActivityB.class。ActivityStarter的任务就是把这些简单的信息变成一个request。把必要有数据都准备好。

3.4.2准备了什么数据

mRequest数据的准备:
1.在这个流程中set了很多参数:

ActivityStarter.java
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();

2.有execute()方法:

ActivityStarter.java
int execute() {// If the caller hasn't already resolved the activity, we're willing// to do so here. If the caller is already holding the WM lock here,// and we need to check dynamic Uri permissions, then we're forced// to assume those permissions are denied to avoid deadlocking.if (mRequest.activityInfo == null) {mRequest.resolveActivity(mSupervisor);//code snippet 1}
}

3.4.3 executeRequest

ActivityStarter.java/*** Executing activity start request and starts the journey of starting an activity. Here* begins with performing several preliminary checks. The normally activity launch flow will* go through {@link #startActivityUnchecked} to {@link #startActivityInner}.*/private int executeRequest(Request request) {if (err == ActivityManager.START_SUCCESS) {Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)+ "} from uid " + callingUid);}}

ActivityStarter.java的execute()里有executeRequest,这时开始执行request请求。
这块就是adb logcat里的那行ActivityTaskManager: START u0 {cmp=com.tblenovo.wufl2.startactivitydemo/.ActivityA} from uid 10201的执行的地方。

再接着看:

/*** Executing activity start request and starts the journey of starting an activity. Here* begins with performing several preliminary checks. The normally activity launch flow will* go through {@link #startActivityUnchecked} to {@link #startActivityInner}.*/
private int executeRequest(Request request) {ActivityInfo aInfo = request.activityInfo;//code snippet 2ResolveInfo rInfo = request.resolveInfo;String resultWho = request.resultWho;//code snippet 3Task inTask = request.inTask;ActivityRecord sourceRecord = null;//code snippet 4ActivityRecord resultRecord = null;//code snippet 5if (resultTo != null) {sourceRecord = mRootWindowContainer.isInAnyStack(resultTo);if (DEBUG_RESULTS) {Slog.v(TAG_RESULTS, "Will send result to " + resultTo + " " + sourceRecord);}if (sourceRecord != null) {if (requestCode >= 0 && !sourceRecord.finishing) {resultRecord = sourceRecord;}}}//code snippet 6final 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);//code snippet 7mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,restrictedBgActivity, intentGrants);
}
  1. 上面代码中code snippet2的request.activityInfo是在code snippet1处初始化的。
  2. 关于code snippet 5中的resultTo大家不陌生吧,它就是在3.3Token里讲到的token。比如,ActivityA启动ActivityB,那么resultTo就是ActivityA(ActivityRecord)
  3. 在code snippet 6中 new了一个ActivityRecord,它就是要被启动的Activity.
  4. 在code snippet 7中 调了startActivityUnchecked()方法。以ActivityA启动ActivityB的为例,方法中的参数inTask 为空。
3.4.3.1ActivityStarter的作用

从分析上面的executeRequest()方法可以知道,ActivityStarter类的设计的作用还有:

  1. 初始化sourceRecord,也就是说要在启动新Activity之前要知道sourceReord是谁
  2. 创建要被启动的ActivityRecord.以ActivityA启动ActivityB的为例,那么这个ActivityRecord就是ActivityB

3.4.4startActivityUnchecked

接着code snippet 7分析。

    /*** Start an activity while most of preliminary checks has been done and caller has been* confirmed that holds necessary permissions to do so.* Here also ensures that the starting activity is removed if the start wasn't successful.*/
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,int startFlags, boolean doResume, ActivityOptions options, Task inTask,boolean restrictedBgActivity, NeededUriGrants intentGrants) {int result = START_CANCELED;final ActivityStack startedActivityStack;try {mService.deferWindowLayout();Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");//code snippet 8result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);} finally {Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);startedActivityStack = handleStartResult(r, result);mService.continueWindowLayout();}postStartActivityProcessing(r, result, startedActivityStack);return result;}

startActivityUnchecked()方法比较简单,直接看code snippet8 调了startActivityInner()

3.4.5 startActivityInner

先看一下代码:

    /*** Start an activity and determine if the activity should be adding to the top of an existing* task or delivered new intent to an existing activity. Also manipulating the activity task* onto requested or valid stack/display.** Note: This method should only be called from {@link #startActivityUnchecked}.*/// TODO(b/152429287): Make it easier to exercise code paths through startActivityInner@VisibleForTesting
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,int startFlags, boolean doResume, ActivityOptions options, Task inTask,boolean restrictedBgActivity, NeededUriGrants intentGrants) {setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,voiceInteractor, restrictedBgActivity);computeLaunchingTaskFlags();computeSourceStack();//code snippet 9mIntent.setFlags(mLaunchFlags);final Task reusedTask = getReusableTask();//code snippet 10}

着重看一下code snippet 9和code snippet 10的作用:

3.4.5.1 computeSourceStack()

在code snippet 9中computeSourceStack()方法,初始化了mSourceStack,它是一个ActivityTask。

private void computeSourceStack() {if (mSourceRecord == null) {mSourceStack = null;return;}if (!mSourceRecord.finishing) {//code snippet 11mSourceStack = mSourceRecord.getRootTask();return;}// If the source is finishing, we can't further count it as our source. This is because the// task it is associated with may now be empty and on its way out, so we don't want to// blindly throw it in to that task.  Instead we will take the NEW_TASK flow and try to find// a task for it. But save the task information so it can be used when creating the new task.if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {Slog.w(TAG, "startActivity called from finishing " + mSourceRecord+ "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;mNewTaskInfo = mSourceRecord.info;// It is not guaranteed that the source record will have a task associated with it. For,// example, if this method is being called for processing a pending activity launch, it// is possible that the activity has been removed from the task after the launch was// enqueued.final Task sourceTask = mSourceRecord.getTask();mNewTaskIntent = sourceTask != null ? sourceTask.intent : null;}mSourceRecord = null;mSourceStack = null;
}

以ActivitA启动ActivityB为例,逻辑在code snippet 11就return了。说明当前ActivityB的source Task就是sourceRecord的task,即ActivityA所在的task。

3.4.5.2 getReusableTask()

以ActivitA启动ActivityB为例(startActivity(new Intent(ActivityA.this,ActivityB.class));),通过加log,getReusableTask()返回值是null. 即reusedTask为null。

3.4.5.3 computeTargetTask()

在startActivityInner()方法继续向下分析,会看到computeTargetTask()和computeLaunchParams两个方法。

startActivityInner():
// Compute if there is an existing task that should be used for.final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();//code snippet 12final boolean newTask = targetTask == null;mTargetTask = targetTask;computeLaunchParams(r, sourceRecord, targetTask);//code snippet 13

由于reusedTask为null(以ActivitA启动ActivityB为例),下面先看一下code snippet 12 computeTargetTask():

private Task computeTargetTask() {if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {// A new task should be created instead of using existing one.return null;} else if (mSourceRecord != null) {//code snippet 13return mSourceRecord.getTask();} else if (mInTask != null) {return mInTask;} else {final ActivityStack stack = getLaunchStack(mStartActivity, mLaunchFlags,null /* task */, mOptions);final ActivityRecord top = stack.getTopNonFinishingActivity();if (top != null) {return top.getTask();} else {// Remove the stack if no activity in the stack.stack.removeIfPossible();}}return null;}

以ActivitA启动ActivityB为例,resultTo不为null,mSourceRecord不为Null,因此会走到code snippet 13的逻辑,即return sourceRecord的task,也就是说返回ActivitA的task. 即targetTask为ActivitA的task。

3.4.5.4 ActivityStarter这个类的作用

确定被启动Activity的Task

3.4.5.5 computeLaunchParams()

startActivityInner()方法的code snippet 13处调用了computeLaunchParams()

private void computeLaunchParams(ActivityRecord r, ActivityRecord sourceRecord,Task targetTask) {final ActivityStack sourceStack = mSourceStack != null ? mSourceStack: mRootWindowContainer.getTopDisplayFocusedStack();if (sourceStack != null && sourceStack.inSplitScreenWindowingMode()&& (mOptions == null|| mOptions.getLaunchWindowingMode() == WINDOWING_MODE_UNDEFINED)) {int windowingMode =targetTask != null ? targetTask.getWindowingMode() : WINDOWING_MODE_UNDEFINED;if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {if (sourceStack.inSplitScreenPrimaryWindowingMode()) {windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;} else if (sourceStack.inSplitScreenSecondaryWindowingMode()) {windowingMode = WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;}}if (mOptions == null) {mOptions = ActivityOptions.makeBasic();}mOptions.setLaunchWindowingMode(windowingMode);}//code snippet 14mSupervisor.getLaunchParamsController().calculate(targetTask, r.info.windowLayout, r,sourceRecord, mOptions, PHASE_BOUNDS, mLaunchParams);mPreferredTaskDisplayArea = mLaunchParams.hasPreferredTaskDisplayArea()? mLaunchParams.mPreferredTaskDisplayArea: mRootWindowContainer.getDefaultTaskDisplayArea();mPreferredWindowingMode = mLaunchParams.mWindowingMode;//code snippet 14
}

从方法名computeLaunchParams就能算到这是初始化启动的参数,从方法的内容看主要是在初始化mPreferredWindowingMode,即WindowMode。以ActivitA启动ActivityB为例,WindowMode等于0,WINDOWING_MODE_UNDEFINED。

  • (ActivityOption)mOptions.getLaunchWindowingMode()

    • ActivityOption 有关于window mode的设置
  • TOTO code snippet 14 mSupervisor.getLaunchParamsController().calculate()在计算什么?这次先不分析。之后再具体分析。
3.4.5.6 windowMode

看一下windowmode的定义,在WindowConfiguration.java里

/*** Class that contains windowing configuration/state for other objects that contain windows directly* or indirectly. E.g. Activities, Task, Displays, ...* The test class is {@link com.android.server.wm.WindowConfigurationTests} which must be kept* up-to-date and ran anytime changes are made to this class.* @hide*/
@TestApi
public class WindowConfiguration implements Parcelable, Comparable<WindowConfiguration> {/** Windowing mode is currently not defined. */public static final int WINDOWING_MODE_UNDEFINED = 0;/** Occupies the full area of the screen or the parent container. */public static final int WINDOWING_MODE_FULLSCREEN = 1;/** Always on-top (always visible). of other siblings in its parent container. */public static final int WINDOWING_MODE_PINNED = 2;/** The primary container driving the screen to be in split-screen mode. */// TODO: Remove once split-screen is migrated to wm-shell.public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3;/*** The containers adjacent to the {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} container in* split-screen mode.* NOTE: Containers launched with the windowing mode with APIs like* {@link ActivityOptions#setLaunchWindowingMode(int)} will be launched in* {@link #WINDOWING_MODE_FULLSCREEN} if the display isn't currently in split-screen windowing* mode* @see #WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY*/// TODO: Remove once split-screen is migrated to wm-shell.public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4;/*** Alias for {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} that makes it clear that the usage* points for APIs like {@link ActivityOptions#setLaunchWindowingMode(int)} that the container* will launch into fullscreen or split-screen secondary depending on if the device is currently* in fullscreen mode or split-screen mode.*/// TODO: Remove once split-screen is migrated to wm-shell.public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY =WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;/** Can be freely resized within its parent container. */// TODO: Remove once freeform is migrated to wm-shell.public static final int WINDOWING_MODE_FREEFORM = 5;/** Generic multi-window with no presentation attribution from the window manager. */public static final int WINDOWING_MODE_MULTI_WINDOW = 6;
3.4.5.7 ActivityStarter这个类的作用

确定被启动Activity的window mode.

3.4.5.8 recycleTask()

接着上面的逻辑,继续向下看:

startActivityInner():final ActivityRecord targetTaskTop = newTask? null : targetTask.getTopNonFinishingActivity();if (targetTaskTop != null) {// Recycle the target task for this launch.startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants);if (startResult != START_SUCCESS) {return startResult;}} else {mAddingToTask = true;}

从recycleTask方法的注释学到了什么?

recycleTask():/*** Prepare the target task to be reused for this launch, which including:* - Position the target task on valid stack on preferred display.* - Comply to the specified activity launch flags* - Determine whether need to add a new activity on top or just brought the task to front.*/

以ActivitA启动ActivityB为例(startActivity(new Intent(ActivityA.this,ActivityB.class));),recycleTask()的流程:

recycleTask():
int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask,NeededUriGrants intentGrants) {// Should not recycle task which is from a different user, just adding the starting// activity to the task.if (targetTask.mUserId != mStartActivity.mUserId) {mTargetStack = targetTask.getStack();mAddingToTask = true;return START_SUCCESS;}.../*** Figure out which task and activity to bring to front when we have found an existing matching* activity record in history. May also clear the task if needed.* @param intentActivity Existing matching activity.* @return {@link ActivityRecord} brought to front.*/setTargetStackIfNeeded(targetTaskTop);//code snippet 15...if (mAddingToTask) {return START_SUCCESS;//code snippet 16}
  1. 在code snippet 15设置了targetStack, setTargetStackIfNeeded()方法的作用可以直接从注释里了解。
  2. 在code snippet 16 return START_SUCCESS ,即mAddingToTask = true.
3.4.5.9 ActivityStarter这个类的作用

确定被启动Activity的targetStack, targetStack是一个ActivityStack.

3.4.5.10 addOrReparentStartingActivity()

以ActivitA启动ActivityB为例(startActivity(new Intent(ActivityA.this,ActivityB.class));),

startActivityInner():if (newTask) {final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)? mSourceRecord.getTask() : null;setNewTask(taskToAffiliate);if (mService.getLockTaskController().isLockTaskModeViolation(mStartActivity.getTask())) {Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);return START_RETURN_LOCK_TASK_MODE_VIOLATION;}} else if (mAddingToTask) {addOrReparentStartingActivity(targetTask, "adding to task");}

因为newTask为false,mAddingToTask为true,因此逻辑会走到addOrReparentStartingActivity()方法里。

addOrReparentStartingActivity():private void addOrReparentStartingActivity(Task parent, String reason) {if (mStartActivity.getTask() == null || mStartActivity.getTask() == parent) {//code snippet 17parent.addChild(mStartActivity);} else {mStartActivity.reparent(parent, parent.getChildCount() /* top */, reason);}}

由于mStartActivity(ActivityB)的task等于targetTask(ActivityA所在的task),因此在code snippet 17就把mStartActivity加到了targetTask里了。

3.4.5.11 ActivityStarter这个类的作用

把要启动的activity加到属于自己的task里。

3.4.5.12 ActivityStack.moveToFront

流程来到了下面的代码段:

startActivityInner():if (!mAvoidMoveToFront && mDoResume) {mTargetStack.getStack().moveToFront("reuseOrNewTask", targetTask);
}

以ActivitA启动ActivityB为例(startActivity(new Intent(ActivityA.this,ActivityB.class));),ActivityStack.moveToFront()执行到的逻辑主要有:

ActivityStack.moveToFront():void moveToFront(String reason, Task task) {if (!isAttached()) {return;}final TaskDisplayArea taskDisplayArea = getDisplayArea();if (isRootTask()) {taskDisplayArea.positionStackAtTop(this, false /* includingParents */, reason);//code snippet 17}if (task == null) {task = this;}task.getParent().positionChildAt(POSITION_TOP, task, true /* includingParents */);//code snippet 18
}
  1. 获得显示区域taskDisplayArea
  2. 把要启动的Activity所在的Task,targetTask,设置在显示区域taskDisplayArea的最上层
  3. task.getParent(),获得一个WindowContainer
  4. 把要启动的Activity所在的Task,targetTask,设置在WindowContainer的最上层
3.4.5.13 ActivityStarter这个类的作用

把要启动的Activity所在的Task设置在显示区域和WindowContainer的最上层

TODO WindowContainer是什么?在之后慢慢学习

3.4.5.14 ActivityStack.startActivityLock()

接着看,下面的流程:

startActivityInner():mTargetStack.startActivityLocked(mStartActivity, topStack.getTopNonFinishingActivity(),newTask, mKeepCurTransition, mOptions);

以ActivitA启动ActivityB为例(startActivity(new Intent(ActivityA.this,ActivityB.class));), ActivityStack.startActivityLocked的主要流程如下:

ActivityStack.startActivityLocked():void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,boolean newTask, boolean keepCurTransition, ActivityOptions options) {Task rTask = r.getTask();final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();final boolean isOrhasTask = rTask == this || hasChild(rTask);Task task = null;task = activityTask;// Slot the activity into the history stack and proceedif (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,new RuntimeException("here").fillInStackTrace());task.positionChildAtTop(r);//code snippet 19// The transition animation and starting window are not needed if {@code allowMoveToFront}// is false, because the activity won't be visible.if ((!isHomeOrRecentsStack() || hasActivity()) && allowMoveToFront) {final DisplayContent dc = getDisplay().mDisplayContent;if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,"Prepare open transition: starting " + r);if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {dc.prepareAppTransition(TRANSIT_NONE, keepCurTransition);mStackSupervisor.mNoAnimActivities.add(r);} else {int transit = TRANSIT_ACTIVITY_OPEN;//code snippet 20dc.prepareAppTransition(transit, keepCurTransition);mStackSupervisor.mNoAnimActivities.remove(r);}boolean doShow = true;if (r.mLaunchTaskBehind) {// r.mLaunchTaskBehind= false// Don't do a starting window for mLaunchTaskBehind. More importantly make sure we// tell WindowManager that r is visible even though it is at the back of the stack.r.setVisibility(true);ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);// Go ahead to execute app transition for this activity since the app transition// will not be triggered through the resume channel.getDisplay().mDisplayContent.executeAppTransition();} else if (SHOW_APP_STARTING_PREVIEW && doShow) {// true// Figure out if we are transitioning from another activity that is// "has the same starting icon" as the next one.  This allows the// window manager to keep the previous window it had previously// created, if it still had one.Task prevTask = r.getTask();ActivityRecord prev = prevTask.topActivityWithStartingWindow();if (prev != null) {// We don't want to reuse the previous starting preview if:// (1) The current activity is in a different task.if (prev.getTask() != prevTask) {prev = null;}// (2) The current activity is already displayed.else if (prev.nowVisible) {prev = null;}}//code snippet 21r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity));}} else {// If this is the first activity, don't do any fancy animations,// because there is nothing for it to animate on top of.ActivityOptions.abort(options);}}
  1. code snippet 19中task.positionChildAtTop®;

    • task为Task
  2. code snippet 20中dc.prepareAppTransition(transit, keepCurTransition);
    • dc为DisplayContent
  3. code snippet 20中 mStackSupervisor.mNoAnimActivities.remove®;
    • mStackSupervisor为ActivityStackSuperisor
  4. code snippet 21中r.showStartingWindow()
    • r为ActivitRecord,即被启动的ActivityB

3.5 时序图

流程先分析到这里,之后的流程是Activity的Pause和Resume,我会单独再分析。

Android11 Acvitity启动流程1-ActivityStarter相关推荐

  1. Launcher进程启动流程

    Launcher进程启动流程 在分析ActivityManagerService启动流程的时候说过,ActivityManagerService启动完成后,会调用ActivityTaskManager ...

  2. framework之Activity启动流程(基于Android11源码)

    一步步看,你就会对activity的启动流程有深刻的认知. 引言 Android11上,Activity的启动流程与Android10的实现(可以参考Activity的启动过程详解(基于10.0源码) ...

  3. Android10.0系统启动之Launcher(桌面)启动流程-[Android取经之路]

    摘要:上一节我们讲完了Android10.0的ActivityManagerService的启动流程,在AMS的最后启动了Launcher进程,今天我们就来看看Launcher的真正启动流程. 阅读本 ...

  4. 【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 二 | AMS 进程相关源码 | 主进程相关源码 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  5. android activity启动流程_Activity 启动流程(二)

    标签: Activity启动流程 Activity启动时间优化 前一篇文章有介绍Launcher请求AMS过程,参考文章- <Activity 启动流程(一)> 本文将介绍AMS到Appl ...

  6. c++builder启动了怎么停止_App 竟然是这样跑起来的 —— Android App/Activity 启动流程分析...

    在我的上一篇文章: AJie:按下电源键后竟然发生了这一幕 -- Android 系统启动流程分析​zhuanlan.zhihu.com 我们分析了系统在开机以后的一系列行为,其中最后一阶段 AMS( ...

  7. android serialport new 软件退出_基于Android9.0,了解Android启动流程

    先记住四个进程和三种方式. **四个进程** 1.Launcher进程 2.system_server进程 3.App进程 4.Zygote进程 **三种方式** 1.Binder方式 2.Socke ...

  8. zygoteinit.java_源码跟踪之启动流程:从ZygoteInit到onCreate

    Instrumentation SDK版本名称: Pie API Level: 28 一.源码调用时序图 1. Activity的启动流程 说明:其中ActivityThread中执行的schedul ...

  9. 红橙Darren视频笔记 Activity启动流程(API28)

    在查看Android Api28 start activity流程的源码时 发现27和28的源码差别很大,对于28的启动流程整理如下: Intent intent = new Intent(MainA ...

最新文章

  1. Redhat7 systemctl命令
  2. zoj 1962 How Many Fibs?(字符串化为数字处理)
  3. 戴尔服务器设置文件存储,DELL服务器RAID配置详细教程-20210730001009.pdf-原创力文档...
  4. 前端如何实现音乐盒胶盘的转动_干货来袭!web前端开发工程师必看之如何使用CSS3实现瀑布流效果?...
  5. Angular使用中的编码tips(持续更)
  6. html设置百度协议,网站HTML结构SEO要求说明(含移动站)
  7. shell 字符串分割
  8. 创建SQL函数计算员工加班时间
  9. typecho免申请开发者应用集成第三方登录插件v2.1.2
  10. 批量修改文件夹或文件权限
  11. 博客园 文章和随笔区别
  12. java8之Stream API(提取子流和组合流)
  13. Bailian2975 Caesar Cryptogram【密码】
  14. 文本处理 - 测试一个对象是否是类字符串
  15. python 公司教程_最全Python快速入门教程,满满都是干货
  16. 附合导线计算软件_再也不盲目跑杆了,一次性搞懂水准测量+导线测量!
  17. CruiseControl入门简介
  18. vue刷新左菜单消失_vue+Element框架menu菜单刷新后保持选中状态
  19. signature=7bfc4e6c1dbcfddf5237122a73885e6d,Bending receiver using heat-shrinkable film
  20. 北大的戴威,为何输给了三本的胡玮炜?

热门文章

  1. Java实现SRT字幕中英文合成工具
  2. 不要埋怨别人让你失望了,只怪你自己期望太多
  3. python url编码与解码
  4. uniqueResult和list
  5. request_irq()、free_irq()
  6. Django 生命周期
  7. 查壳、加壳、脱壳详细教程
  8. ABB robotstudio 创建系统小问题,谢谢
  9. 微信小程序服务器连接失败,微信小程序在苹果上出现[request:fail 发生了 SSL 错误无法建立与该服务器的安全连接。]错误的解决方案...
  10. DNS轮询+泛域名解析