Merge changes I08df6527,I16a5537e into tm-dev

* changes:
  Improve the dumpsys output of the app battery tracker
  Coalesce the shared GID battery usage into its real UID
This commit is contained in:
Jing Ji 2022-04-02 18:05:56 +00:00 committed by Android (Google) Code Review
commit 26f54bd162

View File

@ -55,6 +55,7 @@ import android.os.BatteryConsumer.Dimensions;
import android.os.BatteryStatsInternal;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Build;
import android.os.PowerExemptionManager;
import android.os.PowerExemptionManager.ReasonCode;
import android.os.SystemClock;
@ -62,6 +63,7 @@ import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.ArraySet;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@ -81,6 +83,7 @@ import java.io.PrintWriter;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
/**
* The battery usage tracker for apps, currently we are focusing on background + FGS battery here.
@ -91,6 +94,9 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
static final boolean DEBUG_BACKGROUND_BATTERY_TRACKER = false;
static final boolean DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE =
DEBUG_BACKGROUND_BATTERY_TRACKER | Build.IS_DEBUGGABLE;
// As we don't support realtime per-UID battery usage stats yet, we're polling the stats
// in a regular time basis.
private final long mBatteryUsageStatsPollingIntervalMs;
@ -170,7 +176,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
private long mLastUidBatteryUsageStartTs;
// For debug only.
private final SparseArray<BatteryUsage> mDebugUidPercentages = new SparseArray<>();
private final SparseArray<ImmutableBatteryUsage> mDebugUidPercentages = new SparseArray<>();
AppBatteryTracker(Context context, AppRestrictionController controller) {
this(context, controller, null, null);
@ -337,10 +343,12 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
bgPolicy.mBgCurrentDrainExemptedTypes);
// It's possible the exemptedUsage could be larger than actualUsage,
// as the former one is an approximate value.
final BatteryUsage bgUsage = actualUsage.mutate()
final ImmutableBatteryUsage bgUsage = actualUsage.mutate()
.subtract(exemptedUsage)
.calcPercentage(uid, bgPolicy);
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
.calcPercentage(uid, bgPolicy)
.unmutate();
if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE
&& !BATTERY_USAGE_NONE.equals(actualUsage)) {
Slog.i(TAG, String.format(
"UID %d: %s (%s) | %s | %s over the past %s",
uid,
@ -420,7 +428,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
}
}
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE) {
Slog.i(TAG, "updateBatteryUsageStatsOnce");
}
@ -477,14 +485,17 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
final BatteryUsage lastUsage = mLastUidBatteryUsage.get(uid, BATTERY_USAGE_NONE);
final BatteryUsage curUsage = buf.valueAt(i);
final BatteryUsage before;
final BatteryUsage totalUsage;
if (index >= 0) {
before = mUidBatteryUsage.valueAt(index);
before.subtract(lastUsage).add(curUsage);
totalUsage = mUidBatteryUsage.valueAt(index);
before = DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE
? new BatteryUsage(totalUsage) : BATTERY_USAGE_NONE;
totalUsage.subtract(lastUsage).add(curUsage);
} else {
before = BATTERY_USAGE_NONE;
before = totalUsage = BATTERY_USAGE_NONE;
mUidBatteryUsage.put(uid, curUsage);
}
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE) {
final BatteryUsage actualDelta = new BatteryUsage(curUsage).subtract(lastUsage);
String msg = "Updating mUidBatteryUsage uid=" + uid + ", before=" + before
+ ", after=" + mUidBatteryUsage.get(uid, BATTERY_USAGE_NONE)
@ -496,7 +507,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
if (!actualDelta.isValid()) {
// Something is wrong, the battery usage shouldn't be negative.
Slog.e(TAG, msg);
} else {
} else if (!BATTERY_USAGE_NONE.equals(actualDelta)) {
Slog.i(TAG, msg);
}
}
@ -519,11 +530,16 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
copyUidBatteryUsage(buf, mUidBatteryUsageInWindow);
}
}
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE) {
synchronized (mLock) {
for (int i = 0, size = mUidBatteryUsageInWindow.size(); i < size; i++) {
final ImmutableBatteryUsage usage = mUidBatteryUsageInWindow.valueAt(i);
if (BATTERY_USAGE_NONE.equals(usage)) {
// Skip the logging to avoid spamming.
continue;
}
Slog.i(TAG, "mUidBatteryUsageInWindow uid=" + mUidBatteryUsageInWindow.keyAt(i)
+ " usage=" + mUidBatteryUsageInWindow.valueAt(i));
+ " usage=" + usage);
}
}
}
@ -552,7 +568,19 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
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 int rawUid = uidConsumer.getUid();
if (UserHandle.isIsolated(rawUid)) {
// Isolated processes should have been attributed to their parent processes.
continue;
}
int uid = rawUid;
// Keep the logic in sync with BatteryAppListPreferenceController.java
// Check if this UID is a shared GID. If so, we combine it with the OWNER's
// actual app UID.
final int sharedAppId = UserHandle.getAppIdFromSharedAppGid(uid);
if (sharedAppId > 0) {
uid = UserHandle.getUid(UserHandle.USER_SYSTEM, sharedAppId);
}
final BatteryUsage bgUsage = new BatteryUsage(uidConsumer, bgPolicy)
.scale(scale);
int index = buf.indexOfKey(uid);
@ -562,9 +590,13 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
final BatteryUsage before = buf.valueAt(index);
before.add(bgUsage);
}
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
Slog.i(TAG, "updateBatteryUsageStatsOnceInternal uid=" + uid
if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE
&& !BATTERY_USAGE_NONE.equals(bgUsage)) {
Slog.i(TAG, "updateBatteryUsageStatsOnceInternal uid=" + rawUid
+ ", bgUsage=" + bgUsage
+ (rawUid == uid ? ""
: ", realUid=" + uid
+ ", realUsage=" + buf.get(uid))
+ ", start=" + start
+ ", end=" + end);
}
@ -616,7 +648,8 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
void setDebugUidPercentage(int[] uids, double[][] percentages) {
mDebugUidPercentages.clear();
for (int i = 0; i < uids.length; i++) {
mDebugUidPercentages.put(uids[i], new BatteryUsage().setPercentage(percentages[i]));
mDebugUidPercentages.put(uids[i],
new BatteryUsage().setPercentage(percentages[i]).unmutate());
}
scheduleBgBatteryUsageStatsCheck();
}
@ -642,7 +675,20 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
void dump(PrintWriter pw, String prefix) {
pw.print(prefix);
pw.println("APP BATTERY STATE TRACKER:");
// Force an update.
updateBatteryUsageStatsIfNecessary(mInjector.currentTimeMillis(), true);
// Force a check.
scheduleBgBatteryUsageStatsCheck();
// Wait for its completion (as it runs in handler thread for the sake of thread safe)
final CountDownLatch latch = new CountDownLatch(1);
mBgHandler.getLooper().getQueue().addIdleHandler(() -> {
latch.countDown();
return false;
});
try {
latch.await();
} catch (InterruptedException e) {
}
synchronized (mLock) {
final SparseArray<ImmutableBatteryUsage> uidConsumers = mUidBatteryUsageInWindow;
pw.print(" " + prefix);
@ -811,8 +857,12 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
}
private BatteryUsage setToInternal(@NonNull BatteryUsage other) {
for (int i = 0; i < other.mUsage.length; i++) {
mUsage[i] = other.mUsage[i];
System.arraycopy(other.mUsage, 0, mUsage, 0, other.mUsage.length);
if (other.mPercentage != null) {
mPercentage = new double[other.mPercentage.length];
System.arraycopy(other.mPercentage, 0, mPercentage, 0, other.mPercentage.length);
} else {
mPercentage = null;
}
return this;
}
@ -1297,11 +1347,12 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
/**
* List of the packages with significant background battery usage, key is the UID of
* the package and value is an array of the timestamps when the UID is found guilty and
* should be moved to the next level of restriction.
* the package and value is the pair of {timestamp[], battery usage snapshot[]}
* when the UID is found guilty and should be moved to the next level of restriction.
*/
@GuardedBy("mLock")
private final SparseArray<long[]> mHighBgBatteryPackages = new SparseArray<>();
private final SparseArray<Pair<long[], ImmutableBatteryUsage[]>> mHighBgBatteryPackages =
new SparseArray<>();
@NonNull
private final Object mLock;
@ -1531,8 +1582,9 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
return RESTRICTION_LEVEL_UNKNOWN;
}
synchronized (mLock) {
final long[] ts = mHighBgBatteryPackages.get(uid);
if (ts != null) {
final Pair<long[], ImmutableBatteryUsage[]> pair = mHighBgBatteryPackages.get(uid);
if (pair != null) {
final long[] ts = pair.first;
final int restrictedLevel = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] > 0
? RESTRICTION_LEVEL_RESTRICTED_BUCKET
: RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
@ -1601,10 +1653,10 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
return sb.toString();
}
void handleUidBatteryUsage(final int uid, final BatteryUsage usage) {
void handleUidBatteryUsage(final int uid, final ImmutableBatteryUsage usage) {
final @ReasonCode int reason = shouldExemptUid(uid);
if (reason != REASON_DENIED) {
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE && !BATTERY_USAGE_NONE.equals(usage)) {
Slog.i(TAG, "Exempting battery usage in " + UserHandle.formatUid(uid)
+ " " + PowerExemptionManager.reasonCodeToString(reason));
}
@ -1612,6 +1664,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
}
boolean notifyController = false;
boolean excessive = false;
int index = 0;
final double rbPercentage = sumPercentageOfTypes(usage.getPercentage(),
mBgCurrentDrainRestrictedBucketTypes);
final double brPercentage = sumPercentageOfTypes(usage.getPercentage(),
@ -1625,33 +1678,41 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
final long now = SystemClock.elapsedRealtime();
final int thresholdIndex = getCurrentDrainThresholdIndex(uid, now,
mBgCurrentDrainWindowMs);
final int index = mHighBgBatteryPackages.indexOfKey(uid);
index = mHighBgBatteryPackages.indexOfKey(uid);
final boolean decoupleThresholds = mBgCurrentDrainDecoupleThresholds;
final double rbThreshold = mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex];
final double brThreshold = mBgCurrentDrainBgRestrictedThreshold[thresholdIndex];
if (index < 0) {
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;
mHighBgBatteryPackages.put(uid, ts);
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 (decoupleThresholds && brPercentage >= brThreshold) {
if (ts == null) {
ts = new long[TIME_STAMP_INDEX_LAST];
mHighBgBatteryPackages.put(uid, ts);
usages = new ImmutableBatteryUsage[TIME_STAMP_INDEX_LAST];
mHighBgBatteryPackages.put(uid, Pair.create(ts, usages));
}
ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now;
usages[TIME_STAMP_INDEX_BG_RESTRICTED] = usage;
notifyController = excessive = true;
}
} else {
final long[] ts = mHighBgBatteryPackages.valueAt(index);
final Pair<long[], ImmutableBatteryUsage[]> pair =
mHighBgBatteryPackages.valueAt(index);
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;
}
notifyController = excessive = true;
} else {
@ -1670,6 +1731,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;
}
excessive = true;
} else {
@ -1677,13 +1739,14 @@ 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;
// Now need to notify the controller.
}
}
}
if (excessive) {
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE) {
Slog.i(TAG, "Excessive background current drain " + uid + " "
+ usage + " (" + usage.percentageToString() + " ) over "
+ TimeUtils.formatDuration(mBgCurrentDrainWindowMs));
@ -1694,7 +1757,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE, true);
}
} else {
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE && index >= 0) {
Slog.i(TAG, "Background current drain backs to normal " + uid + " "
+ usage + " (" + usage.percentageToString() + " ) over "
+ TimeUtils.formatDuration(mBgCurrentDrainWindowMs));
@ -1764,9 +1827,10 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
synchronized (mLock) {
// User has explicitly removed it from background restricted level,
// clear the timestamp of the background-restricted
final long[] ts = mHighBgBatteryPackages.get(uid);
if (ts != null) {
ts[TIME_STAMP_INDEX_BG_RESTRICTED] = 0;
final Pair<long[], ImmutableBatteryUsage[]> pair = mHighBgBatteryPackages.get(uid);
if (pair != null) {
pair.first[TIME_STAMP_INDEX_BG_RESTRICTED] = 0;
pair.second[TIME_STAMP_INDEX_BG_RESTRICTED] = null;
}
}
}
@ -1841,6 +1905,10 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
pw.print(KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION);
pw.print('=');
pw.println(mBgCurrentDrainHighThresholdByBgLocation);
pw.print(prefix);
pw.print("Full charge capacity=");
pw.print(mBatteryFullChargeMah);
pw.println(" mAh");
pw.print(prefix);
pw.println("Excessive current drain detected:");
@ -1851,18 +1919,24 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
final long now = SystemClock.elapsedRealtime();
for (int i = 0; i < size; i++) {
final int uid = mHighBgBatteryPackages.keyAt(i);
final long[] ts = mHighBgBatteryPackages.valueAt(i);
final Pair<long[], ImmutableBatteryUsage[]> pair =
mHighBgBatteryPackages.valueAt(i);
final long[] ts = pair.first;
final ImmutableBatteryUsage[] usages = pair.second;
final int thresholdIndex = getCurrentDrainThresholdIndex(uid, now,
mBgCurrentDrainWindowMs);
pw.format("%s%s: (threshold=%4.2f%%/%4.2f%%) %s/%s\n",
pw.format("%s%s: (threshold=%4.2f%%/%4.2f%%) %s / %s\n",
prefix,
UserHandle.formatUid(uid),
mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex],
mBgCurrentDrainBgRestrictedThreshold[thresholdIndex],
ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] == 0 ? "0"
: formatTime(ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET], now),
ts[TIME_STAMP_INDEX_BG_RESTRICTED] == 0 ? "0"
: formatTime(ts[TIME_STAMP_INDEX_BG_RESTRICTED], now));
formatHighBgBatteryRecord(
ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET], now,
usages[TIME_STAMP_INDEX_RESTRICTED_BUCKET]),
formatHighBgBatteryRecord(
ts[TIME_STAMP_INDEX_BG_RESTRICTED], now,
usages[TIME_STAMP_INDEX_BG_RESTRICTED])
);
}
} else {
pw.print(prefix);
@ -1871,5 +1945,14 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
}
}
}
private String formatHighBgBatteryRecord(long ts, long now, ImmutableBatteryUsage usage) {
if (ts > 0 && usage != null) {
return String.format("%s %s (%s)",
formatTime(ts, now), usage.toString(), usage.percentageToString());
} else {
return "0";
}
}
}
}