[AAE Power Mgt] Allow Suspend to RAM without triggering Garage Mode

The Vehicle HAL can tell us to shut down immediately, but it cannot
tell us to suspend immediately. Add that capability.

This capability will be needed when the VHAL initiates a Silent
Boot and then asks for suspension. In this case, we do not want
to postpone the suspension by entering Garage Mode.

Bug: 134521909
Test: Added CarPowerManagementTest.testSleepImmediateEntry()
Test: Added CarPowerManagementServiceTest.testSleepImmediately()
Change-Id: Idc89757a93819560fa848f30eb480645a9ac37c5
diff --git a/service/src/com/android/car/CarPowerManagementService.java b/service/src/com/android/car/CarPowerManagementService.java
index c1341da..456ad8d 100644
--- a/service/src/com/android/car/CarPowerManagementService.java
+++ b/service/src/com/android/car/CarPowerManagementService.java
@@ -521,7 +521,8 @@
                 return (newState.mState == CpmsState.SHUTDOWN_PREPARE)
                     || (newState.mState == CpmsState.SIMULATE_SLEEP);
             case CpmsState.SHUTDOWN_PREPARE:
-                // If VHAL sends SHUTDOWN_IMMEDIATELY while in SHUTDOWN_PREPARE state, do it.
+                // If VHAL sends SHUTDOWN_IMMEDIATELY or SLEEP_IMMEDIATELY while in
+                // SHUTDOWN_PREPARE state, do it.
                 return ((newState.mState == CpmsState.SHUTDOWN_PREPARE) && !newState.mCanPostpone)
                     || (newState.mState == CpmsState.WAIT_FOR_FINISH)
                     || (newState.mState == CpmsState.WAIT_FOR_VHAL);
diff --git a/service/src/com/android/car/hal/PowerHalService.java b/service/src/com/android/car/hal/PowerHalService.java
index 13d477f..faa6a43 100644
--- a/service/src/com/android/car/hal/PowerHalService.java
+++ b/service/src/com/android/car/hal/PowerHalService.java
@@ -145,7 +145,8 @@
             if (mState != VehicleApPowerStateReq.SHUTDOWN_PREPARE) {
                 throw new IllegalStateException("wrong state");
             }
-            return (mParam != VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
+            return (mParam != VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY
+                    && mParam != VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY);
         }
 
         @Override
diff --git a/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java b/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java
index f4d4522..a40bfec 100644
--- a/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java
+++ b/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java
@@ -261,6 +261,22 @@
         mMockDisplayInterface.waitForDisplayState(false);
     }
 
+    @Test
+    @UiThreadTest
+    public void testSleepImmediateEntry() throws Exception {
+        assertWaitForVhal();
+        mMockDisplayInterface.waitForDisplayState(false);
+        mPowerStateHandler.sendStateAndCheckResponse(
+                VehicleApPowerStateReq.ON,
+                0,
+                VehicleApPowerStateReport.ON);
+        mMockDisplayInterface.waitForDisplayState(true);
+        mPowerStateHandler.sendPowerState(
+                VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+                VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY);
+        assertResponse(VehicleApPowerStateReport.SHUTDOWN_START, 0, true);
+    }
+
     // Check that 'expectedState' was reached and is the current state.
     private void assertResponse(int expectedState, int expectedParam, boolean checkParam)
             throws Exception {
@@ -411,8 +427,8 @@
         }
 
         /**
-         * Checks that a power state transition does NOT occur.  If any state does occur during
-         * the timeout period, then the test fails.
+         * Checks that a power state transition does NOT occur. If any state does occur during
+         * the timeout period (other than a POSTPONE), then the test fails.
          */
         private void sendStateAndExpectNoResponse(int state, int param) throws Exception {
             sendPowerState(state, param);
@@ -420,15 +436,14 @@
             if (!mSetWaitSemaphore.tryAcquire(DEFAULT_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
                 // No state transition, this is a success!
                 return;
-            } else {
-                synchronized (this) {
-                    int[] newState = mSetStates.pop();
-                    if (newState[0] != VehicleApPowerStateReport.SHUTDOWN_POSTPONE) {
-                        fail("Unexpected state change occured, state=" + newState[0]);
-                    }
-                    // Reset the collected states
-                    mSetStates = new LinkedList<>();
+            }
+            synchronized (this) {
+                int[] newState = mSetStates.pop();
+                if (newState[0] != VehicleApPowerStateReport.SHUTDOWN_POSTPONE) {
+                    fail("Unexpected state change occurred, state=" + newState[0]);
                 }
+                // Reset the collected states
+                mSetStates = new LinkedList<>();
             }
         }
 
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 382d7ad..c9775d5 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,25 @@
         mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
     }
 
+    public void testSleepImmediately() throws Exception {
+        initTest(0);
+
+        // Transition to ON state
+        mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
+        assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS));
+
+        mPowerHal.setCurrentPowerState(
+                new PowerState(
+                        VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+                        VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY));
+        // Since modules have to manually schedule next wakeup, we should not schedule next wakeup
+        // To test module behavior, we need to actually implement mock listener module.
+        assertStateReceived(PowerHalService.SET_SHUTDOWN_START, 0);
+        assertFalse(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS));
+        mPowerSignalListener.waitForShutdown(WAIT_TIMEOUT_MS);
+        mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
+    }
+
     public void testShutdownWithProcessing() throws Exception {
         final int wakeupTime = 100;
         initTest(wakeupTime);