Fix the accounting for background battery usage of abusive apps.
Bug: 200326767 Bug: 203105544 Test: atest FrameworksMockingServicesTests:BackgroundRestrictionTest Change-Id: I48e3b43fa2dabd27f9d27390fa7cb359ae65cab3
This commit is contained in:
@@ -87,9 +87,6 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
// in a regular time basis.
|
||||
private final long mBatteryUsageStatsPollingIntervalMs;
|
||||
|
||||
// The timestamp when this system_server was started.
|
||||
private long mBootTimestamp;
|
||||
|
||||
static final long BATTERY_USAGE_STATS_POLLING_INTERVAL_MS_LONG = 30 * ONE_MINUTE; // 30 mins
|
||||
static final long BATTERY_USAGE_STATS_POLLING_INTERVAL_MS_DEBUG = 2_000L; // 2s
|
||||
|
||||
@@ -131,7 +128,8 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
private boolean mBatteryUsageStatsUpdatePending;
|
||||
|
||||
/**
|
||||
* The current known battery usage data for each UID, since the system boots.
|
||||
* The current known battery usage data for each UID, since the system boots or
|
||||
* the last battery stats reset prior to that (whoever is earlier).
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private final SparseDoubleArray mUidBatteryUsage = new SparseDoubleArray();
|
||||
@@ -143,7 +141,8 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
private final SparseDoubleArray mUidBatteryUsageInWindow = new SparseDoubleArray();
|
||||
|
||||
/**
|
||||
* The uid battery usage stats data from our last query, it does not include snapshot data.
|
||||
* The uid battery usage stats data from our last query, it consists of the data since
|
||||
* last battery stats reset.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private final SparseDoubleArray mLastUidBatteryUsage = new SparseDoubleArray();
|
||||
@@ -204,7 +203,6 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
}
|
||||
}
|
||||
}
|
||||
mBootTimestamp = mInjector.currentTimeMillis();
|
||||
scheduleBatteryUsageStatsUpdateIfNecessary(mBatteryUsageStatsPollingIntervalMs);
|
||||
}
|
||||
|
||||
@@ -268,7 +266,8 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The total battery usage of the given UID since the system boots.
|
||||
* @return The total battery usage of the given UID since the system boots or last battery
|
||||
* stats reset prior to that (whoever is earlier).
|
||||
*
|
||||
* <p>
|
||||
* Note: as there are throttling in polling the battery usage stats by
|
||||
@@ -387,7 +386,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
final ArraySet<UserHandle> userIds = mTmpUserIds;
|
||||
final SparseDoubleArray buf = mTmpUidBatteryUsage;
|
||||
final BatteryStatsInternal batteryStatsInternal = mInjector.getBatteryStatsInternal();
|
||||
final long windowSize = Math.min(now - mBootTimestamp, bgPolicy.mBgCurrentDrainWindowMs);
|
||||
final long windowSize = bgPolicy.mBgCurrentDrainWindowMs;
|
||||
|
||||
buf.clear();
|
||||
userIds.clear();
|
||||
@@ -408,10 +407,11 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
BatteryUsageStatsQuery.Builder builder = new BatteryUsageStatsQuery.Builder()
|
||||
.includeProcessStateData()
|
||||
.setMaxStatsAgeMs(0);
|
||||
final BatteryUsageStats stats = updateBatteryUsageStatsOnceInternal(
|
||||
final BatteryUsageStats stats = updateBatteryUsageStatsOnceInternal(0,
|
||||
buf, builder, userIds, batteryStatsInternal);
|
||||
final long curStart = stats != null ? stats.getStatsStartTimestamp() : 0L;
|
||||
long curDuration = now - curStart;
|
||||
final long curEnd = stats != null ? stats.getStatsEndTimestamp() : now;
|
||||
long curDuration = curEnd - curStart;
|
||||
boolean needUpdateUidBatteryUsageInWindow = true;
|
||||
|
||||
if (curDuration >= windowSize) {
|
||||
@@ -422,7 +422,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
needUpdateUidBatteryUsageInWindow = false;
|
||||
}
|
||||
|
||||
// Save the current data, which includes the battery usage since last snapshot.
|
||||
// Save the current data, which includes the battery usage since last reset.
|
||||
mTmpUidBatteryUsage2.clear();
|
||||
copyUidBatteryUsage(buf, mTmpUidBatteryUsage2);
|
||||
|
||||
@@ -437,10 +437,10 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
builder = new BatteryUsageStatsQuery.Builder()
|
||||
.includeProcessStateData()
|
||||
.aggregateSnapshots(lastUidBatteryUsageStartTs, curStart);
|
||||
updateBatteryUsageStatsOnceInternal(buf, builder, userIds, batteryStatsInternal);
|
||||
updateBatteryUsageStatsOnceInternal(0, buf, builder, userIds, batteryStatsInternal);
|
||||
curDuration += curStart - lastUidBatteryUsageStartTs;
|
||||
}
|
||||
if (needUpdateUidBatteryUsageInWindow && curDuration > windowSize) {
|
||||
if (needUpdateUidBatteryUsageInWindow && curDuration >= windowSize) {
|
||||
// If we do have long enough data for the window, save it.
|
||||
synchronized (mLock) {
|
||||
copyUidBatteryUsage(buf, mUidBatteryUsageInWindow, windowSize * 1.0d / curDuration);
|
||||
@@ -453,22 +453,22 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
for (int i = 0, size = buf.size(); i < size; i++) {
|
||||
final int uid = buf.keyAt(i);
|
||||
final int index = mUidBatteryUsage.indexOfKey(uid);
|
||||
final double delta = Math.max(0.0d,
|
||||
buf.valueAt(i) - mLastUidBatteryUsage.get(uid, 0.0d));
|
||||
final double lastUsage = mLastUidBatteryUsage.get(uid, 0.0d);
|
||||
final double curUsage = buf.valueAt(i);
|
||||
final double before;
|
||||
if (index >= 0) {
|
||||
before = mUidBatteryUsage.valueAt(index);
|
||||
mUidBatteryUsage.setValueAt(index, before + delta);
|
||||
mUidBatteryUsage.setValueAt(index, before - lastUsage + curUsage);
|
||||
} else {
|
||||
before = 0.0d;
|
||||
mUidBatteryUsage.put(uid, delta);
|
||||
mUidBatteryUsage.put(uid, curUsage);
|
||||
}
|
||||
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
|
||||
final double actualDelta = buf.valueAt(i) - mLastUidBatteryUsage.get(uid, 0.0d);
|
||||
final double actualDelta = curUsage - lastUsage;
|
||||
String msg = "Updating mUidBatteryUsage uid=" + uid + ", before=" + before
|
||||
+ ", after=" + mUidBatteryUsage.get(uid, 0.0d)
|
||||
+ ", delta=" + actualDelta
|
||||
+ ", last=" + mLastUidBatteryUsage.get(uid, 0.0d)
|
||||
+ ", last=" + lastUsage
|
||||
+ ", curStart=" + curStart
|
||||
+ ", lastLastStart=" + lastUidBatteryUsageStartTs
|
||||
+ ", thisLastStart=" + mLastUidBatteryUsageStartTs;
|
||||
@@ -487,17 +487,28 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
|
||||
if (needUpdateUidBatteryUsageInWindow) {
|
||||
// No sufficient data for the full window still, query snapshots again.
|
||||
final long start = now - windowSize;
|
||||
final long end = lastUidBatteryUsageStartTs - 1;
|
||||
builder = new BatteryUsageStatsQuery.Builder()
|
||||
.includeProcessStateData()
|
||||
.aggregateSnapshots(now - windowSize, lastUidBatteryUsageStartTs);
|
||||
updateBatteryUsageStatsOnceInternal(buf, builder, userIds, batteryStatsInternal);
|
||||
.aggregateSnapshots(start, end);
|
||||
updateBatteryUsageStatsOnceInternal(end - start,
|
||||
buf, builder, userIds, batteryStatsInternal);
|
||||
synchronized (mLock) {
|
||||
copyUidBatteryUsage(buf, mUidBatteryUsageInWindow);
|
||||
}
|
||||
}
|
||||
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
|
||||
synchronized (mLock) {
|
||||
for (int i = 0, size = mUidBatteryUsageInWindow.size(); i < size; i++) {
|
||||
Slog.i(TAG, "mUidBatteryUsageInWindow uid=" + mUidBatteryUsageInWindow.keyAt(i)
|
||||
+ " usage=" + mUidBatteryUsageInWindow.valueAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static BatteryUsageStats updateBatteryUsageStatsOnceInternal(
|
||||
private static BatteryUsageStats updateBatteryUsageStatsOnceInternal(long expectedDuration,
|
||||
SparseDoubleArray buf, BatteryUsageStatsQuery.Builder builder,
|
||||
ArraySet<UserHandle> userIds, BatteryStatsInternal batteryStatsInternal) {
|
||||
for (int i = 0, size = userIds.size(); i < size; i++) {
|
||||
@@ -512,11 +523,15 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
final BatteryUsageStats stats = statsList.get(0);
|
||||
final List<UidBatteryConsumer> uidConsumers = stats.getUidBatteryConsumers();
|
||||
if (uidConsumers != null) {
|
||||
final long start = stats.getStatsStartTimestamp();
|
||||
final long end = stats.getStatsEndTimestamp();
|
||||
final double scale = expectedDuration > 0
|
||||
? (expectedDuration * 1.0d) / (end - start) : 1.0d;
|
||||
for (UidBatteryConsumer uidConsumer : uidConsumers) {
|
||||
// TODO: b/200326767 - as we are not supporting per proc state attribution yet,
|
||||
// we couldn't distinguish between a real FGS vs. a bound FGS proc state.
|
||||
final int uid = uidConsumer.getUid();
|
||||
final double bgUsage = getBgUsage(uidConsumer);
|
||||
final double bgUsage = getBgUsage(uidConsumer) * scale;
|
||||
int index = buf.indexOfKey(uid);
|
||||
if (index < 0) {
|
||||
buf.put(uid, bgUsage);
|
||||
@@ -526,8 +541,8 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
|
||||
Slog.i(TAG, "updateBatteryUsageStatsOnceInternal uid=" + uid
|
||||
+ ", bgUsage=" + bgUsage
|
||||
+ ", start=" + stats.getStatsStartTimestamp()
|
||||
+ ", end=" + stats.getStatsEndTimestamp());
|
||||
+ ", start=" + start
|
||||
+ ", end=" + end);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -607,8 +622,6 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
synchronized (mLock) {
|
||||
final SparseDoubleArray uidConsumers = mUidBatteryUsageInWindow;
|
||||
pw.print(" " + prefix);
|
||||
pw.print("Boot=");
|
||||
TimeUtils.dumpTime(pw, mBootTimestamp);
|
||||
pw.print(" Last battery usage start=");
|
||||
TimeUtils.dumpTime(pw, mLastUidBatteryUsageStartTs);
|
||||
pw.println();
|
||||
|
||||
@@ -561,6 +561,7 @@ public final class BackgroundRestrictionTest {
|
||||
|
||||
mCurrentTimeMillis = 10_000L;
|
||||
doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
|
||||
doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
|
||||
doReturn(statsList).when(mBatteryStatsInternal).getBatteryUsageStats(anyObject());
|
||||
|
||||
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
|
||||
@@ -568,6 +569,8 @@ public final class BackgroundRestrictionTest {
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros,
|
||||
() -> {
|
||||
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
|
||||
doReturn(mCurrentTimeMillis + windowMs)
|
||||
.when(stats).getStatsEndTimestamp();
|
||||
mCurrentTimeMillis += windowMs + 1;
|
||||
try {
|
||||
listener.verify(timeout, testUid, testPkgName,
|
||||
@@ -583,6 +586,8 @@ public final class BackgroundRestrictionTest {
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros,
|
||||
() -> {
|
||||
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
|
||||
doReturn(mCurrentTimeMillis + windowMs)
|
||||
.when(stats).getStatsEndTimestamp();
|
||||
mCurrentTimeMillis += windowMs + 1;
|
||||
// It should have gone to the restricted bucket.
|
||||
listener.verify(timeout, testUid, testPkgName,
|
||||
@@ -599,6 +604,8 @@ public final class BackgroundRestrictionTest {
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros,
|
||||
() -> {
|
||||
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
|
||||
doReturn(mCurrentTimeMillis + windowMs)
|
||||
.when(stats).getStatsEndTimestamp();
|
||||
mCurrentTimeMillis += windowMs + 1;
|
||||
// We won't change restriction level until user interactions.
|
||||
try {
|
||||
@@ -621,6 +628,8 @@ public final class BackgroundRestrictionTest {
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros,
|
||||
() -> {
|
||||
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
|
||||
doReturn(mCurrentTimeMillis + windowMs)
|
||||
.when(stats).getStatsEndTimestamp();
|
||||
mCurrentTimeMillis += windowMs + 1;
|
||||
mIdleStateListener.onUserInteractionStarted(testPkgName, testUser);
|
||||
waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
|
||||
@@ -643,6 +652,8 @@ public final class BackgroundRestrictionTest {
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros,
|
||||
() -> {
|
||||
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
|
||||
doReturn(mCurrentTimeMillis + windowMs)
|
||||
.when(stats).getStatsEndTimestamp();
|
||||
mCurrentTimeMillis += windowMs + 1;
|
||||
// It should have gone to the restricted bucket.
|
||||
listener.verify(timeout, testUid, testPkgName,
|
||||
@@ -660,6 +671,8 @@ public final class BackgroundRestrictionTest {
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros,
|
||||
() -> {
|
||||
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
|
||||
doReturn(mCurrentTimeMillis + windowMs)
|
||||
.when(stats).getStatsEndTimestamp();
|
||||
mCurrentTimeMillis += windowMs + 1;
|
||||
// We won't change restriction level until user interactions.
|
||||
try {
|
||||
@@ -685,6 +698,8 @@ public final class BackgroundRestrictionTest {
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, 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.
|
||||
@@ -1317,6 +1332,7 @@ public final class BackgroundRestrictionTest {
|
||||
|
||||
mCurrentTimeMillis = 10_000L;
|
||||
doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
|
||||
doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
|
||||
doReturn(statsList).when(mBatteryStatsInternal).getBatteryUsageStats(anyObject());
|
||||
|
||||
// Run with a media playback service which starts/stops immediately, we should
|
||||
@@ -1631,6 +1647,7 @@ public final class BackgroundRestrictionTest {
|
||||
listener.mLatchHolder[0] = new CountDownLatch(1);
|
||||
if (initialBg != null) {
|
||||
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
|
||||
doReturn(mCurrentTimeMillis + windowMs).when(stats).getStatsEndTimestamp();
|
||||
mCurrentTimeMillis += windowMs + 1;
|
||||
setUidBatteryConsumptions(stats, uids, initialBg, initialFgs, initialFg);
|
||||
mAppBatteryExemptionTracker.reset();
|
||||
@@ -1645,6 +1662,8 @@ public final class BackgroundRestrictionTest {
|
||||
runTestBgCurrentDrainMonitorOnce(listener, stats, uids, bg, fgs, fg, false,
|
||||
() -> {
|
||||
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
|
||||
doReturn(mCurrentTimeMillis + windowMs)
|
||||
.when(stats).getStatsEndTimestamp();
|
||||
mCurrentTimeMillis += windowMs + 1;
|
||||
if (expectingTimeout) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user