diff options
| author | 2022-08-23 18:24:14 +0000 | |
|---|---|---|
| committer | 2022-08-23 18:24:14 +0000 | |
| commit | fecb3aed379bd9a00b7991827a28f5a2c238b6ad (patch) | |
| tree | f994645a7430fd126a336c339631c52e5f01b270 | |
| parent | a7ee33e7a7593fd306914ea8171694d6a22dff7f (diff) | |
Revert "Revert "Breaking history writing out of BatteryStatsImpl""
This reverts commit a7ee33e7a7593fd306914ea8171694d6a22dff7f.
Reason for revert: Rolling the change forward
Change-Id: If6847dbe91e901ca07a0cde402b366b2a3d1f46a
8 files changed, 1768 insertions, 1406 deletions
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 09a52e452f9a..da206268917e 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -2326,11 +2326,6 @@ public abstract class BatteryStats { public abstract void finishIteratingHistoryLocked(); /** - * Return the base time offset for the battery history. - */ - public abstract long getHistoryBaseTime(); - - /** * Returns the number of times the device has been started. */ public abstract int getStartCount(); @@ -7615,8 +7610,6 @@ public abstract class BatteryStats { CHECKIN_VERSION, getParcelVersion(), getStartPlatformVersion(), getEndPlatformVersion()); - long now = getHistoryBaseTime() + SystemClock.elapsedRealtime(); - if ((flags & (DUMP_INCLUDE_HISTORY | DUMP_HISTORY_ONLY)) != 0) { if (startIteratingHistoryLocked()) { try { diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java index 962870e733f7..6909965edcd8 100644 --- a/core/java/com/android/internal/os/BatteryStatsHistory.java +++ b/core/java/com/android/internal/os/BatteryStatsHistory.java @@ -17,25 +17,35 @@ package com.android.internal.os; import android.annotation.Nullable; -import android.os.BatteryStats; +import android.os.BatteryManager; +import android.os.BatteryStats.HistoryItem; +import android.os.BatteryStats.HistoryStepDetails; +import android.os.BatteryStats.HistoryTag; import android.os.Parcel; +import android.os.ParcelFormatException; +import android.os.Process; import android.os.StatFs; import android.os.SystemClock; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Slog; +import android.util.SparseArray; +import android.util.TimeUtils; 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; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; -import java.util.function.Supplier; +import java.util.concurrent.locks.ReentrantLock; /** * BatteryStatsHistory encapsulates battery history files. @@ -56,57 +66,62 @@ import java.util.function.Supplier; * All interfaces in BatteryStatsHistory should only be called by BatteryStatsImpl and protected by * locks on BatteryStatsImpl object. */ -@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public class BatteryStatsHistory { private static final boolean DEBUG = false; private static final String TAG = "BatteryStatsHistory"; // Current on-disk Parcel version. Must be updated when the format of the parcelable changes - public static final int VERSION = 208; + private static final int VERSION = 208; - public static final String HISTORY_DIR = "battery-history"; - public static final String FILE_SUFFIX = ".bin"; + private static final String HISTORY_DIR = "battery-history"; + private static final String FILE_SUFFIX = ".bin"; private static final int MIN_FREE_SPACE = 100 * 1024 * 1024; + // Part of initial delta int that specifies the time delta. - public static final int DELTA_TIME_MASK = 0x7ffff; - public static final int DELTA_TIME_LONG = 0x7ffff; // The delta is a following long - public static final int DELTA_TIME_INT = 0x7fffe; // The delta is a following int - public static final int DELTA_TIME_ABS = 0x7fffd; // Following is an entire abs update. + static final int DELTA_TIME_MASK = 0x7ffff; + static final int DELTA_TIME_LONG = 0x7ffff; // The delta is a following long + static final int DELTA_TIME_INT = 0x7fffe; // The delta is a following int + static final int DELTA_TIME_ABS = 0x7fffd; // Following is an entire abs update. // Flag in delta int: a new battery level int follows. - public static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000; + static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000; // Flag in delta int: a new full state and battery status int follows. - public static final int DELTA_STATE_FLAG = 0x00100000; + static final int DELTA_STATE_FLAG = 0x00100000; // Flag in delta int: a new full state2 int follows. - public static final int DELTA_STATE2_FLAG = 0x00200000; + static final int DELTA_STATE2_FLAG = 0x00200000; // Flag in delta int: contains a wakelock or wakeReason tag. - public static final int DELTA_WAKELOCK_FLAG = 0x00400000; + static final int DELTA_WAKELOCK_FLAG = 0x00400000; // Flag in delta int: contains an event description. - public static final int DELTA_EVENT_FLAG = 0x00800000; + static final int DELTA_EVENT_FLAG = 0x00800000; // Flag in delta int: contains the battery charge count in uAh. - public static final int DELTA_BATTERY_CHARGE_FLAG = 0x01000000; + static final int DELTA_BATTERY_CHARGE_FLAG = 0x01000000; // These upper bits are the frequently changing state bits. - public static final int DELTA_STATE_MASK = 0xfe000000; + static final int DELTA_STATE_MASK = 0xfe000000; // These are the pieces of battery state that are packed in to the upper bits of // the state int that have been packed in to the first delta int. They must fit // in STATE_BATTERY_MASK. - public static final int STATE_BATTERY_MASK = 0xff000000; - public static final int STATE_BATTERY_STATUS_MASK = 0x00000007; - public static final int STATE_BATTERY_STATUS_SHIFT = 29; - public static final int STATE_BATTERY_HEALTH_MASK = 0x00000007; - public static final int STATE_BATTERY_HEALTH_SHIFT = 26; - public static final int STATE_BATTERY_PLUG_MASK = 0x00000003; - public static final int STATE_BATTERY_PLUG_SHIFT = 24; + static final int STATE_BATTERY_MASK = 0xff000000; + static final int STATE_BATTERY_STATUS_MASK = 0x00000007; + static final int STATE_BATTERY_STATUS_SHIFT = 29; + static final int STATE_BATTERY_HEALTH_MASK = 0x00000007; + static final int STATE_BATTERY_HEALTH_SHIFT = 26; + static final int STATE_BATTERY_PLUG_MASK = 0x00000003; + static final int STATE_BATTERY_PLUG_SHIFT = 24; // We use the low bit of the battery state int to indicate that we have full details // from a battery level change. - public static final int BATTERY_DELTA_LEVEL_FLAG = 0x00000001; + static final int BATTERY_DELTA_LEVEL_FLAG = 0x00000001; // Flag in history tag index: indicates that this is the first occurrence of this tag, // therefore the tag value is written in the parcel - public static final int TAG_FIRST_OCCURRENCE_FLAG = 0x8000; + static final int TAG_FIRST_OCCURRENCE_FLAG = 0x8000; - @Nullable - private final Supplier<Integer> mMaxHistoryFiles; 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; + /** * The active history file that the history buffer is backed up into. */ @@ -144,19 +159,77 @@ public class BatteryStatsHistory { */ private int mParcelIndex = 0; + private final ReentrantLock mWriteLock = new ReentrantLock(); + + private final HistoryItem mHistoryCur = new HistoryItem(); + + private boolean mHaveBatteryLevel; + private boolean mRecordingHistory; + + private static final int HISTORY_TAG_INDEX_LIMIT = 0x7ffe; + private static final int MAX_HISTORY_TAG_STRING_LENGTH = 1024; + + private final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>(); + private SparseArray<HistoryTag> mHistoryTags; + private final HistoryItem mHistoryLastWritten = new HistoryItem(); + private final HistoryItem mHistoryLastLastWritten = new HistoryItem(); + private final HistoryItem mHistoryAddTmp = new HistoryItem(); + private int mNextHistoryTagIdx = 0; + private int mNumHistoryTagChars = 0; + private int mHistoryBufferLastPos = -1; + private int mActiveHistoryStates = 0xffffffff; + private int mActiveHistoryStates2 = 0xffffffff; + private long mLastHistoryElapsedRealtimeMs = 0; + private long mTrackRunningHistoryElapsedRealtimeMs = 0; + private long mTrackRunningHistoryUptimeMs = 0; + private long mHistoryBaseTimeMs; + + private byte mLastHistoryStepLevel = 0; + + private BatteryStatsHistoryIterator mBatteryStatsHistoryIterator; + + /** + * A delegate responsible for computing additional details for a step in battery history. + */ + public interface HistoryStepDetailsCalculator { + /** + * Returns additional details for the current history step or null. + */ + @Nullable + HistoryStepDetails getHistoryStepDetails(); + + /** + * Resets the calculator to get ready for a new battery session + */ + void clear(); + } + /** * Constructor * - * @param historyBuffer The in-memory history buffer. - * @param systemDir typically /data/system - * @param maxHistoryFiles the largest number of history buffer files to keep + * @param systemDir typically /data/system + * @param maxHistoryFiles the largest number of history buffer files to keep + * @param maxHistoryBufferSize the most amount of RAM to used for buffering of history steps */ + public BatteryStatsHistory(File systemDir, int maxHistoryFiles, int maxHistoryBufferSize, + HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { + this(Parcel.obtain(), systemDir, maxHistoryFiles, maxHistoryBufferSize, + stepDetailsCalculator, clock); + initHistoryBuffer(); + } + + @VisibleForTesting public BatteryStatsHistory(Parcel historyBuffer, File systemDir, - Supplier<Integer> maxHistoryFiles) { + int maxHistoryFiles, int maxHistoryBufferSize, + HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { mHistoryBuffer = historyBuffer; - mHistoryDir = new File(systemDir, HISTORY_DIR); + mSystemDir = systemDir; mMaxHistoryFiles = maxHistoryFiles; + mMaxHistoryBufferSize = maxHistoryBufferSize; + mStepDetailsCalculator = stepDetailsCalculator; + mClock = clock; + mHistoryDir = new File(systemDir, HISTORY_DIR); mHistoryDir.mkdirs(); if (!mHistoryDir.exists()) { Slog.wtf(TAG, "HistoryDir does not exist:" + mHistoryDir.getPath()); @@ -192,19 +265,81 @@ public class BatteryStatsHistory { } } + public BatteryStatsHistory(HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { + mStepDetailsCalculator = stepDetailsCalculator; + mClock = clock; + + mHistoryBuffer = Parcel.obtain(); + mSystemDir = null; + mHistoryDir = null; + initHistoryBuffer(); + } + /** * Used when BatteryStatsImpl object is created from deserialization of a parcel, - * such as Settings app or checkin file. - * @param historyBuffer the history buffer + * such as a checkin file. */ - public BatteryStatsHistory(Parcel historyBuffer) { - mHistoryDir = null; + private BatteryStatsHistory(Parcel historyBuffer, + HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { mHistoryBuffer = historyBuffer; - mMaxHistoryFiles = null; + mClock = clock; + mSystemDir = null; + mHistoryDir = null; + mStepDetailsCalculator = stepDetailsCalculator; + } + + private void initHistoryBuffer() { + mHistoryBaseTimeMs = 0; + mLastHistoryElapsedRealtimeMs = 0; + mTrackRunningHistoryElapsedRealtimeMs = 0; + mTrackRunningHistoryUptimeMs = 0; + + mHistoryBuffer.setDataSize(0); + mHistoryBuffer.setDataPosition(0); + mHistoryBuffer.setDataCapacity(mMaxHistoryBufferSize / 2); + mHistoryLastLastWritten.clear(); + mHistoryLastWritten.clear(); + mHistoryTagPool.clear(); + mNextHistoryTagIdx = 0; + mNumHistoryTagChars = 0; + mHistoryBufferLastPos = -1; + mActiveHistoryStates = 0xffffffff; + mActiveHistoryStates2 = 0xffffffff; + if (mStepDetailsCalculator != null) { + mStepDetailsCalculator.clear(); + } + } + + /** + * Changes the maximum number of history files to be kept. + */ + public void setMaxHistoryFiles(int maxHistoryFiles) { + mMaxHistoryFiles = maxHistoryFiles; + } + + /** + * Changes the maximum size of the history buffer, in bytes. + */ + public void setMaxHistoryBufferSize(int maxHistoryBufferSize) { + mMaxHistoryBufferSize = maxHistoryBufferSize; } - public File getHistoryDirectory() { - return mHistoryDir; + /** + * Creates a read-only copy of the battery history. Does not copy the files stored + * 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); + } + + /** + * Returns true if this instance only supports reading history. + */ + public boolean isReadOnly() { + return mActiveFile == null; } /** @@ -221,12 +356,13 @@ public class BatteryStatsHistory { /** * Create history AtomicFile from file number. + * * @param num file number. * @return AtomicFile object. */ private AtomicFile getFile(int num) { return new AtomicFile( - new File(mHistoryDir, num + FILE_SUFFIX)); + new File(mHistoryDir, num + FILE_SUFFIX)); } /** @@ -234,7 +370,7 @@ public class BatteryStatsHistory { * create next history file. */ public void startNextFile() { - if (mMaxHistoryFiles == null) { + if (mMaxHistoryFiles == 0) { Slog.wtf(TAG, "mMaxHistoryFiles should not be zero when writing history"); return; } @@ -264,7 +400,7 @@ public class BatteryStatsHistory { // 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 (mFileNumbers.size() > mMaxHistoryFiles.get()) { + while (mFileNumbers.size() > mMaxHistoryFiles) { int oldest = mFileNumbers.get(0); getFile(oldest).delete(); mFileNumbers.remove(0); @@ -272,36 +408,43 @@ public class BatteryStatsHistory { } /** - * Delete all existing history files. Active history file start from number 0 again. + * Clear history buffer and delete all existing history files. Active history file start from + * number 0 again. */ - public void resetAllFiles() { + public void reset() { + if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!"); for (Integer i : mFileNumbers) { getFile(i).delete(); } mFileNumbers.clear(); mFileNumbers.add(0); setActiveFile(0); + + initHistoryBuffer(); } /** * Start iterating history files and history buffer. + * * @return always return true. */ - public boolean startIteratingHistory() { + public BatteryStatsHistoryIterator iterate() { mRecordCount = 0; mCurrentFileIndex = 0; mCurrentParcel = null; mCurrentParcelEnd = 0; mParcelIndex = 0; - return true; + mBatteryStatsHistoryIterator = new BatteryStatsHistoryIterator(this); + return mBatteryStatsHistoryIterator; } /** * Finish iterating history files and history buffer. */ - public void finishIteratingHistory() { + void finishIteratingHistory() { // setDataPosition so mHistoryBuffer Parcel can be written. mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize()); + mBatteryStatsHistoryIterator = null; if (DEBUG) { Slog.d(TAG, "Battery history records iterated: " + mRecordCount); } @@ -311,11 +454,12 @@ public class BatteryStatsHistory { * When iterating history files and history buffer, always start from the lowest numbered * history file, when reached the mActiveFile (highest numbered history file), do not read from * mActiveFile, read from history buffer instead because the buffer has more updated data. + * * @param out a history item. * @return The parcel that has next record. null if finished all history files and history - * buffer + * buffer */ - public Parcel getNextParcel(BatteryStats.HistoryItem out) { + public Parcel getNextParcel(HistoryItem out) { if (mRecordCount == 0) { // reset out if it is the first record. out.clear(); @@ -323,8 +467,7 @@ public class BatteryStatsHistory { ++mRecordCount; // First iterate through all records in current parcel. - if (mCurrentParcel != null) - { + if (mCurrentParcel != null) { if (mCurrentParcel.dataPosition() < mCurrentParcelEnd) { // There are more records in current parcel. return mCurrentParcel; @@ -389,7 +532,8 @@ public class BatteryStatsHistory { /** * Read history file into a parcel. - * @param out the Parcel read into. + * + * @param out the Parcel read into. * @param file the File to read from. * @return true if success, false otherwise. */ @@ -402,8 +546,8 @@ public class BatteryStatsHistory { Slog.d(TAG, "readFileToParcel:" + file.getBaseFile().getPath() + " duration ms:" + (SystemClock.uptimeMillis() - start)); } - } catch(Exception e) { - Slog.e(TAG, "Error reading file "+ file.getBaseFile().getPath(), e); + } catch (Exception e) { + Slog.e(TAG, "Error reading file " + file.getBaseFile().getPath(), e); return false; } out.unmarshall(raw, 0, raw.length); @@ -413,6 +557,7 @@ public class BatteryStatsHistory { /** * Skip the header part of history parcel. + * * @param p history parcel to skip head. * @return true if version match, false if not. */ @@ -428,18 +573,68 @@ public class BatteryStatsHistory { } /** + * Writes the battery history contents for persistence. + */ + public void writeSummaryToParcel(Parcel out, boolean inclHistory) { + out.writeBoolean(inclHistory); + if (inclHistory) { + writeToParcel(out); + } + + out.writeInt(mHistoryTagPool.size()); + for (Map.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) { + HistoryTag tag = ent.getKey(); + out.writeInt(ent.getValue()); + out.writeString(tag.string); + out.writeInt(tag.uid); + } + } + + /** + * Reads battery history contents from a persisted parcel. + */ + public void readSummaryFromParcel(Parcel in) { + boolean inclHistory = in.readBoolean(); + if (inclHistory) { + readFromParcel(in); + } + + mHistoryTagPool.clear(); + mNextHistoryTagIdx = 0; + mNumHistoryTagChars = 0; + + int numTags = in.readInt(); + for (int i = 0; i < numTags; i++) { + int idx = in.readInt(); + String str = in.readString(); + int uid = in.readInt(); + HistoryTag tag = new HistoryTag(); + tag.string = str; + tag.uid = uid; + tag.poolIdx = idx; + mHistoryTagPool.put(tag, idx); + if (idx >= mNextHistoryTagIdx) { + mNextHistoryTagIdx = idx + 1; + } + mNumHistoryTagChars += tag.string.length() + 1; + } + } + + /** * Read all history files and serialize into a big Parcel. * Checkin file calls this method. * * @param out the output parcel */ public void writeToParcel(Parcel out) { + writeHistoryBuffer(out); writeToParcel(out, false /* useBlobs */); } /** * This is for Settings app, when Settings app receives big history parcel, it call * this method to parse it into list of parcels. + * * @param out the output parcel */ public void writeToBatteryUsageStatsParcel(Parcel out) { @@ -450,13 +645,13 @@ public class BatteryStatsHistory { private void writeToParcel(Parcel out, boolean useBlobs) { final long start = SystemClock.uptimeMillis(); out.writeInt(mFileNumbers.size() - 1); - for(int i = 0; i < mFileNumbers.size() - 1; i++) { + for (int i = 0; i < mFileNumbers.size() - 1; i++) { AtomicFile file = getFile(mFileNumbers.get(i)); byte[] raw = new byte[0]; try { raw = file.readFully(); - } catch(Exception e) { - Slog.e(TAG, "Error reading file "+ file.getBaseFile().getPath(), e); + } catch (Exception e) { + Slog.e(TAG, "Error reading file " + file.getBaseFile().getPath(), e); } if (useBlobs) { out.writeBlob(raw); @@ -480,17 +675,55 @@ public class BatteryStatsHistory { Parcel historyBuffer = Parcel.obtain(); historyBuffer.unmarshall(historyBlob, 0, historyBlob.length); - BatteryStatsHistory history = new BatteryStatsHistory(historyBuffer); + BatteryStatsHistory history = new BatteryStatsHistory(historyBuffer, null, + Clock.SYSTEM_CLOCK); history.readFromParcel(in, true /* useBlobs */); return history; } /** + * Read history from a check-in file. + */ + public boolean readSummary() { + if (mActiveFile == null) { + Slog.w(TAG, "readSummary: no history file associated with this instance"); + return false; + } + + Parcel parcel = Parcel.obtain(); + try { + final long start = SystemClock.uptimeMillis(); + if (mActiveFile.exists()) { + byte[] raw = mActiveFile.readFully(); + if (raw.length > 0) { + parcel.unmarshall(raw, 0, raw.length); + parcel.setDataPosition(0); + readHistoryBuffer(parcel); + } + if (DEBUG) { + Slog.d(TAG, "read history file::" + + mActiveFile.getBaseFile().getPath() + + " bytes:" + raw.length + " took ms:" + (SystemClock.uptimeMillis() + - start)); + } + } + } catch (Exception e) { + Slog.e(TAG, "Error reading battery history", e); + reset(); + return false; + } finally { + parcel.recycle(); + } + return true; + } + + /** * This is for the check-in file, which has all history files embedded. * * @param in the input parcel. */ public void readFromParcel(Parcel in) { + readHistoryBuffer(in); readFromParcel(in, false /* useBlobs */); } @@ -498,7 +731,7 @@ public class BatteryStatsHistory { final long start = SystemClock.uptimeMillis(); mHistoryParcels = new ArrayList<>(); final int count = in.readInt(); - for(int i = 0; i < count; i++) { + for (int i = 0; i < count; i++) { byte[] temp = useBlobs ? in.readBlob() : in.createByteArray(); if (temp == null || temp.length == 0) { continue; @@ -521,10 +754,12 @@ public class BatteryStatsHistory { return stats.getAvailableBytes() > MIN_FREE_SPACE; } + @VisibleForTesting public List<Integer> getFilesNumbers() { return mFileNumbers; } + @VisibleForTesting public AtomicFile getActiveFile() { return mActiveFile; } @@ -534,15 +769,972 @@ public class BatteryStatsHistory { */ public int getHistoryUsedSize() { int ret = 0; - for(int i = 0; i < mFileNumbers.size() - 1; i++) { + for (int i = 0; i < mFileNumbers.size() - 1; i++) { ret += getFile(mFileNumbers.get(i)).getBaseFile().length(); } ret += mHistoryBuffer.dataSize(); if (mHistoryParcels != null) { - for(int i = 0; i < mHistoryParcels.size(); i++) { + for (int i = 0; i < mHistoryParcels.size(); i++) { ret += mHistoryParcels.get(i).dataSize(); } } return ret; } + + /** + * Enables/disables recording of history. When disabled, all "record*" calls are a no-op. + */ + public void setHistoryRecordingEnabled(boolean enabled) { + mRecordingHistory = enabled; + } + + /** + * Returns true if history recording is enabled. + */ + public boolean isRecordingHistory() { + return mRecordingHistory; + } + + /** + * Forces history recording regardless of charging state. + */ + @VisibleForTesting + public void forceRecordAllHistory() { + mHaveBatteryLevel = true; + mRecordingHistory = true; + } + + /** + * Starts a history buffer by recording the current wall-clock time. + */ + public void startRecordingHistory(final long elapsedRealtimeMs, final long uptimeMs, + boolean reset) { + mRecordingHistory = true; + mHistoryCur.currentTime = mClock.currentTimeMillis(); + writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, + reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME); + mHistoryCur.currentTime = 0; + } + + /** + * Prepares to continue recording after restoring previous history from persistent storage. + */ + public void continueRecordingHistory() { + if (mHistoryBuffer.dataPosition() <= 0 && mFileNumbers.size() <= 1) { + return; + } + + mRecordingHistory = true; + final long elapsedRealtimeMs = mClock.elapsedRealtime(); + final long uptimeMs = mClock.uptimeMillis(); + writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_START); + startRecordingHistory(elapsedRealtimeMs, uptimeMs, false); + } + + /** + * Notes the current battery state to be reflected in the next written history item. + */ + public void setBatteryState(boolean charging, int status, int level, int chargeUah) { + mHaveBatteryLevel = true; + setChargingState(charging); + mHistoryCur.batteryStatus = (byte) status; + mHistoryCur.batteryLevel = (byte) level; + mHistoryCur.batteryChargeUah = chargeUah; + } + + /** + * Notes the current battery state to be reflected in the next written history item. + */ + public void setBatteryState(int status, int level, int health, int plugType, int temperature, + int voltageMv, int chargeUah) { + mHaveBatteryLevel = true; + mHistoryCur.batteryStatus = (byte) status; + mHistoryCur.batteryLevel = (byte) level; + mHistoryCur.batteryHealth = (byte) health; + mHistoryCur.batteryPlugType = (byte) plugType; + mHistoryCur.batteryTemperature = (short) temperature; + mHistoryCur.batteryVoltage = (char) voltageMv; + mHistoryCur.batteryChargeUah = chargeUah; + } + + /** + * Notes the current power plugged-in state to be reflected in the next written history item. + */ + public void setPluggedInState(boolean pluggedIn) { + if (pluggedIn) { + mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG; + } else { + mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; + } + } + + /** + * Notes the current battery charging state to be reflected in the next written history item. + */ + public void setChargingState(boolean charging) { + if (charging) { + mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG; + } else { + mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG; + } + } + + /** + * Records a history event with the given code, name and UID. + */ + public void recordEvent(long elapsedRealtimeMs, long uptimeMs, int code, String name, + int uid) { + mHistoryCur.eventCode = code; + mHistoryCur.eventTag = mHistoryCur.localEventTag; + mHistoryCur.eventTag.string = name; + mHistoryCur.eventTag.uid = uid; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a time change event. + */ + public void recordCurrentTimeChange(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) { + if (!mRecordingHistory) { + return; + } + + mHistoryCur.currentTime = currentTimeMs; + writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, + HistoryItem.CMD_CURRENT_TIME); + mHistoryCur.currentTime = 0; + } + + /** + * Records a system shutdown event. + */ + public void recordShutdownEvent(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) { + if (!mRecordingHistory) { + return; + } + + mHistoryCur.currentTime = currentTimeMs; + writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_SHUTDOWN); + mHistoryCur.currentTime = 0; + } + + /** + * Records a battery state change event. + */ + public void recordBatteryState(long elapsedRealtimeMs, long uptimeMs, int batteryLevel, + boolean isPlugged) { + mHistoryCur.batteryLevel = (byte) batteryLevel; + setPluggedInState(isPlugged); + if (DEBUG) { + Slog.v(TAG, "Battery unplugged to: " + + Integer.toHexString(mHistoryCur.states)); + } + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a history item with the amount of charge consumed by WiFi. Used on certain devices + * equipped with on-device power metering. + */ + public void recordWifiConsumedCharge(long elapsedRealtimeMs, long uptimeMs, + double monitoredRailChargeMah) { + mHistoryCur.wifiRailChargeMah += monitoredRailChargeMah; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a wakelock start event. + */ + public void recordWakelockStartEvent(long elapsedRealtimeMs, long uptimeMs, String historyName, + int uid) { + mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; + mHistoryCur.wakelockTag.string = historyName; + mHistoryCur.wakelockTag.uid = uid; + recordStateStartEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG); + } + + /** + * Updates the previous history event with a wakelock name and UID. + */ + public boolean maybeUpdateWakelockTag(long elapsedRealtimeMs, long uptimeMs, String historyName, + int uid) { + if (mHistoryLastWritten.cmd != HistoryItem.CMD_UPDATE) { + return false; + } + if (mHistoryLastWritten.wakelockTag != null) { + // We'll try to update the last tag. + mHistoryLastWritten.wakelockTag = null; + mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; + mHistoryCur.wakelockTag.string = historyName; + mHistoryCur.wakelockTag.uid = uid; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + return true; + } + + /** + * Records an event when some state flag changes to true. + */ + public void recordStateStartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) { + mHistoryCur.states |= stateFlags; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records an event when some state flag changes to false. + */ + public void recordStateStopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) { + mHistoryCur.states &= ~stateFlags; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records an event when some state flags change to true and some to false. + */ + public void recordStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int stateStartFlags, + int stateStopFlags) { + mHistoryCur.states = (mHistoryCur.states | stateStartFlags) & ~stateStopFlags; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records an event when some state2 flag changes to true. + */ + public void recordState2StartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) { + mHistoryCur.states2 |= stateFlags; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records an event when some state2 flag changes to false. + */ + public void recordState2StopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) { + mHistoryCur.states2 &= ~stateFlags; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records an wakeup event. + */ + public void recordWakeupEvent(long elapsedRealtimeMs, long uptimeMs, String reason) { + mHistoryCur.wakeReasonTag = mHistoryCur.localWakeReasonTag; + mHistoryCur.wakeReasonTag.string = reason; + mHistoryCur.wakeReasonTag.uid = 0; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a screen brightness change event. + */ + public void recordScreenBrightnessEvent(long elapsedRealtimeMs, long uptimeMs, + int brightnessBin) { + mHistoryCur.states = (mHistoryCur.states & ~HistoryItem.STATE_BRIGHTNESS_MASK) + | (brightnessBin << HistoryItem.STATE_BRIGHTNESS_SHIFT); + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a GNSS signal level change event. + */ + public void recordGpsSignalQualityEvent(long elapsedRealtimeMs, long uptimeMs, + int signalLevel) { + mHistoryCur.states2 = (mHistoryCur.states2 & ~HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK) + | (signalLevel << HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT); + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a device idle mode change event. + */ + public void recordDeviceIdleEvent(long elapsedRealtimeMs, long uptimeMs, int mode) { + mHistoryCur.states2 = (mHistoryCur.states2 & ~HistoryItem.STATE2_DEVICE_IDLE_MASK) + | (mode << HistoryItem.STATE2_DEVICE_IDLE_SHIFT); + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a telephony state change event. + */ + public void recordPhoneStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int addStateFlag, + int removeStateFlag, int state, int signalStrength) { + mHistoryCur.states = (mHistoryCur.states | addStateFlag) & ~removeStateFlag; + if (state != -1) { + mHistoryCur.states = + (mHistoryCur.states & ~HistoryItem.STATE_PHONE_STATE_MASK) + | (state << HistoryItem.STATE_PHONE_STATE_SHIFT); + } + if (signalStrength != -1) { + mHistoryCur.states = + (mHistoryCur.states & ~HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK) + | (signalStrength << HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT); + } + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a data connection type change event. + */ + public void recordDataConnectionTypeChangeEvent(long elapsedRealtimeMs, long uptimeMs, + int dataConnectionType) { + mHistoryCur.states = (mHistoryCur.states & ~HistoryItem.STATE_DATA_CONNECTION_MASK) + | (dataConnectionType << HistoryItem.STATE_DATA_CONNECTION_SHIFT); + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a WiFi supplicant state change event. + */ + public void recordWifiSupplicantStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, + int supplState) { + mHistoryCur.states2 = + (mHistoryCur.states2 & ~HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK) + | (supplState << HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT); + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a WiFi signal strength change event. + */ + public void recordWifiSignalStrengthChangeEvent(long elapsedRealtimeMs, long uptimeMs, + int strengthBin) { + mHistoryCur.states2 = + (mHistoryCur.states2 & ~HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK) + | (strengthBin << HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT); + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Writes the current history item to history. + */ + public void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs) { + if (mTrackRunningHistoryElapsedRealtimeMs != 0) { + final long diffElapsedMs = elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtimeMs; + final long diffUptimeMs = uptimeMs - mTrackRunningHistoryUptimeMs; + if (diffUptimeMs < (diffElapsedMs - 20)) { + final long wakeElapsedTimeMs = elapsedRealtimeMs - (diffElapsedMs - diffUptimeMs); + mHistoryAddTmp.setTo(mHistoryLastWritten); + mHistoryAddTmp.wakelockTag = null; + mHistoryAddTmp.wakeReasonTag = null; + mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE; + mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG; + writeHistoryItem(wakeElapsedTimeMs, uptimeMs, mHistoryAddTmp); + } + } + mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG; + mTrackRunningHistoryElapsedRealtimeMs = elapsedRealtimeMs; + mTrackRunningHistoryUptimeMs = uptimeMs; + writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur); + } + + private void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) { + if (!mHaveBatteryLevel || !mRecordingHistory) { + return; + } + + final long timeDiffMs = (mHistoryBaseTimeMs + elapsedRealtimeMs) - mHistoryLastWritten.time; + final int diffStates = mHistoryLastWritten.states ^ (cur.states & mActiveHistoryStates); + final int diffStates2 = mHistoryLastWritten.states2 ^ (cur.states2 & mActiveHistoryStates2); + final int lastDiffStates = mHistoryLastWritten.states ^ mHistoryLastLastWritten.states; + final int lastDiffStates2 = mHistoryLastWritten.states2 ^ mHistoryLastLastWritten.states2; + if (DEBUG) { + Slog.i(TAG, "ADD: tdelta=" + timeDiffMs + " diff=" + + Integer.toHexString(diffStates) + " lastDiff=" + + Integer.toHexString(lastDiffStates) + " diff2=" + + Integer.toHexString(diffStates2) + " lastDiff2=" + + Integer.toHexString(lastDiffStates2)); + } + if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE + && timeDiffMs < 1000 && (diffStates & lastDiffStates) == 0 + && (diffStates2 & lastDiffStates2) == 0 + && (!mHistoryLastWritten.tagsFirstOccurrence && !cur.tagsFirstOccurrence) + && (mHistoryLastWritten.wakelockTag == null || cur.wakelockTag == null) + && (mHistoryLastWritten.wakeReasonTag == null || cur.wakeReasonTag == null) + && mHistoryLastWritten.stepDetails == null + && (mHistoryLastWritten.eventCode == HistoryItem.EVENT_NONE + || cur.eventCode == HistoryItem.EVENT_NONE) + && mHistoryLastWritten.batteryLevel == cur.batteryLevel + && mHistoryLastWritten.batteryStatus == cur.batteryStatus + && mHistoryLastWritten.batteryHealth == cur.batteryHealth + && mHistoryLastWritten.batteryPlugType == cur.batteryPlugType + && mHistoryLastWritten.batteryTemperature == cur.batteryTemperature + && mHistoryLastWritten.batteryVoltage == cur.batteryVoltage) { + // We can merge this new change in with the last one. Merging is + // allowed as long as only the states have changed, and within those states + // as long as no bit has changed both between now and the last entry, as + // well as the last entry and the one before it (so we capture any toggles). + if (DEBUG) Slog.i(TAG, "ADD: rewinding back to " + mHistoryBufferLastPos); + mHistoryBuffer.setDataSize(mHistoryBufferLastPos); + mHistoryBuffer.setDataPosition(mHistoryBufferLastPos); + mHistoryBufferLastPos = -1; + elapsedRealtimeMs = mHistoryLastWritten.time - mHistoryBaseTimeMs; + // If the last written history had a wakelock tag, we need to retain it. + // Note that the condition above made sure that we aren't in a case where + // both it and the current history item have a wakelock tag. + if (mHistoryLastWritten.wakelockTag != null) { + cur.wakelockTag = cur.localWakelockTag; + cur.wakelockTag.setTo(mHistoryLastWritten.wakelockTag); + } + // If the last written history had a wake reason tag, we need to retain it. + // Note that the condition above made sure that we aren't in a case where + // both it and the current history item have a wakelock tag. + if (mHistoryLastWritten.wakeReasonTag != null) { + cur.wakeReasonTag = cur.localWakeReasonTag; + cur.wakeReasonTag.setTo(mHistoryLastWritten.wakeReasonTag); + } + // If the last written history had an event, we need to retain it. + // Note that the condition above made sure that we aren't in a case where + // both it and the current history item have an event. + if (mHistoryLastWritten.eventCode != HistoryItem.EVENT_NONE) { + cur.eventCode = mHistoryLastWritten.eventCode; + cur.eventTag = cur.localEventTag; + cur.eventTag.setTo(mHistoryLastWritten.eventTag); + } + mHistoryLastWritten.setTo(mHistoryLastLastWritten); + } + final int dataSize = mHistoryBuffer.dataSize(); + + if (dataSize >= mMaxHistoryBufferSize) { + if (mMaxHistoryBufferSize == 0) { + Slog.wtf(TAG, "mMaxHistoryBufferSize should not be zero when writing history"); + mMaxHistoryBufferSize = 1024; + } + + //open a new history file. + final long start = SystemClock.uptimeMillis(); + writeHistory(); + if (DEBUG) { + Slog.d(TAG, "addHistoryBufferLocked writeHistory took ms:" + + (SystemClock.uptimeMillis() - start)); + } + startNextFile(); + mHistoryBuffer.setDataSize(0); + mHistoryBuffer.setDataPosition(0); + mHistoryBuffer.setDataCapacity(mMaxHistoryBufferSize / 2); + mHistoryBufferLastPos = -1; + mHistoryLastWritten.clear(); + mHistoryLastLastWritten.clear(); + + // Mark every entry in the pool with a flag indicating that the tag + // has not yet been encountered while writing the current history buffer. + for (Map.Entry<HistoryTag, Integer> entry : mHistoryTagPool.entrySet()) { + entry.setValue(entry.getValue() | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG); + } + // Make a copy of mHistoryCur. + HistoryItem copy = new HistoryItem(); + copy.setTo(cur); + // startRecordingHistory will reset mHistoryCur. + startRecordingHistory(elapsedRealtimeMs, uptimeMs, false); + // Add the copy into history buffer. + writeHistoryItem(elapsedRealtimeMs, uptimeMs, copy, HistoryItem.CMD_UPDATE); + return; + } + + if (dataSize == 0) { + // The history is currently empty; we need it to start with a time stamp. + cur.currentTime = mClock.currentTimeMillis(); + writeHistoryItem(elapsedRealtimeMs, uptimeMs, cur, HistoryItem.CMD_RESET); + } + writeHistoryItem(elapsedRealtimeMs, uptimeMs, cur, HistoryItem.CMD_UPDATE); + } + + private void writeHistoryItem(long elapsedRealtimeMs, + @SuppressWarnings("UnusedVariable") long uptimeMs, HistoryItem cur, byte cmd) { + if (mBatteryStatsHistoryIterator != null) { + throw new IllegalStateException("Can't do this while iterating history!"); + } + mHistoryBufferLastPos = mHistoryBuffer.dataPosition(); + mHistoryLastLastWritten.setTo(mHistoryLastWritten); + final boolean hasTags = mHistoryLastWritten.tagsFirstOccurrence || cur.tagsFirstOccurrence; + mHistoryLastWritten.setTo(mHistoryBaseTimeMs + elapsedRealtimeMs, cmd, cur); + mHistoryLastWritten.tagsFirstOccurrence = hasTags; + mHistoryLastWritten.states &= mActiveHistoryStates; + mHistoryLastWritten.states2 &= mActiveHistoryStates2; + writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten); + mLastHistoryElapsedRealtimeMs = elapsedRealtimeMs; + cur.wakelockTag = null; + cur.wakeReasonTag = null; + cur.eventCode = HistoryItem.EVENT_NONE; + cur.eventTag = null; + cur.tagsFirstOccurrence = false; + if (DEBUG) { + Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos + + " now " + mHistoryBuffer.dataPosition() + + " size is now " + mHistoryBuffer.dataSize()); + } + } + + /* + The history delta format uses flags to denote further data in subsequent ints in the parcel. + + There is always the first token, which may contain the delta time, or an indicator of + the length of the time (int or long) following this token. + + First token: always present, + 31 23 15 7 0 + â–ˆM|L|K|J|I|H|G|Fâ–ˆE|D|C|B|A|T|T|Tâ–ˆT|T|T|T|T|T|T|Tâ–ˆT|T|T|T|T|T|T|Tâ–ˆ + + T: the delta time if it is <= 0x7fffd. Otherwise 0x7fffe indicates an int immediately + follows containing the time, and 0x7ffff indicates a long immediately follows with the + delta time. + A: battery level changed and an int follows with battery data. + B: state changed and an int follows with state change data. + C: state2 has changed and an int follows with state2 change data. + D: wakelock/wakereason has changed and an wakelock/wakereason struct follows. + E: event data has changed and an event struct follows. + F: battery charge in coulombs has changed and an int with the charge follows. + G: state flag denoting that the mobile radio was active. + H: state flag denoting that the wifi radio was active. + I: state flag denoting that a wifi scan occurred. + J: state flag denoting that a wifi full lock was held. + K: state flag denoting that the gps was on. + L: state flag denoting that a wakelock was held. + M: state flag denoting that the cpu was running. + + Time int/long: if T in the first token is 0x7ffff or 0x7fffe, then an int or long follows + with the time delta. + + Battery level int: if A in the first token is set, + 31 23 15 7 0 + â–ˆL|L|L|L|L|L|L|Tâ–ˆT|T|T|T|T|T|T|Tâ–ˆT|V|V|V|V|V|V|Vâ–ˆV|V|V|V|V|V|V|Dâ–ˆ + + D: indicates that extra history details follow. + V: the battery voltage. + T: the battery temperature. + L: the battery level (out of 100). + + State change int: if B in the first token is set, + 31 23 15 7 0 + â–ˆS|S|S|H|H|H|P|Pâ–ˆF|E|D|C|B| | |Aâ–ˆ | | | | | | | â–ˆ | | | | | | | â–ˆ + + A: wifi multicast was on. + B: battery was plugged in. + C: screen was on. + D: phone was scanning for signal. + E: audio was on. + F: a sensor was active. + + State2 change int: if C in the first token is set, + 31 23 15 7 0 + â–ˆM|L|K|J|I|H|H|Gâ–ˆF|E|D|C| | | | â–ˆ | | | | | | | â–ˆ |B|B|B|A|A|A|Aâ–ˆ + + A: 4 bits indicating the wifi supplicant state: {@link BatteryStats#WIFI_SUPPL_STATE_NAMES}. + B: 3 bits indicating the wifi signal strength: 0, 1, 2, 3, 4. + C: a bluetooth scan was active. + D: the camera was active. + E: bluetooth was on. + F: a phone call was active. + G: the device was charging. + H: 2 bits indicating the device-idle (doze) state: off, light, full + I: the flashlight was on. + J: wifi was on. + K: wifi was running. + L: video was playing. + M: power save mode was on. + + Wakelock/wakereason struct: if D in the first token is set, + Event struct: if E in the first token is set, + History step details struct: if D in the battery level int is set, + + Battery charge int: if F in the first token is set, an int representing the battery charge + in coulombs follows. + */ + /** + * Writes the delta between the previous and current history items into history buffer. + */ + public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) { + if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) { + dest.writeInt(BatteryStatsHistory.DELTA_TIME_ABS); + cur.writeToParcel(dest, 0); + return; + } + + final long deltaTime = cur.time - last.time; + final int lastBatteryLevelInt = buildBatteryLevelInt(last); + final int lastStateInt = buildStateInt(last); + + int deltaTimeToken; + if (deltaTime < 0 || deltaTime > Integer.MAX_VALUE) { + deltaTimeToken = BatteryStatsHistory.DELTA_TIME_LONG; + } else if (deltaTime >= BatteryStatsHistory.DELTA_TIME_ABS) { + deltaTimeToken = BatteryStatsHistory.DELTA_TIME_INT; + } else { + deltaTimeToken = (int) deltaTime; + } + int firstToken = deltaTimeToken | (cur.states & BatteryStatsHistory.DELTA_STATE_MASK); + final int includeStepDetails = mLastHistoryStepLevel > cur.batteryLevel + ? BatteryStatsHistory.BATTERY_DELTA_LEVEL_FLAG : 0; + mLastHistoryStepLevel = cur.batteryLevel; + final int batteryLevelInt = buildBatteryLevelInt(cur) | includeStepDetails; + final boolean batteryLevelIntChanged = batteryLevelInt != lastBatteryLevelInt; + if (batteryLevelIntChanged) { + firstToken |= BatteryStatsHistory.DELTA_BATTERY_LEVEL_FLAG; + } + final int stateInt = buildStateInt(cur); + final boolean stateIntChanged = stateInt != lastStateInt; + if (stateIntChanged) { + firstToken |= BatteryStatsHistory.DELTA_STATE_FLAG; + } + final boolean state2IntChanged = cur.states2 != last.states2; + if (state2IntChanged) { + firstToken |= BatteryStatsHistory.DELTA_STATE2_FLAG; + } + if (cur.wakelockTag != null || cur.wakeReasonTag != null) { + firstToken |= BatteryStatsHistory.DELTA_WAKELOCK_FLAG; + } + if (cur.eventCode != HistoryItem.EVENT_NONE) { + firstToken |= BatteryStatsHistory.DELTA_EVENT_FLAG; + } + + final boolean batteryChargeChanged = cur.batteryChargeUah != last.batteryChargeUah; + if (batteryChargeChanged) { + firstToken |= BatteryStatsHistory.DELTA_BATTERY_CHARGE_FLAG; + } + dest.writeInt(firstToken); + if (DEBUG) { + Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken) + + " deltaTime=" + deltaTime); + } + + if (deltaTimeToken >= BatteryStatsHistory.DELTA_TIME_INT) { + if (deltaTimeToken == BatteryStatsHistory.DELTA_TIME_INT) { + if (DEBUG) Slog.i(TAG, "WRITE DELTA: int deltaTime=" + (int) deltaTime); + dest.writeInt((int) deltaTime); + } else { + if (DEBUG) Slog.i(TAG, "WRITE DELTA: long deltaTime=" + deltaTime); + dest.writeLong(deltaTime); + } + } + if (batteryLevelIntChanged) { + dest.writeInt(batteryLevelInt); + if (DEBUG) { + Slog.i(TAG, "WRITE DELTA: batteryToken=0x" + + Integer.toHexString(batteryLevelInt) + + " batteryLevel=" + cur.batteryLevel + + " batteryTemp=" + cur.batteryTemperature + + " batteryVolt=" + (int) cur.batteryVoltage); + } + } + if (stateIntChanged) { + dest.writeInt(stateInt); + if (DEBUG) { + Slog.i(TAG, "WRITE DELTA: stateToken=0x" + + Integer.toHexString(stateInt) + + " batteryStatus=" + cur.batteryStatus + + " batteryHealth=" + cur.batteryHealth + + " batteryPlugType=" + cur.batteryPlugType + + " states=0x" + Integer.toHexString(cur.states)); + } + } + if (state2IntChanged) { + dest.writeInt(cur.states2); + if (DEBUG) { + Slog.i(TAG, "WRITE DELTA: states2=0x" + + Integer.toHexString(cur.states2)); + } + } + if (cur.wakelockTag != null || cur.wakeReasonTag != null) { + int wakeLockIndex; + int wakeReasonIndex; + if (cur.wakelockTag != null) { + wakeLockIndex = writeHistoryTag(cur.wakelockTag); + if (DEBUG) { + Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx + + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string); + } + } else { + wakeLockIndex = 0xffff; + } + if (cur.wakeReasonTag != null) { + wakeReasonIndex = writeHistoryTag(cur.wakeReasonTag); + if (DEBUG) { + Slog.i(TAG, "WRITE DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx + + " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string); + } + } else { + wakeReasonIndex = 0xffff; + } + dest.writeInt((wakeReasonIndex << 16) | wakeLockIndex); + if (cur.wakelockTag != null + && (wakeLockIndex & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { + cur.wakelockTag.writeToParcel(dest, 0); + cur.tagsFirstOccurrence = true; + } + if (cur.wakeReasonTag != null + && (wakeReasonIndex & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { + cur.wakeReasonTag.writeToParcel(dest, 0); + cur.tagsFirstOccurrence = true; + } + } + if (cur.eventCode != HistoryItem.EVENT_NONE) { + final int index = writeHistoryTag(cur.eventTag); + final int codeAndIndex = (cur.eventCode & 0xffff) | (index << 16); + dest.writeInt(codeAndIndex); + if ((index & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { + cur.eventTag.writeToParcel(dest, 0); + cur.tagsFirstOccurrence = true; + } + if (DEBUG) { + Slog.i(TAG, "WRITE DELTA: event=" + cur.eventCode + " tag=#" + + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":" + + cur.eventTag.string); + } + } + + cur.stepDetails = mStepDetailsCalculator.getHistoryStepDetails(); + if (includeStepDetails != 0) { + cur.stepDetails.writeToParcel(dest); + } + + if (batteryChargeChanged) { + if (DEBUG) Slog.i(TAG, "WRITE DELTA: batteryChargeUah=" + cur.batteryChargeUah); + dest.writeInt(cur.batteryChargeUah); + } + dest.writeDouble(cur.modemRailChargeMah); + dest.writeDouble(cur.wifiRailChargeMah); + } + + private int buildBatteryLevelInt(HistoryItem h) { + return ((((int) h.batteryLevel) << 25) & 0xfe000000) + | ((((int) h.batteryTemperature) << 15) & 0x01ff8000) + | ((((int) h.batteryVoltage) << 1) & 0x00007ffe); + } + + private int buildStateInt(HistoryItem h) { + int plugType = 0; + if ((h.batteryPlugType & BatteryManager.BATTERY_PLUGGED_AC) != 0) { + plugType = 1; + } else if ((h.batteryPlugType & BatteryManager.BATTERY_PLUGGED_USB) != 0) { + plugType = 2; + } else if ((h.batteryPlugType & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0) { + plugType = 3; + } + return ((h.batteryStatus & BatteryStatsHistory.STATE_BATTERY_STATUS_MASK) + << BatteryStatsHistory.STATE_BATTERY_STATUS_SHIFT) + | ((h.batteryHealth & BatteryStatsHistory.STATE_BATTERY_HEALTH_MASK) + << BatteryStatsHistory.STATE_BATTERY_HEALTH_SHIFT) + | ((plugType & BatteryStatsHistory.STATE_BATTERY_PLUG_MASK) + << BatteryStatsHistory.STATE_BATTERY_PLUG_SHIFT) + | (h.states & (~BatteryStatsHistory.STATE_BATTERY_MASK)); + } + + /** + * Returns the index for the specified tag. If this is the first time the tag is encountered + * while writing the current history buffer, the method returns + * <code>(index | TAG_FIRST_OCCURRENCE_FLAG)</code> + */ + private int writeHistoryTag(HistoryTag tag) { + if (tag.string == null) { + Slog.wtfStack(TAG, "writeHistoryTag called with null name"); + } + + final int stringLength = tag.string.length(); + if (stringLength > MAX_HISTORY_TAG_STRING_LENGTH) { + Slog.e(TAG, "Long battery history tag: " + tag.string); + tag.string = tag.string.substring(0, MAX_HISTORY_TAG_STRING_LENGTH); + } + + Integer idxObj = mHistoryTagPool.get(tag); + int idx; + if (idxObj != null) { + idx = idxObj; + if ((idx & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { + mHistoryTagPool.put(tag, idx & ~BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG); + } + return idx; + } else if (mNextHistoryTagIdx < HISTORY_TAG_INDEX_LIMIT) { + idx = mNextHistoryTagIdx; + HistoryTag key = new HistoryTag(); + key.setTo(tag); + tag.poolIdx = idx; + mHistoryTagPool.put(key, idx); + mNextHistoryTagIdx++; + + mNumHistoryTagChars += stringLength + 1; + if (mHistoryTags != null) { + mHistoryTags.put(idx, key); + } + return idx | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG; + } else { + // Tag pool overflow: include the tag itself in the parcel + return HISTORY_TAG_INDEX_LIMIT | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG; + } + } + + /** + * Don't allow any more batching in to the current history event. + */ + public void commitCurrentHistoryBatchLocked() { + mHistoryLastWritten.cmd = HistoryItem.CMD_NULL; + } + + /** + * Saves the accumulated history buffer in the active file, see {@link #getActiveFile()} . + */ + public void writeHistory() { + if (mActiveFile == null) { + Slog.w(TAG, "writeHistory: no history file associated with this instance"); + return; + } + + Parcel p = Parcel.obtain(); + try { + final long start = SystemClock.uptimeMillis(); + writeHistoryBuffer(p); + if (DEBUG) { + Slog.d(TAG, "writeHistoryBuffer duration ms:" + + (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize()); + } + writeParcelToFileLocked(p, mActiveFile); + } finally { + p.recycle(); + } + } + + /** + * Reads history buffer from a persisted Parcel. + */ + public void readHistoryBuffer(Parcel in) throws ParcelFormatException { + final int version = in.readInt(); + if (version != BatteryStatsHistory.VERSION) { + Slog.w("BatteryStats", "readHistoryBuffer: version got " + version + + ", expected " + BatteryStatsHistory.VERSION + "; erasing old stats"); + return; + } + + final long historyBaseTime = in.readLong(); + + mHistoryBuffer.setDataSize(0); + mHistoryBuffer.setDataPosition(0); + + int bufSize = in.readInt(); + int curPos = in.dataPosition(); + if (bufSize >= (mMaxHistoryBufferSize * 100)) { + throw new ParcelFormatException( + "File corrupt: history data buffer too large " + bufSize); + } else if ((bufSize & ~3) != bufSize) { + throw new ParcelFormatException( + "File corrupt: history data buffer not aligned " + bufSize); + } else { + if (DEBUG) { + Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize + + " bytes at " + curPos); + } + mHistoryBuffer.appendFrom(in, curPos, bufSize); + in.setDataPosition(curPos + bufSize); + } + + if (DEBUG) { + StringBuilder sb = new StringBuilder(128); + sb.append("****************** OLD mHistoryBaseTimeMs: "); + TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); + Slog.i(TAG, sb.toString()); + } + mHistoryBaseTimeMs = historyBaseTime; + if (DEBUG) { + StringBuilder sb = new StringBuilder(128); + sb.append("****************** NEW mHistoryBaseTimeMs: "); + TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); + Slog.i(TAG, sb.toString()); + } + + // We are just arbitrarily going to insert 1 minute from the sample of + // the last run until samples in this run. + if (mHistoryBaseTimeMs > 0) { + long oldnow = mClock.elapsedRealtime(); + mHistoryBaseTimeMs = mHistoryBaseTimeMs - oldnow + 1; + if (DEBUG) { + StringBuilder sb = new StringBuilder(128); + sb.append("****************** ADJUSTED mHistoryBaseTimeMs: "); + TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); + Slog.i(TAG, sb.toString()); + } + } + } + + private void writeHistoryBuffer(Parcel out) { + if (DEBUG) { + StringBuilder sb = new StringBuilder(128); + sb.append("****************** WRITING mHistoryBaseTimeMs: "); + TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); + sb.append(" mLastHistoryElapsedRealtimeMs: "); + TimeUtils.formatDuration(mLastHistoryElapsedRealtimeMs, sb); + Slog.i(TAG, sb.toString()); + } + out.writeInt(BatteryStatsHistory.VERSION); + out.writeLong(mHistoryBaseTimeMs + mLastHistoryElapsedRealtimeMs); + out.writeInt(mHistoryBuffer.dataSize()); + if (DEBUG) { + Slog.i(TAG, "***************** WRITING HISTORY: " + + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition()); + } + out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize()); + } + + private void writeParcelToFileLocked(Parcel p, AtomicFile file) { + FileOutputStream fos = null; + mWriteLock.lock(); + try { + final long startTimeMs = SystemClock.uptimeMillis(); + fos = file.startWrite(); + fos.write(p.marshall()); + fos.flush(); + file.finishWrite(fos); + if (DEBUG) { + Slog.d(TAG, "writeParcelToFileLocked file:" + file.getBaseFile().getPath() + + " duration ms:" + (SystemClock.uptimeMillis() - startTimeMs) + + " bytes:" + p.dataSize()); + } + com.android.internal.logging.EventLogTags.writeCommitSysConfigFile( + "batterystats", SystemClock.uptimeMillis() - startTimeMs); + } catch (IOException e) { + Slog.w(TAG, "Error writing battery statistics", e); + file.failWrite(fos); + } finally { + mWriteLock.unlock(); + } + } + + /** + * Returns the total number of history tags in the tag pool. + */ + public int getHistoryStringPoolSize() { + return mHistoryTagPool.size(); + } + + /** + * Returns the total number of bytes occupied by the history tag pool. + */ + public int getHistoryStringPoolBytes() { + return mNumHistoryTagChars; + } + + /** + * Returns the string held by the requested history tag. + */ + public String getHistoryTagPoolString(int index) { + ensureHistoryTagArray(); + HistoryTag historyTag = mHistoryTags.get(index); + return historyTag != null ? historyTag.string : null; + } + + /** + * Returns the UID held by the requested history tag. + */ + public int getHistoryTagPoolUid(int index) { + ensureHistoryTagArray(); + HistoryTag historyTag = mHistoryTags.get(index); + return historyTag != null ? historyTag.uid : Process.INVALID_UID; + } + + private void ensureHistoryTagArray() { + if (mHistoryTags != null) { + return; + } + + mHistoryTags = new SparseArray<>(mHistoryTagPool.size()); + for (Map.Entry<HistoryTag, Integer> entry : mHistoryTagPool.entrySet()) { + mHistoryTags.put(entry.getValue() & ~BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG, + entry.getKey()); + } + } } diff --git a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java index de8b414c4b78..1bf878cb9119 100644 --- a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java +++ b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java @@ -36,7 +36,6 @@ public class BatteryStatsHistoryIterator { public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history) { mBatteryStatsHistory = history; - mBatteryStatsHistory.startIteratingHistory(); } /** @@ -231,4 +230,11 @@ public class BatteryStatsHistoryIterator { out.batteryTemperature = (short) ((batteryLevelInt & 0x01ff8000) >>> 15); out.batteryVoltage = (char) ((batteryLevelInt & 0x00007ffe) >>> 1); } + + /** + * Should be called when iteration is complete. + */ + public void close() { + mBatteryStatsHistory.finishIteratingHistory(); + } } diff --git a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java index fe4aa534df6f..df902c2916ba 100644 --- a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java @@ -657,7 +657,7 @@ public class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStat // Now that we have finally received all the data, we can tell mStats about it. synchronized (mStats) { - mStats.addHistoryEventLocked( + mStats.recordHistoryEventLocked( elapsedRealtime, uptime, BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS, 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 0c9ada8fa6db..968f9161b3c1 100644 --- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java +++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java @@ -108,6 +108,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.os.BatteryStatsHistory; +import com.android.internal.os.BatteryStatsHistory.HistoryStepDetailsCalculator; import com.android.internal.os.BatteryStatsHistoryIterator; import com.android.internal.os.BinderCallsStats; import com.android.internal.os.BinderTransactionNameResolver; @@ -173,7 +174,6 @@ public class BatteryStatsImpl extends BatteryStats { private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY; private static final boolean DEBUG_BINDER_STATS = false; private static final boolean DEBUG_MEMORY = false; - private static final boolean DEBUG_HISTORY = false; // TODO: remove "tcp" from network methods, since we measure total stats. @@ -322,6 +322,11 @@ public class BatteryStatsImpl extends BatteryStats { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) protected Queue<UidToRemove> mPendingRemovedUids = new LinkedList<>(); + @NonNull + BatteryStatsHistory copyHistory() { + return mHistory.copy(); + } + @VisibleForTesting public final class UidToRemove { private final int mStartUid; @@ -413,7 +418,7 @@ public class BatteryStatsImpl extends BatteryStats { if (changed) { final long uptimeMs = mClock.uptimeMillis(); final long elapsedRealtimeMs = mClock.elapsedRealtime(); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.writeHistoryItem(elapsedRealtimeMs, uptimeMs); } } } @@ -668,16 +673,16 @@ public class BatteryStatsImpl extends BatteryStats { /** * Mapping isolated uids to the actual owning app uid. */ - final SparseIntArray mIsolatedUids = new SparseIntArray(); + private final SparseIntArray mIsolatedUids = new SparseIntArray(); /** * Internal reference count of isolated uids. */ - final SparseIntArray mIsolatedUidRefCounts = new SparseIntArray(); + private final SparseIntArray mIsolatedUidRefCounts = new SparseIntArray(); /** * The statistics we have collected organized by uids. */ - final SparseArray<BatteryStatsImpl.Uid> mUidStats = new SparseArray<>(); + private final SparseArray<BatteryStatsImpl.Uid> mUidStats = new SparseArray<>(); // A set of pools of currently active timers. When a timer is queried, we will divide the // elapsed time by the number of active timers to arrive at that timer's share of the time. @@ -685,20 +690,21 @@ public class BatteryStatsImpl extends BatteryStats { // changes. @VisibleForTesting protected ArrayList<StopwatchTimer> mPartialTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mFullTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mDrawTimers = new ArrayList<>(); - final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers = new SparseArray<>(); - final ArrayList<StopwatchTimer> mWifiRunningTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mFullWifiLockTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mWifiMulticastTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mWifiScanTimers = new ArrayList<>(); - final SparseArray<ArrayList<StopwatchTimer>> mWifiBatchedScanTimers = new SparseArray<>(); - final ArrayList<StopwatchTimer> mAudioTurnedOnTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mVideoTurnedOnTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mFlashlightTurnedOnTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mCameraTurnedOnTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mBluetoothScanOnTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mFullTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mDrawTimers = new ArrayList<>(); + private final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers = new SparseArray<>(); + private final ArrayList<StopwatchTimer> mWifiRunningTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mFullWifiLockTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mWifiMulticastTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mWifiScanTimers = new ArrayList<>(); + private final SparseArray<ArrayList<StopwatchTimer>> mWifiBatchedScanTimers = + new SparseArray<>(); + private final ArrayList<StopwatchTimer> mAudioTurnedOnTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mVideoTurnedOnTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mFlashlightTurnedOnTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mCameraTurnedOnTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mBluetoothScanOnTimers = new ArrayList<>(); // Last partial timers we use for distributing CPU usage. @VisibleForTesting @@ -713,69 +719,24 @@ public class BatteryStatsImpl extends BatteryStats { protected final TimeBase mOnBatteryScreenOffTimeBase = new TimeBase(true); private boolean mSystemReady; - boolean mShuttingDown; - - final HistoryEventTracker mActiveEvents = new HistoryEventTracker(); - - long mHistoryBaseTimeMs; - protected boolean mHaveBatteryLevel = false; - protected boolean mRecordingHistory = false; - int mNumHistoryItems; - - private static final int HISTORY_TAG_INDEX_LIMIT = 0x7ffe; - private static final int MAX_HISTORY_TAG_STRING_LENGTH = 1024; - - final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>(); - private SparseArray<HistoryTag> mHistoryTags; - final Parcel mHistoryBuffer = Parcel.obtain(); - final HistoryItem mHistoryLastWritten = new HistoryItem(); - final HistoryItem mHistoryLastLastWritten = new HistoryItem(); - final HistoryItem mHistoryAddTmp = new HistoryItem(); - int mNextHistoryTagIdx = 0; - int mNumHistoryTagChars = 0; - int mHistoryBufferLastPos = -1; - int mActiveHistoryStates = 0xffffffff; - int mActiveHistoryStates2 = 0xffffffff; - long mLastHistoryElapsedRealtimeMs = 0; - long mTrackRunningHistoryElapsedRealtimeMs = 0; - long mTrackRunningHistoryUptimeMs = 0; + private boolean mShuttingDown; + + private final HistoryEventTracker mActiveEvents = new HistoryEventTracker(); + private final HistoryStepDetailsCalculatorImpl mStepDetailsCalculator = + new HistoryStepDetailsCalculatorImpl(); + + private boolean mHaveBatteryLevel = false; + private boolean mBatteryPluggedIn; + private int mBatteryStatus; + private int mBatteryLevel; + private int mBatteryPlugType; + private int mBatteryChargeUah; + private int mBatteryHealth; + private int mBatteryTemperature; + private int mBatteryVoltageMv = -1; @NonNull - final BatteryStatsHistory mBatteryStatsHistory; - - final HistoryItem mHistoryCur = new HistoryItem(); - - // Used by computeHistoryStepDetails - HistoryStepDetails mLastHistoryStepDetails = null; - byte mLastHistoryStepLevel = 0; - final HistoryStepDetails mCurHistoryStepDetails = new HistoryStepDetails(); - final HistoryStepDetails mTmpHistoryStepDetails = new HistoryStepDetails(); - - /** - * Total time (in milliseconds) spent executing in user code. - */ - long mLastStepCpuUserTimeMs; - long mCurStepCpuUserTimeMs; - /** - * Total time (in milliseconds) spent executing in kernel code. - */ - long mLastStepCpuSystemTimeMs; - long mCurStepCpuSystemTimeMs; - /** - * Times from /proc/stat (but measured in milliseconds). - */ - long mLastStepStatUserTimeMs; - long mLastStepStatSystemTimeMs; - long mLastStepStatIOWaitTimeMs; - long mLastStepStatIrqTimeMs; - long mLastStepStatSoftIrqTimeMs; - long mLastStepStatIdleTimeMs; - long mCurStepStatUserTimeMs; - long mCurStepStatSystemTimeMs; - long mCurStepStatIOWaitTimeMs; - long mCurStepStatIrqTimeMs; - long mCurStepStatSoftIrqTimeMs; - long mCurStepStatIdleTimeMs; + private final BatteryStatsHistory mHistory; private BatteryStatsHistoryIterator mBatteryStatsHistoryIterator; @@ -1391,7 +1352,6 @@ public class BatteryStatsImpl extends BatteryStats { int mDischargeUnplugLevel; int mDischargePlugLevel; int mDischargeCurrentLevel; - int mCurrentBatteryLevel; int mLowDischargeAmountSinceCharge; int mHighDischargeAmountSinceCharge; int mDischargeScreenOnUnplugLevel; @@ -1443,7 +1403,6 @@ public class BatteryStatsImpl extends BatteryStats { private int mNumConnectivityChange; - private int mBatteryVoltageMv = -1; private int mEstimatedBatteryCapacityMah = -1; private int mLastLearnedBatteryCapacityUah = -1; @@ -1627,28 +1586,27 @@ public class BatteryStatsImpl extends BatteryStats { } public BatteryStatsImpl(Clock clock) { - this(clock, (File) null); + this(clock, null); } public BatteryStatsImpl(Clock clock, File historyDirectory) { init(clock); + mHandler = null; + mConstants = new Constants(mHandler); mStartClockTimeMs = clock.currentTimeMillis(); mCheckinFile = null; mDailyFile = null; if (historyDirectory == null) { mStatsFile = null; - mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer); + mHistory = new BatteryStatsHistory(mStepDetailsCalculator, mClock); } else { mStatsFile = new AtomicFile(new File(historyDirectory, "batterystats.bin")); - mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer, historyDirectory, - this::getMaxHistoryFiles); + mHistory = new BatteryStatsHistory(historyDirectory, mConstants.MAX_HISTORY_FILES, + mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, mClock); } - mHandler = null; mPlatformIdleStateCallback = null; mMeasuredEnergyRetriever = null; mUserInfoProvider = null; - mConstants = new Constants(mHandler); - clearHistoryLocked(); } private void init(Clock clock) { @@ -3911,406 +3869,188 @@ public class BatteryStatsImpl extends BatteryStats { return kmt; } - /** - * Returns the index for the specified tag. If this is the first time the tag is encountered - * while writing the current history buffer, the method returns - * <code>(index | TAG_FIRST_OCCURRENCE_FLAG)</code> - */ - private int writeHistoryTag(HistoryTag tag) { - if (tag.string == null) { - Slog.wtfStack(TAG, "writeHistoryTag called with null name"); - } - - final int stringLength = tag.string.length(); - if (stringLength > MAX_HISTORY_TAG_STRING_LENGTH) { - Slog.e(TAG, "Long battery history tag: " + tag.string); - tag.string = tag.string.substring(0, MAX_HISTORY_TAG_STRING_LENGTH); - } - - Integer idxObj = mHistoryTagPool.get(tag); - int idx; - if (idxObj != null) { - idx = idxObj; - if ((idx & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { - mHistoryTagPool.put(tag, idx & ~BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG); - } - return idx; - } else if (mNextHistoryTagIdx < HISTORY_TAG_INDEX_LIMIT) { - idx = mNextHistoryTagIdx; - HistoryTag key = new HistoryTag(); - key.setTo(tag); - tag.poolIdx = idx; - mHistoryTagPool.put(key, idx); - mNextHistoryTagIdx++; - - mNumHistoryTagChars += stringLength + 1; - if (mHistoryTags != null) { - mHistoryTags.put(idx, key); - } - return idx | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG; - } else { - // Tag pool overflow: include the tag itself in the parcel - return HISTORY_TAG_INDEX_LIMIT | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG; - } - } - - /* - The history delta format uses flags to denote further data in subsequent ints in the parcel. - - There is always the first token, which may contain the delta time, or an indicator of - the length of the time (int or long) following this token. - - First token: always present, - 31 23 15 7 0 - â–ˆM|L|K|J|I|H|G|Fâ–ˆE|D|C|B|A|T|T|Tâ–ˆT|T|T|T|T|T|T|Tâ–ˆT|T|T|T|T|T|T|Tâ–ˆ - - T: the delta time if it is <= 0x7fffd. Otherwise 0x7fffe indicates an int immediately - follows containing the time, and 0x7ffff indicates a long immediately follows with the - delta time. - A: battery level changed and an int follows with battery data. - B: state changed and an int follows with state change data. - C: state2 has changed and an int follows with state2 change data. - D: wakelock/wakereason has changed and an wakelock/wakereason struct follows. - E: event data has changed and an event struct follows. - F: battery charge in coulombs has changed and an int with the charge follows. - G: state flag denoting that the mobile radio was active. - H: state flag denoting that the wifi radio was active. - I: state flag denoting that a wifi scan occurred. - J: state flag denoting that a wifi full lock was held. - K: state flag denoting that the gps was on. - L: state flag denoting that a wakelock was held. - M: state flag denoting that the cpu was running. - - Time int/long: if T in the first token is 0x7ffff or 0x7fffe, then an int or long follows - with the time delta. - - Battery level int: if A in the first token is set, - 31 23 15 7 0 - â–ˆL|L|L|L|L|L|L|Tâ–ˆT|T|T|T|T|T|T|Tâ–ˆT|V|V|V|V|V|V|Vâ–ˆV|V|V|V|V|V|V|Dâ–ˆ - - D: indicates that extra history details follow. - V: the battery voltage. - T: the battery temperature. - L: the battery level (out of 100). - - State change int: if B in the first token is set, - 31 23 15 7 0 - â–ˆS|S|S|H|H|H|P|Pâ–ˆF|E|D|C|B| | |Aâ–ˆ | | | | | | | â–ˆ | | | | | | | â–ˆ - - A: wifi multicast was on. - B: battery was plugged in. - C: screen was on. - D: phone was scanning for signal. - E: audio was on. - F: a sensor was active. - - State2 change int: if C in the first token is set, - 31 23 15 7 0 - â–ˆM|L|K|J|I|H|H|Gâ–ˆF|E|D|C| | | | â–ˆ | | | | | | | â–ˆ |B|B|B|A|A|A|Aâ–ˆ - - A: 4 bits indicating the wifi supplicant state: {@link BatteryStats#WIFI_SUPPL_STATE_NAMES}. - B: 3 bits indicating the wifi signal strength: 0, 1, 2, 3, 4. - C: a bluetooth scan was active. - D: the camera was active. - E: bluetooth was on. - F: a phone call was active. - G: the device was charging. - H: 2 bits indicating the device-idle (doze) state: off, light, full - I: the flashlight was on. - J: wifi was on. - K: wifi was running. - L: video was playing. - M: power save mode was on. - - Wakelock/wakereason struct: if D in the first token is set, - TODO(adamlesinski): describe wakelock/wakereason struct. - - Event struct: if E in the first token is set, - TODO(adamlesinski): describe the event struct. - - History step details struct: if D in the battery level int is set, - TODO(adamlesinski): describe the history step details struct. - - Battery charge int: if F in the first token is set, an int representing the battery charge - in coulombs follows. - */ + private class HistoryStepDetailsCalculatorImpl implements HistoryStepDetailsCalculator { + private final HistoryStepDetails mDetails = new HistoryStepDetails(); - @GuardedBy("this") - public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) { - if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) { - dest.writeInt(BatteryStatsHistory.DELTA_TIME_ABS); - cur.writeToParcel(dest, 0); - return; - } + private boolean mHasHistoryStepDetails; - final long deltaTime = cur.time - last.time; - final int lastBatteryLevelInt = buildBatteryLevelInt(last); - final int lastStateInt = buildStateInt(last); + private int mLastHistoryStepLevel; - int deltaTimeToken; - if (deltaTime < 0 || deltaTime > Integer.MAX_VALUE) { - deltaTimeToken = BatteryStatsHistory.DELTA_TIME_LONG; - } else if (deltaTime >= BatteryStatsHistory.DELTA_TIME_ABS) { - deltaTimeToken = BatteryStatsHistory.DELTA_TIME_INT; - } else { - deltaTimeToken = (int)deltaTime; - } - int firstToken = deltaTimeToken | (cur.states & BatteryStatsHistory.DELTA_STATE_MASK); - final int includeStepDetails = mLastHistoryStepLevel > cur.batteryLevel - ? BatteryStatsHistory.BATTERY_DELTA_LEVEL_FLAG : 0; - final boolean computeStepDetails = includeStepDetails != 0 - || mLastHistoryStepDetails == null; - final int batteryLevelInt = buildBatteryLevelInt(cur) | includeStepDetails; - final boolean batteryLevelIntChanged = batteryLevelInt != lastBatteryLevelInt; - if (batteryLevelIntChanged) { - firstToken |= BatteryStatsHistory.DELTA_BATTERY_LEVEL_FLAG; - } - final int stateInt = buildStateInt(cur); - final boolean stateIntChanged = stateInt != lastStateInt; - if (stateIntChanged) { - firstToken |= BatteryStatsHistory.DELTA_STATE_FLAG; - } - final boolean state2IntChanged = cur.states2 != last.states2; - if (state2IntChanged) { - firstToken |= BatteryStatsHistory.DELTA_STATE2_FLAG; - } - if (cur.wakelockTag != null || cur.wakeReasonTag != null) { - firstToken |= BatteryStatsHistory.DELTA_WAKELOCK_FLAG; - } - if (cur.eventCode != HistoryItem.EVENT_NONE) { - firstToken |= BatteryStatsHistory.DELTA_EVENT_FLAG; - } - - final boolean batteryChargeChanged = cur.batteryChargeUah != last.batteryChargeUah; - if (batteryChargeChanged) { - firstToken |= BatteryStatsHistory.DELTA_BATTERY_CHARGE_FLAG; - } - dest.writeInt(firstToken); - if (DEBUG) Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken) - + " deltaTime=" + deltaTime); - - if (deltaTimeToken >= BatteryStatsHistory.DELTA_TIME_INT) { - if (deltaTimeToken == BatteryStatsHistory.DELTA_TIME_INT) { - if (DEBUG) Slog.i(TAG, "WRITE DELTA: int deltaTime=" + (int)deltaTime); - dest.writeInt((int)deltaTime); - } else { - if (DEBUG) Slog.i(TAG, "WRITE DELTA: long deltaTime=" + deltaTime); - dest.writeLong(deltaTime); - } - } - if (batteryLevelIntChanged) { - dest.writeInt(batteryLevelInt); - if (DEBUG) Slog.i(TAG, "WRITE DELTA: batteryToken=0x" - + Integer.toHexString(batteryLevelInt) - + " batteryLevel=" + cur.batteryLevel - + " batteryTemp=" + cur.batteryTemperature - + " batteryVolt=" + (int)cur.batteryVoltage); - } - if (stateIntChanged) { - dest.writeInt(stateInt); - if (DEBUG) Slog.i(TAG, "WRITE DELTA: stateToken=0x" - + Integer.toHexString(stateInt) - + " batteryStatus=" + cur.batteryStatus - + " batteryHealth=" + cur.batteryHealth - + " batteryPlugType=" + cur.batteryPlugType - + " states=0x" + Integer.toHexString(cur.states)); - } - if (state2IntChanged) { - dest.writeInt(cur.states2); - if (DEBUG) Slog.i(TAG, "WRITE DELTA: states2=0x" - + Integer.toHexString(cur.states2)); - } - if (cur.wakelockTag != null || cur.wakeReasonTag != null) { - int wakeLockIndex; - int wakeReasonIndex; - if (cur.wakelockTag != null) { - wakeLockIndex = writeHistoryTag(cur.wakelockTag); - if (DEBUG) Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx - + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string); - } else { - wakeLockIndex = 0xffff; - } - if (cur.wakeReasonTag != null) { - wakeReasonIndex = writeHistoryTag(cur.wakeReasonTag); - if (DEBUG) Slog.i(TAG, "WRITE DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx - + " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string); - } else { - wakeReasonIndex = 0xffff; - } - dest.writeInt((wakeReasonIndex<<16) | wakeLockIndex); - if (cur.wakelockTag != null - && (wakeLockIndex & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { - cur.wakelockTag.writeToParcel(dest, 0); - cur.tagsFirstOccurrence = true; - } - if (cur.wakeReasonTag != null - && (wakeReasonIndex & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { - cur.wakeReasonTag.writeToParcel(dest, 0); - cur.tagsFirstOccurrence = true; - } - } - if (cur.eventCode != HistoryItem.EVENT_NONE) { - final int index = writeHistoryTag(cur.eventTag); - final int codeAndIndex = (cur.eventCode & 0xffff) | (index << 16); - dest.writeInt(codeAndIndex); - if ((index & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { - cur.eventTag.writeToParcel(dest, 0); - cur.tagsFirstOccurrence = true; + /** + * Total time (in milliseconds) spent executing in user code. + */ + private long mLastStepCpuUserTimeMs; + private long mCurStepCpuUserTimeMs; + /** + * Total time (in milliseconds) spent executing in kernel code. + */ + private long mLastStepCpuSystemTimeMs; + private long mCurStepCpuSystemTimeMs; + /** + * Times from /proc/stat (but measured in milliseconds). + */ + private long mLastStepStatUserTimeMs; + private long mLastStepStatSystemTimeMs; + private long mLastStepStatIOWaitTimeMs; + private long mLastStepStatIrqTimeMs; + private long mLastStepStatSoftIrqTimeMs; + private long mLastStepStatIdleTimeMs; + private long mCurStepStatUserTimeMs; + private long mCurStepStatSystemTimeMs; + private long mCurStepStatIOWaitTimeMs; + private long mCurStepStatIrqTimeMs; + private long mCurStepStatSoftIrqTimeMs; + private long mCurStepStatIdleTimeMs; + + @Override + public HistoryStepDetails getHistoryStepDetails() { + if (mBatteryLevel >= mLastHistoryStepLevel && mHasHistoryStepDetails) { + mLastHistoryStepLevel = mBatteryLevel; + return null; } - if (DEBUG) Slog.i(TAG, "WRITE DELTA: event=" + cur.eventCode + " tag=#" - + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":" - + cur.eventTag.string); - } - if (computeStepDetails) { + + // Perform a CPU update right after we do this collection, so we have started + // collecting good data for the next step. + requestImmediateCpuUpdate(); + if (mPlatformIdleStateCallback != null) { - mCurHistoryStepDetails.statSubsystemPowerState = + mDetails.statSubsystemPowerState = mPlatformIdleStateCallback.getSubsystemLowPowerStats(); if (DEBUG) Slog.i(TAG, "WRITE SubsystemPowerState:" + - mCurHistoryStepDetails.statSubsystemPowerState); - - } - computeHistoryStepDetails(mCurHistoryStepDetails, mLastHistoryStepDetails); - if (includeStepDetails != 0) { - mCurHistoryStepDetails.writeToParcel(dest); - } - cur.stepDetails = mCurHistoryStepDetails; - mLastHistoryStepDetails = mCurHistoryStepDetails; - } else { - cur.stepDetails = null; - } - if (mLastHistoryStepLevel < cur.batteryLevel) { - mLastHistoryStepDetails = null; - } - mLastHistoryStepLevel = cur.batteryLevel; - - if (batteryChargeChanged) { - if (DEBUG) Slog.i(TAG, "WRITE DELTA: batteryChargeUah=" + cur.batteryChargeUah); - dest.writeInt(cur.batteryChargeUah); - } - dest.writeDouble(cur.modemRailChargeMah); - dest.writeDouble(cur.wifiRailChargeMah); - } - - private int buildBatteryLevelInt(HistoryItem h) { - return ((((int)h.batteryLevel)<<25)&0xfe000000) - | ((((int)h.batteryTemperature)<<15)&0x01ff8000) - | ((((int)h.batteryVoltage)<<1)&0x00007ffe); - } - - private int buildStateInt(HistoryItem h) { - int plugType = 0; - if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_AC) != 0) { - plugType = 1; - } else if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_USB) != 0) { - plugType = 2; - } else if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0) { - plugType = 3; - } - return ((h.batteryStatus & BatteryStatsHistory.STATE_BATTERY_STATUS_MASK) - << BatteryStatsHistory.STATE_BATTERY_STATUS_SHIFT) - | ((h.batteryHealth & BatteryStatsHistory.STATE_BATTERY_HEALTH_MASK) - << BatteryStatsHistory.STATE_BATTERY_HEALTH_SHIFT) - | ((plugType & BatteryStatsHistory.STATE_BATTERY_PLUG_MASK) - << BatteryStatsHistory.STATE_BATTERY_PLUG_SHIFT) - | (h.states & (~BatteryStatsHistory.STATE_BATTERY_MASK)); - } - - private void computeHistoryStepDetails(final HistoryStepDetails out, - final HistoryStepDetails last) { - final HistoryStepDetails tmp = last != null ? mTmpHistoryStepDetails : out; - - // Perform a CPU update right after we do this collection, so we have started - // collecting good data for the next step. - requestImmediateCpuUpdate(); - - if (last == null) { - // We are not generating a delta, so all we need to do is reset the stats - // we will later be doing a delta from. - final int NU = mUidStats.size(); - for (int i=0; i<NU; i++) { - final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); - uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs; - uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs; - } - mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs; - mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs; - mLastStepStatUserTimeMs = mCurStepStatUserTimeMs; - mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs; - mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs; - mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs; - mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs; - mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs; - tmp.clear(); - return; - } - if (DEBUG) { - Slog.d(TAG, "Step stats last: user=" + mLastStepCpuUserTimeMs + " sys=" - + mLastStepStatSystemTimeMs + " io=" + mLastStepStatIOWaitTimeMs - + " irq=" + mLastStepStatIrqTimeMs + " sirq=" - + mLastStepStatSoftIrqTimeMs + " idle=" + mLastStepStatIdleTimeMs); - Slog.d(TAG, "Step stats cur: user=" + mCurStepCpuUserTimeMs + " sys=" - + mCurStepStatSystemTimeMs + " io=" + mCurStepStatIOWaitTimeMs - + " irq=" + mCurStepStatIrqTimeMs + " sirq=" - + mCurStepStatSoftIrqTimeMs + " idle=" + mCurStepStatIdleTimeMs); - } - out.userTime = (int) (mCurStepCpuUserTimeMs - mLastStepCpuUserTimeMs); - out.systemTime = (int) (mCurStepCpuSystemTimeMs - mLastStepCpuSystemTimeMs); - out.statUserTime = (int) (mCurStepStatUserTimeMs - mLastStepStatUserTimeMs); - out.statSystemTime = (int) (mCurStepStatSystemTimeMs - mLastStepStatSystemTimeMs); - out.statIOWaitTime = (int) (mCurStepStatIOWaitTimeMs - mLastStepStatIOWaitTimeMs); - out.statIrqTime = (int) (mCurStepStatIrqTimeMs - mLastStepStatIrqTimeMs); - out.statSoftIrqTime = (int) (mCurStepStatSoftIrqTimeMs - mLastStepStatSoftIrqTimeMs); - out.statIdlTime = (int) (mCurStepStatIdleTimeMs - mLastStepStatIdleTimeMs); - out.appCpuUid1 = out.appCpuUid2 = out.appCpuUid3 = -1; - out.appCpuUTime1 = out.appCpuUTime2 = out.appCpuUTime3 = 0; - out.appCpuSTime1 = out.appCpuSTime2 = out.appCpuSTime3 = 0; - final int NU = mUidStats.size(); - for (int i=0; i<NU; i++) { - final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); - final int totalUTimeMs = (int) (uid.mCurStepUserTimeMs - uid.mLastStepUserTimeMs); - final int totalSTimeMs = (int) (uid.mCurStepSystemTimeMs - uid.mLastStepSystemTimeMs); - final int totalTimeMs = totalUTimeMs + totalSTimeMs; - uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs; - uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs; - if (totalTimeMs <= (out.appCpuUTime3 + out.appCpuSTime3)) { - continue; - } - if (totalTimeMs <= (out.appCpuUTime2 + out.appCpuSTime2)) { - out.appCpuUid3 = uid.mUid; - out.appCpuUTime3 = totalUTimeMs; - out.appCpuSTime3 = totalSTimeMs; + mDetails.statSubsystemPowerState); + } + + if (!mHasHistoryStepDetails) { + // We are not generating a delta, so all we need to do is reset the stats + // we will later be doing a delta from. + final int uidCount = mUidStats.size(); + for (int i = 0; i < uidCount; i++) { + final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); + uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs; + uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs; + } + mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs; + mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs; + mLastStepStatUserTimeMs = mCurStepStatUserTimeMs; + mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs; + mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs; + mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs; + mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs; + mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs; + mDetails.clear(); } else { - out.appCpuUid3 = out.appCpuUid2; - out.appCpuUTime3 = out.appCpuUTime2; - out.appCpuSTime3 = out.appCpuSTime2; - if (totalTimeMs <= (out.appCpuUTime1 + out.appCpuSTime1)) { - out.appCpuUid2 = uid.mUid; - out.appCpuUTime2 = totalUTimeMs; - out.appCpuSTime2 = totalSTimeMs; - } else { - out.appCpuUid2 = out.appCpuUid1; - out.appCpuUTime2 = out.appCpuUTime1; - out.appCpuSTime2 = out.appCpuSTime1; - out.appCpuUid1 = uid.mUid; - out.appCpuUTime1 = totalUTimeMs; - out.appCpuSTime1 = totalSTimeMs; + if (DEBUG) { + Slog.d(TAG, "Step stats last: user=" + mLastStepCpuUserTimeMs + " sys=" + + mLastStepStatSystemTimeMs + " io=" + mLastStepStatIOWaitTimeMs + + " irq=" + mLastStepStatIrqTimeMs + " sirq=" + + mLastStepStatSoftIrqTimeMs + " idle=" + mLastStepStatIdleTimeMs); + Slog.d(TAG, "Step stats cur: user=" + mCurStepCpuUserTimeMs + " sys=" + + mCurStepStatSystemTimeMs + " io=" + mCurStepStatIOWaitTimeMs + + " irq=" + mCurStepStatIrqTimeMs + " sirq=" + + mCurStepStatSoftIrqTimeMs + " idle=" + mCurStepStatIdleTimeMs); + } + mDetails.userTime = (int) (mCurStepCpuUserTimeMs - mLastStepCpuUserTimeMs); + mDetails.systemTime = (int) (mCurStepCpuSystemTimeMs - mLastStepCpuSystemTimeMs); + mDetails.statUserTime = (int) (mCurStepStatUserTimeMs - mLastStepStatUserTimeMs); + mDetails.statSystemTime = + (int) (mCurStepStatSystemTimeMs - mLastStepStatSystemTimeMs); + mDetails.statIOWaitTime = + (int) (mCurStepStatIOWaitTimeMs - mLastStepStatIOWaitTimeMs); + mDetails.statIrqTime = (int) (mCurStepStatIrqTimeMs - mLastStepStatIrqTimeMs); + mDetails.statSoftIrqTime = + (int) (mCurStepStatSoftIrqTimeMs - mLastStepStatSoftIrqTimeMs); + mDetails.statIdlTime = (int) (mCurStepStatIdleTimeMs - mLastStepStatIdleTimeMs); + mDetails.appCpuUid1 = mDetails.appCpuUid2 = mDetails.appCpuUid3 = -1; + mDetails.appCpuUTime1 = mDetails.appCpuUTime2 = mDetails.appCpuUTime3 = 0; + mDetails.appCpuSTime1 = mDetails.appCpuSTime2 = mDetails.appCpuSTime3 = 0; + final int uidCount = mUidStats.size(); + for (int i = 0; i < uidCount; i++) { + final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); + final int totalUTimeMs = + (int) (uid.mCurStepUserTimeMs - uid.mLastStepUserTimeMs); + final int totalSTimeMs = + (int) (uid.mCurStepSystemTimeMs - uid.mLastStepSystemTimeMs); + final int totalTimeMs = totalUTimeMs + totalSTimeMs; + uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs; + uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs; + if (totalTimeMs <= (mDetails.appCpuUTime3 + mDetails.appCpuSTime3)) { + continue; + } + if (totalTimeMs <= (mDetails.appCpuUTime2 + mDetails.appCpuSTime2)) { + mDetails.appCpuUid3 = uid.mUid; + mDetails.appCpuUTime3 = totalUTimeMs; + mDetails.appCpuSTime3 = totalSTimeMs; + } else { + mDetails.appCpuUid3 = mDetails.appCpuUid2; + mDetails.appCpuUTime3 = mDetails.appCpuUTime2; + mDetails.appCpuSTime3 = mDetails.appCpuSTime2; + if (totalTimeMs <= (mDetails.appCpuUTime1 + mDetails.appCpuSTime1)) { + mDetails.appCpuUid2 = uid.mUid; + mDetails.appCpuUTime2 = totalUTimeMs; + mDetails.appCpuSTime2 = totalSTimeMs; + } else { + mDetails.appCpuUid2 = mDetails.appCpuUid1; + mDetails.appCpuUTime2 = mDetails.appCpuUTime1; + mDetails.appCpuSTime2 = mDetails.appCpuSTime1; + mDetails.appCpuUid1 = uid.mUid; + mDetails.appCpuUTime1 = totalUTimeMs; + mDetails.appCpuSTime1 = totalSTimeMs; + } + } } + mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs; + mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs; + mLastStepStatUserTimeMs = mCurStepStatUserTimeMs; + mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs; + mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs; + mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs; + mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs; + mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs; + } + + mHasHistoryStepDetails = mBatteryLevel <= mLastHistoryStepLevel; + mLastHistoryStepLevel = mBatteryLevel; + + return mDetails; + } + + public void addCpuStats(int totalUTimeMs, int totalSTimeMs, int statUserTimeMs, + int statSystemTimeMs, int statIOWaitTimeMs, int statIrqTimeMs, + int statSoftIrqTimeMs, int statIdleTimeMs) { + if (DEBUG) { + Slog.d(TAG, "Adding cpu: tuser=" + totalUTimeMs + " tsys=" + totalSTimeMs + + " user=" + statUserTimeMs + " sys=" + statSystemTimeMs + + " io=" + statIOWaitTimeMs + " irq=" + statIrqTimeMs + + " sirq=" + statSoftIrqTimeMs + " idle=" + statIdleTimeMs); } + mCurStepCpuUserTimeMs += totalUTimeMs; + mCurStepCpuSystemTimeMs += totalSTimeMs; + mCurStepStatUserTimeMs += statUserTimeMs; + mCurStepStatSystemTimeMs += statSystemTimeMs; + mCurStepStatIOWaitTimeMs += statIOWaitTimeMs; + mCurStepStatIrqTimeMs += statIrqTimeMs; + mCurStepStatSoftIrqTimeMs += statSoftIrqTimeMs; + mCurStepStatIdleTimeMs += statIdleTimeMs; + } + + @Override + public void clear() { + mHasHistoryStepDetails = false; + mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs = 0; + mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs = 0; + mLastStepStatUserTimeMs = mCurStepStatUserTimeMs = 0; + mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs = 0; + mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs = 0; + mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs = 0; + mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs = 0; + mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs = 0; } - mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs; - mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs; - mLastStepStatUserTimeMs = mCurStepStatUserTimeMs; - mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs; - mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs; - mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs; - mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs; - mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs; } @GuardedBy("this") @Override public void commitCurrentHistoryBatchLocked() { - mHistoryLastWritten.cmd = HistoryItem.CMD_NULL; + mHistory.commitCurrentHistoryBatchLocked(); } @GuardedBy("this") @@ -4326,191 +4066,9 @@ public class BatteryStatsImpl extends BatteryStats { } @GuardedBy("this") - void addHistoryBufferLocked(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) { - if (!mHaveBatteryLevel || !mRecordingHistory) { - return; - } - - final long timeDiffMs = (mHistoryBaseTimeMs + elapsedRealtimeMs) - mHistoryLastWritten.time; - final int diffStates = mHistoryLastWritten.states^(cur.states&mActiveHistoryStates); - final int diffStates2 = mHistoryLastWritten.states2^(cur.states2&mActiveHistoryStates2); - final int lastDiffStates = mHistoryLastWritten.states^mHistoryLastLastWritten.states; - final int lastDiffStates2 = mHistoryLastWritten.states2^mHistoryLastLastWritten.states2; - if (DEBUG) { - Slog.i(TAG, "ADD: tdelta=" + timeDiffMs + " diff=" - + Integer.toHexString(diffStates) + " lastDiff=" - + Integer.toHexString(lastDiffStates) + " diff2=" - + Integer.toHexString(diffStates2) + " lastDiff2=" - + Integer.toHexString(lastDiffStates2)); - } - if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE - && timeDiffMs < 1000 && (diffStates & lastDiffStates) == 0 - && (diffStates2&lastDiffStates2) == 0 - && (!mHistoryLastWritten.tagsFirstOccurrence && !cur.tagsFirstOccurrence) - && (mHistoryLastWritten.wakelockTag == null || cur.wakelockTag == null) - && (mHistoryLastWritten.wakeReasonTag == null || cur.wakeReasonTag == null) - && mHistoryLastWritten.stepDetails == null - && (mHistoryLastWritten.eventCode == HistoryItem.EVENT_NONE - || cur.eventCode == HistoryItem.EVENT_NONE) - && mHistoryLastWritten.batteryLevel == cur.batteryLevel - && mHistoryLastWritten.batteryStatus == cur.batteryStatus - && mHistoryLastWritten.batteryHealth == cur.batteryHealth - && mHistoryLastWritten.batteryPlugType == cur.batteryPlugType - && mHistoryLastWritten.batteryTemperature == cur.batteryTemperature - && mHistoryLastWritten.batteryVoltage == cur.batteryVoltage) { - // We can merge this new change in with the last one. Merging is - // allowed as long as only the states have changed, and within those states - // as long as no bit has changed both between now and the last entry, as - // well as the last entry and the one before it (so we capture any toggles). - if (DEBUG) Slog.i(TAG, "ADD: rewinding back to " + mHistoryBufferLastPos); - mHistoryBuffer.setDataSize(mHistoryBufferLastPos); - mHistoryBuffer.setDataPosition(mHistoryBufferLastPos); - mHistoryBufferLastPos = -1; - elapsedRealtimeMs = mHistoryLastWritten.time - mHistoryBaseTimeMs; - // If the last written history had a wakelock tag, we need to retain it. - // Note that the condition above made sure that we aren't in a case where - // both it and the current history item have a wakelock tag. - if (mHistoryLastWritten.wakelockTag != null) { - cur.wakelockTag = cur.localWakelockTag; - cur.wakelockTag.setTo(mHistoryLastWritten.wakelockTag); - } - // If the last written history had a wake reason tag, we need to retain it. - // Note that the condition above made sure that we aren't in a case where - // both it and the current history item have a wakelock tag. - if (mHistoryLastWritten.wakeReasonTag != null) { - cur.wakeReasonTag = cur.localWakeReasonTag; - cur.wakeReasonTag.setTo(mHistoryLastWritten.wakeReasonTag); - } - // If the last written history had an event, we need to retain it. - // Note that the condition above made sure that we aren't in a case where - // both it and the current history item have an event. - if (mHistoryLastWritten.eventCode != HistoryItem.EVENT_NONE) { - cur.eventCode = mHistoryLastWritten.eventCode; - cur.eventTag = cur.localEventTag; - cur.eventTag.setTo(mHistoryLastWritten.eventTag); - } - mHistoryLastWritten.setTo(mHistoryLastLastWritten); - } - final int dataSize = mHistoryBuffer.dataSize(); - - if (dataSize >= mConstants.MAX_HISTORY_BUFFER) { - //open a new history file. - final long start = SystemClock.uptimeMillis(); - writeHistoryLocked(); - if (DEBUG) { - Slog.d(TAG, "addHistoryBufferLocked writeHistoryLocked takes ms:" - + (SystemClock.uptimeMillis() - start)); - } - mBatteryStatsHistory.startNextFile(); - mHistoryBuffer.setDataSize(0); - mHistoryBuffer.setDataPosition(0); - mHistoryBuffer.setDataCapacity(mConstants.MAX_HISTORY_BUFFER / 2); - mHistoryBufferLastPos = -1; - mHistoryLastWritten.clear(); - mHistoryLastLastWritten.clear(); - - // Mark every entry in the pool with a flag indicating that the tag - // has not yet been encountered while writing the current history buffer. - for (Map.Entry<HistoryTag, Integer> entry: mHistoryTagPool.entrySet()) { - entry.setValue(entry.getValue() | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG); - } - // Make a copy of mHistoryCur. - HistoryItem copy = new HistoryItem(); - copy.setTo(cur); - // startRecordingHistory will reset mHistoryCur. - startRecordingHistory(elapsedRealtimeMs, uptimeMs, false); - // Add the copy into history buffer. - addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE, copy); - return; - } - - if (dataSize == 0) { - // The history is currently empty; we need it to start with a time stamp. - cur.currentTime = mClock.currentTimeMillis(); - addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_RESET, cur); - } - addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE, cur); - } - - @GuardedBy("this") - private void addHistoryBufferLocked(long elapsedRealtimeMs, byte cmd, HistoryItem cur) { - if (mBatteryStatsHistoryIterator != null) { - throw new IllegalStateException("Can't do this while iterating history!"); - } - mHistoryBufferLastPos = mHistoryBuffer.dataPosition(); - mHistoryLastLastWritten.setTo(mHistoryLastWritten); - final boolean hasTags = mHistoryLastWritten.tagsFirstOccurrence || cur.tagsFirstOccurrence; - mHistoryLastWritten.setTo(mHistoryBaseTimeMs + elapsedRealtimeMs, cmd, cur); - mHistoryLastWritten.tagsFirstOccurrence = hasTags; - mHistoryLastWritten.states &= mActiveHistoryStates; - mHistoryLastWritten.states2 &= mActiveHistoryStates2; - writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten); - mLastHistoryElapsedRealtimeMs = elapsedRealtimeMs; - cur.wakelockTag = null; - cur.wakeReasonTag = null; - cur.eventCode = HistoryItem.EVENT_NONE; - cur.eventTag = null; - cur.tagsFirstOccurrence = false; - if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos - + " now " + mHistoryBuffer.dataPosition() - + " size is now " + mHistoryBuffer.dataSize()); - } - - @GuardedBy("this") - void addHistoryRecordLocked(long elapsedRealtimeMs, long uptimeMs) { - if (mTrackRunningHistoryElapsedRealtimeMs != 0) { - final long diffElapsedMs = elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtimeMs; - final long diffUptimeMs = uptimeMs - mTrackRunningHistoryUptimeMs; - if (diffUptimeMs < (diffElapsedMs - 20)) { - final long wakeElapsedTimeMs = elapsedRealtimeMs - (diffElapsedMs - diffUptimeMs); - mHistoryAddTmp.setTo(mHistoryLastWritten); - mHistoryAddTmp.wakelockTag = null; - mHistoryAddTmp.wakeReasonTag = null; - mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE; - mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG; - addHistoryRecordInnerLocked(wakeElapsedTimeMs, uptimeMs, mHistoryAddTmp); - } - } - mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG; - mTrackRunningHistoryElapsedRealtimeMs = elapsedRealtimeMs; - mTrackRunningHistoryUptimeMs = uptimeMs; - addHistoryRecordInnerLocked(elapsedRealtimeMs, uptimeMs, mHistoryCur); - } - - @GuardedBy("this") - void addHistoryRecordInnerLocked(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) { - addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, cur); - } - - @GuardedBy("this") - public void addHistoryEventLocked(long elapsedRealtimeMs, long uptimeMs, int code, + public void recordHistoryEventLocked(long elapsedRealtimeMs, long uptimeMs, int code, String name, int uid) { - mHistoryCur.eventCode = code; - mHistoryCur.eventTag = mHistoryCur.localEventTag; - mHistoryCur.eventTag.string = name; - mHistoryCur.eventTag.uid = uid; - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); - } - - @GuardedBy("this") - void clearHistoryLocked() { - if (DEBUG_HISTORY) Slog.i(TAG, "********** CLEARING HISTORY!"); - mHistoryBaseTimeMs = 0; - mLastHistoryElapsedRealtimeMs = 0; - mTrackRunningHistoryElapsedRealtimeMs = 0; - mTrackRunningHistoryUptimeMs = 0; - - mHistoryBuffer.setDataSize(0); - mHistoryBuffer.setDataPosition(0); - mHistoryBuffer.setDataCapacity(mConstants.MAX_HISTORY_BUFFER / 2); - mHistoryLastLastWritten.clear(); - mHistoryLastWritten.clear(); - mHistoryTagPool.clear(); - mNextHistoryTagIdx = 0; - mNumHistoryTagChars = 0; - mHistoryBufferLastPos = -1; - mActiveHistoryStates = 0xffffffff; - mActiveHistoryStates2 = 0xffffffff; + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, code, name, uid); } @GuardedBy("this") @@ -4663,13 +4221,13 @@ public class BatteryStatsImpl extends BatteryStats { if (!mActiveEvents.updateState(code, name, uid, 0)) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, code, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, code, name, uid); } @GuardedBy("this") public void noteCurrentTimeChangedLocked(long currentTimeMs, long elapsedRealtimeMs, long uptimeMs) { - recordCurrentTimeChangeLocked(currentTimeMs, elapsedRealtimeMs, uptimeMs); + mHistory.recordCurrentTimeChange(elapsedRealtimeMs, uptimeMs, currentTimeMs); } @GuardedBy("this") @@ -4686,7 +4244,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mRecordAllHistory) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PROC_START, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PROC_START, name, uid); } @GuardedBy("this") @@ -4744,8 +4302,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mRecordAllHistory) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PROC_FINISH, - name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PROC_FINISH, name, uid); } @GuardedBy("this") @@ -4761,7 +4318,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_START, name, uid, 0)) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SYNC_START, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SYNC_START, name, uid); } @GuardedBy("this") @@ -4777,8 +4334,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_FINISH, name, uid, 0)) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SYNC_FINISH, - name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SYNC_FINISH, name, uid); } @GuardedBy("this") @@ -4794,7 +4350,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_START, name, uid, 0)) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_JOB_START, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_JOB_START, name, uid); } @GuardedBy("this") @@ -4812,7 +4368,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_FINISH, name, uid, 0)) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_JOB_FINISH, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_JOB_FINISH, name, uid); } @GuardedBy("this") @@ -4860,7 +4416,7 @@ public class BatteryStatsImpl extends BatteryStats { for (int i = 0; i < workSource.size(); ++i) { uid = mapUid(workSource.getUid(i)); if (mActiveEvents.updateState(historyItem, name, uid, 0)) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); } } @@ -4869,7 +4425,7 @@ public class BatteryStatsImpl extends BatteryStats { for (int i = 0; i < workChains.size(); ++i) { uid = mapUid(workChains.get(i).getAttributionUid()); if (mActiveEvents.updateState(historyItem, name, uid, 0)) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); } } } @@ -4877,7 +4433,7 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); if (mActiveEvents.updateState(historyItem, name, uid, 0)) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); } } } @@ -4952,7 +4508,7 @@ public class BatteryStatsImpl extends BatteryStats { for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) { SparseIntArray uids = ent.getValue(); for (int j=0; j<uids.size(); j++) { - addHistoryEventLocked(mSecRealtime, mSecUptime, + mHistory.recordEvent(mSecRealtime, mSecUptime, HistoryItem.EVENT_PROC_FINISH, ent.getKey(), uids.keyAt(j)); } } @@ -4967,8 +4523,8 @@ public class BatteryStatsImpl extends BatteryStats { for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) { SparseIntArray uids = ent.getValue(); for (int j=0; j<uids.size(); j++) { - addHistoryEventLocked(mSecRealtime, mSecUptime, - HistoryItem.EVENT_PROC_START, ent.getKey(), uids.keyAt(j)); + mHistory.recordEvent(mSecRealtime, mSecUptime, HistoryItem.EVENT_PROC_START, + ent.getKey(), uids.keyAt(j)); } } } @@ -5011,30 +4567,19 @@ public class BatteryStatsImpl extends BatteryStats { if (mRecordAllHistory) { if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName, mappedUid, 0)) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_WAKE_LOCK_START, historyName, mappedUid); } } if (mWakeLockNesting == 0) { - mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: " - + Integer.toHexString(mHistoryCur.states)); - mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; - mHistoryCur.wakelockTag.string = historyName; - mHistoryCur.wakelockTag.uid = mappedUid; mWakeLockImportant = !unimportantForLogging; - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); - } else if (!mWakeLockImportant && !unimportantForLogging - && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE) { - if (mHistoryLastWritten.wakelockTag != null) { - // We'll try to update the last tag. - mHistoryLastWritten.wakelockTag = null; - mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; - mHistoryCur.wakelockTag.string = historyName; - mHistoryCur.wakelockTag.uid = mappedUid; - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); - } - mWakeLockImportant = true; + mHistory.recordWakelockStartEvent(elapsedRealtimeMs, uptimeMs, historyName, + mappedUid); + } else if (!mWakeLockImportant && !unimportantForLogging) { + if (mHistory.maybeUpdateWakelockTag(elapsedRealtimeMs, uptimeMs, historyName, + mappedUid)) { + mWakeLockImportant = true; + } } mWakeLockNesting++; } @@ -5087,15 +4632,13 @@ public class BatteryStatsImpl extends BatteryStats { } if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, mappedUid, 0)) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, mappedUid); } } if (mWakeLockNesting == 0) { - mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WAKE_LOCK_FLAG); } } if (mappedUid >= 0) { @@ -5286,7 +4829,7 @@ public class BatteryStatsImpl extends BatteryStats { mappedUid, 0)) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_LONG_WAKE_LOCK_START, + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_LONG_WAKE_LOCK_START, historyName, mappedUid); if (mappedUid != uid) { // Prevent the isolated uid mapping from being removed while the wakelock is @@ -5339,7 +4882,7 @@ public class BatteryStatsImpl extends BatteryStats { mappedUid, 0)) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH, + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH, historyName, mappedUid); if (mappedUid != uid) { // Decrement the ref count for the isolated uid and delete the mapping if uneeded. @@ -5361,15 +4904,10 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWakeupReasonLocked(String reason, long elapsedRealtimeMs, long uptimeMs) { - if (DEBUG_HISTORY) Slog.v(TAG, "Wakeup reason \"" + reason +"\": " - + Integer.toHexString(mHistoryCur.states)); aggregateLastWakeupUptimeLocked(elapsedRealtimeMs, uptimeMs); - mHistoryCur.wakeReasonTag = mHistoryCur.localWakeReasonTag; - mHistoryCur.wakeReasonTag.string = reason; - mHistoryCur.wakeReasonTag.uid = 0; + mHistory.recordWakeupEvent(elapsedRealtimeMs, uptimeMs, reason); mLastWakeupReason = reason; mLastWakeupUptimeMs = uptimeMs; - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } @GuardedBy("this") @@ -5380,22 +4918,11 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void finishAddingCpuLocked(int totalUTimeMs, int totalSTimeMs, int statUserTimeMs, - int statSystemTimeMs, int statIOWaitTimeMs, int statIrqTimeMs, - int statSoftIrqTimeMs, int statIdleTimeMs) { - if (DEBUG) { - Slog.d(TAG, "Adding cpu: tuser=" + totalUTimeMs + " tsys=" + totalSTimeMs - + " user=" + statUserTimeMs + " sys=" + statSystemTimeMs - + " io=" + statIOWaitTimeMs + " irq=" + statIrqTimeMs - + " sirq=" + statSoftIrqTimeMs + " idle=" + statIdleTimeMs); - } - mCurStepCpuUserTimeMs += totalUTimeMs; - mCurStepCpuSystemTimeMs += totalSTimeMs; - mCurStepStatUserTimeMs += statUserTimeMs; - mCurStepStatSystemTimeMs += statSystemTimeMs; - mCurStepStatIOWaitTimeMs += statIOWaitTimeMs; - mCurStepStatIrqTimeMs += statIrqTimeMs; - mCurStepStatSoftIrqTimeMs += statSoftIrqTimeMs; - mCurStepStatIdleTimeMs += statIdleTimeMs; + int statSystemTimeMs, int statIOWaitTimeMs, int statIrqTimeMs, + int statSoftIrqTimeMs, int statIdleTimeMs) { + mStepDetailsCalculator.addCpuStats(totalUTimeMs, totalSTimeMs, statUserTimeMs, + statSystemTimeMs, statIOWaitTimeMs, statIrqTimeMs, + statSoftIrqTimeMs, statIdleTimeMs); } public void noteProcessDiedLocked(int uid, int pid) { @@ -5425,10 +4952,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteStartSensorLocked(int uid, int sensor, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mSensorNesting == 0) { - mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_SENSOR_ON_FLAG); } mSensorNesting++; getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -5445,10 +4970,8 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); mSensorNesting--; if (mSensorNesting == 0) { - mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Stop sensor to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_SENSOR_ON_FLAG); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) .noteStopSensor(sensor, elapsedRealtimeMs); @@ -5498,10 +5021,8 @@ public class BatteryStatsImpl extends BatteryStats { } final int mappedUid = mapUid(uid); if (mGpsNesting == 0) { - mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_GPS_ON_FLAG); } mGpsNesting++; @@ -5526,10 +5047,8 @@ public class BatteryStatsImpl extends BatteryStats { final int mappedUid = mapUid(uid); mGpsNesting--; if (mGpsNesting == 0) { - mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Stop GPS to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_GPS_ON_FLAG); stopAllGpsSignalQualityTimersLocked(-1, elapsedRealtimeMs); mGpsSignalQualityBin = -1; } @@ -5562,12 +5081,9 @@ public class BatteryStatsImpl extends BatteryStats { if(!mGpsSignalQualityTimer[signalLevel].isRunningLocked()) { mGpsSignalQualityTimer[signalLevel].startRunningLocked(elapsedRealtimeMs); } - mHistoryCur.states2 = (mHistoryCur.states2&~HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK) - | (signalLevel << HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordGpsSignalQualityEvent(elapsedRealtimeMs, uptimeMs, signalLevel); mGpsSignalQualityBin = signalLevel; } - return; } @GuardedBy("this") @@ -5740,41 +5256,33 @@ public class BatteryStatsImpl extends BatteryStats { } } - boolean updateHistory = false; + int startStates = 0; + int stopStates = 0; if (Display.isDozeState(state) && !Display.isDozeState(oldState)) { - mHistoryCur.states |= HistoryItem.STATE_SCREEN_DOZE_FLAG; + startStates |= HistoryItem.STATE_SCREEN_DOZE_FLAG; mScreenDozeTimer.startRunningLocked(elapsedRealtimeMs); - updateHistory = true; } else if (Display.isDozeState(oldState) && !Display.isDozeState(state)) { - mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_DOZE_FLAG; + stopStates |= HistoryItem.STATE_SCREEN_DOZE_FLAG; mScreenDozeTimer.stopRunningLocked(elapsedRealtimeMs); - updateHistory = true; } if (Display.isOnState(state)) { - mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: " - + Integer.toHexString(mHistoryCur.states)); + startStates |= HistoryItem.STATE_SCREEN_ON_FLAG; mScreenOnTimer.startRunningLocked(elapsedRealtimeMs); if (mScreenBrightnessBin >= 0) { mScreenBrightnessTimer[mScreenBrightnessBin] .startRunningLocked(elapsedRealtimeMs); } - updateHistory = true; } else if (Display.isOnState(oldState)) { - mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: " - + Integer.toHexString(mHistoryCur.states)); + stopStates |= HistoryItem.STATE_SCREEN_ON_FLAG; mScreenOnTimer.stopRunningLocked(elapsedRealtimeMs); if (mScreenBrightnessBin >= 0) { mScreenBrightnessTimer[mScreenBrightnessBin] .stopRunningLocked(elapsedRealtimeMs); } - updateHistory = true; } - if (updateHistory) { - if (DEBUG_HISTORY) Slog.v(TAG, "Screen state to: " - + Display.stateToString(state)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + if (startStates != 0 || stopStates != 0) { + mHistory.recordStateChangeEvent(elapsedRealtimeMs, uptimeMs, startStates, + stopStates); } // Per screen state Cpu stats needed. Prepare to schedule an external sync. @@ -5888,13 +5396,7 @@ public class BatteryStatsImpl extends BatteryStats { long uptimeMs) { if (mScreenBrightnessBin != overallBin) { if (overallBin >= 0) { - mHistoryCur.states = (mHistoryCur.states & ~HistoryItem.STATE_BRIGHTNESS_MASK) - | (overallBin << HistoryItem.STATE_BRIGHTNESS_SHIFT); - if (DEBUG_HISTORY) { - Slog.v(TAG, "Screen brightness " + overallBin + " to: " - + Integer.toHexString(mHistoryCur.states)); - } - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordScreenBrightnessEvent(elapsedRealtimeMs, uptimeMs, overallBin); } if (mScreenState == Display.STATE_ON) { if (mScreenBrightnessBin >= 0) { @@ -5921,8 +5423,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWakeUpLocked(String reason, int reasonUid, long elapsedRealtimeMs, long uptimeMs) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SCREEN_WAKE_UP, - reason, reasonUid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SCREEN_WAKE_UP, reason, + reasonUid); } @GuardedBy("this") @@ -5941,7 +5443,7 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteConnectivityChangedLocked(int type, String extra, long elapsedRealtimeMs, long uptimeMs) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_CONNECTIVITY_CHANGED, + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_CONNECTIVITY_CHANGED, extra, type); mNumConnectivityChange++; } @@ -5950,7 +5452,7 @@ public class BatteryStatsImpl extends BatteryStats { private void noteMobileRadioApWakeupLocked(final long elapsedRealtimeMillis, final long uptimeMillis, int uid) { uid = mapUid(uid); - addHistoryEventLocked(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "", + mHistory.recordEvent(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "", uid); getUidStatsLocked(uid, elapsedRealtimeMillis, uptimeMillis).noteMobileRadioApWakeupLocked(); } @@ -5976,7 +5478,8 @@ public class BatteryStatsImpl extends BatteryStats { } mMobileRadioActiveStartTimeMs = realElapsedRealtimeMs = timestampNs / (1000 * 1000); - mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG; + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG); } else { realElapsedRealtimeMs = timestampNs / (1000*1000); long lastUpdateTimeMs = mMobileRadioActiveStartTimeMs; @@ -5988,11 +5491,9 @@ public class BatteryStatsImpl extends BatteryStats { mMobileRadioActiveAdjustedTime.addCountLocked(elapsedRealtimeMs - realElapsedRealtimeMs); } - mHistoryCur.states &= ~HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG; + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG); } - if (DEBUG_HISTORY) Slog.v(TAG, "Mobile network active " + active + " to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mMobileRadioPowerState = powerState; // Inform current RatBatteryStats that the modem active state might have changed. @@ -6042,17 +5543,14 @@ public class BatteryStatsImpl extends BatteryStats { mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_POWER_SAVE) | stepState; mPowerSaveModeEnabled = enabled; if (enabled) { - mHistoryCur.states2 |= HistoryItem.STATE2_POWER_SAVE_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Power save mode enabled to: " - + Integer.toHexString(mHistoryCur.states2)); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_POWER_SAVE_FLAG); mPowerSaveModeEnabledTimer.startRunningLocked(elapsedRealtimeMs); } else { - mHistoryCur.states2 &= ~HistoryItem.STATE2_POWER_SAVE_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Power save mode disabled to: " - + Integer.toHexString(mHistoryCur.states2)); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_POWER_SAVE_FLAG); mPowerSaveModeEnabledTimer.stopRunningLocked(elapsedRealtimeMs); } - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); FrameworkStatsLog.write(FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED, enabled ? FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__ON @@ -6076,7 +5574,7 @@ public class BatteryStatsImpl extends BatteryStats { nowLightIdling = true; } if (activeReason != null && (mDeviceIdling || mDeviceLightIdling)) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_ACTIVE, + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_ACTIVE, activeReason, activeUid); } if (mDeviceIdling != nowIdling || mDeviceLightIdling != nowLightIdling) { @@ -6106,11 +5604,7 @@ public class BatteryStatsImpl extends BatteryStats { } } if (mDeviceIdleMode != mode) { - mHistoryCur.states2 = (mHistoryCur.states2 & ~HistoryItem.STATE2_DEVICE_IDLE_MASK) - | (mode << HistoryItem.STATE2_DEVICE_IDLE_SHIFT); - if (DEBUG_HISTORY) Slog.v(TAG, "Device idle mode changed to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordDeviceIdleEvent(elapsedRealtimeMs, uptimeMs, mode); long lastDuration = elapsedRealtimeMs - mLastIdleTimeStartMs; mLastIdleTimeStartMs = elapsedRealtimeMs; if (mDeviceIdleMode == DEVICE_IDLE_MODE_LIGHT) { @@ -6138,7 +5632,7 @@ public class BatteryStatsImpl extends BatteryStats { public void notePackageInstalledLocked(String pkgName, long versionCode, long elapsedRealtimeMs, long uptimeMs) { // XXX need to figure out what to do with long version codes. - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PACKAGE_INSTALLED, + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PACKAGE_INSTALLED, pkgName, (int)versionCode); PackageChange pc = new PackageChange(); pc.mPackageName = pkgName; @@ -6150,8 +5644,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void notePackageUninstalledLocked(String pkgName, long elapsedRealtimeMs, long uptimeMs) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, - HistoryItem.EVENT_PACKAGE_UNINSTALLED, pkgName, 0); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PACKAGE_UNINSTALLED, + pkgName, 0); PackageChange pc = new PackageChange(); pc.mPackageName = pkgName; pc.mUpdate = true; @@ -6180,10 +5674,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void notePhoneOnLocked(long elapsedRealtimeMs, long uptimeMs) { if (!mPhoneOn) { - mHistoryCur.states2 |= HistoryItem.STATE2_PHONE_IN_CALL_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_PHONE_IN_CALL_FLAG); mPhoneOn = true; mPhoneOnTimer.startRunningLocked(elapsedRealtimeMs); } @@ -6192,10 +5684,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void notePhoneOffLocked(long elapsedRealtimeMs, long uptimeMs) { if (mPhoneOn) { - mHistoryCur.states2 &= ~HistoryItem.STATE2_PHONE_IN_CALL_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_PHONE_IN_CALL_FLAG); mPhoneOn = false; mPhoneOnTimer.stopRunningLocked(elapsedRealtimeMs); } @@ -6233,11 +5723,12 @@ public class BatteryStatsImpl extends BatteryStats { if (mUsbDataState != newState) { mUsbDataState = newState; if (connected) { - mHistoryCur.states2 |= HistoryItem.STATE2_USB_DATA_LINK_FLAG; + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_USB_DATA_LINK_FLAG); } else { - mHistoryCur.states2 &= ~HistoryItem.STATE2_USB_DATA_LINK_FLAG; + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_USB_DATA_LINK_FLAG); } - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } } @@ -6258,6 +5749,10 @@ public class BatteryStatsImpl extends BatteryStats { long elapsedRealtimeMs, long uptimeMs) { boolean scanning = false; boolean newHistory = false; + int addStateFlag = 0; + int removeStateFlag = 0; + int newState = -1; + int newSignalStrength = -1; mPhoneServiceStateRaw = state; mPhoneSimStateRaw = simState; @@ -6286,10 +5781,8 @@ public class BatteryStatsImpl extends BatteryStats { scanning = true; strengthBin = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN; if (!mPhoneSignalScanningTimer.isRunningLocked()) { - mHistoryCur.states |= HistoryItem.STATE_PHONE_SCANNING_FLAG; + addStateFlag = HistoryItem.STATE_PHONE_SCANNING_FLAG; newHistory = true; - if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: " - + Integer.toHexString(mHistoryCur.states)); mPhoneSignalScanningTimer.startRunningLocked(elapsedRealtimeMs); FrameworkStatsLog.write(FrameworkStatsLog.PHONE_SERVICE_STATE_CHANGED, state, simState, strengthBin); @@ -6299,9 +5792,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!scanning) { // If we are no longer scanning, then stop the scanning timer. if (mPhoneSignalScanningTimer.isRunningLocked()) { - mHistoryCur.states &= ~HistoryItem.STATE_PHONE_SCANNING_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Phone stopped scanning to: " - + Integer.toHexString(mHistoryCur.states)); + removeStateFlag = HistoryItem.STATE_PHONE_SCANNING_FLAG; newHistory = true; mPhoneSignalScanningTimer.stopRunningLocked(elapsedRealtimeMs); FrameworkStatsLog.write(FrameworkStatsLog.PHONE_SERVICE_STATE_CHANGED, state, @@ -6310,10 +5801,7 @@ public class BatteryStatsImpl extends BatteryStats { } if (mPhoneServiceState != state) { - mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_PHONE_STATE_MASK) - | (state << HistoryItem.STATE_PHONE_STATE_SHIFT); - if (DEBUG_HISTORY) Slog.v(TAG, "Phone state " + state + " to: " - + Integer.toHexString(mHistoryCur.states)); + newState = state; newHistory = true; mPhoneServiceState = state; } @@ -6327,11 +5815,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mPhoneSignalStrengthsTimer[strengthBin].isRunningLocked()) { mPhoneSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtimeMs); } - mHistoryCur.states = - (mHistoryCur.states & ~HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK) - | (strengthBin << HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT); - if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + strengthBin + " to: " - + Integer.toHexString(mHistoryCur.states)); + newSignalStrength = strengthBin; newHistory = true; FrameworkStatsLog.write( FrameworkStatsLog.PHONE_SIGNAL_STRENGTH_CHANGED, strengthBin); @@ -6342,7 +5826,8 @@ public class BatteryStatsImpl extends BatteryStats { } if (newHistory) { - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordPhoneStateChangeEvent(elapsedRealtimeMs, uptimeMs, + addStateFlag, removeStateFlag, newState, newSignalStrength); } } @@ -6466,11 +5951,7 @@ public class BatteryStatsImpl extends BatteryStats { if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData); if (mPhoneDataConnectionType != bin) { - mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK) - | (bin << HistoryItem.STATE_DATA_CONNECTION_SHIFT); - if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordDataConnectionTypeChangeEvent(elapsedRealtimeMs, uptimeMs, bin); if (mPhoneDataConnectionType >= 0) { mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked( elapsedRealtimeMs); @@ -6543,10 +6024,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWifiOnLocked(long elapsedRealtimeMs, long uptimeMs) { if (!mWifiOn) { - mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_WIFI_ON_FLAG); mWifiOn = true; mWifiOnTimer.startRunningLocked(elapsedRealtimeMs); scheduleSyncExternalStatsLocked("wifi-off", ExternalStatsSync.UPDATE_WIFI); @@ -6556,10 +6035,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWifiOffLocked(long elapsedRealtimeMs, long uptimeMs) { if (mWifiOn) { - mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_WIFI_ON_FLAG); mWifiOn = false; mWifiOnTimer.stopRunningLocked(elapsedRealtimeMs); scheduleSyncExternalStatsLocked("wifi-on", ExternalStatsSync.UPDATE_WIFI); @@ -6570,10 +6047,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteAudioOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mAudioOnNesting == 0) { - mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_AUDIO_ON_FLAG); mAudioOnTimer.startRunningLocked(elapsedRealtimeMs); } mAudioOnNesting++; @@ -6588,10 +6063,8 @@ public class BatteryStatsImpl extends BatteryStats { } uid = mapUid(uid); if (--mAudioOnNesting == 0) { - mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_AUDIO_ON_FLAG); mAudioOnTimer.stopRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6602,10 +6075,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteVideoOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mVideoOnNesting == 0) { - mHistoryCur.states2 |= HistoryItem.STATE2_VIDEO_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_VIDEO_ON_FLAG); mVideoOnTimer.startRunningLocked(elapsedRealtimeMs); } mVideoOnNesting++; @@ -6620,10 +6091,8 @@ public class BatteryStatsImpl extends BatteryStats { } uid = mapUid(uid); if (--mVideoOnNesting == 0) { - mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_VIDEO_ON_FLAG); mVideoOnTimer.stopRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6634,10 +6103,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteResetAudioLocked(long elapsedRealtimeMs, long uptimeMs) { if (mAudioOnNesting > 0) { mAudioOnNesting = 0; - mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_AUDIO_ON_FLAG); mAudioOnTimer.stopAllRunningLocked(elapsedRealtimeMs); for (int i=0; i<mUidStats.size(); i++) { BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); @@ -6650,10 +6117,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteResetVideoLocked(long elapsedRealtimeMs, long uptimeMs) { if (mVideoOnNesting > 0) { mVideoOnNesting = 0; - mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_VIDEO_ON_FLAG); mVideoOnTimer.stopAllRunningLocked(elapsedRealtimeMs); for (int i=0; i<mUidStats.size(); i++) { BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); @@ -6705,10 +6170,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteFlashlightOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mFlashlightOnNesting++ == 0) { - mHistoryCur.states2 |= HistoryItem.STATE2_FLASHLIGHT_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight on to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_FLASHLIGHT_FLAG); mFlashlightOnTimer.startRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6722,10 +6185,8 @@ public class BatteryStatsImpl extends BatteryStats { } uid = mapUid(uid); if (--mFlashlightOnNesting == 0) { - mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_FLASHLIGHT_FLAG); mFlashlightOnTimer.stopRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6736,10 +6197,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteCameraOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mCameraOnNesting++ == 0) { - mHistoryCur.states2 |= HistoryItem.STATE2_CAMERA_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Camera on to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_CAMERA_FLAG); mCameraOnTimer.startRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6753,10 +6212,8 @@ public class BatteryStatsImpl extends BatteryStats { } uid = mapUid(uid); if (--mCameraOnNesting == 0) { - mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_CAMERA_FLAG); mCameraOnTimer.stopRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6767,10 +6224,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteResetCameraLocked(long elapsedRealtimeMs, long uptimeMs) { if (mCameraOnNesting > 0) { mCameraOnNesting = 0; - mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_CAMERA_FLAG); mCameraOnTimer.stopAllRunningLocked(elapsedRealtimeMs); for (int i=0; i<mUidStats.size(); i++) { BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); @@ -6783,10 +6238,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteResetFlashlightLocked(long elapsedRealtimeMs, long uptimeMs) { if (mFlashlightOnNesting > 0) { mFlashlightOnNesting = 0; - mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_FLASHLIGHT_FLAG); mFlashlightOnTimer.stopAllRunningLocked(elapsedRealtimeMs); for (int i=0; i<mUidStats.size(); i++) { BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); @@ -6803,10 +6256,8 @@ public class BatteryStatsImpl extends BatteryStats { } uid = mapUid(uid); if (mBluetoothScanNesting == 0) { - mHistoryCur.states2 |= HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan started for: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG); mBluetoothScanTimer.startRunningLocked(elapsedRealtimeMs); } mBluetoothScanNesting++; @@ -6847,10 +6298,8 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); mBluetoothScanNesting--; if (mBluetoothScanNesting == 0) { - mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan stopped for: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG); mBluetoothScanTimer.stopRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6885,10 +6334,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteResetBluetoothScanLocked(long elapsedRealtimeMs, long uptimeMs) { if (mBluetoothScanNesting > 0) { mBluetoothScanNesting = 0; - mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "BLE can stopped for: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG); mBluetoothScanTimer.stopAllRunningLocked(elapsedRealtimeMs); for (int i=0; i<mUidStats.size(); i++) { BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); @@ -6928,7 +6375,7 @@ public class BatteryStatsImpl extends BatteryStats { private void noteWifiRadioApWakeupLocked(final long elapsedRealtimeMillis, final long uptimeMillis, int uid) { uid = mapUid(uid); - addHistoryEventLocked(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "", + mHistory.recordEvent(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "", uid); getUidStatsLocked(uid, elapsedRealtimeMillis, uptimeMillis).noteWifiRadioApWakeupLocked(); } @@ -6944,15 +6391,14 @@ public class BatteryStatsImpl extends BatteryStats { if (uid > 0) { noteWifiRadioApWakeupLocked(elapsedRealtimeMs, uptimeMs, uid); } - mHistoryCur.states |= HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG; + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG); mWifiActiveTimer.startRunningLocked(elapsedRealtimeMs); } else { - mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG; + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG); mWifiActiveTimer.stopRunningLocked(timestampNs / (1000 * 1000)); } - if (DEBUG_HISTORY) Slog.v(TAG, "Wifi network active " + active + " to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mWifiRadioPowerState = powerState; } } @@ -6960,10 +6406,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWifiRunningLocked(WorkSource ws, long elapsedRealtimeMs, long uptimeMs) { if (!mGlobalWifiRunning) { - mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_RUNNING_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_WIFI_RUNNING_FLAG); mGlobalWifiRunning = true; mGlobalWifiRunningTimer.startRunningLocked(elapsedRealtimeMs); int N = ws.size(); @@ -7031,10 +6475,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWifiStoppedLocked(WorkSource ws, long elapsedRealtimeMs, long uptimeMs) { if (mGlobalWifiRunning) { - mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_RUNNING_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_WIFI_RUNNING_FLAG); mGlobalWifiRunning = false; mGlobalWifiRunningTimer.stopRunningLocked(elapsedRealtimeMs); int N = ws.size(); @@ -7082,12 +6524,7 @@ public class BatteryStatsImpl extends BatteryStats { } mWifiSupplState = supplState; mWifiSupplStateTimer[supplState].startRunningLocked(elapsedRealtimeMs); - mHistoryCur.states2 = - (mHistoryCur.states2&~HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK) - | (supplState << HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT); - if (DEBUG_HISTORY) Slog.v(TAG, "Wifi suppl state " + supplState + " to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordWifiSupplicantStateChangeEvent(elapsedRealtimeMs, uptimeMs, supplState); } } @@ -7116,12 +6553,8 @@ public class BatteryStatsImpl extends BatteryStats { if (!mWifiSignalStrengthsTimer[strengthBin].isRunningLocked()) { mWifiSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtimeMs); } - mHistoryCur.states2 = - (mHistoryCur.states2&~HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK) - | (strengthBin << HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT); - if (DEBUG_HISTORY) Slog.v(TAG, "Wifi signal strength " + strengthBin + " to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordWifiSignalStrengthChangeEvent(elapsedRealtimeMs, uptimeMs, + strengthBin); } else { stopAllWifiSignalStrengthTimersLocked(-1, elapsedRealtimeMs); } @@ -7134,10 +6567,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteFullWifiLockAcquiredLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { if (mWifiFullLockNesting == 0) { - mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_FULL_LOCK_FLAG); } mWifiFullLockNesting++; getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -7148,10 +6579,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteFullWifiLockReleasedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { mWifiFullLockNesting--; if (mWifiFullLockNesting == 0) { - mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_FULL_LOCK_FLAG); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) .noteFullWifiLockReleasedLocked(elapsedRealtimeMs); @@ -7167,10 +6596,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWifiScanStartedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { if (mWifiScanNesting == 0) { - mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan started for: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_SCAN_FLAG); } mWifiScanNesting++; getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -7186,10 +6613,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteWifiScanStoppedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { mWifiScanNesting--; if (mWifiScanNesting == 0) { - mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan stopped for: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_SCAN_FLAG); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) .noteWifiScanStoppedLocked(elapsedRealtimeMs); @@ -7214,14 +6639,10 @@ public class BatteryStatsImpl extends BatteryStats { public void noteWifiMulticastEnabledLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mWifiMulticastNesting == 0) { - mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); - + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG); // Start Wifi Multicast overall timer if (!mWifiMulticastWakelockTimer.isRunningLocked()) { - if (DEBUG_HISTORY) Slog.v(TAG, "WiFi Multicast Overall Timer Started"); mWifiMulticastWakelockTimer.startRunningLocked(elapsedRealtimeMs); } } @@ -7235,14 +6656,12 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); mWifiMulticastNesting--; if (mWifiMulticastNesting == 0) { - mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG); // Stop Wifi Multicast overall timer if (mWifiMulticastWakelockTimer.isRunningLocked()) { - if (DEBUG_HISTORY) Slog.v(TAG, "Multicast Overall Timer Stopped"); + if (DEBUG) Slog.v(TAG, "Multicast Overall Timer Stopped"); mWifiMulticastWakelockTimer.stopRunningLocked(elapsedRealtimeMs); } } @@ -7994,8 +7413,9 @@ public class BatteryStatsImpl extends BatteryStats { // If the start clock time has changed by more than a year, then presumably // the previous time was completely bogus. So we are going to figure out a // new time based on how much time has elapsed since we started counting. - recordCurrentTimeChangeLocked(currentTimeMs, mClock.elapsedRealtime(), - mClock.uptimeMillis()); + mHistory.recordCurrentTimeChange(mClock.elapsedRealtime(), mClock.uptimeMillis(), + currentTimeMs + ); return currentTimeMs - (mClock.elapsedRealtime() - (mRealtimeStartUs / 1000)); } return mStartClockTimeMs; @@ -11227,18 +10647,19 @@ public class BatteryStatsImpl extends BatteryStats { UserInfoProvider userInfoProvider) { init(clock); + mHandler = new MyHandler(handler.getLooper()); + mConstants = new Constants(mHandler); + if (systemDir == null) { mStatsFile = null; - mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer); + mHistory = new BatteryStatsHistory(mStepDetailsCalculator, mClock); } else { mStatsFile = new AtomicFile(new File(systemDir, "batterystats.bin")); - mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer, systemDir, - this::getMaxHistoryFiles); + mHistory = new BatteryStatsHistory(systemDir, mConstants.MAX_HISTORY_FILES, + mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, mClock); } mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin")); mDailyFile = new AtomicFile(new File(systemDir, "batterystats-daily.xml")); - mHandler = new MyHandler(handler.getLooper()); - mConstants = new Constants(mHandler); mStartCount++; initTimersAndCounters(); mOnBattery = mOnBatteryInternal = false; @@ -11247,7 +10668,6 @@ public class BatteryStatsImpl extends BatteryStats { initTimes(uptimeUs, realtimeUs); mStartPlatformVersion = mEndPlatformVersion = Build.ID; initDischarge(realtimeUs); - clearHistoryLocked(); updateDailyDeadlineLocked(); mPlatformIdleStateCallback = cb; mMeasuredEnergyRetriever = energyStatsCb; @@ -11258,12 +10678,6 @@ public class BatteryStatsImpl extends BatteryStats { FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mDeviceIdleMode); } - private int getMaxHistoryFiles() { - synchronized (this) { - return mConstants.MAX_HISTORY_FILES; - } - } - @VisibleForTesting protected void initTimersAndCounters() { mScreenOnTimer = new StopwatchTimer(mClock, null, -1, null, mOnBatteryTimeBase); @@ -11345,7 +10759,7 @@ public class BatteryStatsImpl extends BatteryStats { mDischargeUnplugLevel = 0; mDischargePlugLevel = -1; mDischargeCurrentLevel = 0; - mCurrentBatteryLevel = 0; + mBatteryLevel = 0; } public void setPowerProfileLocked(PowerProfile profile) { @@ -11732,7 +11146,7 @@ public class BatteryStatsImpl extends BatteryStats { } public int getHistoryUsedSize() { - return mBatteryStatsHistory.getHistoryUsedSize(); + return mHistory.getHistoryUsedSize(); } @Override @@ -11746,43 +11160,27 @@ public class BatteryStatsImpl extends BatteryStats { */ @VisibleForTesting public BatteryStatsHistoryIterator createBatteryStatsHistoryIterator() { - return new BatteryStatsHistoryIterator(mBatteryStatsHistory); + return mHistory.iterate(); } @Override public int getHistoryStringPoolSize() { - return mHistoryTagPool.size(); + return mHistory.getHistoryStringPoolSize(); } @Override public int getHistoryStringPoolBytes() { - return mNumHistoryTagChars; + return mHistory.getHistoryStringPoolBytes(); } @Override public String getHistoryTagPoolString(int index) { - ensureHistoryTagArray(); - HistoryTag historyTag = mHistoryTags.get(index); - return historyTag != null ? historyTag.string : null; + return mHistory.getHistoryTagPoolString(index); } @Override public int getHistoryTagPoolUid(int index) { - ensureHistoryTagArray(); - HistoryTag historyTag = mHistoryTags.get(index); - return historyTag != null ? historyTag.uid : Process.INVALID_UID; - } - - private void ensureHistoryTagArray() { - if (mHistoryTags != null) { - return; - } - - mHistoryTags = new SparseArray<>(mHistoryTagPool.size()); - for (Map.Entry<HistoryTag, Integer> entry: mHistoryTagPool.entrySet()) { - mHistoryTags.put(entry.getValue() & ~BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG, - entry.getKey()); - } + return mHistory.getHistoryTagPoolUid(index); } @Override @@ -11792,15 +11190,11 @@ public class BatteryStatsImpl extends BatteryStats { @Override public void finishIteratingHistoryLocked() { + mBatteryStatsHistoryIterator.close(); mBatteryStatsHistoryIterator = null; } @Override - public long getHistoryBaseTime() { - return mHistoryBaseTimeMs; - } - - @Override public int getStartCount() { return mStartCount; } @@ -11853,24 +11247,23 @@ public class BatteryStatsImpl extends BatteryStats { long realtimeUs = mSecRealtime * 1000; resetAllStatsLocked(mSecUptime, mSecRealtime, RESET_REASON_ADB_COMMAND); pullPendingStateUpdatesLocked(); - addHistoryRecordLocked(mSecRealtime, mSecUptime); - mDischargeCurrentLevel = mDischargeUnplugLevel = mDischargePlugLevel - = mCurrentBatteryLevel = mHistoryCur.batteryLevel; + mHistory.writeHistoryItem(mSecRealtime, mSecUptime); + mDischargeCurrentLevel = mDischargeUnplugLevel = mDischargePlugLevel = mBatteryLevel; mOnBatteryTimeBase.reset(uptimeUs, realtimeUs); mOnBatteryScreenOffTimeBase.reset(uptimeUs, realtimeUs); - if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) == 0) { + if (!mBatteryPluggedIn) { if (Display.isOnState(mScreenState)) { - mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel; + mDischargeScreenOnUnplugLevel = mBatteryLevel; mDischargeScreenDozeUnplugLevel = 0; mDischargeScreenOffUnplugLevel = 0; } else if (Display.isDozeState(mScreenState)) { mDischargeScreenOnUnplugLevel = 0; - mDischargeScreenDozeUnplugLevel = mHistoryCur.batteryLevel; + mDischargeScreenDozeUnplugLevel = mBatteryLevel; mDischargeScreenOffUnplugLevel = 0; } else { mDischargeScreenOnUnplugLevel = 0; mDischargeScreenDozeUnplugLevel = 0; - mDischargeScreenOffUnplugLevel = mHistoryCur.batteryLevel; + mDischargeScreenOffUnplugLevel = mBatteryLevel; } mDischargeAmountScreenOn = 0; mDischargeAmountScreenOff = 0; @@ -12014,27 +11407,12 @@ public class BatteryStatsImpl extends BatteryStats { resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs); - mLastHistoryStepDetails = null; - mLastStepCpuUserTimeMs = mLastStepCpuSystemTimeMs = 0; - mCurStepCpuUserTimeMs = mCurStepCpuSystemTimeMs = 0; - mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs = 0; - mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs = 0; - mLastStepStatUserTimeMs = mCurStepStatUserTimeMs = 0; - mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs = 0; - mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs = 0; - mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs = 0; - mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs = 0; - mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs = 0; - mNumAllUidCpuTimeReads = 0; mNumUidsRemoved = 0; initDischarge(elapsedRealtimeUs); - clearHistoryLocked(); - if (mBatteryStatsHistory != null) { - mBatteryStatsHistory.resetAllFiles(); - } + mHistory.reset(); // Flush external data, gathering snapshots, but don't process it since it is pre-reset data mIgnoreNextExternalStats = true; @@ -12057,7 +11435,7 @@ public class BatteryStatsImpl extends BatteryStats { for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) { SparseIntArray uids = ent.getValue(); for (int j=0; j<uids.size(); j++) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, i, ent.getKey(), + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, i, ent.getKey(), uids.keyAt(j)); } } @@ -12482,9 +11860,8 @@ public class BatteryStatsImpl extends BatteryStats { (long) (mTmpRailStats.getWifiTotalEnergyUseduWs() / opVolt); mWifiActivity.getMonitoredRailChargeConsumedMaMs().addCountLocked( monitoredRailChargeConsumedMaMs); - mHistoryCur.wifiRailChargeMah += - (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordWifiConsumedCharge(elapsedRealtimeMs, uptimeMs, + (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR)); mTmpRailStats.resetWifiTotalEnergyUsed(); if (uidEstimatedConsumptionMah != null) { @@ -12597,9 +11974,8 @@ public class BatteryStatsImpl extends BatteryStats { (long) (mTmpRailStats.getCellularTotalEnergyUseduWs() / opVolt); mModemActivity.getMonitoredRailChargeConsumedMaMs().addCountLocked( monitoredRailChargeConsumedMaMs); - mHistoryCur.modemRailChargeMah += - (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordWifiConsumedCharge(elapsedRealtimeMs, uptimeMs, + (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR)); mTmpRailStats.resetCellularTotalEnergyUsed(); } @@ -12867,8 +12243,8 @@ public class BatteryStatsImpl extends BatteryStats { } } if (levelMaxTimeSpent == ModemActivityInfo.getNumTxPowerLevels() - 1) { - mHistoryCur.states2 |= HistoryItem.STATE2_CELLULAR_HIGH_TX_POWER_FLAG; - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_CELLULAR_HIGH_TX_POWER_FLAG); } } @@ -14301,11 +13677,7 @@ public class BatteryStatsImpl extends BatteryStats { mHandler.removeCallbacks(mDeferSetCharging); if (mCharging != charging) { mCharging = charging; - if (charging) { - mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG; - } else { - mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG; - } + mHistory.setChargingState(charging); mHandler.sendEmptyMessage(MSG_REPORT_CHARGING); return true; } @@ -14319,6 +13691,15 @@ public class BatteryStatsImpl extends BatteryStats { mSystemReady = true; } + /** + * Force recording of all history events regardless of the "charging" state. + */ + @VisibleForTesting + public void forceRecordAllHistory() { + mHistory.forceRecordAllHistory(); + mRecordAllHistory = true; + } + @GuardedBy("this") protected void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery, final int oldStatus, final int level, final int chargeUah) { @@ -14402,15 +13783,12 @@ public class BatteryStatsImpl extends BatteryStats { mInitStepMode = mCurStepMode; mModStepMode = 0; pullPendingStateUpdatesLocked(); - mHistoryCur.batteryLevel = (byte)level; - mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: " - + Integer.toHexString(mHistoryCur.states)); if (reset) { - mRecordingHistory = true; - startRecordingHistory(mSecRealtime, mSecUptime, reset); + mHistory.startRecordingHistory(mSecRealtime, mSecUptime, reset); + initActiveHistoryEventsLocked(mSecRealtime, mSecUptime); } - addHistoryRecordLocked(mSecRealtime, mSecUptime); + mBatteryPluggedIn = false; + mHistory.recordBatteryState(mSecRealtime, mSecUptime, level, mBatteryPluggedIn); mDischargeCurrentLevel = mDischargeUnplugLevel = level; if (Display.isOnState(screenState)) { mDischargeScreenOnUnplugLevel = level; @@ -14432,11 +13810,8 @@ public class BatteryStatsImpl extends BatteryStats { } else { mOnBattery = mOnBatteryInternal = false; pullPendingStateUpdatesLocked(); - mHistoryCur.batteryLevel = (byte)level; - mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(mSecRealtime, mSecUptime); + mBatteryPluggedIn = true; + mHistory.recordBatteryState(mSecRealtime, mSecUptime, level, mBatteryPluggedIn); mDischargeCurrentLevel = mDischargePlugLevel = level; if (level < mDischargeUnplugLevel) { mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1; @@ -14451,45 +13826,12 @@ public class BatteryStatsImpl extends BatteryStats { mModStepMode = 0; } if (doWrite || (mLastWriteTimeMs + (60 * 1000)) < mSecRealtime) { - if (mStatsFile != null && mBatteryStatsHistory.getActiveFile() != null) { + if (mStatsFile != null && !mHistory.isReadOnly()) { writeAsyncLocked(); } } } - @GuardedBy("this") - private void startRecordingHistory(final long elapsedRealtimeMs, final long uptimeMs, - boolean reset) { - mRecordingHistory = true; - mHistoryCur.currentTime = mClock.currentTimeMillis(); - addHistoryBufferLocked(elapsedRealtimeMs, - reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME, - mHistoryCur); - mHistoryCur.currentTime = 0; - if (reset) { - initActiveHistoryEventsLocked(elapsedRealtimeMs, uptimeMs); - } - } - - @GuardedBy("this") - private void recordCurrentTimeChangeLocked(final long currentTimeMs, - final long elapsedRealtimeMs, final long uptimeMs) { - if (mRecordingHistory) { - mHistoryCur.currentTime = currentTimeMs; - addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_CURRENT_TIME, mHistoryCur); - mHistoryCur.currentTime = 0; - } - } - - @GuardedBy("this") - private void recordShutdownLocked(final long currentTimeMs, final long elapsedRealtimeMs) { - if (mRecordingHistory) { - mHistoryCur.currentTime = currentTimeMs; - addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_SHUTDOWN, mHistoryCur); - mHistoryCur.currentTime = 0; - } - } - private void scheduleSyncExternalStatsLocked(String reason, int updateFlags) { if (mExternalSync != null) { mExternalSync.scheduleSync(reason, updateFlags); @@ -14507,8 +13849,7 @@ public class BatteryStatsImpl extends BatteryStats { // Temperature is encoded without the signed bit, so clamp any negative temperatures to 0. temp = Math.max(0, temp); - reportChangesToStatsLog(mHaveBatteryLevel ? mHistoryCur : null, - status, plugType, level); + reportChangesToStatsLog(status, plugType, level); final boolean onBattery = isOnBattery(plugType, status); if (!mHaveBatteryLevel) { @@ -14518,52 +13859,47 @@ public class BatteryStatsImpl extends BatteryStats { // plugged in, then twiddle our state to correctly reflect that // since we won't be going through the full setOnBattery(). if (onBattery == mOnBattery) { - if (onBattery) { - mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; - } else { - mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG; - } + mHistory.setPluggedInState(!onBattery); } + mBatteryStatus = status; + mBatteryLevel = level; + mBatteryChargeUah = chargeUah; + // Always start out assuming charging, that will be updated later. - mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG; - mHistoryCur.batteryStatus = (byte)status; - mHistoryCur.batteryLevel = (byte)level; - mHistoryCur.batteryChargeUah = chargeUah; + mHistory.setBatteryState(true /* charging */, status, level, chargeUah); + mMaxChargeStepLevel = mMinDischargeStepLevel = mLastChargeStepLevel = mLastDischargeStepLevel = level; - } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) { + } else if (mBatteryLevel != level || mOnBattery != onBattery) { recordDailyStatsIfNeededLocked(level >= 100 && onBattery, currentTimeMs); } - int oldStatus = mHistoryCur.batteryStatus; + int oldStatus = mBatteryStatus; if (onBattery) { mDischargeCurrentLevel = level; - if (!mRecordingHistory) { - mRecordingHistory = true; - startRecordingHistory(elapsedRealtimeMs, uptimeMs, true); + if (!mHistory.isRecordingHistory()) { + mHistory.startRecordingHistory(elapsedRealtimeMs, uptimeMs, true); } } else if (level < 96 && status != BatteryManager.BATTERY_STATUS_UNKNOWN) { - if (!mRecordingHistory) { - mRecordingHistory = true; - startRecordingHistory(elapsedRealtimeMs, uptimeMs, true); + if (!mHistory.isRecordingHistory()) { + mHistory.startRecordingHistory(elapsedRealtimeMs, uptimeMs, true); } } - mBatteryVoltageMv = voltageMv; - mCurrentBatteryLevel = level; if (mDischargePlugLevel < 0) { mDischargePlugLevel = level; } if (onBattery != mOnBattery) { - mHistoryCur.batteryLevel = (byte)level; - mHistoryCur.batteryStatus = (byte)status; - mHistoryCur.batteryHealth = (byte)health; - mHistoryCur.batteryPlugType = (byte)plugType; - mHistoryCur.batteryTemperature = (short)temp; - mHistoryCur.batteryVoltage = (char) voltageMv; - if (chargeUah < mHistoryCur.batteryChargeUah) { + mBatteryLevel = level; + mBatteryStatus = status; + mBatteryHealth = health; + mBatteryPlugType = plugType; + mBatteryTemperature = temp; + mBatteryVoltageMv = voltageMv; + mHistory.setBatteryState(status, level, health, plugType, temp, voltageMv, chargeUah); + if (chargeUah < mBatteryChargeUah) { // Only record discharges - final long chargeDiff = mHistoryCur.batteryChargeUah - chargeUah; + final long chargeDiff = (long) mBatteryChargeUah - chargeUah; mDischargeCounter.addCountLocked(chargeDiff); mDischargeScreenOffCounter.addCountLocked(chargeDiff); if (Display.isDozeState(mScreenState)) { @@ -14575,12 +13911,12 @@ public class BatteryStatsImpl extends BatteryStats { mDischargeDeepDozeCounter.addCountLocked(chargeDiff); } } - mHistoryCur.batteryChargeUah = chargeUah; + mBatteryChargeUah = chargeUah; setOnBatteryLocked(elapsedRealtimeMs, uptimeMs, onBattery, oldStatus, level, chargeUah); } else { boolean changed = false; - if (mHistoryCur.batteryLevel != level) { - mHistoryCur.batteryLevel = (byte)level; + if (mBatteryLevel != level) { + mBatteryLevel = level; changed = true; // TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record @@ -14588,33 +13924,33 @@ public class BatteryStatsImpl extends BatteryStats { mExternalSync.scheduleSyncDueToBatteryLevelChange( mConstants.BATTERY_LEVEL_COLLECTION_DELAY_MS); } - if (mHistoryCur.batteryStatus != status) { - mHistoryCur.batteryStatus = (byte)status; + if (mBatteryStatus != status) { + mBatteryStatus = status; changed = true; } - if (mHistoryCur.batteryHealth != health) { - mHistoryCur.batteryHealth = (byte)health; + if (mBatteryHealth != health) { + mBatteryHealth = health; changed = true; } - if (mHistoryCur.batteryPlugType != plugType) { - mHistoryCur.batteryPlugType = (byte)plugType; + if (mBatteryPlugType != plugType) { + mBatteryPlugType = plugType; changed = true; } - if (temp >= (mHistoryCur.batteryTemperature+10) - || temp <= (mHistoryCur.batteryTemperature-10)) { - mHistoryCur.batteryTemperature = (short)temp; + if (temp >= (mBatteryTemperature + 10) + || temp <= (mBatteryTemperature - 10)) { + mBatteryTemperature = temp; changed = true; } - if (voltageMv > (mHistoryCur.batteryVoltage + 20) - || voltageMv < (mHistoryCur.batteryVoltage - 20)) { - mHistoryCur.batteryVoltage = (char) voltageMv; + if (voltageMv > (mBatteryVoltageMv + 20) + || voltageMv < (mBatteryVoltageMv - 20)) { + mBatteryVoltageMv = voltageMv; changed = true; } - if (chargeUah >= (mHistoryCur.batteryChargeUah + 10) - || chargeUah <= (mHistoryCur.batteryChargeUah - 10)) { - if (chargeUah < mHistoryCur.batteryChargeUah) { + if (chargeUah >= (mBatteryChargeUah + 10) + || chargeUah <= (mBatteryChargeUah - 10)) { + if (chargeUah < mBatteryChargeUah) { // Only record discharges - final long chargeDiff = mHistoryCur.batteryChargeUah - chargeUah; + final long chargeDiff = (long) mBatteryChargeUah - chargeUah; mDischargeCounter.addCountLocked(chargeDiff); mDischargeScreenOffCounter.addCountLocked(chargeDiff); if (Display.isDozeState(mScreenState)) { @@ -14626,9 +13962,10 @@ public class BatteryStatsImpl extends BatteryStats { mDischargeDeepDozeCounter.addCountLocked(chargeDiff); } } - mHistoryCur.batteryChargeUah = chargeUah; + mBatteryChargeUah = chargeUah; changed = true; } + long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT) | (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT) | (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT); @@ -14686,7 +14023,10 @@ public class BatteryStatsImpl extends BatteryStats { mLastChargeStepLevel = level; } if (changed) { - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.setBatteryState(mBatteryStatus, mBatteryLevel, mBatteryHealth, + mBatteryPlugType, mBatteryTemperature, mBatteryVoltageMv, + mBatteryChargeUah); + mHistory.writeHistoryItem(elapsedRealtimeMs, uptimeMs); } } if (!onBattery && @@ -14695,7 +14035,7 @@ public class BatteryStatsImpl extends BatteryStats { // We don't record history while we are plugged in and fully charged // (or when battery is not present). The next time we are // unplugged, history will be cleared. - mRecordingHistory = DEBUG; + mHistory.setHistoryRecordingEnabled(DEBUG); } mLastLearnedBatteryCapacityUah = chargeFullUah; @@ -14714,17 +14054,18 @@ public class BatteryStatsImpl extends BatteryStats { } // Inform StatsLog of setBatteryState changes. - // If this is the first reporting, pass in recentPast == null. - private void reportChangesToStatsLog(HistoryItem recentPast, - final int status, final int plugType, final int level) { + private void reportChangesToStatsLog(final int status, final int plugType, final int level) { + if (!mHaveBatteryLevel) { + return; + } - if (recentPast == null || recentPast.batteryStatus != status) { + if (mBatteryStatus != status) { FrameworkStatsLog.write(FrameworkStatsLog.CHARGING_STATE_CHANGED, status); } - if (recentPast == null || recentPast.batteryPlugType != plugType) { + if (mBatteryPlugType != plugType) { FrameworkStatsLog.write(FrameworkStatsLog.PLUGGED_STATE_CHANGED, plugType); } - if (recentPast == null || recentPast.batteryLevel != level) { + if (mBatteryLevel != level) { FrameworkStatsLog.write(FrameworkStatsLog.BATTERY_LEVEL_CHANGED, level); } } @@ -14794,7 +14135,7 @@ public class BatteryStatsImpl extends BatteryStats { if (msPerLevel <= 0) { return -1; } - return (msPerLevel * mCurrentBatteryLevel) * 1000; + return (msPerLevel * mBatteryLevel) * 1000; } @Override @@ -14824,7 +14165,7 @@ public class BatteryStatsImpl extends BatteryStats { if (msPerLevel <= 0) { return -1; } - return (msPerLevel * (100 - mCurrentBatteryLevel)) * 1000; + return (msPerLevel * (100 - mBatteryLevel)) * 1000; } /*@hide */ @@ -15255,7 +14596,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void shutdownLocked() { - recordShutdownLocked(mClock.currentTimeMillis(), mClock.elapsedRealtime()); + mHistory.recordShutdownEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), + mClock.currentTimeMillis()); writeSyncLocked(); mShuttingDown = true; } @@ -15463,7 +14805,6 @@ public class BatteryStatsImpl extends BatteryStats { PROC_STATE_CHANGE_COLLECTION_DELAY_MS = mParser.getLong( KEY_PROC_STATE_CHANGE_COLLECTION_DELAY_MS, DEFAULT_PROC_STATE_CHANGE_COLLECTION_DELAY_MS); - MAX_HISTORY_FILES = mParser.getInt(KEY_MAX_HISTORY_FILES, ActivityManager.isLowRamDeviceStatic() ? DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE @@ -15474,9 +14815,20 @@ public class BatteryStatsImpl extends BatteryStats { : DEFAULT_MAX_HISTORY_BUFFER_KB) * 1024; updateBatteryChargedDelayMsLocked(); + + onChange(); } } + /** + * Propagates changes in constant values. + */ + @VisibleForTesting + public void onChange() { + mHistory.setMaxHistoryFiles(MAX_HISTORY_FILES); + mHistory.setMaxHistoryBufferSize(MAX_HISTORY_BUFFER); + } + private void updateBatteryChargedDelayMsLocked() { // a negative value indicates that we should ignore this override final int delay = Settings.Global.getInt(mResolver, @@ -15697,27 +15049,11 @@ public class BatteryStatsImpl extends BatteryStats { } private void writeHistoryLocked() { - if (mBatteryStatsHistory.getActiveFile() == null) { - Slog.w(TAG, "writeHistoryLocked: no history file associated with this instance"); - return; - } - if (mShuttingDown) { return; } - Parcel p = Parcel.obtain(); - try { - final long start = SystemClock.uptimeMillis(); - writeHistoryBuffer(p, true); - if (DEBUG) { - Slog.d(TAG, "writeHistoryBuffer duration ms:" - + (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize()); - } - writeParcelToFileLocked(p, mBatteryStatsHistory.getActiveFile()); - } finally { - p.recycle(); - } + mHistory.writeHistory(); } private final ReentrantLock mWriteLock = new ReentrantLock(); @@ -15756,13 +15092,6 @@ public class BatteryStatsImpl extends BatteryStats { return; } - final AtomicFile activeHistoryFile = mBatteryStatsHistory.getActiveFile(); - if (activeHistoryFile == null) { - Slog.w(TAG, - "readLocked: no history file associated with this instance"); - return; - } - mUidStats.clear(); Parcel stats = Parcel.obtain(); @@ -15775,7 +15104,7 @@ public class BatteryStatsImpl extends BatteryStats { readSummaryFromParcel(stats); if (DEBUG) { Slog.d(TAG, "readLocked stats file:" + mStatsFile.getBaseFile().getPath() - + " bytes:" + raw.length + " takes ms:" + (SystemClock.uptimeMillis() + + " bytes:" + raw.length + " took ms:" + (SystemClock.uptimeMillis() - start)); } } @@ -15787,126 +15116,19 @@ public class BatteryStatsImpl extends BatteryStats { stats.recycle(); } - Parcel history = Parcel.obtain(); - try { - final long start = SystemClock.uptimeMillis(); - if (activeHistoryFile.exists()) { - byte[] raw = activeHistoryFile.readFully(); - if (raw.length > 0) { - history.unmarshall(raw, 0, raw.length); - history.setDataPosition(0); - readHistoryBuffer(history); - } - if (DEBUG) { - Slog.d(TAG, "readLocked history file::" - + activeHistoryFile.getBaseFile().getPath() - + " bytes:" + raw.length + " takes ms:" + (SystemClock.uptimeMillis() - - start)); - } - } - } catch (Exception e) { - Slog.e(TAG, "Error reading battery history", e); - clearHistoryLocked(); - mBatteryStatsHistory.resetAllFiles(); - } finally { - history.recycle(); + if (!mHistory.readSummary()) { + resetAllStatsLocked(SystemClock.uptimeMillis(), SystemClock.elapsedRealtime(), + RESET_REASON_CORRUPT_FILE); } mEndPlatformVersion = Build.ID; - if (mHistoryBuffer.dataPosition() > 0 - || mBatteryStatsHistory.getFilesNumbers().size() > 1) { - mRecordingHistory = true; - final long elapsedRealtimeMs = mClock.elapsedRealtime(); - final long uptimeMs = mClock.uptimeMillis(); - addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_START, mHistoryCur); - startRecordingHistory(elapsedRealtimeMs, uptimeMs, false); - } + mHistory.continueRecordingHistory(); recordDailyStatsIfNeededLocked(false, mClock.currentTimeMillis()); } @GuardedBy("this") - void readHistoryBuffer(Parcel in) throws ParcelFormatException { - final int version = in.readInt(); - if (version != BatteryStatsHistory.VERSION) { - Slog.w("BatteryStats", "readHistoryBuffer: version got " + version - + ", expected " + BatteryStatsHistory.VERSION + "; erasing old stats"); - return; - } - - final long historyBaseTime = in.readLong(); - - mHistoryBuffer.setDataSize(0); - mHistoryBuffer.setDataPosition(0); - - int bufSize = in.readInt(); - int curPos = in.dataPosition(); - if (bufSize >= (mConstants.MAX_HISTORY_BUFFER*100)) { - throw new ParcelFormatException("File corrupt: history data buffer too large " + - bufSize); - } else if ((bufSize&~3) != bufSize) { - throw new ParcelFormatException("File corrupt: history data buffer not aligned " + - bufSize); - } else { - if (DEBUG_HISTORY) Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize - + " bytes at " + curPos); - mHistoryBuffer.appendFrom(in, curPos, bufSize); - in.setDataPosition(curPos + bufSize); - } - - if (DEBUG_HISTORY) { - StringBuilder sb = new StringBuilder(128); - sb.append("****************** OLD mHistoryBaseTimeMs: "); - TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); - Slog.i(TAG, sb.toString()); - } - mHistoryBaseTimeMs = historyBaseTime; - if (DEBUG_HISTORY) { - StringBuilder sb = new StringBuilder(128); - sb.append("****************** NEW mHistoryBaseTimeMs: "); - TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); - Slog.i(TAG, sb.toString()); - } - - // We are just arbitrarily going to insert 1 minute from the sample of - // the last run until samples in this run. - if (mHistoryBaseTimeMs > 0) { - long oldnow = mClock.elapsedRealtime(); - mHistoryBaseTimeMs = mHistoryBaseTimeMs - oldnow + 1; - if (DEBUG_HISTORY) { - StringBuilder sb = new StringBuilder(128); - sb.append("****************** ADJUSTED mHistoryBaseTimeMs: "); - TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); - Slog.i(TAG, sb.toString()); - } - } - } - - void writeHistoryBuffer(Parcel out, boolean inclData) { - if (DEBUG_HISTORY) { - StringBuilder sb = new StringBuilder(128); - sb.append("****************** WRITING mHistoryBaseTimeMs: "); - TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); - sb.append(" mLastHistoryElapsedRealtimeMs: "); - TimeUtils.formatDuration(mLastHistoryElapsedRealtimeMs, sb); - Slog.i(TAG, sb.toString()); - } - out.writeInt(BatteryStatsHistory.VERSION); - out.writeLong(mHistoryBaseTimeMs + mLastHistoryElapsedRealtimeMs); - if (!inclData) { - out.writeInt(0); - out.writeInt(0); - return; - } - - out.writeInt(mHistoryBuffer.dataSize()); - if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: " - + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition()); - out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize()); - } - - @GuardedBy("this") public void readSummaryFromParcel(Parcel in) throws ParcelFormatException { final int version = in.readInt(); @@ -15916,31 +15138,7 @@ public class BatteryStatsImpl extends BatteryStats { return; } - boolean inclHistory = in.readBoolean(); - if (inclHistory) { - readHistoryBuffer(in); - mBatteryStatsHistory.readFromParcel(in); - } - - mHistoryTagPool.clear(); - mNextHistoryTagIdx = 0; - mNumHistoryTagChars = 0; - - int numTags = in.readInt(); - for (int i=0; i<numTags; i++) { - int idx = in.readInt(); - String str = in.readString(); - int uid = in.readInt(); - HistoryTag tag = new HistoryTag(); - tag.string = str; - tag.uid = uid; - tag.poolIdx = idx; - mHistoryTagPool.put(tag, idx); - if (idx >= mNextHistoryTagIdx) { - mNextHistoryTagIdx = idx+1; - } - mNumHistoryTagChars += tag.string.length() + 1; - } + mHistory.readSummaryFromParcel(in); mStartCount = in.readInt(); mUptimeUs = in.readLong(); @@ -15953,7 +15151,7 @@ public class BatteryStatsImpl extends BatteryStats { mDischargeUnplugLevel = in.readInt(); mDischargePlugLevel = in.readInt(); mDischargeCurrentLevel = in.readInt(); - mCurrentBatteryLevel = in.readInt(); + mBatteryLevel = in.readInt(); mEstimatedBatteryCapacityMah = in.readInt(); mLastLearnedBatteryCapacityUah = in.readInt(); mMinLearnedBatteryCapacityUah = in.readInt(); @@ -16456,19 +15654,7 @@ public class BatteryStatsImpl extends BatteryStats { out.writeInt(VERSION); - out.writeBoolean(inclHistory); - if (inclHistory) { - writeHistoryBuffer(out, true); - mBatteryStatsHistory.writeToParcel(out); - } - - out.writeInt(mHistoryTagPool.size()); - for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) { - HistoryTag tag = ent.getKey(); - out.writeInt(ent.getValue()); - out.writeString(tag.string); - out.writeInt(tag.uid); - } + mHistory.writeSummaryToParcel(out, inclHistory); out.writeInt(mStartCount); out.writeLong(computeUptime(nowUptime, STATS_SINCE_CHARGED)); @@ -16481,7 +15667,7 @@ public class BatteryStatsImpl extends BatteryStats { out.writeInt(mDischargeUnplugLevel); out.writeInt(mDischargePlugLevel); out.writeInt(mDischargeCurrentLevel); - out.writeInt(mCurrentBatteryLevel); + out.writeInt(mBatteryLevel); out.writeInt(mEstimatedBatteryCapacityMah); out.writeInt(mLastLearnedBatteryCapacityUah); out.writeInt(mMinLearnedBatteryCapacityUah); diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java index 0cdd4d101459..c36d950b6cf6 100644 --- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java +++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java @@ -22,7 +22,6 @@ import android.os.BatteryConsumer; import android.os.BatteryStats; import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; -import android.os.Parcel; import android.os.Process; import android.os.SystemClock; import android.os.UidBatteryConsumer; @@ -32,10 +31,8 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.os.BatteryStatsHistory; import com.android.internal.os.PowerProfile; -import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -220,18 +217,7 @@ public class BatteryUsageStatsProvider { } BatteryStatsImpl batteryStatsImpl = (BatteryStatsImpl) mStats; - - // Make a copy of battery history to avoid concurrent modification. - Parcel historyBuffer = Parcel.obtain(); - historyBuffer.appendFrom(batteryStatsImpl.mHistoryBuffer, 0, - batteryStatsImpl.mHistoryBuffer.dataSize()); - - final File systemDir = - batteryStatsImpl.mBatteryStatsHistory.getHistoryDirectory().getParentFile(); - final BatteryStatsHistory batteryStatsHistory = - new BatteryStatsHistory(historyBuffer, systemDir, null); - - batteryUsageStatsBuilder.setBatteryHistory(batteryStatsHistory); + batteryUsageStatsBuilder.setBatteryHistory(batteryStatsImpl.copyHistory()); } BatteryUsageStats stats = batteryUsageStatsBuilder.build(); diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java index 61a7f3853746..5c9348525861 100644 --- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java +++ b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java @@ -28,6 +28,7 @@ import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.internal.os.BatteryStatsHistory; +import com.android.internal.os.Clock; import org.junit.Before; import org.junit.Test; @@ -49,13 +50,14 @@ public class BatteryStatsHistoryTest { private final Parcel mHistoryBuffer = Parcel.obtain(); private File mSystemDir; private File mHistoryDir; + private final Clock mClock = new MockClock(); @Before public void setUp() { MockitoAnnotations.initMocks(this); Context context = InstrumentationRegistry.getContext(); mSystemDir = context.getDataDir(); - mHistoryDir = new File(mSystemDir, BatteryStatsHistory.HISTORY_DIR); + mHistoryDir = new File(mSystemDir, "battery-history"); String[] files = mHistoryDir.list(); if (files != null) { for (int i = 0; i < files.length; i++) { @@ -67,8 +69,8 @@ public class BatteryStatsHistoryTest { @Test public void testConstruct() { - BatteryStatsHistory history = - new BatteryStatsHistory(mHistoryBuffer, mSystemDir, () -> 32); + BatteryStatsHistory history = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024, + null, mClock); createActiveFile(history); verifyFileNumbers(history, Arrays.asList(0)); verifyActiveFile(history, "0.bin"); @@ -76,8 +78,8 @@ public class BatteryStatsHistoryTest { @Test public void testStartNextFile() { - BatteryStatsHistory history = - new BatteryStatsHistory(mHistoryBuffer, mSystemDir, () -> 32); + BatteryStatsHistory history = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024, + null, mClock); List<Integer> fileList = new ArrayList<>(); fileList.add(0); createActiveFile(history); @@ -114,13 +116,13 @@ public class BatteryStatsHistoryTest { assertEquals(0, history.getHistoryUsedSize()); // create a new BatteryStatsHistory object, it will pick up existing history files. - BatteryStatsHistory history2 = - new BatteryStatsHistory(mHistoryBuffer, mSystemDir, () -> 32); - // verify construct can pick up all files from file system. + BatteryStatsHistory history2 = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024, + null, mClock); + // verify constructor can pick up all files from file system. verifyFileNumbers(history2, fileList); verifyActiveFile(history2, "33.bin"); - history2.resetAllFiles(); + history2.reset(); createActiveFile(history2); // verify all existing files are deleted. for (int i = 2; i < 33; ++i) { diff --git a/services/tests/servicestests/src/com/android/server/power/stats/MockBatteryStatsImpl.java b/services/tests/servicestests/src/com/android/server/power/stats/MockBatteryStatsImpl.java index 713e78638b95..570b2ee617f5 100644 --- a/services/tests/servicestests/src/com/android/server/power/stats/MockBatteryStatsImpl.java +++ b/services/tests/servicestests/src/com/android/server/power/stats/MockBatteryStatsImpl.java @@ -63,6 +63,7 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { MockBatteryStatsImpl(Clock clock, File historyDirectory) { super(clock, historyDirectory); initTimersAndCounters(); + setMaxHistoryBuffer(128 * 1024); setExternalStatsSyncLocked(mExternalStatsSync); informThatAllExternalStatsAreFlushed(); @@ -104,12 +105,6 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { return mForceOnBattery ? true : super.isOnBattery(); } - public void forceRecordAllHistory() { - mHaveBatteryLevel = true; - mRecordingHistory = true; - mRecordAllHistory = true; - } - public TimeBase getOnBatteryBackgroundTimeBase(int uid) { return getUidStatsLocked(uid).mOnBatteryBackgroundTimeBase; } @@ -201,12 +196,14 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { @GuardedBy("this") public MockBatteryStatsImpl setMaxHistoryFiles(int maxHistoryFiles) { mConstants.MAX_HISTORY_FILES = maxHistoryFiles; + mConstants.onChange(); return this; } @GuardedBy("this") public MockBatteryStatsImpl setMaxHistoryBuffer(int maxHistoryBuffer) { mConstants.MAX_HISTORY_BUFFER = maxHistoryBuffer; + mConstants.onChange(); return this; } |