简介

ActivityManagerService中对Activity的管理都是以Task的形式,任务Task是指在执行特定作业时与用户交互的一系列 Activity, 这些 Activity 按照各自的打开顺序排列在堆栈Stack中,AMS中分别以TaskRecord和ActivityStack表示,Activity则用ActivityRecord表示。因此我们也可以这么认为ActivityManagerService对Activity的管理,其实真正实现上来说是对ActivityStack,TaskRecord和ActivityRecord这三个数据结构的管理。更多详细的Task,Stack信息我们可以参考Google官网中Understand Tasks and Back Stack。
通常我们可以通过如下命令获取Android系统中Stack和Task的一些基本信息:

adb shell am stack list
Stack id=1 bounds=[0,0][240,320] displayId=0 userId=0
  taskId=142: com.android.settings/com.android.settings.Settings bounds=[0,0][240,320] userId=0 visible=true topActivity=ComponentInfo{com.android.settings/com.android.settings.Settings}

Stack id=0 bounds=[0,0][240,320] displayId=0 userId=0
  taskId=139: com.android.launcher3/com.android.launcher3.Launcher bounds=[0,0][240,320] userId=0 visible=false topActivity=ComponentInfo{com.android.launcher3/com.android.launcher3.Launcher}

如果我们想要获取对应Stack中Task以及Task中Activity的详细信息,比如Task中Activity的数量,Activity的启动Intent,Activity的启动模式等等,我们可以通过如下命令:

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #1:
  mFullscreen=true
  isSleeping=false
  mBounds=null
    Task id #142
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
    * TaskRecord{32da96f #142 A=com.android.settings U=0 StackId=1 sz=1}
      userId=0 effectiveUid=1000 mCallingUid=u0a14 mUserSetupComplete=true mCallingPackage=com.android.launcher3
      affinity=com.android.settings
      intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.settings/.Settings}
      origActivity=com.android.settings/.Settings
      realActivity=com.android.settings/.Settings
      autoRemoveRecents=false isPersistable=true numFullscreen=1 taskType=0 mTaskToReturnTo=1
      rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
      Activities=[ActivityRecord{f46fe89 u0 com.android.settings/.Settings t142}]
      askedCompatMode=false inRecents=true isAvailable=true
      lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/142_task_thumbnail.png
      stackId=1
      hasBeenVisible=true mResizeMode=RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION mSupportsPictureInPicture=false isResizeable=true firstActiveTime=1672808557 lastActiveTime=1672809402 (inactive for 223s)
      * Hist #0: ActivityRecord{f46fe89 u0 com.android.settings/.Settings t142}
          packageName=com.android.settings processName=com.android.settings
          launchedFromUid=10014 launchedFromPackage=com.android.launcher3 userId=0
          app=ProcessRecord{218dd1e 2581:com.android.settings/1000}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.settings/.Settings bnds=[159,155][237,242] }
          frontOfTask=true task=TaskRecord{32da96f #142 A=com.android.settings U=0 StackId=1 sz=1}
          taskAffinity=com.android.settings
          realActivity=com.android.settings/.Settings
          baseDir=/system/priv-app/Settings/Settings.apk
          dataDir=/data/user_de/0/com.android.settings
          stateNotNeeded=false componentSpecified=true mActivityType=0
          compat={160dpi always-compat} labelRes=0x7f120b06 icon=0x7f0800df theme=0x7f1301c8
          mLastReportedConfigurations:
           mGlobalConfig={1.0 ?mcc?mnc [en_US] ldltr sw240dp w240dp h248dp 160dpi smll port -touch -keyb/v/h -nav/h appBounds=Rect(0, 0 - 240, 272) s.4}
           mOverrideConfig={1.0 ?mcc?mnc [en_US] ldltr sw240dp w240dp h248dp 160dpi smll port -touch -keyb/v/h -nav/h appBounds=Rect(0, 0 - 240, 272) s.4}
          CurrentConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw240dp w240dp h248dp 160dpi smll port -touch -keyb/v/h -nav/h appBounds=Rect(0, 0 - 240, 272) s.4}
          taskDescription: iconFilename=/data/system_ce/0/recent_images/142_activity_icon_1672808529.png label="null" primaryColor=fff5f5f5
            backgroundColor=fffafafa
            statusBarColor=ff757575
            navigationBarColor=ff000000
          launchFailed=false launchCount=1 lastLaunchTime=-3m44s281ms
          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=2
          frozenBeforeDestroy=false forceNewConfig=false
          mActivityType=APPLICATION_ACTIVITY_TYPE
          waitingVisible=false nowVisible=true lastVisibleTime=-3m40s512ms
          resizeMode=RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION
          mLastReportedMultiWindowMode=false mLastReportedPictureInPictureMode=false

    Running activities (most recent first):
      TaskRecord{32da96f #142 A=com.android.settings U=0 StackId=1 sz=1}
        Run #0: ActivityRecord{f46fe89 u0 com.android.settings/.Settings t142}

    mResumedActivity: ActivityRecord{f46fe89 u0 com.android.settings/.Settings t142}

  Stack #0:
  mFullscreen=true
  isSleeping=false
  mBounds=null
    Task id #139
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
    * TaskRecord{b1b0e06 #139 I=com.android.launcher3/.Launcher U=0 StackId=0 sz=1}
      userId=0 effectiveUid=u0a14 mCallingUid=1000 mUserSetupComplete=true mCallingPackage=null
      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{1f09444 u0 com.android.launcher3/.Launcher t139}]
      askedCompatMode=false inRecents=true isAvailable=true
      lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/139_task_thumbnail.png
      stackId=0
      hasBeenVisible=true mResizeMode=RESIZE_MODE_RESIZEABLE mSupportsPictureInPicture=false isResizeable=true firstActiveTime=1667109722 lastActiveTime=1672808679 (inactive for 224s)
      * Hist #0: ActivityRecord{1f09444 u0 com.android.launcher3/.Launcher t139}
          packageName=com.android.launcher3 processName=com.android.launcher3
          launchedFromUid=0 launchedFromPackage=null userId=0
          app=ProcessRecord{31ae0ef 3012:com.android.launcher3/u0a14}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher }
          frontOfTask=true task=TaskRecord{b1b0e06 #139 I=com.android.launcher3/.Launcher U=0 StackId=0 sz=1}
          taskAffinity=null
          realActivity=com.android.launcher3/.Launcher
          baseDir=/system/priv-app/Launcher3Go/Launcher3Go.apk
          dataDir=/data/user/0/com.android.launcher3
          stateNotNeeded=true componentSpecified=false mActivityType=1
          compat={160dpi always-compat} labelRes=0x7f0c000d icon=0x7f020021 theme=0x7f120002
          mLastReportedConfigurations:
           mGlobalConfig={1.0 ?mcc?mnc [en_US] ldltr sw240dp w240dp h248dp 160dpi smll port -touch -keyb/v/h -nav/h appBounds=Rect(0, 0 - 240, 272) s.4}
           mOverrideConfig={1.0 ?mcc?mnc [en_US] ldltr sw240dp w240dp h248dp 160dpi smll port -touch -keyb/v/h -nav/h appBounds=Rect(0, 0 - 240, 272) s.4}
          CurrentConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw240dp w240dp h248dp 160dpi smll port -touch -keyb/v/h -nav/h appBounds=Rect(0, 0 - 240, 272) s.4}
          taskDescription: iconFilename=null label="null" primaryColor=fff5f5f5
            backgroundColor=fffafafa
            statusBarColor=0
            navigationBarColor=0
          launchFailed=false launchCount=0 lastLaunchTime=-1h38m41s610ms
          haveState=true icicle=Bundle[mParcelledData.dataSize=4096]
          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=-43m15s482ms
          resizeMode=RESIZE_MODE_RESIZEABLE
          mLastReportedMultiWindowMode=false mLastReportedPictureInPictureMode=false

    Running activities (most recent first):
      TaskRecord{b1b0e06 #139 I=com.android.launcher3/.Launcher U=0 StackId=0 sz=1}
        Run #0: ActivityRecord{1f09444 u0 com.android.launcher3/.Launcher t139}

    mLastPausedActivity: ActivityRecord{1f09444 u0 com.android.launcher3/.Launcher t139}
Display #1 (activities from top to bottom):

  ResumedActivity: ActivityRecord{f46fe89 u0 com.android.settings/.Settings t142}
  mFocusedStack=ActivityStack{4f3c6a8 stackId=1, 1 tasks} mLastFocusedStack=ActivityStack{4f3c6a8 stackId=1, 1 tasks}
  mCurTaskIdForUser={0=142}
  mUserStackInFront={}
  mStacks={0=ActivityStack{7020d13 stackId=0, 1 tasks}, 1=ActivityStack{4f3c6a8 stackId=1, 1 tasks}}
  mLockTaskModeState=NONE  mLockTaskPackages (userId:packages)=
    0:[]
 mLockTaskModeTasks[]
  KeyguardController:
    mKeyguardShowing=false
    mKeyguardGoingAway=false
    mOccluded=false
    mDismissingKeyguardActivity=null
    mDismissalRequested=false
    mVisibilityTransactionDepth=0

至于为什么使用如上命令就能获取这么多的信息,建议还是去多多的阅读系统源码,或许我们可以找到我们想要的答案。

ActivityManagerService中的Stack

Android系统中一些常用的Stack

Name

Value

Description

HOME_STACK_ID

0

一般HomeActivity所在的Stack,就是Launcher所在的Stack

FULLSCREEN_WORKSPACE_STACK_ID

1

正常情况下,我们启动的Activity都在这个Stack

FREEFORM_WORKSPACE_STACK_ID

2

自由模式下,一般平板中会使用

DOCKED_STACK_ID

3

进入分屏模式后,新创建的便是该类型的Stack

PINNED_STACK_ID

4

画中画模式下,处于画中画Activity所在的Stack

RECENTS_STACK_ID

5

SystemUI的RecentActivity所在的Stack

ASSISTANT_STACK_ID

6

有Android assistant启动的Activity都在此Stack,国内手机貌似很少使用该Stack

从这些常用的Stack的作用上来看,我们可以简单的理解Android更多的会根据各种不同的行为和场景来区分不同的ActivityStack。从之前的dump信息我们便可以断定ActivityStack中主要存放的就是各种Task,对应的便是TaskRecord,实际Android代码中也确实如此。对于ActivityStack的各种管理,Android又抽象出ActivityStackSupervisor类,我们从命名中也可以看出该类专门负责ActivityStack的管理。后续Activity的启动流程分析中,我们将更多的接触并分析该类。一般Android系统启动时,开机启动到Launcher界面,便会创建HOME_STACK_ID Stack(下面便是开机的Trace Log,可以结合Trace和代码具体理一下这个创建的过程,这里就不再细述了)专门用于存放Home Activity。

01-20 23:40:35.110  1964  1964 D ABM_TRACE_MAIN: java.lang.Throwable
01-20 23:40:35.110  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.am.ActivityStack.<init>(ActivityStack.java:458)
01-20 23:40:35.110  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.am.ActivityStackSupervisor.createStack(ActivityStackSupervisor.java:2657)
01-20 23:40:35.110  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.am.ActivityStackSupervisor.createStackOnDisplay(ActivityStackSupervisor.java:2648)
01-20 23:40:35.110  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.am.ActivityStackSupervisor.getStack(ActivityStackSupervisor.java:2251)
01-20 23:40:35.110  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.am.ActivityStackSupervisor.setWindowManager(ActivityStackSupervisor.java:689)
01-20 23:40:35.110  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.am.ActivityManagerService.setWindowManager(ActivityManagerService.java:2629)
01-20 23:40:35.110  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.SystemServer.startOtherServices(SystemServer.java:861)
01-20 23:40:35.110  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.SystemServer.run(SystemServer.java:398)
01-20 23:40:35.110  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.SystemServer.main(SystemServer.java:274)
01-20 23:40:35.110  1964  1964 D ABM_TRACE_MAIN: 	at java.lang.reflect.Method.invoke(Native Method)
01-20 23:40:35.110  1964  1964 D ABM_TRACE_MAIN: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
01-20 23:40:35.110  1964  1964 D ABM_TRACE_MAIN: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:787)
01-20 23:40:35.129  1964  1964 I wm_stack_created: 0
01-20 23:40:35.140  1964  1964 D ABM_TRACE_MAIN: java.lang.Throwable
01-20 23:40:35.140  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.am.ActivityStackSupervisor$ActivityDisplay.attachStack(ActivityStackSupervisor.java:4749)
01-20 23:40:35.140  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.am.ActivityStack.postAddToDisplay(ActivityStack.java:514)
01-20 23:40:35.140  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.am.ActivityStack.<init>(ActivityStack.java:472)
01-20 23:40:35.140  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.am.ActivityStackSupervisor.createStack(ActivityStackSupervisor.java:2657)
01-20 23:40:35.140  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.am.ActivityStackSupervisor.createStackOnDisplay(ActivityStackSupervisor.java:2648)
01-20 23:40:35.140  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.am.ActivityStackSupervisor.getStack(ActivityStackSupervisor.java:2251)
01-20 23:40:35.140  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.am.ActivityStackSupervisor.setWindowManager(ActivityStackSupervisor.java:689)
01-20 23:40:35.140  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.am.ActivityManagerService.setWindowManager(ActivityManagerService.java:2629)
01-20 23:40:35.140  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.SystemServer.startOtherServices(SystemServer.java:861)
01-20 23:40:35.140  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.SystemServer.run(SystemServer.java:398)
01-20 23:40:35.140  1964  1964 D ABM_TRACE_MAIN: 	at com.android.server.SystemServer.main(SystemServer.java:274)
01-20 23:40:35.140  1964  1964 D ABM_TRACE_MAIN: 	at java.lang.reflect.Method.invoke(Native Method)
01-20 23:40:35.140  1964  1964 D ABM_TRACE_MAIN: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
01-20 23:40:35.140  1964  1964 D ABM_TRACE_MAIN: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:787)
01-20 23:40:35.141  1964  1964 V ABM_Log : attachStack: attaching ActivityStack{abbc88a stackId=0, 0 tasks} to displayId=0 position=0

一般我们可以通过event log可以获取ActivityStack的创建与销毁

wm_stack_created (StackId|1|5)
wm_task_removed (TaskId|1|5),(Reason|3)

虽然这是WindowManagerService相关的Log,但是Window在组织和管理各种窗口时ActivityManagerService管理Activity一样都是通过各种堆栈形式的,并且WindowManagerService里面对应的堆栈顺序都是和ActivityManagerService中保持一致的,他们在Activity启动时创建的顺序也是一前一后的,其中相关的数据结构的对应关系如下:

ActivityStack 	TaskStack
TaskRecord 	Task
ActivityRecord	APPWindowToken

一般我们在创建Activity时,根据不同功能的需要,创建对应或使用不同的ActivityStack,一般使用ActivityStackSupervisor.getStack去获取,如果不存在便创建新的。对应的当我们Activity销毁的时候,Android系统会从该Activity所在的Task中移除该Activity,如果该Activity是lastActivity,系统还会从ActivityStack中移除该Task,如果从ActivityStack移除完该Task之后,ActivityStack中不存在任何Task,系统还会将该ActivityStack销毁回收。

 ActivityManagerService中的Task

Activity启动过程中,对于ActivityStack应用开发者很少接触, 我们也可以不去关注它的创建与销毁,更多的这都是系统完成的。通过前文ActivityManagerService解读之Activity启动再探所述,我们知道可以更多的使用不同的启动模式,外加各种Task属性和设置不同的Intent flag来影响Activity Task的创建管理行为。比如每次需要Activity创建单独的Task时您可以使用singleInstance模式,等等(更多关于启动模式和Task属性以及不同intent flag请参阅ActivityManagerService解读之Activity启动再探一文)。当我们启动Activity或者销毁Activity时,系统为该Activity创建Task或者销毁Task时候,我们一般会看见如下Log:

wm_task_created (TaskId|1|5),(StackId|1|5)
am_create_task (User|1|5),(Task ID|1|5)

wm_task_removed (TaskId|1|5),(Reason|3)

Task是从用户角度来管理Activity的,Android系统更多的是根据用户的操作来将一系列Activity按启动顺序放于同一个Task中,这些Activity可以来自不同的应用,因为从用户角度来说,这些操作只是为自己服务而已,用户并不知道他们来自不同的应用。

写在最后

ActivityStack和TaskRecord是ActivityManagerService管理Activity的两个相当重要的数据,了解他们的作用对分析Activity启动大有作用,懂得Activity启动流程,在日常项目开发中才能应对各种需求,实施各种不同的应对方案,比如最近很火的插件技术,想要插件话Activity,必须得了解Activity的启动流程,又比如优化应用的启动速度等等。