文章目录

  • Activity状态
  • 管理者的诞生
  • ActivityStack
  • stack切换

Activity状态

  Activity在应用端由ActivityClientRecord负责描述其生命周期的过程与状态,但最终这些过程与状态是由ActivityManagerService(以下简称AMS)来管理和控制的。类似于应用进程在AMS中使用ProcessRecord描述,安卓四大组件在AMS中也拥有对应的对象来描述。

  • BroadcastRecord:描述了应用进程的BroadcastReceiver,由BroadcastQueue负责管理。
  • ServiceRecord:描述了Service服务组件,由ActiveServices负责管理。
  • ContentProviderRecord:描述ContentProvider内容提供者,由ProviderMap管理。
  • ActivityRecord:用于描述Activity,由ActivityStackSupervisor进行管理。

  正如深入理解AMS之Activity对Activity的介绍那样,Activity直观上来说就意指一个个的窗口页面。安卓为了有效管理窗口页面的交互过程与状态,衍生出了Activity生命周期的概念。AMS为了管理Activity在这些生命周期间的状态迁移,定义了如下Activity可能经历到的状态:

// frameworks/base/services/core/java/com/android/server/am/ActivityStack.java$ActivityStateenum ActivityState {INITIALIZING,//正在初始化RESUMED,//恢复前台状态PAUSING,//正在暂停PAUSED,//暂停状态STOPPING,//正在停止STOPPED,//停止状态FINISHING,//正在移除DESTROYING,//正在销毁DESTROYED//销毁状态}

  上述这些状态并不难理解,其中某些状态的定义甚至与Activity生命周期方法暗暗相合。ActivityRecord中的state成员正是为了描述其对应的Activity所处的状态。

// frameworks/base/services/core/java/com/android/server/am/ActivityRecord.javaActivityState state;    // current state we are in

管理者的诞生

  在AMS中,ActivityStackSupervisor(以下简称ASS)负责管理Activity,从其类名含义上而言,ActivityStack是Activity任务栈,Supervisor意为监管者,两者合而为一也很清晰地表明了ASS的作用。

  ASS在深入理解AMS之启动过程一文中介绍AMS构造方法时被创建。

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.javapublic ActivityStackSupervisor(ActivityManagerService service) {mService = service;mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());}

  在ASS构造方法中获取了在AMS中创建的ServiceThread线程(这个线程本质上是一个HandlerThread线程)的Looper,并据此创建了属于ASS独有的Handler,此后往这个mHandler发送的Message最终都会在AMS的服务线程中执行。

  在ASS被创建完成后并不意味着这个管理者可以立即为Activity服务了,事实上Activity创建时需要指定显示屏幕(一般情况下,使用了默认屏幕所以可以不指定)和创建Window窗口,这就还需要等待DMS与WMS初始化完成,在SystemServer中DMS与WMS先后完成初始化后会调用AMS.setWindowManager()方法并进而通知ASS。

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java#setWindowManagervoid setWindowManager(WindowManagerService wm) {synchronized (mService) {mWindowManager = wm;mDisplayManager =(DisplayManager)mService.mContext.getSystemService(Context.DISPLAY_SERVICE);mDisplayManager.registerDisplayListener(this, null);Display[] displays = mDisplayManager.getDisplays();for (int displayNdx = displays.length - 1; displayNdx >= 0; --displayNdx) {final int displayId = displays[displayNdx].getDisplayId();ActivityDisplay activityDisplay = new ActivityDisplay(displayId);if (activityDisplay.mDisplay == null) {throw new IllegalStateException("Default Display does not exist");}mActivityDisplays.put(displayId, activityDisplay);}createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY);mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID);//...}}

  当代码进行到此处,ASS就要着手准备Activity的管理环境了。在介绍上述代码的作用之前,有几个必要的类需要先了解一下:

  • ActivityDisplay。在ASS中用于描述显示屏幕,其构造方法传入其负责描述屏幕的displayId,这样ActivityDisplay创建时就可据此知道其所描述屏幕的各项属性。ASS中所有的ActivityDisplay都会被保存在成员mActivityDisplays中。
// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java$ActivityDisplayclass ActivityDisplay {//...final ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();ActivityDisplay(int displayId) {final Display display = mDisplayManager.getDisplay(displayId);if (display == null) {return;}init(display);}void init(Display display) {mDisplay = display;mDisplayId = display.getDisplayId();mDisplay.getDisplayInfo(mDisplayInfo);}//...}

  在ActivityDisplay中有个非常重要的集合mStacks,这个集合管理了其所描述的显示屏幕的所有ActivityStack,换言之,此屏幕上的所有ActivityStack都在此集合中有记录,可以通过attachActivities()和detachActivitiesLocked()方法来增删这些ActivityStack。

  除此之外,在ASS中还提供了对虚拟屏幕的显示需求的类VirtualActivityDisplay类(继承自ActivityDisplay),这个描述类的构造方法需要传入虚拟屏幕的宽、高、屏幕密度,之后通过DMS的createVirtualDisplay将这个display构建出来。

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java$VirtualActivityDisplayclass VirtualActivityDisplay extends ActivityDisplay {VirtualDisplay mVirtualDisplay;VirtualActivityDisplay(int width, int height, int density) {DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();mVirtualDisplay = dm.createVirtualDisplay(mService.mContext, null,VIRTUAL_DISPLAY_BASE_NAME, width, height, density, null,DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY, null, null);//根据参数构建虚拟屏幕init(mVirtualDisplay.getDisplay());mWindowManager.handleDisplayAdded(mDisplayId);//通知WMS屏幕增加}
  • ActivityContainer。ActivityStack的容器类,它负责描述ActivityStack,包括其StackId、所属Display、容器状态等。ActivityContainer继承自IActivityContainer.Stub,支持binder调用,显而易见的是,它与其负责描述ActivityStack是一对一关系。
// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java$ActivityContainerclass ActivityContainer extends android.app.IActivityContainer.Stub {//...final int mStackId;IActivityContainerCallback mCallback = null;final ActivityStack mStack;//...ActivityDisplay mActivityDisplay;int mContainerState = CONTAINER_STATE_HAS_SURFACE;ActivityContainer(int stackId) {synchronized (mService) {mStackId = stackId;mStack = new ActivityStack(this);//...}}
  • ActivityStack。Stack在计算机术语中意为FIFO类型的线性栈,此处我们把ActivityStack称为任务栈(之后本文任务栈皆指ActivityStack)。如果我们把向XXX商家付款、与XXX进行微信聊天、上淘宝买手机理解为一个个任务的话,那么这些任务按时间来排序就会形成任务序列,这个任务序列就组成ActivityStack。安卓则对这些任务栈的区分更为严格,在副屏处理的任务会放入副屏任务栈中,由副屏ActivityDisplay进行管理。

  • TaskRecord。TaskRecord是任务记录的意思,如果我们把上淘宝买手机称作一个任务,那么这个任务至少有那么几步操作:1.进淘宝首页搜手机关键词,2.列表页寻找心仪手机,3.进入详情页购买并付款。这几步操作构成了多个Activity页面组成的显示序列,这就是一个TaskRecord,由于按返回按键后会回到上一个显示页面,我们也可以称之为返回栈。在系统中,多个TaskRecord可组成一个ActivityStack,由ActivityStack的成员mTaskHistory负责记录。

  • ActivityRecord。上边已经介绍过,Activity主要用于描述一个Activity。但是需要注意的是:一个ActivityRecord描述了一个启动的Activity,但是一个Activity却可以由于启动方式的原因存在多个ActivityRecord。

  再回到ASS.setWindowManager()方法中,我们可以看见其通过DMS.getDisplays()获取已有的显示屏幕并通过ActivityDisplay来描述这些Display。然后为默认屏幕创建了HomeStack,这个操作通过方法createStackOnDisplay()完成。

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.javaprivate int createStackOnDisplay(int stackId, int displayId) {ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);if (activityDisplay == null) {return -1;}ActivityContainer activityContainer = new ActivityContainer(stackId);mActivityContainers.put(stackId, activityContainer);activityContainer.attachToDisplayLocked(activityDisplay);return stackId;}

  对于主屏也就是DEFAULT_DISPLAY默认屏幕来说,其一般拥有两个ActivityStack:其一为此处创建的HomeStack,主要负责管理Launcher中的安卓桌面和SystemUI中的最近任务列表;另一个就是管理其他应用Activity的NormalStack。这两种Stack及其内容我们可以通过命令dumpsys activity activities查看。

HomeStack与NormalStack本质上都是ActivityStack,此处是基于其功能上的不同才将这两种ActivityStack分别命名。

  安卓系统启动后首先显示的是存放于HomeStack的安卓桌面Launcher,所以ASS在启动时就会将HomeStack初始化,并将其记录为焦点Stack。

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java#setWindowManagermHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID);

  上述代码中焦点Stack(即FocusedStack)意指上次启动的Activity所处的Stack,初始情况下将其记录为HomeStack也无可非议,但若之后普通应用Activity启动,则focus会转移到NormalStack身上。为了区分Activity是应该放入HomeStack还是NormalStack中进行管理,每个ActivityRecord都有一个成员变量mActivityType来辨识其类型,ActivityRecord的可能类型如下:

// frameworks/base/services/core/java/com/android/server/am/ActivityRecord.javastatic final int APPLICATION_ACTIVITY_TYPE = 0;static final int HOME_ACTIVITY_TYPE = 1;static final int RECENTS_ACTIVITY_TYPE = 2;

  很容易想象,若当前创建的ActivityRecord类型以HOME或RECENT开头,则应该存入HomeStack进行管理。

ActivityStack

  ASS中的HomeStack和NormalStack分别存放不同类型的ActivityRecord,且对ActivityRecord的实际管理操作也是由它负责。出于管理需要,在ActivityStack中形成了庞大的成员体系。

  下边是用于管理ActivityRecord的集合部分。

ArrayList 泛型类型 作用
mTaskHistory TaskRecord 管理了属于当前stack的各种Task任务,按时间序列排序,
mLRUActivities ActivityRecord 按LRU排序的所有启动过的Activity,第一个元素为LRU元素
mNoAnimActivities ActivityRecord 集合中的Activity不考虑状态迁移动画

  下边是用于管理ActivityRecord的状态部分。

ActivityRecord 作用
mPausingActivity 当前正在暂停的Activity
mLastPausedActivity 上一个处于暂停状态的Activity
mLastNoHistoryActivity 上一个不会有历史记录的Activity
mResumedActivity 当前出于恢复状态(即出于前台)的Activity,可能为空
mLastStartedActivity 上一个被启动的Activity

  ActivityStack主要负责管理Task任务。当我们调用startActivity()时,ASS会判断当前将要启动的Activity是否需要新的Task,如果需要的话就创建TaskRecord并交由ActivityStack的startActivityLocked()方法来负责执行。

  startActivityLocked()方法具体内容如下所示,我们仅关注其Task任务部分。

// frameworks/base/services/core/java/com/android/server/am/ActivityStack.javafinal void startActivityLocked(ActivityRecord r, boolean newTask,boolean doResume, boolean keepCurTransition, Bundle options) {TaskRecord rTask = r.task;final int taskId = rTask.taskId;if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {insertTaskAtTop(rTask);//把rTask挪至ActivityStack的栈顶mWindowManager.moveTaskToTop(taskId);//关联WMS}TaskRecord task = null;//...task = r.task;task.addActivityToTop(r);//把要启动的ActivityRecord挪至TaskRecord栈顶task.setFrontOfTask();//将当前TaskRecord的frontOfTask变量置为true,Stack中其他TaskRecord相应变量置为false。r.putInHistory();//将当前ActivityRecord置为可放入history记录中//...if (doResume) {mStackSupervisor.resumeTopActivitiesLocked(this, r, options);//将stack任务栈顶的task恢复,主要是task返回栈中的栈顶Activity恢复。}}

  上述方法中insertTaskAtTop()方法就是把当前的task放入ActivityStack的成员mTaskHistory中进行管理。

  mTaskHistory中的TaskRecord根据其所处的ActivityStack类型的不同,可以区分为HomeTask及ApplicationTask,这点同ActivityRecord的类型区分极为相似。这种相似性是理所当然的,因为TaskRecord类型的区分主要依据其栈底ActivityRecord元素的类型。由此,TaskRecord中有以下方法判断其自身类型。

// frameworks/base/services/core/java/com/android/server/am/TaskRecord.javaboolean isHomeTask() {return taskType == HOME_ACTIVITY_TYPE;}boolean isApplicationTask() {return taskType == APPLICATION_ACTIVITY_TYPE;}boolean isOverHomeStack() {return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE;}

stack切换

  在介绍Stack切换之前,我们先了解一下FocusedStack的概念。

FocusedStack同HomeStack、NormalStack一样,在本文中都是一个抽象概念而并非具体java类。在ASS管理多ActivityStack的过程中,处于显示状态的ActivityRecord所在的ActivityStack就被成为FocusedStack。系统初始化完成后Launcher桌面处于显示状态,所以HomeStack就被默认设为FocusedStack,但当我们点击桌面上的某个应用后,这时候就是NormalStack处于焦点的了。

  ASS所负责启动的ActivityRecord因为其类型的不同需要存放在不同的ActivityStack中。所以每启动一次Activity,其所处的ActivityStack就需要检查一次是否是当前FocusedStack,如果不是则需要调整FocusedStack,这个调整过程是由下边adjustStackFocus()方法控制的。

  根据要启动的Activity是属于HomeStack还是NormalStack,adjustStackFocus()方法的内容可以据此分为两个分支。我们先来看下HomeStack分支的内容。

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.javaActivityStack adjustStackFocus(ActivityRecord r, boolean newTask) {final TaskRecord task = r.task;// On leanback only devices we should keep all activities in the same stack.if (!mLeanbackOnlyDevice &&(r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {//NormalStack分支,此处不展开}return mHomeStack;}

  如上可见,如果当前系统是Leanback TV系统,或者要启动的Activity属于HomeStack所管辖的类型(HOME_ACTIVITY_TYPE或RECENTS_ACTIVITY_TYPE),则adjustStackFocus()方法返回的是HomeStack。否则,则需要调整focus即进入if语句中的NormalStack分支。

  以下即是adjustStackFocus()方法真正要调整focus的完整过程。

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java#adjustStackFocus//part1if (task != null) {//如果启动r是需要新建Task的,则此处task为空,否则则进入此循环。final ActivityStack taskStack = task.stack;if (taskStack.isOnHomeDisplay()) {//主屏上的stackif (mFocusedStack != taskStack) {if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Setting " +"focused stack to r=" + r + " task=" + task);mFocusedStack = taskStack;} else {if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,"adjustStackFocus: Focused stack already=" + mFocusedStack);}}return taskStack;//如果ActivityRecord是普通应用且指定了Task,则此处变焦后返回stack}//part2final ActivityContainer container = r.mInitialActivityContainer;//r创建时指定if (container != null) {// The first time put it on the desired stack, after this put on task stack.r.mInitialActivityContainer = null;return container.mStack;}//part3if (mFocusedStack != mHomeStack && (!newTask ||mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {//主要不是Virtual的,isEligible都返回trueif (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,"adjustStackFocus: Have a focused stack=" + mFocusedStack);return mFocusedStack;}//part4final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;//取到主屏上所有stackfor (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {final ActivityStack stack = homeDisplayStacks.get(stackNdx);if (!stack.isHomeStack()) {if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,"adjustStackFocus: Setting focused stack=" + stack);mFocusedStack = stack;return mFocusedStack;}}//part5//考虑到第一次adjust情形时normal stack还并未创建// Need to create an app stack for this user.int stackId = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r +" stackId=" + stackId);mFocusedStack = getStack(stackId);return mFocusedStack;

这个相应的调整过程如代码中所示的那样可以划分为5种情形。

  1. 当前启动的Activity已找到Task容纳,属于非newTask的情形。如果已有task存放,则可据此找到Task所属ActivityStack,并且如果被启动的Activity是主屏Activity,则可调整focus(说明focus这个概念只有主屏有)。
  2. 当前启动的Activity指定了想要存放的ActivityContainer(即ActivityStack)。ActivityContainer是ActivityStack的容器类,它们是一对一的关系。此处若果指明了启动Activity的存放容器mInitialActivityContainer,就意味着Activity找到了ActivityStack来存放。
  3. 当前处于focus态的ActivityStack并非HomeStack(说明focus至少已调整过一次)。走到此处的Activity显然没有指定其所处的Task,只要当前的focus不是在HomeStack或虚拟出来的Stack上,则直接返回当前FocusedStack。
  4. 当前focus从初始化以来未调整过,但主屏已有多个ActivityStack。此情形则直接找到此Display中栈顶非Home类型的Stack并作为focus返回。
  5. 当前主屏只有HomeStack存在。此情形则需要创建一个新的ActivityStack并指定为FocusedStack以存放ActivityRecord。

  在调整完focus之后一般情况下还需要通过ActivityStack的moveToFront()方法把调整后的FocusedStack置为所属Display的栈顶元素。

// frameworks/base/services/core/java/com/android/server/am/ActivityStack.javafinal void moveToFront() {if (isAttached()) {if (isOnHomeDisplay()) {mStackSupervisor.moveHomeStack(isHomeStack());}mStacks.remove(this);mStacks.add(this);}}

深入理解AMS之Activity管理相关推荐

  1. Android ActivityManagerService(AMS)的Activity管理

    对于AMS来讲,Activity管理是它的核心工作,前面两篇文章都是讲AMS的启动流程和进程的管理,这两篇文章其实是为本文做铺垫的,只有理解了前面两篇文章才能更好地理解AMS的activity管理.在 ...

  2. Android Ams对于Activity生命周期的管理

    分析Activity的生命周期管理,我觉得应该先看下面两篇关于Activity的官方文档: 了解 Activity 生命周期 处理 Activity 状态更改 里面有下面一段话,比较简洁的说出了Act ...

  3. Activity管理(三):activity内核管理方案详细讲解

    一.Activity的生命周期 Activity的管理同样是基于C/S架构的,所有的activity管理都在server端进行.在Server端对每个activity进行调度的同时,Client端负责 ...

  4. 深入理解AMS --- 一 AMS 的启动

    深入理解AMS --- 一 AMS 的启动 深入理解AMS --- 一 AMS 的启动 一 Zygote fork 1.1 Zygote fork SystemServer 进程 1.2 System ...

  5. Activity管理(三)

    onRestart()->onStart()->onResume() b) 完成了第一步对activity生命周期的响应之后,在第二步这里主要是处理窗口的添加动作:把DecorView添加 ...

  6. 【Android工具类】Activity管理工具类AppManager

    转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 import java.util.Stack;import android.app.Activity; im ...

  7. Linux内核深入理解定时器和时间管理(7):相关的系统调用

    Linux内核深入理解定时器和时间管理 相关的系统调用 rtoax 2021年3月 在原文基础上,增加5.10.13内核源码相关内容. 结构体 ---------------------------- ...

  8. Linux内核深入理解定时器和时间管理(5):clockevents 框架

    Linux内核深入理解定时器和时间管理 clockevents 框架 rtoax 2021年3月 在原文基础上,增加5.10.13内核源码相关内容. 1. Introduction to the cl ...

  9. Linux内核深入理解定时器和时间管理(4):定时器 timer

    Linux内核深入理解定时器和时间管理 定时器 timer rtoax 2021年3月 在原文基础上,增加5.10.13内核源码相关内容. 1. Timers This is fourth part ...

最新文章

  1. XtraBackup
  2. 白岩松西湖大学演讲:科研人要学会讲故事,可以从发朋友圈开始练
  3. 【LeetCode从零单排】No118 Pascal's Triangle
  4. FFmpeg 源代码:avcodec_find_decoder()和avcodec_find_decoder_by_name()
  5. SQL Server安全(6/11):执行上下文与代码签名(Execution Context and Code Signing)
  6. 日志框架实现数据采集分析和报警
  7. mysql数据的表分区二
  8. 在 Mac 上的 Keynote 讲演中如何更改共享演示文稿的设置?
  9. QImage互转cv::Mat
  10. pdfminer识别pdf无法识别问题
  11. 苹果电脑怎么断网?你会断网吗? Mac电脑断网方法
  12. kali安装中文拼音输入法2
  13. python爬取去哪网数据_用户观点:企查查数据爬取技术与Python 爬取企查查数据...
  14. 12306之梆梆加固libsecexe.so的脱壳及修复
  15. [leetcode/lintcode 题解] 谷歌面试题:基因相似度
  16. 19款国产手机无一幸免:15分钟破解人脸识别,打印眼镜让刷脸形同虚设 ?
  17. 车间生产管理(一)· 产线流程控制及产品质量追溯解决方案
  18. MIT麻省理工最新研究揭示GAN生成数据可视化分析
  19. 菜谱点菜c语言编程,菜单点菜并计算价格 C++改成C 运行成功100分
  20. HDU 1717 数学

热门文章

  1. 【QT上位机设计——串口收发和波形显示】
  2. DWG文件转换高清JPG文件
  3. 春运期间乘火车须知(搞笑版)
  4. 永嘉原*厂-VK1Q68D 是低功耗LED显示/数码管显示驱动IC,带键盘扫描电路,4~7 位,10~13 段 显示,QFN24 4*4MM超小体积封装
  5. 转载:Java3D实现三维显示
  6. 百度前端实习生面试(连跪之旅)
  7. 【数据库原理与应用】为什么要学习数据库?数据库的由来和发展
  8. python opencv打开图片 关闭_自学python-opencv(9)图像开闭操作
  9. 股票量化分析工具QTYX使用攻略——均线系统多头排列选股(更新2.5.7)
  10. 基于ssm游戏论坛平台源码