summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/BatteryStats.java578
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java443
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java19
3 files changed, 860 insertions, 180 deletions
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 4dadda2..43d3a71 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -30,6 +30,7 @@ import android.content.pm.ApplicationInfo;
import android.telephony.SignalStrength;
import android.text.format.DateFormat;
import android.util.Printer;
+import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
@@ -542,6 +543,286 @@ public abstract class BatteryStats implements Parcelable {
}
}
+ public static final class LevelStepTracker {
+ public long mLastStepTime = -1;
+ public int mNumStepDurations;
+ public final long[] mStepDurations;
+
+ public LevelStepTracker(int maxLevelSteps) {
+ mStepDurations = new long[maxLevelSteps];
+ }
+
+ public LevelStepTracker(int numSteps, long[] steps) {
+ mNumStepDurations = numSteps;
+ mStepDurations = new long[numSteps];
+ System.arraycopy(steps, 0, mStepDurations, 0, numSteps);
+ }
+
+ public long getDurationAt(int index) {
+ return mStepDurations[index] & STEP_LEVEL_TIME_MASK;
+ }
+
+ public int getLevelAt(int index) {
+ return (int)((mStepDurations[index] & STEP_LEVEL_LEVEL_MASK)
+ >> STEP_LEVEL_LEVEL_SHIFT);
+ }
+
+ public int getInitModeAt(int index) {
+ return (int)((mStepDurations[index] & STEP_LEVEL_INITIAL_MODE_MASK)
+ >> STEP_LEVEL_INITIAL_MODE_SHIFT);
+ }
+
+ public int getModModeAt(int index) {
+ return (int)((mStepDurations[index] & STEP_LEVEL_MODIFIED_MODE_MASK)
+ >> STEP_LEVEL_MODIFIED_MODE_SHIFT);
+ }
+
+ private void appendHex(long val, int topOffset, StringBuilder out) {
+ boolean hasData = false;
+ while (topOffset >= 0) {
+ int digit = (int)( (val>>topOffset) & 0xf );
+ topOffset -= 4;
+ if (!hasData && digit == 0) {
+ continue;
+ }
+ hasData = true;
+ if (digit >= 0 && digit <= 9) {
+ out.append((char)('0' + digit));
+ } else {
+ out.append((char)('a' + digit - 10));
+ }
+ }
+ }
+
+ public void encodeEntryAt(int index, StringBuilder out) {
+ long item = mStepDurations[index];
+ long duration = item & STEP_LEVEL_TIME_MASK;
+ int level = (int)((item & STEP_LEVEL_LEVEL_MASK)
+ >> STEP_LEVEL_LEVEL_SHIFT);
+ int initMode = (int)((item & STEP_LEVEL_INITIAL_MODE_MASK)
+ >> STEP_LEVEL_INITIAL_MODE_SHIFT);
+ int modMode = (int)((item & STEP_LEVEL_MODIFIED_MODE_MASK)
+ >> STEP_LEVEL_MODIFIED_MODE_SHIFT);
+ switch ((initMode&STEP_LEVEL_MODE_SCREEN_STATE) + 1) {
+ case Display.STATE_OFF: out.append('f'); break;
+ case Display.STATE_ON: out.append('o'); break;
+ case Display.STATE_DOZE: out.append('d'); break;
+ case Display.STATE_DOZE_SUSPEND: out.append('z'); break;
+ }
+ if ((initMode&STEP_LEVEL_MODE_POWER_SAVE) != 0) {
+ out.append('p');
+ }
+ switch ((modMode&STEP_LEVEL_MODE_SCREEN_STATE) + 1) {
+ case Display.STATE_OFF: out.append('F'); break;
+ case Display.STATE_ON: out.append('O'); break;
+ case Display.STATE_DOZE: out.append('D'); break;
+ case Display.STATE_DOZE_SUSPEND: out.append('Z'); break;
+ }
+ if ((modMode&STEP_LEVEL_MODE_POWER_SAVE) != 0) {
+ out.append('P');
+ }
+ out.append('-');
+ appendHex(level, 4, out);
+ out.append('-');
+ appendHex(duration, STEP_LEVEL_LEVEL_SHIFT-4, out);
+ }
+
+ public void decodeEntryAt(int index, String value) {
+ final int N = value.length();
+ int i = 0;
+ char c;
+ long out = 0;
+ while (i < N && (c=value.charAt(i)) != '-') {
+ i++;
+ switch (c) {
+ case 'f': out |= ((Display.STATE_OFF-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT); break;
+ case 'o': out |= ((Display.STATE_ON-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT); break;
+ case 'd': out |= ((Display.STATE_DOZE-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT); break;
+ case 'z': out |= ((Display.STATE_DOZE_SUSPEND-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT);
+ break;
+ case 'p': out |= (STEP_LEVEL_MODE_POWER_SAVE<<STEP_LEVEL_INITIAL_MODE_SHIFT);
+ break;
+ case 'F': out |= ((Display.STATE_OFF-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT); break;
+ case 'O': out |= ((Display.STATE_ON-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT); break;
+ case 'D': out |= ((Display.STATE_DOZE-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT); break;
+ case 'Z': out |= ((Display.STATE_DOZE_SUSPEND-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
+ break;
+ case 'P': out |= (STEP_LEVEL_MODE_POWER_SAVE<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
+ break;
+ }
+ }
+ i++;
+ int level = 0;
+ while (i < N && (c=value.charAt(i)) != '-') {
+ i++;
+ level <<= 4;
+ if (c >= '0' && c <= '9') {
+ level += c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ level += c - 'a' + 10;
+ } else if (c >= 'A' && c <= 'F') {
+ level += c - 'A' + 10;
+ }
+ }
+ out |= (level << STEP_LEVEL_LEVEL_SHIFT) & STEP_LEVEL_LEVEL_MASK;
+ long duration = 0;
+ while (i < N && (c=value.charAt(i)) != '-') {
+ i++;
+ duration <<= 4;
+ if (c >= '0' && c <= '9') {
+ duration += c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ duration += c - 'a' + 10;
+ } else if (c >= 'A' && c <= 'F') {
+ duration += c - 'A' + 10;
+ }
+ }
+ mStepDurations[index] = out | (duration & STEP_LEVEL_TIME_MASK);
+ }
+
+ public void init() {
+ mLastStepTime = -1;
+ mNumStepDurations = 0;
+ }
+
+ public void clearTime() {
+ mLastStepTime = -1;
+ }
+
+ public long computeTimePerLevel() {
+ final long[] steps = mStepDurations;
+ final int numSteps = mNumStepDurations;
+
+ // For now we'll do a simple average across all steps.
+ if (numSteps <= 0) {
+ return -1;
+ }
+ long total = 0;
+ for (int i=0; i<numSteps; i++) {
+ total += steps[i] & STEP_LEVEL_TIME_MASK;
+ }
+ return total / numSteps;
+ /*
+ long[] buckets = new long[numSteps];
+ int numBuckets = 0;
+ int numToAverage = 4;
+ int i = 0;
+ while (i < numSteps) {
+ long totalTime = 0;
+ int num = 0;
+ for (int j=0; j<numToAverage && (i+j)<numSteps; j++) {
+ totalTime += steps[i+j] & STEP_LEVEL_TIME_MASK;
+ num++;
+ }
+ buckets[numBuckets] = totalTime / num;
+ numBuckets++;
+ numToAverage *= 2;
+ i += num;
+ }
+ if (numBuckets < 1) {
+ return -1;
+ }
+ long averageTime = buckets[numBuckets-1];
+ for (i=numBuckets-2; i>=0; i--) {
+ averageTime = (averageTime + buckets[i]) / 2;
+ }
+ return averageTime;
+ */
+ }
+
+ public long computeTimeEstimate(long modesOfInterest, long modeValues,
+ int[] outNumOfInterest) {
+ final long[] steps = mStepDurations;
+ final int count = mNumStepDurations;
+ if (count <= 0) {
+ return -1;
+ }
+ long total = 0;
+ int numOfInterest = 0;
+ for (int i=0; i<count; i++) {
+ long initMode = (steps[i] & STEP_LEVEL_INITIAL_MODE_MASK)
+ >> STEP_LEVEL_INITIAL_MODE_SHIFT;
+ long modMode = (steps[i] & STEP_LEVEL_MODIFIED_MODE_MASK)
+ >> STEP_LEVEL_MODIFIED_MODE_SHIFT;
+ // If the modes of interest didn't change during this step period...
+ if ((modMode&modesOfInterest) == 0) {
+ // And the mode values during this period match those we are measuring...
+ if ((initMode&modesOfInterest) == modeValues) {
+ // Then this can be used to estimate the total time!
+ numOfInterest++;
+ total += steps[i] & STEP_LEVEL_TIME_MASK;
+ }
+ }
+ }
+ if (numOfInterest <= 0) {
+ return -1;
+ }
+
+ if (outNumOfInterest != null) {
+ outNumOfInterest[0] = numOfInterest;
+ }
+
+ // The estimated time is the average time we spend in each level, multipled
+ // by 100 -- the total number of battery levels
+ return (total / numOfInterest) * 100;
+ }
+
+ public void addLevelSteps(int numStepLevels, long modeBits, long elapsedRealtime) {
+ int stepCount = mNumStepDurations;
+ final long lastStepTime = mLastStepTime;
+ if (lastStepTime >= 0 && numStepLevels > 0) {
+ final long[] steps = mStepDurations;
+ long duration = elapsedRealtime - lastStepTime;
+ for (int i=0; i<numStepLevels; i++) {
+ System.arraycopy(steps, 0, steps, 1, steps.length-1);
+ long thisDuration = duration / (numStepLevels-i);
+ duration -= thisDuration;
+ if (thisDuration > STEP_LEVEL_TIME_MASK) {
+ thisDuration = STEP_LEVEL_TIME_MASK;
+ }
+ steps[0] = thisDuration | modeBits;
+ }
+ stepCount += numStepLevels;
+ if (stepCount > steps.length) {
+ stepCount = steps.length;
+ }
+ }
+ mNumStepDurations = stepCount;
+ mLastStepTime = elapsedRealtime;
+ }
+
+ public void readFromParcel(Parcel in) {
+ final int N = in.readInt();
+ mNumStepDurations = N;
+ for (int i=0; i<N; i++) {
+ mStepDurations[i] = in.readLong();
+ }
+ }
+
+ public void writeToParcel(Parcel out) {
+ final int N = mNumStepDurations;
+ out.writeInt(N);
+ for (int i=0; i<N; i++) {
+ out.writeLong(mStepDurations[i]);
+ }
+ }
+ }
+
+ public static final class DailyItem {
+ public long mStartTime;
+ public long mEndTime;
+ public LevelStepTracker mDischargeSteps;
+ public LevelStepTracker mChargeSteps;
+ }
+
+ public abstract DailyItem getDailyItemLocked(int daysAgo);
+
+ public abstract long getCurrentDailyStartTime();
+
+ public abstract long getNextMinDailyDeadline();
+
+ public abstract long getNextMaxDailyDeadline();
+
public final static class HistoryTag {
public String string;
public int uid;
@@ -1724,15 +2005,15 @@ public abstract class BatteryStats implements Parcelable {
// Bits in a step duration that are the new battery level we are at.
public static final long STEP_LEVEL_LEVEL_MASK = 0x0000ff0000000000L;
- public static final long STEP_LEVEL_LEVEL_SHIFT = 40;
+ public static final int STEP_LEVEL_LEVEL_SHIFT = 40;
// Bits in a step duration that are the initial mode we were in at that step.
public static final long STEP_LEVEL_INITIAL_MODE_MASK = 0x00ff000000000000L;
- public static final long STEP_LEVEL_INITIAL_MODE_SHIFT = 48;
+ public static final int STEP_LEVEL_INITIAL_MODE_SHIFT = 48;
// Bits in a step duration that indicate which modes changed during that step.
public static final long STEP_LEVEL_MODIFIED_MODE_MASK = 0xff00000000000000L;
- public static final long STEP_LEVEL_MODIFIED_MODE_SHIFT = 56;
+ public static final int STEP_LEVEL_MODIFIED_MODE_SHIFT = 56;
// Step duration mode: the screen is on, off, dozed, etc; value is Display.STATE_* - 1.
public static final int STEP_LEVEL_MODE_SCREEN_STATE = 0x03;
@@ -1740,17 +2021,56 @@ public abstract class BatteryStats implements Parcelable {
// Step duration mode: power save is on.
public static final int STEP_LEVEL_MODE_POWER_SAVE = 0x04;
+ public static final int[] STEP_LEVEL_MODES_OF_INTEREST = new int[] {
+ STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+ STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+ STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+ STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+ STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+ STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+ STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+ STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+ };
+ public static final int[] STEP_LEVEL_MODE_VALUES = new int[] {
+ (Display.STATE_OFF-1),
+ (Display.STATE_OFF-1)|STEP_LEVEL_MODE_POWER_SAVE,
+ (Display.STATE_ON-1),
+ (Display.STATE_ON-1)|STEP_LEVEL_MODE_POWER_SAVE,
+ (Display.STATE_DOZE-1),
+ (Display.STATE_DOZE-1)|STEP_LEVEL_MODE_POWER_SAVE,
+ (Display.STATE_DOZE_SUSPEND-1),
+ (Display.STATE_DOZE_SUSPEND-1)|STEP_LEVEL_MODE_POWER_SAVE,
+ };
+ public static final String[] STEP_LEVEL_MODE_LABELS = new String[] {
+ "screen off",
+ "screen off power save",
+ "screen on",
+ "screen on power save",
+ "screen doze",
+ "screen doze power save",
+ "screen doze-suspend",
+ "screen doze-suspend power save",
+ };
+ public static final String[] STEP_LEVEL_MODE_TAGS = new String[] {
+ "off",
+ "off-save",
+ "on",
+ "on-save",
+ "doze",
+ "doze-save",
+ "susp",
+ "susp-save",
+ };
+
/**
- * Return the historical number of discharge steps we currently have.
+ * Return the array of discharge step durations.
*/
- public abstract int getNumDischargeStepDurations();
+ public abstract LevelStepTracker getDischargeLevelStepTracker();
/**
- * Return the array of discharge step durations; the number of valid
- * items in it is returned by {@link #getNumDischargeStepDurations()}.
- * These values are in milliseconds.
+ * Return the array of daily discharge step durations.
*/
- public abstract long[] getDischargeStepDurationsArray();
+ public abstract LevelStepTracker getDailyDischargeLevelStepTracker();
/**
* Compute an approximation for how much time (in microseconds) remains until the battery
@@ -1763,16 +2083,14 @@ public abstract class BatteryStats implements Parcelable {
public abstract long computeChargeTimeRemaining(long curTime);
/**
- * Return the historical number of charge steps we currently have.
+ * Return the array of charge step durations.
*/
- public abstract int getNumChargeStepDurations();
+ public abstract LevelStepTracker getChargeLevelStepTracker();
/**
- * Return the array of charge step durations; the number of valid
- * items in it is returned by {@link #getNumChargeStepDurations()}.
- * These values are in milliseconds.
+ * Return the array of daily charge step durations.
*/
- public abstract long[] getChargeStepDurationsArray();
+ public abstract LevelStepTracker getDailyChargeLevelStepTracker();
public abstract Map<String, ? extends Timer> getWakeupReasonStats();
@@ -3913,47 +4231,27 @@ public abstract class BatteryStats implements Parcelable {
pw.print(suffix);
}
- private static boolean dumpTimeEstimate(PrintWriter pw, String label, long[] steps,
- int count, long modesOfInterest, long modeValues) {
- if (count <= 0) {
+ private static boolean dumpTimeEstimate(PrintWriter pw, String label1, String label2,
+ String label3, long estimatedTime) {
+ if (estimatedTime < 0) {
return false;
}
- long total = 0;
- int numOfInterest = 0;
- for (int i=0; i<count; i++) {
- long initMode = (steps[i] & STEP_LEVEL_INITIAL_MODE_MASK)
- >> STEP_LEVEL_INITIAL_MODE_SHIFT;
- long modMode = (steps[i] & STEP_LEVEL_MODIFIED_MODE_MASK)
- >> STEP_LEVEL_MODIFIED_MODE_SHIFT;
- // If the modes of interest didn't change during this step period...
- if ((modMode&modesOfInterest) == 0) {
- // And the mode values during this period match those we are measuring...
- if ((initMode&modesOfInterest) == modeValues) {
- // Then this can be used to estimate the total time!
- numOfInterest++;
- total += steps[i] & STEP_LEVEL_TIME_MASK;
- }
- }
- }
- if (numOfInterest <= 0) {
- return false;
- }
-
- // The estimated time is the average time we spend in each level, multipled
- // by 100 -- the total number of battery levels
- long estimatedTime = (total / numOfInterest) * 100;
-
- pw.print(label);
+ pw.print(label1);
+ pw.print(label2);
+ pw.print(label3);
StringBuilder sb = new StringBuilder(64);
formatTimeMs(sb, estimatedTime);
pw.print(sb);
pw.println();
-
return true;
}
- private static boolean dumpDurationSteps(PrintWriter pw, String header, long[] steps,
- int count, boolean checkin) {
+ private static boolean dumpDurationSteps(PrintWriter pw, String prefix, String header,
+ LevelStepTracker steps, boolean checkin) {
+ if (steps == null) {
+ return false;
+ }
+ int count = steps.mNumStepDurations;
if (count <= 0) {
return false;
}
@@ -3962,13 +4260,10 @@ public abstract class BatteryStats implements Parcelable {
}
String[] lineArgs = new String[4];
for (int i=0; i<count; i++) {
- long duration = steps[i] & STEP_LEVEL_TIME_MASK;
- int level = (int)((steps[i] & STEP_LEVEL_LEVEL_MASK)
- >> STEP_LEVEL_LEVEL_SHIFT);
- long initMode = (steps[i] & STEP_LEVEL_INITIAL_MODE_MASK)
- >> STEP_LEVEL_INITIAL_MODE_SHIFT;
- long modMode = (steps[i] & STEP_LEVEL_MODIFIED_MODE_MASK)
- >> STEP_LEVEL_MODIFIED_MODE_SHIFT;
+ long duration = steps.getDurationAt(i);
+ int level = steps.getLevelAt(i);
+ long initMode = steps.getInitModeAt(i);
+ long modMode = steps.getModModeAt(i);
if (checkin) {
lineArgs[0] = Long.toString(duration);
lineArgs[1] = Integer.toString(level);
@@ -3990,7 +4285,8 @@ public abstract class BatteryStats implements Parcelable {
}
dumpLine(pw, 0 /* uid */, "i" /* category */, header, (Object[])lineArgs);
} else {
- pw.print(" #"); pw.print(i); pw.print(": ");
+ pw.print(prefix);
+ pw.print("#"); pw.print(i); pw.print(": ");
TimeUtils.formatDuration(duration, pw);
pw.print(" to "); pw.print(level);
boolean haveModes = false;
@@ -4022,10 +4318,11 @@ public abstract class BatteryStats implements Parcelable {
public static final int DUMP_UNPLUGGED_ONLY = 1<<0;
public static final int DUMP_CHARGED_ONLY = 1<<1;
- public static final int DUMP_HISTORY_ONLY = 1<<2;
- public static final int DUMP_INCLUDE_HISTORY = 1<<3;
- public static final int DUMP_VERBOSE = 1<<4;
- public static final int DUMP_DEVICE_WIFI_ONLY = 1<<5;
+ public static final int DUMP_DAILY_ONLY = 1<<2;
+ public static final int DUMP_HISTORY_ONLY = 1<<3;
+ public static final int DUMP_INCLUDE_HISTORY = 1<<4;
+ public static final int DUMP_VERBOSE = 1<<5;
+ public static final int DUMP_DEVICE_WIFI_ONLY = 1<<6;
private void dumpHistoryLocked(PrintWriter pw, int flags, long histStart, boolean checkin) {
final HistoryPrinter hprinter = new HistoryPrinter();
@@ -4111,6 +4408,36 @@ public abstract class BatteryStats implements Parcelable {
}
}
+ private void dumpDailyLevelStepSummary(PrintWriter pw, String prefix, String label,
+ LevelStepTracker steps, StringBuilder tmpSb, int[] tmpOutInt) {
+ if (steps == null) {
+ return;
+ }
+ long timeRemaining = steps.computeTimeEstimate(0, 0, tmpOutInt);
+ if (timeRemaining >= 0) {
+ pw.print(prefix); pw.print(label); pw.print(" total time: ");
+ tmpSb.setLength(0);
+ formatTimeMs(tmpSb, timeRemaining);
+ pw.print(tmpSb);
+ pw.print(" (from "); pw.print(tmpOutInt[0]);
+ pw.println(" steps)");
+ }
+ for (int i=0; i< STEP_LEVEL_MODES_OF_INTEREST.length; i++) {
+ long estimatedTime = steps.computeTimeEstimate(STEP_LEVEL_MODES_OF_INTEREST[i],
+ STEP_LEVEL_MODE_VALUES[i], tmpOutInt);
+ if (estimatedTime > 0) {
+ pw.print(prefix); pw.print(label); pw.print(" ");
+ pw.print(STEP_LEVEL_MODE_LABELS[i]);
+ pw.print(" time: ");
+ tmpSb.setLength(0);
+ formatTimeMs(tmpSb, estimatedTime);
+ pw.print(tmpSb);
+ pw.print(" (from "); pw.print(tmpOutInt[0]);
+ pw.println(" steps)");
+ }
+ }
+ }
+
/**
* Dumps a human-readable summary of the battery statistics to the given PrintWriter.
*
@@ -4120,8 +4447,8 @@ public abstract class BatteryStats implements Parcelable {
public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
prepareForDumpLocked();
- final boolean filtering =
- (flags&(DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) != 0;
+ final boolean filtering = (flags
+ & (DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
if ((flags&DUMP_HISTORY_ONLY) != 0 || !filtering) {
final long historyTotalSize = getHistoryTotalSize();
@@ -4165,7 +4492,7 @@ public abstract class BatteryStats implements Parcelable {
}
}
- if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) == 0) {
+ if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
return;
}
@@ -4199,50 +4526,24 @@ public abstract class BatteryStats implements Parcelable {
}
if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
- if (dumpDurationSteps(pw, "Discharge step durations:", getDischargeStepDurationsArray(),
- getNumDischargeStepDurations(), false)) {
+ if (dumpDurationSteps(pw, " ", "Discharge step durations:",
+ getDischargeLevelStepTracker(), false)) {
long timeRemaining = computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
if (timeRemaining >= 0) {
pw.print(" Estimated discharge time remaining: ");
TimeUtils.formatDuration(timeRemaining / 1000, pw);
pw.println();
}
- dumpTimeEstimate(pw, " Estimated screen off time: ",
- getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
- STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
- (Display.STATE_OFF-1));
- dumpTimeEstimate(pw, " Estimated screen off power save time: ",
- getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
- STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
- (Display.STATE_OFF-1)|STEP_LEVEL_MODE_POWER_SAVE);
- dumpTimeEstimate(pw, " Estimated screen on time: ",
- getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
- STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
- (Display.STATE_ON-1));
- dumpTimeEstimate(pw, " Estimated screen on power save time: ",
- getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
- STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
- (Display.STATE_ON-1)|STEP_LEVEL_MODE_POWER_SAVE);
- dumpTimeEstimate(pw, " Estimated screen doze time: ",
- getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
- STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
- (Display.STATE_DOZE-1));
- dumpTimeEstimate(pw, " Estimated screen doze power save time: ",
- getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
- STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
- (Display.STATE_DOZE-1)|STEP_LEVEL_MODE_POWER_SAVE);
- dumpTimeEstimate(pw, " Estimated screen doze suspend time: ",
- getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
- STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
- (Display.STATE_DOZE_SUSPEND-1));
- dumpTimeEstimate(pw, " Estimated screen doze suspend power save time: ",
- getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
- STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
- (Display.STATE_DOZE_SUSPEND-1)|STEP_LEVEL_MODE_POWER_SAVE);
+ final LevelStepTracker steps = getDischargeLevelStepTracker();
+ for (int i=0; i< STEP_LEVEL_MODES_OF_INTEREST.length; i++) {
+ dumpTimeEstimate(pw, " Estimated ", STEP_LEVEL_MODE_LABELS[i], " time: ",
+ steps.computeTimeEstimate(STEP_LEVEL_MODES_OF_INTEREST[i],
+ STEP_LEVEL_MODE_VALUES[i], null));
+ }
pw.println();
}
- if (dumpDurationSteps(pw, "Charge step durations:", getChargeStepDurationsArray(),
- getNumChargeStepDurations(), false)) {
+ if (dumpDurationSteps(pw, " ", "Charge step durations:",
+ getChargeLevelStepTracker(), false)) {
long timeRemaining = computeChargeTimeRemaining(SystemClock.elapsedRealtime());
if (timeRemaining >= 0) {
pw.print(" Estimated charge time remaining: ");
@@ -4251,6 +4552,75 @@ public abstract class BatteryStats implements Parcelable {
}
pw.println();
}
+ }
+ if (!filtering || (flags&(DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0) {
+ pw.println("Daily stats:");
+ pw.print(" Current start time: ");
+ pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+ getCurrentDailyStartTime()).toString());
+ pw.print(" Next min deadline: ");
+ pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+ getNextMinDailyDeadline()).toString());
+ pw.print(" Next max deadline: ");
+ pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+ getNextMaxDailyDeadline()).toString());
+ StringBuilder sb = new StringBuilder(64);
+ int[] outInt = new int[1];
+ LevelStepTracker dsteps = getDailyDischargeLevelStepTracker();
+ LevelStepTracker csteps = getDailyChargeLevelStepTracker();
+ if (dsteps.mNumStepDurations > 0 || csteps.mNumStepDurations > 0) {
+ if ((flags&DUMP_DAILY_ONLY) != 0) {
+ if (dumpDurationSteps(pw, " ", " Current daily discharge step durations:",
+ dsteps, false)) {
+ dumpDailyLevelStepSummary(pw, " ", "Discharge", dsteps,
+ sb, outInt);
+ }
+ if (dumpDurationSteps(pw, " ", " Current daily charge step durations:",
+ csteps, false)) {
+ dumpDailyLevelStepSummary(pw, " ", "Charge", csteps,
+ sb, outInt);
+ }
+ } else {
+ pw.println(" Current daily steps:");
+ dumpDailyLevelStepSummary(pw, " ", "Discharge", dsteps,
+ sb, outInt);
+ dumpDailyLevelStepSummary(pw, " ", "Charge", csteps,
+ sb, outInt);
+ }
+ }
+ DailyItem dit;
+ int curIndex = 0;
+ while ((dit=getDailyItemLocked(curIndex)) != null) {
+ curIndex++;
+ if ((flags&DUMP_DAILY_ONLY) != 0) {
+ pw.println();
+ }
+ pw.print(" Daily from ");
+ pw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", dit.mStartTime).toString());
+ pw.print(" to ");
+ pw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", dit.mEndTime).toString());
+ pw.println(":");
+ if ((flags&DUMP_DAILY_ONLY) != 0) {
+ if (dumpDurationSteps(pw, " ",
+ " Discharge step durations:", dit.mDischargeSteps, false)) {
+ dumpDailyLevelStepSummary(pw, " ", "Discharge", dit.mDischargeSteps,
+ sb, outInt);
+ }
+ if (dumpDurationSteps(pw, " ",
+ " Charge step durations:", dit.mChargeSteps, false)) {
+ dumpDailyLevelStepSummary(pw, " ", "Charge", dit.mChargeSteps,
+ sb, outInt);
+ }
+ } else {
+ dumpDailyLevelStepSummary(pw, " ", "Discharge", dit.mDischargeSteps,
+ sb, outInt);
+ dumpDailyLevelStepSummary(pw, " ", "Charge", dit.mChargeSteps,
+ sb, outInt);
+ }
+ }
+ pw.println();
+ }
+ if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
pw.println("Statistics since last charge:");
pw.println(" System starts: " + getStartCount()
+ ", currently on battery: " + getIsOnBattery());
@@ -4275,8 +4645,8 @@ public abstract class BatteryStats implements Parcelable {
long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
- final boolean filtering =
- (flags&(DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) != 0;
+ final boolean filtering = (flags &
+ (DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
if ((flags&DUMP_INCLUDE_HISTORY) != 0 || (flags&DUMP_HISTORY_ONLY) != 0) {
if (startIteratingHistoryLocked()) {
@@ -4302,7 +4672,7 @@ public abstract class BatteryStats implements Parcelable {
}
}
- if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) == 0) {
+ if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
return;
}
@@ -4334,8 +4704,7 @@ public abstract class BatteryStats implements Parcelable {
}
}
if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
- dumpDurationSteps(pw, DISCHARGE_STEP_DATA, getDischargeStepDurationsArray(),
- getNumDischargeStepDurations(), true);
+ dumpDurationSteps(pw, "", DISCHARGE_STEP_DATA, getDischargeLevelStepTracker(), true);
String[] lineArgs = new String[1];
long timeRemaining = computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
if (timeRemaining >= 0) {
@@ -4343,8 +4712,7 @@ public abstract class BatteryStats implements Parcelable {
dumpLine(pw, 0 /* uid */, "i" /* category */, DISCHARGE_TIME_REMAIN_DATA,
(Object[])lineArgs);
}
- dumpDurationSteps(pw, CHARGE_STEP_DATA, getChargeStepDurationsArray(),
- getNumChargeStepDurations(), true);
+ dumpDurationSteps(pw, "", CHARGE_STEP_DATA, getChargeLevelStepTracker(), true);
timeRemaining = computeChargeTimeRemaining(SystemClock.elapsedRealtime());
if (timeRemaining >= 0) {
lineArgs[0] = Long.toString(timeRemaining);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index d0c7f8c..f6c5dc7 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -56,20 +56,29 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
+import android.util.Xml;
import android.view.Display;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -94,7 +103,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 118 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 119 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -111,6 +120,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private final JournaledFile mFile;
public final AtomicFile mCheckinFile;
+ public final AtomicFile mDailyFile;
static final int MSG_UPDATE_WAKELOCKS = 1;
static final int MSG_REPORT_POWER_CHANGE = 2;
@@ -386,16 +396,22 @@ public final class BatteryStatsImpl extends BatteryStats {
int mModStepMode = 0;
int mLastDischargeStepLevel;
- long mLastDischargeStepTime;
int mMinDischargeStepLevel;
- int mNumDischargeStepDurations;
- final long[] mDischargeStepDurations = new long[MAX_LEVEL_STEPS];
+ final LevelStepTracker mDischargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS);
+ final LevelStepTracker mDailyDischargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS*2);
int mLastChargeStepLevel;
- long mLastChargeStepTime;
int mMaxChargeStepLevel;
- int mNumChargeStepDurations;
- final long[] mChargeStepDurations = new long[MAX_LEVEL_STEPS];
+ final LevelStepTracker mChargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS);
+ final LevelStepTracker mDailyChargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS*2);
+
+ static final int MAX_DAILY_ITEMS = 10;
+
+ long mDailyStartTime = 0;
+ long mNextMinDailyDeadline = 0;
+ long mNextMaxDailyDeadline = 0;
+
+ final ArrayList<DailyItem> mDailyItems = new ArrayList<>();
long mLastWriteTime = 0; // Milliseconds
@@ -478,6 +494,7 @@ public final class BatteryStatsImpl extends BatteryStats {
public BatteryStatsImpl() {
mFile = null;
mCheckinFile = null;
+ mDailyFile = null;
mHandler = null;
clearHistoryLocked();
}
@@ -3199,6 +3216,7 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteScreenStateLocked(int state) {
if (mScreenState != state) {
+ recordDailyStatsIfNeededLocked(true);
final int oldState = mScreenState;
mScreenState = state;
if (DEBUG) Slog.v(TAG, "Screen state: oldState=" + Display.stateToString(oldState)
@@ -6594,6 +6612,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mFile = null;
}
mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin"));
+ mDailyFile = new AtomicFile(new File(systemDir, "batterystats-daily.xml"));
mHandler = new MyHandler(handler.getLooper());
mStartCount++;
mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase);
@@ -6652,11 +6671,13 @@ public final class BatteryStatsImpl extends BatteryStats {
mCurrentBatteryLevel = 0;
initDischarge();
clearHistoryLocked();
+ updateDailyDeadlineLocked();
}
public BatteryStatsImpl(Parcel p) {
mFile = null;
mCheckinFile = null;
+ mDailyFile = null;
mHandler = null;
clearHistoryLocked();
readFromParcel(p);
@@ -6676,6 +6697,286 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ public void updateDailyDeadlineLocked() {
+ // Get the current time.
+ long currentTime = mDailyStartTime = System.currentTimeMillis();
+ Calendar calDeadline = Calendar.getInstance();
+ calDeadline.setTimeInMillis(currentTime);
+
+ // Move time up to the next day, ranging from 1am to 3pm.
+ calDeadline.set(Calendar.DAY_OF_YEAR, calDeadline.get(Calendar.DAY_OF_YEAR) + 1);
+ calDeadline.set(Calendar.MILLISECOND, 0);
+ calDeadline.set(Calendar.SECOND, 0);
+ calDeadline.set(Calendar.MINUTE, 0);
+ calDeadline.set(Calendar.HOUR_OF_DAY, 1);
+ mNextMinDailyDeadline = calDeadline.getTimeInMillis();
+ calDeadline.set(Calendar.HOUR_OF_DAY, 3);
+ mNextMaxDailyDeadline = calDeadline.getTimeInMillis();
+ }
+
+ public void recordDailyStatsIfNeededLocked(boolean settled) {
+ long currentTime = System.currentTimeMillis();
+ if (currentTime >= mNextMaxDailyDeadline) {
+ recordDailyStatsLocked();
+ } else if (settled && currentTime >= mNextMinDailyDeadline) {
+ recordDailyStatsLocked();
+ } else if (currentTime < (mDailyStartTime-(1000*60*60*24))) {
+ recordDailyStatsLocked();
+ }
+ }
+
+ public void recordDailyStatsLocked() {
+ DailyItem item = new DailyItem();
+ item.mStartTime = mDailyStartTime;
+ item.mEndTime = System.currentTimeMillis();
+ boolean hasData = false;
+ if (mDailyDischargeStepTracker.mNumStepDurations > 0) {
+ hasData = true;
+ item.mDischargeSteps = new LevelStepTracker(
+ mDailyDischargeStepTracker.mNumStepDurations,
+ mDailyDischargeStepTracker.mStepDurations);
+ }
+ if (mDailyChargeStepTracker.mNumStepDurations > 0) {
+ hasData = true;
+ item.mChargeSteps = new LevelStepTracker(
+ mDailyChargeStepTracker.mNumStepDurations,
+ mDailyChargeStepTracker.mStepDurations);
+ }
+ mDailyDischargeStepTracker.init();
+ mDailyChargeStepTracker.init();
+ updateDailyDeadlineLocked();
+
+ if (hasData) {
+ mDailyItems.add(item);
+ while (mDailyItems.size() > MAX_DAILY_ITEMS) {
+ mDailyItems.remove(0);
+ }
+ final ByteArrayOutputStream memStream = new ByteArrayOutputStream();
+ try {
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(memStream, "utf-8");
+ writeDailyItemsLocked(out);
+ BackgroundThread.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mCheckinFile) {
+ FileOutputStream stream = null;
+ try {
+ stream = mDailyFile.startWrite();
+ memStream.writeTo(stream);
+ stream.flush();
+ FileUtils.sync(stream);
+ stream.close();
+ mDailyFile.finishWrite(stream);
+ } catch (IOException e) {
+ Slog.w("BatteryStats",
+ "Error writing battery daily items", e);
+ mDailyFile.failWrite(stream);
+ }
+ }
+ }
+ });
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ private void writeDailyItemsLocked(XmlSerializer out) throws IOException {
+ StringBuilder sb = new StringBuilder(64);
+ out.startDocument(null, true);
+ out.startTag(null, "daily-items");
+ for (int i=0; i<mDailyItems.size(); i++) {
+ final DailyItem dit = mDailyItems.get(i);
+ out.startTag(null, "item");
+ out.attribute(null, "start", Long.toString(dit.mStartTime));
+ out.attribute(null, "end", Long.toString(dit.mEndTime));
+ writeDailyLevelSteps(out, "dis", dit.mDischargeSteps, sb);
+ writeDailyLevelSteps(out, "chg", dit.mChargeSteps, sb);
+ out.endTag(null, "item");
+ }
+ out.endTag(null, "daily-items");
+ out.endDocument();
+ }
+
+ private void writeDailyLevelSteps(XmlSerializer out, String tag, LevelStepTracker steps,
+ StringBuilder tmpBuilder) throws IOException {
+ if (steps != null) {
+ out.startTag(null, tag);
+ out.attribute(null, "n", Integer.toString(steps.mNumStepDurations));
+ for (int i=0; i<steps.mNumStepDurations; i++) {
+ out.startTag(null, "s");
+ tmpBuilder.setLength(0);
+ steps.encodeEntryAt(i, tmpBuilder);
+ out.attribute(null, "v", tmpBuilder.toString());
+ out.endTag(null, "s");
+ }
+ out.endTag(null, tag);
+ }
+ }
+
+ public void readDailyStatsLocked() {
+ Slog.d(TAG, "Reading daily items from " + mDailyFile.getBaseFile());
+ mDailyItems.clear();
+ FileInputStream stream;
+ try {
+ stream = mDailyFile.openRead();
+ } catch (FileNotFoundException e) {
+ return;
+ }
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, null);
+ readDailyItemsLocked(parser);
+ } catch (XmlPullParserException e) {
+ } finally {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ private void readDailyItemsLocked(XmlPullParser parser) {
+ try {
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("no start tag found");
+ }
+
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("item")) {
+ readDailyItemTagLocked(parser);
+ } else {
+ Slog.w(TAG, "Unknown element under <daily-items>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ } catch (IllegalStateException e) {
+ Slog.w(TAG, "Failed parsing daily " + e);
+ } catch (NullPointerException e) {
+ Slog.w(TAG, "Failed parsing daily " + e);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Failed parsing daily " + e);
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "Failed parsing daily " + e);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed parsing daily " + e);
+ } catch (IndexOutOfBoundsException e) {
+ Slog.w(TAG, "Failed parsing daily " + e);
+ }
+ }
+
+ void readDailyItemTagLocked(XmlPullParser parser) throws NumberFormatException,
+ XmlPullParserException, IOException {
+ DailyItem dit = new DailyItem();
+ String attr = parser.getAttributeValue(null, "start");
+ if (attr != null) {
+ dit.mStartTime = Long.parseLong(attr);
+ }
+ attr = parser.getAttributeValue(null, "end");
+ if (attr != null) {
+ dit.mEndTime = Long.parseLong(attr);
+ }
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("dis")) {
+ readDailyItemTagDetailsLocked(parser, dit, false, "dis");
+ } else if (tagName.equals("chg")) {
+ readDailyItemTagDetailsLocked(parser, dit, true, "chg");
+ } else {
+ Slog.w(TAG, "Unknown element under <item>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ mDailyItems.add(dit);
+ }
+
+ void readDailyItemTagDetailsLocked(XmlPullParser parser, DailyItem dit, boolean isCharge,
+ String tag)
+ throws NumberFormatException, XmlPullParserException, IOException {
+ final String numAttr = parser.getAttributeValue(null, "n");
+ if (numAttr == null) {
+ Slog.w(TAG, "Missing 'n' attribute at " + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ return;
+ }
+ final int num = Integer.parseInt(numAttr);
+ LevelStepTracker steps = new LevelStepTracker(num);
+ if (isCharge) {
+ dit.mChargeSteps = steps;
+ } else {
+ dit.mDischargeSteps = steps;
+ }
+ int i = 0;
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if ("s".equals(tagName)) {
+ if (i < num) {
+ String valueAttr = parser.getAttributeValue(null, "v");
+ if (valueAttr != null) {
+ steps.decodeEntryAt(i, valueAttr);
+ i++;
+ }
+ }
+ } else {
+ Slog.w(TAG, "Unknown element under <" + tag + ">: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ steps.mNumStepDurations = i;
+ }
+
+ @Override
+ public DailyItem getDailyItemLocked(int daysAgo) {
+ int index = mDailyItems.size()-1-daysAgo;
+ return index >= 0 ? mDailyItems.get(index) : null;
+ }
+
+ @Override
+ public long getCurrentDailyStartTime() {
+ return mDailyStartTime;
+ }
+
+ @Override
+ public long getNextMinDailyDeadline() {
+ return mNextMinDailyDeadline;
+ }
+
+ @Override
+ public long getNextMaxDailyDeadline() {
+ return mNextMaxDailyDeadline;
+ }
+
@Override
public boolean startIteratingOldHistoryLocked() {
if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
@@ -6846,10 +7147,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mDischargeAmountScreenOnSinceCharge = 0;
mDischargeAmountScreenOff = 0;
mDischargeAmountScreenOffSinceCharge = 0;
- mLastDischargeStepTime = -1;
- mNumDischargeStepDurations = 0;
- mLastChargeStepTime = -1;
- mNumChargeStepDurations = 0;
+ mDischargeStepTracker.init();
+ mChargeStepTracker.init();
}
public void resetAllStatsCmdLocked() {
@@ -7072,12 +7371,13 @@ public final class BatteryStatsImpl extends BatteryStats {
resetAllStatsLocked();
mDischargeStartLevel = level;
reset = true;
- mNumDischargeStepDurations = 0;
+ mDischargeStepTracker.init();
}
mOnBattery = mOnBatteryInternal = true;
mLastDischargeStepLevel = level;
mMinDischargeStepLevel = level;
- mLastDischargeStepTime = -1;
+ mDischargeStepTracker.clearTime();
+ mDailyDischargeStepTracker.clearTime();
mInitStepMode = mCurStepMode;
mModStepMode = 0;
pullPendingStateUpdatesLocked();
@@ -7116,10 +7416,9 @@ public final class BatteryStatsImpl extends BatteryStats {
}
updateDischargeScreenLevelsLocked(screenOn, screenOn);
updateTimeBasesLocked(false, !screenOn, uptime, realtime);
- mNumChargeStepDurations = 0;
+ mChargeStepTracker.init();
mLastChargeStepLevel = level;
mMaxChargeStepLevel = level;
- mLastChargeStepTime = -1;
mInitStepMode = mCurStepMode;
mModStepMode = 0;
}
@@ -7171,34 +7470,12 @@ public final class BatteryStatsImpl extends BatteryStats {
// This should probably be exposed in the API, though it's not critical
private static final int BATTERY_PLUGGED_NONE = 0;
- private static int addLevelSteps(long[] steps, int stepCount, long lastStepTime,
- int numStepLevels, long modeBits, long elapsedRealtime) {
- if (lastStepTime >= 0 && numStepLevels > 0) {
- long duration = elapsedRealtime - lastStepTime;
- for (int i=0; i<numStepLevels; i++) {
- System.arraycopy(steps, 0, steps, 1, steps.length-1);
- long thisDuration = duration / (numStepLevels-i);
- duration -= thisDuration;
- if (thisDuration > STEP_LEVEL_TIME_MASK) {
- thisDuration = STEP_LEVEL_TIME_MASK;
- }
- steps[0] = thisDuration | modeBits;
- }
- stepCount += numStepLevels;
- if (stepCount > steps.length) {
- stepCount = steps.length;
- }
- }
- return stepCount;
- }
-
public void setBatteryState(int status, int health, int plugType, int level,
int temp, int volt) {
synchronized(this) {
final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
final long uptime = SystemClock.uptimeMillis();
final long elapsedRealtime = SystemClock.elapsedRealtime();
- int oldStatus = mHistoryCur.batteryStatus;
if (!mHaveBatteryLevel) {
mHaveBatteryLevel = true;
// We start out assuming that the device is plugged in (not
@@ -7212,8 +7489,14 @@ public final class BatteryStatsImpl extends BatteryStats {
mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
}
}
- oldStatus = status;
+ mHistoryCur.batteryStatus = (byte)status;
+ mHistoryCur.batteryLevel = (byte)level;
+ mMaxChargeStepLevel = mMinDischargeStepLevel =
+ mLastChargeStepLevel = mLastDischargeStepLevel = level;
+ } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) {
+ recordDailyStatsIfNeededLocked(level >= 100 && onBattery);
}
+ int oldStatus = mHistoryCur.batteryStatus;
if (onBattery) {
mDischargeCurrentLevel = level;
if (!mRecordingHistory) {
@@ -7274,23 +7557,23 @@ public final class BatteryStatsImpl extends BatteryStats {
| (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT);
if (onBattery) {
if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
- mNumDischargeStepDurations = addLevelSteps(mDischargeStepDurations,
- mNumDischargeStepDurations, mLastDischargeStepTime,
- mLastDischargeStepLevel - level, modeBits, elapsedRealtime);
+ mDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
+ modeBits, elapsedRealtime);
+ mDailyDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
+ modeBits, elapsedRealtime);
mLastDischargeStepLevel = level;
mMinDischargeStepLevel = level;
- mLastDischargeStepTime = elapsedRealtime;
mInitStepMode = mCurStepMode;
mModStepMode = 0;
}
} else {
if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
- mNumChargeStepDurations = addLevelSteps(mChargeStepDurations,
- mNumChargeStepDurations, mLastChargeStepTime,
- level - mLastChargeStepLevel, modeBits, elapsedRealtime);
+ mChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
+ modeBits, elapsedRealtime);
+ mDailyChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
+ modeBits, elapsedRealtime);
mLastChargeStepLevel = level;
mMaxChargeStepLevel = level;
- mLastChargeStepTime = elapsedRealtime;
mInitStepMode = mCurStepMode;
mModStepMode = 0;
}
@@ -7565,22 +7848,24 @@ public final class BatteryStatsImpl extends BatteryStats {
long usPerLevel = duration/discharge;
return usPerLevel * mCurrentBatteryLevel;
*/
- if (mNumDischargeStepDurations < 1) {
+ if (mDischargeStepTracker.mNumStepDurations < 1) {
return -1;
}
- long msPerLevel = computeTimePerLevel(mDischargeStepDurations, mNumDischargeStepDurations);
+ long msPerLevel = mDischargeStepTracker.computeTimePerLevel();
if (msPerLevel <= 0) {
return -1;
}
return (msPerLevel * mCurrentBatteryLevel) * 1000;
}
- public int getNumDischargeStepDurations() {
- return mNumDischargeStepDurations;
+ @Override
+ public LevelStepTracker getDischargeLevelStepTracker() {
+ return mDischargeStepTracker;
}
- public long[] getDischargeStepDurationsArray() {
- return mDischargeStepDurations;
+ @Override
+ public LevelStepTracker getDailyDischargeLevelStepTracker() {
+ return mDailyDischargeStepTracker;
}
@Override
@@ -7602,22 +7887,24 @@ public final class BatteryStatsImpl extends BatteryStats {
long usPerLevel = duration/(curLevel-plugLevel);
return usPerLevel * (100-curLevel);
*/
- if (mNumChargeStepDurations < 1) {
+ if (mChargeStepTracker.mNumStepDurations < 1) {
return -1;
}
- long msPerLevel = computeTimePerLevel(mChargeStepDurations, mNumChargeStepDurations);
+ long msPerLevel = mChargeStepTracker.computeTimePerLevel();
if (msPerLevel <= 0) {
return -1;
}
return (msPerLevel * (100-mCurrentBatteryLevel)) * 1000;
}
- public int getNumChargeStepDurations() {
- return mNumChargeStepDurations;
+ @Override
+ public LevelStepTracker getChargeLevelStepTracker() {
+ return mChargeStepTracker;
}
- public long[] getChargeStepDurationsArray() {
- return mChargeStepDurations;
+ @Override
+ public LevelStepTracker getDailyChargeLevelStepTracker() {
+ return mDailyChargeStepTracker;
}
long getBatteryUptimeLocked() {
@@ -7915,6 +8202,10 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public void readLocked() {
+ if (mDailyFile != null) {
+ readDailyStatsLocked();
+ }
+
if (mFile == null) {
Slog.w("BatteryStats", "readLocked: no file associated with this instance");
return;
@@ -7952,6 +8243,8 @@ public final class BatteryStatsImpl extends BatteryStats {
addHistoryBufferLocked(elapsedRealtime, uptime, HistoryItem.CMD_START, mHistoryCur);
startRecordingHistory(elapsedRealtime, uptime, false);
}
+
+ recordDailyStatsIfNeededLocked(false);
}
public int describeContents() {
@@ -8110,10 +8403,13 @@ public final class BatteryStatsImpl extends BatteryStats {
mHighDischargeAmountSinceCharge = in.readInt();
mDischargeAmountScreenOnSinceCharge = in.readInt();
mDischargeAmountScreenOffSinceCharge = in.readInt();
- mNumDischargeStepDurations = in.readInt();
- in.readLongArray(mDischargeStepDurations);
- mNumChargeStepDurations = in.readInt();
- in.readLongArray(mChargeStepDurations);
+ mDischargeStepTracker.readFromParcel(in);
+ mChargeStepTracker.readFromParcel(in);
+ mDailyDischargeStepTracker.readFromParcel(in);
+ mDailyChargeStepTracker.readFromParcel(in);
+ mDailyStartTime = in.readLong();
+ mNextMinDailyDeadline = in.readLong();
+ mNextMaxDailyDeadline = in.readLong();
mStartCount++;
@@ -8404,10 +8700,13 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(getHighDischargeAmountSinceCharge());
out.writeInt(getDischargeAmountScreenOnSinceCharge());
out.writeInt(getDischargeAmountScreenOffSinceCharge());
- out.writeInt(mNumDischargeStepDurations);
- out.writeLongArray(mDischargeStepDurations);
- out.writeInt(mNumChargeStepDurations);
- out.writeLongArray(mChargeStepDurations);
+ mDischargeStepTracker.writeToParcel(out);
+ mChargeStepTracker.writeToParcel(out);
+ mDailyDischargeStepTracker.writeToParcel(out);
+ mDailyChargeStepTracker.writeToParcel(out);
+ out.writeLong(mDailyStartTime);
+ out.writeLong(mNextMinDailyDeadline);
+ out.writeLong(mNextMaxDailyDeadline);
mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
@@ -8770,10 +9069,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mDischargeAmountScreenOnSinceCharge = in.readInt();
mDischargeAmountScreenOff = in.readInt();
mDischargeAmountScreenOffSinceCharge = in.readInt();
- mNumDischargeStepDurations = in.readInt();
- in.readLongArray(mDischargeStepDurations);
- mNumChargeStepDurations = in.readInt();
- in.readLongArray(mChargeStepDurations);
+ mDischargeStepTracker.readFromParcel(in);
+ mChargeStepTracker.readFromParcel(in);
mLastWriteTime = in.readLong();
mBluetoothPingCount = in.readInt();
@@ -8912,10 +9209,8 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(mDischargeAmountScreenOnSinceCharge);
out.writeInt(mDischargeAmountScreenOff);
out.writeInt(mDischargeAmountScreenOffSinceCharge);
- out.writeInt(mNumDischargeStepDurations);
- out.writeLongArray(mDischargeStepDurations);
- out.writeInt(mNumChargeStepDurations);
- out.writeLongArray(mChargeStepDurations);
+ mDischargeStepTracker.writeToParcel(out);
+ mChargeStepTracker.writeToParcel(out);
out.writeLong(mLastWriteTime);
out.writeInt(getBluetoothPingCount());
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index c0928c7..991d3fa 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -752,14 +752,17 @@ public final class BatteryStatsService extends IBatteryStats.Stub
private void dumpHelp(PrintWriter pw) {
pw.println("Battery stats (batterystats) dump options:");
pw.println(" [--checkin] [--history] [--history-start] [--unplugged] [--charged] [-c]");
- pw.println(" [--reset] [--write] [-h] [<package.name>]");
+ pw.println(" [--daily] [--reset] [--write] [--new-daily] [--read-daily] [-h] [<package.name>]");
pw.println(" --checkin: format output for a checkin report.");
pw.println(" --history: show only history data.");
pw.println(" --history-start <num>: show only history data starting at given time offset.");
pw.println(" --unplugged: only output data since last unplugged.");
pw.println(" --charged: only output data since last charged.");
+ pw.println(" --daily: only output full daily data.");
pw.println(" --reset: reset the stats, clearing all current data.");
pw.println(" --write: force write current collected stats to disk.");
+ pw.println(" --new-daily: immediately create and write new daily stats record.");
+ pw.println(" --read-daily: read-load last written daily stats.");
pw.println(" <package.name>: optional name of package to filter output by.");
pw.println(" -h: print this help text.");
pw.println("Battery stats (batterystats) commands:");
@@ -836,6 +839,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub
flags |= BatteryStats.DUMP_UNPLUGGED_ONLY;
} else if ("--charged".equals(arg)) {
flags |= BatteryStats.DUMP_CHARGED_ONLY;
+ } else if ("--daily".equals(arg)) {
+ flags |= BatteryStats.DUMP_DAILY_ONLY;
} else if ("--reset".equals(arg)) {
synchronized (mStats) {
mStats.resetAllStatsCmdLocked();
@@ -848,6 +853,18 @@ public final class BatteryStatsService extends IBatteryStats.Stub
pw.println("Battery stats written.");
noOutput = true;
}
+ } else if ("--new-daily".equals(arg)) {
+ synchronized (mStats) {
+ mStats.recordDailyStatsLocked();
+ pw.println("New daily stats written.");
+ noOutput = true;
+ }
+ } else if ("--read-daily".equals(arg)) {
+ synchronized (mStats) {
+ mStats.readDailyStatsLocked();
+ pw.println("Last daily stats read.");
+ noOutput = true;
+ }
} else if ("--enable".equals(arg) || "enable".equals(arg)) {
i = doEnableOrDisable(pw, i, args, true);
if (i < 0) {