这类问题一般比较难分析,符合以下情况的才有可能分析出来:
There is a recursion among check for sleep and complete pause during sleeping
01-08 08:45:42.946 1941 5167 I wm_finish_activity: [0,240239432,5187,com.ss.android.auto/com.ss.android.account.v2.view.AccountLoginActivity,app-request]
01-08 08:45:42.949 1941 5167 I wm_pause_activity: [0,240239432,com.ss.android.auto/com.ss.android.account.v2.view.AccountLoginActivity,userLeaving=false,finish]
01-08 08:45:42.977 30679 30679 I wm_on_top_resumed_lost_called: [240239432,com.ss.android.account.v2.view.AccountLoginActivity,topStateChangedWhenResumed]
01-08 08:45:42.980 1941 2054 I WindowManager: Display0 turned off...
// 问题发生在息屏场景
01-08 08:45:43.001 1941 2054 I wm_sleep_token: [0,1,ScreenOff]
// 问题AccountLoginActivity已经完成onPaused回调
01-08 08:45:43.007 30679 30679 I wm_on_paused_called: [0,240239432,com.ss.android.account.v2.view.AccountLoginActivity,performPause,1]
01-08 08:45:43.011 1941 22598 I wm_set_resumed_activity: [0,com.ss.android.auto/.ugc.video.activity.UgcNewDetailActivity,resumeTopActivity - onActivityStateChanged]
01-08 08:45:43.016 1941 22598 I wm_resume_activity: [0,212386622,5187,com.ss.android.auto/.ugc.video.activity.UgcNewDetailActivity]
01-08 08:45:43.021 1941 22598 I wm_add_to_stopping: [0,240239432,com.ss.android.auto/com.ss.android.account.v2.view.AccountLoginActivity,completeFinishing]
// 重复打印很多次,表明递归
01-08 08:45:43.022 1941 2009 I am_wtf : [0,1941,system_server,-1,ActivityTaskManager,Going to pause when pause is already pending for ActivityRecord
{e51c348 u0 com.ss.android.auto/com.ss.android.account.v2.view.AccountLoginActivity} t5187 f}} state=FINISHING]
01-08 08:45:43.045 1941 2009 I am_wtf : [0,1941,system_server,-1,ActivityTaskManager,Going to pause when pause is already pending for ActivityRecord
{e51c348 u0 com.ss.android.auto/com.ss.android.account.v2.view.AccountLoginActivity}
t5187 f}} state=PAUSED]
......
一直在重复TaskFragment.startPausing -> TaskFragment.sleepIfPossible 的堆栈
at com.android.server.wm.TaskFragment.startPausing(TaskFragment.java:1690)
at com.android.server.wm.TaskFragment.sleepIfPossible(TaskFragment.java:856)
at com.android.server.wm.Task.lambda$goToSleepIfPossible$20(Task.java:5425)
at com.android.server.wm.Task$$ExternalSyntheticLambda9.accept(unavailable:6)
at com.android.server.wm.TaskFragment.forAllLeafTaskFragments(TaskFragment.java:1952)
at com.android.server.wm.Task.lambda$forAllLeafTasksAndLeafTaskFragments$14(Task.java:3699)
at com.android.server.wm.Task$$ExternalSyntheticLambda31.accept(unavailable:6)
at com.android.server.wm.Task.forAllLeafTasks(Task.java:3644)
at com.android.server.wm.Task.forAllLeafTasksAndLeafTaskFragments(Task.java:3687)
at com.android.server.wm.Task.goToSleepIfPossible(Task.java:5424)
at com.android.server.wm.Task.checkReadyForSleep(Task.java:5406)
at com.android.server.wm.ActivityRecord.addToStopping(ActivityRecord.java:6974)
at com.android.server.wm.ActivityRecord.completeFinishing(ActivityRecord.java:4091)
at com.android.server.wm.TaskFragment.completePause(TaskFragment.java:1854)
at com.android.server.wm.TaskFragment.startPausing(TaskFragment.java:1696)
...
...
at com.android.server.wm.TaskFragment.startPausing(TaskFragment.java:1696)
at com.android.server.wm.TaskFragment.sleepIfPossible(TaskFragment.java:856)
at com.android.server.wm.Task.lambda$goToSleepIfPossible$20(Task.java:5425)
at com.android.server.wm.Task$$ExternalSyntheticLambda9.accept(unavailable:6)
at com.android.server.wm.TaskFragment.forAllLeafTaskFragments(TaskFragment.java:1952)
at com.android.server.wm.Task.lambda$forAllLeafTasksAndLeafTaskFragments$14(Task.java:3699)
at com.android.server.wm.Task$$ExternalSyntheticLambda31.accept(unavailable:6)
at com.android.server.wm.Task.forAllLeafTasks(Task.java:3644)
at com.android.server.wm.Task.forAllLeafTasksAndLeafTaskFragments(Task.java:3687)
at com.android.server.wm.Task.goToSleepIfPossible(Task.java:5424)
at com.android.server.wm.Task.checkReadyForSleep(Task.java:5406)
at com.android.server.wm.ActivityRecord.addToStopping(ActivityRecord.java:6974)
at com.android.server.wm.ActivityRecord.completeFinishing(ActivityRecord.java:4091)
at com.android.server.wm.TaskFragment.completePause(TaskFragment.java:1854)
at com.android.server.wm.TaskFragment.startPausing(TaskFragment.java:1696)
at com.android.server.wm.TaskFragment.sleepIfPossible(TaskFragment.java:856)
at com.android.server.wm.Task.lambda$goToSleepIfPossible$20(Task.java:5425)
at com.android.server.wm.Task$$ExternalSyntheticLambda9.accept(unavailable:6)
at com.android.server.wm.TaskFragment.forAllLeafTaskFragments(TaskFragment.java:1952)
at com.android.server.wm.Task.lambda$forAllLeafTasksAndLeafTaskFragments$14(Task.java:3699)
at com.android.server.wm.Task$$ExternalSyntheticLambda31.accept(unavailable:6)
at com.android.server.wm.Task.forAllLeafTasks(Task.java:3644)
at com.android.server.wm.Task.forAllLeafTasksAndLeafTaskFragments(Task.java:3687)
at com.android.server.wm.Task.goToSleepIfPossible(Task.java:5424)
at com.android.server.wm.Task.checkReadyForSleep(Task.java:5406)
at com.android.server.wm.ActivityRecord.completeResumeLocked(ActivityRecord.java:6766)
at com.android.server.wm.TaskFragment.resumeTopActivity(TaskFragment.java:1609)
at com.android.server.wm.Task.resumeTopActivityInnerLocked(Task.java:5665)
at com.android.server.wm.Task.resumeTopActivityUncheckedLocked(Task.java:5593)
at com.android.server.wm.Task.resumeTopActivityUncheckedLocked(Task.java:5648)
at com.android.server.wm.ActivityRecord.makeActiveIfNeeded(ActivityRecord.java:6551)
at com.android.server.wm.RootWindowContainer.lambda$resumeFocusedTasksTopActivities$18(RootWindowContainer.java:2468)
at com.android.server.wm.RootWindowContainer$$ExternalSyntheticLambda17.accept(unavailable:15)
at com.android.server.wm.Task.forAllRootTasks(Task.java:3656)
at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2127)
at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2127)
at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2127)
... repeated 2 times
at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2120)
at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2446)
at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2424)
at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2419)
at com.android.server.wm.ActivityRecord.addToFinishingAndWaitForIdle(ActivityRecord.java:4178)
at com.android.server.wm.ActivityRecord.completeFinishing(ActivityRecord.java:4095)
at com.android.server.wm.TaskFragment.completePause(TaskFragment.java:1854)
at com.android.server.wm.ActivityRecord.activityPaused(ActivityRecord.java:6784)
at com.android.server.wm.ActivityClientController.activityPaused(ActivityClientController.java:191)
- locked <0x093a97ff> (a com.android.server.wm.WindowManagerGlobalLock)
at android.app.IActivityClientController$Stub.onTransact(IActivityClientController.java:582)
at com.android.server.wm.ActivityClientController.onTransact(ActivityClientController.java:131)
at android.os.Binder.execTransactInternal(Binder.java:1285)
at android.os.Binder.execTransact(Binder.java:1249)
首先查看关键log中重复log打印的地方在TaskFragment#startPausing()
at com.android.server.wm.Task.goToSleepIfPossible(Task.java:5424)
// 这里的shouldSleepActivities返回true,才会走到上面的goToSleepIfPossible
at com.android.server.wm.Task.checkReadyForSleep(Task.java:5406)
at com.android.server.wm.ActivityRecord.addToStopping(ActivityRecord.java:6974)
at com.android.server.wm.ActivityRecord.completeFinishing(ActivityRecord.java:4091)
at com.android.server.wm.TaskFragment.completePause(TaskFragment.java:1854)
// shouldSleepActivities 返回false,才会走到上面的completePause
at com.android.server.wm.TaskFragment.startPausing(TaskFragment.java:1696)
// TaskFragment.java
boolean startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming,
String reason) {
......
if (mPausingActivity != null) {
Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
+ " state=" + mPausingActivity.getState());
// 按理谷歌这里已经做了规避递归,此处看log应该还没亮屏,不会走到completePause陷入递归
if (!shouldSleepActivities()) {
// Avoid recursion among check for sleep and complete pause during sleeping.
// Because activity will be paused immediately after resume, just let pause
// be completed by the order of activity paused from clients.
completePause(false, resuming);
}
}
// Task.java
void checkReadyForSleep() {
if (shouldSleepActivities() && goToSleepIfPossible(false /* shuttingDown */)) {
mTaskSupervisor.checkReadyForSleepLocked(true /* allowDelay */);
}
}
//Task.java
boolean shouldSleepActivities() {
final DisplayContent display = mDisplayContent;
final boolean isKeyguardGoingAway = (mDisplayContent != null)
? mDisplayContent.isKeyguardGoingAway()
: mRootWindowContainer.getDefaultDisplay().isKeyguardGoingAway();
// Do not sleep activities in this root task if we're marked as focused and the keyguard
// is in the process of going away.
if (isKeyguardGoingAway && isFocusedRootTaskOnDisplay()
// Avoid resuming activities on secondary displays since we don't want bubble
// activities to be resumed while bubble is still collapsed.
// TODO(b/113840485): Having keyguard going away state for secondary displays.
&& display.isDefaultDisplay) {
return false;
}
return display != null ? display.isSleeping() : mAtmService.isSleepingLocked();
}
// TaskFragment.java
boolean shouldSleepActivities() {
return false;
}
合理推测:
默认情况下Task是TaskFragment子类,Task重写了shouldSleepActivities方法的话就应该执行Task中的方法。但是在平行窗口模式下,Task中包含TaskFragment对象,且jira中也可看到只在pad/Fold等有平行窗口的机型上上报。
本地验证 :
本地测试发现,平行窗口右侧页面最上方是诸如登录页面的半透明theme样式的页面finish且屏幕此时息屏(本地android studio 赋值DisplayContent的mSleeping为true)可复现该问题。
给谷歌提patch:
https://android-review.googlesource.com/c/platform/frameworks/base/+/2383980
其次按照上面复现步骤确定ConfirmAccessControl本来的状态应该为resume
.....
// ConfirmAccessControl 一直重复打印resume、pause相关生命周期
// 注意这里每次的线程id不同,说明不是同一个线程堆栈出现递归
07-14 17:40:50.029 1000 2339 2381 I wm_resume_activity: [0,201462615,23,com.miui.securitycenter/com.miui.applicationlock.ConfirmAccessControl]
07-14 17:40:50.032 1000 2339 2381 I wm_pause_activity: [0,201462615,com.miui.securitycenter/com.miui.applicationlock.ConfirmAccessControl,userLeaving=false,pauseBackTasks]
07-14 17:40:50.182 1000 9884 9884 I wm_on_resume_called: [0,201462615,com.miui.applicationlock.ConfirmAccessControl,RESUME_ACTIVITY,62]
07-14 17:40:50.188 1000 9884 9884 I wm_on_paused_called: [0,201462615,com.miui.applicationlock.ConfirmAccessControl,performPause,2]
07-14 17:40:50.195 1000 2339 5156 I wm_resume_activity: [0,201462615,23,com.miui.securitycenter/com.miui.applicationlock.ConfirmAccessControl]
07-14 17:40:50.197 1000 2339 5156 I wm_pause_activity: [0,201462615,com.miui.securitycenter/com.miui.applicationlock.ConfirmAccessControl,userLeaving=false,pauseBackTasks]
07-14 17:40:50.312 1000 9884 9884 I wm_on_resume_called: [0,201462615,com.miui.applicationlock.ConfirmAccessControl,RESUME_ACTIVITY,50]
07-14 17:40:50.317 1000 9884 9884 I wm_on_paused_called: [0,201462615,com.miui.applicationlock.ConfirmAccessControl,performPause,4]
.......
从关键log可以看出一直在重复执行pause流程,所以在PauseActivityItem 打断点,发现system server的binder线程一直重复执行如下堆栈,且针对的也确实都是ConfirmAccessControl页面。
形成了ActivityClientController.activityPaused -> ClientLifecycleManager.scheduleTransaction,system server <-> app之间的递归。
Breakpoint reached
// system server binder app去执行pause流程
at com.android.server.wm.ClientLifecycleManager.scheduleTransaction(ClientLifecycleManager.java:69)
at com.android.server.wm.TaskFragment.schedulePauseActivity(TaskFragment.java:1847)
at com.android.server.wm.TaskFragment.startPausing(TaskFragment.java:1789)
at com.android.server.wm.TaskFragment.startPausing(TaskFragment.java:1686)
at com.android.server.wm.TaskDisplayArea.lambda$pauseBackTasks$8$com-android-server-wm-TaskDisplayArea(TaskDisplayArea.java:1400)
at com.android.server.wm.TaskDisplayArea$$ExternalSyntheticLambda5.accept(D8$$SyntheticClass:-1)
at com.android.server.wm.Task.forAllLeafTasks(Task.java:3673)
at com.android.server.wm.WindowContainer.forAllLeafTasks(WindowContainer.java:2116)
at com.android.server.wm.TaskDisplayArea.pauseBackTasks(TaskDisplayArea.java:1392)
// 第二次出现resume逻辑,且此次resume的是应用锁下面LauncherUI页面,不合理
at com.android.server.wm.TaskFragment.resumeTopActivity(TaskFragment.java:1325)
at com.android.server.wm.Task.lambda$resumeTopActivityInnerLocked$24(Task.java:5787)
at com.android.server.wm.Task$$ExternalSyntheticLambda33.accept(D8$$SyntheticClass:-1)
at com.android.server.wm.TaskFragment.forAllLeafTaskFragments(TaskFragment.java:1976)
at com.android.server.wm.TaskFragment.forAllLeafTaskFragments(TaskFragment.java:1964)
at com.android.server.wm.Task.resumeTopActivityInnerLocked(Task.java:5780)
at com.android.server.wm.Task.resumeTopActivityUncheckedLocked(Task.java:5702)
at com.android.server.wm.Task.resumeTopActivityUncheckedLocked(Task.java:5762)
at com.android.server.wm.ActivityRecord.makeActiveIfNeeded(ActivityRecord.java:6801)
at com.android.server.wm.EnsureActivitiesVisibleHelper.setActivityVisibilityState(EnsureActivitiesVisibleHelper.java:226)
at com.android.server.wm.EnsureActivitiesVisibleHelper.process(EnsureActivitiesVisibleHelper.java:144)
at com.android.server.wm.TaskFragment.updateActivityVisibilities(TaskFragment.java:1181)
at com.android.server.wm.Task.lambda$ensureActivitiesVisible$23(Task.java:5598)
at com.android.server.wm.Task$$ExternalSyntheticLambda23.accept(D8$$SyntheticClass:-1)
at com.android.server.wm.Task.forAllLeafTasks(Task.java:3673)
at com.android.server.wm.Task.ensureActivitiesVisible(Task.java:5597)
at com.android.server.wm.TaskDisplayArea.lambda$ensureActivitiesVisible$11(TaskDisplayArea.java:1997)
at com.android.server.wm.TaskDisplayArea$$ExternalSyntheticLambda2.accept(D8$$SyntheticClass:-1)
at com.android.server.wm.Task.forAllRootTasks(Task.java:3685)
at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2151)
at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2144)
at com.android.server.wm.TaskDisplayArea.ensureActivitiesVisible(TaskDisplayArea.java:1996)
// 第一次准备resume ConfirmAccessControl页面,正确流程
at com.android.server.wm.TaskFragment.resumeTopActivity(TaskFragment.java:1221)
at com.android.server.wm.Task.resumeTopActivityInnerLocked(Task.java:5779)
at com.android.server.wm.Task.resumeTopActivityUncheckedLocked(Task.java:5702)
at com.android.server.wm.Task.resumeTopActivityUncheckedLocked(Task.java:5727)
at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2531)
at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2517)
at com.android.server.wm.TaskFragment.completePause(TaskFragment.java:1917)
at com.android.server.wm.ActivityRecord.activityPaused(ActivityRecord.java:7035)
// app进程binder 系统pause已完成
at com.android.server.wm.ActivityClientController.activityPaused(ActivityClientController.java:195)
at android.app.IActivityClientController$Stub.onTransact(IActivityClientController.java:592)
at com.android.server.wm.ActivityClientController.onTransact(ActivityClientController.java:133)
at android.os.Binder.execTransactInternal(Binder.java:1285)
at android.os.Binder.execTransact(Binder.java:1249)
PauseActivityItem{finished=false,userLeaving=false,configChanges=0,dontReport=false,autoEnteringPip=false}
从上面堆栈可以看出第二次resume 应用锁下面的LauncherUI页面不太合理,查看微信Task发现如下不合理的结构:
所以推测上面的第一次resume是正常resume RootTask的直接child ConfirmAccessControl页面,第二次resume 异常resume了Task的child的TaskFragment中的LauncherUI页面。
从上面堆栈可以看出第二次resume的触发点是下面resumeTopActivityInnerLocked方法的forAllLeafTaskFragments的callback中。
而forAllLeafTaskFragments 主要是遍历Task下面的TaskFragment的并执行resumeTopActivity操作,一般callback执行场景应该是在平行窗口的场景中,确保左右两个TaskFragment中的top页面能正常resume。
@GuardedBy("mService")
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,
boolean deferPause) {
if (!mAtmService.isBooting() && !mAtmService.isBooted()) {
// Not ready yet!
return false;
}
final ActivityRecord topActivity = topRunningActivity(true /* focusableOnly */);
if (topActivity == null) {
// There are no activities left in this task, let's look somewhere else.
return resumeNextFocusableActivityWhenRootTaskIsEmpty(prev, options);
}
final boolean[] resumed = new boolean[1];
// 第一次resume,正常页面
final TaskFragment topFragment = topActivity.getTaskFragment();
resumed[0] = topFragment.resumeTopActivity(prev, options, deferPause);
forAllLeafTaskFragments(f -> {
if (topFragment == f) {
return;
}
if (!f.canBeResumed(null /* starting */)) {
return;
}
// 第二次resume到TaskFragment中的页面
resumed[0] |= f.resumeTopActivity(prev, options, deferPause);
}, true);
return resumed[0];
}
查看该Task中的TaskFragment创建是否合理:
// 微信进程创建TaskFragment堆栈如下
createTaskFragment:482, WindowContainerTransaction (android.window)
createTaskFragment:251, JetpackTaskFragmentOrganizer (androidx.window.extensions.embedding)
createTaskFragment:434, SplitPresenter (androidx.window.extensions.embedding)
createTaskFragment:241, JetpackTaskFragmentOrganizer (androidx.window.extensions.embedding)
createTaskFragmentAndReparentActivity:262, JetpackTaskFragmentOrganizer (androidx.window.extensions.embedding)
expandActivity:199, JetpackTaskFragmentOrganizer (androidx.window.extensions.embedding)
expandActivity:682, SplitController (androidx.window.extensions.embedding)
resolveActivityToContainer:560, SplitController (androidx.window.extensions.embedding)
onActivityCreated:494, SplitController (androidx.window.extensions.embedding)
onActivityPostCreated:1796, SplitController$LifecycleCallbacks (androidx.window.extensions.embedding)
dispatchActivityPostCreated:395, Application (android.app)
dispatchActivityPostCreated:1486, Activity (android.app)
performCreate:8590, Activity (android.app)
本地调试微信的WelcomeActivity满足了mSplitRules规则,走了expandActivity的逻辑,导致创建了TaskFragment,但这些规则是微信自己适配谷歌平行窗口的,所以不能从创建TaskFragment来规避该问题。
// SplitController.java
@VisibleForTesting
boolean resolveActivityToContainer(@NonNull Activity activity, boolean isOnReparent) {
// 1. Whether the new launched activity should always expand.
if (shouldExpand(activity, null /* intent */)) {
expandActivity(activity);
return true;
}
本地测试全屏场景下按以上步骤不能复现问题,经调试发现不满足canBeResumed,直接return,走不到下面的resumeTopActivity流程,形成不了递归。
// Task.java
@GuardedBy("mService")
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,
boolean deferPause) {
.......
final boolean[] resumed = new boolean[1];
final TaskFragment topFragment = topActivity.getTaskFragment();
resumed[0] = topFragment.resumeTopActivity(prev, options, deferPause);
forAllLeafTaskFragments(f -> {
if (topFragment == f) {
return;
}
// 全屏情况下,不满足canBeResumed,直接return,走不到下面的resumeTopActivity流程,形成不了递归
if (!f.canBeResumed(null /* starting */)) {
return;
}
resumed[0] |= f.resumeTopActivity(prev, options, deferPause);
}, true);
return resumed[0];
}
所以来看看canBeResumed方法
// TaskFragment.java
boolean canBeResumed(@Nullable ActivityRecord starting) {
// No need to resume activity in TaskFragment that is not visible.
return isTopActivityFocusable()
&& getVisibility(starting) == TASK_FRAGMENT_VISIBILITY_VISIBLE;
}
// TaskFragment.java
int getVisibility(ActivityRecord starting) {
........
// 这里的other即ConfirmAccessControl页面
final int otherWindowingMode = other.getWindowingMode();
if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) {
if (isTranslucent(other, starting)) {
// Can be visible behind a translucent fullscreen TaskFragment.
gotTranslucentFullscreen = true;
continue;
}
// 全屏直接返回,不递归
return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
// 小窗的mode为WINDOWING_MODE_FREEFORM,也不满足下面的条件
} else if (otherWindowingMode == WINDOWING_MODE_MULTI_WINDOW
&& other.matchParentBounds()) {
if (isTranslucent(other, starting)) {
// Can be visible behind a translucent TaskFragment.
gotTranslucentFullscreen = true;
continue;
}
// Multi-window TaskFragment that matches parent bounds would occlude other children
return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
}
.....
// 小窗最后走的这里的流程,返回TASK_FRAGMENT_VISIBILITY_VISIBLE
// Lastly - check if there is a translucent fullscreen TaskFragment on top.
return gotTranslucentFullscreen
? TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT
: TASK_FRAGMENT_VISIBILITY_VISIBLE;
}
合理总结:
上面的getVisibility方法中,小窗应该也跟multi window mode一样处理,毕竟它覆盖住了同一层级底下的TaskFragment,所以该TaskFragment的getVisibility应该也返回TASK_FRAGMENT_VISIBILITY_INVISIBLE。
给谷歌提patch:
谷歌merge
https://android-review.googlesource.com/c/platform/frameworks/base/+/2674876
// 看event log是startPausing过程中陷入递归
08-19 00:27:07.266 1000 11789 17981 I wm_create_activity: [0,93149810,1422,com.taobao.idlefish/.maincontainer.activity.MainActivity,android.intent.action.MAIN,NULL,NULL,270598144]
08-19 00:27:08.036 1000 11789 17981 I wm_restart_activity: [0,93149810,1422,com.taobao.idlefish/.maincontainer.activity.MainActivity]
08-19 00:27:08.978 1000 11789 21836 I wm_finish_activity: [0,197701613,1422,com.lbe.security.miui/com.android.packageinstaller.permission.ui.GrantPermissionsActivity,app-request]
08-19 00:27:09.000 10284 16745 16745 I wm_on_create_called: [0,93149810,com.taobao.idlefish.maincontainer.activity.MainActivity,performCreate,395]
// 陷入递归的页面为GrantPermissionsActivity
08-19 00:27:09.008 1000 11789 21836 I wm_pause_activity: [0,197701613,com.lbe.security.miui/com.android.packageinstaller.permission.ui.GrantPermissionsActivity,userLeaving=false,finish]
08-19 00:27:09.035 10190 13482 13482 I wm_on_paused_called: [0,197701613,com.android.packageinstaller.permission.ui.GrantPermissionsActivity,performPause,0]
// 重复打印的log
08-19 00:27:09.056 1000 11789 11844 I am_wtf : [0,11789,system_server,-1,ActivityTaskManager,Going to pause when pause is already pending for ActivityRecord\\\{bc8afed u0 com.lbe.security.miui/com.android.packageinstaller.permission.ui.GrantPermissionsActivity t1422 f}} state=FINISHING]
.......
08-19 00:28:03.749 1000 11789 11844 I am_wtf : [0,11789,system_server,-1,ActivityTaskManager,Going to pause when pause is already pending for ActivityRecord\\{bc8afed u0 com.lbe.security.miui/com.android.packageinstaller.permission.ui.GrantPermissionsActivity t1422 f}} state=FINISHING]
看下面堆栈可以看出TaskFragment.startPausing- >WindowProcessController.updateTopResumingActivityInProcessIfNeeded之间的递归。
at com.android.server.wm.TaskFragment.startPausing(TaskFragment.java:1773)
........
// 第二次循环堆栈
at com.android.server.wm.TaskFragment.startPausing(TaskFragment.java:1779)
at com.android.server.wm.WindowProcessController.updateTopResumingActivityInProcessIfNeeded(WindowProcessController.java:925)
at com.android.server.wm.ActivityRecord.canResumeByCompat(ActivityRecord.java:11696)
at com.android.server.wm.ActivityRecord.shouldBeResumed(ActivityRecord.java:7019)
at com.android.server.wm.ActivityRecord.shouldResumeActivity(ActivityRecord.java:7007)
at com.android.server.wm.ActivityRecord.makeActiveIfNeeded(ActivityRecord.java:6940)
at com.android.server.wm.RootWindowContainer.lambda$resumeFocusedTasksTopActivities$17(RootWindowContainer.java:2654)
at com.android.server.wm.RootWindowContainer$$ExternalSyntheticLambda14.accept(unavailable:13)
at com.android.server.wm.Task.forAllRootTasks(Task.java:3677)
at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2231)
at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2231)
at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2231)
... repeated 2 times
at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2224)
at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2628)
at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2606)
at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2601)
at com.android.server.wm.ActivityRecord.addToFinishingAndWaitForIdle(ActivityRecord.java:4405)
at com.android.server.wm.ActivityRecord.completeFinishing(ActivityRecord.java:4322)
at com.android.server.wm.TaskFragment.completePause(TaskFragment.java:1951)
// 第一次循环堆栈
at com.android.server.wm.TaskFragment.startPausing(TaskFragment.java:1779)
at com.android.server.wm.WindowProcessController.updateTopResumingActivityInProcessIfNeeded(WindowProcessController.java:925)
at com.android.server.wm.ActivityRecord.canResumeByCompat(ActivityRecord.java:11696)
at com.android.server.wm.ActivityRecord.shouldBeResumed(ActivityRecord.java:7019)
at com.android.server.wm.ActivityRecord.shouldResumeActivity(ActivityRecord.java:7007)
at com.android.server.wm.ActivityRecord.makeActiveIfNeeded(ActivityRecord.java:6940)
at com.android.server.wm.RootWindowContainer.lambda$resumeFocusedTasksTopActivities$17(RootWindowContainer.java:2654)
at com.android.server.wm.RootWindowContainer$$ExternalSyntheticLambda14.accept(unavailable:13)
at com.android.server.wm.Task.forAllRootTasks(Task.java:3677)
at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2231)
at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2231)
at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2231)
... repeated 2 times
at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2224)
at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2628)
at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2606)
at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2601)
at com.android.server.wm.ActivityRecord.addToFinishingAndWaitForIdle(ActivityRecord.java:4405)
at com.android.server.wm.ActivityRecord.completeFinishing(ActivityRecord.java:4322)
at com.android.server.wm.TaskFragment.completePause(TaskFragment.java:1951)
at com.android.server.wm.ActivityRecord.activityPaused(ActivityRecord.java:7188)
at com.android.server.wm.ActivityClientController.activityPaused(ActivityClientController.java:243)
- locked <0x08c0fce1> (a com.android.server.wm.WindowManagerGlobalLock)
at android.app.IActivityClientController$Stub.onTransact(IActivityClientController.java:673)
at com.android.server.wm.ActivityClientController.onTransact(ActivityClientController.java:171)
at android.os.Binder.execTransactInternal(Binder.java:1346)
at android.os.Binder.execTransact(Binder.java:1282)
log打印的地方:
// TaskFragment.java
boolean startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming,
String reason) {
......
if (mPausingActivity != null) {
Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
+ " state=" + mPausingActivity.getState());
if (!shouldSleepActivities()) {
// Avoid recursion among check for sleep and complete pause during sleeping.
// Because activity will be paused immediately after resume, just let pause
// be completed by the order of activity paused from clients.
completePause(false, resuming);
}
}
主要看下updateTopResumingActivityInProcessIfNeeded 的代码逻辑
// 1. 该app的targetSdk确实小于28
Package [com.taobao.idlefish] (4d601a0):
appId=10284
pkg=Package{55da159 com.taobao.idlefish}
.......
versionCode=340 minSdk=21 targetSdk=28
// topRunningActivity为MainActivity
08-19 00:27:07.266 1000 11789 17981 I wm_create_activity: [0,93149810,1422,com.taobao.idlefish/.maincontainer.activity.MainActivity,android.intent.action.MAIN,NULL,NULL,270598144]
08-19 00:27:08.036 1000 11789 17981 I wm_restart_activity: [0,93149810,1422,com.taobao.idlefish/.maincontainer.activity.MainActivity]
// 因为InitActivity还没执行pause,所以它的状态仍然是RESUMED
08-19 00:27:08.041 1000 11789 17981 I wm_add_to_stopping: [0,3457984,com.taobao.idlefish/com.taobao.fleamarket.home.activity.InitActivity,makeInvisible]
此处addToStopping堆栈应该如下:
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: addToStopping
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: java.lang.Throwable
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.ActivityRecord.addToStopping(ActivityRecord.java:7457)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.ActivityRecord.makeInvisible(ActivityRecord.java:6997)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.EnsureActivitiesVisibleHelper.setActivityVisibilityState(EnsureActivitiesVisibleHelper.java:242)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.EnsureActivitiesVisibleHelper.process(EnsureActivitiesVisibleHelper.java:144)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.TaskFragment.updateActivityVisibilities(TaskFragment.java:1243)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.Task.lambda$ensureActivitiesVisible$23(Task.java:5641)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.Task$$ExternalSyntheticLambda26.accept(Unknown Source:10)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.Task.forAllLeafTasks(Task.java:3709)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.Task.ensureActivitiesVisible(Task.java:5640)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.Task.ensureActivitiesVisible(Task.java:5612)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.ActivityStarter.startActivityInner(ActivityStarter.java:2105)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.ActivityStarter.startActivityUnchecked(ActivityStarter.java:1667)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.ActivityStarter.executeRequest(ActivityStarter.java:1482)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.ActivityStarter.execute(ActivityStarter.java:854)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1460)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1411)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.ActivityTaskManagerService.startActivity(ActivityTaskManagerService.java:1386)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at android.app.IActivityTaskManager$Stub.onTransact(IActivityTaskManager.java:1209)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at com.android.server.wm.ActivityTaskManagerService.onTransact(ActivityTaskManagerService.java:6022)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at android.os.Binder.execTransactInternal(Binder.java:1346)
09-20 14:19:51.252 2179 9854 D ActivityTaskManager: at android.os.Binder.execTransact(Binder.java:1282)
09-20 14:19:51.252 2179 9854 D WindowManager: Requesting StartTransition: TransitionRecord{c8aa251 id=20 type=OPEN flags=0x0}
// WindowProcessController#updateTopResumingActivityInProcessIfNeeded
boolean updateTopResumingActivityInProcessIfNeeded(@NonNull ActivityRecord activity) {
// 对于大部分app来说,基本在这里直接返回,只有targetSdk小于Q的app才有可能发生这个问题
if (mInfo.targetSdkVersion >= Q || mPreQTopResumedActivity == activity) {
return true;
}
if (!activity.isAttached()) {
// No need to update if the activity hasn't attach to any display.
return false;
}
boolean canUpdate = false;
// 因为堆栈走到了下面的taskFrag.startPausing,所以mPreQTopResumedActivity != null
// 但是对于Task中的第一个Activity而言,此处的mPreQTopResumedActivity为null,topDisplay为null
final DisplayContent topDisplay =
(mPreQTopResumedActivity != null && mPreQTopResumedActivity.isAttached())
? mPreQTopResumedActivity.mDisplayContent
: null;
// Update the topmost activity if current top activity is
// - not on any display OR
// - no longer visible OR
// - not focusable (in PiP mode for instance)
// 第一个Activity会走如下if语句
if (topDisplay == null
|| !mPreQTopResumedActivity.isVisibleRequested()
|| !mPreQTopResumedActivity.isFocusable()) {
canUpdate = true;
}
final DisplayContent display = activity.mDisplayContent;
// Update the topmost activity if the current top activity wasn't on top of the other one.
if (!canUpdate && topDisplay.compareTo(display) < 0) {
canUpdate = true;
}
// Update the topmost activity if the activity has higher z-order than the current
// top-resumed activity.
if (!canUpdate) {
final ActivityRecord ar = topDisplay.getActivity(r -> r == activity,
true /* traverseTopToBottom */, mPreQTopResumedActivity);
if (ar != null && ar != mPreQTopResumedActivity) {
canUpdate = true;
}
}
// 第一个Activity直接赋值到mPreQTopResumedActivity中
if (canUpdate) {
// Make sure the previous top activity in the process no longer be resumed.
if (mPreQTopResumedActivity != null && mPreQTopResumedActivity.isState(RESUMED)) {
final TaskFragment taskFrag = mPreQTopResumedActivity.getTaskFragment();
if (taskFrag != null) {
boolean userLeaving = taskFrag.shouldBeVisible(null);
taskFrag.startPausing(userLeaving, false /* uiSleeping */,
activity, "top-resumed-changed");
}
}
mPreQTopResumedActivity = activity;
}
return canUpdate;
}
这里的权限页面为通知权限,system server 在应用的首个Activity启动的时候去start
launchNotificationPermissionRequestDialog:1371, PermissionPolicyService$Internal (com.android.server.policy)
showNotificationPromptIfNeeded:1229, PermissionPolicyService$Internal (com.android.server.policy)
showNotificationPromptIfNeeded:1218, PermissionPolicyService$Internal (com.android.server.policy)
run:7867, NotificationManagerService$ShowNotificationPermissionPromptRunnable (com.android.server.notification)
handleCallback:958, Handler (android.os)
dispatchMessage:99, Handler (android.os)
loopOnce:224, Looper (android.os)
loop:318, Looper (android.os)
run:1049, SystemServer (com.android.server)
main:729, SystemServer (com.android.server)
invoke:-1, Method (java.lang.reflect)
run:561, RuntimeInit$MethodAndArgsCaller (com.android.internal.os)
main:991, ZygoteInit (com.android.internal.os)
onActivityLaunched:1180, PermissionPolicyService$Internal$1 (com.android.server.policy)
onActivityLaunched:499, ActivityStartInterceptor (com.android.server.wm)
postStartActivityProcessing:1605, ActivityStarter (com.android.server.wm)
startActivityUnchecked:1683, ActivityStarter (com.android.server.wm)
executeRequest:1482, ActivityStarter (com.android.server.wm)
execute:854, ActivityStarter (com.android.server.wm)
startActivityAsUser:1460, ActivityTaskManagerService (com.android.server.wm)
startActivityAsUser:1411, ActivityTaskManagerService (com.android.server.wm)
startActivity:1386, ActivityTaskManagerService (com.android.server.wm) // InitActivity启动过程中
onTransact:1209, IActivityTaskManager$Stub (android.app)
onTransact:6022, ActivityTaskManagerService (com.android.server.wm)
execTransactInternal:1346, Binder (android.os)
execTransact:1282, Binder (android.os)
合理总结:
大致推测出复现步骤场景:
// 启动闲鱼首页InitActivity
09-06 19:42:35.811 1000 1782 2274 I am_proc_start: [0,29266,10288,com.taobao.idlefish,next-top-activity,\\{com.taobao.idlefish/com.taobao.fleamarket.home.activity.InitActivity}]
09-06 19:42:35.887 1000 1782 5725 I wm_restart_activity: [0,201923591,12580,com.taobao.idlefish/com.taobao.fleamarket.home.activity.InitActivity]
09-06 19:42:35.896 1000 1782 5725 I wm_set_resumed_activity: [0,com.taobao.idlefish/com.taobao.fleamarket.home.activity.InitActivity,minimalResumeActivityLocked - onActivityStateChanged]
// 立刻进入最近任务,在GrantPermissionsActivity启动之前,避免InitActivity被pause
09-06 19:42:36.179 1000 1782 4896 I wm_focused_root_task: [0,0,12013,-1,startExistingRecents]
09-06 19:42:36.188 1000 1782 4896 I wm_set_resumed_activity: [0,com.miui.home/.launcher.Launcher,resumeTopActivity - onActivityStateChanged]
// system server 同Task异步延时启动权限页面,通知权限(这里跟启动InitActivity是不同的线程,且几乎1s后才启动,miui的修改导致)
09-06 19:42:36.847 1000 1782 1782 I wm_create_activity: [0,49649226,12580,com.lbe.security.miui/com.android.packageinstaller.permission.ui.GrantPermissionsActivity,android.content.pm.action.REQUEST_PERMISSIONS_FOR_OTHER,NULL,NULL,277086208]
// 最近任务又立刻点击跟闲鱼Starting window交互(必须很快的进入最近任务再很快的点击闲鱼卡片)
09-06 19:42:37.092 1000 1782 3684 I input_interaction: Interaction with: 3c90915 Splash Screen com.taobao.idlefish (server),
{touchableRegion=[0,717][1800,2163], visible=true, trustedOverlay=false, flags[NOT_TOUCHABLE=false, NOT_FOCUSABLE=false, NOT_TOUCH_MODAL=false]}
, [Gesture Monitor] swipe-up (server), [Gesture Monitor] pip-resize (server), [Gesture Monitor] caption-touch (server), [Gesture Monitor] miui-gesture (server), PointerEventDispatcher0 (server),
// 权限页面可见,此时闲鱼页面还没创建显示(进程不同)
09-06 19:42:37.114 10190 29249 29249 I wm_on_resume_called: [0,49649226,com.android.packageinstaller.permission.ui.GrantPermissionsActivity,RESUME_ACTIVITY,1]
// 闲鱼application 初始化
09-06 19:42:37.836 10288 29266 29266 I wm_on_application_create_called: [0,com.taobao.idlefish,1673]
// InitActivity onCreate中,启动闲鱼主页面
09-06 19:42:38.010 1000 1782 1946 I wm_create_activity: [0,49229126,12580,com.taobao.idlefish/.maincontainer.activity.MainActivity,android.intent.action.MAIN,NULL,NULL,270598144]
09-06 19:42:38.040 1000 1782 1946 I wm_restart_activity: [0,49229126,12580,com.taobao.idlefish/.maincontainer.activity.MainActivity]
09-06 19:42:38.094 10288 29266 29266 I wm_on_create_called: [0,201923591,com.taobao.fleamarket.home.activity.InitActivity,performCreate,208]
09-06 19:42:38.041 1000 1782 1946 I wm_add_to_stopping: [0,201923591,com.taobao.idlefish/com.taobao.fleamarket.home.activity.InitActivity,makeInvisible]
// 在InitActivity stop或者finish之前finish GrantPermissionsActivity页面,保证InitActivity 处于resume状态
09-06 19:42:38.456 1000 1782 3802 I wm_finish_activity: [0,49649226,12580,com.lbe.security.miui/com.android.packageinstaller.permission.ui.GrantPermissionsActivity,app-request]
解决:
本地尝试如下修改并提issue和patch给谷歌:
// WindowProcessController#updateTopResumingActivityInProcessIfNeeded
if (canUpdate) {
// Make sure the previous top activity in the process no longer be resumed.
- if (mPreQTopResumedActivity != null && mPreQTopResumedActivity.isState(RESUMED)) {
+ if (mPreQTopResumedActivity != null && mPreQTopResumedActivity.isState(RESUMED)
+ && !mAtm.mTaskSupervisor.mStoppingActivities.contains(mPreQTopResumedActivity)) {
final TaskFragment taskFrag = mPreQTopResumedActivity.getTaskFragment();
if (taskFrag != null) {
boolean userLeaving = taskFrag.shouldBeVisible(null);
taskFrag.startPausing(userLeaving, false /* uiSleeping */,
activity, "top-resumed-changed");
@@ -926,7 +927,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
activity, "top-resumed-changed");
}
}
谷歌反馈在他们内部的分支上已经修复过