Add setting/experiment for small battery devices to have
all forced app standby enabled except for when the device is charging. Reverting the revert of this CL. The only change is to use EXTRA_PLUGGED instead of EXTRA_STATUS in detecting charging state. Verified that this passes CTS test for battery saver. Bug: 69259147 Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java Test: atest CtsBatterySavingTestCases Change-Id: I4f3ffc0c865a1a3a035b6d9d6838b5056b666eb9
This commit is contained in:
@@ -9895,6 +9895,15 @@ public final class Settings {
|
||||
*/
|
||||
public static final String FORCED_APP_STANDBY_ENABLED = "forced_app_standby_enabled";
|
||||
|
||||
/**
|
||||
* Whether or not to enable Forced App Standby on small battery devices.
|
||||
* Type: int (0 for false, 1 for true)
|
||||
* Default: 0
|
||||
* @hide
|
||||
*/
|
||||
public static final String FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED
|
||||
= "forced_app_standby_for_small_battery_enabled";
|
||||
|
||||
/**
|
||||
* Whether or not Network Watchlist feature is enabled.
|
||||
* Type: int (0 for false, 1 for true)
|
||||
|
||||
@@ -41,4 +41,13 @@ message ForceAppStandbyTrackerProto {
|
||||
|
||||
// Packages that are disallowed OP_RUN_ANY_IN_BACKGROUND.
|
||||
repeated RunAnyInBackgroundRestrictedPackages run_any_in_background_restricted_packages = 5;
|
||||
|
||||
// Whether device is a small battery device
|
||||
optional bool is_small_battery_device = 6;
|
||||
|
||||
// Whether force app standby for small battery device setting is enabled
|
||||
optional bool force_all_apps_standby_for_small_battery = 7;
|
||||
|
||||
// Whether device is charging
|
||||
optional bool is_charging = 8;
|
||||
}
|
||||
|
||||
@@ -213,6 +213,7 @@ public class SettingsBackupTest {
|
||||
Settings.Global.FANCY_IME_ANIMATIONS,
|
||||
Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
|
||||
Settings.Global.FORCED_APP_STANDBY_ENABLED,
|
||||
Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
|
||||
Settings.Global.FSTRIM_MANDATORY_INTERVAL,
|
||||
Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
|
||||
Settings.Global.GLOBAL_HTTP_PROXY_HOST,
|
||||
|
||||
@@ -26,6 +26,8 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
@@ -89,6 +91,9 @@ public class ForceAppStandbyTracker {
|
||||
|
||||
private final MyHandler mHandler;
|
||||
|
||||
@VisibleForTesting
|
||||
FeatureFlagsObserver mFlagsObserver;
|
||||
|
||||
/**
|
||||
* Pair of (uid (not user-id), packageName) with OP_RUN_ANY_IN_BACKGROUND *not* allowed.
|
||||
*/
|
||||
@@ -113,14 +118,36 @@ public class ForceAppStandbyTracker {
|
||||
@GuardedBy("mLock")
|
||||
boolean mStarted;
|
||||
|
||||
/**
|
||||
* Only used for small battery use-case.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
boolean mForceAllAppsStandby; // True if device is in extreme battery saver mode
|
||||
boolean mIsPluggedIn;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
boolean mForcedAppStandbyEnabled; // True if the forced app standby feature is enabled
|
||||
boolean mBatterySaverEnabled;
|
||||
|
||||
private class FeatureFlagObserver extends ContentObserver {
|
||||
FeatureFlagObserver() {
|
||||
/**
|
||||
* True if the forced app standby is currently enabled
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
boolean mForceAllAppsStandby;
|
||||
|
||||
/**
|
||||
* True if the forced app standby for small battery devices feature is enabled in settings
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
boolean mForceAllAppStandbyForSmallBattery;
|
||||
|
||||
/**
|
||||
* True if the forced app standby feature is enabled in settings
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
boolean mForcedAppStandbyEnabled;
|
||||
|
||||
@VisibleForTesting
|
||||
class FeatureFlagsObserver extends ContentObserver {
|
||||
FeatureFlagsObserver() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@@ -128,6 +155,9 @@ public class ForceAppStandbyTracker {
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED),
|
||||
false, this);
|
||||
|
||||
mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
|
||||
Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED), false, this);
|
||||
}
|
||||
|
||||
boolean isForcedAppStandbyEnabled() {
|
||||
@@ -135,20 +165,43 @@ public class ForceAppStandbyTracker {
|
||||
Settings.Global.FORCED_APP_STANDBY_ENABLED, 1) == 1;
|
||||
}
|
||||
|
||||
boolean isForcedAppStandbyForSmallBatteryEnabled() {
|
||||
return Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, 0) == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
final boolean enabled = isForcedAppStandbyEnabled();
|
||||
synchronized (mLock) {
|
||||
if (mForcedAppStandbyEnabled == enabled) {
|
||||
return;
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
if (Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED).equals(uri)) {
|
||||
final boolean enabled = isForcedAppStandbyEnabled();
|
||||
synchronized (mLock) {
|
||||
if (mForcedAppStandbyEnabled == enabled) {
|
||||
return;
|
||||
}
|
||||
mForcedAppStandbyEnabled = enabled;
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG,"Forced app standby feature flag changed: "
|
||||
+ mForcedAppStandbyEnabled);
|
||||
}
|
||||
}
|
||||
mForcedAppStandbyEnabled = enabled;
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG,
|
||||
"Forced app standby feature flag changed: " + mForcedAppStandbyEnabled);
|
||||
mHandler.notifyForcedAppStandbyFeatureFlagChanged();
|
||||
} else if (Settings.Global.getUriFor(
|
||||
Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED).equals(uri)) {
|
||||
final boolean enabled = isForcedAppStandbyForSmallBatteryEnabled();
|
||||
synchronized (mLock) {
|
||||
if (mForceAllAppStandbyForSmallBattery == enabled) {
|
||||
return;
|
||||
}
|
||||
mForceAllAppStandbyForSmallBattery = enabled;
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Forced app standby for small battery feature flag changed: "
|
||||
+ mForceAllAppStandbyForSmallBattery);
|
||||
}
|
||||
updateForceAllAppStandbyState();
|
||||
}
|
||||
} else {
|
||||
Slog.w(TAG, "Unexpected feature flag uri encountered: " + uri);
|
||||
}
|
||||
mHandler.notifyFeatureFlagChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,9 +342,11 @@ public class ForceAppStandbyTracker {
|
||||
mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
|
||||
mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
|
||||
mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
|
||||
final FeatureFlagObserver flagObserver = new FeatureFlagObserver();
|
||||
flagObserver.register();
|
||||
mForcedAppStandbyEnabled = flagObserver.isForcedAppStandbyEnabled();
|
||||
mFlagsObserver = new FeatureFlagsObserver();
|
||||
mFlagsObserver.register();
|
||||
mForcedAppStandbyEnabled = mFlagsObserver.isForcedAppStandbyEnabled();
|
||||
mForceAllAppStandbyForSmallBattery =
|
||||
mFlagsObserver.isForcedAppStandbyForSmallBatteryEnabled();
|
||||
|
||||
try {
|
||||
mIActivityManager.registerUidObserver(new UidObserver(),
|
||||
@@ -306,16 +361,24 @@ public class ForceAppStandbyTracker {
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_USER_REMOVED);
|
||||
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
||||
mContext.registerReceiver(new MyReceiver(), filter);
|
||||
|
||||
refreshForcedAppStandbyUidPackagesLocked();
|
||||
|
||||
mPowerManagerInternal.registerLowPowerModeObserver(
|
||||
ServiceType.FORCE_ALL_APPS_STANDBY,
|
||||
(state) -> updateForceAllAppsStandby(state.batterySaverEnabled));
|
||||
(state) -> {
|
||||
synchronized (mLock) {
|
||||
mBatterySaverEnabled = state.batterySaverEnabled;
|
||||
updateForceAllAppStandbyState();
|
||||
}
|
||||
});
|
||||
|
||||
updateForceAllAppsStandby(mPowerManagerInternal.getLowPowerState(
|
||||
ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled);
|
||||
mBatterySaverEnabled = mPowerManagerInternal.getLowPowerState(
|
||||
ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled;
|
||||
|
||||
updateForceAllAppStandbyState();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,6 +403,11 @@ public class ForceAppStandbyTracker {
|
||||
return LocalServices.getService(PowerManagerInternal.class);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean isSmallBatteryDevice() {
|
||||
return ActivityManager.isSmallBatteryDevice();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update {@link #mRunAnyRestrictedPackages} with the current app ops state.
|
||||
*/
|
||||
@@ -369,18 +437,26 @@ public class ForceAppStandbyTracker {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateForceAllAppStandbyState() {
|
||||
synchronized (mLock) {
|
||||
if (mForceAllAppStandbyForSmallBattery && isSmallBatteryDevice()) {
|
||||
toggleForceAllAppsStandbyLocked(!mIsPluggedIn);
|
||||
} else {
|
||||
toggleForceAllAppsStandbyLocked(mBatterySaverEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update {@link #mForceAllAppsStandby} and notifies the listeners.
|
||||
*/
|
||||
void updateForceAllAppsStandby(boolean enable) {
|
||||
synchronized (mLock) {
|
||||
if (enable == mForceAllAppsStandby) {
|
||||
return;
|
||||
}
|
||||
mForceAllAppsStandby = enable;
|
||||
|
||||
mHandler.notifyForceAllAppsStandbyChanged();
|
||||
private void toggleForceAllAppsStandbyLocked(boolean enable) {
|
||||
if (enable == mForceAllAppsStandby) {
|
||||
return;
|
||||
}
|
||||
mForceAllAppsStandby = enable;
|
||||
|
||||
mHandler.notifyForceAllAppsStandbyChanged();
|
||||
}
|
||||
|
||||
private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) {
|
||||
@@ -515,6 +591,11 @@ public class ForceAppStandbyTracker {
|
||||
if (userId > 0) {
|
||||
mHandler.doUserRemoved(userId);
|
||||
}
|
||||
} else if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
|
||||
synchronized (mLock) {
|
||||
mIsPluggedIn = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0);
|
||||
}
|
||||
updateForceAllAppStandbyState();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -533,7 +614,7 @@ public class ForceAppStandbyTracker {
|
||||
private static final int MSG_TEMP_WHITELIST_CHANGED = 5;
|
||||
private static final int MSG_FORCE_ALL_CHANGED = 6;
|
||||
private static final int MSG_USER_REMOVED = 7;
|
||||
private static final int MSG_FEATURE_FLAG_CHANGED = 8;
|
||||
private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;
|
||||
|
||||
public MyHandler(Looper looper) {
|
||||
super(looper);
|
||||
@@ -563,8 +644,8 @@ public class ForceAppStandbyTracker {
|
||||
obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
|
||||
}
|
||||
|
||||
public void notifyFeatureFlagChanged() {
|
||||
obtainMessage(MSG_FEATURE_FLAG_CHANGED).sendToTarget();
|
||||
public void notifyForcedAppStandbyFeatureFlagChanged() {
|
||||
obtainMessage(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED).sendToTarget();
|
||||
}
|
||||
|
||||
public void doUserRemoved(int userId) {
|
||||
@@ -618,7 +699,7 @@ public class ForceAppStandbyTracker {
|
||||
l.onForceAllAppsStandbyChanged(sender);
|
||||
}
|
||||
return;
|
||||
case MSG_FEATURE_FLAG_CHANGED:
|
||||
case MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED:
|
||||
// Feature flag for forced app standby changed.
|
||||
final boolean unblockAlarms;
|
||||
synchronized (mLock) {
|
||||
@@ -841,6 +922,18 @@ public class ForceAppStandbyTracker {
|
||||
pw.print("Force all apps standby: ");
|
||||
pw.println(isForceAllAppsStandbyEnabled());
|
||||
|
||||
pw.print(indent);
|
||||
pw.print("Small Battery Device: ");
|
||||
pw.println(isSmallBatteryDevice());
|
||||
|
||||
pw.print(indent);
|
||||
pw.print("Force all apps standby for small battery device: ");
|
||||
pw.println(mForceAllAppStandbyForSmallBattery);
|
||||
|
||||
pw.print(indent);
|
||||
pw.print("Plugged In: ");
|
||||
pw.println(mIsPluggedIn);
|
||||
|
||||
pw.print(indent);
|
||||
pw.print("Foreground uids: [");
|
||||
|
||||
@@ -880,6 +973,11 @@ public class ForceAppStandbyTracker {
|
||||
final long token = proto.start(fieldId);
|
||||
|
||||
proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY, mForceAllAppsStandby);
|
||||
proto.write(ForceAppStandbyTrackerProto.IS_SMALL_BATTERY_DEVICE,
|
||||
isSmallBatteryDevice());
|
||||
proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY_FOR_SMALL_BATTERY,
|
||||
mForceAllAppStandbyForSmallBattery);
|
||||
proto.write(ForceAppStandbyTrackerProto.IS_CHARGING, mIsPluggedIn);
|
||||
|
||||
for (int i = 0; i < mForegroundUids.size(); i++) {
|
||||
if (mForegroundUids.valueAt(i)) {
|
||||
|
||||
@@ -42,6 +42,7 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager.ServiceType;
|
||||
@@ -51,6 +52,7 @@ import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.Global;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.test.mock.MockContentResolver;
|
||||
@@ -105,6 +107,9 @@ public class ForceAppStandbyTrackerTest {
|
||||
PowerManagerInternal injectPowerManagerInternal() {
|
||||
return mMockPowerManagerInternal;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isSmallBatteryDevice() { return mIsSmallBatteryDevice; };
|
||||
}
|
||||
|
||||
private static final int UID_1 = Process.FIRST_APPLICATION_UID + 1;
|
||||
@@ -144,6 +149,7 @@ public class ForceAppStandbyTrackerTest {
|
||||
private FakeSettingsProvider mFakeSettingsProvider;
|
||||
|
||||
private boolean mPowerSaveMode;
|
||||
private boolean mIsSmallBatteryDevice;
|
||||
|
||||
private final ArraySet<Pair<Integer, String>> mRestrictedPackages = new ArraySet();
|
||||
|
||||
@@ -232,6 +238,7 @@ public class ForceAppStandbyTrackerTest {
|
||||
assertNotNull(mAppOpsCallback);
|
||||
assertNotNull(mPowerSaveObserver);
|
||||
assertNotNull(mReceiver);
|
||||
assertNotNull(instance.mFlagsObserver);
|
||||
}
|
||||
|
||||
private void setAppOps(int uid, String packageName, boolean restrict) throws RemoteException {
|
||||
@@ -852,6 +859,56 @@ public class ForceAppStandbyTrackerTest {
|
||||
assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSmallBatteryAndPluggedIn() throws Exception {
|
||||
// This is a small battery device
|
||||
mIsSmallBatteryDevice = true;
|
||||
|
||||
final ForceAppStandbyTrackerTestable instance = newInstance();
|
||||
callStart(instance);
|
||||
assertFalse(instance.isForceAllAppsStandbyEnabled());
|
||||
|
||||
// Setting/experiment for all app standby for small battery is enabled
|
||||
Global.putInt(mMockContentResolver, Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, 1);
|
||||
instance.mFlagsObserver.onChange(true,
|
||||
Global.getUriFor(Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED));
|
||||
assertTrue(instance.isForceAllAppsStandbyEnabled());
|
||||
|
||||
// When battery is plugged in, force app standby is disabled
|
||||
Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
|
||||
intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_USB);
|
||||
mReceiver.onReceive(mMockContext, intent);
|
||||
assertFalse(instance.isForceAllAppsStandbyEnabled());
|
||||
|
||||
// When battery stops plugged in, force app standby is enabled
|
||||
mReceiver.onReceive(mMockContext, new Intent(Intent.ACTION_BATTERY_CHANGED));
|
||||
assertTrue(instance.isForceAllAppsStandbyEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotSmallBatteryAndPluggedIn() throws Exception {
|
||||
// Not a small battery device, so plugged in status should not affect forced app standby
|
||||
mIsSmallBatteryDevice = false;
|
||||
|
||||
final ForceAppStandbyTrackerTestable instance = newInstance();
|
||||
callStart(instance);
|
||||
assertFalse(instance.isForceAllAppsStandbyEnabled());
|
||||
|
||||
mPowerSaveMode = true;
|
||||
mPowerSaveObserver.accept(getPowerSaveState());
|
||||
assertTrue(instance.isForceAllAppsStandbyEnabled());
|
||||
|
||||
// When battery is plugged in, force app standby is unaffected
|
||||
Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
|
||||
intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_USB);
|
||||
mReceiver.onReceive(mMockContext, intent);
|
||||
assertTrue(instance.isForceAllAppsStandbyEnabled());
|
||||
|
||||
// When battery stops plugged in, force app standby is unaffected
|
||||
mReceiver.onReceive(mMockContext, new Intent(Intent.ACTION_BATTERY_CHANGED));
|
||||
assertTrue(instance.isForceAllAppsStandbyEnabled());
|
||||
}
|
||||
|
||||
static int[] array(int... appIds) {
|
||||
Arrays.sort(appIds);
|
||||
return appIds;
|
||||
|
||||
Reference in New Issue
Block a user