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$ActivityState
enum ActivityState {
INITIALIZING,//正在初始化
RESUMED,//恢复前台状态
PAUSING,//正在暂停
PAUSED,//暂停状态
STOPPING,//正在停止
STOPPED,//停止状态
FINISHING,//正在移除
DESTROYING,//正在销毁
DESTROYED//销毁状态
}
上述这些状态并不难理解,其中某些状态的定义甚至与Activity生命周期方法暗暗相合。ActivityRecord中的state成员正是为了描述其对应的Activity所处的状态。
// frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java
ActivityState 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.java
public 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#setWindowManager
void 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$ActivityDisplay
class 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$VirtualActivityDisplay
class 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$ActivityContainer
class 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.java
private 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#setWindowManager
mHomeStack = 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.java
static 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.java
final 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.java
boolean 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.java
ActivityStack 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
//part1
if (task != null) {//如果启动r是需要新建Task的,则此处task为空,否则则进入此循环。
final ActivityStack taskStack = task.stack;
if (taskStack.isOnHomeDisplay()) {//主屏上的stack
if (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
}
//part2
final 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;
}
//part3
if (mFocusedStack != mHomeStack && (!newTask ||
mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {//主要不是Virtual的,isEligible都返回true
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
"adjustStackFocus: Have a focused stack=" + mFocusedStack);
return mFocusedStack;
}
//part4
final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;//取到主屏上所有stack
for (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种情形。
- 当前启动的Activity已找到Task容纳,属于非newTask的情形。如果已有task存放,则可据此找到Task所属ActivityStack,并且如果被启动的Activity是主屏Activity,则可调整focus(说明focus这个概念只有主屏有)。
- 当前启动的Activity指定了想要存放的ActivityContainer(即ActivityStack)。ActivityContainer是ActivityStack的容器类,它们是一对一的关系。此处若果指明了启动Activity的存放容器mInitialActivityContainer,就意味着Activity找到了ActivityStack来存放。
- 当前处于focus态的ActivityStack并非HomeStack(说明focus至少已调整过一次)。走到此处的Activity显然没有指定其所处的Task,只要当前的focus不是在HomeStack或虚拟出来的Stack上,则直接返回当前FocusedStack。
- 当前focus从初始化以来未调整过,但主屏已有多个ActivityStack。此情形则直接找到此Display中栈顶非Home类型的Stack并作为focus返回。
- 当前主屏只有HomeStack存在。此情形则需要创建一个新的ActivityStack并指定为FocusedStack以存放ActivityRecord。
在调整完focus之后一般情况下还需要通过ActivityStack的moveToFront()方法把调整后的FocusedStack置为所属Display的栈顶元素。
// frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
final void moveToFront() {
if (isAttached()) {
if (isOnHomeDisplay()) {
mStackSupervisor.moveHomeStack(isHomeStack());
}
mStacks.remove(this);
mStacks.add(this);
}
}