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

Commit 6ed73b2a authored by Dmitri Plotnikov's avatar Dmitri Plotnikov
Browse files

Fixing concurrency of battery history directory

Bug: 325315330
Test: atest PowerStatsTests
Test: atest --host PowerStatsTestsRavenwood
Change-Id: I7639899fd6babdbfbba98c4ab310557de24d03a4
parent 9e3b6391
Loading
Loading
Loading
Loading
+328 −187
Original line number Diff line number Diff line
@@ -136,10 +136,8 @@ public class BatteryStatsHistory {
    private final Parcel mHistoryBuffer;
    private final File mSystemDir;
    private final HistoryStepDetailsCalculator mStepDetailsCalculator;
    private final File mHistoryDir;
    private final Clock mClock;

    private int mMaxHistoryFiles;
    private int mMaxHistoryBufferSize;

    /**
@@ -150,7 +148,7 @@ public class BatteryStatsHistory {
    /**
     * A list of history files with increasing timestamps.
     */
    private final List<BatteryHistoryFile> mHistoryFiles = new ArrayList<>();
    private final BatteryHistoryDirectory mHistoryDir;

    /**
     * A list of small history parcels, used when BatteryStatsImpl object is created from
@@ -161,7 +159,8 @@ public class BatteryStatsHistory {
    /**
     * When iterating history files, the current file index.
     */
    private int mCurrentFileIndex;
    private BatteryHistoryFile mCurrentFile;

    /**
     * When iterating history files, the current file parcel.
     */
@@ -203,7 +202,6 @@ public class BatteryStatsHistory {
    private byte mLastHistoryStepLevel = 0;
    private boolean mMutable = true;
    private final BatteryStatsHistory mWritableHistory;
    private boolean mCleanupEnabled = true;

    private static class BatteryHistoryFile implements Comparable<BatteryHistoryFile> {
        public final long monotonicTimeMs;
@@ -235,6 +233,271 @@ public class BatteryStatsHistory {
        }
    }

    private static class BatteryHistoryDirectory {
        private final File mDirectory;
        private final MonotonicClock mMonotonicClock;
        private int mMaxHistoryFiles;
        private final List<BatteryHistoryFile> mHistoryFiles = new ArrayList<>();
        private final ReentrantLock mLock = new ReentrantLock();
        private boolean mCleanupNeeded;

        BatteryHistoryDirectory(File directory, MonotonicClock monotonicClock,
                int maxHistoryFiles) {
            mDirectory = directory;
            mMonotonicClock = monotonicClock;
            mMaxHistoryFiles = maxHistoryFiles;
            if (mMaxHistoryFiles == 0) {
                Slog.wtf(TAG, "mMaxHistoryFiles should not be zero when writing history");
            }
        }

        void setMaxHistoryFiles(int maxHistoryFiles) {
            mMaxHistoryFiles = maxHistoryFiles;
            cleanup();
        }

        void lock() {
            mLock.lock();
        }

        void unlock() {
            mLock.unlock();
            if (mCleanupNeeded) {
                cleanup();
            }
        }

        boolean isLocked() {
            return mLock.isLocked();
        }

        void load() {
            mDirectory.mkdirs();
            if (!mDirectory.exists()) {
                Slog.wtf(TAG, "HistoryDir does not exist:" + mDirectory.getPath());
            }

            final List<File> toRemove = new ArrayList<>();
            final Set<BatteryHistoryFile> dedup = new ArraySet<>();
            mDirectory.listFiles((dir, name) -> {
                final int b = name.lastIndexOf(FILE_SUFFIX);
                if (b <= 0) {
                    toRemove.add(new File(dir, name));
                    return false;
                }
                try {
                    long monotonicTime = Long.parseLong(name.substring(0, b));
                    dedup.add(new BatteryHistoryFile(mDirectory, monotonicTime));
                } catch (NumberFormatException e) {
                    toRemove.add(new File(dir, name));
                    return false;
                }
                return true;
            });
            if (!dedup.isEmpty()) {
                mHistoryFiles.addAll(dedup);
                Collections.sort(mHistoryFiles);
            }
            if (!toRemove.isEmpty()) {
                // Clear out legacy history files, which did not follow the X-Y.bin naming format.
                BackgroundThread.getHandler().post(() -> {
                    lock();
                    try {
                        for (File file : toRemove) {
                            file.delete();
                        }
                    } finally {
                        unlock();
                    }
                });
            }
        }

        List<String> getFileNames() {
            lock();
            try {
                List<String> names = new ArrayList<>();
                for (BatteryHistoryFile historyFile : mHistoryFiles) {
                    names.add(historyFile.atomicFile.getBaseFile().getName());
                }
                return names;
            } finally {
                unlock();
            }
        }

        @Nullable
        BatteryHistoryFile getFirstFile() {
            lock();
            try {
                if (!mHistoryFiles.isEmpty()) {
                    return mHistoryFiles.get(0);
                }
                return null;
            } finally {
                unlock();
            }
        }

        @Nullable
        BatteryHistoryFile getLastFile() {
            lock();
            try {
                if (!mHistoryFiles.isEmpty()) {
                    return mHistoryFiles.get(mHistoryFiles.size() - 1);
                }
                return null;
            } finally {
                unlock();
            }
        }

        @Nullable
        BatteryHistoryFile getNextFile(BatteryHistoryFile current, long startTimeMs,
                long endTimeMs) {
            if (!mLock.isHeldByCurrentThread()) {
                throw new IllegalStateException("Iterating battery history without a lock");
            }

            int nextFileIndex = 0;
            int firstFileIndex = 0;
            // skip the last file because its data is in history buffer.
            int lastFileIndex = mHistoryFiles.size() - 2;
            for (int i = lastFileIndex; i >= 0; i--) {
                BatteryHistoryFile file = mHistoryFiles.get(i);
                if (current != null && file.monotonicTimeMs == current.monotonicTimeMs) {
                    nextFileIndex = i + 1;
                }
                if (file.monotonicTimeMs > endTimeMs) {
                    lastFileIndex = i - 1;
                }
                if (file.monotonicTimeMs <= startTimeMs) {
                    firstFileIndex = i;
                    break;
                }
            }

            if (nextFileIndex < firstFileIndex) {
                nextFileIndex = firstFileIndex;
            }

            if (nextFileIndex <= lastFileIndex) {
                return mHistoryFiles.get(nextFileIndex);
            }

            return null;
        }

        BatteryHistoryFile makeBatteryHistoryFile() {
            BatteryHistoryFile file = new BatteryHistoryFile(mDirectory,
                    mMonotonicClock.monotonicTime());
            lock();
            try {
                mHistoryFiles.add(file);
            } finally {
                unlock();
            }
            return file;
        }

        void writeToParcel(Parcel out, boolean useBlobs) {
            lock();
            try {
                final long start = SystemClock.uptimeMillis();
                out.writeInt(mHistoryFiles.size() - 1);
                for (int i = 0; i < mHistoryFiles.size() - 1; i++) {
                    AtomicFile file = mHistoryFiles.get(i).atomicFile;
                    byte[] raw = new byte[0];
                    try {
                        raw = file.readFully();
                    } catch (Exception e) {
                        Slog.e(TAG, "Error reading file " + file.getBaseFile().getPath(), e);
                    }
                    if (useBlobs) {
                        out.writeBlob(raw);
                    } else {
                        // Avoiding blobs in the check-in file for compatibility
                        out.writeByteArray(raw);
                    }
                }
                if (DEBUG) {
                    Slog.d(TAG,
                            "writeToParcel duration ms:" + (SystemClock.uptimeMillis() - start));
                }
            } finally {
                unlock();
            }
        }

        int getFileCount() {
            lock();
            try {
                return mHistoryFiles.size();
            } finally {
                unlock();
            }
        }

        int getSize() {
            lock();
            try {
                int ret = 0;
                for (int i = 0; i < mHistoryFiles.size() - 1; i++) {
                    ret += (int) mHistoryFiles.get(i).atomicFile.getBaseFile().length();
                }
                return ret;
            } finally {
                unlock();
            }
        }

        void reset() {
            lock();
            try {
                if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!");
                for (BatteryHistoryFile file : mHistoryFiles) {
                    file.atomicFile.delete();
                }
                mHistoryFiles.clear();
            } finally {
                unlock();
            }
        }

        private void cleanup() {
            if (mDirectory == null) {
                return;
            }

            if (isLocked()) {
                mCleanupNeeded = true;
                return;
            }

            mCleanupNeeded = false;

            lock();
            try {
                // if free disk space is less than 100MB, delete oldest history file.
                if (!hasFreeDiskSpace(mDirectory)) {
                    BatteryHistoryFile oldest = mHistoryFiles.remove(0);
                    oldest.atomicFile.delete();
                }

                // if there are more history files than allowed, delete oldest history files.
                // mMaxHistoryFiles comes from Constants.MAX_HISTORY_FILES and
                // can be updated by DeviceConfig at run time.
                while (mHistoryFiles.size() > mMaxHistoryFiles) {
                    BatteryHistoryFile oldest = mHistoryFiles.get(0);
                    oldest.atomicFile.delete();
                    mHistoryFiles.remove(0);
                }
            } finally {
                unlock();
            }
        }
    }

    /**
     * A delegate responsible for computing additional details for a step in battery history.
     */
@@ -351,7 +614,6 @@ public class BatteryStatsHistory {
            BatteryStatsHistory writableHistory) {
        mHistoryBuffer = historyBuffer;
        mSystemDir = systemDir;
        mMaxHistoryFiles = maxHistoryFiles;
        mMaxHistoryBufferSize = maxHistoryBufferSize;
        mStepDetailsCalculator = stepDetailsCalculator;
        mTracer = tracer;
@@ -363,66 +625,32 @@ public class BatteryStatsHistory {
            mMutable = false;
        }

        mHistoryDir = new File(systemDir, HISTORY_DIR);
        mHistoryDir.mkdirs();
        if (!mHistoryDir.exists()) {
            Slog.wtf(TAG, "HistoryDir does not exist:" + mHistoryDir.getPath());
        }

        final List<File> toRemove = new ArrayList<>();
        final Set<BatteryHistoryFile> dedup = new ArraySet<>();
        mHistoryDir.listFiles((dir, name) -> {
            final int b = name.lastIndexOf(FILE_SUFFIX);
            if (b <= 0) {
                toRemove.add(new File(dir, name));
                return false;
            }
            try {
                long monotonicTime = Long.parseLong(name.substring(0, b));
                dedup.add(new BatteryHistoryFile(mHistoryDir, monotonicTime));
            } catch (NumberFormatException e) {
                toRemove.add(new File(dir, name));
                return false;
            }
            return true;
        });
        if (!dedup.isEmpty()) {
            mHistoryFiles.addAll(dedup);
            Collections.sort(mHistoryFiles);
            setActiveFile(mHistoryFiles.get(mHistoryFiles.size() - 1));
        } else if (mMutable) {
            // No file found, default to have the initial file.
            BatteryHistoryFile name = makeBatteryHistoryFile();
            mHistoryFiles.add(name);
            setActiveFile(name);
        }
        if (!toRemove.isEmpty()) {
            // Clear out legacy history files, which did not follow the X-Y.bin naming format.
            BackgroundThread.getHandler().post(() -> {
                for (File file : toRemove) {
                    file.delete();
                }
            });
        if (writableHistory != null) {
            mHistoryDir = writableHistory.mHistoryDir;
        } else {
            mHistoryDir = new BatteryHistoryDirectory(new File(systemDir, HISTORY_DIR),
                    monotonicClock, maxHistoryFiles);
            mHistoryDir.load();
            BatteryHistoryFile activeFile = mHistoryDir.getLastFile();
            if (activeFile == null) {
                activeFile = mHistoryDir.makeBatteryHistoryFile();
            }
            setActiveFile(activeFile);
        }

    private BatteryHistoryFile makeBatteryHistoryFile() {
        return new BatteryHistoryFile(mHistoryDir, mMonotonicClock.monotonicTime());
    }

    public BatteryStatsHistory(int maxHistoryFiles, int maxHistoryBufferSize,
    public BatteryStatsHistory(int maxHistoryBufferSize,
            HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock,
            MonotonicClock monotonicClock) {
        this(maxHistoryFiles, maxHistoryBufferSize, stepDetailsCalculator, clock, monotonicClock,
        this(maxHistoryBufferSize, stepDetailsCalculator, clock, monotonicClock,
                new TraceDelegate(), new EventLogger());
    }

    @VisibleForTesting
    public BatteryStatsHistory(int maxHistoryFiles, int maxHistoryBufferSize,
    public BatteryStatsHistory(int maxHistoryBufferSize,
            HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock,
            MonotonicClock monotonicClock, TraceDelegate traceDelegate,
            EventLogger eventLogger) {
        mMaxHistoryFiles = maxHistoryFiles;
        mMaxHistoryBufferSize = maxHistoryBufferSize;
        mStepDetailsCalculator = stepDetailsCalculator;
        mTracer = traceDelegate;
@@ -484,7 +712,9 @@ public class BatteryStatsHistory {
     * Changes the maximum number of history files to be kept.
     */
    public void setMaxHistoryFiles(int maxHistoryFiles) {
        mMaxHistoryFiles = maxHistoryFiles;
        if (mHistoryDir != null) {
            mHistoryDir.setMaxHistoryFiles(maxHistoryFiles);
        }
    }

    /**
@@ -513,7 +743,7 @@ public class BatteryStatsHistory {
     * Returns true if this instance only supports reading history.
     */
    public boolean isReadOnly() {
        return !mMutable || mActiveFile == null || mHistoryDir == null;
        return !mMutable || mActiveFile == null/* || mHistoryDir == null*/;
    }

    /**
@@ -538,25 +768,13 @@ public class BatteryStatsHistory {

    @GuardedBy("this")
    private void startNextFileLocked(long elapsedRealtimeMs) {
        if (mMaxHistoryFiles == 0) {
            Slog.wtf(TAG, "mMaxHistoryFiles should not be zero when writing history");
            return;
        }

        if (mHistoryFiles.isEmpty()) {
            Slog.wtf(TAG, "mFileNumbers should never be empty");
            return;
        }

        final long start = SystemClock.uptimeMillis();
        writeHistory();
        if (DEBUG) {
            Slog.d(TAG, "writeHistory took ms:" + (SystemClock.uptimeMillis() - start));
        }

        final BatteryHistoryFile next = makeBatteryHistoryFile();
        mHistoryFiles.add(next);
        setActiveFile(next);
        setActiveFile(mHistoryDir.makeBatteryHistoryFile());
        try {
            mActiveFile.getBaseFile().createNewFile();
        } catch (IOException e) {
@@ -578,37 +796,7 @@ public class BatteryStatsHistory {
        }

        mWrittenPowerStatsDescriptors.clear();
        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()) {
            BatteryHistoryFile oldest = mHistoryFiles.remove(0);
            oldest.atomicFile.delete();
        }

        // if there are more history files than allowed, delete oldest history files.
        // mMaxHistoryFiles comes from Constants.MAX_HISTORY_FILES and can be updated by GService
        // config at run time.
        while (mHistoryFiles.size() > mMaxHistoryFiles) {
            BatteryHistoryFile oldest = mHistoryFiles.get(0);
            oldest.atomicFile.delete();
            mHistoryFiles.remove(0);
        }
        mHistoryDir.cleanup();
    }

    /**
@@ -616,9 +804,7 @@ public class BatteryStatsHistory {
     * currently being read.
     */
    public boolean isResetEnabled() {
        synchronized (this) {
            return mCleanupEnabled;
        }
        return mHistoryDir == null || !mHistoryDir.isLocked();
    }

    /**
@@ -627,16 +813,10 @@ public class BatteryStatsHistory {
     */
    public void reset() {
        synchronized (this) {
            if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!");
            for (BatteryHistoryFile file : mHistoryFiles) {
                file.atomicFile.delete();
            if (mHistoryDir != null) {
                mHistoryDir.reset();
                setActiveFile(mHistoryDir.makeBatteryHistoryFile());
            }
            mHistoryFiles.clear();

            BatteryHistoryFile name = makeBatteryHistoryFile();
            mHistoryFiles.add(name);
            setActiveFile(name);

            initHistoryBuffer();
        }
    }
@@ -646,8 +826,9 @@ public class BatteryStatsHistory {
     */
    public long getStartTime() {
        synchronized (this) {
            if (!mHistoryFiles.isEmpty()) {
                return mHistoryFiles.get(0).monotonicTimeMs;
            BatteryHistoryFile file = mHistoryDir.getFirstFile();
            if (file != null) {
                return file.monotonicTimeMs;
            } else {
                return mHistoryBufferStartTime;
            }
@@ -668,15 +849,13 @@ public class BatteryStatsHistory {
            return copy().iterate(startTimeMs, endTimeMs);
        }

        mCurrentFileIndex = 0;
        if (mHistoryDir != null) {
            mHistoryDir.lock();
        }
        mCurrentFile = null;
        mCurrentParcel = null;
        mCurrentParcelEnd = 0;
        mParcelIndex = 0;
        if (mWritableHistory != null) {
            synchronized (mWritableHistory) {
                mWritableHistory.setCleanupEnabledLocked(false);
            }
        }
        return new BatteryStatsHistoryIterator(this, startTimeMs, endTimeMs);
    }

@@ -685,10 +864,8 @@ public class BatteryStatsHistory {
     */
    void iteratorFinished() {
        mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
        if (mWritableHistory != null) {
            synchronized (mWritableHistory) {
                mWritableHistory.setCleanupEnabledLocked(true);
            }
        if (mHistoryDir != null) {
            mHistoryDir.unlock();
        }
    }

@@ -719,40 +896,28 @@ public class BatteryStatsHistory {
            }
        }

        int firstFileIndex = 0;
        // skip the last file because its data is in history buffer.
        int lastFileIndex = mHistoryFiles.size() - 1;
        for (int i = mHistoryFiles.size() - 1; i >= 0; i--) {
            BatteryHistoryFile file = mHistoryFiles.get(i);
            if (file.monotonicTimeMs >= endTimeMs) {
                lastFileIndex = i;
            }
            if (file.monotonicTimeMs <= startTimeMs) {
                firstFileIndex = i;
                break;
            }
        }

        if (mCurrentFileIndex < firstFileIndex) {
            mCurrentFileIndex = firstFileIndex;
        }

        while (mCurrentFileIndex < lastFileIndex) {
        if (mHistoryDir != null) {
            BatteryHistoryFile nextFile = mHistoryDir.getNextFile(mCurrentFile, startTimeMs,
                    endTimeMs);
            while (nextFile != null) {
                mCurrentParcel = null;
                mCurrentParcelEnd = 0;
                final Parcel p = Parcel.obtain();
            AtomicFile file = mHistoryFiles.get(mCurrentFileIndex++).atomicFile;
                AtomicFile file = nextFile.atomicFile;
                if (readFileToParcel(p, file)) {
                    int bufSize = p.readInt();
                    int curPos = p.dataPosition();
                    mCurrentParcelEnd = curPos + bufSize;
                    mCurrentParcel = p;
                    if (curPos < mCurrentParcelEnd) {
                        mCurrentFile = nextFile;
                        return mCurrentParcel;
                    }
                } else {
                    p.recycle();
                }
                nextFile = mHistoryDir.getNextFile(nextFile, startTimeMs, endTimeMs);
            }
        }

        // mHistoryParcels is created when BatteryStatsImpl object is created from deserialization
@@ -922,25 +1087,8 @@ public class BatteryStatsHistory {
    }

    private void writeToParcel(Parcel out, boolean useBlobs) {
        final long start = SystemClock.uptimeMillis();
        out.writeInt(mHistoryFiles.size() - 1);
        for (int i = 0; i < mHistoryFiles.size() - 1; i++) {
            AtomicFile file = mHistoryFiles.get(i).atomicFile;
            byte[] raw = new byte[0];
            try {
                raw = file.readFully();
            } catch (Exception e) {
                Slog.e(TAG, "Error reading file " + file.getBaseFile().getPath(), e);
            }
            if (useBlobs) {
                out.writeBlob(raw);
            } else {
                // Avoiding blobs in the check-in file for compatibility
                out.writeByteArray(raw);
            }
        }
        if (DEBUG) {
            Slog.d(TAG, "writeToParcel duration ms:" + (SystemClock.uptimeMillis() - start));
        if (mHistoryDir != null) {
            mHistoryDir.writeToParcel(out, useBlobs);
        }
    }

@@ -1021,22 +1169,18 @@ public class BatteryStatsHistory {
     * @return true if there is more than 100MB free disk space left.
     */
    @android.ravenwood.annotation.RavenwoodReplace
    private boolean hasFreeDiskSpace() {
        final StatFs stats = new StatFs(mHistoryDir.getAbsolutePath());
    private static boolean hasFreeDiskSpace(File systemDir) {
        final StatFs stats = new StatFs(systemDir.getAbsolutePath());
        return stats.getAvailableBytes() > MIN_FREE_SPACE;
    }

    private boolean hasFreeDiskSpace$ravenwood() {
    private static boolean hasFreeDiskSpace$ravenwood(File systemDir) {
        return true;
    }

    @VisibleForTesting
    public List<String> getFilesNames() {
        List<String> names = new ArrayList<>();
        for (BatteryHistoryFile historyFile : mHistoryFiles) {
            names.add(historyFile.atomicFile.getBaseFile().getName());
        }
        return names;
        return mHistoryDir.getFileNames();
    }

    @VisibleForTesting
@@ -1048,10 +1192,7 @@ public class BatteryStatsHistory {
     * @return the total size of all history files and history buffer.
     */
    public int getHistoryUsedSize() {
        int ret = 0;
        for (int i = 0; i < mHistoryFiles.size() - 1; i++) {
            ret += mHistoryFiles.get(i).atomicFile.getBaseFile().length();
        }
        int ret = mHistoryDir.getSize();
        ret += mHistoryBuffer.dataSize();
        if (mHistoryParcels != null) {
            for (int i = 0; i < mHistoryParcels.size(); i++) {
@@ -1109,7 +1250,7 @@ public class BatteryStatsHistory {
     */
    public void continueRecordingHistory() {
        synchronized (this) {
            if (mHistoryBuffer.dataPosition() <= 0 && mHistoryFiles.size() <= 1) {
            if (mHistoryBuffer.dataPosition() <= 0 && mHistoryDir.getFileCount() <= 1) {
                return;
            }

+5 −1
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ public class BatteryStatsHistoryIterator implements Iterator<BatteryStats.Histor
    private BatteryStats.HistoryItem mHistoryItem = new BatteryStats.HistoryItem();
    private boolean mNextItemReady;
    private boolean mTimeInitialized;
    private boolean mClosed;

    public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history, long startTimeMs,
            long endTimeMs) {
@@ -322,6 +323,9 @@ public class BatteryStatsHistoryIterator implements Iterator<BatteryStats.Histor
     */
    @Override
    public void close() {
        if (!mClosed) {
            mClosed = true;
            mBatteryStatsHistory.iteratorFinished();
        }
    }
}
+4 −5
Original line number Diff line number Diff line
@@ -1817,9 +1817,8 @@ public class BatteryStatsImpl extends BatteryStats {
        if (historyDirectory == null) {
            mCheckinFile = null;
            mStatsFile = null;
            mHistory = new BatteryStatsHistory(mConstants.MAX_HISTORY_FILES,
                    mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, mClock, mMonotonicClock,
                    traceDelegate, eventLogger);
            mHistory = new BatteryStatsHistory(mConstants.MAX_HISTORY_BUFFER,
                    mStepDetailsCalculator, mClock, mMonotonicClock, traceDelegate, eventLogger);
        } else {
            mCheckinFile = new AtomicFile(new File(historyDirectory, "batterystats-checkin.bin"));
            mStatsFile = new AtomicFile(new File(historyDirectory, "batterystats.bin"));
@@ -10962,8 +10961,8 @@ public class BatteryStatsImpl extends BatteryStats {
            mStatsFile = null;
            mCheckinFile = null;
            mDailyFile = null;
            mHistory = new BatteryStatsHistory(mConstants.MAX_HISTORY_FILES,
                    mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, mClock, mMonotonicClock);
            mHistory = new BatteryStatsHistory(mConstants.MAX_HISTORY_BUFFER,
                    mStepDetailsCalculator, mClock, mMonotonicClock);
        } else {
            mStatsFile = new AtomicFile(new File(systemDir, "batterystats.bin"));
            mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin"));
+3 −19

File changed.

Preview size limit exceeded, changes collapsed.

+44 −15

File changed.

Preview size limit exceeded, changes collapsed.

Loading