Activity任务栈
eaaomk 2021-12-27 23:00:00 JavaAndroid
# Activity任务栈
- 相信读者看到这里也比较困惑,AMS不是管理所有Activity的调度吗?那为什么看不见它在哪里?大家在网上搜索关键词 <adb 命令查看Activity栈>有如下结果:
adb shell dumpsys activity activities
- 我们连接上手机,输入这个命令,随后会打印出如下类似信息:
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
Stack #30: type=standard mode=fullscreen
isSleeping=true
mLastPausedActivity: ActivityRecord{3fc7301 u0 com.android.settings/.Settings$SprdUsbSettingsActivity t30}
* Task{4733394 #30 visible=true type=standard mode=fullscreen translucent=true A=1000:com.android.settings U=0 StackId=30 sz=1}
* Hist #0: ActivityRecord{3fc7301 u0 com.android.settings/.Settings$SprdUsbSettingsActivity t30}
Stack #1: type=home mode=fullscreen
isSleeping=true
mLastPausedActivity: ActivityRecord{c2abe2d u0 com.***.***.launcher/com.android.***.recents_ui_overrides.src.com.android.launcher3.uioverrides.*** t21}
* Task{e6d9bdb #21 visible=true type=home mode=fullscreen translucent=false A=10207:com.***.***.launcher.task.Launcher U=0 StackId=1 sz=1}
* Hist #0: ActivityRecord{c2abe2d u0 com.***.***.launcher/com.android.***.recents_ui_overrides.src.com.android.launcher3.uioverrides.*** t21}
Stack #28: type=standard mode=fullscreen
isSleeping=true
mLastPausedActivity: ActivityRecord{3b2528 u0 com.***20/.activities.***Activity t28}
* Task{f6b1ebe #28 visible=false type=standard mode=fullscreen translucent=true A=10212:com.***20 U=0 StackId=28 sz=2}
* Hist #1: ActivityRecord{3b2528 u0 com.***20/.activities.***Activity t28}
* Hist #0: ActivityRecord{f07160e u0 com.***20/.activities.***Activity t28}
- 如此可见,Activity在ATMS中如何保存的就可以清晰的观察出来了。
- 在Display中,存在多个Stack,一个Stack中存在多个Task,一个Task中存在多个ActivityRecord。
- 我们的一个应用对应了一个Stack,系统中存在多个应用在运行,Display就对应着多个Stack,这个Stack在Android 源码中对应的就是ActivityStack类,这时候就应该注意到了,我们的Activity有不同的启动模式,各个启动模式说法中所说的任务栈就是这个ActivityStack,举个栗子:SingleInstance模式中提到的开启一个新的栈就是ActivityStack。 分析到这里应该都明白了,ActivityRecord对应的就是一个Activity。
- 我们回过头来看看,既然命令能够查看到Android系统的任务栈,那么它一定是有数据的,那么它是从哪里获得的这些数据呢?上源码:
//frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
// 此方法就是在获取我们所有的Activity的信息。
boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient,String dumpPackage) {
boolean printed = false;
boolean needSep = false;
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
DisplayContent displayContent = getChildAt(displayNdx);
if (printed) {
pw.println();
}
/// 开始打印了
pw.print("Display #"); pw.print(displayContent.mDisplayId);
pw.println(" (activities from top to bottom):");
for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
// 获取一个taskDisplayArea,一般情况下是默认的
final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx);
for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
/// 遍历taskDisplayArea中的所有ActivityStack
final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
if (stack == null) {
continue;
}
if (needSep) {
pw.println();
}
// 开始调用ActivityStack的dump 继续打印
needSep = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, false);
printed |= needSep;
}
}
...
}
...
return printed;
}
//frameworks/base/services/core/java/com/android/server/wm/ActivityStack.java
boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient,String dumpPackage, final boolean needSep) {
Runnable headerPrinter = () -> {
if (needSep) {
pw.println();
}
/// 我们的Stack 就是ActivityStack
pw.println(" Stack #" + getRootTaskId()
+ ": type=" + activityTypeToString(getActivityType())
+ " mode=" + windowingModeToString(getWindowingMode()));
pw.println(" isSleeping=" + shouldSleepActivities());
pw.println(" mBounds=" + getRequestedOverrideBounds());
};
...
printed |= dumpActivities(fd, pw, dumpAll, dumpClient, dumpPackage, false, headerPrinter);
return printed;
}
//frameworks/base/services/core/java/com/android/server/wm/ActivityStack.java
private boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
boolean dumpClient, String dumpPackage, boolean needSep, Runnable header) {
if (!hasChild()) {
return false;
}
...
forAllLeafTasks((task) -> {
final String prefix = " ";
...
final ArrayList<ActivityRecord> activities = new ArrayList<>();
// Add activities by traversing the hierarchy from bottom to top, since activities
// are dumped in reverse order in {@link ActivityStackSupervisor#dumpHistoryList()}.
task.forAllActivities((Consumer<ActivityRecord>) activities::add,
false /* traverseTopToBottom */);
//打印ActivityRecord
dumpHistoryList(fd, pw, activities, prefix, "Hist", true, !dumpAll, dumpClient,
dumpPackage, false, headerPrinter, task);
}, true /* traverseTopToBottom */);
return printed.get();
}
# 任务栈数据结构剖析
- 数据结构相对来讲稍微复杂一点点,接下来用一个简化版的类图作为说明,注意,这里也涉及到的是WMS。
- 上图中十分关键的类是WindowContainer类,在这个类中,拥有一个属性mChildren,它其实就是一个ArrayList,WindowList只不过是继承它,多写了几个方法罢了,下面的类再去继承这个WindowContainer,也就都拥有了mChildren属性。
- 按照上图的顺序,Android系统中的任务栈数据结构就是《无限套娃》
- 在系统服务启动的过程中,WMS与AMS的第一次套娃在这里:
//frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t){
...
t.traceBegin("StartWindowManagerService");
// WMS needs sensor service ready
ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
mSensorServiceStart = null;
// 初始化WMS,将ATMS放进去
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
t.traceEnd();
t.traceBegin("SetWindowManagerService");
// WMS 创建完成,将其放入到AMS中
mActivityManagerService.setWindowManager(wm);
t.traceEnd();
t.traceBegin("WindowManagerServiceOnInitReady");
// 准备工作结束,调用WMS的一些初始化后续的操作
wm.onInitReady();
t.traceEnd();
...
}
- 看看setWindowManager方法在做什么:
//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void setWindowManager(WindowManagerService wm) {
synchronized (this) {
// 引用WMS
mWindowManager = wm;
mWmInternal = LocalServices.getService(WindowManagerInternal.class);
// 再设置到ATMS
mActivityTaskManager.setWindowManager(wm);
}
}
- 这里也是将WMS存入了一个引用,方便后续操作直接调用WMS
- 重点在这里,套娃开始,ATMS中的mRootWindowContainer其实是WMS中的一个属性,它在WMS诞生的的时候进行了初始化,后续会在WMS系列中讲到.
//frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
public void setWindowManager(WindowManagerService wm) {
synchronized (mGlobalLock) {
// 引用WMS
mWindowManager = wm;
// 设置mRootWindowContainer
mRootWindowContainer = wm.mRoot;
...
// 继续向下设置WMS
mLockTaskController.setWindowManager(wm);
mStackSupervisor.setWindowManager(wm);
mRootWindowContainer.setWindowManager(wm);
}
}
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
// 定义的WMS静态变量sInstance
private static WindowManagerService sInstance;
static WindowManagerService getInstance() {
return sInstance;
}
//初始化方法
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm) {
return main(context, im, showBootMsgs, onlyCore, policy, atm,
SurfaceControl.Transaction::new, Surface::new, SurfaceControl.Builder::new);
}
@VisibleForTesting
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, Supplier<SurfaceControl.Transaction> transactionFactory,
Supplier<Surface> surfaceFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
DisplayThread.getHandler().runWithScissors(() ->
//真正的初始化在这里
sInstance = new SprdWindowManagerService(context, im, showBootMsgs, onlyCore, policy,
atm, transactionFactory, surfaceFactory, surfaceControlFactory), 0);
return sInstance;
}
# 总结
- mRootWindowContainer 是在WMS中进行初始化的,初始化完成后,又将其注入到了AMS、ATMS中,在WMS的初始化的过程中,又将其注入到了ATMS下的mStackSupervisor中。它就是一块砖,哪里需要哪里搬。WMS与AMS还有很多交互的地方需要调用对方的方法,所以会看见一个参数四处都在传递与引用。但总的包含关系已经在上面的类图中体现了:
- RootWindowContainer 包含 DisplayContent
- DisplayContent 包含 DisplayAreaPolicy,
- DisplayAreaPolicy 包含 TaskDisplayArea
- TaskDisplayArea 包含 ActivityStack
- ActivityStack 包含 ActivityRecord
- 其实这里有一个疑问,我们的堆栈信息看见的是一个Stack内部拥有的是一个对象是Task,那么Stack里面会有多个Task吗?还是说这个Task并不存在,Stack直接包含了ActivityRecord?笔者已经尝试了下面几种方式,供读者尝试:
- 以SingleInstance模式启动,开启了新的ActivityStack,堆栈信息显示的是多了一个Stack
- 在应用程序A中拉起应用程序B的一个Activity,开启了新的ActivityStack,堆栈信息显示的是多了一个Stack
- 普通模式下,同应用程序内部启动一个新的Activity,会与启动它的Activity在同一个Stack下
- 启动应用程序的第一个Activity,会打开一个新的ActivityStack
- 这里我们暂时只需要关注这个ActivityStack即可。一般情况下,在Android任务栈中,一个ActivityStack记录了一个应用的所有启动的Activity信息,我们的应用程序默认都是运行在同一个进程中的,它们可能会存在不同的ActivityStack里面(以SingleInstance这种模式启动的将会打开一个新的ActivityStack),但是它们的进程一定是相同的,当然也可以实现一个应用程序多个进程(AIDL 跨进程通信),那么进程就不相同了。这里我们重点关注一般情况,ActivityStack里面包含了这个应用程序所有启动的 任务(ActivityRecord),堆栈信息中的Stack也就是大家平时都了解到的Activity的四大启动模式中提及到的任务栈(ActivityStack),不同的启动方式决定了我们启动的Activity存在于哪个任务栈,在这个任务栈中存储的有我们启动的Activity记录,它并不是以一个Activity的形式存在,而是以ActivityRecord的形式存在。