Add an API to tell whenever device supports userspace reboot

If device doesn't support userspace reboot then call to
PowerManager.reboot("userspace") will throw an
UnsupportedOperationException.

For the case of upgrading devices, Treble enforces that previous vendor
image should work with the new system image. Since userspace reboot
requires services to be stopped and restarted cleanly, which upgrading
devices might not be able to comply with, we need to have an API to
distinguish between devices that support userspace reboot and the ones
that do not.

Test: atest PowerManagerTest
Test: atest CtsUserspaceRebootHostSideTestCases
Bug: 138605273
Bug: 135984674
Change-Id: I8303f43ab29499eb2995f0256854c787055d9560
This commit is contained in:
Nikita Ioffe
2019-12-18 13:45:15 +00:00
parent f5b6267d93
commit 717dbbf1a4
4 changed files with 39 additions and 2 deletions

View File

@@ -35016,11 +35016,12 @@ package android.os {
method public boolean isIgnoringBatteryOptimizations(String);
method public boolean isInteractive();
method public boolean isPowerSaveMode();
method public boolean isRebootingUserspaceSupported();
method @Deprecated public boolean isScreenOn();
method public boolean isSustainedPerformanceModeSupported();
method public boolean isWakeLockLevelSupported(int);
method public android.os.PowerManager.WakeLock newWakeLock(int, String);
method public void reboot(String);
method public void reboot(@Nullable String);
method public void removeThermalStatusListener(@NonNull android.os.PowerManager.OnThermalStatusChangedListener);
field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
field public static final String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";

View File

@@ -5986,6 +5986,7 @@ package android.os {
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.USER_ACTIVITY}) public void userActivity(long, int, int);
field public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1; // 0x1
field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0
field public static final String REBOOT_USERSPACE = "userspace";
field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3
field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1
field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0

View File

@@ -20,6 +20,7 @@ import android.Manifest.permission;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
@@ -604,6 +605,13 @@ public final class PowerManager {
*/
public static final String REBOOT_SAFE_MODE = "safemode";
/**
* The 'reason' value used for rebooting userspace.
* @hide
*/
@SystemApi
public static final String REBOOT_USERSPACE = "userspace";
/**
* The 'reason' value used when rebooting the device without turning on the screen.
* @hide
@@ -1382,6 +1390,14 @@ public final class PowerManager {
}
}
/**
* Returns {@code true} if this device supports rebooting userspace.
*/
// TODO(b/138605180): add link to documentation once it's ready.
public boolean isRebootingUserspaceSupported() {
return SystemProperties.getBoolean("ro.init.userspace_reboot.is_supported", false);
}
/**
* Reboot the device. Will not return if the reboot is successful.
* <p>
@@ -1390,8 +1406,14 @@ public final class PowerManager {
*
* @param reason code to pass to the kernel (e.g., "recovery") to
* request special boot modes, or null.
* @throws UnsupportedOperationException if userspace reboot was requested on a device that
* doesn't support it.
*/
public void reboot(String reason) {
public void reboot(@Nullable String reason) {
if (REBOOT_USERSPACE.equals(reason) && !isRebootingUserspaceSupported()) {
throw new UnsupportedOperationException(
"Attempted userspace reboot on a device that doesn't support it");
}
try {
mService.reboot(false, reason, true);
} catch (RemoteException e) {

View File

@@ -239,4 +239,17 @@ public class PowerManagerTest extends AndroidTestCase {
verify(mListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
.times(1)).onThermalStatusChanged(status);
}
@Test
public void testUserspaceRebootNotSupported_throwsUnsupportedOperationException() {
// Can't use assumption framework with AndroidTestCase :(
if (mPm.isRebootingUserspaceSupported()) {
return;
}
try {
mPm.reboot(PowerManager.REBOOT_USERSPACE);
fail("UnsupportedOperationException not thrown");
} catch (UnsupportedOperationException expected) {
}
}
}