Merge "Dump battery history without locking"
This commit is contained in:
committed by
Android (Google) Code Review
commit
5023847f89
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user