Activity生命周期递归问题查看

这类问题一般比较难分析,符合以下情况的才有可能分析出来:

  • 能够复现并调试
  • 有问题时的堆栈以及对应的event log

TaskFragment#shouldSleepActivities 方法导致递归

There is a recursion among check for sleep and complete pause during sleeping

关键log

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)
  1. 因为上面有走到TaskFragment#completePause,所以这里的shouldSleepActivities会返回false
// 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);
        }
    }
  1. 因为Task.checkReadyForSleep后面有走到Task.goToSleepIfPossible,所以这里的shouldSleepActivities会返回true
// Task.java
void checkReadyForSleep() {
    if (shouldSleepActivities() && goToSleepIfPossible(false /* shuttingDown */)) {
        mTaskSupervisor.checkReadyForSleepLocked(true /* allowDelay */);
    }
}
  1. 但是对同一个Task而言,一个方法基本不会在一个堆栈里既返回false,又返回true。从shouldSleepActivities本身查看下。
    查看代码可以得出,Task继承自TaskFragment,但是TaskFragment的shouldSleepActivities永远返回false,而Task中的shouldSleepActivities在此息屏场景下应该是返回true的。
//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

TaskFragment#getVisibility 未处理小窗模式导致递归

复现步骤

  1. 给微信设置应用锁,以小窗方式打开微信
  2. 息屏后亮屏,应用锁会启动在微信Task最上面
    结果:锁屏解锁后屏幕无反应,过一阵才恢复正常进入桌面

关键log

其次按照上面复现步骤确定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}

关键代码

不合理的TaskFragment结构

从上面堆栈可以看出第二次resume 应用锁下面的LauncherUI页面不太合理,查看微信Task发现如下不合理的结构:
Activity生命周期递归问题查看_第1张图片
所以推测上面的第一次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来规避该问题。
Activity生命周期递归问题查看_第2张图片

// 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;
} 
  • 全屏时getVisibility(starting)获取到的是TASK_FRAGMENT_VISIBILITY_INVISIBLE,所以此处canBeResumed返回false
  • 而小窗下获取到的是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:
Activity生命周期递归问题查看_第3张图片
谷歌merge
https://android-review.googlesource.com/c/platform/frameworks/base/+/2674876

WPC#updateTopResumingActivityInProcessIfNeeded方法未处理Stopping列表

关键log

// 看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. 上面陷入pause循环的activity所在Task对应的app的targetSdkVersion 小于29
    上面的event log可以看出发生递归的GrantPermissionsActivity 处于task#1422,对应的app为com.taobao.idlefish
// 1. 该app的targetSdk确实小于28
  Package [com.taobao.idlefish] (4d601a0):
    appId=10284
    pkg=Package{55da159 com.taobao.idlefish}
   .......
    versionCode=340 minSdk=21 targetSdk=28
  1. mPreQTopResumedActivity 和 pause循环的activity处于同一个Task/TaskFragment
    因为InitActivity为闲鱼的第一个actiivty,所以这里的topDisplay为null,赋值InitActivity到mPreQTopResumedActivity
  2. mPreQTopResumedActivity 不为null且处于RESUMED状态
// 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)

总结 & 解决

合理总结:
大致推测出复现步骤场景:

  1. 首次打开(或清除数据)闲鱼App,页面没加载出来立刻上滑进入最近任务
  2. 最近任务权限弹框出来立刻点击重新返回App
// 启动闲鱼首页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");
                 }
             }

谷歌反馈在他们内部的分支上已经修复过

你可能感兴趣的:(AMS,android,java)