Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e966996e authored by Dmitri Plotnikov's avatar Dmitri Plotnikov
Browse files

Dump battery history without locking

Bug: 262895225
Test: atest FrameworksServicesTests:BatteryStatsTests

Change-Id: I254226422f20ebd9b85e5d69ff75e8c316ec589d
parent d145dc0f
Loading
Loading
Loading
Loading
+32 −27
Original line number Diff line number Diff line
@@ -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);
            }
        }

+96 −38
Original line number Diff line number Diff line
@@ -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,22 +317,18 @@ 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) {
        mHistoryDir.listFiles((dir, name) -> {
            final int b = name.lastIndexOf(FILE_SUFFIX);
            if (b <= 0) {
                return false;
            }
                final Integer c =
                        ParseUtils.parseInt(name.substring(0, b), -1);
            final int c = ParseUtils.parseInt(name.substring(0, b), -1);
            if (c != -1) {
                dedup.add(c);
                return true;
            } else {
                return false;
            }
            }
        });
        if (!dedup.isEmpty()) {
            mFileNumbers.addAll(dedup);
@@ -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,8 +560,14 @@ public class BatteryStatsHistory {
    void iteratorFinished() {
        // setDataPosition so mHistoryBuffer Parcel can be written.
        mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
        if (mWritableHistory != null) {
            synchronized (mWritableHistory) {
                mWritableHistory.setCleanupEnabledLocked(true);
            }
        } else {
            mMutable = true;
        }
    }

    /**
     * When iterating history files and history buffer, always start from the lowest numbered
@@ -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);
    }

    /**
+3 −5
Original line number Diff line number Diff line
@@ -2900,12 +2900,10 @@ 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);
            mStats.dump(mContext, pw, flags, reqUid, historyStart);
            if (writeData) {
                mStats.writeAsyncLocked();
            }
            }
            pw.println();
            mCpuWakeupStats.dump(new IndentingPrintWriter(pw, "  "), SystemClock.elapsedRealtime());

+35 −31
Original line number Diff line number Diff line
@@ -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,8 +16677,9 @@ 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);
        synchronized (this) {
            pw.print("Per process state tracking available: ");
            pw.println(trackPerProcStateCpuTimes());
            pw.print("Total cpu time reads: ");
@@ -16695,7 +16697,8 @@ public class BatteryStatsImpl extends BatteryStats {
                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(
                        "  " + isolatedUid + "->" + ownerUid + " (ref count = " + refCount + ")");
            }
            pw.println();
@@ -16707,6 +16710,7 @@ public class BatteryStatsImpl extends BatteryStats {
            pw.println();
            dumpEnergyConsumerStatsLocked(pw);
        }
    }
    @Override
    protected BatteryUsageStats getBatteryUsageStats(Context context, boolean detailed) {