Android四大组件之Activity启动流程源码实现详解(二)


      Activity启动流程源码实现详解(二)

Android四大组件源码实现详解系列博客目录:

Android应用进程创建流程大揭秘
Android四大组件之bindService源码实现详解
Android四大组件之Activity启动流程源码实现详解概要
Android四大组件之Activity启动流程源码实现详解(一)
Android四大组件之Activity启动流程源码实现详解(二)


前言

  还记得大明湖畔的夏雨荷吗!错了,还记得我们前面章节博客Android四大组件之Activity启动流程源码实现详解(一)吗,在上述博客中我们重点分析了Activity启动的如下相关知识点:

发起端进程是怎么通过Instrumentation管理类并且借助AMP完成启动Activity请求的发送system_server进程中的AMS初步处理启动Activiyt的请求,并借助PKMS服务解析intent获取目标Activity的ActivityInfo信息,然后通过上述解析得到的数据为目标Activiyt构建ActivityRecord数据结构

那么在本篇博客中我们将继续分析system_server对Activity启动请求的处理流程:

  • system_server进程通过AMS处理启动Activity请求:
     4.为目标Activity查找/分配或者创建最优Task栈以及ActivityStack栈
     5.Pause前台Activity
     6.Resume请求的目标Activity
     7.AMS请求zygote进程为目标Activity创建所属进程

    注意:本篇的介绍是基于Android 7.xx平台为基础的,其中涉及的代码路径如下:

    frameworks/base/services/core/java/com/android/server/am/
    --- ActivityManagerService.java
    --- ProcessRecord.java
    --- ActivityRecord.java
    --- ActivityResult.java
    --- ActivityStack.java
    --- ActivityStackSupervisor.java
    --- ActivityStarter.java
    --- TaskRecord.java

    frameworks/base/services/core/java/com/android/server/pm/
    --- PackageManagerService.java

    frameworks/base/core/java/android/content/pm/
    --- ActivityInfo.java

    frameworks/base/core/java/android/app/
    --- IActivityManager.java
    --- ActivityManagerNative.java (内部包含AMP)
    --- ActivityManager.java
    --- AppGlobals.java
    --- Activity.java
    --- ActivityThread.java(内含AT)
    --- LoadedApk.java
    --- AppGlobals.java
    --- Application.java
    --- Instrumentation.java

    --- IApplicationThread.java
    --- ApplicationThreadNative.java (内部包含ATP)
    --- ActivityThread.java (内含ApplicationThread)
    --- ContextImpl.java

    并且在后续的源码分析过程中为了简述方便,会将做如下简述:
    ApplicationThreadProxy简称为ATP
    ActivityManagerProxy简称为AMP
    ActivityManagerService简称为AMS
    ActivityManagerNative简称AMN
    ApplicationThreadNative简称ATN
    PackageManagerService简称为PKMS
    ApplicationThread简称为AT
    ActivityStarter简称为AS,这里不要和ActivityServices搞混淆了
    ActivityStackSupervisor简称为ASS

    在正式开始今天博客相关源码分析前,还是先奉上调用的时序图以便小伙们先从整体上有个清晰的概括,然后再从细节开撸!

    Android四大组件之Activity启动流程源码实现详解(二)

    一.前期知识准备

      说实话,此处章节是我在将第二大章节写了一大半情况下回过头来撰写的,因为如果这里不将此处的知识点阐述清楚的话,感觉后面的章节没有办法进行!还记得我们在前面博客Android四大组件之Activity启动流程源码实现详解概要的章节2.7中我们分析了ActivityRecord、TaskRecord、ActivityStack、ProcessRecord、ActivityStackSupervisor在整个Activity启动的中的关系视图,但是该示意图是从整个AMS框架来说的,并且也只是介绍了一个大概。
    Android四大组件之Activity启动流程源码实现详解(二)

    今天我们先抛开AMS的整体不谈,先谈谈ActivityRecord、TaskRecord、ActivityStack这三个类之间的关联,因为本篇的源码分析将会重点涉及到这三者,所以要先弄明白几个重要的类及概念(ActivityRecord在前面的博客Android四大组件之Activity启动流程源码实现详解(一)已经有分析过了),所以在正式源码前我们先来看看另外两者!
    Android四大组件之Activity启动流程源码实现详解(二)


    1.1 TaskRecord

      TaskRecord是用来管理ActivityRecord的容器数据结构,用于记录该任务栈的activity开启的先后顺序,而TaskRecord对这些ActivityRecord的管理是以栈的形式来管理的,既然是栈那就肯定满足后进先出的原则!TaskRecord管理的ActivityRecord不一定都属于同一个App进程,这个需要根据实际情况来判定(这个从我们的最上面的示意图也可以看到)!

    //[TaskRecord.java]
    final class TaskRecord {
    final int taskId; // 任务ID
    String affinity; // 是指root activity的affinity,即该Task中第一个Activity
    String rootAffinity; //
    Intent intent; // 最开始创建该Task的intent

    int userId; // 记录创建该Task的用户id

    final ArrayList<ActivityRecord> mActivities;//使用一个ArrayList来保存所有的管理的ActivityRecord

    String mCallingPackage;//调用者包名
    ActivityStack stack;//TaskRecord所在的ActivityStack
    final ActivityManagerService mService;//AMS的

    //添加Activity到Task栈顶部
    void addActivityToTop(ActivityRecord r) {
    addActivityAtIndex(mActivities.size(), r);
    }

    //添加Activity到指定的索引位置
    void addActivityAtIndex(int index, ActivityRecord r) {
    ...
    }

    //获取根ActivityRecord的intent信息
    Intent getBaseIntent() {
    return intent != null ? intent : affinityIntent;
    }

    //获取根ActivityRecord,即Task栈底的ActivityRecord(因为它是后进先出)
    ActivityRecord getRootActivity() {
    for (int i = 0; i < mActivities.size(); i++) {
    final ActivityRecord r = mActivities.get(i);
    if (r.finishing) {
    continue;
    }
    return r;
    }
    return null;
    }
    //获取栈顶ActivityRecord
    ActivityRecord getTopActivity() {
    for (int i = mActivities.size() - 1; i >= 0; --i) {
    final ActivityRecord r = mActivities.get(i);
    if (r.finishing) {
    continue;
    }
    return r;
    }
    return null;
    }

    @Override
    public String toString() {
    StringBuilder sb = new StringBuilder(128);
    if (stringName != null) {
    sb.append(stringName);
    sb.append(" U=");
    sb.append(userId);
    sb.append(" StackId=");
    sb.append(stack != null ? stack.mStackId : INVALID_STACK_ID);
    sb.append(" sz=");
    sb.append(mActivities.size());
    sb.append('}');
    return sb.toString();
    }
    sb.append("TaskRecord{");
    sb.append(Integer.toHexString(System.identityHashCode(this)));
    sb.append(" #");
    sb.append(taskId);
    if (affinity != null) {
    sb.append(" A=");
    sb.append(affinity);
    } else if (intent != null) {
    sb.append(" I=");
    sb.append(intent.getComponent().flattenToShortString());
    } else if (affinityIntent != null) {
    sb.append(" aI=");
    sb.append(affinityIntent.getComponent().flattenToShortString());
    } else {
    sb.append(" ??");
    }
    stringName = sb.toString();
    return toString();
    }
    }

    有了前面的分析,我们来实际看看TaskRecord的数据情况,而恰好Android为我们提供了一个很好的命令dumpsy可以让我们洞察一切,通过dump可以看到此时存在有八个TaskRecord!

    XXX:/ # dumpsys activity | grep TaskRecord
    * Recent #0: TaskRecord{b80c4da #80 A=com.android.launcher3 U=0 StackId=0 sz=1}
    * Recent #1: TaskRecord{c6a6d0b #1 I=com.android.settings/.FallbackHome U=0 StackId=-1 sz=0}
    * Recent #2: TaskRecord{80bf7e8 #79 A=com.android.settings U=0 StackId=-1 sz=0}
    * Recent #3: TaskRecord{8116e01 #77 A=com.android.calculator2 U=0 StackId=-1 sz=0}
    * Recent #4: TaskRecord{4b654a6 #76 A=com.cyanogenmod.filemanager U=0 StackId=-1 sz=0}
    * Recent #5: TaskRecord{dd0cee7 #75 A=org.codeaurora.gallery U=0 StackId=-1 sz=0}
    * Recent #6: TaskRecord{e9caa94 #74 A=com.xxx.printtest U=0 StackId=-1 sz=0}
    * Recent #7: TaskRecord{725e93d #44 I=com.android.settings/.Settings$DataUsageSummaryActivity U=0 StackId=-1 sz=0}
    TaskRecord{b80c4da #80 A=com.android.launcher3 U=0 StackId=0 sz=1}
    TaskRecord{b80c4da #80 A=com.android.launcher3 U=0 StackId=0 sz=1}



    1.2 ActivityStack

      如果说TaskRecord是ActivityRecord的大管家,那么ActivityStack则是TaskRecord大管家,即ActivityStack是用来管理TaskRecord一种结构容器。ActivityStack也是我们通常意义上所说的Activity栈,它存在如下的几种的StackId(即我们可以把ActivityStack归纳为几种情况),这个也可以通过前面1.1章节最后的打印看出来!

    //【ActivityManager.java StackId]
    public static class StackId {

    public static final int INVALID_STACK_ID = -1;//非法stack ID.
    public static final int FIRST_STATIC_STACK_ID = 0;

    //Launcher的Activity以及recentsAPP
    public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID;

    //正常启动Activity的所处的ActivityStack
    public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;

    public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1;
    public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1;//这个是分屏应用所处于的ActivityStack
    public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;//画中画模式
    public static final int LAST_STATIC_STACK_ID = PINNED_STACK_ID;
    public static final int FIRST_DYNAMIC_STACK_ID = LAST_STATIC_STACK_ID + 1;
    }

    接着继续修理ActivityStack,把我的意大利炮拿出来朝着它狠狠的开炮!

    //
    final class ActivityStack {
    ...

    //Activity状态值,和Activity生命周期对应
    enum ActivityState {
    INITIALIZING,
    RESUMED,
    PAUSING,
    PAUSED,
    STOPPING,
    STOPPED,
    FINISHING,
    DESTROYING,
    DESTROYED
    }

    ...
    final ActivityManagerService mService;//AMS服务的引用
    final WindowManagerService mWindowManager;//WMS服务的引用

    //使用一个ArrayList来保存TaskRecord
    private final ArrayList<TaskRecord>mTaskHistory = new ArrayList<>();

    //该Stack中正在pause的ActivityRecord
    ActivityRecord mPausingActivity = null;

    //个表示当前ActivityStack处于已经resumed的activity
    ActivityRecord mResumedActivity = null;

    //表示该Stack中最后被paused过程的activity
    ActivityRecord mLastPausedActivity = null;

    ActivityRecord mLastStartedActivity = null;

    final int mStackId;//该Stack的身份ID

    ...
    //在每个ActivityStack中保存着一份所有的ActivityStack
    ArrayList<ActivityStack> mStacks;

    int mDisplayId;

    //管理ActivityStack的的ASS的引用
    final ActivityStackSupervisor mStackSupervisor;

    //创建TakRecord,这个会在后面的博客中调用到
    TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
    IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
    boolean toTop) {

    //创建一个task
    TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
    voiceInteractor);
    // add the task to stack first, mTaskPositioner might need the stack association
    //将task添加到ActivityStack中去
    addTask(task, toTop, "createTaskRecord");
    final boolean isLockscreenShown = mService.mLockScreenShown == LOCK_SCREEN_SHOWN;
    if (!layoutTaskInStack(task, info.windowLayout) && mBounds != null && task.isResizeable()
    && !isLockscreenShown) {
    task.updateOverrideConfiguration(mBounds);
    }
    return task;
    }
    //添加TaskRecord
    void addTask(final TaskRecord task, final boolean toTop, String reason) {
    final ActivityStack prevStack = preAddTask(task, reason, toTop);

    task.stack = this;
    if (toTop) {
    insertTaskAtTop(task, null);
    } else {
    mTaskHistory.add(0, task);
    updateTaskMovement(task, false);
    }
    postAddTask(task, prevStack);
    }
    @Override
    public String toString() {
    return "ActivityStack{" + Integer.toHexString(System.identityHashCode(this))
    + " stackId=" + mStackId + ", " + mTaskHistory.size() + " tasks}";
    }
    ..
    }

      通过前面的源码我们可以看到ActivityStack使用了一个ArrayList来保存TaskRecord,另外,ActivityStack中还持有ActivityStackSupervisor对象的引用,这个是用来管理ActivityStacks的这里就不过多介绍了,章节1.3会简单介绍一下,后面会开辟一个专门的章节来分析这块!

    有了前面的分析,我们来实际看看ActivityStack的数据情况,而恰好Android为我们提供了一个很好的命令dumpsy可以让我们洞察一切,通过dump可以看到此时存在一个ActivityStack!

    XXX:/ # dumpsys activity | grep ActivityStack
    mFocusedStack=ActivityStack{55a06c8 stackId=1, 5 tasks} mLastFocusedStack=ActivityStack{55a06c8 stackId=1, 5 tasks}



    1.3 ActivityStackSupervisor

      如果说ActivityStack则是TaskRecord大管家,那么ActivityStackSupervisor则是ActivityStack大管家,即ActivityStackSupervisor是用来管理ActivityStack一种结构容器。

    public final class ActivityStackSupervisor implements DisplayListener {
    ...
    final ActivityManagerService mService;//AMS 实例对象的引用
    private RecentTasks mRecentTasks;//管理RecentTasks
    int mCurrentUser;//当前用户
    ActivityStack mHomeStack;//Home所属Stack
    ActivityStack mFocusedStack;//当前持有焦点的Stack
    private ActivityStack mLastFocusedStack;//最后获取焦点的stack,此时表示正在切换
    //ActivityDisplay列表,以当前的displayid为key这个可以对应多种显示设备,我们这里只考虑一种),以ActivityDisplay为value
    private final SparseArray<ActivityDisplay> mActivityDisplays = new SparseArray<>();
    private SparseArray<ActivityContainer> mActivityContainers = new SparseArray<>();//以mStackId为key

    class ActivityDisplay {
    int mDisplayId;
    Display mDisplay;
    DisplayInfo mDisplayInfo = new DisplayInfo();

    final ArrayList<ActivityStack> mStacks = new ArrayList<>();

    ActivityRecord mVisibleBehindActivity;

    ActivityDisplay() {
    }
    ...
    }
    ...
    }

    这里我们重点关注一下mHomeStack和mFocusedStack以及mLastFocusedStack,并且mActivityDisplays是通过displayid来区分当前显示的ActivityStack的。


    1.4 Activity各种栈关系总结

    Android四大组件之Activity启动流程源码实现详解(二)
    有了前面知识的铺垫,我们这里对AMS中牵涉的各种栈结构体的组成关系来简单总结一下:

    在不考虑分屏和虚拟屏的情况下,我们认为ActivityStackSupervisor与ActivityDisplay都是系统唯一,如果考虑起来就复杂了每个ActivityStack中可以有若干个TaskRecord对象,它有一个ArrayList类型的成员mTaskHistory,用于存储TaskRecord每个TaskRecord包含如果若干个ActivityRecord对象,这就是我们常说的任务栈,具有后进先出的特点每个ActivityRecord记录一个Activity信息,并且每个ActivityRecord会对应到一个TaskRecord,ActivityRecord中类型为TaskRecord的成员task,记录所属的Task,这里有一点需要注意的是Activity和ActivityRecord并不是一对一的,而是一对多,因为一个Actitiy可能存在多个启动方式进而导致存在多个ActivityRecordActivityStackSupervisor,负责所有Activity栈的管理。内部管理了mHomeStack、mFocusedStack和mLastFocusedStack三个Activity栈。其中,mHomeStack管理的是Launcher相关的Activity栈;mFocusedStack管理的是当前显示在前台Activity的Activity栈;mLastFocusedStack管理的是上一次显示在前台Activity的Activity栈ActivityDisplay主要有Home Stack和App Stack这两个栈

    上述几个之间的管理非常紧凑,可以通过正向链表和反向链表通过其中的一个点切入获取到其它对应的关联的结构,这个从后续分析的查找复用ActivityRecord和Task以及Stack可以看出来

  • 正向关系链表
    ActivityStackSupervisor.mActivityDisplays
    ---> ActivityDisplay.mStacks
    ---> ActivityStack.mTaskHistory
    ---> TaskRecord.mActivities
    ---> ActivityRecord

  • 反向关系链表
    ActivityRecord.task
    ---> TaskRecord.stack
    ---> ActivityStack.mStackSupervisor
    ---> ActivityStackSupervisor

    关于上述之间的关联,小伙们可以使用命令dumpsys activity activities进行查看,虽然这里将贴出来会显得很啰嗦,但是为了小伙们的学习我这里也是拼了,因为这样会更加的清晰明了!

    ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
    Display #0 (activities from top to bottom)://测试终端只存在一个显示设备,所以Displayid只会存在一个
    Stack #1://当前焦点的ActivtyStack id
    mFullscreen=true
    mBounds=null
    Task id #96//当前获取焦点的Task任务栈id
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
    * TaskRecord{56df812 #96 A=com.cyanogenmod.filemanager U=0 StackId=1 sz=1}//Task任务栈具体信息
    userId=0 effectiveUid=u0a21 mCallingUid=u0a23 mUserSetupComplete=true mCallingPackage=com.android.launcher3
    affinity=com.cyanogenmod.filemanager
    intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.cyanogenmod.filemanager/.activities.NavigationActivity}//启动目标Activity的intent信息
    realActivity=com.cyanogenmod.filemanager/.activities.NavigationActivity
    autoRemoveRecents=false isPersistable=true numFullscreen=1 taskType=0 mTaskToReturnTo=1
    rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
    Activities=[ActivityRecord{dac4005 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t96}]//当前获取焦点的Activity的ActivityRecord信息
    askedCompatMode=false inRecents=true isAvailable=true
    lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/96_task_thumbnail.png
    stackId=1
    hasBeenVisible=true mResizeMode=RESIZE_MODE_UNRESIZEABLE isResizeable=false firstActiveTime=1601263245356 lastActiveTime=1601263245356 (inactive for 38s)
    * Hist #0: ActivityRecord{dac4005 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t96}
    packageName=com.cyanogenmod.filemanager processName=com.cyanogenmod.filemanager
    launchedFromUid=10023 launchedFromPackage=com.android.launcher3 userId=0
    app=ProcessRecord{1544be3 8312:com.cyanogenmod.filemanager/u0a21}
    Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.cyanogenmod.filemanager/.activities.NavigationActivity bnds=[536,168][712,356] }
    frontOfTask=true task=TaskRecord{56df812 #96 A=com.cyanogenmod.filemanager U=0 StackId=1 sz=1}
    taskAffinity=com.cyanogenmod.filemanager
    realActivity=com.cyanogenmod.filemanager/.activities.NavigationActivity
    baseDir=/system/app/CMFileManager/CMFileManager.apk
    dataDir=/data/user/0/com.cyanogenmod.filemanager
    stateNotNeeded=false componentSpecified=true mActivityType=0
    compat={320dpi} labelRes=0x7f0c0008 icon=0x7f020062 theme=0x7f0e0000
    config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w360dp h568dp 320dpi nrml port finger -keyb/v/h -nav/h s.5}
    taskConfigOverride={1.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}
    taskDescription: iconFilename=null label="null" color=ff1e88e5
    launchFailed=false launchCount=1 lastLaunchTime=-38s806ms
    haveState=false icicle=null
    state=RESUMED stopped=false delayedResume=false finishing=false
    keysPaused=false inHistory=true visible=true sleeping=false idle=true mStartingWindowState=STARTING_WINDOW_SHOWN
    fullscreen=true noDisplay=false immersive=false launchMode=1
    frozenBeforeDestroy=false forceNewConfig=false
    mActivityType=APPLICATION_ACTIVITY_TYPE
    waitingVisible=false nowVisible=true lastVisibleTime=-37s955ms
    resizeMode=RESIZE_MODE_UNRESIZEABLE
    Task id #95//Stack id为1中另外的Taask
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
    * TaskRecord{495a9e0 #95 A=org.codeaurora.gallery U=0 StackId=1 sz=1}
    userId=0 effectiveUid=u0a13 mCallingUid=u0a23 mUserSetupComplete=true mCallingPackage=com.android.launcher3
    affinity=org.codeaurora.gallery
    intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity}
    realActivity=org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity
    autoRemoveRecents=false isPersistable=true numFullscreen=1 taskType=0 mTaskToReturnTo=1
    rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
    Activities=[ActivityRecord{1c174fa u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t95}]
    askedCompatMode=false inRecents=true isAvailable=true
    lastThumbnail=android.graphics.Bitmap@bbc499 lastThumbnailFile=/data/system_ce/0/recent_images/95_task_thumbnail.png
    stackId=1
    hasBeenVisible=true mResizeMode=RESIZE_MODE_FORCE_RESIZEABLE isResizeable=true firstActiveTime=1601263244132 lastActiveTime=1601263244132 (inactive for 40s)
    * Hist #0: ActivityRecord{1c174fa u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t95}
    packageName=org.codeaurora.gallery processName=org.codeaurora.gallery
    launchedFromUid=10023 launchedFromPackage=com.android.launcher3 userId=0
    app=ProcessRecord{ff4ff7f 8258:org.codeaurora.gallery/u0a13}
    Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity bnds=[360,168][536,356] }
    frontOfTask=true task=TaskRecord{495a9e0 #95 A=org.codeaurora.gallery U=0 StackId=1 sz=1}
    taskAffinity=org.codeaurora.gallery
    realActivity=org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity
    baseDir=/system/priv-app/SnapdragonGallery/SnapdragonGallery.apk
    dataDir=/data/user/0/org.codeaurora.gallery
    stateNotNeeded=false componentSpecified=true mActivityType=0
    compat={320dpi} labelRes=0x7f0b00f1 icon=0x7f030001 theme=0x7f100035
    config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w360dp h568dp 320dpi nrml port finger -keyb/v/h -nav/h s.5}
    taskConfigOverride={1.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}
    taskDescription: iconFilename=null label="null" color=fff5f5f5
    launchFailed=false launchCount=0 lastLaunchTime=-41s697ms
    haveState=true icicle=Bundle[mParcelledData.dataSize=1556]
    state=STOPPED stopped=true delayedResume=false finishing=false
    keysPaused=false inHistory=true visible=false sleeping=false idle=true mStartingWindowState=STARTING_WINDOW_SHOWN
    fullscreen=true noDisplay=false immersive=false launchMode=0
    frozenBeforeDestroy=false forceNewConfig=false
    mActivityType=APPLICATION_ACTIVITY_TYPE
    waitingVisible=false nowVisible=false lastVisibleTime=-41s87ms
    connections=[ConnectionRecord{d694795 u0 CR org.codeaurora.gallery/com.android.gallery3d.app.BatchService:@c63ab4c}]
    resizeMode=RESIZE_MODE_FORCE_RESIZEABLE

    Running activities (most recent first):
    TaskRecord{56df812 #96 A=com.cyanogenmod.filemanager U=0 StackId=1 sz=1}
    Run #1: ActivityRecord{dac4005 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t96}
    TaskRecord{495a9e0 #95 A=org.codeaurora.gallery U=0 StackId=1 sz=1}
    Run #0: ActivityRecord{1c174fa u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t95}

    mResumedActivity: ActivityRecord{dac4005 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t96}

    Stack #0://Launcher所属的ActivityStack
    mFullscreen=true
    mBounds=null
    Task id #88
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
    * TaskRecord{a9ad0b9 #88 A=com.android.launcher3 U=0 StackId=0 sz=1}
    userId=0 effectiveUid=u0a23 mCallingUid=1000 mUserSetupComplete=true mCallingPackage=android
    affinity=com.android.launcher3
    intent={act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher}
    realActivity=com.android.launcher3/.Launcher
    autoRemoveRecents=false isPersistable=true numFullscreen=1 taskType=1 mTaskToReturnTo=0
    rootWasReset=false mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
    Activities=[ActivityRecord{9997f10 u0 com.android.launcher3/.Launcher t88}]
    askedCompatMode=false inRecents=true isAvailable=true
    lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/88_task_thumbnail.png
    stackId=0
    hasBeenVisible=true mResizeMode=RESIZE_MODE_FORCE_RESIZEABLE isResizeable=false firstActiveTime=1601263245268 lastActiveTime=1601263245268 (inactive for 38s)
    * Hist #0: ActivityRecord{9997f10 u0 com.android.launcher3/.Launcher t88}
    packageName=com.android.launcher3 processName=com.android.launcher3
    launchedFromUid=0 launchedFromPackage=null userId=0
    app=ProcessRecord{7996cfe 5669:com.android.launcher3/u0a23}
    Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher }
    frontOfTask=true task=TaskRecord{a9ad0b9 #88 A=com.android.launcher3 U=0 StackId=0 sz=1}
    taskAffinity=com.android.launcher3
    realActivity=com.android.launcher3/.Launcher
    baseDir=/system/app/XXXLauncher3/XXXLauncher3.apk
    dataDir=/data/user/0/com.android.launcher3
    stateNotNeeded=true componentSpecified=false mActivityType=1
    compat={320dpi} labelRes=0x7f0a0001 icon=0x7f030001 theme=0x7f0d0002
    config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w360dp h568dp 320dpi nrml port finger -keyb/v/h -nav/h s.5}
    taskConfigOverride={1.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}
    taskDescription: iconFilename=null label="null" color=ff222222
    launchFailed=false launchCount=0 lastLaunchTime=-1h27m5s112ms
    haveState=true icicle=Bundle[mParcelledData.dataSize=3940]
    state=STOPPED stopped=true delayedResume=false finishing=false
    keysPaused=false inHistory=true visible=false sleeping=false idle=true mStartingWindowState=STARTING_WINDOW_NOT_SHOWN
    fullscreen=true noDisplay=false immersive=false launchMode=2
    frozenBeforeDestroy=false forceNewConfig=false
    mActivityType=HOME_ACTIVITY_TYPE
    waitingVisible=false nowVisible=false lastVisibleTime=-39s442ms
    resizeMode=RESIZE_MODE_FORCE_RESIZEABLE

    Task id #94//Task对应的ID
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
    * TaskRecord{ca4459f #94 A=com.android.systemui U=0 StackId=0 sz=1}
    userId=0 effectiveUid=u0a14 mCallingUid=u0a14 mUserSetupComplete=true mCallingPackage=com.android.systemui
    affinity=com.android.systemui
    intent={flg=0x10804000 cmp=com.android.systemui/.recents.RecentsActivity bnds=[32,1024][688,1840]}
    realActivity=com.android.systemui/.recents.RecentsActivity
    autoRemoveRecents=false isPersistable=false numFullscreen=1 taskType=2 mTaskToReturnTo=1
    rootWasReset=false mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
    Activities=[ActivityRecord{f344048 u0 com.android.systemui/.recents.RecentsActivity t94}]
    askedCompatMode=false inRecents=true isAvailable=true
    lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/94_task_thumbnail.png
    stackId=0
    hasBeenVisible=true mResizeMode=RESIZE_MODE_RESIZEABLE isResizeable=true firstActiveTime=1601263239735 lastActiveTime=1601263239735 (inactive for 44s)
    * Hist #0: ActivityRecord{f344048 u0 com.android.systemui/.recents.RecentsActivity t94}
    packageName=com.android.systemui processName=com.android.systemui
    launchedFromUid=10014 launchedFromPackage=com.android.systemui userId=0
    app=ProcessRecord{3142ae0 4683:com.android.systemui/u0a14}
    Intent { flg=0x10804000 cmp=com.android.systemui/.recents.RecentsActivity bnds=[32,1024][688,1840] }
    frontOfTask=true task=TaskRecord{ca4459f #94 A=com.android.systemui U=0 StackId=0 sz=1}
    taskAffinity=com.android.systemui
    realActivity=com.android.systemui/.recents.RecentsActivity
    baseDir=/system/priv-app/SystemUI/SystemUI.apk
    dataDir=/data/user_de/0/com.android.systemui
    stateNotNeeded=true componentSpecified=true mActivityType=2
    compat={320dpi} labelRes=0x7f0f0257 icon=0x7f020159 theme=0x7f1301e3
    config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w360dp h568dp 320dpi nrml port finger -keyb/v/h -nav/h s.5}
    taskConfigOverride={1.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}
    taskDescription: iconFilename=null label="null" color=ff212121
    launchFailed=false launchCount=0 lastLaunchTime=-1m32s445ms
    haveState=true icicle=Bundle[mParcelledData.dataSize=500]
    state=STOPPED stopped=true delayedResume=false finishing=false
    keysPaused=false inHistory=true visible=false sleeping=false idle=true mStartingWindowState=STARTING_WINDOW_NOT_SHOWN
    fullscreen=true noDisplay=false immersive=false launchMode=3
    frozenBeforeDestroy=false forceNewConfig=false
    mActivityType=RECENTS_ACTIVITY_TYPE
    waitingVisible=false nowVisible=false lastVisibleTime=-46s419ms
    resizeMode=RESIZE_MODE_RESIZEABLE

    Running activities (most recent first):
    TaskRecord{a9ad0b9 #88 A=com.android.launcher3 U=0 StackId=0 sz=1}
    Run #1: ActivityRecord{9997f10 u0 com.android.launcher3/.Launcher t88}
    TaskRecord{ca4459f #94 A=com.android.systemui U=0 StackId=0 sz=1}
    Run #0: ActivityRecord{f344048 u0 com.android.systemui/.recents.RecentsActivity t94}

    mLastPausedActivity: ActivityRecord{9997f10 u0 com.android.launcher3/.Launcher t88}

    //当前持有焦点的Activity
    mFocusedActivity: ActivityRecord{dac4005 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t96}
    //持有焦点的ActivityStack
    mFocusedStack=ActivityStack{d2f835e stackId=1, 2 tasks} mLastFocusedStack=ActivityStack{d2f835e stackId=1, 2 tasks}
    mSleepTimeout=false
    mCurTaskIdForUser={0=96}
    mUserStackInFront={}
    mActivityContainers={0=ActivtyContainer{0}A, 1=ActivtyContainer{1}A}
    mLockTaskModeState=NONE mLockTaskPackages (userId:packages)=
    0:[]
    mLockTaskModeTasks[]

    二.为目标Activity查找/分配或者创建最优Task栈

      接着我们前面博客Android四大组件之Activity启动流程源码实现详解(一)未完成之使命,继续分析AS.startActivityLocked方法。在正式分析之前,我要在此提前打一个预防针,这是因为该方法涉及的知识点非常多,并且代码也很多,所以各位小伙们一定打起精神一鼓作气的将其拿下来(当然小伙们也可以抛开此章节,直接进入第三大章节分析后面的流程,因为这个并不影响Activity启动的整体流程分析)!
      startActivityLocked方法主要从代码逻辑上可以分为两大部分来阐述:

  • 第一大部分:
    1、初始化Activity启动状态
    2、计算launchFlag
    3、计算调用者的ActivityStack
    4、检查是否存在复用的TaskRecord
    5、对于存在复用的TaskRecord则进行相应的ActivityStack、TaskRecord的移动(说实话,我也没有真的搞懂,希望这块比较有经验的小伙们能和我一起学习)
    6、计算当前启动Activity所属的TaskRecord
    7、把当前启动的Activity放到所属TaskRecord的栈顶
  • 第二大部分:
    8、最后调用resumeFocusedStackTopActivityLocked创建正在启动的Activity、Paused当前resumed的Activity,
    9、以及resumed当前启动的Activity

    本大章节将重点分析第一大部分内容,不要问我有多少,我只能说很多很多!

    //[ActivityStarter.java]
    /* 这里的sourceRecord是指发起调用者
    r待启动的ActivityRecord,这是是在前面创建的一个ActivityRecord对象
    startFlags表示启动目标Activity的flag,取值为0,
    doResume表示是否要将Activity推入Resume状态,从上一个方法传入进来的参数值为true
    */
    private int startActivityUnchecked(final ActivityRecord r,
    ActivityRecord sourceRecord,
    IVoiceInteractionSession voiceSession,
    IVoiceInteractor voiceInteractor,
    int startFlags, boolean doResume,
    ActivityOptions options,
    TaskRecord inTask) {

    //初始化Activity启动的一些状态,这里主要是根据启动模式的相关设置进行了一些变量的处理。比如newtask,document等等
    //初始化Activity启动状态,获取launchmode flag 同时解决一些falg和launchmode的冲突
    setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
    voiceInteractor);//详见章节2.1

    //计算目标Activity的launchMode模式
    computeLaunchingTaskFlags();//详见章节2.2

    //确定发起端的ActivityStack情况
    computeSourceStack();//详见章节1.3

    mIntent.setFlags(mLaunchFlags);//把前面解析得到的mLaunchFlags,设置目标Activity的launchMode启动模式

    // 根据mLaunchFlags来查找是否有可重用的activity
    /**
    * 这边主要是判断当前启动的Activity是否存在可以利用的Task
    * 当启动模式launchMode为singleTask、singleInstance,或者启动时
    * Flag设置为FLAG_ACTIVITY_NEW_TASK并没设置FLAG_ACTIVITY_MULTIPLE_TASK
    * 并且当前启动的Activity不是以startActivityForResult启动的,
    * 满足以上情况才会寻找是否存在有复用的Task。
    * 匹配规则:
    * 1、对于启动模式为singleInstance,遍历所有ActivityStack和Task的堆栈中查找
    *是否存在以当前启动Activity相同的Activity。
    * 2、其它情况下,遍历所有ActivityStack和Task的堆栈,查找Task中intent变量
    *是否当前启动Activity相匹配,如果不存在,则去匹配task的亲和性(即
    *在AndroidManifest中android:taskAffinity定义的。
    */
    mReusedActivity = getReusableIntentActivity();//详见2.4

    final int preferredLaunchStackId =
    (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;//此时mOptions为null

    //如果找到了可重用的activity,需要清理掉原来的信息,并把当前启动的activity的信息拷贝进去
    //做清理和拷贝工作...
    if (mReusedActivity != null) {//详见章节2.5

    ...
    //设置当前启动Activity的Task为复用的Task
    if (mStartActivity.task == null) {
    mStartActivity.task = mReusedActivity.task;
    }
    if (mReusedActivity.task.intent == null) {
    mReusedActivity.task.setIntent(mStartActivity);
    }

    /*
    *这边处理启动时设置FLAG_ACTIVITY_CLEAR_TOP时,要清除复用Task中存在与当前启动
    *Activity相同的Activity之上的Activity
    *举个例子:比如复用Task1中存在有Activity A,B,C,D,此时正在启动的Activity B,那么C**和D也要finish,另外此时如果B *为标准启动模式,并且没有设置FLAG_ACTIVITY_SINGLE_TOP,那么B也会finish。具体的读者可以跟进
    *mReusedActivity.task.performClearTaskForReuseLocked看下。
    */
    if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
    || mLaunchSingleInstance || mLaunchSingleTask) {
    final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
    mStartActivity, mLaunchFlags);
    if (top != null) {
    if (top.frontOfTask) {
    top.task.setIntent(mStartActivity);
    }
    ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
    // 没必要新建实例,回调onNewIntent并将top移至前台
    top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
    mStartActivity.launchedFromPackage);
    }
    }

    // 计算哪个task和activity要移至前台,必要时会进行task的清理工作
    mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity);

    if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
    resumeTargetStackIfNeeded();
    return START_RETURN_INTENT_TO_CALLER;
    }
    //根据复用情况设置task
    setTaskFromIntentActivity(mReusedActivity);

    //mAddingToTask为true表示要新建,mReuseTask为空表示task被清除了
    if (!mAddingToTask && mReuseTask == null) {
    resumeTargetStackIfNeeded();
    return START_TASK_TO_FRONT;
    }
    }

    if (mStartActivity.packageName == null) {
    if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
    mStartActivity.resultTo.task.stack.sendActivityResultLocked(
    -1, mStartActivity.resultTo, mStartActivity.resultWho,
    mStartActivity.requestCode, RESULT_CANCELED, null);
    }
    ActivityOptions.abort(mOptions);
    return START_CLASS_NOT_FOUND;
    }

    final ActivityStack topStack = mSupervisor.mFocusedStack;
    final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
    final boolean dontStart = top != null && mStartActivity.resultTo == null
    && top.realActivity.equals(mStartActivity.realActivity)
    && top.userId == mStartActivity.userId
    && top.app != null && top.app.thread != null
    && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
    || mLaunchSingleTop || mLaunchSingleTask);
    if (dontStart) {
    ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
    topStack.mLastPausedActivity = null;
    if (mDoResume) {
    mSupervisor.resumeFocusedStackTopActivityLocked();
    }
    ActivityOptions.abort(mOptions);
    if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
    return START_RETURN_INTENT_TO_CALLER;
    }
    top.deliverNewIntentLocked(
    mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
    mSupervisor.handleNonResizableTaskIfNeeded(
    top.task, preferredLaunchStackId, topStack.mStackId);

    return START_DELIVERED_TO_TOP;
    }

    boolean newTask = false;
    final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
    ? mSourceRecord.task : null;

    if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
    && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
    newTask = true;
    // 重用或者新建task
    setTaskFromReuseOrCreateNewTask(taskToAffiliate);

    if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
    Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
    return START_RETURN_LOCK_TASK_MODE_VIOLATION;
    }
    if (!mMovedOtherTask) {
    updateTaskReturnToType(mStartActivity.task, mLaunchFlags, topStack);
    }
    } else if (mSourceRecord != null) {
    if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
    Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
    return START_RETURN_LOCK_TASK_MODE_VIOLATION;
    }

    // 不是新建task的,重用原activity的task
    final int result = setTaskFromSourceRecord();
    if (result != START_SUCCESS) {
    return result;
    }
    } else if (mInTask != null) {
    if (mSupervisor.isLockTaskModeViolation(mInTask)) {
    Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
    return START_RETURN_LOCK_TASK_MODE_VIOLATION;
    }

    final int result = setTaskFromInTask();
    if (result != START_SUCCESS) {
    return result;
    }
    } else {
    setTaskToCurrentTopOrCreateNewTask();
    }

    mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
    mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);

    if (mSourceRecord != null && mSourceRecord.isRecentsActivity()) {
    mStartActivity.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
    }
    if (newTask) {
    EventLog.writeEvent(
    EventLogTags.AM_CREATE_TASK, mStartActivity.userId, mStartActivity.task.taskId);
    }
    ActivityStack.logStartActivity(
    EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task);
    mTargetStack.mLastPausedActivity = null;

    /*把当前启动的Activity加入TaskRecord以及绑定WindowManagerService*/
    mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
    ...
    return START_SUCCESS;
    }

    该部分代码很长,很长!但是没有办法,阅读源码就是这么操蛋,我们只能一步步分解,强行分析了!


    2.1 AS.setInitialState设置数据初始化状态

    //[ActivityStarter.java]
    private void setInitialState(ActivityRecord r,//表示要启动的目标Activity信息
    ActivityOptions options, //options是附件信息,此时为null
    TaskRecord inTask,
    boolean doResume, //此处的doResume的值为true
    int startFlags, //这里传入的startFlags为0
    ActivityRecord sourceRecord,//发起端的Activity信息
    IVoiceInteractionSession voiceSession,
    IVoiceInteractor voiceInteractor) {
    reset();//对所有变量进行重置

    mStartActivity = r;//将要启动的目标Activiyt信息赋值给mStartActivity
    mIntent = r.intent;
    mOptions = options;
    mCallingUid = r.launchedFromUid;
    mSourceRecord = sourceRecord;
    mVoiceSession = voiceSession;
    mVoiceInteractor = voiceInteractor;

    mLaunchBounds = getOverrideBounds(r, options, inTask);
    //获取Activity的启动模式,这些值是从<activity>标签中读取的,即目标Activity所定义的启动方式
    // 除了目标Activity定义的启动模式外,调用者也可以设置Activity的启动模式
    // 这些参数都体现在Intent的Flags中
    mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP;
    mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;
    mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;

    /*
    这里会根据启动模式来调整flag到NEW_DOCUMEN 如果intent中的和mainfest中的冲突,那么manfest的启动模式优先
    FLAG_ACTIVITY_NEW_DOCUMENT是打开一个文件的标识
    其处理流程遵循如下逻辑:
    1、如果此Activity是由singleInstance或者singleTask的话且flag带了NEW_DOCUMENT,则需要去掉NEW_DOCUMENT和MULTIPLE_TASK的flag
    2、如果不属于第一种情况则读取ActivityInfo中的documentLaunchMode来对flag赋值
    */
    mLaunchFlags = adjustLaunchFlagsToDocumentMode(
    r, mLaunchSingleInstance, mLaunchSingleTask, mIntent.getFlags());

    // 是否为后台启动任务的标志位
    mLaunchTaskBehind = r.mLaunchTaskBehind
    && !mLaunchSingleTask && !mLaunchSingleInstance
    && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;

    /*如果是newTask的启动模式,那么会将resultTo设置为null。
    *这里做了一个处理。这个活动被启动到一个新的任务中,而且还需要得到请求结果。
    *那么,这是相当混乱的,因此,立即发送回一个取消,让新的任务继续启动像往常一样,不依赖于它的发起者
    *也就是newTask的启动模式,是无法获取到请求结果的*/
    sendNewTaskResultRequestIfNeeded();

    //如果设置了NEW_DOCUMENT标志同时此Activity不是其他Activity启动的
    //则在加上NEW_TASK的标志
    if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
    mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
    }

    if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
    //对于后台启动的新任务,可以多任务运行
    if (mLaunchTaskBehind
    || r.info.documentLaunchMode == DOCUMENT_LAUNCH_ALWAYS) {
    mLaunchFlags |= FLAG_ACTIVITY_MULTIPLE_TASK;
    }
    }

    mSupervisor.mUserLeaving = (mLaunchFlags & FLAG_ACTIVITY_NO_USER_ACTION) == 0;

    mDoResume = doResume;//此时的doReume为true所以不会走入此分支
    //当本次不需要resume时,则设置为延迟resume的状态
    if (!doResume || !mSupervisor.okToShowLocked(r)) {
    r.delayedResume = true;
    mDoResume = false;
    }

    //此时mOptions为null不会走入此分支
    if (mOptions != null && mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) {
    r.mTaskOverlay = true;
    final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
    final ActivityRecord top = task != null ? task.getTopActivity() : null;
    if (top != null && !top.visible) {

    mDoResume = false;
    mAvoidMoveToFront = true;
    }
    }

    /**FLAG_ACTIVITY_PREVIOUS_IS_TOP:
    *如果给Intent对象设置了这个标记,这个Intent对象被用于从一个存在的Activity中启动一个新的Activity,
    *那么新的这个 Activity不能用于接受发送给顶层activity的intent,这个新的activity的前一个activity被作为顶部activity
    *如果设置FLAG_ACTIVITY_PREVIOUS_IS_TOP,当前Activity不会作为栈顶来启动新的Activity而是把当前Activity的前一个作为栈顶.简而言之,栈ABC启动D则栈变成ABD。所以sourceRecord设置为null
    */
    mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;

    mInTask = inTask;
    if (inTask != null && !inTask.inRecents) {
    Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
    mInTask = null;
    }

    mStartFlags = startFlags;
    //我们传入的startFlags为0不会走入此分支
    if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
    ActivityRecord checkedCaller = sourceRecord;
    if (checkedCaller == null) {
    checkedCaller = mSupervisor.mFocusedStack.topRunningNonDelayedActivityLocked(
    mNotTop);
    }
    if (!checkedCaller.realActivity.equals(r.realActivity)) {
    //调用者 与将要启动的Activity不相同时,进入该分支
    mStartFlags &= ~START_FLAG_ONLY_IF_NEEDED;
    }
    }
    //是否有动画
    mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
    }
    private void reset() {
    mStartActivity = null;
    mIntent = null;
    mCallingUid = -1;
    mOptions = null;

    mLaunchSingleTop = false;
    mLaunchSingleInstance = false;
    mLaunchSingleTask = false;
    mLaunchTaskBehind = false;
    mLaunchFlags = 0;

    mLaunchBounds = null;

    mNotTop = null;
    mDoResume = false;
    mStartFlags = 0;
    mSourceRecord = null;

    mInTask = null;
    mAddingToTask = false;// 表示是否在传入的inTask中启动Actiivty,后面会根据实际情况重新设置该变量
    mReuseTask = null;

    mNewTaskInfo = null;
    mNewTaskIntent = null;
    mSourceStack = null;

    mTargetStack = null;
    mMovedOtherTask = false;
    mMovedToFront = false;
    mNoAnimation = false;
    mKeepCurTransition = false;
    mAvoidMoveToFront = false;

    mVoiceSession = null;
    mVoiceInteractor = null;
    }

      在正式开始掰持掰持上述源码前,我们先来捣鼓捣鼓几个概念,因为源码中会有涉及到,当然这部分知识我在博客中Android四大组件之Activity启动流程源码实现详解概要也有提到过:

  • 启动模式(launchMode):
    //[ActivityInfo.java]
    public class ActivityInfo extends ComponentInfo
    implements Parcelable {
    ...
    public static final int LAUNCH_MULTIPLE = 0;
    public static final int LAUNCH_SINGLE_TOP = 1;
    public static final int LAUNCH_SINGLE_TASK = 2;
    public static final int LAUNCH_SINGLE_INSTANCE = 3;
    ...
    }

    启动模式 对应特点

    LAUNCH_MULTIPLE(standard)每次启动新Activity,都会创建新的Activity,这是最常见标准情形LAUNCH_SINGLE_TOP(singleTop)当启动新Acitity,在栈顶存在相同Activity,则不会创建新Activity;其余情况同上LAUNCH_SINGLE_TASK(singleTask)当启动新Acitity,在栈中存在相同Activity(可以是不在栈顶),则不会创建新Activity,而是移除该Activity之上的所有Activity;其余情况同上LAUNCH_SINGLE_INSTANCE(singleInstance)每个Task栈只有一个Activity,其余情况同上

  • 启动Activity的flag常用值:
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    启动Activity常用Flag值 对应特点

    FLAG_ACTIVITY_NEW_TASK将Activity放入一个新启动的TaskFLAG_ACTIVITY_CLEAR_TASK启动Activity时,将目标Activity关联的Task清除,再启动该Task,将该Activity放入该Task,也就是说,这个新启动的activity变为了这个空Tas的根activity.所有老的activity都结束掉。该flags跟FLAG_ACTIVITY_NEW_TASK配合使用 FLAG_ACTIVITY_CLEAR_TOP启动非栈顶Activity时,先清除该Activity之上的Activity。例如Task已有A、B、C三个Activity,启动A,则清除B,C。类似于SingleTop FLAG_ACTIVITY_PREVIOUS_IS_TOP如果给Intent对象设置了这个标记,这个Intent对象被用于从一个存在的Activity中启动一个新的Activity,那么新的这个 Activity不能用于接受发送给顶层activity的intent,这个新的activity的前一个activity被作为顶部activity START_FLAG_ONLY_IF_NEEDED该flag表示只有在需要的时候才启动目标Activity。也就是说如果调用者和被启动的是一个,那么就没有必要去进行重复的步骤了

    好了,让我们来开始分析源码setInitialState方法的业务逻辑,主要就是进行一些初始化,如下:

    首先调用通过reset方法,直接将所需要修改的变量进行了重置优化处理启动模式:
    1.如果是newTask,则将resultTo设置为空
    2.对FLAG_ACTIVITY_NEW_DOCUMENT的文档标识的处理
    3.对FLAG_ACTIVITY_PREVIOUS_IS_TOP启动标志的处理
    4.记录动画标识


    2.2 AS.computeLaunchingTaskFlags计算目标Activity的Task的flag

      是不是被1.1章节涉及到的概念整懵了,这还没有完呢,又要开始了!这就是我所说的为啥说本大章节是Activity中最难突破的点,那也啥办法呢只能一点点突破了!在正式开始该部分的源码分析前是时候放出看家法宝了(Android四大组件之Activity启动流程源码实现详解概要有简单掰扯过)!Android四大组件之Activity启动流程源码实现详解(二)

    //[ActivityStarter.java]
    /**
    根据launchMode和Intent中的FLAG_ACTIVITY_NEW_TASK等flag综合计算activity的启动模式,
    结果保存在mLaunchFlags中。计算的过程不仅要考虑目标activity的launchMode,
    也要考虑原来activity的launchMode和Intent中所带着的flag
    */
    private void computeLaunchingTaskFlags() {
    //当调用者不是来自Activity,但是又明确指定指定了目标task运行该Activity的话,这个情况比较少见
    if (mSourceRecord == null && mInTask != null && mInTask.stack != null) {
    //查找任务栈mInTask的intent信息,
    final Intent baseIntent = mInTask.getBaseIntent();
    /*
    TaskRecord由多个activityRecord组成,是我们平时所说的任务栈,
    里面包含着它所管理的activity列表(其中的关系详见上述图示)
    这里返回第一个没有结束的activity
    */
    final ActivityRecord root = mInTask.getRootActivity();
    if (baseIntent == null) {
    ActivityOptions.abort(mOptions);
    throw new IllegalArgumentException("Launching into task without base intent: "
    + mInTask);
    }

    if (mLaunchSingleInstance || mLaunchSingleTask) {
    /*
    如果启动模式是LAUNCH_SINGLE_INSTANCE或者LAUNCH_SINGLE_TASK,
    那么必须保证堆栈是他们所运行的堆栈,否则就抛出异常
    */
    if (!baseIntent.getComponent().equals(mStartActivity.intent.getComponent())) {
    ActivityOptions.abort(mOptions);
    throw new IllegalArgumentException("Trying to launch singleInstance/Task "
    + mStartActivity + " into different task " + mInTask);
    }
    if (root != null) {
    ActivityOptions.abort(mOptions);
    throw new IllegalArgumentException("Caller with mInTask " + mInTask
    + " has root " + root + " but target is singleInstance/Task");
    }
    }

    /*
    如果根部为空,说明里面还没有activity,可以把我们要启动的activity作为它的rootTask启动,
    所以会对这个task做初始化操作
    */
    if (root == null) {
    final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK
    | FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS;
    mLaunchFlags = (mLaunchFlags & ~flagsOfInterest)
    | (baseIntent.getFlags() & flagsOfInterest);
    mIntent.setFlags(mLaunchFlags);
    mInTask.setIntent(mStartActivity);
    //mAddingToTask这个变量表示已经找到某个task来放置Activity,
    //有可能是启动时指定的task还有可能是启动的sourceTask,反正就是不用再去遍历寻找task
    mAddingToTask = true;//标记是否增加到栈中
    } else if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
    //当前栈根部不为空,但是启动模式是FLAG_ACTIVITY_NEW_TASK,那么不需要添加新的activity,
    //只要直接把当前task带到前台显示即可,这个地方需要重点关注一下
    mAddingToTask = false;
    } else {
    //不是一个空的task,并且也没有设置FLAG_ACTIVITY_NEW_TASK启动参数,所以需要添加一个activity到这个task中,设置 mAddingToTask = true
    mAddingToTask = true;
    }

    //说明用户指定的task是可用的,设置mReuseTask = mInTask
    mReuseTask = mInTask;
    } else {
    mInTask = null;
    /*
    此时sourceRecord不为空或者用户没有指定mInTask。这种情况就需要设置mInTask为null,因为sourceRecord优先级大于mInTask. 这个条件还对特殊情况做了处理,保证要启动的activity尽量放到SourceRecord 之上
    */
    if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null
    && mSourceRecord.isFreeform()) {
    mAddingToTask = true;
    }
    }

    if (mInTask == null) {
    if (mSourceRecord == null) {//未指定Task且没有sourceRecord,//根据调用方和要启动的activty的启动模式来进行调整。将acitivty启动模式调整为为newTask
    //调用者并不是Activity context,则强制创建新task
    if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {//如果其源任务栈也不存在,无法附加要启动的activity到sourceRecord的task中,则强制新建Task
    Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
    "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
    mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
    }
    } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
    //发起调用者的Activity带有single instance,这种activity只能自己独自在一个task上,
    //所以新启动的activity也要添加FLAG_ACTIVITY_NEW_TASK参数,在新的task上启动activity
    mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
    } else if (mLaunchSingleInstance || mLaunchSingleTask) {
    //目标Activity带有single instance或者single task,则创建新task
    mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
    }
    }
    }

      这细节分析起来的太操蛋了,太多细枝末节的东西了,看来Activity的TaskRecord的处理真的是一个难点啊!在computeLaunchingTaskFlags方法中根据发起端/目的端的launchMode和以及Intent中的FLAG_ACTIVITY_NEW_TASK等flag综合计算activity的启动模式,并且主要分了两个大类情况来处理:

  • 发起端的ActivityRecord信息记录为空,但是明确指定要启动的Activity所在的任务栈

    要使用的任务栈必须有baseIntent。也就是必须有任务栈创建时所使用的intent信息,否则抛异常如果启动模式是 singleInstance 或者 singleTask ,那么要使用的任务栈的根ActivityRecorkd必须为空。而且启动任务栈所使用的Component必须是当前Component。否则扔异常如果任务栈的根AcitivityRecord为空,那么指定的mInTask其实就是一个新的任务栈,修改启动模式mLaunchFlags 。并且标记mAddingToTask为true如果任务栈的根AcitivityRecord不为空,并且启动标识有newTask。那么标记mAddingToTask为false如果任务栈的根AcitivityRecord不为空,并且启动标识不为newTask。那么标记mAddingToTask为true将要启动的任务栈赋值给可复用的任务栈mReuseTask

  • 剩下的情况就是发起端的ActivityRecord信息记录不为空或者没有指定mInTask。这种情况直接将指定的mInTask清空

    上述操作猛如虎工资2500!当上述两种情况处理完成以后,上述方法会进行一次判断处理,如果指定运行的任务栈mInTask为空(包括没有设置,或者后来清空),那么会分情况对启动标识进行调整:

    如果调用方AcitivityRecord信息为空,这时候将要启动的目标acitivity既无法附加到调用方的任务栈中,也没有指定的执行的任务栈mInTask存在,那么此时Android系统只能直接强制将其增加newTaks启动标识,在新的任务栈中启动如果调用方的AcitivityRecord携带有启动标识位singleInstance,那么说明调用方需要独自在一个任务栈上,要启动的目标acitivity也无法附加到其任务栈,那么这时候直接将其增加newTaks启动标识,在新的任务栈中启动。如果要启动目标Activity的启动模式是singTask,或者singleInstance。那么增加newTaks启动标识

    分析至此我们可以得出一个结论就是computeLaunchingTaskFlags的主要功能就是根据发起端/目的端的launchMode和以及Intent中的携带的FLAG_ACTIVITY_NEW_TASK等flag综合计算activity的启动模式或者说调整启动目标Activiyt的启动模式。


    2.3 AS.computeSourceStack计算发起方Activity的栈

    //[ActivityStarter.java]
    //确定发起端的Stack情况
    private void computeSourceStack() {
    if (mSourceRecord == null) {
    mSourceStack = null;
    return;
    }
    if (!mSourceRecord.finishing) {
    //当调用者Activity不为空,且不处于finishing状态,则其所在栈赋于sourceStack
    mSourceStack = mSourceRecord.task.stack;
    return;
    }
    //如果调用方已经finish了,那么就无法将其作为我们的源任务栈了,这时候,要强行添加FLAG_ACTIVITY_NEW_TASK标志使activity启动到一个新的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;
    //保存task的intent信息和taskinfo信息是为了新建task的时候尝试恢复这个task
    mNewTaskInfo = mSourceRecord.info;
    mNewTaskIntent = mSourceRecord.task.intent;
    }
    mSourceRecord = null;
    mSourceStack = null;
    }

      好家伙嘛!终于来了一个简单点的逻辑了,分为三部分处理:

    如果发起方的Activity的mSourceRecord为null,那么发起方Activity的栈就置为null吗,没有儿子那来的父母不是如果发起方的mSourceRecord不为null,且没有被结束的话,直接是从发起方的ActivityRecord拿到ActivityStack对象而如果发起方已经结束了,则添加newTask标识来启动新的任务


    2.4 AS.getReusableIntentActivity查找可复用的Activity

    //[ActivityStarter.java]
    private ActivityRecord getReusableIntentActivity() {
    /*
    标识是否可以放入一个已经存在的栈
    该条件成立的前提是:
    1.判断方法是设置了FLAG_ACTIVITY_NEW_TASK,但是并非MULTIPLE_TASK
    2.或者LAUNCH_SINGLE_INSTANCE或者LAUNCH_SINGLE_TASK模式
    */
    boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
    (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
    || mLaunchSingleInstance || mLaunchSingleTask;
    //还要根据目标Activiyt任务栈是否为空来进行判断
    putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
    ActivityRecord intentActivity = null;
    if (mOptions != null && mOptions.getLaunchTaskId() != -1) {//跳过此处
    ...
    } else if (putIntoExistingTask) {//可以放入一个已经存在的Task栈
    if (mLaunchSingleInstance) {//启动模式是LAUNCH_SINGLE_INSTANCE,那么因为其是一种全局唯一的,需要进行搜索遍历
    /*
    findActivityLocked方法根据传入的Intent和ActivityInfo这两个参数可以获取一个Activity的包名,
    该方法会从栈顶至栈底遍历ActivityStack中的所有Activity,如果包名匹配成功,就返回
    */
    intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, false);
    } else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
    intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
    !mLaunchSingleTask);
    } else {
    //这里是最常见的形式,mStartActivity是需要启动的Activity,intentActivity是找到的可用的Task中顶部的Activity
    /*
    该方法的功能是找到目标ActivityRecord(target)所在的任务栈(TaskRecord),如果找到,则返回栈顶的ActivityRecord,否则,返回null
    */
    intentActivity = mSupervisor.findTaskLocked(mStartActivity);
    }
    }
    return intentActivity;
    }

      getReusableIntentActivity方法主要是来查找是否有可以重用的activity,这个只对启动模式为LAUNCH_SINGLE_INSTANCE和LAUNCH_SINGLE_TASK或者FLAG_ACTIVITY_NEW_ TASK不为0的Activity才有用,对于standard的activity,该方法永远返回null。
    如果putIntoExistingTask为true表示可以进行复用,那么接着就根据情况进行不同的遍历查找:

    启动模式是singleInstance。这种启动模式属于全局唯一的。通过ASS的findActivity 方法来查找是否存在可以复用的Activity如果启动表示有 FLAG_ACTIVITY_LAUNCH_ADJACENT ,也是通过通过ASS的findActivity的来查找是否存在可以复用的Activity其他情况则调用ASS的findTaskLocked方法来查找搜索是存在目标Activity所在的任务栈,如果找到则返回栈顶的ActiviytRecord

    对于以上的查找就不分析了,这个牵涉的东西太多了,后面打算开辟专门章节来分析。


    2.5 存在复用ActivityRecord处理

    假如此时我们找到了复用的ActivityRecord,我们看看Android是怎么对其进行相关处理的。

    //[ActivityStarter.java]
    private void startActivityUnchecked(ActivityRecord r,//表示要启动的目标Activity信息
    ActivityOptions options, //options是附件信息,此时为null
    TaskRecord inTask,
    boolean doResume, //此处的doResume的值为true
    int startFlags, //这里传入的startFlags为0
    ActivityRecord sourceRecord,//发起端的Activity信息
    IVoiceInteractionSession voiceSession,
    IVoiceInteractor voiceInteractor) {
    ...

    //如果找到了可重用的activity,需要清理掉原来的信息,并把当前启动的activity的信息拷贝进去
    //做清理和拷贝工作...
    /*
    此时当前的Task列表中存在有复用的Activity
    可能为相同的Activity或者具有相同的affinity的task
    如果是第一次启动某个应用或者从adb am中启动以及第一次启动Launcher
    那么复用的TaskRecord为null
    */
    if (mReusedActivity != null) {
    ...
    //设置当前启动Activity的Task为复用的Task
    if (mStartActivity.task == null) {
    mStartActivity.task = mReusedActivity.task;
    }
    //设置可以复用Activity所属的TaskRecord的初始intent为目标Activity的ActivityRecord
    if (mReusedActivity.task.intent == null) {
    mReusedActivity.task.setIntent(mStartActivity);
    }

    //清除task中复用的activity上面的activity
    if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
    || mLaunchSingleInstance || mLaunchSingleTask) {
    /*
    这边处理启动时设置FLAG_ACTIVITY_CLEAR_TOP时,要清除复用activity所属TaskRecord之上的activity
    举个例子:比如复用Task1中存在有Activity A,B,C,D,此时正在启动的Activity B,那么C和D也要finish
    如果找到的可复用的activity的launchMode为LAUNCH_MULTIPLE,并且目标Activity没有设置为FLAG_ACTIVITY_SINGLE_TOP那么此时也会将可复用activity清除
    对于要启动的activity的启动模式为LAUNCH_MULTIPLE的,performClearTaskForReuseLocked返回值top肯定是空的
    */
    final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
    mStartActivity, mLaunchFlags); //[详见章节2.6]
    if (top != null) {
    if (top.frontOfTask) {//如果该ActivityRecord是所属任务栈的root activity,那么将目标activity设置为栈顶的Activity
    top.task.setIntent(mStartActivity);
    }
    ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
    // 没必要新建实例,回调onNewIntent并将top移至前台
    top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
    mStartActivity.launchedFromPackage);
    }
    }

    // 将复用ActivityRecord所属TaskRecord移动到顶端,必要时会进行task的清理工作
    mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity); //详见章节[2.7]

    //对于复用Task情况下START_FLAG_ONLY_IF_NEEDED这个FLAG只是resumed
    //该flag表示只有在需要的时候才启动目标Activity。也就是说如果调用者和被启动的是一个,那么就没有必要去进行重复的步骤了
    if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
    //resume显示到前台
    resumeTargetStackIfNeeded();
    return START_RETURN_INTENT_TO_CALLER;
    }
    //根据intent情况设置TaskRecord
    setTaskFromIntentActivity(mReusedActivity);//[详见章节2.8]

    //如果不需要把当前启动的Activity增加到Task并且不存在复用Task
    //那么仅仅进行resumed过程
    //mAddingToTask为true表示要新建,mReuseTask为空表示task被清除了
    if (!mAddingToTask && mReuseTask == null) {
    //调用显示到前台
    resumeTargetStackIfNeeded();
    return START_TASK_TO_FRONT;
    }
    }
    ...
    }

      在找到可以复用的ActivityRecord以后,startActivityUnchecked方法的处理逻辑远远还没有结束,依旧会继续着相关逻辑的处理:

    如果目标Activity的所属TaskRecord为null,则将查找到的可复用的Activity的所属TaskRecord填充如果可复用Activity所属TaskRecord的初始Activity为null,则使用目标Activity填充当我们启动目标Activity时候如果设置了FLAG_ACTIVITY_CLEAR_TOP标志位,或者目标Activiyt在AndroidManifest中设置了singleTask/singleInstance等启动模式说明此时需要清掉TaskRecord的数据。这时候会调用 performClearTaskForReuseLocked 方法将目标Activity上面的所有的Activity,并将当前activity置顶并返回顶部的ActivityRecord信息。最后调用 deliverNewIntent 方法最后不管是否进行了栈顶数据的清除。接下来就要将我们可以复用的Activity所在的TaskRecord移动到其所在的ActivityStack的顶部


    2.6 TaskRecord.performClearTaskForReuseLocked

      本来想给上述标题添加一个中文注解,但是吗有时候真的是只可意会不可言传啊,上面的英文原文反而更觉贴切!

    //[TaskRecord.java]

    ActivityRecord performClearTaskForReuseLocked(
    ActivityRecord newR,//目标Activity
    int launchFlags//启动目标Activity的flag
    ) {
    mReuseTask = true;
    final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
    mReuseTask = false;
    return result;
    }

    final ArrayList<ActivityRecord> mActivities;//存储TaskRecord管理的ActivityRecord

    final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
    int numActivities = mActivities.size();
    //注意,此处是从TaskRecord的栈定开始遍历
    for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
    ActivityRecord r = mActivities.get(activityNdx);
    if (r.finishing) {
    continue;
    }
    //找到了合适的activity,那么所有位于它上面的目标都需要结束
    //注意此处的equal有被重写,主要通过判断报名和类名是否一直
    if (r.realActivity.equals(newR.realActivity)) {
    final ActivityRecord ret = r;

    for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
    r = mActivities.get(activityNdx);
    if (r.finishing) {
    continue;
    }
    ActivityOptions opts = r.takeOptionsLocked();
    if (opts != null) {
    ret.updateOptionsLocked(opts);
    }
    if (stack != null && stack.finishActivityLocked(
    r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
    --activityNdx;
    --numActivities;
    }
    }

    //如果要复用的activity是multi模式,并且目标Activity没有设置FLAG_ACTIVITY_SINGLE_TOP启动模式那么也会调用finish结束掉
    if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
    && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
    if (!ret.finishing) {
    if (stack != null) {
    stack.finishActivityLocked(
    ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
    }
    return null;
    }
    }

    return ret;
    }
    }

    return null;
    }

      performClearTaskForReuseLocked方法不是特别复杂,主要是遍历TaskRecord对象实例中的ActivityRecord列表mActivities,然后依据一定的规则清除可复用TaskRecord栈中的ActivityRecord,其遍历清除遵循的逻辑如下:

    以倒序方式遍历mActivities(即从尾部开始遍历,这个也符合栈的存储结构),查找到被复用的Activity找到被复用的Activity以后,往尾部一次循环,调用ActivityStack的 finishActivityLocked 方法来结束掉对应的Activity,并减少引用数经过上述遍历清楚规则以后,最后还有一个规则就是如果要复用的activity是multi模式,并且目标Activity没有设置FLAG_ACTIVITY_SINGLE_TOP启动模式那么也会调用finish结束掉,也会结束掉当前这个复用的Activity。并且返回null,如果这个返回了null的话,就不会调用复用的activity的 deliverNewIntent 方法,相当于会重新启动。

    经过上面的步骤以后,不管是否进行了栈顶数据的清除,接下来就要将我们可以复用的Activity所在的TaskRecord移动到其所在的ActivityStack的顶部。


    2.7 TaskRecord.setTargetStackAndMoveToFrontIfNeeded

      说实话这个博客中的各种Stack和Task的分析,我自己都要吐了,太残暴了这些个东西。尼玛,有啥办法只能硬啃了。我们接着分析setTargetStackAndMoveToFrontIfNeeded看看它是怎么处理我们将要启动Activity的Stack以及Task的,又是各种的一顿操作啊!

    //[TaskRecord.java]
    //这里的入参参数为可复用ActivityRecord
    private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) {
    //获取可复用ActivityRecord所属ActivityStack
    mTargetStack = intentActivity.task.stack;
    mTargetStack.mLastPausedActivity = null;

    //获取当前前台的ActivityStack,ASS中保存着所有的ActivityStack
    final ActivityStack focusStack = mSupervisor.getFocusedStack();
    //获取当前前台ActivityStack栈顶的ActivityRecord
    ActivityRecord curTop = (focusStack == null)
    ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);

    //判断顶部的栈是否符合要求(即判断现在栈顶的栈是否为能够复用的activityrecord所在的栈)
    if (curTop != null
    && (curTop.task != intentActivity.task || curTop.task != focusStack.topTask())
    && !mAvoidMoveToFront) {

    //增加一个标记,标识这个task是从任务栈的后面移动上来的
    mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);

    //这里的mSourceRecord表示的是发起端,此处是判断合法性
    if (mSourceRecord == null || (mSourceStack.topActivity() != null &&
    mSourceStack.topActivity().task == mSourceRecord.task)) {
    if (mLaunchTaskBehind && mSourceRecord != null) {
    intentActivity.setTaskToAffiliateWith(mSourceRecord.task);
    }
    mMovedOtherTask = true;

    //willclearTask表明是否同时使用了NEW_TASK 和 CLEAR_TASK的flag
    final boolean willClearTask =
    (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
    if (!willClearTask) {//不需要清空,那么就需要将复用的task移至栈顶

    //根据规则获取当前要启动activity所属的ActivityStack栈
    final ActivityStack launchStack = getLaunchStack(
    mStartActivity, mLaunchFlags, mStartActivity.task, mOptions);

    //当要启动的栈与目标一致或者要启动的栈为空。这是我们一般的标准流程。会调用moveTaskToFrontLocked方法,将当前栈移动到与用户交互的栈顶
    if (launchStack == null || launchStack == mTargetStack) {
    mTargetStack.moveTaskToFrontLocked(
    intentActivity.task, mNoAnimation, mOptions,
    mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
    mMovedToFront = true;
    //其它情况
    } else if (launchStack.mStackId == DOCKED_STACK_ID
    || launchStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
    if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
    //这边是把复用的Task移动到其它的ActivityStack
    mSupervisor.moveTaskToStackLocked(intentActivity.task.taskId,
    launchStack.mStackId, ON_TOP, FORCE_FOCUS, "launchToSide",
    ANIMATE);
    } else {
    mTargetStack.moveTaskToFrontLocked(intentActivity.task, mNoAnimation,
    mOptions, mStartActivity.appTimeTracker,
    "bringToFrontInsteadOfAdjacentLaunch");
    }
    mMovedToFront = true;
    }
    mOptions = null;
    }
    updateTaskReturnToType(intentActivity.task, mLaunchFlags, focusStack);
    }
    }
    //这边表示如果不需要Task移动,移动targetStack到前台
    if (!mMovedToFront && mDoResume) {
    mTargetStack.moveToFront("intentActivityFound");
    }

    mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.task, INVALID_STACK_ID,
    mTargetStack.mStackId);

    if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
    return mTargetStack.resetTaskIfNeededLocked(intentActivity, mStartActivity);
    }
    return intentActivity;
    }

      感觉分析这块的代码,每次都是对我脑细胞和精神的一次摧残啊!我们来看看这个方法的大致流程:

  • 从ASS中找到当前和用户交互ActivityStack,然后从ActivityStack中找到正在和用户交互的ActivityRecord。同时找到其所在的任务栈(TaskRecord)(此处这几者之间牵涉的关系详见章节一)

  • 当发现当前栈顶的TaskRecord和我们要启动的Activity所使用的TaskRecord不是同一个时,这时候如果设置的标志位不会清空栈顶的信息的话,需要将要目标TaskRecord移动到栈顶位置。但是这个移动也需要分情况来进行

    1.首先通过getLaunchStack方法获取目标ActivityStcak信息intentTask。
    2.这时候会比较我们要启动的ActivityStack和当前复用的ActivityRecord所对应的ActivityStack作比较,然后根据不同情况走不同的分支

    当要启动的栈(launchStack)与目标(mTargetStack)一致,或者要启动的栈为空。则调用 moveTaskToFrontLocked 将对应的TaskRecord移动到栈顶位置当要启动的栈(launchStack)为分屏模式且flag满足FLAG_ACTIVITY_LAUNCH_ADJACENT则调用ASS的moveTaskToStackLocked迁移到lauchStack 中要启动的栈是其它模式则调用moveTaskToFrontLocked 将对应的TaskRecord移动到栈顶位置
    2.7.1 ActivityStack.moveTaskToFrontLocked将TaskRecord移动到栈顶

    //[ActivityStack.java]
    //此处的入参TaskRecord为可以复用的TaskRecord
    final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, ActivityOptions options,
    AppTimeTracker timeTracker, String reason) {
    if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);

    final int numTasks = mTaskHistory.size();//获取AS中有多少TaskRecord
    final int index = mTaskHistory.indexOf(tr);//获取入参的tr在当前的AS中的位置
    if (numTasks == 0 || index < 0) {//异常情况处理
    if (noAnimation) {
    ActivityOptions.abort(options);
    } else {
    updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
    }
    return;
    }

    if (timeTracker != null) {
    for (int i = tr.mActivities.size() - 1; i >= 0; i--) {
    tr.mActivities.get(i).appTimeTracker = timeTracker;
    }
    }

    //将Task移动到ActivityStack的栈顶端
    insertTaskAtTop(tr, null);

    //获取到TaskRecord的栈顶activity
    ActivityRecord top = tr.getTopActivity();
    if (!okToShowLocked(top)) {//判断是否可见
    addRecentActivityLocked(top);
    ActivityOptions.abort(options);
    return;
    }

    //获取到ActivityStack中顶部正在运行的Activity
    //这时候stack的topActivity应该是上一步已经移到栈复用的Task
    ActivityRecord r = topRunningActivityLocked();

    /*
    更新AMS中的focusedActivity
    这边会把当前Activity所属的Stack移到栈顶,
    并且会更新ActivityStackSupervisor中的
    mLastFocusedStack、mFocusedStack这两个变量
    */
    mService.setFocusedActivityLocked(r, reason);

    if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
    if (noAnimation) {
    mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
    if (r != null) {
    mNoAnimActivities.add(r);
    }
    ActivityOptions.abort(options);
    } else {
    updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
    }

    //调用持有焦点的任务栈的顶部Activity的onResume()方法
    mStackSupervisor.resumeFocusedStackTopActivityLocked();
    EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);

    if (VALIDATE_TOKENS) {
    validateAppTokensLocked();
    }
    }

      前面我们简单的总结了moveTaskToFrontLocked的功能就是将TaskRecord移动到ActivityStack,其执行该流程的主要步骤如下:

    将可复用TaskRecord插入到ActivityStack的栈顶端,至于是那个ActivityStack这个要根据实际情况来定获取ActivityStack中顶部正在运行的Activity,这时候stack的topActivity应该是上一步已经移到栈复用的Task更新AMS中的focusedActivity,这边会把当前Activity所属的Stack移到栈顶调用持有焦点的任务栈的顶部Activity的onResume()方法

    让我们回过头来继续重看一下setTargetStackAndMoveToFrontIfNeeded方法,可以看到经过我们的分析可知此时当前启动Activity可以复用的Task已经移动到了栈顶了。

    到现在为止,我们已经可以复用的ActivityRecord的TaskRecord移动到交互栈顶。这时候还没有over战斗依然在进行,我们回到章节2.5看到此时会根据实际的情况对可复用的Activity信息,进行一些整理工作。


    2.8 AS.setTaskFromIntentActivity对复用Task根据intent情况继续处理

    //[ActivityStarter.java]
    //注意此时传入的参数为可复用ActivityRecord
    private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
    //设置了FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK标志位的复用的Task会finish所有的Activity,并且重新
    //更新复用Task信息的当前启动的Activit
    if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
    mReuseTask = intentActivity.task;
    mReuseTask.performClearTaskLocked();
    mReuseTask.setIntent(mStartActivity);
    mMovedOtherTask = true;
    } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
    || mLaunchSingleInstance || mLaunchSingleTask) {
    //清空栈,这里跟之前的2.6章节栈顶数据的清除操作相似,但是那里处理的是top不为空,这里处理的是top为空的情况,也就是launchMode == ActivityInfo.LAUNCH_MULTIPLE
    ActivityRecord top = intentActivity.task.performClearTaskLocked(mStartActivity,
    mLaunchFlags);
    if (top == null) {
    mAddingToTask = true;
    mSourceRecord = intentActivity;
    final TaskRecord task = mSourceRecord.task;
    if (task != null && task.stack == null) {
    mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
    null /* bounds */, mLaunchFlags, mOptions);
    mTargetStack.addTask(task,
    !mLaunchTaskBehind /* toTop */, "startActivityUnchecked");
    }
    }
    }
    任务栈顶部的activity和要启动的activity是同一个
    else if (mStartActivity.realActivity.equals(intentActivity.task.realActivity)) {
    //如果是sigleTop,那么就调用deliverNewIntent
    if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop)
    && intentActivity.realActivity.equals(mStartActivity.realActivity)) {
    ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity,
    intentActivity.task);
    if (intentActivity.frontOfTask) {//如果是栈的根activity,那么设置
    intentActivity.task.setIntent(mStartActivity);
    }
    intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
    mStartActivity.launchedFromPackage);
    } else if (!intentActivity.task.isSameIntentFilter(mStartActivity)) {
    //如果不是singleTop,那么认为是需要启动一个新的activity
    mAddingToTask = true;
    mSourceRecord = intentActivity;
    }
    } else if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
    // 对FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标志出处理,这个主要用于快捷图标和或者从通知启动,这种情况需要替换task最上面的activity,所以需要添加activity到task中
    mAddingToTask = true;
    mSourceRecord = intentActivity;
    } else if (!intentActivity.task.rootWasReset) {
    intentActivity.task.setIntent(mStartActivity);
    }
    }

      再接再厉继续分析,让我们看看此方法中会对可复用的Activity所在的ActivityStack和TaskRecord做怎么样的处理:

    如果设置了FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK标志位,那么mReuseTask设置为可以复用的intentActivity的任务栈如果设置了清空了FLAG_ACTIVITY_CLEAR_TOP栈或者使用了singleInstance或者singleTask的一种,此时会拿到顶部的Task,然后重新添加到ActivityStack中如果要启动的Activity和当前顶部的Activity是同一个,会根据情况调用onNewIntent方法

    此时对于可复用的的Activity所在的TaskRecord处理已经完全完结了,此时已经将TaskRecord移动到栈顶位置了,这其中的各种切换逻辑真的是眼花缭乱啊,让人搞得晕头转向!


    2.9 存在复用ActivityRecord处理小结

      存在复用ActivityRecord处理的处理已经分析完毕了,各位小伙们真的理解了吗!我想没有,因为我也么有绕出来,其中涉及的各种场景太多了,看来还是得带入实际情况进行分析,但是这个就脱离我们本篇的范畴了,因为我们本篇重点讲解Activity的启动主流程!我们这里还是简单的对存在复用ActivityRecord处理小结一下,经过上述繁琐的处理对于可复用的的Activity所在的TaskRecord已经移动到栈顶位置了,其基本的调用流程如下:

    AS.startActivityUnchecked(...)
    mReusedActivity.task.performClearTaskForReuseLocked(...)//清除task中复用的activity上面的activity
    AS.setTargetStackAndMoveToFrontIfNeeded(...)// 将复用ActivityRecord所属TaskRecordy和ActivityStack移动到顶端,必要时会进行task的清理工作
    AS.setTaskFromIntentActivity(...)//根据intent的情况对复用的Task进行调整

    如果读者朋友们,只想从整理上了解Activity的启动流程,那么第二大章节阅读过程中如果有问题也没有用关系,因为这个并不牵涉到整体流程的分析。


    2.10 继续AS.startActivityUnchecked未完成之使命处理目标Activity不存在的情况

      当存在复用ActivityRecord时,经过前面章节一系列的处理此时已将将可复用activty替换成现在的目标activty,也就不用新建task了。那么生活还得继续,让我们跳出reusedActivity不为空的情况,接着继续后续的分析。

    //[ActivityStarter.java]
    /* 这里的sourceRecord是指发起调用者
    r是指本次的将要启动的Activity
    startFlags为启动目标Activity设置的flag值
    doResume的值为true
    */
    private int startActivityUnchecked(final ActivityRecord r,
    ActivityRecord sourceRecord,
    IVoiceInteractionSession voiceSession,
    IVoiceInteractor voiceInteractor,
    int startFlags, boolean doResume,
    ActivityOptions options,
    TaskRecord inTask) {

    ...

    //如果找到了可重用的activity,需要清理掉原来的信息,并把当前启动的activity的信息拷贝进去
    //做清理和拷贝工作...
    if (mReusedActivity != null) {
    ...
    }

    if (mStartActivity.packageName == null) {//异常处理
    if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
    mStartActivity.resultTo.task.stack.sendActivityResultLocked(
    -1, mStartActivity.resultTo, mStartActivity.resultWho,
    mStartActivity.requestCode, RESULT_CANCELED, null);
    }
    ActivityOptions.abort(mOptions);
    return START_CLASS_NOT_FOUND;
    }

    //获取当前前台的ActivityStack 以及ActivityRecord
    final ActivityStack topStack = mSupervisor.mFocusedStack;
    final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
    //是否需要启动新的Activity标记,一长串的判断
    final boolean dontStart = top != null && mStartActivity.resultTo == null
    && top.realActivity.equals(mStartActivity.realActivity)
    && top.userId == mStartActivity.userId
    && top.app != null && top.app.thread != null
    && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
    || mLaunchSingleTop || mLaunchSingleTask);

    if (dontStart) {//不需要重新启动,那么使用复用逻辑,将当前activity显示到前端即可
    ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
    topStack.mLastPausedActivity = null;
    if (mDoResume) {//此时为true
    mSupervisor.resumeFocusedStackTopActivityLocked();
    }
    ActivityOptions.abort(mOptions);
    if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
    return START_RETURN_INTENT_TO_CALLER;
    }
    //调用NewIntent方法
    top.deliverNewIntentLocked(
    mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
    mSupervisor.handleNonResizableTaskIfNeeded(
    top.task, preferredLaunchStackId, topStack.mStackId);

    return START_DELIVERED_TO_TOP;
    }
    }

      通过代码分析我们可知此时判断当前顶部运行的Activity是否是我们所要启动的Activity,并且启动模式是singTop或者singleTask,如果是的话,则不会新建Activity,而是调用onResume和newIntent方法。因为这两种模式下,如果顶层是当前Activity的话,都不会启动新的Activity。这也就是我们常说的 A->B->C ,此时如果C的模式是singleTop,这时候再启动C的话,栈内仍然是A->B->C。这里很明显不是此种情况!

    革命仍未成功还需继续努力,让我们接着对startActivityUnchecked后续源码继续分析

    //[ActivityStarter.java]
    //表示是否需要创建新的任务栈
    boolean newTask = false;
    final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
    ? mSourceRecord.task : null;

    /*
    如果要启动的目标Activity没有对应的resultTo,
    并且也没有添加到对应栈中
    而且设置了FLAG_ACTIVITY_NEW_TASK。
    mAddingToTask为false说明没有找到对应的栈来启动我们的Activity。
    所以会通过创建或者复用一个栈来存放Activity
    */
    if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
    && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
    // 该类情况表示要在一个新的任务中启动Activity
    newTask = true;
    // 重用或者新建task
    setTaskFromReuseOrCreateNewTask(taskToAffiliate);//详见章节2.10.1
    ...
    }
    /*
    当mSourceRecord不为空,把新的ActivityRecord绑定到启动者的TaskRecord上。
    一般情况下,mSourceRecord就是调用者,譬如通常的Launcher启动或者发起端的启动
    但也有特殊情况,举个例子,如果启动模式为singleTask,栈中又不存在相同的Activity时,
    mSourceRecord就是栈顶的Activity
    */
    else if (mSourceRecord != null) {
    ...
    // 不是新建task的,重用原activity的task
    // 该类情况下,宿主栈就是调用者Activity所在的ActivityStack。
    // 处理方式也大同小异,把宿主任务挪到栈顶,针对launchFlags做一些调整
    final int result = setTaskFromSourceRecord();//详见章节2.10.2
    if (result != START_SUCCESS) {
    return result;
    }
    } else if (mInTask != null) {//启动时指定了目标栈(mInTask),ActivityRecord绑定到mInTask,在指定的任务栈中启动Activity

    if (mSupervisor.isLockTaskModeViolation(mInTask)) {
    Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
    return START_RETURN_LOCK_TASK_MODE_VIOLATION;
    }

    final int result = setTaskFromInTask();//详见2.10.3
    if (result != START_SUCCESS) {
    return result;
    }
    } else {
    //该类情况表示既不是从一个Activity启动,也不是在新的任务中启动,都不是则直接找焦点的ActivityStack上栈顶的Task,直接绑定,这种情况比较少见

    setTaskToCurrentTopOrCreateNewTask();//详见章节2.10.4
    }

      说实话这种逻辑性的代码分析起来很操蛋,也很容易让人陷入其中不能自拔,但是生活还得继续着,代码也得分析!上述的源码主要根据实际情况来继续进行要启动的Activity栈信息的处理,这里的处理逻辑又分为如下几种情况:

    如果要启动的目标Activity没有对应的resultTo,并且也没有指定mInTask,并且也没有添加到对应栈中,而且更是设置了FLAG_ACTIVITY_NEW_TASK,此时说明没有找到对应的栈来启动我们的Activity,则会调用setTaskFromReuseOrCreateNewTask继续处理 如果发起端的mSourceRecord不为空,把新的ActivityRecord绑定到启动者的TaskRecord上 如果启动时指定了目标栈(mInTask),ActivityRecord绑定到mInTask。 如果都不是则直接找焦点的ActivityStack上栈顶的Task,直接绑定

    依然还没有完,Activity启动中的生命周期一个也没有看到!尼玛,还是对上述每种情况下是如何寻找任务栈的方式来简单来进行一下分析!

    2.10.1 AS.setTaskFromReuseOrCreateNewTask

    //[ActivityStarter.java]
    private void setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
    //获取当前持有焦点的ActivityStack
    mTargetStack = computeStackFocus(mStartActivity, true, mLaunchBounds, mLaunchFlags,
    mOptions);
    //如果复用的任务栈(TaskRecord)为空,说明没有可以让我们用来使用的任务栈
    if (mReuseTask == null) {
    //创建任务栈
    final TaskRecord task = mTargetStack.createTaskRecord(
    mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
    mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
    mNewTaskIntent != null ? mNewTaskIntent : mIntent,
    mVoiceSession, mVoiceInteractor, !mLaunchTaskBehind /* toTop */);
    //设置目标Activity的任务栈为新建的task
    mStartActivity.setTask(task, taskToAffiliate);
    if (mLaunchBounds != null) {
    final int stackId = mTargetStack.mStackId;
    if (StackId.resizeStackWithLaunchBounds(stackId)) {
    mService.resizeStack(
    stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
    } else {
    mStartActivity.task.updateOverrideConfiguration(mLaunchBounds);
    }
    }
    if (DEBUG_TASKS) Slog.v(TAG_TASKS,
    "Starting new activity " +
    mStartActivity + " in new task " + mStartActivity.task);
    } else {
    //设置目标Activity的任务栈为新建的task
    mStartActivity.setTask(mReuseTask, taskToAffiliate);
    }
    }

    setTaskFromReuseOrCreateNewTask方法的处理逻辑比较简单,总结归纳起来如下:

    获取系统当前的持有焦点的ActivitytStack对象mTargetStack接着判断是否存在可以复用的TaskRecord,如果没有可复用TaskRecord则通过mTargetStack的方法createTaskRecord创建,然后将目标Activity的任务栈设置为其创建的前面创建的task如果存在可以复用的TaskRecord,则将目标Activity的任务栈设置为其可以复用的任务栈
    2.10.2 AS.setTaskFromSourceRecord

      进入此分支的前提是mSourceRecord不为null,即发起端为Activity,此时会直接把目标ActivityRecord绑定到启动者的TaskRecord上

    //[ActivityStarter.java]
    private int setTaskFromSourceRecord() {

    //获取启动着的任务栈
    final TaskRecord sourceTask = mSourceRecord.task;

    //此时的发起端Actiivty所在的TaskRecord就是处于sourceStack栈顶,所以sourceStack.topTask就是要启动的Activity所在的栈
    //如果目标Activity不允许在屏幕上显示或者源任务栈和目标任务不在同一个栈
    final boolean moveStackAllowed = sourceTask.stack.topTask() != sourceTask;
    if (moveStackAllowed) {
    //获取当前要启动activity所属的ActivityStack栈
    mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task,
    mOptions);
    }

    if (mTargetStack == null) {//目标ActivityStack为空
    mTargetStack = sourceTask.stack;
    } else if (mTargetStack != sourceTask.stack) {
    //把启动方的任务栈绑定到目标ActivityStack上
    mSupervisor.moveTaskToStackLocked(sourceTask.taskId, mTargetStack.mStackId,
    ON_TOP, FORCE_FOCUS, "launchToSide", !ANIMATE);
    }
    if (mDoResume) {
    mTargetStack.moveToFront("sourceStackToFront");
    }

    //获取目标ActivityStack的顶部task
    final TaskRecord topTask = mTargetStack.topTask();

    //目标任务栈移动到ActivityStack的顶部,也就是设置为焦点
    if (topTask != sourceTask && !mAvoidMoveToFront) {
    mTargetStack.moveTaskToFrontLocked(sourceTask, mNoAnimation, mOptions,
    mStartActivity.appTimeTracker, "sourceTaskToFront");
    }

    //如果目标activity还没有加入到栈中,而且启动标志设置了CLEAR_TOP,那么我们将Activity添加到已经存在的任务栈中,并调用clear方法清空对应的activity
    if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0) {
    // In this case, we are adding the activity to an existing task, but the caller has

    ActivityRecord top = sourceTask.performClearTaskLocked(mStartActivity, mLaunchFlags);
    mKeepCurTransition = true;
    if (top != null) {
    ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
    top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);

    mTargetStack.mLastPausedActivity = null;
    if (mDoResume) {
    mSupervisor.resumeFocusedStackTopActivityLocked();
    }
    ActivityOptions.abort(mOptions);
    return START_DELIVERED_TO_TOP;
    }
    } else if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
    final ActivityRecord top = sourceTask.findActivityInHistoryLocked(mStartActivity);
    if (top != null) {
    final TaskRecord task = top.task;
    task.moveActivityToFrontLocked(top);
    top.updateOptionsLocked(mOptions);
    ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, task);
    top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
    mTargetStack.mLastPausedActivity = null;
    if (mDoResume) {
    mSupervisor.resumeFocusedStackTopActivityLocked();
    }
    return START_DELIVERED_TO_TOP;
    }
    }

    //将Activity添加到相应的Task
    mStartActivity.setTask(sourceTask, null);
    if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
    + " in existing task " + mStartActivity.task + " from source " + mSourceRecord);
    return START_SUCCESS;
    }

    我们对该流程简单的分析一下,感觉这来来回回的绕着圈好难啊!

    要启动得Activity栈的顶部TaskRecord和启动方的TaskRecord不一致,则需要移动到其他的ActivityStack去显示。这里会通过AS.getLaunchStack从有效的displayId中去查找对应的ActivityStack。如果目标ActivityStack为空,这种属于默认的情况。会设置为启动方的ActivityStack。如果目标ActivityStack存在而且和启动方的ActivityStack不一致,则把启动方的任务栈(TaskRecord)绑定到目标所在的ActivityStack上 把目标ActivityStack移动到最前方,同时也移到ActivityDisplay集合的顶部。最后一种情况AddingToTask为false,打开FLAG_ACTIVITY_CLEAR_TOP,则清除启动方的TaskRecord中的顶部。顶部不为空,则调用newIntent,再根据需要调用resume方法。最后调用mStartActivity.setTask将Activity添加到相应的Task

    对于上述的各种流程,小伙们能搞懂是最好了,搞不懂也没有关系,不影响Activity的整体启动。

    2.10.3 AS.setTaskFromInTask

      进入此分支的前提是mInTask不为null,即指定了目标Task

    //[ActivityStarter.java]
    //将目标Activity的任务栈设置为mInTask
    private int setTaskFromInTask() {
    if (mLaunchBounds != null) {
    mInTask.updateOverrideConfiguration(mLaunchBounds);
    int stackId = mInTask.getLaunchStackId();
    if (stackId != mInTask.stack.mStackId) {
    final ActivityStack stack = mSupervisor.moveTaskToStackUncheckedLocked(
    mInTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
    stackId = stack.mStackId;
    }
    if (StackId.resizeStackWithLaunchBounds(stackId)) {
    mService.resizeStack(stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
    }
    }

    //根据实际情况检查是需要创建新的activity还是重新使用任务栈顶部的activity
    mTargetStack = mInTask.stack;
    //将mInTask移动到顶部
    mTargetStack.moveTaskToFrontLocked(
    mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront");

    //获取指定任务栈顶Activity
    ActivityRecord top = mInTask.getTopActivity();
    if (top != null && top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId) {
    //如果设置了singleTop或者启动模式为singleTop或者singleTask,那么调用newIntent方法
    if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
    || mLaunchSingleTop || mLaunchSingleTask) {
    ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
    if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
    return START_RETURN_INTENT_TO_CALLER;
    }
    top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
    return START_DELIVERED_TO_TOP;
    }
    }

    //mAddingToTask是标记位,标记着是否需要将Activity添加到TaskRecord中,
    // 在之前进行如果已经将目标Activity放入到任务栈的话,这里就不需要再次放入了,
    //只需要把TaskRecord移动ActivityStack顶部即可
    if (!mAddingToTask) {
    // We don't actually want to have this activity added to the task, so just
    // stop here but still tell the caller that we consumed the intent.
    ActivityOptions.abort(mOptions);
    return START_TASK_TO_FRONT;
    }

    //将Activity添加到mInTask任务栈中
    mStartActivity.setTask(mInTask, null);
    if (DEBUG_TASKS) Slog.v(TAG_TASKS,
    "Starting new activity " + mStartActivity + " in explicit task " + mStartActivity.task);

    return START_SUCCESS;
    }

    好吗,这里的setTaskFromInTask方法也针对不同的情况分别进行了处理:

    如果mInTask的顶部和我们要启动的Activity相同,而且启动了singleTop或者singleTask,那么就直接调用newIntent方法。 如果acitivity在之前的操作中已经添加到mInTask中了,那么这里只需要将mInTask移动到其所在ActivityStack的顶部即可。 剩下的情况就需要将mInTask移动到ActivityStack的顶部,然后Activity添加到mInTask任务栈中。
    2.10.4 AS.setTaskToCurrentTopOrCreateNewTask

      尼玛终于只有最好的一种情况了

    	//查找当前焦点的ActivityStack上栈顶的Task,或者创建一个新的任务栈
    private void setTaskToCurrentTopOrCreateNewTask() {
    //获取持有焦点的ActivityStack
    mTargetStack = computeStackFocus(mStartActivity, false, null /* bounds */, mLaunchFlags,
    mOptions);
    if (mDoResume) {
    mTargetStack.moveToFront("addingToTopTask");
    }
    //获取栈顶的ActivityRecord,也就是会被我们覆盖的那个Activity
    final ActivityRecord prev = mTargetStack.topActivity();

    //尝试从持有焦点的ActivityRecord获取其顶部的任务栈,如果获取不到的话,则创建一个
    final TaskRecord task = (prev != null) ? prev.task : mTargetStack.createTaskRecord(
    mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
    mStartActivity.info, mIntent, null, null, true);
    //将activity添加到任务栈中
    mStartActivity.setTask(task, null);
    mWindowManager.moveTaskToTop(mStartActivity.task.taskId);
    if (DEBUG_TASKS) Slog.v(TAG_TASKS,
    "Starting new activity " + mStartActivity + " in new guessed " + mStartActivity.task);
    }

    尼玛此时此刻,actvity及其对应的task位置已经安排妥当,现在可以准备让这个activity开始工作了,真不容易啊!不容易啊!


    2.11 AS.startActivityUnchecked未完成之使命ActiviytStack.startActivityLocked

    //[ActivityStarter.java]
    /* 这里的sourceRecord是指发起调用者
    r是指本次的将要启动的Activity,startFlags取值为0,
    doResume的值为true
    */
    private int startActivityUnchecked(final ActivityRecord r,
    ActivityRecord sourceRecord,
    IVoiceInteractionSession voiceSession,
    IVoiceInteractor voiceInteractor,
    int startFlags, boolean doResume,
    ActivityOptions options,
    TaskRecord inTask) {
    ...
    //把当前启动的Activity加入TaskRecord以及绑定WindowManagerService
    mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
    ...
    }

      本来是打算将前面第二章节涉及的两大部分都讲述完毕,但是一看现在的这个文字量看来只能将第一大部分分析完成了,我们接着继续

    //[ActivityStack.java]
    final void startActivityLocked(
    ActivityRecord r, //待启动的ActivityRecord
    boolean newTask, //是否需要在新的任务中启动Activity
    boolean keepCurTransition,//是否需要立即显示Activity。有些需要Pending的Activity,该值为false;对于初次对于此处而言,该值为true
    ActivityOptions options
    ) {
    //rTask即之前创建的TaskRecord,或者为查找到的可复用的TaskRecord
    TaskRecord rTask = r.task;
    final int taskId = rTask.taskId;//获取taskid

    //表示宿主栈ActivityStack中没有历史任务,或者强制要求在新的任务中启动Activity
    if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
    insertTaskAtTop(rTask, r);//插入新创建或复用的TaskRecord到栈顶
    mWindowManager.moveTaskToTop(taskId);//同时在Windowmanager中也移动到栈顶
    }
    TaskRecord task = null;
    // 进入该条件,表示需要在一个已有的任务中启动Activity
    // 先设置一个标志位,表示是否需要启动Activity,默认当然是要显示;
    // 但是当目标任务之上有全屏的Activity时,该标志位被置为false
    if (!newTask) {//这是表示存在复用的TaskRecord
    boolean startIt = true;
    //遍历TaskRecord从这儿也可以得出TaskRecord在ActivityStack是以栈的方式管理的
    //因为此时是倒序遍历的
    for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
    task = mTaskHistory.get(taskNdx);
    if (task.getTopActivity() == null) {
    continue;
    }
    if (task == r.task) {//在Task堆栈中找到了复用的Task
    if (!startIt) {
    task.addActivityToTop(r);//把当前启动的Activity加入到复用的Task栈顶
    r.putInHistory();
    addConfigOverride(r, task);//绑定到windowmanager中,此处很重要,但是不会在此分析
    if (VALIDATE_TOKENS) {
    validateAppTokensLocked();
    }
    ActivityOptions.abort(options);
    return;
    }
    break;
    } else if (task.numFullscreen > 0) {
    startIt = false;
    }
    }
    }

    if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
    mStackSupervisor.mUserLeaving = false;
    if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
    "startActivity() behind front, mUserLeaving=false");
    }

    // 以上完成的操作就是将待显示的任务放到了宿主栈的栈顶位置,
    // 接下来,需要将待显示的ActivityRecord放到任务的栈顶
    task = r.task;
    //当前启动的Activity加到所属Task栈顶中
    task.addActivityToTop(r);
    // 将一个新的ActivityRecord添加到任务栈顶后,需要重新调整FrontOfTask
    task.setFrontOfTask();

    r.putInHistory();// 标记目标ActivityRecord已经放置到目标栈中
    /*
    如果当前ActivityStack不为 HomeStack,或者该ActivityStack中activity个数不为0
    */
    if (!isHomeStack() || numActivities() > 0) {
    boolean showStartingIcon = newTask;
    ProcessRecord proc = r.app;
    if (proc == null) {
    proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
    }
    //对于刚启动HOME应用时,表示进程ProcessReocrd还为空
    if (proc == null || proc.thread == null) {
    showStartingIcon = true;
    }

    if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
    mWindowManager.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
    mNoAnimActivities.add(r);
    } else {
    mWindowManager.prepareAppTransition(newTask
    ? r.mLaunchTaskBehind
    ? TRANSIT_TASK_OPEN_BEHIND
    : TRANSIT_TASK_OPEN
    : TRANSIT_ACTIVITY_OPEN, keepCurTransition);
    mNoAnimActivities.remove(r);
    }
    //当前启动的Activity绑定到WIndowManagerService当中
    addConfigOverride(r, task);
    boolean doShow = true;
    if (newTask) {
    if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
    resetTaskIfNeededLocked(r, r);
    doShow = topRunningNonDelayedActivityLocked(null) == r;
    }
    } else if (options != null && options.getAnimationType()
    == ActivityOptions.ANIM_SCENE_TRANSITION) {
    doShow = false;
    }
    if (r.mLaunchTaskBehind) {
    mWindowManager.setAppVisibility(r.appToken, true);
    ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
    } else if (SHOW_APP_STARTING_PREVIEW && doShow) {
    ActivityRecord prev = r.task.topRunningActivityWithStartingWindowLocked();
    if (prev != null) {
    if (prev.task != r.task) {
    prev = null;
    }
    // (2) The current activity is already displayed.
    else if (prev.nowVisible) {
    prev = null;
    }
    }
    r.showStartingWindow(prev, showStartingIcon);
    }
    } else {
    // 进入该分支,表示当前的ActivityStack中还没有任何Activity,则不需要设置任何Activity启动相关的动画
    // 只是将待启动的Activity绑定到窗口上
    addConfigOverride(r, task);
    ActivityOptions.abort(options);
    options = null;
    }
    if (VALIDATE_TOKENS) {
    validateAppTokensLocked();
    }
    }

    void addConfigOverride(ActivityRecord r, TaskRecord task) {
    final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
    // 将待启动的Activity绑定到窗口上
    mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
    r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
    (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
    task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig,
    task.mResizeMode, r.isAlwaysFocusable(), task.isHomeTask(),
    r.appInfo.targetSdkVersion);
    r.taskConfigOverride = task.mOverrideConfig;
    }

    该方法的主要主要执行如下的两大逻辑:

    将ActivityRecord放到目标任务的栈顶位置。注意,这里有两个栈顶位置:一个是ActivityRecord在TaskRecord中的位置,另一个是TaskRecord在ActivityStack中的位置。前一个是肯定的,但后一个,还得根据实际的情况决定

    将待启动的ActivityRecord绑定到了一个窗口。与此同时,Activity启动的动画也在此设置。为了省略分之细节,所以与WMS交互的窗口操作逻辑就不放出来了

    总之经过以上的重重步骤,此时目标Activity对应的Task也创建了,也把当前启动的Activity加入到Task正确的位置,ActivityStack也移动到了正确位置。此时本章节就分析到这里了!

    小结

      阅读源码是很操蛋的事情,同样的如果将太多的逻辑放在一篇中我想小伙们也会阅读起来也会操蛋,失去耐心的的,所以本篇章就先到这里了。分析至此我们对前面的篇章做一个小结,我们前面主要干了如下相关的事情:

    初始化Activity启动状态计算launchFlag计算调用者的ActivityStack检查是否存在复用的TaskRecord对于存在复用的TaskRecord则进行相应的ActivityStack、TaskRecord的移动(说实话,我也没有真的搞懂,希望这块比较有经验的小伙们能和我一起学习)计算当前启动Activity所属的TaskRecord把当前启动的Activity放到所属TaskRecord的栈顶

    并且通过前面的博文分析,小伙们心里应该有了如下的知识图谱:

    一个ActivityRecord对应一个Activity,保存了一个Activity的所有信息;但是一个Activity可能会有多个ActivityRecord,因为Activity可以被多次启动,这个主要取决于其启动模式,即二者不是一对一的关系,ActivityRecord如果存在一对一的关系,那么也只能说相对于Applicatiion而言一个TaskRecord由一个或者多个ActivityRecord组成,这就是我们常说的任务栈,具有后进先出的特点。ActivityStack则是用来管理TaskRecord的,包含了多个TaskRecord。singleTask 和 singleTop 模式的都会去任务栈中遍历寻找是否已经启动了相应实例ActivityStackSupervisor 用来管理 ActivityStack 的,APP与 ActivityStack 之间并无必然的联系,这个要根据实际情况来看。有可能是一个APP对应一个 ActivityStack ,有可能是一个APP对应多个 ActivityStack ,也有可能是多个APP共用一个 ActivityStack并且启动模式如果intent中的和mainfest中的冲突,那么manfest的启动模式优先

    好了本篇博客真的只能到此了,虽然本人耗费了很多的时间来对Activity启动涉及的Task和ActivityStack等调度相关的知识点来进行分析和讲解,但是这其中牵涉的东西太多了,并且由于个人能力有限,自我感觉依然分析的不是很清晰,只能大伙见谅了。如果小伙们喜欢欢迎点赞或者能和我讨论关于本篇的知识点!

    参考博客:
    https://www.lizenghai.com/archives/94931.html#getReusableIntentActivity_Activity

    原创:https://www.panoramacn.com
    源码网提供WordPress源码,帝国CMS源码discuz源码,微信小程序,小说源码,杰奇源码,thinkphp源码,ecshop模板源码,微擎模板源码,dede源码,织梦源码等。

    专业搭建小说网站,小说程序,杰奇系列,微信小说系列,app系列小说

    Android四大组件之Activity启动流程源码实现详解(二)

    免责声明,若由于商用引起版权纠纷,一切责任均由使用者承担。

    您必须遵守我们的协议,如果您下载了该资源行为将被视为对《免责声明》全部内容的认可-> 联系客服 投诉资源
    www.panoramacn.com资源全部来自互联网收集,仅供用于学习和交流,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。 敬请谅解! 侵权删帖/违法举报/投稿等事物联系邮箱:2640602276@qq.com
    未经允许不得转载:书荒源码源码网每日更新网站源码模板! » Android四大组件之Activity启动流程源码实现详解(二)
    关注我们小说电影免费看
    关注我们,获取更多的全网素材资源,有趣有料!
    120000+人已关注
    分享到:
    赞(0) 打赏
  • 评论抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址

    您的打赏就是我分享的动力!

    支付宝扫一扫打赏

    微信扫一扫打赏