Create APIs to interact with DynamicPowerSaver
This creates the PowerManager APIs that allow apps with the
appropriate permissions to interact with Dynamic Power Saver.
Bug: 111450127
Test: WIP
Change-Id: I5b9483fa0fba81a4ade622b1f3dbaec580b68a67
diff --git a/api/system-current.txt b/api/system-current.txt
index e0c58b4..93a9f52 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4109,8 +4109,12 @@
}
public final class PowerManager {
+ method public int getPowerSaveMode();
+ method public boolean setDynamicPowerSavings(boolean, int);
method public boolean setPowerSaveMode(boolean);
method public void userActivity(long, int, int);
+ field public static final int POWER_SAVER_MODE_DYNAMIC = 1; // 0x1
+ field public static final int POWER_SAVER_MODE_PERCENTAGE = 0; // 0x0
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
diff --git a/api/test-current.txt b/api/test-current.txt
index 6213b17..a66c209 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -744,7 +744,11 @@
}
public final class PowerManager {
+ method public int getPowerSaveMode();
+ method public boolean setDynamicPowerSavings(boolean, int);
method public boolean setPowerSaveMode(boolean);
+ field public static final int POWER_SAVER_MODE_DYNAMIC = 1; // 0x1
+ field public static final int POWER_SAVER_MODE_PERCENTAGE = 0; // 0x0
}
public class Process {
@@ -981,6 +985,9 @@
public static final class Settings.Global extends android.provider.Settings.NameValueTable {
field public static final java.lang.String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
+ field public static final java.lang.String AUTOMATIC_POWER_SAVER_MODE = "automatic_power_saver_mode";
+ field public static final java.lang.String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold";
+ field public static final java.lang.String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled";
field public static final java.lang.String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
field public static final java.lang.String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
field public static final java.lang.String LOW_POWER_MODE = "low_power";
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 7ceeb52..ca5b233 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -48,6 +48,8 @@
boolean isPowerSaveMode();
PowerSaveState getPowerSaveState(int serviceType);
boolean setPowerSaveMode(boolean mode);
+ boolean setDynamicPowerSavings(boolean dynamicPowerSavingsEnabled, int disableThreshold);
+ int getPowerSaveMode();
boolean isDeviceIdleMode();
boolean isLightDeviceIdleMode();
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 27c281d..a307cd8 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -16,6 +16,7 @@
package android.os;
+import android.Manifest.permission;
import android.annotation.IntDef;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
@@ -1185,6 +1186,105 @@
}
/**
+ * Updates the current state of dynamic power savings and disable threshold. This is
+ * a signal to the system which an app can update to serve as an indicator that
+ * the user will be in a battery critical situation before being able to plug in.
+ * Only apps with the {@link android.Manifest.permission#POWER_SAVER} permission may do this.
+ * This is a device global state, not a per user setting.
+ *
+ * <p>When enabled, the system may enact various measures for reducing power consumption in
+ * order to help ensure that the user will make it to their next charging point. The most
+ * visible of these will be the automatic enabling of battery saver if the user has set
+ * their battery saver mode to "automatic". Note
+ * that this is NOT simply an on/off switch for features, but rather a hint for the
+ * system to consider enacting these power saving features, some of which have additional
+ * logic around when to activate based on this signal.
+ *
+ * <p>The provided threshold is the percentage the system should consider itself safe at given
+ * the current state of the device. The value is an integer representing a battery level.
+ *
+ * <p>The threshold is meant to set an explicit stopping point for dynamic power savings
+ * functionality so that the dynamic power savings itself remains a signal rather than becoming
+ * an on/off switch for a subset of features.
+ * @hide
+ *
+ * @param dynamicPowerSavingsEnabled A signal indicating to the system if it believes the
+ * dynamic power savings behaviors should be activated.
+ * @param disableThreshold When the suggesting app believes it would be safe to disable dynamic
+ * power savings behaviors.
+ * @return True if the update was allowed and succeeded.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(permission.POWER_SAVER)
+ public boolean setDynamicPowerSavings(boolean dynamicPowerSavingsEnabled,
+ int disableThreshold) {
+ try {
+ return mService.setDynamicPowerSavings(dynamicPowerSavingsEnabled, disableThreshold);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Indicates automatic battery saver toggling by the system will be based on percentage.
+ *
+ * @see PowerManager#getPowerSaveMode()
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final int POWER_SAVER_MODE_PERCENTAGE = 0;
+
+ /**
+ * Indicates automatic battery saver toggling by the system will be based on the state
+ * of the dynamic power savings signal.
+ *
+ * @see PowerManager#setDynamicPowerSavings(boolean, int)
+ * @see PowerManager#getPowerSaveMode()
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final int POWER_SAVER_MODE_DYNAMIC = 1;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ POWER_SAVER_MODE_PERCENTAGE,
+ POWER_SAVER_MODE_DYNAMIC
+
+ })
+ public @interface AutoPowerSaverMode{}
+
+
+ /**
+ * Returns the current battery saver control mode. Values it may return are defined in
+ * AutoPowerSaverMode. Note that this is a global device state, not a per user setting.
+ *
+ * @return The current value power saver mode for the system.
+ *
+ * @see AutoPowerSaverMode
+ * @see PowerManager#getPowerSaveMode()
+ * @hide
+ */
+ @AutoPowerSaverMode
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.POWER_SAVER)
+ public int getPowerSaveMode() {
+ try {
+ return mService.getPowerSaveMode();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Get data about the battery saver mode for a specific service
* @param serviceType unique key for the service, one of {@link ServiceType}
* @return Battery saver state data.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4b3fbe6..0402222 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11813,9 +11813,10 @@
* Battery level [1-100] at which low power mode automatically turns on.
* Pre-Q If 0, it will not automatically turn on. Q and newer it will only automatically
* turn on if the {@link #AUTOMATIC_POWER_SAVER_MODE} setting is also set to
- * {@link #AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE}.
+ * {@link android.os.PowerManager.AutoPowerSaverMode#POWER_SAVER_MODE_PERCENTAGE}.
*
* @see #AUTOMATIC_POWER_SAVER_MODE
+ * @see android.os.PowerManager#getPowerSaveMode()
* @hide
*/
public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
@@ -11825,78 +11826,38 @@
new SettingsValidators.InclusiveIntegerRangeValidator(0, 100);
/**
- * Indicates automatic battery saver toggling by the system will be based on battery level.
- *
- * @hide
- */
- public static final int AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE = 0;
-
- /**
- * Indicates automatic battery saver toggling by the system will be based on
- * {@link #DYNAMIC_POWER_SAVINGS_ENABLED} and
- * {@link #DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD}.
- *
- * @see #DYNAMIC_POWER_SAVINGS_ENABLED
- *
- * @hide
- */
- public static final int AUTOMATIC_POWER_SAVER_MODE_DYNAMIC = 1;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE,
- AUTOMATIC_POWER_SAVER_MODE_DYNAMIC
-
- })
- public @interface AutoPowerSaverMode{}
-
- /**
* Whether battery saver is currently set to trigger based on percentage, dynamic power
- * savings trigger, or none. See {@link AutoPowerSaverMode} for accepted values.
+ * savings trigger, or none. See {@link android.os.PowerManager.AutoPowerSaverMode} for
+ * accepted values.
*
* @hide
*/
+ @TestApi
public static final String AUTOMATIC_POWER_SAVER_MODE = "automatic_power_saver_mode";
private static final Validator AUTOMATIC_POWER_SAVER_MODE_VALIDATOR =
new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1"});
/**
- * The percentage the system should consider itself safe at if the dynamic power savings was
- * previously enabled and it enacted measures to reduce power consumption. Value is
- * an integer representing a battery level.
+ * The setting that backs the disable threshold for the setPowerSavingsWarning api in
+ * PowerManager
*
- * <p>This value is used to set an explicit stopping point for dynamic power savings
- * functionality so that the {@link #DYNAMIC_POWER_SAVINGS_ENABLED} setting remains a signal
- * for the system rather than becoming an on/off switch itself.
+ * @see android.os.PowerManager#setDynamicPowerSavings(boolean, int)
* @hide
*/
+ @TestApi
public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD =
"dynamic_power_savings_disable_threshold";
+ private static final Validator DYNAMIC_POWER_SAVINGS_VALIDATOR =
+ new SettingsValidators.InclusiveIntegerRangeValidator(0, 100);
/**
- * A signal to the system which an app can update which indicates that
- * the user will be in a battery critical situation in the near future.
- * Only apps with the {@link android.Manifest.permission.POWER_SAVER} permission may modify
- * this setting.
+ * The setting which backs the setDynamicPowerSavings api in PowerManager.
*
- * <p>When enabled, the system may enact various measures for reducing power consumption in
- * order to help ensure that the user will make it to their next charging point. The most
- * visible of these will be the automatic enabling of battery saver if the user has set
- * {@link #AUTOMATIC_POWER_SAVER_MODE} to {@link #AUTOMATIC_POWER_SAVER_MODE_DYNAMIC}. Note
- * that this is NOT an on/off switch for all these features, but rather a hint for the
- * system to consider enacting these power saving features, some of which have additional
- * logic around when to activate based on this signal.
- *
- * <p>Supported values:
- * <ul>
- * <li>0 = Disabled
- * <li>1 = Enabled
- * </ul>
- * @see #DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD
+ * @see android.os.PowerManager#setDynamicPowerSavings(boolean, int)
* @hide
*/
+ @TestApi
public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled";
/**
@@ -12822,6 +12783,8 @@
VALIDATORS.put(LOW_POWER_MODE_TRIGGER_LEVEL_MAX,
LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR);
VALIDATORS.put(AUTOMATIC_POWER_SAVER_MODE, AUTOMATIC_POWER_SAVER_MODE_VALIDATOR);
+ VALIDATORS.put(DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
+ DYNAMIC_POWER_SAVINGS_VALIDATOR);
VALIDATORS.put(BLUETOOTH_ON, BLUETOOTH_ON_VALIDATOR);
VALIDATORS.put(PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_VALIDATOR);
VALIDATORS.put(PRIVATE_DNS_SPECIFIER, PRIVATE_DNS_SPECIFIER_VALIDATOR);
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index a1fbe0a..c7945bd02 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -324,6 +324,7 @@
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<permission name="android.permission.MOVE_PACKAGE"/>
<permission name="android.permission.PACKAGE_USAGE_STATS" />
+ <permission name="android.permission.POWER_SAVER" />
<permission name="android.permission.READ_FRAME_BUFFER"/>
<permission name="android.permission.READ_LOWPAN_CREDENTIAL"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 822c39b..89690fb 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -83,6 +83,7 @@
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
+ <uses-permission android:name="android.permission.POWER_SAVER" />
<uses-permission android:name="android.permission.INSTALL_LOCATION_PROVIDER" />
<uses-permission android:name="android.permission.BACKUP" />
<uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 43a9c78..29d6237 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -4439,6 +4439,42 @@
}
@Override // Binder call
+ public boolean setDynamicPowerSavings(boolean dynamicPowerSavingsEnabled,
+ int disableThreshold) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER,
+ "updateDynamicPowerSavings");
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ final ContentResolver resolver = mContext.getContentResolver();
+ boolean success = Settings.Global.putInt(resolver,
+ Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
+ disableThreshold);
+ if (success) {
+ // abort updating if we weren't able to succeed on the threshold
+ success &= Settings.Global.putInt(resolver,
+ Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED,
+ dynamicPowerSavingsEnabled ? 1 : 0);
+ }
+ return success;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public int getPowerSaveMode() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER, null);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
public boolean isDeviceIdleMode() {
final long ident = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index 6acaf0e..f262f6d 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
+import android.os.PowerManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
@@ -241,7 +242,7 @@
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
final int automaticBatterySaver = getGlobalSetting(
Global.AUTOMATIC_POWER_SAVER_MODE,
- Settings.Global.AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE);
+ PowerManager.POWER_SAVER_MODE_PERCENTAGE);
final int dynamicPowerSavingsDisableThreshold = getGlobalSetting(
Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
mDynamicPowerSavingsDefaultDisableThreshold);
@@ -343,6 +344,17 @@
}
}
+ @GuardedBy("mLock")
+ private boolean isBatteryLowLocked() {
+ final boolean percentageLow =
+ mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_PERCENTAGE
+ && mIsBatteryLevelLow;
+ final boolean dynamicPowerSavingsLow =
+ mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_DYNAMIC
+ && mBatteryLevel <= mDynamicPowerSavingsDisableThreshold;
+ return percentageLow || dynamicPowerSavingsLow;
+ }
+
/**
* Decide whether to auto-start / stop battery saver.
*/
@@ -361,14 +373,8 @@
if (!(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
return; // Not fully initialized yet.
}
- final boolean percetageLow =
- mSettingAutomaticBatterySaver
- == Settings.Global.AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE
- && mIsBatteryLevelLow;
- final boolean dynamicPowerSavingsLow =
- mSettingAutomaticBatterySaver == Settings.Global.AUTOMATIC_POWER_SAVER_MODE_DYNAMIC
- && mBatteryLevel <= mDynamicPowerSavingsDisableThreshold;
- if (!percetageLow && !dynamicPowerSavingsLow) {
+
+ if (!isBatteryLowLocked()) {
updateSnoozingLocked(false, "Battery not low");
}
if (mIsPowered) {
@@ -384,7 +390,7 @@
"Sticky restore");
} else if (mSettingAutomaticBatterySaver
- == Settings.Global.AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE
+ == PowerManager.POWER_SAVER_MODE_PERCENTAGE
&& isAutoBatterySaverConfiguredLocked()) {
if (mIsBatteryLevelLow && !mBatterySaverSnoozing) {
enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false,
@@ -397,21 +403,21 @@
"Percentage Auto OFF");
}
} else if (mSettingAutomaticBatterySaver
- == Settings.Global.AUTOMATIC_POWER_SAVER_MODE_DYNAMIC) {
+ == PowerManager.POWER_SAVER_MODE_DYNAMIC) {
if (mBatteryLevel >= mDynamicPowerSavingsDisableThreshold) {
enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF,
- "Dynamic Power Savings Auto OFF");
+ "Dynamic Warning Auto OFF");
} else if (mDynamicPowerSavingsBatterySaver && !mBatterySaverSnoozing) {
enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false,
BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON,
- "Dynamic Power Savings Auto ON");
+ "Dynamic Warning Auto ON");
}
}
// do nothing if automatic battery saver mode = PERCENTAGE and low warning threshold = 0%
}
- /**
+ /**
* {@link com.android.server.power.PowerManagerService} calls it when
* {@link android.os.PowerManager#setPowerSaveMode} is called.
*
@@ -462,15 +468,7 @@
// When battery saver is disabled manually (while battery saver is enabled)
// when the battery level is low, we "snooze" BS -- i.e. disable auto battery saver.
// We resume auto-BS once the battery level is not low, or the device is plugged in.
- final boolean percetageLow =
- mSettingAutomaticBatterySaver
- == Settings.Global.AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE
- && mIsBatteryLevelLow;
- final boolean dynamicPowerSavingsLow =
- mSettingAutomaticBatterySaver
- == Settings.Global.AUTOMATIC_POWER_SAVER_MODE_DYNAMIC
- && mBatteryLevel <= mDynamicPowerSavingsDisableThreshold;
- if (isBatterySaverEnabled() && (percetageLow || dynamicPowerSavingsLow)) {
+ if (isBatterySaverEnabled() && isBatteryLowLocked()) {
updateSnoozingLocked(true, "Manual snooze");
}
}