From 18abd0ef7e64c4c6d27b80670fa8755626764e67 Mon Sep 17 00:00:00 2001 From: David Stevens Date: Thu, 17 Aug 2017 14:55:47 -0700 Subject: [PATCH] Fix activity manager timeout during shutdown Flip the return value for ActivityStack.goToSleepIfPossible from true if something needs to be done to true if the stack successfully went to sleep. An incorrect check in ActivityStack.checkReadyForSleep was causing ActivityStackSupervisor to sometimes not get notified when a stack finished stopping during shutdown. Also, no-delay calls to ActivityStackSupervisor#checkReadyForSleepLocked would fail to put activities to sleep. BUG: 64756886 Test: go/run-boottest Change-Id: Icec590ed9a0e0f035881b7eb03a280787dcfced1 --- .../com/android/server/am/ActivityStack.java | 7 ++-- .../server/am/ActivityStackSupervisor.java | 42 +++++++++---------- .../android/server/am/ActivityStackTests.java | 4 +- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 84fd0de4f0ab8..c2656a188dc88 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1184,7 +1184,8 @@ class ActivityStack extends ConfigurationContai * function get called again when those actions complete. * * @param shuttingDown true when the called because the device is shutting down. - * @return true if something must be done before going to sleep. + * @return true if the stack finished going to sleep, false if the stack only started the + * process of going to sleep (checkReadyForSleep will be called when that process finishes). */ boolean goToSleepIfPossible(boolean shuttingDown) { boolean shouldSleep = true; @@ -1235,10 +1236,10 @@ class ActivityStack extends ConfigurationContai goToSleep(); } - return !shouldSleep; + return shouldSleep; } - private void goToSleep() { + void goToSleep() { ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); // Make sure any paused or stopped but visible activities are now sleeping. diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 1c1895449466e..68a4ad964ab81 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -3173,15 +3173,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean timedout = false; final long endTime = System.currentTimeMillis() + timeout; while (true) { - boolean cantShutdown = false; - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - cantShutdown |= - stacks.get(stackNdx).goToSleepIfPossible(true /* shuttingDown */); - } - } - if (cantShutdown) { + if (!putStacksToSleepLocked(true /* allowDelay */, true /* shuttingDown */)) { long timeRemaining = endTime - System.currentTimeMillis(); if (timeRemaining > 0) { try { @@ -3268,19 +3260,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return; } - if (allowDelay) { - boolean dontSleep = false; - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - final ArrayList stacks = display.mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - dontSleep |= stacks.get(stackNdx).goToSleepIfPossible(false /* shuttingDown */); - } - } - - if (dontSleep) { - return; - } + if (!putStacksToSleepLocked(allowDelay, false /* shuttingDown */)) { + return; } // Send launch end powerhint before going sleep @@ -3296,6 +3277,23 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } + // Tries to put all activity stacks to sleep. Returns true if all stacks were + // successfully put to sleep. + private boolean putStacksToSleepLocked(boolean allowDelay, boolean shuttingDown) { + boolean allSleep = true; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + if (allowDelay) { + allSleep &= stacks.get(stackNdx).goToSleepIfPossible(shuttingDown); + } else { + stacks.get(stackNdx).goToSleep(); + } + } + } + return allSleep; + } + boolean reportResumedActivityLocked(ActivityRecord r) { final ActivityStack stack = r.getStack(); if (isFocusedStack(stack)) { 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 ba221591fc92d..80e241c0581f0 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -17,9 +17,9 @@ package com.android.server.am; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; import android.app.ActivityManager; import android.content.ComponentName; @@ -81,7 +81,7 @@ public class ActivityStackTests extends ActivityTestsBase { final boolean waiting = testStack.goToSleepIfPossible(false); // Ensure we report not being ready for sleep. - assertTrue(waiting); + assertFalse(waiting); // Make sure the resumed activity is untouched. assertEquals(testStack.mResumedActivity, activityRecord);