Merge "Dump battery history without locking"
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 083b4f6..a35b088 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2425,8 +2425,9 @@
public abstract int getHistoryTagPoolUid(int index);
/**
- * Returns a BatteryStatsHistoryIterator. Battery history will remain immutable until the
- * {@link BatteryStatsHistoryIterator#close()} method is invoked.
+ * Returns a BatteryStatsHistoryIterator. Battery history will continue being writable,
+ * but the iterator will continue iterating over the snapshot taken at the time this method
+ * is called.
*/
public abstract BatteryStatsHistoryIterator iterateBatteryStatsHistory();
@@ -5120,14 +5121,6 @@
sb.append(formatCharge(power));
}
- /**
- * Temporary for settings.
- */
- public final void dumpLocked(Context context, PrintWriter pw, String prefix, int which,
- int reqUid) {
- dumpLocked(context, pw, prefix, which, reqUid, checkWifiOnly(context));
- }
-
@SuppressWarnings("unused")
public final void dumpLocked(Context context, PrintWriter pw, String prefix, final int which,
int reqUid, boolean wifiOnly) {
@@ -7483,7 +7476,25 @@
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) {
+ private void dumpHistory(PrintWriter pw, int flags, long histStart, boolean checkin) {
+ if (!checkin) {
+ synchronized (this) {
+ final long historyTotalSize = getHistoryTotalSize();
+ final long historyUsedSize = getHistoryUsedSize();
+ pw.print("Battery History (");
+ pw.print((100 * historyUsedSize) / historyTotalSize);
+ pw.print("% used, ");
+ printSizeValue(pw, historyUsedSize);
+ pw.print(" used of ");
+ printSizeValue(pw, historyTotalSize);
+ pw.print(", ");
+ pw.print(getHistoryStringPoolSize());
+ pw.print(" strings using ");
+ printSizeValue(pw, getHistoryStringPoolBytes());
+ pw.println("):");
+ }
+ }
+
final HistoryPrinter hprinter = new HistoryPrinter();
long lastTime = -1;
long baseTime = -1;
@@ -7628,27 +7639,14 @@
* @param pw a Printer to receive the dump output.
*/
@SuppressWarnings("unused")
- public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
+ public void dump(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
prepareForDumpLocked();
final boolean filtering = (flags
& (DUMP_HISTORY_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
if ((flags&DUMP_HISTORY_ONLY) != 0 || !filtering) {
- final long historyTotalSize = getHistoryTotalSize();
- final long historyUsedSize = getHistoryUsedSize();
- pw.print("Battery History (");
- pw.print((100 * historyUsedSize) / historyTotalSize);
- pw.print("% used, ");
- printSizeValue(pw, historyUsedSize);
- pw.print(" used of ");
- printSizeValue(pw, historyTotalSize);
- pw.print(", ");
- pw.print(getHistoryStringPoolSize());
- pw.print(" strings using ");
- printSizeValue(pw, getHistoryStringPoolBytes());
- pw.println("):");
- dumpHistoryLocked(pw, flags, histStart, false);
+ dumpHistory(pw, flags, histStart, false);
pw.println();
}
@@ -7656,6 +7654,13 @@
return;
}
+ synchronized (this) {
+ dumpLocked(context, pw, flags, reqUid, filtering);
+ }
+ }
+
+ private void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid,
+ boolean filtering) {
if (!filtering) {
SparseArray<? extends Uid> uidStats = getUidStats();
final int NU = uidStats.size();
@@ -7823,7 +7828,7 @@
}
pw.print("\"");
pw.println();
- dumpHistoryLocked(pw, flags, histStart, true);
+ dumpHistory(pw, flags, histStart, true);
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index ddc0c0c..9e176e3 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -40,12 +40,12 @@
import android.util.SparseArray;
import android.util.TimeUtils;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ParseUtils;
import java.io.File;
import java.io.FileOutputStream;
-import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -198,6 +198,8 @@
private final VarintParceler mVarintParceler = new VarintParceler();
private byte mLastHistoryStepLevel = 0;
private boolean mMutable = true;
+ private final BatteryStatsHistory mWritableHistory;
+ private boolean mCleanupEnabled = true;
/**
* A delegate responsible for computing additional details for a step in battery history.
@@ -272,10 +274,32 @@
initHistoryBuffer();
}
+ /**
+ * Creates a read-only wrapper for the supplied writable history.
+ */
+ public BatteryStatsHistory(BatteryStatsHistory writableHistory) {
+ this(Parcel.obtain(), writableHistory.mSystemDir, 0, 0, null, null, null, writableHistory);
+ mMutable = false;
+
+ synchronized (mWritableHistory) {
+ // Make a copy of battery history to avoid concurrent modification.
+ mHistoryBuffer.appendFrom(mWritableHistory.mHistoryBuffer, 0,
+ mWritableHistory.mHistoryBuffer.dataSize());
+ }
+ }
+
@VisibleForTesting
public BatteryStatsHistory(Parcel historyBuffer, File systemDir,
int maxHistoryFiles, int maxHistoryBufferSize,
HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, TraceDelegate tracer) {
+ this(historyBuffer, systemDir, maxHistoryFiles, maxHistoryBufferSize, stepDetailsCalculator,
+ clock, tracer, null);
+ }
+
+ private BatteryStatsHistory(Parcel historyBuffer, File systemDir,
+ int maxHistoryFiles, int maxHistoryBufferSize,
+ HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, TraceDelegate tracer,
+ BatteryStatsHistory writableHistory) {
mHistoryBuffer = historyBuffer;
mSystemDir = systemDir;
mMaxHistoryFiles = maxHistoryFiles;
@@ -283,6 +307,7 @@
mStepDetailsCalculator = stepDetailsCalculator;
mTracer = tracer;
mClock = clock;
+ mWritableHistory = writableHistory;
mHistoryDir = new File(systemDir, HISTORY_DIR);
mHistoryDir.mkdirs();
@@ -292,21 +317,17 @@
final Set<Integer> dedup = new ArraySet<>();
// scan directory, fill mFileNumbers and mActiveFile.
- mHistoryDir.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- final int b = name.lastIndexOf(FILE_SUFFIX);
- if (b <= 0) {
- return false;
- }
- final Integer c =
- ParseUtils.parseInt(name.substring(0, b), -1);
- if (c != -1) {
- dedup.add(c);
- return true;
- } else {
- return false;
- }
+ mHistoryDir.listFiles((dir, name) -> {
+ final int b = name.lastIndexOf(FILE_SUFFIX);
+ if (b <= 0) {
+ return false;
+ }
+ final int c = ParseUtils.parseInt(name.substring(0, b), -1);
+ if (c != -1) {
+ dedup.add(c);
+ return true;
+ } else {
+ return false;
}
});
if (!dedup.isEmpty()) {
@@ -328,21 +349,29 @@
mHistoryBuffer = Parcel.obtain();
mSystemDir = null;
mHistoryDir = null;
+ mWritableHistory = null;
initHistoryBuffer();
}
/**
- * Used when BatteryStatsImpl object is created from deserialization of a parcel,
- * such as a checkin file.
+ * Used when BatteryStatsHistory object is created from deserialization of a BatteryUsageStats
+ * parcel.
*/
- private BatteryStatsHistory(Parcel historyBuffer,
- HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) {
- mHistoryBuffer = historyBuffer;
- mTracer = new TraceDelegate();
- mClock = clock;
+ private BatteryStatsHistory(Parcel parcel) {
+ mClock = Clock.SYSTEM_CLOCK;
+ mTracer = null;
mSystemDir = null;
mHistoryDir = null;
- mStepDetailsCalculator = stepDetailsCalculator;
+ mStepDetailsCalculator = null;
+ mWritableHistory = null;
+ mMutable = false;
+
+ final byte[] historyBlob = parcel.readBlob();
+
+ mHistoryBuffer = Parcel.obtain();
+ mHistoryBuffer.unmarshall(historyBlob, 0, historyBlob.length);
+
+ readFromParcel(parcel, true /* useBlobs */);
}
private void initHistoryBuffer() {
@@ -386,10 +415,7 @@
* in the system directory, so it is not safe while actively writing history.
*/
public BatteryStatsHistory copy() {
- // Make a copy of battery history to avoid concurrent modification.
- Parcel historyBuffer = Parcel.obtain();
- historyBuffer.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
- return new BatteryStatsHistory(historyBuffer, mSystemDir, 0, 0, null, null, mTracer);
+ return new BatteryStatsHistory(this);
}
/**
@@ -448,6 +474,25 @@
Slog.e(TAG, "Could not create history file: " + mActiveFile.getBaseFile());
}
+ synchronized (this) {
+ cleanupLocked();
+ }
+ }
+
+ @GuardedBy("this")
+ private void setCleanupEnabledLocked(boolean enabled) {
+ mCleanupEnabled = enabled;
+ if (mCleanupEnabled) {
+ cleanupLocked();
+ }
+ }
+
+ @GuardedBy("this")
+ private void cleanupLocked() {
+ if (!mCleanupEnabled || mHistoryDir == null) {
+ return;
+ }
+
// if free disk space is less than 100MB, delete oldest history file.
if (!hasFreeDiskSpace()) {
int oldest = mFileNumbers.remove(0);
@@ -465,6 +510,16 @@
}
/**
+ * Returns true if it is safe to reset history. It will return false if the history is
+ * currently being read.
+ */
+ public boolean isResetEnabled() {
+ synchronized (this) {
+ return mCleanupEnabled;
+ }
+ }
+
+ /**
* Clear history buffer and delete all existing history files. Active history file start from
* number 0 again.
*/
@@ -491,6 +546,11 @@
mCurrentParcelEnd = 0;
mParcelIndex = 0;
mMutable = false;
+ if (mWritableHistory != null) {
+ synchronized (mWritableHistory) {
+ mWritableHistory.setCleanupEnabledLocked(false);
+ }
+ }
return new BatteryStatsHistoryIterator(this);
}
@@ -500,7 +560,13 @@
void iteratorFinished() {
// setDataPosition so mHistoryBuffer Parcel can be written.
mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
- mMutable = true;
+ if (mWritableHistory != null) {
+ synchronized (mWritableHistory) {
+ mWritableHistory.setCleanupEnabledLocked(true);
+ }
+ } else {
+ mMutable = true;
+ }
}
/**
@@ -717,15 +783,7 @@
* the {@link #writeToBatteryUsageStatsParcel} method.
*/
public static BatteryStatsHistory createFromBatteryUsageStatsParcel(Parcel in) {
- final byte[] historyBlob = in.readBlob();
-
- Parcel historyBuffer = Parcel.obtain();
- historyBuffer.unmarshall(historyBlob, 0, historyBlob.length);
-
- BatteryStatsHistory history = new BatteryStatsHistory(historyBuffer, null,
- Clock.SYSTEM_CLOCK);
- history.readFromParcel(in, true /* useBlobs */);
- return history;
+ return new BatteryStatsHistory(in);
}
/**
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 7719c5a..f09622f 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -2905,11 +2905,9 @@
if (DBG) Slog.d(TAG, "begin dumpLocked from UID " + Binder.getCallingUid());
awaitCompletion();
- synchronized (mStats) {
- mStats.dumpLocked(mContext, pw, flags, reqUid, historyStart);
- if (writeData) {
- mStats.writeAsyncLocked();
- }
+ mStats.dump(mContext, pw, flags, reqUid, historyStart);
+ if (writeData) {
+ mStats.writeAsyncLocked();
}
pw.println();
mCpuWakeupStats.dump(new IndentingPrintWriter(pw, " "), SystemClock.elapsedRealtime());
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index c278550..89c5c9e 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -11299,7 +11299,7 @@
*/
@Override
public BatteryStatsHistoryIterator iterateBatteryStatsHistory() {
- return mHistory.iterate();
+ return mHistory.copy().iterate();
}
@Override
@@ -14054,7 +14054,8 @@
&& (oldStatus == BatteryManager.BATTERY_STATUS_FULL
|| level >= 90
|| (mDischargeCurrentLevel < 20 && level >= 80)
- || getHighDischargeAmountSinceCharge() >= 200)) {
+ || getHighDischargeAmountSinceCharge() >= 200)
+ && mHistory.isResetEnabled()) {
Slog.i(TAG, "Resetting battery stats: level=" + level + " status=" + oldStatus
+ " dischargeLevel=" + mDischargeCurrentLevel
+ " lowAmount=" + getLowDischargeAmountSinceCharge()
@@ -16604,7 +16605,7 @@
}
@GuardedBy("this")
- public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
+ public void dump(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
if (DEBUG) {
pw.println("mOnBatteryTimeBase:");
mOnBatteryTimeBase.dump(pw, " ");
@@ -16676,36 +16677,39 @@
pr.println("*** Camera timer:");
mCameraOnTimer.logState(pr, " ");
}
- super.dumpLocked(context, pw, flags, reqUid, histStart);
+ super.dump(context, pw, flags, reqUid, histStart);
- pw.print("Per process state tracking available: ");
- pw.println(trackPerProcStateCpuTimes());
- pw.print("Total cpu time reads: ");
- pw.println(mNumSingleUidCpuTimeReads);
- pw.print("Batching Duration (min): ");
- pw.println((mClock.uptimeMillis() - mCpuTimeReadsTrackingStartTimeMs) / (60 * 1000));
- pw.print("All UID cpu time reads since the later of device start or stats reset: ");
- pw.println(mNumAllUidCpuTimeReads);
- pw.print("UIDs removed since the later of device start or stats reset: ");
- pw.println(mNumUidsRemoved);
+ synchronized (this) {
+ pw.print("Per process state tracking available: ");
+ pw.println(trackPerProcStateCpuTimes());
+ pw.print("Total cpu time reads: ");
+ pw.println(mNumSingleUidCpuTimeReads);
+ pw.print("Batching Duration (min): ");
+ pw.println((mClock.uptimeMillis() - mCpuTimeReadsTrackingStartTimeMs) / (60 * 1000));
+ pw.print("All UID cpu time reads since the later of device start or stats reset: ");
+ pw.println(mNumAllUidCpuTimeReads);
+ pw.print("UIDs removed since the later of device start or stats reset: ");
+ pw.println(mNumUidsRemoved);
- pw.println("Currently mapped isolated uids:");
- final int numIsolatedUids = mIsolatedUids.size();
- for (int i = 0; i < numIsolatedUids; i++) {
- final int isolatedUid = mIsolatedUids.keyAt(i);
- final int ownerUid = mIsolatedUids.valueAt(i);
- final int refCount = mIsolatedUidRefCounts.get(isolatedUid);
- pw.println(" " + isolatedUid + "->" + ownerUid + " (ref count = " + refCount + ")");
+ pw.println("Currently mapped isolated uids:");
+ final int numIsolatedUids = mIsolatedUids.size();
+ for (int i = 0; i < numIsolatedUids; i++) {
+ final int isolatedUid = mIsolatedUids.keyAt(i);
+ final int ownerUid = mIsolatedUids.valueAt(i);
+ final int refCount = mIsolatedUidRefCounts.get(isolatedUid);
+ pw.println(
+ " " + isolatedUid + "->" + ownerUid + " (ref count = " + refCount + ")");
+ }
+
+ pw.println();
+ dumpConstantsLocked(pw);
+
+ pw.println();
+ dumpCpuPowerBracketsLocked(pw);
+
+ pw.println();
+ dumpEnergyConsumerStatsLocked(pw);
}
-
- pw.println();
- dumpConstantsLocked(pw);
-
- pw.println();
- dumpCpuPowerBracketsLocked(pw);
-
- pw.println();
- dumpEnergyConsumerStatsLocked(pw);
}
@Override