From 5daa3121a92f5e3124b8db469aeddea269a4c1df Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Wed, 19 Apr 2017 10:40:42 -0700 Subject: [PATCH] Do not pause resumed activity in resumeTopActivityUncheckedLocked. A number of operations occur between setting the resumed activity and notifying the activity to resume. One of these steps is updating the configuration, which can cause the device to pause the resumed activity. Since the activity has not been told to resume, this leads to a pause before resume. This changelist addresses the issue by checking whether we are in the middle of resuming the top activity before attempting to stop the currently set resumed activity. Change-Id: I3b5b61de6b1b5a35b7773912b4e63d6c69096c04 Fixes: 35637717 Test: bit FrameworksServicesTests:com.android.server.am.ActivityStackTests#testNoPauseDuringResumeTopActivity --- .../com/android/server/am/ActivityStack.java | 20 ++++++++++++++++ .../android/server/am/ActivityStackTests.java | 24 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 85c5c647ceede..824ec68a86605 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1152,6 +1152,18 @@ class ActivityStack extends ConfigurationContai if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep needs to pause " + mResumedActivity); if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING, "Sleep => pause with userLeaving=false"); + + // If we are in the middle of resuming the top activity in + // {@link #resumeTopActivityUncheckedLocked}, mResumedActivity will be set but not + // resumed yet. We must not proceed pausing the activity here. This method will be + // called again if necessary as part of + // {@link ActivityStackSupervisor#checkReadyForSleepLocked}. + if (mStackSupervisor.inResumeTopActivity) { + if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "In the middle of resuming top activity " + + mResumedActivity); + return true; + } + startPausingLocked(false, true, null, false); return true; } @@ -1229,6 +1241,7 @@ class ActivityStack extends ConfigurationContai } } ActivityRecord prev = mResumedActivity; + if (prev == null) { if (resuming == null) { Slog.wtf(TAG, "Trying to pause when nothing is resumed"); @@ -2191,6 +2204,13 @@ class ActivityStack extends ConfigurationContai } finally { mStackSupervisor.inResumeTopActivity = false; } + // When resuming the top activity, it may be necessary to pause the top activity (for + // example, returning to the lock screen. We suppress the normal pause logic in + // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the end. + // We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here to ensure + // any necessary pause logic occurs. + mStackSupervisor.checkReadyForSleepLocked(); + return result; } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java index f42abf1927f05..58166b6c1ac5b 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -16,8 +16,10 @@ package com.android.server.am; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import android.content.ComponentName; import android.platform.test.annotations.Presubmit; @@ -50,6 +52,7 @@ public class ActivityStackTests extends ActivityTestsBase { "testEmptyTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING); assertNull(task.getWindowContainerController()); } + @Test public void testOccupiedTaskCleanupOnRemove() throws Exception { final ActivityManagerService service = createActivityManagerService(); @@ -60,4 +63,25 @@ public class ActivityStackTests extends ActivityTestsBase { "testOccupiedTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING); assertNotNull(task.getWindowContainerController()); } + + @Test + public void testNoPauseDuringResumeTopActivity() throws Exception { + final ActivityManagerService service = createActivityManagerService(); + final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); + final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task); + final ActivityStack testStack = service.mStackSupervisor.getStack(TEST_STACK_ID); + + // Simulate the a resumed activity set during + // {@link ActivityStack#resumeTopActivityUncheckedLocked}. + service.mStackSupervisor.inResumeTopActivity = true; + testStack.mResumedActivity = activityRecord; + + final boolean waiting = testStack.checkReadyForSleepLocked(); + + // Ensure we report not being ready for sleep. + assertTrue(waiting); + + // Make sure the resumed activity is untouched. + assertEquals(testStack.mResumedActivity, activityRecord); + } }