diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 083b4f6a3bf54..a35b088476cf3 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -2425,8 +2425,9 @@ public abstract class BatteryStats { 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 @@ public abstract class BatteryStats { 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 abstract class BatteryStats { 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 @@ public abstract class BatteryStats { * @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 @@ public abstract class BatteryStats { 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 uidStats = getUidStats(); final int NU = uidStats.size(); @@ -7823,7 +7828,7 @@ public abstract class BatteryStats { } 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 ddc0c0c49b932..9e176e3e93b4f 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.Slog; 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 @@ public class BatteryStatsHistory { 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 @@ public class BatteryStatsHistory { 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 @@ public class BatteryStatsHistory { mStepDetailsCalculator = stepDetailsCalculator; mTracer = tracer; mClock = clock; + mWritableHistory = writableHistory; mHistoryDir = new File(systemDir, HISTORY_DIR); mHistoryDir.mkdirs(); @@ -292,21 +317,17 @@ public class BatteryStatsHistory { final Set 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 @@ public class BatteryStatsHistory { 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 @@ public class BatteryStatsHistory { * 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 @@ public class BatteryStatsHistory { 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); @@ -464,6 +509,16 @@ public class BatteryStatsHistory { } } + /** + * 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 @@ public class BatteryStatsHistory { mCurrentParcelEnd = 0; mParcelIndex = 0; mMutable = false; + if (mWritableHistory != null) { + synchronized (mWritableHistory) { + mWritableHistory.setCleanupEnabledLocked(false); + } + } return new BatteryStatsHistoryIterator(this); } @@ -500,7 +560,13 @@ public class BatteryStatsHistory { 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 @@ public class BatteryStatsHistory { * 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 7719c5a53b24f..f09622f101ac4 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 @@ public final class BatteryStatsService extends IBatteryStats.Stub 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 c278550c3bfe8..89c5c9efff8a7 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 @@ public class BatteryStatsImpl extends BatteryStats { */ @Override public BatteryStatsHistoryIterator iterateBatteryStatsHistory() { - return mHistory.iterate(); + return mHistory.copy().iterate(); } @Override @@ -14054,7 +14054,8 @@ public class BatteryStatsImpl extends BatteryStats { && (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 @@ public class BatteryStatsImpl extends BatteryStats { } @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 @@ public class BatteryStatsImpl extends BatteryStats { 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