Track foreground activities in battery stats.
To help correlate battery usage against actual foreground app usage,
start tracking time on a per UID basis. It uses the nesting feature
of StopwatchTimer to track multiple PIDs inside the same UID.
Improves units on docs, and persists foreground CPU time with a
consistent ordering. Reports foreground activities time and
foreground CPU time.
Change-Id: I95d12963923e3fd421730f6fbfc842dfd8d3a055
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 499ec77..29e8d9c 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -98,6 +98,11 @@
public static final int VIBRATOR_ON = 9;
/**
+ * A constant indicating a foreground activity timer
+ */
+ public static final int FOREGROUND_ACTIVITY = 10;
+
+ /**
* Include all of the data in the stats, including previously saved data.
*/
public static final int STATS_SINCE_CHARGED = 0;
@@ -125,7 +130,7 @@
/**
* Bump the version on this if the checkin format changes.
*/
- private static final int BATTERY_STATS_CHECKIN_VERSION = 5;
+ private static final int BATTERY_STATS_CHECKIN_VERSION = 6;
private static final long BYTES_PER_KB = 1024;
private static final long BYTES_PER_MB = 1048576; // 1024^2
@@ -137,6 +142,7 @@
private static final String PROCESS_DATA = "pr";
private static final String SENSOR_DATA = "sr";
private static final String VIBRATOR_DATA = "vib";
+ private static final String FOREGROUND_DATA = "fg";
private static final String WAKELOCK_DATA = "wl";
private static final String KERNEL_WAKELOCK_DATA = "kwl";
private static final String NETWORK_DATA = "nt";
@@ -276,6 +282,8 @@
public abstract void noteAudioTurnedOffLocked();
public abstract void noteVideoTurnedOnLocked();
public abstract void noteVideoTurnedOffLocked();
+ public abstract void noteActivityResumedLocked();
+ public abstract void noteActivityPausedLocked();
public abstract long getWifiRunningTime(long batteryRealtime, int which);
public abstract long getFullWifiLockTime(long batteryRealtime, int which);
public abstract long getWifiScanTime(long batteryRealtime, int which);
@@ -283,6 +291,7 @@
int which);
public abstract long getAudioTurnedOnTime(long batteryRealtime, int which);
public abstract long getVideoTurnedOnTime(long batteryRealtime, int which);
+ public abstract Timer getForegroundActivityTimer();
public abstract Timer getVibratorOnTimer();
/**
@@ -1229,7 +1238,7 @@
final int NU = uidStats.size();
String category = STAT_NAMES[which];
-
+
// Dump "battery" stat
dumpLine(pw, 0 /* uid */, category, BATTERY_DATA,
which == STATS_SINCE_CHARGED ? getStartCount() : "N/A",
@@ -1417,22 +1426,31 @@
}
}
+ Timer fgTimer = u.getForegroundActivityTimer();
+ if (fgTimer != null) {
+ // Convert from microseconds to milliseconds with rounding
+ long totalTime = (fgTimer.getTotalTimeLocked(batteryRealtime, which) + 500) / 1000;
+ int count = fgTimer.getCountLocked(which);
+ if (totalTime != 0) {
+ dumpLine(pw, uid, category, FOREGROUND_DATA, totalTime, count);
+ }
+ }
+
Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
if (processStats.size() > 0) {
for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
: processStats.entrySet()) {
Uid.Proc ps = ent.getValue();
-
- long userTime = ps.getUserTime(which);
- long systemTime = ps.getSystemTime(which);
- int starts = ps.getStarts(which);
-
- if (userTime != 0 || systemTime != 0 || starts != 0) {
- dumpLine(pw, uid, category, PROCESS_DATA,
- ent.getKey(), // proc
- userTime * 10, // cpu time in ms
- systemTime * 10, // user time in ms
- starts); // process starts
+
+ final long userMillis = ps.getUserTime(which) * 10;
+ final long systemMillis = ps.getSystemTime(which) * 10;
+ final long foregroundMillis = ps.getForegroundTime(which) * 10;
+ final long starts = ps.getStarts(which);
+
+ if (userMillis != 0 || systemMillis != 0 || foregroundMillis != 0
+ || starts != 0) {
+ dumpLine(pw, uid, category, PROCESS_DATA, ent.getKey(), userMillis,
+ systemMillis, foregroundMillis, starts);
}
}
}
@@ -1961,6 +1979,24 @@
}
}
+ Timer fgTimer = u.getForegroundActivityTimer();
+ if (fgTimer != null) {
+ // Convert from microseconds to milliseconds with rounding
+ long totalTime = (fgTimer.getTotalTimeLocked(batteryRealtime, which) + 500) / 1000;
+ int count = fgTimer.getCountLocked(which);
+ if (totalTime != 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Foreground activities: ");
+ formatTimeMs(sb, totalTime);
+ sb.append("realtime (");
+ sb.append(count);
+ sb.append(" times)");
+ pw.println(sb.toString());
+ uidActivity = true;
+ }
+ }
+
Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
if (processStats.size() > 0) {
for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
@@ -1968,23 +2004,26 @@
Uid.Proc ps = ent.getValue();
long userTime;
long systemTime;
+ long foregroundTime;
int starts;
int numExcessive;
userTime = ps.getUserTime(which);
systemTime = ps.getSystemTime(which);
+ foregroundTime = ps.getForegroundTime(which);
starts = ps.getStarts(which);
numExcessive = which == STATS_SINCE_CHARGED
? ps.countExcessivePowers() : 0;
- if (userTime != 0 || systemTime != 0 || starts != 0
+ if (userTime != 0 || systemTime != 0 || foregroundTime != 0 || starts != 0
|| numExcessive != 0) {
sb.setLength(0);
sb.append(prefix); sb.append(" Proc ");
sb.append(ent.getKey()); sb.append(":\n");
sb.append(prefix); sb.append(" CPU: ");
formatTime(sb, userTime); sb.append("usr + ");
- formatTime(sb, systemTime); sb.append("krn");
+ formatTime(sb, systemTime); sb.append("krn ; ");
+ formatTime(sb, foregroundTime); sb.append("fg");
if (starts != 0) {
sb.append("\n"); sb.append(prefix); sb.append(" ");
sb.append(starts); sb.append(" proc starts");
@@ -2042,7 +2081,7 @@
sb.append(sent.getKey()); sb.append(":\n");
sb.append(prefix); sb.append(" Created for: ");
formatTimeMs(sb, startTime / 1000);
- sb.append(" uptime\n");
+ sb.append("uptime\n");
sb.append(prefix); sb.append(" Starts: ");
sb.append(starts);
sb.append(", launches: "); sb.append(launches);