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

  Activity启动流程(三)- Activity Task调度算法复盘分析

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

Android应用进程创建流程大揭秘
Android四大组件之bindService源码实现详解
Android四大组件之Activity启动流程源码实现详解概要
Android四大组件之Activity启动流程源码实现详解(一)
Android四大组件之Activity启动流程源码实现详解(二)
Activity启动流程(三)- Activity Task调度算法复盘分析


前言

  还记得我们在前面博客Android四大组件之Activity启动流程源码实现详解(二)中做的艰苦卓越的斗争吗!这场战役之惨烈,战况之持久前所未有!虽然过程是疼苦的,但是战果也是显赫和令人满意的,通过上述战役我们取得了如下的阶段性成果:

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

总而言之经过上述一顿猛虎般的操作,此时要启动的目标Actvity及其对应的task位置以及ActivityStack已经安排妥当,现在可以准备接下来的相关工作了,本来我也是准备这么干的,可是总感觉分析少了点什么!通过前面的分析我们知道了ActivityStack类的startActivityUncheckedLocked方法负责调度ActivityRecord以及TaskRecord,并且通过前面的分析我们也可以知道调度算法非常复杂,最好需结合实际场景分析调度算法。但是前面我们只是对startActivityUncheckedLocked整个源码进行了流水式的分析,而没有结合实际,所以本篇博客将结合实际场景分析调度算法,将Activity启动过程中涉及的TaskRecord和ActivityStack的调度再来复盘一下!

注意:本篇的介绍是基于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

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

在这里插入图片描述



一.实际场景一复盘分析

  假设我们存在如下的Activity启动场景某应用内有两个Activity,A和B,A为该应用入口Activity,从A可跳转至B,A和B的启动模式都为standard,我们以该场景为切入口来分析Activity启动过程中Task任务栈和Activity栈的调度。本章接将会重点围绕如下三种Activity启动情况分析:

  • 从Launcher桌面第一次启动应用时的任务调度情况:

  • 任务调度时会创建新task,并将新的ActivityRecord加入这个新的task,然后将task放入合适的Stack的栈顶

    扫描二维码关注公众号,回复: 11874278 查看本文章
  • 应用内Activity跳转时的任务调度情况:

  • 任务调度时会将新的ActivityRecord加入已有的task,然后将该ActivityRecord移动到Task顶端,然后将task放入合适的Stack的栈顶

  • 然后按Home键,再打开应用程序时的调度情况:

  • 任务调度时会先找到已有的相关task,并显示栈顶的Activity

通过前面的博客Android四大组件之Activity启动流程源码实现详解(二)我们知道Activity启动过程中Task和ActivityStack的调度涉及的代码众多,所以在复盘的过程中我们只抽取重点,并将AS.startActivityUnchecked中的涉及的方法,我们将采用伪代码的方式进行分析,只为了小伙们们能更好的了解Task和ActivityStack的调度!


1.1 从Launcher桌面第一次启动应用时Activity的Task以及Stack调度情况

  在正式启动前,我们先来看看此时Android终端中的各种Task和ActivityStack的情况,我们可以通过Android内置的命令dumpsys activity activities来进行查看,此时的Activity的栈以及Task情况如下:

#adb shell dumpsys activity activities
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #0://Home所属Stack对应的taskid,其对应的值为HOME_STACK_ID 
  mFullscreen=true
  mBounds=null
    Task id #8
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
    * TaskRecord{
    
    3a6c4af #8 A=com.android.launcher3 U=0 StackId=0 sz=1}
      userId=0 effectiveUid=u0a23 mCallingUid=0 mUserSetupComplete=true mCallingPackage=null
      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=1
      rootWasReset=false mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
      Activities=[ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}]
      askedCompatMode=false inRecents=true isAvailable=true
      lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/8_task_thumbnail.png
      stackId=0
      hasBeenVisible=true mResizeMode=RESIZE_MODE_FORCE_RESIZEABLE isResizeable=false firstActiveTime=1602505452631 lastActiveTime=1602505452631 (inactive for 2s)
      * Hist #0: ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}
          packageName=com.android.launcher3 processName=com.android.launcher3
          launchedFromUid=0 launchedFromPackage=null userId=0
          app=ProcessRecord{
    
    c4940bc 14811: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{
    
    3a6c4af #8 A=com.android.launcher3 U=0 StackId=0 sz=1}
          taskAffinity=com.android.launcher3
          realActivity=com.android.launcher3/.Launcher
          baseDir=/system/app/PaxLauncher3/PaxLauncher3.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=-1m17s726ms
          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_NOT_SHOWN
          fullscreen=true noDisplay=false immersive=false launchMode=2
          frozenBeforeDestroy=false forceNewConfig=false
          mActivityType=HOME_ACTIVITY_TYPE
          waitingVisible=false nowVisible=true lastVisibleTime=-2s190ms
          resizeMode=RESIZE_MODE_FORCE_RESIZEABLE

    Running activities (most recent first):
      TaskRecord{
    
    3a6c4af #8 A=com.android.launcher3 U=0 StackId=0 sz=1}
        Run #0: ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}

    mResumedActivity: ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}
    mLastPausedActivity: ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}

  mFocusedActivity: ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}
  mFocusedStack=ActivityStack{
    
    a520845 stackId=0, 1 tasks} mLastFocusedStack=ActivityStack{
    
    a520845 stackId=0, 1 tasks}
  mSleepTimeout=false
  mCurTaskIdForUser={
    
    0=8}
  mUserStackInFront={
    
    }
  mActivityContainers={
    
    0=ActivtyContainer{
    
    0}A}
  mLockTaskModeState=NONE mLockTaskPackages (userId:packages)=
    0:[]
 mLockTaskModeTasks[]

通过前面的dump,此时我们可以知道了ASS中的mHomeStack已经创建了,并且Launcher桌面Activity对应的Task和ActivityRecord都已经OK了!但是由于Launcher桌面Activity的启动不在本篇的分析中,它对应的Activity的Task以及相关的调度就不予分析了!

从Launcher桌面第一次启动应用时Activity的Task以及Stack调度执行如下所示:

//[ActivityStarter.java]
	/*
	这里的sourceRecord是指发起调用者 
	r是指本次的将要启动的Activity
	startFlags取值为0
	doResume的值为true
	inTask为发起方指定的任务栈,此时为null
	这里主要确定目标Activity的launchMode Task栈等,即Task的创建和管理
	*/
    private int startActivityUnchecked(final ActivityRecord r, 
    									ActivityRecord sourceRecord,
            							IVoiceInteractionSession voiceSession, 
            							IVoiceInteractor voiceInteractor,
            							int startFlags, 
            							boolean doResume, 
            							ActivityOptions options, 
            							TaskRecord inTask) {
    
    

		//设置初始化状态,此时需要重点关注该方法中的如下几个目标值的获取,为了分析的方便,我会将该方法展开
		setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
		              voiceInteractor);
        /*****************************************************************************/
        	//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下
			private void setInitialState(ActivityRecord r, 
										ActivityOptions options, 
										TaskRecord inTask,
            							boolean doResume, 
            							int startFlags, 
            							ActivityRecord sourceRecord,
            							IVoiceInteractionSession 
            							voiceSession, 
            							IVoiceInteractor voiceInteractor) {
    
    
						//此处分支会走,将启动过程中的涉及的相关变量进行初始化
						reset();     
						...   
						mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP;//此时为false
						mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;//此时为false
						mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;//此时为false
						//这里重点关注一下,此时mIntent.getFlags携带的为FLAG_ACTIVITY_RESET_TASK_IF_NEEDED|FLAG_ACTIVITY_NEW_TASK,这个地方是关键因为后面会根据这些值进行Task和Stack的调度
						mLaunchFlags = adjustLaunchFlagsToDocumentMode(r,mLaunchSingleInstance, mLaunchSingleTask, mIntent.getFlags());
						...
						mDoResume = doResume;
						...
						mInTask = inTask;
						...
						mStartFlags = startFlags;//此时的mStartFlags为0
      		}
        /*****************************************************************************/

		//根据发起端,计算目标Activity的launchMode模式
		computeLaunchingTaskFlags();
		/*****************************************************************************/
			//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下
			//根据发起者launchMode情况,决定目标Activity的Flags情况
    		private void computeLaunchingTaskFlags() {
    
    
    			//此时场景下的mSourceRecord不为null,mInTask为null,所以不会进入该分支
    			if (mSourceRecord == null && mInTask != null && mInTask.stack != null) {
    
    
    				...
    			}else {
    
    //会进入此分支
		            mInTask = null;
		            //不满足条件,不会进入该分支
		            if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null
		                    && mSourceRecord.isFreeform())  {
    
    
		                	...
		            }
    			}
        	}
        	//此时的mInTask为null,会进入此分支,但是该分支下面的三个小分支都不会进入
        	if (mInTask == null) {
    
    
	            if (mSourceRecord == null) {
    
    //mSourceRecord不为null,此时的mSourceRecord为Launcher,不会进入此分支
					...
	            } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
    
    //launcher应用activity的启动模式为singleTask
					...
	            } else if (mLaunchSingleInstance || mLaunchSingleTask) {
    
    //不会进入此分支,此时都为false
					...
	            }
        	}
		/*****************************************************************************/

		//确定发起端的ActivityStack情况
		computeSourceStack();
		/*****************************************************************************/
			//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下     
			//确定发起端的Stack情况
	    	private void computeSourceStack() {
    
    
		        if (mSourceRecord == null) {
    
    //mSourceRecord不为null,不会进入此分支
					...
		        }
		        if (!mSourceRecord.finishing) {
    
    //此时明显mSourceRecord没有被finish所以会进入此分支
					//当调用者Activity不为空,且不处于finishing状态,则其所在栈赋于sourceStack
		            mSourceStack = mSourceRecord.task.stack;
		            return;
		        }
				...
	    	}   
   	  /*****************************************************************************/	

		mIntent.setFlags(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定义的。
	      */
		 //此时肯定不存在复用的Activity,因为除开启动了Launcher对应的Activity,啥都还没有启动呢
		 mReusedActivity = getReusableIntentActivity();
		/*****************************************************************************/	
			//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下 	 
			 private ActivityRecord getReusableIntentActivity() {
    
    
			 	  //此时的mLaunchFlags的取值为FLAG_ACTIVITY_RESET_TASK_IF_NEEDED|FLAG_ACTIVITY_NEW_TASK,所以为true
			      boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
			              (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
			              || mLaunchSingleInstance || mLaunchSingleTask;
			
				  //此时mInTask为false,mStartActivity.resultTo为null
			      putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
			      ActivityRecord intentActivity = null;
			      if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
    
    
			      	...
			      } else if (putIntoExistingTask) {
    
    
			          if (mLaunchSingleInstance) {
    
    //不会进入此分支
					...
			          } else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
    
    //不会进入此分支
					...
			          } else {
    
    //会走入此分支,在ASS中查找是否存在启动目标Activity,很明显此时不存在,所以intentActivity得到的值为null
			              intentActivity = mSupervisor.findTaskLocked(mStartActivity);
			          }
			      }
			      return intentActivity;
			  }
	    /*****************************************************************************/		

		...
		//如果找到了可重用的activity,则进行下一步相关操作,在此场景下很明显没有找到可复用的Activity
		if (mReusedActivity != null) {
    
    //不会进入此分支,忽略
			...
		}  

        if (mStartActivity.packageName == null) {
    
    //异常处理,正常启动不会进入此分支忽略
			...
        }


		//是否需要启动新的Activity标记,此场景下dontStart为false
        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) {
    
    //不会走入此分支,忽略
			...
        }

		//表示是否需要创建新的任务栈
        boolean newTask = false;
		...

      
        /*
        	如果要启动的目标Activity没有对应的resultTo,很明显由于mLaunchFlags携带FLAG_ACTIVITY_NEW_TASK所以result会被置为null
        	并且也没有添加到对应栈中,mAddingToTask为false
        	而且设置了FLAG_ACTIVITY_NEW_TASK。
        	说明没有找到对应的栈来启动我们的Activity。
            所以会通过创建或者复用一个栈来存放Activity
            此场景下会进入该分支
        */
        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
    
    //此场景会进入此分支
            newTask = true;
			// 重用启动端Activity所属Task或者新建task
            setTaskFromReuseOrCreateNewTask(taskToAffiliate);
			/*****************************************************************************/	
			//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下 	 
				//从发起端获取Task任务栈或者新建一个任务栈
				//此处的入参taskToAffiliate为null
			    private void setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
    
    
			    	//获取目标ActivityStack栈,即目标Activity所属的Stack栈
			        mTargetStack = computeStackFocus(mStartActivity, true, mLaunchBounds, mLaunchFlags,
			                mOptions);
			
			        if (mReuseTask == null) {
    
    //此时mReuseTask为null,会进入该分支
						//创建新的Task
			            final TaskRecord task = mTargetStack.createTaskRecord(
			                    mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
			                    mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
			                    mNewTaskIntent != null ? mNewTaskIntent : mIntent,
			                    mVoiceSession, mVoiceInteractor, !mLaunchTaskBehind /* toTop */);
			            //将创建的Task设置为目标Activity的Task
			            mStartActivity.setTask(task, taskToAffiliate);
			            if (mLaunchBounds != null) {
    
    //此时的mLaunchBounds为null,不会进入此分支
							...
			            }
			        } else {
    
    //不会进入此分支,因为此时的mReuseTask为null,在setInitialState被设置的,后续没有被修改过
			            mStartActivity.setTask(mReuseTask, taskToAffiliate);
			        }
			    }
			/*****************************************************************************/
			...
            if (!mMovedOtherTask) {
    
    //会走入此分支
                updateTaskReturnToType(mStartActivity.task, mLaunchFlags, topStack);
            }
        }
		/*
			当mSourceRecord不为空,把新的ActivityRecord绑定到启动者的TaskRecord上。
         	一般情况下,mSourceRecord就是调用者,如本例中的Launcher;
        	但也有特殊情况,举个例子,如果启动模式为singleTask,栈中又不存在相同的Activity时,
        	mSourceRecord就是栈顶的Activity
		*/
		else if (mSourceRecord != null) {
    
    //不会进入此分支
			...
        } else if (mInTask != null) {
    
    //启动时指定了目标栈(mInTask),ActivityRecord绑定到mInTask,不会进入此分支
			...
        } else {
    
    //不会进入此分支
			...
        }	

		//权限检测
        mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
                mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);

        if (mSourceRecord != null && mSourceRecord.isRecentsActivity()) {
    
    //不会走入此分支,因为我们的发起端是Luancher不属于RecentsActivity
			...
        }

		...
		/*把当前启动的Activity加入TaskRecord以及绑定WindowManagerService*/
        mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);	
		/*****************************************************************************/	
			//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下  
		    final void startActivityLocked(	ActivityRecord r, //此时的r为目标Activity
		    								boolean newTask, //newTask表示是否要创建Task,为true
		    								boolean keepCurTransition,
		            						ActivityOptions options) 
		   {
    
    
		        TaskRecord rTask = r.task;
		        final int taskId = rTask.taskId;
				
		        if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
    
    //会进入此分支
		            //task中的上一个activity已被移除,或者ams重用该task,则将该task移到顶部
		            insertTaskAtTop(rTask, r);//将前面创建的Task放到Stack的顶部
		            mWindowManager.moveTaskToTop(taskId);
		        }
		        TaskRecord task = null;
		        if (!newTask) {
    
    //newTask为true不会走此分支
					...
		        }
		
				...
		
		        task = r.task;
		
				//将Activity移动到Stack的顶端
		        task.addActivityToTop(r);
		        task.setFrontOfTask();
		
		        r.putInHistory();
		        if (!isHomeStack() || numActivities() > 0) {
    
    //会进入此分支,此时的ActivityStack不是HomeStack
					//这个地方很重要
		            addConfigOverride(r, task);
		        } else {
    
    //不会进入此分支
					...
		        }
		        ...
		    }	
		/*****************************************************************************/		
		...	    		      
}

至此从Launcher桌面第一次启动应用时Activity的Task以及Stack调度就完成了,我们对其小结一下,其主要流程可以精简为如下几个步骤:

  • 调用AS.setInitialState方法,对启动目标Activity时Task任务栈和ActivityStack栈将要涉及的变量进行初始化设置
  • 根据发起端Activity的情况,调用computeLaunchingTaskFlags计算目标Activity的launchMode模式
  • 调用computeSourceStack确定发起端Stack的情况
  • 经过上述的一系列处理以后,已经确定目标Activity相关的LauncherMode,flag等启动模式了,接下来调用getReusableIntentActivity确定是否有可复用的Activity,在此场景下肯定不会存在可以复用的Activity
  • 接着调用方法setTaskFromReuseOrCreateNewTask创建目标Activity对应的Task和找到合适的Stack,并且将创建的Task移动到目标Stack的顶端
  • 接着继续调用ASS.startActivityLocked方法,将目标Activity加入TaskRecord,并且将其放入对应ActivityStack的顶部以及绑定WindowManagerService

经过如上的步骤以后,我们的目标Activity所属的Task和Stack就已经安排妥当了,我们此时可以通过命令查看,可以看到此时的mFocusedActivity和mFocusedStack为目标Activity。

#adb shell dumpsys activity activities
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #1://目标Activity对应的Stackid,其值为FULLSCREEN_WORKSPACE_STACK_ID的值
  mFullscreen=true
  mBounds=null
    Task id #9
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
    * TaskRecord{
    
    d361623 #9 A=com.example.test U=0 StackId=1 sz=1}
      userId=0 effectiveUid=u0a48 mCallingUid=u0a23 mUserSetupComplete=true mCallingPackage=com.android.launcher3
      affinity=com.example.test
      intent={
    
    act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.test/.MainActivity}
      realActivity=com.example.test/.MainActivity
      autoRemoveRecents=false isPersistable=true numFullscreen=1 taskType=0 mTaskToReturnTo=1
      rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
      Activities=[ActivityRecord{
    
    dd0bb9a u0 com.example.test/.AMainActivity t9}]
      askedCompatMode=false inRecents=true isAvailable=true
      lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/9_task_thumbnail.png
      stackId=1
      hasBeenVisible=true mResizeMode=RESIZE_MODE_FORCE_RESIZEABLE isResizeable=true firstActiveTime=1602505456984 lastActiveTime=1602505456984 (inactive for 3s)
      * Hist #0: ActivityRecord{
    
    dd0bb9a u0 com.example.test/.AMainActivity t9}
          packageName=com.example.test processName=com.example.test
          launchedFromUid=10023 launchedFromPackage=com.android.launcher3 userId=0
          app=ProcessRecord{
    
    cd84720 15340:com.example.test/u0a48}
          Intent {
    
     act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.test/.AMainActivity bnds=[184,356][360,544] }
          frontOfTask=true task=TaskRecord{
    
    d361623 #9 A=com.example.test U=0 StackId=1 sz=1}
          taskAffinity=com.example.test
          realActivity=com.example.test/.MainActivity
          baseDir=/data/app/com.example.test-1/base.apk
          dataDir=/data/user/0/com.example.test
          stateNotNeeded=false componentSpecified=true mActivityType=0
          compat={
    
    320dpi} labelRes=0x7f050000 icon=0x7f020000 theme=0x7f060001
          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=ffe6e6e6
          launchFailed=false launchCount=1 lastLaunchTime=-3s640ms
          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=0
          frozenBeforeDestroy=false forceNewConfig=false
          mActivityType=APPLICATION_ACTIVITY_TYPE
          waitingVisible=false nowVisible=true lastVisibleTime=-3s152ms
          resizeMode=RESIZE_MODE_FORCE_RESIZEABLE

    Running activities (most recent first):
      TaskRecord{
    
    d361623 #9 A=com.example.test U=0 StackId=1 sz=1}
        Run #0: ActivityRecord{
    
    dd0bb9a u0 com.example.test/.AMainActivity t9}

    mResumedActivity: ActivityRecord{
    
    dd0bb9a u0 com.example.test/.AMainActivity t9}

  Stack #0:
  mFullscreen=true
  mBounds=null
    Task id #8
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
    * TaskRecord{
    
    3a6c4af #8 A=com.android.launcher3 U=0 StackId=0 sz=1}
      userId=0 effectiveUid=u0a23 mCallingUid=0 mUserSetupComplete=true mCallingPackage=null
      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=1
      rootWasReset=false mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
      Activities=[ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}]
      askedCompatMode=false inRecents=true isAvailable=true
      lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/8_task_thumbnail.png
      stackId=0
      hasBeenVisible=true mResizeMode=RESIZE_MODE_FORCE_RESIZEABLE isResizeable=false firstActiveTime=1602505456850 lastActiveTime=1602505456850 (inactive for 3s)
      * Hist #0: ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}
          packageName=com.android.launcher3 processName=com.android.launcher3
          launchedFromUid=0 launchedFromPackage=null userId=0
          app=ProcessRecord{
    
    c4940bc 14811: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{
    
    3a6c4af #8 A=com.android.launcher3 U=0 StackId=0 sz=1}
          taskAffinity=com.android.launcher3
          realActivity=com.android.launcher3/.Launcher
          baseDir=/system/app/PaxLauncher3/PaxLauncher3.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=-1m23s381ms
          haveState=true icicle=Bundle[mParcelledData.dataSize=3788]
          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=-7s845ms
          resizeMode=RESIZE_MODE_FORCE_RESIZEABLE

    Running activities (most recent first):
      TaskRecord{
    
    3a6c4af #8 A=com.android.launcher3 U=0 StackId=0 sz=1}
        Run #0: ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}

    mLastPausedActivity: ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}

  mFocusedActivity: ActivityRecord{
    
    dd0bb9a u0 com.example.test/.AMainActivity t9}
  mFocusedStack=ActivityStack{
    
    8238d9 stackId=1, 1 tasks} mLastFocusedStack=ActivityStack{
    
    8238d9 stackId=1, 1 tasks}
  mSleepTimeout=false
  mCurTaskIdForUser={
    
    0=9}
  mUserStackInFront={
    
    }
  mActivityContainers={
    
    0=ActivtyContainer{
    
    0}A, 1=ActivtyContainer{
    
    1}A}
  mLockTaskModeState=NONE mLockTaskPackages (userId:packages)=
    0:[]
 mLockTaskModeTasks[]


1.2 从已经启动应用的A Activity跳转到B Activity

  通过这种方式启动目标Activity较前面的启动方式要简单一些,因为无需创建新的Task了,只需要将目标Activity加入到A所属的Task即可,注意此时启动B Activity是标准的启动方式。此时启动目标B Activity的Task以及Stack调度执行如下所示:

//[ActivityStarter.java]
	/*
	这里的sourceRecord是指发起调用者 
	r是指本次的将要启动的Activity
	startFlags取值为0
	doResume的值为true
	inTask为发起方指定的任务栈,此时为null
	这里主要确定目标Activity的launchMode Task栈等,即Task的创建和管理
	*/
    private int startActivityUnchecked(final ActivityRecord r, 
    									ActivityRecord sourceRecord,
            							IVoiceInteractionSession voiceSession, 
            							IVoiceInteractor voiceInteractor,
            							int startFlags, 
            							boolean doResume, 
            							ActivityOptions options, 
            							TaskRecord inTask) {
    
    

		//设置初始化状态,此时需要重点关注该方法中的如下几个目标值的获取,为了分析的方便,我会将该方法展开
		setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
		              voiceInteractor);
        /*****************************************************************************/
        	//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下
			private void setInitialState(ActivityRecord r, 
										ActivityOptions options, 
										TaskRecord inTask,
            							boolean doResume, 
            							int startFlags, 
            							ActivityRecord sourceRecord,
            							IVoiceInteractionSession 
            							voiceSession, 
            							IVoiceInteractor voiceInteractor) {
    
    
						//此处分支会走,将启动过程中的涉及的相关变量进行初始化
						reset();     
						...   
						mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP;//此时为false
						mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;//此时为false
						mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;//此时为false
						//这里重点关注一下,此时mIntent.getFlags携带的flags为0,此处很关键
						mLaunchFlags = adjustLaunchFlagsToDocumentMode(r,mLaunchSingleInstance, mLaunchSingleTask, mIntent.getFlags());
						...
						mDoResume = doResume;
						...
						mInTask = inTask;
						...
						mStartFlags = startFlags;//此时的mStartFlags为0
      		}
        /*****************************************************************************/
		//根据发起端,计算目标Activity的launchMode模式
		computeLaunchingTaskFlags();
		/*****************************************************************************/
			//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下
			//根据发起者launchMode情况,决定目标Activity的Flags情况
    		private void computeLaunchingTaskFlags() {
    
    
    			//此时场景下的mSourceRecord不为null,mInTask为null,所以不会进入该分支
    			if (mSourceRecord == null && mInTask != null && mInTask.stack != null) {
    
    
    				...
    			}else {
    
    //会进入此分支
		            mInTask = null;
		            //不满足条件,不会进入该分支
		            if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null
		                    && mSourceRecord.isFreeform())  {
    
    
		                	mAddingToTask = true;
		            }
    			}
        	}
        	//此时的mInTask为null,会进入此分支,但是该分支下面的三个小分支都不会进入
        	if (mInTask == null) {
    
    
	            if (mSourceRecord == null) {
    
    //mSourceRecord不为null,此时的mSourceRecord为Launcher,不会进入此分支
					...
	            } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
    
    //launcher应用activity的启动模式为singleTask
					...
	            } else if (mLaunchSingleInstance || mLaunchSingleTask) {
    
    //不会进入此分支,此时都为false
					...
	            }
        	}
		/*****************************************************************************/    
		//确定发起端的ActivityStack情况
		computeSourceStack();
		/*****************************************************************************/
			//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下     
			//确定发起端的Stack情况
	    	private void computeSourceStack() {
    
    
		        if (mSourceRecord == null) {
    
    //mSourceRecord不为null,不会进入此分支
					...
		        }
		        if (!mSourceRecord.finishing) {
    
    //此时明显mSourceRecord没有被finish所以会进入此分支
					//当调用者Activity不为空,且不处于finishing状态,则其所在栈赋于sourceStack
		            mSourceStack = mSourceRecord.task.stack;
		            return;
		        }
				...
	    	}   
   	  /*****************************************************************************/	

		mIntent.setFlags(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定义的。
	      */
		 //此时肯定不存在复用的Activity,因为除开启动了A对应的Activity,啥都还没有启动呢
		 mReusedActivity = getReusableIntentActivity();
		/*****************************************************************************/	
			//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下 	
		    private ActivityRecord getReusableIntentActivity() {
    
    
		    	//此时的mLaunchFlags为0,而mLaunchSingleInstance为false,mLaunchSingleTask也为false,肯定不会存在可以复用的Activity
		        boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
		                (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
		                || mLaunchSingleInstance || mLaunchSingleTask;
		        putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
		        ActivityRecord intentActivity = null;
		        if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
    
    
					...
		        } else if (putIntoExistingTask) {
    
    
					...
		        }
		        return intentActivity;
		    }			 	
		/*****************************************************************************/		

		//如果找到了可重用的activity,则进行下一步相关操作,在此场景下很明显没有找到可复用的Activity
		if (mReusedActivity != null) {
    
    //不会进入此分支,忽略
			...
		}  

        if (mStartActivity.packageName == null) {
    
    //异常处理,正常启动不会进入此分支忽略
			...
        }


		//是否需要启动新的Activity标记,此场景下dontStart为false
        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) {
    
    //不会走入此分支,忽略
			...
        }

		//表示是否需要创建新的任务栈
        boolean newTask = false;
		...		

        /*
        	如果要启动的目标Activity没有对应的resultTo,
        	并且也没有添加到对应栈中
        	而且设置了FLAG_ACTIVITY_NEW_TASK。
        	说明没有找到对应的栈来启动我们的Activity。
            所以会通过创建或者复用一个栈来存放Activity
        */
        //不会进入此分支
        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
    
    
			...				...
        }
		/*
			当mSourceRecord不为空,把新的ActivityRecord绑定到启动者的TaskRecord上。
			此场景下会走入此分支,从发起端Activity A获取Task以及它所属的Stack
		*/	    
		else if (mSourceRecord != null) {
    
    

			// 不是新建task的,重用原activity的task
            final int result = setTaskFromSourceRecord();
			/*****************************************************************************/	
				//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下 
			    private int setTaskFromSourceRecord() {
    
    
					//获取启动Activity的任务栈
			        final TaskRecord sourceTask = mSourceRecord.task;
			        //此时的发起端Actiivty所在的TaskRecord就是处于sourceStack栈顶,所以sourceStack.topTask就是要启动的Activity所在的栈
			        //如果目标Activity不允许在屏幕上显示或者源任务栈和目标任务不在同一个栈
			        final boolean moveStackAllowed = sourceTask.stack.topTask() != sourceTask;
					//获取当前要启动activity所属的ActivityStack栈
			        if (moveStackAllowed) {
    
    //不会进入此分支						
						...
			        }
					
					//目标ActivityStack为空
			        if (mTargetStack == null) {
    
    
			            mTargetStack = sourceTask.stack;//进入此分支
			        } else if (mTargetStack != sourceTask.stack) {
    
    
			        	//把启动方的任务栈绑定到目标ActivityStack上
						...
			        }
			        if (mDoResume) {
    
    
			            mTargetStack.moveToFront("sourceStackToFront");
			        }
			
					//获取目标ActivityStack的顶部task
			        final TaskRecord topTask = mTargetStack.topTask();
			        if (topTask != sourceTask && !mAvoidMoveToFront) {
    
    //不会走入此分支
						
			        }
			
					//如果目标activity还没有加入到栈中,而且启动标志设置了CLEAR_TOP,那么我们将Activity添加到已经存在的任务栈中,并调用clear方法清空对应的activity
			        if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0) {
    
    //很明显不会进入此分支
						...
			        } else if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
    
    //不会进入此分支
						...
			        }
			        mStartActivity.setTask(sourceTask, null);//设置目标Activity B的Task为A Activity所属的Task

			        return START_SUCCESS;
			    }				
			/*****************************************************************************/						            
            if (result != START_SUCCESS) {
    
    
                return result;
            }
        } else if (mInTask != null) {
    
    //启动时指定了目标栈(mInTask),ActivityRecord绑定到mInTask,此场景下不会进入此分支
			...
        } else {
    
    //不会进入此分支,忽略
			..,
        }		
		...
		/*把当前启动的Activity加入TaskRecord以及绑定WindowManagerService*/
        mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);	
		/*****************************************************************************/	
			//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下  
		    final void startActivityLocked(	ActivityRecord r, //此时的r为目标Activity
		    								boolean newTask, //newTask表示是否要创建Task,为true
		    								boolean keepCurTransition,
		            						ActivityOptions options) 
		   {
    
    
		        TaskRecord rTask = r.task;
		        final int taskId = rTask.taskId;
				
		        if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
    
    //不会进入此分支
					...
		        }
		        TaskRecord task = null;
		        if (!newTask) {
    
    //newTask为false会走入此分支
					...
		        }
		
				...
		
		        task = r.task;
		
				//将Activity移动到Stack的顶端
		        task.addActivityToTop(r);
		        task.setFrontOfTask();
		
		        r.putInHistory();
		        if (!isHomeStack() || numActivities() > 0) {
    
    //会进入此分支,此时的ActivityStack不是HomeStack
					//这个地方很重要
		            addConfigOverride(r, task);
		        } else {
    
    //不会进入此分支
					...
		        }
		        ...
		    }	
		/*****************************************************************************/		
		...	 
}		   		              

至此从从已经启动应用的A Activity跳转到B Activity的Task以及Stack的调度就完成了,我们对其小结一下,其主要流程可以精简为如下几个步骤:

  • 调用AS.setInitialState方法,对启动目标Activity时Task任务栈和ActivityStack栈将要涉及的变量进行初始化设置
  • 根据发起端Activity的情况,调用computeLaunchingTaskFlags计算目标Activity的launchMode模式
  • 调用computeSourceStack确定发起端Stack的情况
  • 经过上述的一系列处理以后,已经确定目标Activity相关的LauncherMode,flag等启动模式了,接下来调用getReusableIntentActivity确定是否有可复用的Activity,在此场景下肯定不会存在可以复用的Activity
  • 接着调用方法setTaskFromSourceRecord从发起端Activity获取Task和Stack
  • 接着继续调用ASS.startActivityLocked方法,将目标Activity加入TaskRecord,并且将其放入对应ActivityStack的顶部以及绑定WindowManagerService

经过如上的步骤以后,我们的目标Activity所属的Task和Stack就已经安排妥当了,我们此时可以通过命令查看,可以看到此时的mFocusedStack和Task为目标Activity A所对应的。

#adb shell dumpsys activity activities
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #1://目标Activity对应的Stackid,其值为FULLSCREEN_WORKSPACE_STACK_ID的值
  mFullscreen=true
  mBounds=null
    Task id #9
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
    * TaskRecord{
    
    d361623 #9 A=com.example.test U=0 StackId=1 sz=2}
      userId=0 effectiveUid=u0a48 mCallingUid=u0a23 mUserSetupComplete=true mCallingPackage=com.android.launcher3
      affinity=com.example.test
      intent={
    
    act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.test/.MainActivity}
      realActivity=com.example.test/.MainActivity
      autoRemoveRecents=false isPersistable=true numFullscreen=2 taskType=0 mTaskToReturnTo=1
      rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
      Activities=[ActivityRecord{
    
    dd0bb9a u0 com.example.test/.AMainActivity t9}, ActivityRecord{
    
    59a829e u0 com.example.test/.BActivity t9}]
      askedCompatMode=false inRecents=true isAvailable=true
      lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/9_task_thumbnail.png
      stackId=1
      hasBeenVisible=true mResizeMode=RESIZE_MODE_FORCE_RESIZEABLE isResizeable=true firstActiveTime=1602505463616 lastActiveTime=1602505463616 (inactive for 2s)
      * Hist #1: ActivityRecord{
    
    59a829e u0 com.example.test/.BActivity t9}//任务栈顶Activity为BActivity
          packageName=com.example.test processName=com.example.test
          launchedFromUid=10048 launchedFromPackage=com.example.test userId=0
          app=ProcessRecord{
    
    cd84720 15340:com.example.test/u0a48}
          Intent {
    
     cmp=com.example.test/.BActivity }
          frontOfTask=false task=TaskRecord{
    
    d361623 #9 A=com.example.test U=0 StackId=1 sz=2}
          taskAffinity=com.example.test
          realActivity=com.example.test/.BActivity
          baseDir=/data/app/com.example.test-1/base.apk
          dataDir=/data/user/0/com.example.test
          stateNotNeeded=false componentSpecified=true mActivityType=0
          compat={
    
    320dpi} labelRes=0x7f050000 icon=0x7f020000 theme=0x7f060001
          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=ffe6e6e6
          launchFailed=false launchCount=1 lastLaunchTime=-2s860ms
          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_NOT_SHOWN
          fullscreen=true noDisplay=false immersive=false launchMode=0
          frozenBeforeDestroy=false forceNewConfig=false
          mActivityType=APPLICATION_ACTIVITY_TYPE
          waitingVisible=false nowVisible=true lastVisibleTime=-2s362ms
          resizeMode=RESIZE_MODE_FORCE_RESIZEABLE
      * Hist #0: ActivityRecord{
    
    dd0bb9a u0 com.example.test/.AMainActivity t9}
          packageName=com.example.test processName=com.example.test
          launchedFromUid=10023 launchedFromPackage=com.android.launcher3 userId=0
          app=ProcessRecord{
    
    cd84720 15340:com.example.test/u0a48}
          Intent {
    
     act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.test/.AMainActivity bnds=[184,356][360,544] }
          frontOfTask=true task=TaskRecord{
    
    d361623 #9 A=com.example.test U=0 StackId=1 sz=2}
          taskAffinity=com.example.test
          realActivity=com.example.test/.MainActivity
          baseDir=/data/app/com.example.test-1/base.apk
          dataDir=/data/user/0/com.example.test
          stateNotNeeded=false componentSpecified=true mActivityType=0
          compat={
    
    320dpi} labelRes=0x7f050000 icon=0x7f020000 theme=0x7f060001
          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=ffe6e6e6
          launchFailed=false launchCount=0 lastLaunchTime=-9s493ms
          haveState=true icicle=Bundle[mParcelledData.dataSize=1132]
          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=-9s5ms
          resizeMode=RESIZE_MODE_FORCE_RESIZEABLE

    Running activities (most recent first):
      TaskRecord{
    
    d361623 #9 A=com.example.test U=0 StackId=1 sz=2}
        Run #1: ActivityRecord{
    
    59a829e u0 com.example.test/.BActivity t9}
        Run #0: ActivityRecord{
    
    dd0bb9a u0 com.example.test/.AMainActivity t9}

    mResumedActivity: ActivityRecord{
    
    59a829e u0 com.example.test/.BActivity t9}
    mLastPausedActivity: ActivityRecord{
    
    dd0bb9a u0 com.example.test/.AMainActivity t9}

  Stack #0:
  mFullscreen=true
  mBounds=null
    Task id #8
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
    * TaskRecord{
    
    3a6c4af #8 A=com.android.launcher3 U=0 StackId=0 sz=1}
      userId=0 effectiveUid=u0a23 mCallingUid=0 mUserSetupComplete=true mCallingPackage=null
      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=1
      rootWasReset=false mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
      Activities=[ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}]
      askedCompatMode=false inRecents=true isAvailable=true
      lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/8_task_thumbnail.png
      stackId=0
      hasBeenVisible=true mResizeMode=RESIZE_MODE_FORCE_RESIZEABLE isResizeable=false firstActiveTime=1602505456850 lastActiveTime=1602505456850 (inactive for 9s)
      * Hist #0: ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}
          packageName=com.android.launcher3 processName=com.android.launcher3
          launchedFromUid=0 launchedFromPackage=null userId=0
          app=ProcessRecord{
    
    c4940bc 14811: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{
    
    3a6c4af #8 A=com.android.launcher3 U=0 StackId=0 sz=1}
          taskAffinity=com.android.launcher3
          realActivity=com.android.launcher3/.Launcher
          baseDir=/system/app/PaxLauncher3/PaxLauncher3.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=-1m29s234ms
          haveState=true icicle=Bundle[mParcelledData.dataSize=3788]
          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=-13s698ms
          resizeMode=RESIZE_MODE_FORCE_RESIZEABLE

    Running activities (most recent first):
      TaskRecord{
    
    3a6c4af #8 A=com.android.launcher3 U=0 StackId=0 sz=1}
        Run #0: ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}

    mLastPausedActivity: ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}

  mFocusedActivity: ActivityRecord{
    
    59a829e u0 com.example.test/.BActivity t9}//焦点Activity为BActivity
  mFocusedStack=ActivityStack{
    
    8238d9 stackId=1, 1 tasks} mLastFocusedStack=ActivityStack{
    
    8238d9 stackId=1, 1 tasks}
  mSleepTimeout=false
  mCurTaskIdForUser={
    
    0=9}
  mUserStackInFront={
    
    }
  mActivityContainers={
    
    0=ActivtyContainer{
    
    0}A, 1=ActivtyContainer{
    
    1}A}
  mLockTaskModeState=NONE mLockTaskPackages (userId:packages)=
    0:[]
 mLockTaskModeTasks[]


1.3 按Home按键退出应用,然后重新打开应用

  我们先不调试,我们想想想此时场景下会怎么处理呢!此时的Task相关的调度逻辑如下,此时会先找到已有的相关task,并显示栈顶的Activity,任务调度执行如下所示:

//[ActivityStarter.java]
	/*
	这里的sourceRecord是指发起调用者 
	r是指本次的将要启动的Activity
	startFlags取值为0
	doResume的值为true
	inTask为发起方指定的任务栈,此时为null
	这里主要确定目标Activity的launchMode Task栈等,即Task的创建和管理
	*/
    private int startActivityUnchecked(final ActivityRecord r, 
    									ActivityRecord sourceRecord,
            							IVoiceInteractionSession voiceSession, 
            							IVoiceInteractor voiceInteractor,
            							int startFlags, 
            							boolean doResume, 
            							ActivityOptions options, 
            							TaskRecord inTask) {
    
    

		//设置初始化状态,此时需要重点关注该方法中的如下几个目标值的获取,为了分析的方便,我会将该方法展开
		setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
		              voiceInteractor);
        /*****************************************************************************/
        	//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下
			private void setInitialState(ActivityRecord r, 
										ActivityOptions options, 
										TaskRecord inTask,
            							boolean doResume, 
            							int startFlags, 
            							ActivityRecord sourceRecord,
            							IVoiceInteractionSession 
            							voiceSession, 
            							IVoiceInteractor voiceInteractor) {
    
    
						//此处分支会走,将启动过程中的涉及的相关变量进行初始化
						reset();     
						...   
						mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP;//此时为false
						mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;//此时为false
						mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;//此时为false
						//这里重点关注一下,此时mIntent.getFlags携带的flags为0,此处很关键
						mLaunchFlags = adjustLaunchFlagsToDocumentMode(r,mLaunchSingleInstance, mLaunchSingleTask, mIntent.getFlags());
						...
						mDoResume = doResume;
						...
						mInTask = inTask;
						...
						mStartFlags = startFlags;//此时的mStartFlags为0
      		}
        /*****************************************************************************/
		//根据发起端,计算目标Activity的launchMode模式
		computeLaunchingTaskFlags();
		/*****************************************************************************/
			//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下
			//根据发起者launchMode情况,决定目标Activity的Flags情况
    		private void computeLaunchingTaskFlags() {
    
    
    			//此时场景下的mSourceRecord不为null,mInTask为null,所以不会进入该分支
    			if (mSourceRecord == null && mInTask != null && mInTask.stack != null) {
    
    
    				...
    			}else {
    
    //会进入此分支
		            mInTask = null;
		            //不满足条件,不会进入该分支
		            if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null
		                    && mSourceRecord.isFreeform())  {
    
    
		                	mAddingToTask = true;
		            }
    			}
        	}
        	//此时的mInTask为null,会进入此分支,但是该分支下面的三个小分支都不会进入
        	if (mInTask == null) {
    
    
	            if (mSourceRecord == null) {
    
    //mSourceRecord不为null,此时的mSourceRecord为Launcher,不会进入此分支
					...
	            } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
    
    //launcher应用activity的启动模式为singleTask
					...
	            } else if (mLaunchSingleInstance || mLaunchSingleTask) {
    
    //不会进入此分支,此时都为false
					...
	            }
        	}
		/*****************************************************************************/    
		//确定发起端的ActivityStack情况
		computeSourceStack();
		/*****************************************************************************/
			//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下     
			//确定发起端的Stack情况
	    	private void computeSourceStack() {
    
    
		        if (mSourceRecord == null) {
    
    //mSourceRecord不为null,不会进入此分支
					...
		        }
		        if (!mSourceRecord.finishing) {
    
    //此时明显mSourceRecord没有被finish所以会进入此分支
					//当调用者Activity不为空,且不处于finishing状态,则其所在栈赋于sourceStack
		            mSourceStack = mSourceRecord.task.stack;
		            return;
		        }
				...
	    	}   
   	  /*****************************************************************************/	

		mIntent.setFlags(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定义的。
	      */
		 //此时存在复用额Activity,因为我们前面已经创建了目标Activity而且没有被销毁
		 mReusedActivity = getReusableIntentActivity();
		/*****************************************************************************/	
			//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下 	 
			 private ActivityRecord getReusableIntentActivity() {
    
    
			 	  //此时的mLaunchFlags的取值为FLAG_ACTIVITY_RESET_TASK_IF_NEEDED|FLAG_ACTIVITY_NEW_TASK,所以为true
			      boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
			              (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
			              || mLaunchSingleInstance || mLaunchSingleTask;
			
				  //此时mInTask为false,mStartActivity.resultTo为null
			      putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
			      ActivityRecord intentActivity = null;
			      if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
    
    
			      	...
			      } else if (putIntoExistingTask) {
    
    
			          if (mLaunchSingleInstance) {
    
    //不会进入此分支
					...
			          } else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
    
    //不会进入此分支
					...
			          } else {
    
    //会走入此分支,在ASS中查找是否存在启动目标Activity,很明显此时存在,所以intentActivity得到的值为Activity B
			              intentActivity = mSupervisor.findTaskLocked(mStartActivity);
			          }
			      }
			      return intentActivity;
			  }
	    /*****************************************************************************/	

		 //如果找到了可重用的activity,需要清理掉原来的信息,并把当前启动的activity的信息拷贝进去
		 //做清理和拷贝工作,此时会进入此分支
        if (mReusedActivity != null) {
    
    	
        	...
			//设置当前启动Activity的Task为复用的Task,进入此分支
            if (mStartActivity.task == null) {
    
    
                mStartActivity.task = mReusedActivity.task;
            }        

	           /*
			 *这边处理启动时设置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) {
    
    //不会进入此分支
				...
	           }
			// 计算哪个task和activity要移至前台,必要时会进行task的清理工作
	        mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity);
			/*****************************************************************************/	
				//这里小伙们就不要关注排版问题了,主要是为了演示整个流程,各位就将就一下 	  
			    private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) {
    
    
			        mTargetStack = intentActivity.task.stack;
			        mTargetStack.mLastPausedActivity = null;
			        final ActivityStack focusStack = mSupervisor.getFocusedStack();
			        ActivityRecord curTop = (focusStack == null)
			                ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);//获取当前前台ActivityStack栈顶的ActivityRecord		
					//判断顶部的栈是否符合要求(即判断现在栈顶的栈是否为能够复用的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) {
    
    //此时的mLaunchTaskBehind为null不进入此分支
			                    ...
			                }
			                mMovedOtherTask = true;
			
	
			                final boolean willClearTask =
			                        (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
			                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);//此时willClearTask 的取值为false
			                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) {
    
    //不会进入该分支
			                            ...
			                    }
			                    mOptions = null;
			                }
			                updateTaskReturnToType(intentActivity.task, mLaunchFlags, focusStack);
			            }
			        }
			        if (!mMovedToFront && mDoResume) {
    
    //不进入此分支
						...
			        }
			
			        mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.task, INVALID_STACK_ID,
			                mTargetStack.mStackId);
			
					//此时Luancher启动的时候携带了该值,所以会走入此分支
			        if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
    
    
			            return mTargetStack.resetTaskIfNeededLocked(intentActivity, mStartActivity);
			        }
				...
			    }			
			/*****************************************************************************/		
            setTaskFromIntentActivity(mReusedActivity);

            if (!mAddingToTask && mReuseTask == null) {
    
    //进入此分支

                resumeTargetStackIfNeeded();
				Log.e(ACTIVITY_TAG, "mReusedActivity != null START_TASK_TO_FRONT");
                return START_TASK_TO_FRONT;
            }

       }				           
}

至此从按Home按键退出应用,然后重新打开应用的Task以及Stack的调度就完成了,我们对其小结一下,其主要流程可以精简为如下几个步骤:

  • 调用AS.setInitialState方法,对启动目标Activity时Task任务栈和ActivityStack栈将要涉及的变量进行初始化设置
  • 根据发起端Activity的情况,调用computeLaunchingTaskFlags计算目标Activity的launchMode模式
  • 调用computeSourceStack确定发起端Stack的情况
  • 经过上述的一系列处理以后,已经确定目标Activity相关的LauncherMode,flag等启动模式了,接下来调用getReusableIntentActivity确定是否有可复用的Activity,在此场景下存在复用的Activity
  • 进入存在复用Activity的分支,调用setTargetStackAndMoveToFrontIfNeeded处理复用的Activity和Task以及Stack
  • 接着直接调用resumeTargetStackIfNeeded恢复复用Task任务栈

经过如上的步骤以后,我们的目标Activity所属的Task和Stack就已经安排妥当了,我们此时可以通过命令查看相对应的Task任务栈和Stack栈了。

#adb shell dumpsys activity activities
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #1:
  mFullscreen=true
  mBounds=null
    Task id #9
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
    * TaskRecord{
    
    d361623 #9 A=com.example.test U=0 StackId=1 sz=2}
      userId=0 effectiveUid=u0a48 mCallingUid=u0a23 mUserSetupComplete=true mCallingPackage=com.android.launcher3
      affinity=com.example.test
      intent={
    
    act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.test/.MainActivity}
      realActivity=com.example.test/.MainActivity
      autoRemoveRecents=false isPersistable=true numFullscreen=2 taskType=0 mTaskToReturnTo=1
      rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
      Activities=[ActivityRecord{
    
    dd0bb9a u0 com.example.test/.AMainActivity t9}, ActivityRecord{
    
    59a829e u0 com.example.test/.BActivity t9}]
      askedCompatMode=false inRecents=true isAvailable=true
      lastThumbnail=android.graphics.Bitmap@d88386f lastThumbnailFile=/data/system_ce/0/recent_images/9_task_thumbnail.png
      stackId=1
      hasBeenVisible=true mResizeMode=RESIZE_MODE_FORCE_RESIZEABLE isResizeable=true firstActiveTime=1602505471813 lastActiveTime=1602505471813 (inactive for 4s)
      * Hist #1: ActivityRecord{
    
    59a829e u0 com.example.test/.BActivity t9}
          packageName=com.example.test processName=com.example.test
          launchedFromUid=10048 launchedFromPackage=com.example.test userId=0
          app=ProcessRecord{
    
    cd84720 15340:com.example.test/u0a48}
          Intent {
    
     cmp=com.example.test/.BActivity bnds=[184,356][360,544] }
          frontOfTask=false task=TaskRecord{
    
    d361623 #9 A=com.example.test U=0 StackId=1 sz=2}
          taskAffinity=com.example.test
          realActivity=com.example.test/.BActivity
          baseDir=/data/app/com.example.test-1/base.apk
          dataDir=/data/user/0/com.example.test
          stateNotNeeded=false componentSpecified=true mActivityType=0
          compat={
    
    320dpi} labelRes=0x7f050000 icon=0x7f020000 theme=0x7f060001
          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=ffe6e6e6
          launchFailed=false launchCount=0 lastLaunchTime=-12s222ms
          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_NOT_SHOWN
          fullscreen=true noDisplay=false immersive=false launchMode=0
          frozenBeforeDestroy=false forceNewConfig=false
          mActivityType=APPLICATION_ACTIVITY_TYPE
          waitingVisible=false nowVisible=true lastVisibleTime=-3s634ms
          resizeMode=RESIZE_MODE_FORCE_RESIZEABLE
      * Hist #0: ActivityRecord{
    
    dd0bb9a u0 com.example.test/.MainActivity t9}
          packageName=com.example.test processName=com.example.test
          launchedFromUid=10023 launchedFromPackage=com.android.launcher3 userId=0
          app=ProcessRecord{
    
    cd84720 15340:com.example.test/u0a48}
          Intent {
    
     act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.test/.MainActivity bnds=[184,356][360,544] }
          frontOfTask=true task=TaskRecord{
    
    d361623 #9 A=com.example.test U=0 StackId=1 sz=2}
          taskAffinity=com.example.test
          realActivity=com.example.test/.MainActivity
          baseDir=/data/app/com.example.test-1/base.apk
          dataDir=/data/user/0/com.example.test
          stateNotNeeded=false componentSpecified=true mActivityType=0
          compat={
    
    320dpi} labelRes=0x7f050000 icon=0x7f020000 theme=0x7f060001
          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=ffe6e6e6
          launchFailed=false launchCount=0 lastLaunchTime=-18s855ms
          haveState=true icicle=Bundle[mParcelledData.dataSize=1132]
          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=-18s367ms
          resizeMode=RESIZE_MODE_FORCE_RESIZEABLE

    Running activities (most recent first):
      TaskRecord{
    
    d361623 #9 A=com.example.test U=0 StackId=1 sz=2}
        Run #1: ActivityRecord{
    
    59a829e u0 com.example.test/.BActivity t9}
        Run #0: ActivityRecord{
    
    dd0bb9a u0 com.example.test/.MainActivity t9}

    mResumedActivity: ActivityRecord{
    
    59a829e u0 com.example.test/.BActivity t9}

  Stack #0:
  mFullscreen=true
  mBounds=null
    Task id #8
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
    * TaskRecord{
    
    3a6c4af #8 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{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}]
      askedCompatMode=false inRecents=true isAvailable=true
      lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/8_task_thumbnail.png
      stackId=0
      hasBeenVisible=true mResizeMode=RESIZE_MODE_FORCE_RESIZEABLE isResizeable=false firstActiveTime=1602505471784 lastActiveTime=1602505471784 (inactive for 4s)
      * Hist #0: ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}
          packageName=com.android.launcher3 processName=com.android.launcher3
          launchedFromUid=0 launchedFromPackage=null userId=0
          app=ProcessRecord{
    
    c4940bc 14811: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{
    
    3a6c4af #8 A=com.android.launcher3 U=0 StackId=0 sz=1}
          taskAffinity=com.android.launcher3
          realActivity=com.android.launcher3/.Launcher
          baseDir=/system/app/PaxLauncher3/PaxLauncher3.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=-1m38s596ms
          haveState=true icicle=Bundle[mParcelledData.dataSize=3788]
          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=-5s891ms
          resizeMode=RESIZE_MODE_FORCE_RESIZEABLE

    Running activities (most recent first):
      TaskRecord{
    
    3a6c4af #8 A=com.android.launcher3 U=0 StackId=0 sz=1}
        Run #0: ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}

    mLastPausedActivity: ActivityRecord{
    
    d5e92f9 u0 com.android.launcher3/.Launcher t8}

  mFocusedActivity: ActivityRecord{
    
    59a829e u0 com.example.test/.BActivity t9}
  mFocusedStack=ActivityStack{
    
    8238d9 stackId=1, 1 tasks} mLastFocusedStack=ActivityStack{
    
    8238d9 stackId=1, 1 tasks}
  mSleepTimeout=false
  mCurTaskIdForUser={
    
    0=9}
  mUserStackInFront={
    
    }
  mActivityContainers={
    
    0=ActivtyContainer{
    
    0}A, 1=ActivtyContainer{
    
    1}A}
  mLockTaskModeState=NONE mLockTaskPackages (userId:packages)=
    0:[]
 mLockTaskModeTasks[]



总结

  Activity启动流程(三)- Activity Task调度算法复盘分析到这里就要告一段落了,从前面的分析可以看出来,Activity和Task的调度算法非常复杂,最好需结合实际场景才好分析,只有这样才知道是否需要新建Task,还是将新的ActivityRecord加入到已有的Task里。当前这一切的前提条件是我们能理解启动模式的一些特点,这样才能对理解调度算法有一个基础,如果一上来就是懵懵懂懂的乱干那就完蛋了,因为你会被这源码绕的晕头转向的搞不清方向了。好了今天就到这里了,希望小伙们能点赞和关注,谢谢!

猜你喜欢

转载自blog.csdn.net/tkwxty/article/details/108995543