Merge "Dump battery history without locking"

This commit is contained in:
Dmitri Plotnikov
2023-01-26 23:05:09 +00:00
committed by Android (Google) Code Review
4 changed files with 165 additions and 100 deletions

View File

@@ -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<? extends Uid> 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);
}
}

View File

@@ -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<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 @@ 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);
}
/**

View File

@@ -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());

View File

@@ -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