[AAE ADB] Simulate 'suspend' via ADB
Add ADB commands:
adb shell dumpsys car_service suspend
adb shell dumpsys car_service resume
or
adb shell dumpsys activity service com.android.car suspend
adb shell dumpsys activity service com.android.car resume
The 'suspend' command initiates SHUTDOWN_PREPARE. After all the
preparations are complete, this code goes into a loop rather than
attempting to power down the CPU. This should allow us to test
Suspend to RAM before the RH850 code and hardware are ready.
The 'resume' command exits the shutdown loop and transitions the
SOC back to the ON state.
Fixes: 125346852
Test: Manually ran ADB commands on a Hawk
Change-Id: I85c7b8526350fca3cb4bb1b6d8b2ac648ae4d206
diff --git a/service/src/com/android/car/CarPowerManagementService.java b/service/src/com/android/car/CarPowerManagementService.java
index 3108a02..c2c43d2 100644
--- a/service/src/com/android/car/CarPowerManagementService.java
+++ b/service/src/com/android/car/CarPowerManagementService.java
@@ -78,6 +78,8 @@
private int mTokenValue = 1;
private boolean mShutdownOnFinish = false;
private boolean mIsBooting = true;
+ private boolean mSimulatingDeepSleep = false;
+ private Object mSimulationSleepObject = new Object();
private final CarUserManagerHelper mCarUserManagerHelper;
@@ -233,7 +235,7 @@
if (state == null) {
return;
}
- Log.i(CarLog.TAG_POWER, "doHandlePowerStateChange: newState=" + state.mState);
+ Log.i(CarLog.TAG_POWER, "doHandlePowerStateChange: newState=" + state.name());
if (!needPowerStateChangeLocked(state)) {
Log.d(CarLog.TAG_POWER, "doHandlePowerStateChange no change needed");
return;
@@ -255,6 +257,9 @@
case CpmsState.SHUTDOWN_PREPARE:
handleShutdownPrepare(state);
break;
+ case CpmsState.SIMULATE_SLEEP:
+ simulateShutdownPrepare();
+ break;
case CpmsState.WAIT_FOR_FINISH:
handleWaitForFinish(state);
break;
@@ -310,7 +315,7 @@
|| !mSystemInterface.isSystemSupportingDeepSleep()
|| !newState.mCanSleep;
if (newState.mCanPostpone) {
- Log.i(CarLog.TAG_POWER, "starting shutdown postpone");
+ Log.i(CarLog.TAG_POWER, "starting shutdown prepare");
sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE);
mHal.sendShutdownPrepare();
doHandlePreprocessing();
@@ -327,6 +332,15 @@
}
}
+ // Simulate system shutdown to Deep Sleep
+ private void simulateShutdownPrepare() {
+ mSystemInterface.setDisplayState(false);
+ Log.i(CarLog.TAG_POWER, "starting shutdown prepare");
+ sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE);
+ mHal.sendShutdownPrepare();
+ doHandlePreprocessing();
+ }
+
private void handleWaitForFinish(CpmsState state) {
sendPowerManagerEvent(state.mCarPowerStateListenerState);
switch (state.mCarPowerStateListenerState) {
@@ -340,7 +354,7 @@
}
private void handleFinish() {
- if (mShutdownOnFinish) {
+ if (mShutdownOnFinish && !mSimulatingDeepSleep) {
// shutdown HU
mSystemInterface.shutdown();
} else {
@@ -433,11 +447,17 @@
synchronized (CarPowerManagementService.this) {
mLastSleepEntryTime = SystemClock.elapsedRealtime();
}
- if (!mSystemInterface.enterDeepSleep()) {
- // System did not suspend. VHAL should transition CPMS to shutdown.
- Log.e(CarLog.TAG_POWER, "Sleep did not succeed. Need to shutdown");
+ if (mSimulatingDeepSleep) {
+ simulateSleepByLooping();
+ } else {
+ boolean sleepSucceeded = mSystemInterface.enterDeepSleep();
+ if (!sleepSucceeded) {
+ // VHAL should transition CPMS to shutdown.
+ Log.e(CarLog.TAG_POWER, "Sleep did not succeed. Now attempting to shut down.");
+ mSystemInterface.shutdown();
+ }
}
- // On wake, reset nextWakeup time. If not set again, system will suspend/shutdown forever.
+ // On wake, reset nextWakeup time. If not set again, system will suspend/shutdown forever.
mNextWakeupSec = 0;
mSystemInterface.refreshDisplayBrightness();
onApPowerStateChange(CpmsState.WAIT_FOR_VHAL, CarPowerStateListener.SUSPEND_EXIT);
@@ -460,17 +480,21 @@
case CpmsState.SUSPEND:
return newState.mState == CpmsState.WAIT_FOR_VHAL;
case CpmsState.ON:
- return newState.mState == CpmsState.SHUTDOWN_PREPARE;
+ 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.
return ((newState.mState == CpmsState.SHUTDOWN_PREPARE) && !newState.mCanPostpone)
|| (newState.mState == CpmsState.WAIT_FOR_FINISH)
- || (newState.mState == CpmsState.WAIT_FOR_VHAL);
+ || (newState.mState == CpmsState.WAIT_FOR_VHAL)
+ || (newState.mState == CpmsState.ON);
+ case CpmsState.SIMULATE_SLEEP:
+ return true;
case CpmsState.WAIT_FOR_FINISH:
return newState.mState == CpmsState.SUSPEND;
default:
Log.e(CarLog.TAG_POWER, "Unhandled state transition: currentState="
- + mCurrentState.mState + ", newState=" + newState.mState);
+ + mCurrentState.name() + ", newState=" + newState.name());
return false;
}
}
@@ -587,7 +611,7 @@
mNextWakeupSec = seconds;
} else {
Log.d(CarLog.TAG_POWER, "Tried to schedule next wake up, but already had shorter "
- + " scheduled time");
+ + "scheduled time");
}
}
@@ -596,7 +620,8 @@
if (currentToken == token) {
mPowerManagerListenerTokens.remove(binder);
if (mPowerManagerListenerTokens.isEmpty() &&
- (mCurrentState.mState == CpmsState.SHUTDOWN_PREPARE)) {
+ (mCurrentState.mState == CpmsState.SHUTDOWN_PREPARE
+ || mCurrentState.mState == CpmsState.SIMULATE_SLEEP)) {
PowerHandler powerHandler;
// All apps are ready to shutdown/suspend.
synchronized (CarPowerManagementService.this) {
@@ -716,6 +741,7 @@
public static final int SHUTDOWN_PREPARE = 2;
public static final int WAIT_FOR_FINISH = 3;
public static final int SUSPEND = 4;
+ public static final int SIMULATE_SLEEP = 5;
/* Config values from AP_POWER_STATE_REQ */
public final boolean mCanPostpone;
@@ -771,12 +797,26 @@
}
CpmsState(int state, int carPowerStateListenerState) {
- this.mCanPostpone = false;
- this.mCanSleep = false;
+ this.mCanPostpone = (state == SIMULATE_SLEEP);
+ this.mCanSleep = (state == SIMULATE_SLEEP);
this.mCarPowerStateListenerState = carPowerStateListenerState;
this.mState = state;
}
+ public String name() {
+ String baseName;
+ switch(mState) {
+ case WAIT_FOR_VHAL: baseName = "WAIT_FOR_VHAL"; break;
+ case ON: baseName = "ON"; break;
+ case SHUTDOWN_PREPARE: baseName = "SHUTDOWN_PREPARE"; break;
+ case WAIT_FOR_FINISH: baseName = "WAIT_FOR_FINISH"; break;
+ case SUSPEND: baseName = "SUSPEND"; break;
+ case SIMULATE_SLEEP: baseName = "SIMULATE_SLEEP"; break;
+ default: baseName = "<unknown>"; break;
+ }
+ return baseName + "(" + mState + ")";
+ }
+
private static int cpmsStateToPowerStateListenerState(int state) {
int powerStateListenerState = 0;
@@ -819,8 +859,55 @@
public String toString() {
return "CpmsState canSleep:" + mCanSleep + ", canPostpone=" + mCanPostpone
+ ", carPowerStateListenerState=" + mCarPowerStateListenerState
- + ", CpmsState=" + mState;
+ + ", CpmsState=" + this.name();
}
}
+ /**
+ * Resume after a manually-invoked suspend.
+ * Invoked using "adb shell dumpsys activity service com.android.car resume".
+ */
+ public void forceSimulatedResume() {
+ synchronized (mSimulationSleepObject) {
+ mSimulatingDeepSleep = false;
+ mSimulationSleepObject.notify();
+ }
+ }
+
+ /**
+ * Manually enter simulated suspend (Deep Sleep) mode
+ * Invoked using "adb shell dumpsys activity service com.android.car suspend".
+ * This is similar to 'onApPowerStateChange()' except that it needs to create a CpmsState
+ * that is not directly derived from a VehicleApPowerStateReq.
+ */
+ public void forceSimulatedSuspend() {
+ synchronized (mSimulationSleepObject) {
+ mSimulatingDeepSleep = true;
+ }
+ PowerHandler handler;
+ synchronized (this) {
+ mPendingPowerStates.addFirst(new CpmsState(CpmsState.SIMULATE_SLEEP,
+ CarPowerStateListener.SHUTDOWN_PREPARE));
+ handler = mHandler;
+ }
+ handler.handlePowerStateChange();
+ }
+
+ // In a real Deep Sleep, the hardware removes power from the CPU (but retains power
+ // on the RAM). This puts the processor to sleep. Upon some external signal, power
+ // is re-applied to the CPU, and processing resumes right where it left off.
+ // We simulate this behavior by simply going into a loop.
+ // We exit the loop when forceResume() is called.
+ private void simulateSleepByLooping() {
+ Log.i(CarLog.TAG_POWER, "Starting to simulate Deep Sleep by looping");
+ synchronized (mSimulationSleepObject) {
+ while (mSimulatingDeepSleep) {
+ try {
+ mSimulationSleepObject.wait();
+ } catch (InterruptedException ignored) {
+ }
+ }
+ }
+ Log.i(CarLog.TAG_POWER, "Exit Deep Sleep simulation loop");
+ }
}
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index 35255ee..d508d5e 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -479,6 +479,8 @@
private static final String COMMAND_GET_DO_ACTIVITIES = "get-do-activities";
private static final String COMMAND_GET_CARPROPERTYCONFIG = "get-carpropertyconfig";
private static final String COMMAND_PROJECTION_UI_MODE = "projection-ui-mode";
+ private static final String COMMAND_RESUME = "resume";
+ private static final String COMMAND_SUSPEND = "suspend";
private static final String PARAM_DAY_MODE = "day";
private static final String PARAM_NIGHT_MODE = "night";
@@ -505,6 +507,10 @@
pw.println("\t Get Distraction Optimized activities in given package.");
pw.println("\tget-carpropertyconfig [propertyId]");
pw.println("\t Get a CarPropertyConfig by Id in Hex or list all CarPropertyConfigs");
+ pw.println("\tsuspend");
+ pw.println("\t Suspend the system to Deep Sleep.");
+ pw.println("\tresume");
+ pw.println("\t Wake the system up after a 'suspend.'");
}
public void exec(String[] args, PrintWriter writer) {
@@ -584,6 +590,14 @@
}
mCarProjectionService.setUiMode(Integer.valueOf(args[1]));
break;
+ case COMMAND_RESUME:
+ mCarPowerManagementService.forceSimulatedResume();
+ writer.println("Resume: Simulating resuming from Deep Sleep");
+ break;
+ case COMMAND_SUSPEND:
+ mCarPowerManagementService.forceSimulatedSuspend();
+ writer.println("Resume: Simulating powering down to Deep Sleep");
+ break;
default:
writer.println("Unknown command: \"" + arg + "\"");
dumpHelp(writer);
diff --git a/service/src/com/android/car/hal/PowerHalService.java b/service/src/com/android/car/hal/PowerHalService.java
index 3972984..ffa5f7a 100644
--- a/service/src/com/android/car/hal/PowerHalService.java
+++ b/service/src/com/android/car/hal/PowerHalService.java
@@ -69,6 +69,34 @@
@VisibleForTesting
public static final int SHUTDOWN_ONLY = VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY;
+ private static String powerStateReportName(int state) {
+ String baseName;
+ switch(state) {
+ case SET_WAIT_FOR_VHAL: baseName = "WAIT_FOR_VHAL"; break;
+ case SET_DEEP_SLEEP_ENTRY: baseName = "DEEP_SLEEP_ENTRY"; break;
+ case SET_DEEP_SLEEP_EXIT: baseName = "DEEP_SLEEP_EXIT"; break;
+ case SET_SHUTDOWN_POSTPONE: baseName = "SHUTDOWN_POSTPONE"; break;
+ case SET_SHUTDOWN_START: baseName = "SHUTDOWN_START"; break;
+ case SET_ON: baseName = "ON"; break;
+ case SET_SHUTDOWN_PREPARE: baseName = "SHUTDOWN_PREPARE"; break;
+ case SET_SHUTDOWN_CANCELLED: baseName = "SHUTDOWN_CANCELLED"; break;
+ default: baseName = "<unknown>"; break;
+ }
+ return baseName + "(" + state + ")";
+ }
+
+ private static String powerStateReqName(int state) {
+ String baseName;
+ switch(state) {
+ case VehicleApPowerStateReq.ON: baseName = "ON"; break;
+ case VehicleApPowerStateReq.SHUTDOWN_PREPARE: baseName = "SHUTDOWN_PREPARE"; break;
+ case VehicleApPowerStateReq.CANCEL_SHUTDOWN: baseName = "CANCEL_SHUTDOWN"; break;
+ case VehicleApPowerStateReq.FINISHED: baseName = "FINISHED"; break;
+ default: baseName = "<unknown>"; break;
+ }
+ return baseName + "(" + state + ")";
+ }
+
public interface PowerEventListener {
/**
* Received power state change event.
@@ -252,7 +280,8 @@
int[] values = { state, additionalParam };
try {
mHal.set(VehicleProperty.AP_POWER_STATE_REPORT, 0).to(values);
- Log.i(CarLog.TAG_POWER, "setPowerState=" + state + " param=" + additionalParam);
+ Log.i(CarLog.TAG_POWER, "setPowerState=" + powerStateReportName(state)
+ + " param=" + additionalParam);
} catch (PropertyTimeoutException e) {
Log.e(CarLog.TAG_POWER, "cannot set to AP_POWER_STATE_REPORT", e);
}
@@ -359,8 +388,8 @@
case AP_POWER_STATE_REQ:
int state = v.value.int32Values.get(VehicleApPowerStateReqIndex.STATE);
int param = v.value.int32Values.get(VehicleApPowerStateReqIndex.ADDITIONAL);
- Log.i(CarLog.TAG_POWER, "Received AP_POWER_STATE_REQ=" + state
- + " param=" + param);
+ Log.i(CarLog.TAG_POWER, "Received AP_POWER_STATE_REQ="
+ + powerStateReqName(state) + " param=" + param);
listener.onApPowerStateChange(new PowerState(state, param));
break;
case DISPLAY_BRIGHTNESS: