Allow "suspend" after a "shutdown" command is canceled
CarPowerManagementService needs to re-evaluate whether to
power down or suspend for each "shutdown" command. Otherwise
it will remember a previous power down command, even if that
command is canceled.
By re-evaluating, it makes takes the correct action, regardless
of previous commands.
Fixes: 144786716
Test: Added CarPowerManagementServiceTest.testShutdownCancel
Test: Added CarPowerManagementServiceTest.testShutdownOnSuspend
Test: Added CarPowerManagementServiceTest.testSuspend
Merged-In: Id856e5d8546e38a7f3d568b5f871b9e945d95773
Change-Id: Id856e5d8546e38a7f3d568b5f871b9e945d95773
(cherry picked from commit cc1f7fb852230159e0daec9c40bbc8348078f46c)
diff --git a/service/src/com/android/car/CarPowerManagementService.java b/service/src/com/android/car/CarPowerManagementService.java
index 83c5051..a1f067b 100644
--- a/service/src/com/android/car/CarPowerManagementService.java
+++ b/service/src/com/android/car/CarPowerManagementService.java
@@ -95,6 +95,8 @@
@GuardedBy("mLock")
private boolean mShutdownOnFinish;
@GuardedBy("mLock")
+ private boolean mShutdownOnNextSuspend;
+ @GuardedBy("mLock")
private boolean mIsBooting = true;
@GuardedBy("mLock")
private boolean mIsResuming;
@@ -215,6 +217,7 @@
writer.print(",mProcessingStartTime:" + mProcessingStartTime);
writer.print(",mLastSleepEntryTime:" + mLastSleepEntryTime);
writer.print(",mNextWakeupSec:" + mNextWakeupSec);
+ writer.print(",mShutdownOnNextSuspend:" + mShutdownOnNextSuspend);
writer.print(",mShutdownOnFinish:" + mShutdownOnFinish);
writer.println(",sShutdownPrepareTimeMs:" + sShutdownPrepareTimeMs);
}
@@ -308,6 +311,7 @@
mHal.sendWaitForVhal();
break;
case CarPowerStateListener.SHUTDOWN_CANCELLED:
+ mShutdownOnNextSuspend = false; // This cancels the "NextSuspend"
mHal.sendShutdownCancel();
break;
case CarPowerStateListener.SUSPEND_EXIT:
@@ -357,7 +361,8 @@
mSystemInterface.setDisplayState(false);
// Shutdown on finish if the system doesn't support deep sleep or doesn't allow it.
synchronized (mLock) {
- mShutdownOnFinish |= !mHal.isDeepSleepAllowed()
+ mShutdownOnFinish = mShutdownOnNextSuspend
+ || !mHal.isDeepSleepAllowed()
|| !mSystemInterface.isSystemSupportingDeepSleep()
|| !newState.mCanSleep;
}
@@ -419,6 +424,7 @@
} else {
doHandleDeepSleep(simulatedMode);
}
+ mShutdownOnNextSuspend = false;
}
@GuardedBy("mLock")
@@ -503,7 +509,7 @@
listener.onStateChanged(newState);
} catch (RemoteException e) {
// It's likely the connection snapped. Let binder death handle the situation.
- Log.e(CarLog.TAG_POWER, "onStateChanged() call failed: " + e, e);
+ Log.e(CarLog.TAG_POWER, "onStateChanged() call failed", e);
}
}
listenerList.finishBroadcast();
@@ -676,7 +682,7 @@
public void requestShutdownOnNextSuspend() {
ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
synchronized (mLock) {
- mShutdownOnFinish = true;
+ mShutdownOnNextSuspend = true;
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
index 945a9d6..056fe9c 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
@@ -142,6 +142,86 @@
mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
}
+ public void testSuspend() throws Exception {
+ final int wakeupTime = 100;
+ initTest(wakeupTime);
+
+ // Start in the ON state
+ mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
+ assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS));
+ // Request suspend
+ mPowerHal.setCurrentPowerState(
+ new PowerState(
+ VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+ VehicleApPowerStateShutdownParam.CAN_SLEEP));
+ // Verify suspend
+ assertStateReceivedForShutdownOrSleepWithPostpone(
+ PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, wakeupTime);
+ }
+
+ public void testShutdownOnSuspend() throws Exception {
+ final int wakeupTime = 100;
+ initTest(wakeupTime);
+
+ // Start in the ON state
+ mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
+ assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS));
+ // Tell it to shutdown
+ mService.requestShutdownOnNextSuspend();
+ // Request suspend
+ mPowerHal.setCurrentPowerState(
+ new PowerState(
+ VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+ VehicleApPowerStateShutdownParam.CAN_SLEEP));
+ // Verify shutdown
+ assertStateReceivedForShutdownOrSleepWithPostpone(
+ PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_LONG_MS, wakeupTime);
+ mPowerSignalListener.waitForShutdown(WAIT_TIMEOUT_MS);
+ // Send the finished signal
+ mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
+ mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
+ // Cancel the shutdown
+ mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.CANCEL_SHUTDOWN, 0));
+ assertStateReceivedForShutdownOrSleepWithPostpone(
+ PowerHalService.SET_SHUTDOWN_CANCELLED, WAIT_TIMEOUT_LONG_MS, 0);
+
+ // Request suspend again
+ mPowerHal.setCurrentPowerState(
+ new PowerState(
+ VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+ VehicleApPowerStateShutdownParam.CAN_SLEEP));
+ // Verify suspend
+ assertStateReceivedForShutdownOrSleepWithPostpone(
+ PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, wakeupTime);
+ }
+
+ public void testShutdownCancel() throws Exception {
+ final int wakeupTime = 100;
+ initTest(wakeupTime);
+
+ // Start in the ON state
+ mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
+ assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS));
+ // Start shutting down
+ mPowerHal.setCurrentPowerState(
+ new PowerState(
+ VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+ VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY));
+ assertStateReceivedForShutdownOrSleepWithPostpone(
+ PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_LONG_MS, 0);
+ // Cancel the shutdown
+ mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.CANCEL_SHUTDOWN, 0));
+ assertStateReceivedForShutdownOrSleepWithPostpone(
+ PowerHalService.SET_SHUTDOWN_CANCELLED, WAIT_TIMEOUT_LONG_MS, 0);
+ // Go to suspend
+ mPowerHal.setCurrentPowerState(
+ new PowerState(
+ VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+ VehicleApPowerStateShutdownParam.CAN_SLEEP));
+ assertStateReceivedForShutdownOrSleepWithPostpone(
+ PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, wakeupTime);
+ }
+
public void testShutdownWithProcessing() throws Exception {
final int wakeupTime = 100;
initTest(wakeupTime);
diff --git a/tests/carservice_unit_test/src/com/android/car/MockedPowerHalService.java b/tests/carservice_unit_test/src/com/android/car/MockedPowerHalService.java
index 7359a03..770cc85 100644
--- a/tests/carservice_unit_test/src/com/android/car/MockedPowerHalService.java
+++ b/tests/carservice_unit_test/src/com/android/car/MockedPowerHalService.java
@@ -87,6 +87,12 @@
doSendState(SET_SHUTDOWN_START, wakeupTimeSec);
}
+ @Override
+ public void sendShutdownCancel() {
+ Log.i(TAG, "sendShutdownCancel");
+ doSendState(SET_SHUTDOWN_CANCELLED, 0);
+ }
+
public synchronized int[] waitForSend(long timeoutMs) throws Exception {
if (mSentStates.size() == 0) {
wait(timeoutMs);