From 3d33a89375dbfc66bc5bf52ce4f289f676658470 Mon Sep 17 00:00:00 2001 From: Jing Ji Date: Sat, 26 Mar 2022 01:03:31 -0700 Subject: [PATCH] Decouple the thresholds of the background restrictions Previously, to reach the threshold of the bg restricted level, it has to reach the threshold of the restricted bucket level before that. However we're using different dimensions of battery usage when comparing to these thresholds. So it'll make more sense to decouple them. Bug: 203105544 Test: atest FrameworksMockingServicesTests:BackgroundRestrictionTest Change-Id: Idee31d6615cbbee0bac2abe232589346d838a9ba --- .../android/server/am/AppBatteryTracker.java | 120 ++++++++++++----- .../server/am/AppRestrictionController.java | 28 ++-- .../android/server/am/BaseAppStatePolicy.java | 6 +- .../am/BaseAppStateTimeSlotEventsTracker.java | 13 +- .../server/am/BackgroundRestrictionTest.java | 121 ++++++++++++++++++ 5 files changed, 241 insertions(+), 47 deletions(-) diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java index 690051f47326f..0cbc7ad404f57 100644 --- a/services/core/java/com/android/server/am/AppBatteryTracker.java +++ b/services/core/java/com/android/server/am/AppBatteryTracker.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION; import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET; import static android.app.ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED; import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET; +import static android.app.ActivityManager.RESTRICTION_LEVEL_UNKNOWN; import static android.app.ActivityManager.isLowRamDeviceStatic; import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM; import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE; @@ -1118,6 +1119,13 @@ final class AppBatteryTracker extends BaseAppStateTracker static final String KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION = DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_high_threshold_by_bg_location"; + /** + * Whether or not the battery usage of the offending app should fulfill the 1st threshold + * before taking actions for the 2nd threshold. + */ + static final String KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS = + DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_decouple_thresholds"; + /** * Default value to the {@link #INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD} of * the {@link #mBgCurrentDrainRestrictedBucketThreshold}. @@ -1190,6 +1198,11 @@ final class AppBatteryTracker extends BaseAppStateTracker */ final boolean mDefaultBgCurrentDrainHighThresholdByBgLocation; + /** + * Default value to {@link #mBgCurrentDrainDecoupleThresholds}. + */ + static final boolean DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD = true; + /** * The index to {@link #mBgCurrentDrainRestrictedBucketThreshold} * and {@link #mBgCurrentDrainBgRestrictedThreshold}. @@ -1257,6 +1270,11 @@ final class AppBatteryTracker extends BaseAppStateTracker */ volatile boolean mBgCurrentDrainHighThresholdByBgLocation; + /** + * @see #KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS. + */ + volatile boolean mBgCurrentDrainDecoupleThresholds; + /** * The capacity of the battery when fully charged in mAh. */ @@ -1369,6 +1387,9 @@ final class AppBatteryTracker extends BaseAppStateTracker case KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES: updateCurrentDrainExemptedTypes(); break; + case KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS: + updateCurrentDrainDecoupleThresholds(); + break; default: super.onPropertiesChanged(name); break; @@ -1466,6 +1487,13 @@ final class AppBatteryTracker extends BaseAppStateTracker mDefaultBgCurrentDrainExemptedTypes); } + private void updateCurrentDrainDecoupleThresholds() { + mBgCurrentDrainDecoupleThresholds = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS, + DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD); + } + @Override public void onSystemReady() { mBatteryFullChargeMah = @@ -1477,20 +1505,30 @@ final class AppBatteryTracker extends BaseAppStateTracker updateCurrentDrainLocationMinDuration(); updateCurrentDrainEventDurationBasedThresholdEnabled(); updateCurrentDrainExemptedTypes(); + updateCurrentDrainDecoupleThresholds(); } @Override - public @RestrictionLevel int getProposedRestrictionLevel(String packageName, int uid) { + @RestrictionLevel + public int getProposedRestrictionLevel(String packageName, int uid, + @RestrictionLevel int maxLevel) { + if (maxLevel <= RESTRICTION_LEVEL_ADAPTIVE_BUCKET) { + return RESTRICTION_LEVEL_UNKNOWN; + } synchronized (mLock) { - final int index = mHighBgBatteryPackages.indexOfKey(uid); - if (index < 0) { - // Not found, return adaptive as the default one. - return RESTRICTION_LEVEL_ADAPTIVE_BUCKET; + final long[] ts = mHighBgBatteryPackages.get(uid); + if (ts != null) { + final int restrictedLevel = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] > 0 + ? RESTRICTION_LEVEL_RESTRICTED_BUCKET + : RESTRICTION_LEVEL_ADAPTIVE_BUCKET; + if (maxLevel > RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) { + return ts[TIME_STAMP_INDEX_BG_RESTRICTED] > 0 + ? RESTRICTION_LEVEL_BACKGROUND_RESTRICTED : restrictedLevel; + } else if (maxLevel == RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) { + return restrictedLevel; + } } - final long[] ts = mHighBgBatteryPackages.valueAt(index); - return ts[TIME_STAMP_INDEX_BG_RESTRICTED] > 0 - ? RESTRICTION_LEVEL_BACKGROUND_RESTRICTED - : RESTRICTION_LEVEL_RESTRICTED_BUCKET; + return RESTRICTION_LEVEL_ADAPTIVE_BUCKET; } } @@ -1573,36 +1611,58 @@ final class AppBatteryTracker extends BaseAppStateTracker final int thresholdIndex = getCurrentDrainThresholdIndex(uid, now, mBgCurrentDrainWindowMs); final int index = mHighBgBatteryPackages.indexOfKey(uid); + final boolean decoupleThresholds = mBgCurrentDrainDecoupleThresholds; + final double rbThreshold = mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex]; + final double brThreshold = mBgCurrentDrainBgRestrictedThreshold[thresholdIndex]; if (index < 0) { - if (rbPercentage >= mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex]) { + long[] ts = null; + if (rbPercentage >= rbThreshold) { // New findings to us, track it and let the controller know. - final long[] ts = new long[TIME_STAMP_INDEX_LAST]; + ts = new long[TIME_STAMP_INDEX_LAST]; ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now; mHighBgBatteryPackages.put(uid, ts); notifyController = excessive = true; } + if (decoupleThresholds && brPercentage >= brThreshold) { + if (ts == null) { + ts = new long[TIME_STAMP_INDEX_LAST]; + mHighBgBatteryPackages.put(uid, ts); + } + ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now; + notifyController = excessive = true; + } } else { final long[] ts = mHighBgBatteryPackages.valueAt(index); - if (rbPercentage < mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex]) { - // it's actually back to normal, but we don't untrack it until - // explicit user interactions. - notifyController = true; - } else { - excessive = true; - if (brPercentage >= mBgCurrentDrainBgRestrictedThreshold[thresholdIndex] - && curLevel == RESTRICTION_LEVEL_RESTRICTED_BUCKET) { - // If we're in the restricted standby bucket but still seeing high - // current drains, tell the controller again. - final long lastResbucket = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET]; - final long lastBgRes = ts[TIME_STAMP_INDEX_BG_RESTRICTED]; - // If it has been a while since restricting the app and since the last - // time we notify the controller, notify it again. - if ((now >= lastResbucket + mBgCurrentDrainWindowMs) && (lastBgRes == 0 - || (now >= lastBgRes + mBgCurrentDrainWindowMs))) { - ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now; - notifyController = true; - } + final long lastRestrictBucketTs = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET]; + if (rbPercentage >= rbThreshold) { + if (lastRestrictBucketTs == 0) { + ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now; } + notifyController = excessive = true; + } else { + // It's actually back to normal, but we don't untrack it until + // explicit user interactions, because the restriction could be the cause + // of going back to normal. + } + if (brPercentage >= brThreshold) { + // If either + // a) It's configured to goto threshold 2 directly without threshold 1; + // b) It's already in the restricted standby bucket, but still seeing + // high current drains, and it's been a while since it's restricted; + // tell the controller. + notifyController = decoupleThresholds + || (curLevel == RESTRICTION_LEVEL_RESTRICTED_BUCKET + && (now > lastRestrictBucketTs + mBgCurrentDrainWindowMs)); + if (notifyController) { + ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now; + } + excessive = true; + } else { + // Reset the track now - if it's already background restricted, it requires + // user consent to unrestrict it; or if it's in restricted bucket level, + // resetting this won't lift it from that level. + ts[TIME_STAMP_INDEX_BG_RESTRICTED] = 0; + // Now need to notify the controller. } } } diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java index b8fb9e85ac08b..eb2d0a1f2f3f9 100644 --- a/services/core/java/com/android/server/am/AppRestrictionController.java +++ b/services/core/java/com/android/server/am/AppRestrictionController.java @@ -24,6 +24,7 @@ import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET; import static android.app.ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED; import static android.app.ActivityManager.RESTRICTION_LEVEL_EXEMPTED; import static android.app.ActivityManager.RESTRICTION_LEVEL_HIBERNATION; +import static android.app.ActivityManager.RESTRICTION_LEVEL_MAX; import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET; import static android.app.ActivityManager.RESTRICTION_LEVEL_UNKNOWN; import static android.app.ActivityManager.UID_OBSERVER_ACTIVE; @@ -1148,7 +1149,8 @@ public final class AppRestrictionController { ? RESTRICTION_LEVEL_RESTRICTED_BUCKET : RESTRICTION_LEVEL_ADAPTIVE_BUCKET; if (calcTrackers) { - @RestrictionLevel int l = calcAppRestrictionLevelFromTackers(uid, packageName); + @RestrictionLevel int l = calcAppRestrictionLevelFromTackers(uid, packageName, + RESTRICTION_LEVEL_MAX); if (l == RESTRICTION_LEVEL_EXEMPTED) { return RESTRICTION_LEVEL_EXEMPTED; } @@ -1160,7 +1162,8 @@ public final class AppRestrictionController { uid, 0, packageName).sendToTarget(); } // Lower the level. - level = RESTRICTION_LEVEL_RESTRICTED_BUCKET; + level = calcAppRestrictionLevelFromTackers(uid, packageName, + RESTRICTION_LEVEL_BACKGROUND_RESTRICTED); } } break; @@ -1177,12 +1180,13 @@ public final class AppRestrictionController { * monitors certain dimensions of the app, the abusive behaviors could be detected in one or * more of these dimensions, but not necessarily all of them.

*/ - private @RestrictionLevel int calcAppRestrictionLevelFromTackers(int uid, String packageName) { + private @RestrictionLevel int calcAppRestrictionLevelFromTackers(int uid, String packageName, + @RestrictionLevel int maxLevel) { @RestrictionLevel int level = RESTRICTION_LEVEL_UNKNOWN; final boolean isRestrictedBucketEnabled = mConstantsObserver.mRestrictedBucketEnabled; for (int i = mAppStateTrackers.size() - 1; i >= 0; i--) { @RestrictionLevel int l = mAppStateTrackers.get(i).getPolicy() - .getProposedRestrictionLevel(packageName, uid); + .getProposedRestrictionLevel(packageName, uid, maxLevel); if (!isRestrictedBucketEnabled && l == RESTRICTION_LEVEL_RESTRICTED_BUCKET) { l = RESTRICTION_LEVEL_ADAPTIVE_BUCKET; } @@ -1471,17 +1475,15 @@ public final class AppRestrictionController { } else if (curLevel >= RESTRICTION_LEVEL_RESTRICTED_BUCKET && level < RESTRICTION_LEVEL_RESTRICTED_BUCKET) { // Moved out of the background-restricted state. - if (curBucket != STANDBY_BUCKET_RARE) { - synchronized (mSettingsLock) { - final int index = mActiveUids.indexOfKey(uid, pkgName); - if (index >= 0) { - mActiveUids.add(uid, pkgName, null); - } + synchronized (mSettingsLock) { + final int index = mActiveUids.indexOfKey(uid, pkgName); + if (index >= 0) { + mActiveUids.add(uid, pkgName, null); } - appStandbyInternal.maybeUnrestrictApp(pkgName, UserHandle.getUserId(uid), - prevReason & REASON_MAIN_MASK, prevReason & REASON_SUB_MASK, - reason, subReason); } + appStandbyInternal.maybeUnrestrictApp(pkgName, UserHandle.getUserId(uid), + prevReason & REASON_MAIN_MASK, prevReason & REASON_SUB_MASK, + reason, subReason); } } diff --git a/services/core/java/com/android/server/am/BaseAppStatePolicy.java b/services/core/java/com/android/server/am/BaseAppStatePolicy.java index 67318a7639079..a55344caea9aa 100644 --- a/services/core/java/com/android/server/am/BaseAppStatePolicy.java +++ b/services/core/java/com/android/server/am/BaseAppStatePolicy.java @@ -87,9 +87,11 @@ public abstract class BaseAppStatePolicy { } /** - * @return The proposed background restriction policy for the given package/uid. + * @return The proposed background restriction policy for the given package/uid, + * the returned level should be capped at {@code maxLevel} (exclusive). */ - public @RestrictionLevel int getProposedRestrictionLevel(String packageName, int uid) { + public @RestrictionLevel int getProposedRestrictionLevel(String packageName, int uid, + @RestrictionLevel int maxLevel) { return RESTRICTION_LEVEL_UNKNOWN; } diff --git a/services/core/java/com/android/server/am/BaseAppStateTimeSlotEventsTracker.java b/services/core/java/com/android/server/am/BaseAppStateTimeSlotEventsTracker.java index 2fbca1fa1724b..b8aee13ccdd70 100644 --- a/services/core/java/com/android/server/am/BaseAppStateTimeSlotEventsTracker.java +++ b/services/core/java/com/android/server/am/BaseAppStateTimeSlotEventsTracker.java @@ -18,6 +18,7 @@ package com.android.server.am; import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET; import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET; +import static android.app.ActivityManager.RESTRICTION_LEVEL_UNKNOWN; import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM; import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE; import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE; @@ -295,11 +296,19 @@ abstract class BaseAppStateTimeSlotEventsTracker } @Override - public @RestrictionLevel int getProposedRestrictionLevel(String packageName, int uid) { + @RestrictionLevel + public int getProposedRestrictionLevel(String packageName, int uid, + @RestrictionLevel int maxLevel) { synchronized (mLock) { - return mExcessiveEventPkgs.get(packageName, uid) == null + final int level = mExcessiveEventPkgs.get(packageName, uid) == null ? RESTRICTION_LEVEL_ADAPTIVE_BUCKET : RESTRICTION_LEVEL_RESTRICTED_BUCKET; + if (maxLevel > RESTRICTION_LEVEL_RESTRICTED_BUCKET) { + return level; + } else if (maxLevel == RESTRICTION_LEVEL_RESTRICTED_BUCKET) { + return RESTRICTION_LEVEL_ADAPTIVE_BUCKET; + } + return RESTRICTION_LEVEL_UNKNOWN; } } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java index 47d4c8d9af466..32a87b62aeab6 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java @@ -579,6 +579,7 @@ public final class BackgroundRestrictionTest { DeviceConfigSession bgPromptFgsWithNotiToBgRestricted = null; DeviceConfigSession bgNotificationMinInterval = null; DeviceConfigSession bgBatteryExemptionTypes = null; + DeviceConfigSession bgCurrentDrainDecoupleThresholds = null; mBgRestrictionController.addAppBackgroundRestrictionListener(listener); @@ -648,6 +649,13 @@ public final class BackgroundRestrictionTest { R.integer.config_bg_current_drain_exempted_types)); bgBatteryExemptionTypes.set(0); + bgCurrentDrainDecoupleThresholds = new DeviceConfigSession<>( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS, + DeviceConfig::getBoolean, + AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD); + bgCurrentDrainDecoupleThresholds.set(true); + mCurrentTimeMillis = 10_000L; doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp(); doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp(); @@ -785,6 +793,11 @@ public final class BackgroundRestrictionTest { anyInt(), anyInt()); }); + // Pretend we have the standby buckets set above. + doReturn(STANDBY_BUCKET_RESTRICTED) + .when(mAppStandbyInternal) + .getAppStandbyBucket(eq(testPkgName), eq(testUser), anyLong(), anyBoolean()); + // Sleep a while and set a higher drain Thread.sleep(windowMs); clearInvocations(mInjector.getAppStandbyInternal()); @@ -921,6 +934,11 @@ public final class BackgroundRestrictionTest { // Expected. } + // Reset the standby bucket. + doReturn(STANDBY_BUCKET_RARE) + .when(mAppStandbyInternal) + .getAppStandbyBucket(eq(testPkgName), eq(testUser), anyLong(), anyBoolean()); + // Turn OFF the FAS. listener.mLatchHolder[0] = new CountDownLatch(1); clearInvocations(mInjector.getAppStandbyInternal()); @@ -930,6 +948,99 @@ public final class BackgroundRestrictionTest { // It'll go back to restricted bucket because it used to behave poorly. listener.verify(timeout, testUid, testPkgName, RESTRICTION_LEVEL_RESTRICTED_BUCKET); verifyRestrictionLevel(RESTRICTION_LEVEL_RESTRICTED_BUCKET, testPkgName, testUid); + + clearInvocations(mInjector.getAppStandbyInternal()); + // Trigger user interaction. + runTestBgCurrentDrainMonitorOnce(listener, stats, uids, + new double[]{restrictBucketThresholdMah - 1, 0}, + new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros, + () -> { + doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp(); + doReturn(mCurrentTimeMillis + windowMs) + .when(stats).getStatsEndTimestamp(); + mCurrentTimeMillis += windowMs + 1; + mIdleStateListener.onUserInteractionStarted(testPkgName, testUser); + waitForIdleHandler(mBgRestrictionController.getBackgroundHandler()); + // It should have been back to normal. + listener.verify(timeout, testUid, testPkgName, + RESTRICTION_LEVEL_ADAPTIVE_BUCKET); + verify(mInjector.getAppStandbyInternal(), atLeast(1)).maybeUnrestrictApp( + eq(testPkgName), + eq(testUser), + eq(REASON_MAIN_USAGE), + eq(REASON_SUB_USAGE_USER_INTERACTION), + eq(REASON_MAIN_USAGE), + eq(REASON_SUB_USAGE_USER_INTERACTION)); + }); + + bgCurrentDrainDecoupleThresholds.set(true); + clearInvocations(mInjector.getAppStandbyInternal()); + + // Go to the threshold right away. + runTestBgCurrentDrainMonitorOnce(listener, stats, uids, + new double[]{0, restrictBucketThresholdMah - 1}, + new double[]{bgRestrictedThresholdMah + 1, 0}, zeros, zeros, + () -> { + doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp(); + doReturn(mCurrentTimeMillis + windowMs) + .when(stats).getStatsEndTimestamp(); + mCurrentTimeMillis += windowMs + 1; + // We won't change restriction level automatically because it needs + // user consent. + try { + listener.verify(timeout, testUid, testPkgName, + RESTRICTION_LEVEL_BACKGROUND_RESTRICTED); + fail("There shouldn't be level change event like this"); + } catch (Exception e) { + // Expected. + } + verify(mInjector.getAppStandbyInternal(), never()).setAppStandbyBucket( + eq(testPkgName), + eq(STANDBY_BUCKET_RARE), + eq(testUser), + anyInt(), anyInt()); + // We should have requested to goto background restricted level. + verify(mBgRestrictionController, times(1)).handleRequestBgRestricted( + eq(testPkgName), + eq(testUid)); + // Verify we have the notification posted now because its FGS is invisible. + checkNotificationShown(new String[] {testPkgName}, atLeast(1), true); + }); + + bgCurrentDrainDecoupleThresholds.set(false); + clearInvocations(mInjector.getAppStandbyInternal()); + clearInvocations(mBgRestrictionController); + + // Go to the threshold right away, but this time, it shouldn't even request to goto + // bg restricted level because it requires to be in restricted bucket before that. + runTestBgCurrentDrainMonitorOnce(listener, stats, uids, + new double[]{0, restrictBucketThresholdMah - 1}, + new double[]{bgRestrictedThresholdMah + 1, 0}, zeros, zeros, + () -> { + doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp(); + doReturn(mCurrentTimeMillis + windowMs) + .when(stats).getStatsEndTimestamp(); + mCurrentTimeMillis += windowMs + 1; + // We won't change restriction level automatically because it needs + // user consent. + try { + listener.verify(timeout, testUid, testPkgName, + RESTRICTION_LEVEL_BACKGROUND_RESTRICTED); + fail("There shouldn't be level change event like this"); + } catch (Exception e) { + // Expected. + } + verify(mInjector.getAppStandbyInternal(), never()).setAppStandbyBucket( + eq(testPkgName), + eq(STANDBY_BUCKET_RARE), + eq(testUser), + anyInt(), anyInt()); + // We should NOT have requested to goto background restricted level. + verify(mBgRestrictionController, never()).handleRequestBgRestricted( + eq(testPkgName), + eq(testUid)); + }); + } finally { closeIfNotNull(bgCurrentDrainMonitor); closeIfNotNull(bgCurrentDrainWindow); @@ -938,6 +1049,7 @@ public final class BackgroundRestrictionTest { closeIfNotNull(bgPromptFgsWithNotiToBgRestricted); closeIfNotNull(bgNotificationMinInterval); closeIfNotNull(bgBatteryExemptionTypes); + closeIfNotNull(bgCurrentDrainDecoupleThresholds); } } @@ -1441,6 +1553,7 @@ public final class BackgroundRestrictionTest { DeviceConfigSession bgPermissionMonitorEnabled = null; DeviceConfigSession bgPermissionsInMonitor = null; DeviceConfigSession bgCurrentDrainHighThresholdByBgLocation = null; + DeviceConfigSession bgCurrentDrainDecoupleThresholds = null; mBgRestrictionController.addAppBackgroundRestrictionListener(listener); @@ -1572,6 +1685,13 @@ public final class BackgroundRestrictionTest { R.bool.config_bg_current_drain_high_threshold_by_bg_location)); bgCurrentDrainHighThresholdByBgLocation.set(true); + bgCurrentDrainDecoupleThresholds = new DeviceConfigSession<>( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS, + DeviceConfig::getBoolean, + AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD); + bgCurrentDrainDecoupleThresholds.set(true); + mCurrentTimeMillis = 10_000L; doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp(); doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp(); @@ -1990,6 +2110,7 @@ public final class BackgroundRestrictionTest { closeIfNotNull(bgPermissionMonitorEnabled); closeIfNotNull(bgPermissionsInMonitor); closeIfNotNull(bgCurrentDrainHighThresholdByBgLocation); + closeIfNotNull(bgCurrentDrainDecoupleThresholds); } }