Merge "Don't auto move into restricted bucket if there's a recent interaction" into tm-dev

This commit is contained in:
Jing Ji
2022-05-09 16:01:01 +00:00
committed by Android (Google) Code Review
2 changed files with 138 additions and 14 deletions

View File

@@ -67,6 +67,7 @@ import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseLongArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -360,6 +361,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
mUidBatteryUsageInWindow.removeAt(i);
}
}
mInjector.getPolicy().onUserRemovedLocked(userId);
}
}
@@ -368,6 +370,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
synchronized (mLock) {
mUidBatteryUsage.delete(uid);
mUidBatteryUsageInWindow.delete(uid);
mInjector.getPolicy().onUidRemovedLocked(uid);
}
}
@@ -1207,6 +1210,14 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
static final String KEY_BG_CURRENT_DRAIN_WINDOW =
DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_window";
/**
* The grace period after an interaction event with the app, if the background current
* drain goes beyond the threshold within that period, the system won't apply the
* restrictions.
*/
static final String KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD =
DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_interaction_grace_period";
/**
* Similar to {@link #KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET}, but a higher
* value for the legitimate cases with higher background current drain.
@@ -1309,6 +1320,11 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
*/
final long mDefaultBgCurrentDrainWindowMs;
/**
* Default value to {@link #mBgCurrentDrainInteractionGracePeriodMs}.
*/
final long mDefaultBgCurrentDrainInteractionGracePeriodMs;
/**
* Default value to the {@link #INDEX_HIGH_CURRENT_DRAIN_THRESHOLD} of
* the {@link #mBgCurrentDrainRestrictedBucketThreshold}.
@@ -1393,6 +1409,11 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
*/
volatile long mBgCurrentDrainWindowMs;
/**
* @see #KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD.
*/
volatile long mBgCurrentDrainInteractionGracePeriodMs;
/**
* @see #KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION.
*/
@@ -1455,6 +1476,12 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
private final SparseArray<Pair<long[], ImmutableBatteryUsage[]>> mHighBgBatteryPackages =
new SparseArray<>();
/**
* The timestamp of the last interaction, key is the UID.
*/
@GuardedBy("mLock")
private final SparseLongArray mLastInteractionTime = new SparseLongArray();
@NonNull
private final Object mLock;
@@ -1478,6 +1505,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
isLowRamDeviceStatic() ? val[1] : val[0];
mDefaultBgCurrentDrainWindowMs = resources.getInteger(
R.integer.config_bg_current_drain_window) * 1_000;
mDefaultBgCurrentDrainInteractionGracePeriodMs = mDefaultBgCurrentDrainWindowMs;
val = getFloatArray(resources.obtainTypedArray(
R.array.config_bg_current_drain_high_threshold_to_restricted_bucket));
mDefaultBgCurrentDrainRestrictedBucketHighThreshold =
@@ -1511,6 +1539,8 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
mBgCurrentDrainBgRestrictedThreshold[1] =
mDefaultBgCurrentDrainBgRestrictedHighThreshold;
mBgCurrentDrainWindowMs = mDefaultBgCurrentDrainWindowMs;
mBgCurrentDrainInteractionGracePeriodMs =
mDefaultBgCurrentDrainInteractionGracePeriodMs;
mBgCurrentDrainMediaPlaybackMinDuration =
mDefaultBgCurrentDrainMediaPlaybackMinDuration;
mBgCurrentDrainLocationMinDuration = mDefaultBgCurrentDrainLocationMinDuration;
@@ -1542,6 +1572,9 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
case KEY_BG_CURRENT_DRAIN_WINDOW:
updateCurrentDrainWindow();
break;
case KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD:
updateCurrentDrainInteractionGracePeriod();
break;
case KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION:
updateCurrentDrainMediaPlaybackMinDuration();
break;
@@ -1626,6 +1659,13 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
mDefaultBgCurrentDrainWindowMs);
}
private void updateCurrentDrainInteractionGracePeriod() {
mBgCurrentDrainInteractionGracePeriodMs = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD,
mDefaultBgCurrentDrainInteractionGracePeriodMs);
}
private void updateCurrentDrainMediaPlaybackMinDuration() {
mBgCurrentDrainMediaPlaybackMinDuration = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -1668,6 +1708,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
super.onSystemReady();
updateCurrentDrainThreshold();
updateCurrentDrainWindow();
updateCurrentDrainInteractionGracePeriod();
updateCurrentDrainMediaPlaybackMinDuration();
updateCurrentDrainLocationMinDuration();
updateCurrentDrainEventDurationBasedThresholdEnabled();
@@ -1685,8 +1726,10 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
synchronized (mLock) {
final Pair<long[], ImmutableBatteryUsage[]> pair = mHighBgBatteryPackages.get(uid);
if (pair != null) {
final long lastInteractionTime = mLastInteractionTime.get(uid, 0L);
final long[] ts = pair.first;
final int restrictedLevel = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] > 0
final int restrictedLevel = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET]
> (lastInteractionTime + mBgCurrentDrainInteractionGracePeriodMs)
&& mTracker.mAppRestrictionController.isAutoRestrictAbusiveAppEnabled()
? RESTRICTION_LEVEL_RESTRICTED_BUCKET
: RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
@@ -1777,6 +1820,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
// We're already in the background restricted level, nothing more we could do.
return;
}
final long lastInteractionTime = mLastInteractionTime.get(uid, 0L);
final long now = SystemClock.elapsedRealtime();
final int thresholdIndex = getCurrentDrainThresholdIndex(uid, now,
mBgCurrentDrainWindowMs);
@@ -1788,13 +1832,17 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
long[] ts = null;
ImmutableBatteryUsage[] usages = null;
if (rbPercentage >= rbThreshold) {
// New findings to us, track it and let the controller know.
ts = new long[TIME_STAMP_INDEX_LAST];
ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now;
usages = new ImmutableBatteryUsage[TIME_STAMP_INDEX_LAST];
usages[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = usage;
mHighBgBatteryPackages.put(uid, Pair.create(ts, usages));
notifyController = excessive = true;
if (now > lastInteractionTime + mBgCurrentDrainInteractionGracePeriodMs) {
// New findings to us, track it and let the controller know.
ts = new long[TIME_STAMP_INDEX_LAST];
ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now;
usages = new ImmutableBatteryUsage[TIME_STAMP_INDEX_LAST];
usages[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = usage;
mHighBgBatteryPackages.put(uid, Pair.create(ts, usages));
// It's beeen long enough since last interaction with this app.
notifyController = true;
}
excessive = true;
}
if (decoupleThresholds && brPercentage >= brThreshold) {
if (ts == null) {
@@ -1812,11 +1860,15 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
final long[] ts = pair.first;
final long lastRestrictBucketTs = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET];
if (rbPercentage >= rbThreshold) {
if (lastRestrictBucketTs == 0) {
ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now;
pair.second[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = usage;
if (now > lastInteractionTime + mBgCurrentDrainInteractionGracePeriodMs) {
if (lastRestrictBucketTs == 0) {
ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now;
pair.second[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = usage;
}
// It's been long enough since last interaction with this app.
notifyController = true;
}
notifyController = excessive = true;
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
@@ -1833,7 +1885,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
&& (now > lastRestrictBucketTs + mBgCurrentDrainWindowMs));
if (notifyController) {
ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now;
pair.second[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = usage;
pair.second[TIME_STAMP_INDEX_BG_RESTRICTED] = usage;
}
excessive = true;
} else {
@@ -1841,7 +1893,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
// 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;
pair.second[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = null;
pair.second[TIME_STAMP_INDEX_BG_RESTRICTED] = null;
// Now need to notify the controller.
}
}
@@ -1902,6 +1954,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
void onUserInteractionStarted(String packageName, int uid) {
boolean changed = false;
synchronized (mLock) {
mLastInteractionTime.put(uid, SystemClock.elapsedRealtime());
final int curLevel = mTracker.mAppRestrictionController.getRestrictionLevel(
uid, packageName);
if (curLevel == RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) {
@@ -1940,9 +1993,30 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
@VisibleForTesting
void reset() {
mHighBgBatteryPackages.clear();
mLastInteractionTime.clear();
mTracker.reset();
}
@GuardedBy("mLock")
void onUserRemovedLocked(final @UserIdInt int userId) {
for (int i = mHighBgBatteryPackages.size() - 1; i >= 0; i--) {
if (UserHandle.getUserId(mHighBgBatteryPackages.keyAt(i)) == userId) {
mHighBgBatteryPackages.removeAt(i);
}
}
for (int i = mLastInteractionTime.size() - 1; i >= 0; i--) {
if (UserHandle.getUserId(mLastInteractionTime.keyAt(i)) == userId) {
mLastInteractionTime.removeAt(i);
}
}
}
@GuardedBy("mLock")
void onUidRemovedLocked(final int uid) {
mHighBgBatteryPackages.remove(uid);
mLastInteractionTime.delete(uid);
}
@Override
void dump(PrintWriter pw, String prefix) {
pw.print(prefix);
@@ -1976,6 +2050,10 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
pw.print('=');
pw.println(mBgCurrentDrainWindowMs);
pw.print(prefix);
pw.print(KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD);
pw.print('=');
pw.println(mBgCurrentDrainInteractionGracePeriodMs);
pw.print(prefix);
pw.print(KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION);
pw.print('=');
pw.println(mBgCurrentDrainMediaPlaybackMinDuration);

View File

@@ -582,6 +582,7 @@ public final class BackgroundRestrictionTest {
DeviceConfigSession<Boolean> bgCurrentDrainMonitor = null;
DeviceConfigSession<Long> bgCurrentDrainWindow = null;
DeviceConfigSession<Long> bgCurrentDrainInteractionGracePeriod = null;
DeviceConfigSession<Float> bgCurrentDrainRestrictedBucketThreshold = null;
DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
DeviceConfigSession<Boolean> bgPromptFgsWithNotiToBgRestricted = null;
@@ -617,6 +618,14 @@ public final class BackgroundRestrictionTest {
R.integer.config_bg_current_drain_window));
bgCurrentDrainWindow.set(windowMs);
bgCurrentDrainInteractionGracePeriod = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD,
DeviceConfig::getLong,
(long) mContext.getResources().getInteger(
R.integer.config_bg_current_drain_window));
bgCurrentDrainInteractionGracePeriod.set(windowMs);
bgCurrentDrainRestrictedBucketThreshold = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET,
@@ -768,6 +777,32 @@ public final class BackgroundRestrictionTest {
clearInvocations(mInjector.getAppStandbyInternal());
// It won't be restricted since user just interacted with it.
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
zeros, new double[]{0, restrictBucketThresholdMah - 1},
zeros, new double[]{restrictBucketThresholdMah + 1, 0},
() -> {
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis + windowMs)
.when(stats).getStatsEndTimestamp();
mCurrentTimeMillis += windowMs + 1;
try {
listener.verify(timeout, testUid, testPkgName,
RESTRICTION_LEVEL_RESTRICTED_BUCKET);
fail("There shouldn't be any level change events");
} catch (Exception e) {
// Expected.
}
verify(mInjector.getAppStandbyInternal(), never()).restrictApp(
eq(testPkgName),
eq(testUser),
anyInt(), anyInt());
});
// Sleep a while.
Thread.sleep(windowMs);
clearInvocations(mInjector.getAppStandbyInternal());
// Now it should have been restricted.
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
zeros, new double[]{0, restrictBucketThresholdMah - 1},
zeros, new double[]{restrictBucketThresholdMah + 1, 0},
@@ -1061,6 +1096,7 @@ public final class BackgroundRestrictionTest {
} finally {
closeIfNotNull(bgCurrentDrainMonitor);
closeIfNotNull(bgCurrentDrainWindow);
closeIfNotNull(bgCurrentDrainInteractionGracePeriod);
closeIfNotNull(bgCurrentDrainRestrictedBucketThreshold);
closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
closeIfNotNull(bgPromptFgsWithNotiToBgRestricted);
@@ -1610,6 +1646,7 @@ public final class BackgroundRestrictionTest {
DeviceConfigSession<Boolean> bgCurrentDrainMonitor = null;
DeviceConfigSession<Long> bgCurrentDrainWindow = null;
DeviceConfigSession<Long> bgCurrentDrainInteractionGracePeriod = null;
DeviceConfigSession<Float> bgCurrentDrainRestrictedBucketThreshold = null;
DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
DeviceConfigSession<Float> bgCurrentDrainRestrictedBucketHighThreshold = null;
@@ -1655,6 +1692,14 @@ public final class BackgroundRestrictionTest {
R.integer.config_bg_current_drain_window));
bgCurrentDrainWindow.set(windowMs);
bgCurrentDrainInteractionGracePeriod = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD,
DeviceConfig::getLong,
(long) mContext.getResources().getInteger(
R.integer.config_bg_current_drain_window));
bgCurrentDrainInteractionGracePeriod.set(windowMs);
bgCurrentDrainRestrictedBucketThreshold = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET,
@@ -2176,6 +2221,7 @@ public final class BackgroundRestrictionTest {
} finally {
closeIfNotNull(bgCurrentDrainMonitor);
closeIfNotNull(bgCurrentDrainWindow);
closeIfNotNull(bgCurrentDrainInteractionGracePeriod);
closeIfNotNull(bgCurrentDrainRestrictedBucketThreshold);
closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
closeIfNotNull(bgCurrentDrainRestrictedBucketHighThreshold);