1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.os;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.os.BatteryManager;
22 import android.os.BatteryStats;
23 import android.os.BatteryStats.BitDescription;
24 import android.os.BatteryStats.CpuUsageDetails;
25 import android.os.BatteryStats.EnergyConsumerDetails;
26 import android.os.BatteryStats.HistoryItem;
27 import android.os.BatteryStats.HistoryStepDetails;
28 import android.os.BatteryStats.HistoryTag;
29 import android.os.Build;
30 import android.os.Parcel;
31 import android.os.ParcelFormatException;
32 import android.os.Process;
33 import android.os.StatFs;
34 import android.os.SystemClock;
35 import android.os.SystemProperties;
36 import android.os.Trace;
37 import android.util.ArraySet;
38 import android.util.AtomicFile;
39 import android.util.Slog;
40 import android.util.SparseArray;
41 import android.util.TimeUtils;
42 
43 import com.android.internal.annotations.GuardedBy;
44 import com.android.internal.annotations.VisibleForTesting;
45 import com.android.internal.util.ParseUtils;
46 
47 import java.io.File;
48 import java.io.FileOutputStream;
49 import java.io.IOException;
50 import java.util.ArrayList;
51 import java.util.Collections;
52 import java.util.ConcurrentModificationException;
53 import java.util.HashMap;
54 import java.util.List;
55 import java.util.Map;
56 import java.util.Set;
57 import java.util.concurrent.locks.ReentrantLock;
58 
59 /**
60  * BatteryStatsHistory encapsulates battery history files.
61  * Battery history record is appended into buffer {@link #mHistoryBuffer} and backed up into
62  * {@link #mActiveFile}.
63  * When {@link #mHistoryBuffer} size reaches {@link BatteryStatsImpl.Constants#MAX_HISTORY_BUFFER},
64  * current mActiveFile is closed and a new mActiveFile is open.
65  * History files are under directory /data/system/battery-history/.
66  * History files have name battery-history-<num>.bin. The file number <num> starts from zero and
67  * grows sequentially.
68  * The mActiveFile is always the highest numbered history file.
69  * The lowest number file is always the oldest file.
70  * The highest number file is always the newest file.
71  * The file number grows sequentially and we never skip number.
72  * When count of history files exceeds {@link BatteryStatsImpl.Constants#MAX_HISTORY_FILES},
73  * the lowest numbered file is deleted and a new file is open.
74  *
75  * All interfaces in BatteryStatsHistory should only be called by BatteryStatsImpl and protected by
76  * locks on BatteryStatsImpl object.
77  */
78 public class BatteryStatsHistory {
79     private static final boolean DEBUG = false;
80     private static final String TAG = "BatteryStatsHistory";
81 
82     // Current on-disk Parcel version. Must be updated when the format of the parcelable changes
83     private static final int VERSION = 209;
84 
85     private static final String HISTORY_DIR = "battery-history";
86     private static final String FILE_SUFFIX = ".bin";
87     private static final int MIN_FREE_SPACE = 100 * 1024 * 1024;
88 
89     // Part of initial delta int that specifies the time delta.
90     static final int DELTA_TIME_MASK = 0x7ffff;
91     static final int DELTA_TIME_LONG = 0x7ffff;   // The delta is a following long
92     static final int DELTA_TIME_INT = 0x7fffe;    // The delta is a following int
93     static final int DELTA_TIME_ABS = 0x7fffd;    // Following is an entire abs update.
94     // Flag in delta int: a new battery level int follows.
95     static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000;
96     // Flag in delta int: a new full state and battery status int follows.
97     static final int DELTA_STATE_FLAG = 0x00100000;
98     // Flag in delta int: a new full state2 int follows.
99     static final int DELTA_STATE2_FLAG = 0x00200000;
100     // Flag in delta int: contains a wakelock or wakeReason tag.
101     static final int DELTA_WAKELOCK_FLAG = 0x00400000;
102     // Flag in delta int: contains an event description.
103     static final int DELTA_EVENT_FLAG = 0x00800000;
104     // Flag in delta int: contains the battery charge count in uAh.
105     static final int DELTA_BATTERY_CHARGE_FLAG = 0x01000000;
106     // These upper bits are the frequently changing state bits.
107     static final int DELTA_STATE_MASK = 0xfe000000;
108     // These are the pieces of battery state that are packed in to the upper bits of
109     // the state int that have been packed in to the first delta int.  They must fit
110     // in STATE_BATTERY_MASK.
111     static final int STATE_BATTERY_MASK = 0xff000000;
112     static final int STATE_BATTERY_STATUS_MASK = 0x00000007;
113     static final int STATE_BATTERY_STATUS_SHIFT = 29;
114     static final int STATE_BATTERY_HEALTH_MASK = 0x00000007;
115     static final int STATE_BATTERY_HEALTH_SHIFT = 26;
116     static final int STATE_BATTERY_PLUG_MASK = 0x00000003;
117     static final int STATE_BATTERY_PLUG_SHIFT = 24;
118 
119     // We use the low bit of the battery state int to indicate that we have full details
120     // from a battery level change.
121     static final int BATTERY_LEVEL_DETAILS_FLAG = 0x00000001;
122 
123     // Flag in history tag index: indicates that this is the first occurrence of this tag,
124     // therefore the tag value is written in the parcel
125     static final int TAG_FIRST_OCCURRENCE_FLAG = 0x8000;
126 
127     static final int EXTENSION_MEASURED_ENERGY_HEADER_FLAG = 0x00000001;
128     static final int EXTENSION_MEASURED_ENERGY_FLAG = 0x00000002;
129     static final int EXTENSION_CPU_USAGE_HEADER_FLAG = 0x00000004;
130     static final int EXTENSION_CPU_USAGE_FLAG = 0x00000008;
131 
132     private final Parcel mHistoryBuffer;
133     private final File mSystemDir;
134     private final HistoryStepDetailsCalculator mStepDetailsCalculator;
135     private final File mHistoryDir;
136     private final Clock mClock;
137 
138     private int mMaxHistoryFiles;
139     private int mMaxHistoryBufferSize;
140 
141     /**
142      * The active history file that the history buffer is backed up into.
143      */
144     private AtomicFile mActiveFile;
145     /**
146      * A list of history files with incremental indexes.
147      */
148     private final List<Integer> mFileNumbers = new ArrayList<>();
149 
150     /**
151      * A list of small history parcels, used when BatteryStatsImpl object is created from
152      * deserialization of a parcel, such as Settings app or checkin file.
153      */
154     private List<Parcel> mHistoryParcels = null;
155 
156     /**
157      * When iterating history files, the current file index.
158      */
159     private int mCurrentFileIndex;
160     /**
161      * When iterating history files, the current file parcel.
162      */
163     private Parcel mCurrentParcel;
164     /**
165      * When iterating history file, the current parcel's Parcel.dataSize().
166      */
167     private int mCurrentParcelEnd;
168     /**
169      * Used when BatteryStatsImpl object is created from deserialization of a parcel,
170      * such as Settings app or checkin file, to iterate over history parcels.
171      */
172     private int mParcelIndex = 0;
173 
174     private final ReentrantLock mWriteLock = new ReentrantLock();
175 
176     private final HistoryItem mHistoryCur = new HistoryItem();
177 
178     private boolean mHaveBatteryLevel;
179     private boolean mRecordingHistory;
180 
181     static final int HISTORY_TAG_INDEX_LIMIT = 0x7ffe;
182     private static final int MAX_HISTORY_TAG_STRING_LENGTH = 1024;
183 
184     private final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>();
185     private SparseArray<HistoryTag> mHistoryTags;
186     private final HistoryItem mHistoryLastWritten = new HistoryItem();
187     private final HistoryItem mHistoryLastLastWritten = new HistoryItem();
188     private final HistoryItem mHistoryAddTmp = new HistoryItem();
189     private int mNextHistoryTagIdx = 0;
190     private int mNumHistoryTagChars = 0;
191     private int mHistoryBufferLastPos = -1;
192     private long mLastHistoryElapsedRealtimeMs = 0;
193     private long mTrackRunningHistoryElapsedRealtimeMs = 0;
194     private long mTrackRunningHistoryUptimeMs = 0;
195     private long mHistoryBaseTimeMs;
196     private boolean mMeasuredEnergyHeaderWritten = false;
197     private boolean mCpuUsageHeaderWritten = false;
198     private final VarintParceler mVarintParceler = new VarintParceler();
199     private byte mLastHistoryStepLevel = 0;
200     private boolean mMutable = true;
201     private final BatteryStatsHistory mWritableHistory;
202     private boolean mCleanupEnabled = true;
203 
204     /**
205      * A delegate responsible for computing additional details for a step in battery history.
206      */
207     public interface HistoryStepDetailsCalculator {
208         /**
209          * Returns additional details for the current history step or null.
210          */
211         @Nullable
getHistoryStepDetails()212         HistoryStepDetails getHistoryStepDetails();
213 
214         /**
215          * Resets the calculator to get ready for a new battery session
216          */
clear()217         void clear();
218     }
219 
220     /**
221      * A delegate for android.os.Trace to allow testing static calls. Due to
222      * limitations in Android Tracing (b/153319140), the delegate also records
223      * counter values in system properties which allows reading the value at the
224      * start of a tracing session. This overhead is limited to userdebug builds.
225      * On user builds, tracing still occurs but the counter value will be missing
226      * until the first change occurs.
227      */
228     @VisibleForTesting
229     public static class TraceDelegate {
230         // Note: certain tests currently run as platform_app which is not allowed
231         // to set debug system properties. To ensure that system properties are set
232         // only when allowed, we check the current UID.
233         private final boolean mShouldSetProperty =
234                 Build.IS_USERDEBUG && (Process.myUid() == Process.SYSTEM_UID);
235 
236         /**
237          * Returns true if trace counters should be recorded.
238          */
tracingEnabled()239         public boolean tracingEnabled() {
240             return Trace.isTagEnabled(Trace.TRACE_TAG_POWER) || mShouldSetProperty;
241         }
242 
243         /**
244          * Records the counter value with the given name.
245          */
traceCounter(@onNull String name, int value)246         public void traceCounter(@NonNull String name, int value) {
247             Trace.traceCounter(Trace.TRACE_TAG_POWER, name, value);
248             if (mShouldSetProperty) {
249                 SystemProperties.set("debug.tracing." + name, Integer.toString(value));
250             }
251         }
252 
253         /**
254          * Records an instant event (one with no duration).
255          */
traceInstantEvent(@onNull String track, @NonNull String name)256         public void traceInstantEvent(@NonNull String track, @NonNull String name) {
257             Trace.instantForTrack(Trace.TRACE_TAG_POWER, track, name);
258         }
259     }
260 
261     private TraceDelegate mTracer;
262     private int mTraceLastState = 0;
263     private int mTraceLastState2 = 0;
264 
265     /**
266      * Constructor
267      *
268      * @param systemDir            typically /data/system
269      * @param maxHistoryFiles      the largest number of history buffer files to keep
270      * @param maxHistoryBufferSize the most amount of RAM to used for buffering of history steps
271      */
BatteryStatsHistory(File systemDir, int maxHistoryFiles, int maxHistoryBufferSize, HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock)272     public BatteryStatsHistory(File systemDir, int maxHistoryFiles, int maxHistoryBufferSize,
273             HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) {
274         this(Parcel.obtain(), systemDir, maxHistoryFiles, maxHistoryBufferSize,
275                 stepDetailsCalculator, clock, new TraceDelegate());
276         initHistoryBuffer();
277     }
278 
279     @VisibleForTesting
BatteryStatsHistory(Parcel historyBuffer, File systemDir, int maxHistoryFiles, int maxHistoryBufferSize, HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, TraceDelegate tracer)280     public BatteryStatsHistory(Parcel historyBuffer, File systemDir,
281             int maxHistoryFiles, int maxHistoryBufferSize,
282             HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, TraceDelegate tracer) {
283         this(historyBuffer, systemDir, maxHistoryFiles, maxHistoryBufferSize, stepDetailsCalculator,
284                 clock, tracer, null);
285     }
286 
BatteryStatsHistory(Parcel historyBuffer, File systemDir, int maxHistoryFiles, int maxHistoryBufferSize, HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, TraceDelegate tracer, BatteryStatsHistory writableHistory)287     private BatteryStatsHistory(Parcel historyBuffer, File systemDir,
288             int maxHistoryFiles, int maxHistoryBufferSize,
289             HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, TraceDelegate tracer,
290             BatteryStatsHistory writableHistory) {
291         mHistoryBuffer = historyBuffer;
292         mSystemDir = systemDir;
293         mMaxHistoryFiles = maxHistoryFiles;
294         mMaxHistoryBufferSize = maxHistoryBufferSize;
295         mStepDetailsCalculator = stepDetailsCalculator;
296         mTracer = tracer;
297         mClock = clock;
298         mWritableHistory = writableHistory;
299         if (mWritableHistory != null) {
300             mMutable = false;
301         }
302 
303         mHistoryDir = new File(systemDir, HISTORY_DIR);
304         mHistoryDir.mkdirs();
305         if (!mHistoryDir.exists()) {
306             Slog.wtf(TAG, "HistoryDir does not exist:" + mHistoryDir.getPath());
307         }
308 
309         final Set<Integer> dedup = new ArraySet<>();
310         // scan directory, fill mFileNumbers and mActiveFile.
311         mHistoryDir.listFiles((dir, name) -> {
312             final int b = name.lastIndexOf(FILE_SUFFIX);
313             if (b <= 0) {
314                 return false;
315             }
316             final int c = ParseUtils.parseInt(name.substring(0, b), -1);
317             if (c != -1) {
318                 dedup.add(c);
319                 return true;
320             } else {
321                 return false;
322             }
323         });
324         if (!dedup.isEmpty()) {
325             mFileNumbers.addAll(dedup);
326             Collections.sort(mFileNumbers);
327             setActiveFile(mFileNumbers.get(mFileNumbers.size() - 1));
328         } else {
329             // No file found, default to have file 0.
330             mFileNumbers.add(0);
331             setActiveFile(0);
332         }
333     }
334 
BatteryStatsHistory(int maxHistoryFiles, int maxHistoryBufferSize, HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock)335     public BatteryStatsHistory(int maxHistoryFiles, int maxHistoryBufferSize,
336             HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) {
337         mMaxHistoryFiles = maxHistoryFiles;
338         mMaxHistoryBufferSize = maxHistoryBufferSize;
339         mStepDetailsCalculator = stepDetailsCalculator;
340         mTracer = new TraceDelegate();
341         mClock = clock;
342 
343         mHistoryBuffer = Parcel.obtain();
344         mSystemDir = null;
345         mHistoryDir = null;
346         mWritableHistory = null;
347         initHistoryBuffer();
348     }
349 
350     /**
351      * Used when BatteryStatsHistory object is created from deserialization of a BatteryUsageStats
352      * parcel.
353      */
BatteryStatsHistory(Parcel parcel)354     private BatteryStatsHistory(Parcel parcel) {
355         mClock = Clock.SYSTEM_CLOCK;
356         mTracer = null;
357         mSystemDir = null;
358         mHistoryDir = null;
359         mStepDetailsCalculator = null;
360         mWritableHistory = null;
361         mMutable = false;
362 
363         final byte[] historyBlob = parcel.readBlob();
364 
365         mHistoryBuffer = Parcel.obtain();
366         mHistoryBuffer.unmarshall(historyBlob, 0, historyBlob.length);
367 
368         readFromParcel(parcel, true /* useBlobs */);
369     }
370 
initHistoryBuffer()371     private void initHistoryBuffer() {
372         mHistoryBaseTimeMs = 0;
373         mLastHistoryElapsedRealtimeMs = 0;
374         mTrackRunningHistoryElapsedRealtimeMs = 0;
375         mTrackRunningHistoryUptimeMs = 0;
376         mMeasuredEnergyHeaderWritten = false;
377         mCpuUsageHeaderWritten = false;
378 
379         mHistoryBuffer.setDataSize(0);
380         mHistoryBuffer.setDataPosition(0);
381         mHistoryBuffer.setDataCapacity(mMaxHistoryBufferSize / 2);
382         mHistoryLastLastWritten.clear();
383         mHistoryLastWritten.clear();
384         mHistoryTagPool.clear();
385         mNextHistoryTagIdx = 0;
386         mNumHistoryTagChars = 0;
387         mHistoryBufferLastPos = -1;
388         if (mStepDetailsCalculator != null) {
389             mStepDetailsCalculator.clear();
390         }
391     }
392 
393     /**
394      * Changes the maximum number of history files to be kept.
395      */
setMaxHistoryFiles(int maxHistoryFiles)396     public void setMaxHistoryFiles(int maxHistoryFiles) {
397         mMaxHistoryFiles = maxHistoryFiles;
398     }
399 
400     /**
401      * Changes the maximum size of the history buffer, in bytes.
402      */
setMaxHistoryBufferSize(int maxHistoryBufferSize)403     public void setMaxHistoryBufferSize(int maxHistoryBufferSize) {
404         mMaxHistoryBufferSize = maxHistoryBufferSize;
405     }
406 
407     /**
408      * Creates a read-only copy of the battery history.  Does not copy the files stored
409      * in the system directory, so it is not safe while actively writing history.
410      */
copy()411     public BatteryStatsHistory copy() {
412         synchronized (this) {
413             // Make a copy of battery history to avoid concurrent modification.
414             Parcel historyBufferCopy = Parcel.obtain();
415             historyBufferCopy.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
416 
417             return new BatteryStatsHistory(historyBufferCopy, mSystemDir, 0, 0, null, null, null,
418                     this);
419         }
420     }
421 
422     /**
423      * Returns true if this instance only supports reading history.
424      */
isReadOnly()425     public boolean isReadOnly() {
426         return mActiveFile == null || mHistoryDir == null;
427     }
428 
429     /**
430      * Set the active file that mHistoryBuffer is backed up into.
431      *
432      * @param fileNumber the history file that mHistoryBuffer is backed up into.
433      */
setActiveFile(int fileNumber)434     private void setActiveFile(int fileNumber) {
435         mActiveFile = getFile(fileNumber);
436         if (DEBUG) {
437             Slog.d(TAG, "activeHistoryFile:" + mActiveFile.getBaseFile().getPath());
438         }
439     }
440 
441     /**
442      * Create history AtomicFile from file number.
443      *
444      * @param num file number.
445      * @return AtomicFile object.
446      */
getFile(int num)447     private AtomicFile getFile(int num) {
448         return new AtomicFile(
449                 new File(mHistoryDir, num + FILE_SUFFIX));
450     }
451 
452     /**
453      * When {@link #mHistoryBuffer} reaches {@link BatteryStatsImpl.Constants#MAX_HISTORY_BUFFER},
454      * create next history file.
455      */
startNextFile()456     public void startNextFile() {
457         if (mMaxHistoryFiles == 0) {
458             Slog.wtf(TAG, "mMaxHistoryFiles should not be zero when writing history");
459             return;
460         }
461 
462         if (mFileNumbers.isEmpty()) {
463             Slog.wtf(TAG, "mFileNumbers should never be empty");
464             return;
465         }
466 
467         // The last number in mFileNumbers is the highest number. The next file number is highest
468         // number plus one.
469         final int next = mFileNumbers.get(mFileNumbers.size() - 1) + 1;
470         mFileNumbers.add(next);
471         setActiveFile(next);
472         try {
473             mActiveFile.getBaseFile().createNewFile();
474         } catch (IOException e) {
475             Slog.e(TAG, "Could not create history file: " + mActiveFile.getBaseFile());
476         }
477 
478         synchronized (this) {
479             cleanupLocked();
480         }
481     }
482 
483     @GuardedBy("this")
setCleanupEnabledLocked(boolean enabled)484     private void setCleanupEnabledLocked(boolean enabled) {
485         mCleanupEnabled = enabled;
486         if (mCleanupEnabled) {
487             cleanupLocked();
488         }
489     }
490 
491     @GuardedBy("this")
cleanupLocked()492     private void cleanupLocked() {
493         if (!mCleanupEnabled || mHistoryDir == null) {
494             return;
495         }
496 
497         // if free disk space is less than 100MB, delete oldest history file.
498         if (!hasFreeDiskSpace()) {
499             int oldest = mFileNumbers.remove(0);
500             getFile(oldest).delete();
501         }
502 
503         // if there are more history files than allowed, delete oldest history files.
504         // mMaxHistoryFiles comes from Constants.MAX_HISTORY_FILES and can be updated by GService
505         // config at run time.
506         while (mFileNumbers.size() > mMaxHistoryFiles) {
507             int oldest = mFileNumbers.get(0);
508             getFile(oldest).delete();
509             mFileNumbers.remove(0);
510         }
511     }
512 
513     /**
514      * Returns true if it is safe to reset history. It will return false if the history is
515      * currently being read.
516      */
isResetEnabled()517     public boolean isResetEnabled() {
518         synchronized (this) {
519             return mCleanupEnabled;
520         }
521     }
522 
523     /**
524      * Clear history buffer and delete all existing history files. Active history file start from
525      * number 0 again.
526      */
reset()527     public void reset() {
528         if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!");
529         for (Integer i : mFileNumbers) {
530             getFile(i).delete();
531         }
532         mFileNumbers.clear();
533         mFileNumbers.add(0);
534         setActiveFile(0);
535 
536         initHistoryBuffer();
537     }
538 
539     /**
540      * Start iterating history files and history buffer.
541      *
542      * @return always return true.
543      */
iterate()544     public BatteryStatsHistoryIterator iterate() {
545         mCurrentFileIndex = 0;
546         mCurrentParcel = null;
547         mCurrentParcelEnd = 0;
548         mParcelIndex = 0;
549         mMutable = false;
550         if (mWritableHistory != null) {
551             synchronized (mWritableHistory) {
552                 mWritableHistory.setCleanupEnabledLocked(false);
553             }
554         }
555         return new BatteryStatsHistoryIterator(this);
556     }
557 
558     /**
559      * Finish iterating history files and history buffer.
560      */
iteratorFinished()561     void iteratorFinished() {
562         // setDataPosition so mHistoryBuffer Parcel can be written.
563         mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
564         if (mWritableHistory != null) {
565             synchronized (mWritableHistory) {
566                 mWritableHistory.setCleanupEnabledLocked(true);
567             }
568         } else {
569             mMutable = true;
570         }
571     }
572 
573     /**
574      * When iterating history files and history buffer, always start from the lowest numbered
575      * history file, when reached the mActiveFile (highest numbered history file), do not read from
576      * mActiveFile, read from history buffer instead because the buffer has more updated data.
577      *
578      * @return The parcel that has next record. null if finished all history files and history
579      * buffer
580      */
581     @Nullable
getNextParcel()582     public Parcel getNextParcel() {
583         // First iterate through all records in current parcel.
584         if (mCurrentParcel != null) {
585             if (mCurrentParcel.dataPosition() < mCurrentParcelEnd) {
586                 // There are more records in current parcel.
587                 return mCurrentParcel;
588             } else if (mHistoryBuffer == mCurrentParcel) {
589                 // finished iterate through all history files and history buffer.
590                 return null;
591             } else if (mHistoryParcels == null
592                     || !mHistoryParcels.contains(mCurrentParcel)) {
593                 // current parcel is from history file.
594                 mCurrentParcel.recycle();
595             }
596         }
597 
598         // Try next available history file.
599         // skip the last file because its data is in history buffer.
600         while (mCurrentFileIndex < mFileNumbers.size() - 1) {
601             mCurrentParcel = null;
602             mCurrentParcelEnd = 0;
603             final Parcel p = Parcel.obtain();
604             AtomicFile file = getFile(mFileNumbers.get(mCurrentFileIndex++));
605             if (readFileToParcel(p, file)) {
606                 int bufSize = p.readInt();
607                 int curPos = p.dataPosition();
608                 mCurrentParcelEnd = curPos + bufSize;
609                 mCurrentParcel = p;
610                 if (curPos < mCurrentParcelEnd) {
611                     return mCurrentParcel;
612                 }
613             } else {
614                 p.recycle();
615             }
616         }
617 
618         // mHistoryParcels is created when BatteryStatsImpl object is created from deserialization
619         // of a parcel, such as Settings app or checkin file.
620         if (mHistoryParcels != null) {
621             while (mParcelIndex < mHistoryParcels.size()) {
622                 final Parcel p = mHistoryParcels.get(mParcelIndex++);
623                 if (!skipHead(p)) {
624                     continue;
625                 }
626                 final int bufSize = p.readInt();
627                 final int curPos = p.dataPosition();
628                 mCurrentParcelEnd = curPos + bufSize;
629                 mCurrentParcel = p;
630                 if (curPos < mCurrentParcelEnd) {
631                     return mCurrentParcel;
632                 }
633             }
634         }
635 
636         // finished iterator through history files (except the last one), now history buffer.
637         if (mHistoryBuffer.dataSize() <= 0) {
638             // buffer is empty.
639             return null;
640         }
641         mHistoryBuffer.setDataPosition(0);
642         mCurrentParcel = mHistoryBuffer;
643         mCurrentParcelEnd = mCurrentParcel.dataSize();
644         return mCurrentParcel;
645     }
646 
647     /**
648      * Read history file into a parcel.
649      *
650      * @param out  the Parcel read into.
651      * @param file the File to read from.
652      * @return true if success, false otherwise.
653      */
readFileToParcel(Parcel out, AtomicFile file)654     public boolean readFileToParcel(Parcel out, AtomicFile file) {
655         byte[] raw = null;
656         try {
657             final long start = SystemClock.uptimeMillis();
658             raw = file.readFully();
659             if (DEBUG) {
660                 Slog.d(TAG, "readFileToParcel:" + file.getBaseFile().getPath()
661                         + " duration ms:" + (SystemClock.uptimeMillis() - start));
662             }
663         } catch (Exception e) {
664             Slog.e(TAG, "Error reading file " + file.getBaseFile().getPath(), e);
665             return false;
666         }
667         out.unmarshall(raw, 0, raw.length);
668         out.setDataPosition(0);
669         return skipHead(out);
670     }
671 
672     /**
673      * Skip the header part of history parcel.
674      *
675      * @param p history parcel to skip head.
676      * @return true if version match, false if not.
677      */
skipHead(Parcel p)678     private boolean skipHead(Parcel p) {
679         p.setDataPosition(0);
680         final int version = p.readInt();
681         if (version != VERSION) {
682             return false;
683         }
684         // skip historyBaseTime field.
685         p.readLong();
686         return true;
687     }
688 
689     /**
690      * Writes the battery history contents for persistence.
691      */
writeSummaryToParcel(Parcel out, boolean inclHistory)692     public void writeSummaryToParcel(Parcel out, boolean inclHistory) {
693         out.writeBoolean(inclHistory);
694         if (inclHistory) {
695             writeToParcel(out);
696         }
697 
698         out.writeInt(mHistoryTagPool.size());
699         for (Map.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) {
700             HistoryTag tag = ent.getKey();
701             out.writeInt(ent.getValue());
702             out.writeString(tag.string);
703             out.writeInt(tag.uid);
704         }
705     }
706 
707     /**
708      * Reads battery history contents from a persisted parcel.
709      */
readSummaryFromParcel(Parcel in)710     public void readSummaryFromParcel(Parcel in) {
711         boolean inclHistory = in.readBoolean();
712         if (inclHistory) {
713             readFromParcel(in);
714         }
715 
716         mHistoryTagPool.clear();
717         mNextHistoryTagIdx = 0;
718         mNumHistoryTagChars = 0;
719 
720         int numTags = in.readInt();
721         for (int i = 0; i < numTags; i++) {
722             int idx = in.readInt();
723             String str = in.readString();
724             int uid = in.readInt();
725             HistoryTag tag = new HistoryTag();
726             tag.string = str;
727             tag.uid = uid;
728             tag.poolIdx = idx;
729             mHistoryTagPool.put(tag, idx);
730             if (idx >= mNextHistoryTagIdx) {
731                 mNextHistoryTagIdx = idx + 1;
732             }
733             mNumHistoryTagChars += tag.string.length() + 1;
734         }
735     }
736 
737     /**
738      * Read all history files and serialize into a big Parcel.
739      * Checkin file calls this method.
740      *
741      * @param out the output parcel
742      */
writeToParcel(Parcel out)743     public void writeToParcel(Parcel out) {
744         writeHistoryBuffer(out);
745         writeToParcel(out, false /* useBlobs */);
746     }
747 
748     /**
749      * This is for Settings app, when Settings app receives big history parcel, it call
750      * this method to parse it into list of parcels.
751      *
752      * @param out the output parcel
753      */
writeToBatteryUsageStatsParcel(Parcel out)754     public void writeToBatteryUsageStatsParcel(Parcel out) {
755         out.writeBlob(mHistoryBuffer.marshall());
756         writeToParcel(out, true /* useBlobs */);
757     }
758 
writeToParcel(Parcel out, boolean useBlobs)759     private void writeToParcel(Parcel out, boolean useBlobs) {
760         final long start = SystemClock.uptimeMillis();
761         out.writeInt(mFileNumbers.size() - 1);
762         for (int i = 0; i < mFileNumbers.size() - 1; i++) {
763             AtomicFile file = getFile(mFileNumbers.get(i));
764             byte[] raw = new byte[0];
765             try {
766                 raw = file.readFully();
767             } catch (Exception e) {
768                 Slog.e(TAG, "Error reading file " + file.getBaseFile().getPath(), e);
769             }
770             if (useBlobs) {
771                 out.writeBlob(raw);
772             } else {
773                 // Avoiding blobs in the check-in file for compatibility
774                 out.writeByteArray(raw);
775             }
776         }
777         if (DEBUG) {
778             Slog.d(TAG, "writeToParcel duration ms:" + (SystemClock.uptimeMillis() - start));
779         }
780     }
781 
782     /**
783      * Reads a BatteryStatsHistory from a parcel written with
784      * the {@link #writeToBatteryUsageStatsParcel} method.
785      */
createFromBatteryUsageStatsParcel(Parcel in)786     public static BatteryStatsHistory createFromBatteryUsageStatsParcel(Parcel in) {
787         return new BatteryStatsHistory(in);
788     }
789 
790     /**
791      * Read history from a check-in file.
792      */
readSummary()793     public boolean readSummary() {
794         if (mActiveFile == null) {
795             Slog.w(TAG, "readSummary: no history file associated with this instance");
796             return false;
797         }
798 
799         Parcel parcel = Parcel.obtain();
800         try {
801             final long start = SystemClock.uptimeMillis();
802             if (mActiveFile.exists()) {
803                 byte[] raw = mActiveFile.readFully();
804                 if (raw.length > 0) {
805                     parcel.unmarshall(raw, 0, raw.length);
806                     parcel.setDataPosition(0);
807                     readHistoryBuffer(parcel);
808                 }
809                 if (DEBUG) {
810                     Slog.d(TAG, "read history file::"
811                             + mActiveFile.getBaseFile().getPath()
812                             + " bytes:" + raw.length + " took ms:" + (SystemClock.uptimeMillis()
813                             - start));
814                 }
815             }
816         } catch (Exception e) {
817             Slog.e(TAG, "Error reading battery history", e);
818             reset();
819             return false;
820         } finally {
821             parcel.recycle();
822         }
823         return true;
824     }
825 
826     /**
827      * This is for the check-in file, which has all history files embedded.
828      *
829      * @param in the input parcel.
830      */
readFromParcel(Parcel in)831     public void readFromParcel(Parcel in) {
832         readHistoryBuffer(in);
833         readFromParcel(in, false /* useBlobs */);
834     }
835 
readFromParcel(Parcel in, boolean useBlobs)836     private void readFromParcel(Parcel in, boolean useBlobs) {
837         final long start = SystemClock.uptimeMillis();
838         mHistoryParcels = new ArrayList<>();
839         final int count = in.readInt();
840         for (int i = 0; i < count; i++) {
841             byte[] temp = useBlobs ? in.readBlob() : in.createByteArray();
842             if (temp == null || temp.length == 0) {
843                 continue;
844             }
845             Parcel p = Parcel.obtain();
846             p.unmarshall(temp, 0, temp.length);
847             p.setDataPosition(0);
848             mHistoryParcels.add(p);
849         }
850         if (DEBUG) {
851             Slog.d(TAG, "readFromParcel duration ms:" + (SystemClock.uptimeMillis() - start));
852         }
853     }
854 
855     /**
856      * @return true if there is more than 100MB free disk space left.
857      */
hasFreeDiskSpace()858     private boolean hasFreeDiskSpace() {
859         final StatFs stats = new StatFs(mHistoryDir.getAbsolutePath());
860         return stats.getAvailableBytes() > MIN_FREE_SPACE;
861     }
862 
863     @VisibleForTesting
getFilesNumbers()864     public List<Integer> getFilesNumbers() {
865         return mFileNumbers;
866     }
867 
868     @VisibleForTesting
getActiveFile()869     public AtomicFile getActiveFile() {
870         return mActiveFile;
871     }
872 
873     /**
874      * @return the total size of all history files and history buffer.
875      */
getHistoryUsedSize()876     public int getHistoryUsedSize() {
877         int ret = 0;
878         for (int i = 0; i < mFileNumbers.size() - 1; i++) {
879             ret += getFile(mFileNumbers.get(i)).getBaseFile().length();
880         }
881         ret += mHistoryBuffer.dataSize();
882         if (mHistoryParcels != null) {
883             for (int i = 0; i < mHistoryParcels.size(); i++) {
884                 ret += mHistoryParcels.get(i).dataSize();
885             }
886         }
887         return ret;
888     }
889 
890     /**
891      * Enables/disables recording of history.  When disabled, all "record*" calls are a no-op.
892      */
setHistoryRecordingEnabled(boolean enabled)893     public void setHistoryRecordingEnabled(boolean enabled) {
894         mRecordingHistory = enabled;
895     }
896 
897     /**
898      * Returns true if history recording is enabled.
899      */
isRecordingHistory()900     public boolean isRecordingHistory() {
901         return mRecordingHistory;
902     }
903 
904     /**
905      * Forces history recording regardless of charging state.
906      */
907     @VisibleForTesting
forceRecordAllHistory()908     public void forceRecordAllHistory() {
909         mHaveBatteryLevel = true;
910         mRecordingHistory = true;
911     }
912 
913     /**
914      * Starts a history buffer by recording the current wall-clock time.
915      */
startRecordingHistory(final long elapsedRealtimeMs, final long uptimeMs, boolean reset)916     public void startRecordingHistory(final long elapsedRealtimeMs, final long uptimeMs,
917             boolean reset) {
918         mRecordingHistory = true;
919         mHistoryCur.currentTime = mClock.currentTimeMillis();
920         writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
921                 reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME);
922         mHistoryCur.currentTime = 0;
923     }
924 
925     /**
926      * Prepares to continue recording after restoring previous history from persistent storage.
927      */
continueRecordingHistory()928     public void continueRecordingHistory() {
929         if (mHistoryBuffer.dataPosition() <= 0 && mFileNumbers.size() <= 1) {
930             return;
931         }
932 
933         mRecordingHistory = true;
934         final long elapsedRealtimeMs = mClock.elapsedRealtime();
935         final long uptimeMs = mClock.uptimeMillis();
936         writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_START);
937         startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
938     }
939 
940     /**
941      * Notes the current battery state to be reflected in the next written history item.
942      */
setBatteryState(boolean charging, int status, int level, int chargeUah)943     public void setBatteryState(boolean charging, int status, int level, int chargeUah) {
944         mHaveBatteryLevel = true;
945         setChargingState(charging);
946         mHistoryCur.batteryStatus = (byte) status;
947         mHistoryCur.batteryLevel = (byte) level;
948         mHistoryCur.batteryChargeUah = chargeUah;
949     }
950 
951     /**
952      * Notes the current battery state to be reflected in the next written history item.
953      */
setBatteryState(int status, int level, int health, int plugType, int temperature, int voltageMv, int chargeUah)954     public void setBatteryState(int status, int level, int health, int plugType, int temperature,
955             int voltageMv, int chargeUah) {
956         mHaveBatteryLevel = true;
957         mHistoryCur.batteryStatus = (byte) status;
958         mHistoryCur.batteryLevel = (byte) level;
959         mHistoryCur.batteryHealth = (byte) health;
960         mHistoryCur.batteryPlugType = (byte) plugType;
961         mHistoryCur.batteryTemperature = (short) temperature;
962         mHistoryCur.batteryVoltage = (char) voltageMv;
963         mHistoryCur.batteryChargeUah = chargeUah;
964     }
965 
966     /**
967      * Notes the current power plugged-in state to be reflected in the next written history item.
968      */
setPluggedInState(boolean pluggedIn)969     public void setPluggedInState(boolean pluggedIn) {
970         if (pluggedIn) {
971             mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
972         } else {
973             mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
974         }
975     }
976 
977     /**
978      * Notes the current battery charging state to be reflected in the next written history item.
979      */
setChargingState(boolean charging)980     public void setChargingState(boolean charging) {
981         if (charging) {
982             mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
983         } else {
984             mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG;
985         }
986     }
987 
988     /**
989      * Records a history event with the given code, name and UID.
990      */
recordEvent(long elapsedRealtimeMs, long uptimeMs, int code, String name, int uid)991     public void recordEvent(long elapsedRealtimeMs, long uptimeMs, int code, String name,
992             int uid) {
993         mHistoryCur.eventCode = code;
994         mHistoryCur.eventTag = mHistoryCur.localEventTag;
995         mHistoryCur.eventTag.string = name;
996         mHistoryCur.eventTag.uid = uid;
997         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
998     }
999 
1000     /**
1001      * Records a time change event.
1002      */
recordCurrentTimeChange(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs)1003     public void recordCurrentTimeChange(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) {
1004         if (!mRecordingHistory) {
1005             return;
1006         }
1007 
1008         mHistoryCur.currentTime = currentTimeMs;
1009         writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
1010                 HistoryItem.CMD_CURRENT_TIME);
1011         mHistoryCur.currentTime = 0;
1012     }
1013 
1014     /**
1015      * Records a system shutdown event.
1016      */
recordShutdownEvent(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs)1017     public void recordShutdownEvent(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) {
1018         if (!mRecordingHistory) {
1019             return;
1020         }
1021 
1022         mHistoryCur.currentTime = currentTimeMs;
1023         writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_SHUTDOWN);
1024         mHistoryCur.currentTime = 0;
1025     }
1026 
1027     /**
1028      * Records a battery state change event.
1029      */
recordBatteryState(long elapsedRealtimeMs, long uptimeMs, int batteryLevel, boolean isPlugged)1030     public void recordBatteryState(long elapsedRealtimeMs, long uptimeMs, int batteryLevel,
1031             boolean isPlugged) {
1032         mHistoryCur.batteryLevel = (byte) batteryLevel;
1033         setPluggedInState(isPlugged);
1034         if (DEBUG) {
1035             Slog.v(TAG, "Battery unplugged to: "
1036                     + Integer.toHexString(mHistoryCur.states));
1037         }
1038         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1039     }
1040 
1041     /**
1042      * Records measured energy data.
1043      */
recordEnergyConsumerDetails(long elapsedRealtimeMs, long uptimeMs, EnergyConsumerDetails energyConsumerDetails)1044     public void recordEnergyConsumerDetails(long elapsedRealtimeMs, long uptimeMs,
1045             EnergyConsumerDetails energyConsumerDetails) {
1046         mHistoryCur.energyConsumerDetails = energyConsumerDetails;
1047         mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
1048         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1049     }
1050 
1051     /**
1052      * Records a history item with the amount of charge consumed by WiFi.  Used on certain devices
1053      * equipped with on-device power metering.
1054      */
recordWifiConsumedCharge(long elapsedRealtimeMs, long uptimeMs, double monitoredRailChargeMah)1055     public void recordWifiConsumedCharge(long elapsedRealtimeMs, long uptimeMs,
1056             double monitoredRailChargeMah) {
1057         mHistoryCur.wifiRailChargeMah += monitoredRailChargeMah;
1058         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1059     }
1060 
1061     /**
1062      * Records a wakelock start event.
1063      */
recordWakelockStartEvent(long elapsedRealtimeMs, long uptimeMs, String historyName, int uid)1064     public void recordWakelockStartEvent(long elapsedRealtimeMs, long uptimeMs, String historyName,
1065             int uid) {
1066         mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
1067         mHistoryCur.wakelockTag.string = historyName;
1068         mHistoryCur.wakelockTag.uid = uid;
1069         recordStateStartEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
1070     }
1071 
1072     /**
1073      * Updates the previous history event with a wakelock name and UID.
1074      */
maybeUpdateWakelockTag(long elapsedRealtimeMs, long uptimeMs, String historyName, int uid)1075     public boolean maybeUpdateWakelockTag(long elapsedRealtimeMs, long uptimeMs, String historyName,
1076             int uid) {
1077         if (mHistoryLastWritten.cmd != HistoryItem.CMD_UPDATE) {
1078             return false;
1079         }
1080         if (mHistoryLastWritten.wakelockTag != null) {
1081             // We'll try to update the last tag.
1082             mHistoryLastWritten.wakelockTag = null;
1083             mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
1084             mHistoryCur.wakelockTag.string = historyName;
1085             mHistoryCur.wakelockTag.uid = uid;
1086             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1087         }
1088         return true;
1089     }
1090 
1091     /**
1092      * Records a wakelock release event.
1093      */
recordWakelockStopEvent(long elapsedRealtimeMs, long uptimeMs, String historyName, int uid)1094     public void recordWakelockStopEvent(long elapsedRealtimeMs, long uptimeMs, String historyName,
1095             int uid) {
1096         mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
1097         mHistoryCur.wakelockTag.string = historyName != null ? historyName : "";
1098         mHistoryCur.wakelockTag.uid = uid;
1099         recordStateStopEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
1100     }
1101 
1102     /**
1103      * Records an event when some state flag changes to true.
1104      */
recordStateStartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags)1105     public void recordStateStartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
1106         mHistoryCur.states |= stateFlags;
1107         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1108     }
1109 
1110     /**
1111      * Records an event when some state flag changes to false.
1112      */
recordStateStopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags)1113     public void recordStateStopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
1114         mHistoryCur.states &= ~stateFlags;
1115         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1116     }
1117 
1118     /**
1119      * Records an event when some state flags change to true and some to false.
1120      */
recordStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int stateStartFlags, int stateStopFlags)1121     public void recordStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int stateStartFlags,
1122             int stateStopFlags) {
1123         mHistoryCur.states = (mHistoryCur.states | stateStartFlags) & ~stateStopFlags;
1124         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1125     }
1126 
1127     /**
1128      * Records an event when some state2 flag changes to true.
1129      */
recordState2StartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags)1130     public void recordState2StartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
1131         mHistoryCur.states2 |= stateFlags;
1132         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1133     }
1134 
1135     /**
1136      * Records an event when some state2 flag changes to false.
1137      */
recordState2StopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags)1138     public void recordState2StopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
1139         mHistoryCur.states2 &= ~stateFlags;
1140         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1141     }
1142 
1143     /**
1144      * Records an wakeup event.
1145      */
recordWakeupEvent(long elapsedRealtimeMs, long uptimeMs, String reason)1146     public void recordWakeupEvent(long elapsedRealtimeMs, long uptimeMs, String reason) {
1147         mHistoryCur.wakeReasonTag = mHistoryCur.localWakeReasonTag;
1148         mHistoryCur.wakeReasonTag.string = reason;
1149         mHistoryCur.wakeReasonTag.uid = 0;
1150         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1151     }
1152 
1153     /**
1154      * Records a screen brightness change event.
1155      */
recordScreenBrightnessEvent(long elapsedRealtimeMs, long uptimeMs, int brightnessBin)1156     public void recordScreenBrightnessEvent(long elapsedRealtimeMs, long uptimeMs,
1157             int brightnessBin) {
1158         mHistoryCur.states = setBitField(mHistoryCur.states, brightnessBin,
1159                 HistoryItem.STATE_BRIGHTNESS_SHIFT,
1160                 HistoryItem.STATE_BRIGHTNESS_MASK);
1161         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1162     }
1163 
1164     /**
1165      * Records a GNSS signal level change event.
1166      */
recordGpsSignalQualityEvent(long elapsedRealtimeMs, long uptimeMs, int signalLevel)1167     public void recordGpsSignalQualityEvent(long elapsedRealtimeMs, long uptimeMs,
1168             int signalLevel) {
1169         mHistoryCur.states2 = setBitField(mHistoryCur.states2, signalLevel,
1170                 HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT,
1171                 HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK);
1172         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1173     }
1174 
1175     /**
1176      * Records a device idle mode change event.
1177      */
recordDeviceIdleEvent(long elapsedRealtimeMs, long uptimeMs, int mode)1178     public void recordDeviceIdleEvent(long elapsedRealtimeMs, long uptimeMs, int mode) {
1179         mHistoryCur.states2 = setBitField(mHistoryCur.states2, mode,
1180                 HistoryItem.STATE2_DEVICE_IDLE_SHIFT,
1181                 HistoryItem.STATE2_DEVICE_IDLE_MASK);
1182         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1183     }
1184 
1185     /**
1186      * Records a telephony state change event.
1187      */
recordPhoneStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int addStateFlag, int removeStateFlag, int state, int signalStrength)1188     public void recordPhoneStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int addStateFlag,
1189             int removeStateFlag, int state, int signalStrength) {
1190         mHistoryCur.states = (mHistoryCur.states | addStateFlag) & ~removeStateFlag;
1191         if (state != -1) {
1192             mHistoryCur.states =
1193                     setBitField(mHistoryCur.states, state,
1194                             HistoryItem.STATE_PHONE_STATE_SHIFT,
1195                             HistoryItem.STATE_PHONE_STATE_MASK);
1196         }
1197         if (signalStrength != -1) {
1198             mHistoryCur.states =
1199                     setBitField(mHistoryCur.states, signalStrength,
1200                             HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT,
1201                             HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK);
1202         }
1203         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1204     }
1205 
1206     /**
1207      * Records a data connection type change event.
1208      */
recordDataConnectionTypeChangeEvent(long elapsedRealtimeMs, long uptimeMs, int dataConnectionType)1209     public void recordDataConnectionTypeChangeEvent(long elapsedRealtimeMs, long uptimeMs,
1210             int dataConnectionType) {
1211         mHistoryCur.states = setBitField(mHistoryCur.states, dataConnectionType,
1212                 HistoryItem.STATE_DATA_CONNECTION_SHIFT,
1213                 HistoryItem.STATE_DATA_CONNECTION_MASK);
1214         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1215     }
1216 
1217     /**
1218      * Records a WiFi supplicant state change event.
1219      */
recordWifiSupplicantStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int supplState)1220     public void recordWifiSupplicantStateChangeEvent(long elapsedRealtimeMs, long uptimeMs,
1221             int supplState) {
1222         mHistoryCur.states2 =
1223                 setBitField(mHistoryCur.states2, supplState,
1224                         HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT,
1225                         HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK);
1226         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1227     }
1228 
1229     /**
1230      * Records a WiFi signal strength change event.
1231      */
recordWifiSignalStrengthChangeEvent(long elapsedRealtimeMs, long uptimeMs, int strengthBin)1232     public void recordWifiSignalStrengthChangeEvent(long elapsedRealtimeMs, long uptimeMs,
1233             int strengthBin) {
1234         mHistoryCur.states2 =
1235                 setBitField(mHistoryCur.states2, strengthBin,
1236                         HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT,
1237                         HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK);
1238         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1239     }
1240 
1241     /**
1242      * Writes event details into Atrace.
1243      */
recordTraceEvents(int code, HistoryTag tag)1244     private void recordTraceEvents(int code, HistoryTag tag) {
1245         if (code == HistoryItem.EVENT_NONE) return;
1246 
1247         final int idx = code & HistoryItem.EVENT_TYPE_MASK;
1248         final String prefix = (code & HistoryItem.EVENT_FLAG_START) != 0 ? "+" :
1249                 (code & HistoryItem.EVENT_FLAG_FINISH) != 0 ? "-" : "";
1250 
1251         final String[] names = BatteryStats.HISTORY_EVENT_NAMES;
1252         if (idx < 0 || idx >= names.length) return;
1253 
1254         final String track = "battery_stats." + names[idx];
1255         final String name = prefix + names[idx] + "=" + tag.uid + ":\"" + tag.string + "\"";
1256         mTracer.traceInstantEvent(track, name);
1257     }
1258 
1259     /**
1260      * Records CPU usage by a specific UID.  The recorded data is the delta from
1261      * the previous record for the same UID.
1262      */
recordCpuUsage(long elapsedRealtimeMs, long uptimeMs, CpuUsageDetails cpuUsageDetails)1263     public void recordCpuUsage(long elapsedRealtimeMs, long uptimeMs,
1264             CpuUsageDetails cpuUsageDetails) {
1265         mHistoryCur.cpuUsageDetails = cpuUsageDetails;
1266         mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
1267         writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1268     }
1269 
1270     /**
1271      * Writes changes to a HistoryItem state bitmap to Atrace.
1272      */
recordTraceCounters(int oldval, int newval, BitDescription[] descriptions)1273     private void recordTraceCounters(int oldval, int newval, BitDescription[] descriptions) {
1274         int diff = oldval ^ newval;
1275         if (diff == 0) return;
1276 
1277         for (int i = 0; i < descriptions.length; i++) {
1278             BitDescription bd = descriptions[i];
1279             if ((diff & bd.mask) == 0) continue;
1280 
1281             int value;
1282             if (bd.shift < 0) {
1283                 value = (newval & bd.mask) != 0 ? 1 : 0;
1284             } else {
1285                 value = (newval & bd.mask) >> bd.shift;
1286             }
1287 
1288             mTracer.traceCounter("battery_stats." + bd.name, value);
1289         }
1290     }
1291 
setBitField(int bits, int value, int shift, int mask)1292     private int setBitField(int bits, int value, int shift, int mask) {
1293         int shiftedValue = value << shift;
1294         if ((shiftedValue & ~mask) != 0) {
1295             Slog.wtfStack(TAG, "Value " + Integer.toHexString(value)
1296                     + " does not fit in the bit field: " + Integer.toHexString(mask));
1297             shiftedValue &= mask;
1298         }
1299         return (bits & ~mask) | shiftedValue;
1300     }
1301 
1302     /**
1303      * Writes the current history item to history.
1304      */
writeHistoryItem(long elapsedRealtimeMs, long uptimeMs)1305     public void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs) {
1306         if (mTrackRunningHistoryElapsedRealtimeMs != 0) {
1307             final long diffElapsedMs = elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtimeMs;
1308             final long diffUptimeMs = uptimeMs - mTrackRunningHistoryUptimeMs;
1309             if (diffUptimeMs < (diffElapsedMs - 20)) {
1310                 final long wakeElapsedTimeMs = elapsedRealtimeMs - (diffElapsedMs - diffUptimeMs);
1311                 mHistoryAddTmp.setTo(mHistoryLastWritten);
1312                 mHistoryAddTmp.wakelockTag = null;
1313                 mHistoryAddTmp.wakeReasonTag = null;
1314                 mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE;
1315                 mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG;
1316                 writeHistoryItem(wakeElapsedTimeMs, uptimeMs, mHistoryAddTmp);
1317             }
1318         }
1319         mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG;
1320         mTrackRunningHistoryElapsedRealtimeMs = elapsedRealtimeMs;
1321         mTrackRunningHistoryUptimeMs = uptimeMs;
1322         writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur);
1323     }
1324 
writeHistoryItem(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur)1325     private void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
1326         if (mTracer != null && mTracer.tracingEnabled()) {
1327             recordTraceEvents(cur.eventCode, cur.eventTag);
1328             recordTraceCounters(mTraceLastState, cur.states,
1329                     BatteryStats.HISTORY_STATE_DESCRIPTIONS);
1330             recordTraceCounters(mTraceLastState2, cur.states2,
1331                     BatteryStats.HISTORY_STATE2_DESCRIPTIONS);
1332             mTraceLastState = cur.states;
1333             mTraceLastState2 = cur.states2;
1334         }
1335 
1336         if (!mHaveBatteryLevel || !mRecordingHistory) {
1337             return;
1338         }
1339 
1340         if (!mMutable) {
1341             throw new ConcurrentModificationException("Battery history is not writable");
1342         }
1343 
1344         final long timeDiffMs = (mHistoryBaseTimeMs + elapsedRealtimeMs) - mHistoryLastWritten.time;
1345         final int diffStates = mHistoryLastWritten.states ^ cur.states;
1346         final int diffStates2 = mHistoryLastWritten.states2 ^ cur.states2;
1347         final int lastDiffStates = mHistoryLastWritten.states ^ mHistoryLastLastWritten.states;
1348         final int lastDiffStates2 = mHistoryLastWritten.states2 ^ mHistoryLastLastWritten.states2;
1349         if (DEBUG) {
1350             Slog.i(TAG, "ADD: tdelta=" + timeDiffMs + " diff="
1351                     + Integer.toHexString(diffStates) + " lastDiff="
1352                     + Integer.toHexString(lastDiffStates) + " diff2="
1353                     + Integer.toHexString(diffStates2) + " lastDiff2="
1354                     + Integer.toHexString(lastDiffStates2));
1355         }
1356 
1357         if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
1358                 && timeDiffMs < 1000 && (diffStates & lastDiffStates) == 0
1359                 && (diffStates2 & lastDiffStates2) == 0
1360                 && (!mHistoryLastWritten.tagsFirstOccurrence && !cur.tagsFirstOccurrence)
1361                 && (mHistoryLastWritten.wakelockTag == null || cur.wakelockTag == null)
1362                 && (mHistoryLastWritten.wakeReasonTag == null || cur.wakeReasonTag == null)
1363                 && mHistoryLastWritten.stepDetails == null
1364                 && (mHistoryLastWritten.eventCode == HistoryItem.EVENT_NONE
1365                 || cur.eventCode == HistoryItem.EVENT_NONE)
1366                 && mHistoryLastWritten.batteryLevel == cur.batteryLevel
1367                 && mHistoryLastWritten.batteryStatus == cur.batteryStatus
1368                 && mHistoryLastWritten.batteryHealth == cur.batteryHealth
1369                 && mHistoryLastWritten.batteryPlugType == cur.batteryPlugType
1370                 && mHistoryLastWritten.batteryTemperature == cur.batteryTemperature
1371                 && mHistoryLastWritten.batteryVoltage == cur.batteryVoltage
1372                 && mHistoryLastWritten.energyConsumerDetails == null
1373                 && mHistoryLastWritten.cpuUsageDetails == null) {
1374             // We can merge this new change in with the last one.  Merging is
1375             // allowed as long as only the states have changed, and within those states
1376             // as long as no bit has changed both between now and the last entry, as
1377             // well as the last entry and the one before it (so we capture any toggles).
1378             if (DEBUG) Slog.i(TAG, "ADD: rewinding back to " + mHistoryBufferLastPos);
1379             mHistoryBuffer.setDataSize(mHistoryBufferLastPos);
1380             mHistoryBuffer.setDataPosition(mHistoryBufferLastPos);
1381             mHistoryBufferLastPos = -1;
1382             elapsedRealtimeMs = mHistoryLastWritten.time - mHistoryBaseTimeMs;
1383             // If the last written history had a wakelock tag, we need to retain it.
1384             // Note that the condition above made sure that we aren't in a case where
1385             // both it and the current history item have a wakelock tag.
1386             if (mHistoryLastWritten.wakelockTag != null) {
1387                 cur.wakelockTag = cur.localWakelockTag;
1388                 cur.wakelockTag.setTo(mHistoryLastWritten.wakelockTag);
1389             }
1390             // If the last written history had a wake reason tag, we need to retain it.
1391             // Note that the condition above made sure that we aren't in a case where
1392             // both it and the current history item have a wakelock tag.
1393             if (mHistoryLastWritten.wakeReasonTag != null) {
1394                 cur.wakeReasonTag = cur.localWakeReasonTag;
1395                 cur.wakeReasonTag.setTo(mHistoryLastWritten.wakeReasonTag);
1396             }
1397             // If the last written history had an event, we need to retain it.
1398             // Note that the condition above made sure that we aren't in a case where
1399             // both it and the current history item have an event.
1400             if (mHistoryLastWritten.eventCode != HistoryItem.EVENT_NONE) {
1401                 cur.eventCode = mHistoryLastWritten.eventCode;
1402                 cur.eventTag = cur.localEventTag;
1403                 cur.eventTag.setTo(mHistoryLastWritten.eventTag);
1404             }
1405             mHistoryLastWritten.setTo(mHistoryLastLastWritten);
1406         }
1407         final int dataSize = mHistoryBuffer.dataSize();
1408 
1409         if (dataSize >= mMaxHistoryBufferSize) {
1410             if (mMaxHistoryBufferSize == 0) {
1411                 Slog.wtf(TAG, "mMaxHistoryBufferSize should not be zero when writing history");
1412                 mMaxHistoryBufferSize = 1024;
1413             }
1414 
1415             //open a new history file.
1416             final long start = SystemClock.uptimeMillis();
1417             writeHistory();
1418             if (DEBUG) {
1419                 Slog.d(TAG, "addHistoryBufferLocked writeHistory took ms:"
1420                         + (SystemClock.uptimeMillis() - start));
1421             }
1422             startNextFile();
1423             mHistoryBuffer.setDataSize(0);
1424             mHistoryBuffer.setDataPosition(0);
1425             mHistoryBuffer.setDataCapacity(mMaxHistoryBufferSize / 2);
1426             mHistoryBufferLastPos = -1;
1427             mHistoryLastWritten.clear();
1428             mHistoryLastLastWritten.clear();
1429 
1430             // Mark every entry in the pool with a flag indicating that the tag
1431             // has not yet been encountered while writing the current history buffer.
1432             for (Map.Entry<HistoryTag, Integer> entry : mHistoryTagPool.entrySet()) {
1433                 entry.setValue(entry.getValue() | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG);
1434             }
1435             mMeasuredEnergyHeaderWritten = false;
1436             mCpuUsageHeaderWritten = false;
1437 
1438             // Make a copy of mHistoryCur.
1439             HistoryItem copy = new HistoryItem();
1440             copy.setTo(cur);
1441             // startRecordingHistory will reset mHistoryCur.
1442             startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
1443             // Add the copy into history buffer.
1444             writeHistoryItem(elapsedRealtimeMs, uptimeMs, copy, HistoryItem.CMD_UPDATE);
1445             return;
1446         }
1447 
1448         if (dataSize == 0) {
1449             // The history is currently empty; we need it to start with a time stamp.
1450             HistoryItem copy = new HistoryItem();
1451             copy.setTo(cur);
1452             copy.currentTime = mClock.currentTimeMillis();
1453             copy.wakelockTag = null;
1454             copy.wakeReasonTag = null;
1455             copy.eventCode = HistoryItem.EVENT_NONE;
1456             copy.eventTag = null;
1457             copy.tagsFirstOccurrence = false;
1458             copy.energyConsumerDetails = null;
1459             copy.cpuUsageDetails = null;
1460             writeHistoryItem(elapsedRealtimeMs, uptimeMs, copy, HistoryItem.CMD_RESET);
1461         }
1462         writeHistoryItem(elapsedRealtimeMs, uptimeMs, cur, HistoryItem.CMD_UPDATE);
1463     }
1464 
writeHistoryItem(long elapsedRealtimeMs, @SuppressWarnings(R) long uptimeMs, HistoryItem cur, byte cmd)1465     private void writeHistoryItem(long elapsedRealtimeMs,
1466             @SuppressWarnings("UnusedVariable") long uptimeMs, HistoryItem cur, byte cmd) {
1467         if (!mMutable) {
1468             throw new ConcurrentModificationException("Battery history is not writable");
1469         }
1470         mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
1471         mHistoryLastLastWritten.setTo(mHistoryLastWritten);
1472         final boolean hasTags = mHistoryLastWritten.tagsFirstOccurrence || cur.tagsFirstOccurrence;
1473         mHistoryLastWritten.setTo(mHistoryBaseTimeMs + elapsedRealtimeMs, cmd, cur);
1474         if (mHistoryLastWritten.time < mHistoryLastLastWritten.time - 60000) {
1475             Slog.wtf(TAG, "Significantly earlier event written to battery history:"
1476                     + " time=" + mHistoryLastWritten.time
1477                     + " previous=" + mHistoryLastLastWritten.time);
1478         }
1479         mHistoryLastWritten.tagsFirstOccurrence = hasTags;
1480         writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);
1481         mLastHistoryElapsedRealtimeMs = elapsedRealtimeMs;
1482         cur.wakelockTag = null;
1483         cur.wakeReasonTag = null;
1484         cur.eventCode = HistoryItem.EVENT_NONE;
1485         cur.eventTag = null;
1486         cur.tagsFirstOccurrence = false;
1487         cur.energyConsumerDetails = null;
1488         cur.cpuUsageDetails = null;
1489         if (DEBUG) {
1490             Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
1491                     + " now " + mHistoryBuffer.dataPosition()
1492                     + " size is now " + mHistoryBuffer.dataSize());
1493         }
1494     }
1495 
1496     /*
1497         The history delta format uses flags to denote further data in subsequent ints in the parcel.
1498 
1499         There is always the first token, which may contain the delta time, or an indicator of
1500         the length of the time (int or long) following this token.
1501 
1502         First token: always present,
1503         31              23              15               7             0
1504         █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█
1505 
1506         T: the delta time if it is <= 0x7fffd. Otherwise 0x7fffe indicates an int immediately
1507            follows containing the time, and 0x7ffff indicates a long immediately follows with the
1508            delta time.
1509         A: battery level changed and an int follows with battery data.
1510         B: state changed and an int follows with state change data.
1511         C: state2 has changed and an int follows with state2 change data.
1512         D: wakelock/wakereason has changed and an wakelock/wakereason struct follows.
1513         E: event data has changed and an event struct follows.
1514         F: battery charge in coulombs has changed and an int with the charge follows.
1515         G: state flag denoting that the mobile radio was active.
1516         H: state flag denoting that the wifi radio was active.
1517         I: state flag denoting that a wifi scan occurred.
1518         J: state flag denoting that a wifi full lock was held.
1519         K: state flag denoting that the gps was on.
1520         L: state flag denoting that a wakelock was held.
1521         M: state flag denoting that the cpu was running.
1522 
1523         Time int/long: if T in the first token is 0x7ffff or 0x7fffe, then an int or long follows
1524         with the time delta.
1525 
1526         Battery level int: if A in the first token is set,
1527         31              23              15               7             0
1528         █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█
1529 
1530         D: indicates that extra history details follow.
1531         V: the battery voltage.
1532         T: the battery temperature.
1533         L: the battery level (out of 100).
1534 
1535         State change int: if B in the first token is set,
1536         31              23              15               7             0
1537         █S|S|S|H|H|H|P|P█F|E|D|C|B| | |A█ | | | | | | | █ | | | | | | | █
1538 
1539         A: wifi multicast was on.
1540         B: battery was plugged in.
1541         C: screen was on.
1542         D: phone was scanning for signal.
1543         E: audio was on.
1544         F: a sensor was active.
1545 
1546         State2 change int: if C in the first token is set,
1547         31              23              15               7             0
1548         █M|L|K|J|I|H|H|G█F|E|D|C| | | | █ | | | | | | | █ |B|B|B|A|A|A|A█
1549 
1550         A: 4 bits indicating the wifi supplicant state: {@link BatteryStats#WIFI_SUPPL_STATE_NAMES}.
1551         B: 3 bits indicating the wifi signal strength: 0, 1, 2, 3, 4.
1552         C: a bluetooth scan was active.
1553         D: the camera was active.
1554         E: bluetooth was on.
1555         F: a phone call was active.
1556         G: the device was charging.
1557         H: 2 bits indicating the device-idle (doze) state: off, light, full
1558         I: the flashlight was on.
1559         J: wifi was on.
1560         K: wifi was running.
1561         L: video was playing.
1562         M: power save mode was on.
1563 
1564         Wakelock/wakereason struct: if D in the first token is set,
1565         Event struct: if E in the first token is set,
1566         History step details struct: if D in the battery level int is set,
1567 
1568         Battery charge int: if F in the first token is set, an int representing the battery charge
1569         in coulombs follows.
1570      */
1571     /**
1572      * Writes the delta between the previous and current history items into history buffer.
1573      */
writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last)1574     public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
1575         if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
1576             dest.writeInt(BatteryStatsHistory.DELTA_TIME_ABS);
1577             cur.writeToParcel(dest, 0);
1578             return;
1579         }
1580 
1581         int extensionFlags = 0;
1582         final long deltaTime = cur.time - last.time;
1583         final int lastBatteryLevelInt = buildBatteryLevelInt(last);
1584         final int lastStateInt = buildStateInt(last);
1585 
1586         int deltaTimeToken;
1587         if (deltaTime < 0 || deltaTime > Integer.MAX_VALUE) {
1588             deltaTimeToken = BatteryStatsHistory.DELTA_TIME_LONG;
1589         } else if (deltaTime >= BatteryStatsHistory.DELTA_TIME_ABS) {
1590             deltaTimeToken = BatteryStatsHistory.DELTA_TIME_INT;
1591         } else {
1592             deltaTimeToken = (int) deltaTime;
1593         }
1594         int firstToken = deltaTimeToken | (cur.states & BatteryStatsHistory.DELTA_STATE_MASK);
1595         int batteryLevelInt = buildBatteryLevelInt(cur);
1596 
1597         if (cur.batteryLevel < mLastHistoryStepLevel || mLastHistoryStepLevel == 0) {
1598             cur.stepDetails = mStepDetailsCalculator.getHistoryStepDetails();
1599             if (cur.stepDetails != null) {
1600                 batteryLevelInt |= BatteryStatsHistory.BATTERY_LEVEL_DETAILS_FLAG;
1601                 mLastHistoryStepLevel = cur.batteryLevel;
1602             }
1603         } else {
1604             cur.stepDetails = null;
1605             mLastHistoryStepLevel = cur.batteryLevel;
1606         }
1607 
1608         final boolean batteryLevelIntChanged = batteryLevelInt != lastBatteryLevelInt;
1609         if (batteryLevelIntChanged) {
1610             firstToken |= BatteryStatsHistory.DELTA_BATTERY_LEVEL_FLAG;
1611         }
1612         final int stateInt = buildStateInt(cur);
1613         final boolean stateIntChanged = stateInt != lastStateInt;
1614         if (stateIntChanged) {
1615             firstToken |= BatteryStatsHistory.DELTA_STATE_FLAG;
1616         }
1617         if (cur.energyConsumerDetails != null) {
1618             extensionFlags |= BatteryStatsHistory.EXTENSION_MEASURED_ENERGY_FLAG;
1619             if (!mMeasuredEnergyHeaderWritten) {
1620                 extensionFlags |= BatteryStatsHistory.EXTENSION_MEASURED_ENERGY_HEADER_FLAG;
1621             }
1622         }
1623         if (cur.cpuUsageDetails != null) {
1624             extensionFlags |= EXTENSION_CPU_USAGE_FLAG;
1625             if (!mCpuUsageHeaderWritten) {
1626                 extensionFlags |= BatteryStatsHistory.EXTENSION_CPU_USAGE_HEADER_FLAG;
1627             }
1628         }
1629         if (extensionFlags != 0) {
1630             cur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
1631         } else {
1632             cur.states2 &= ~HistoryItem.STATE2_EXTENSIONS_FLAG;
1633         }
1634         final boolean state2IntChanged = cur.states2 != last.states2 || extensionFlags != 0;
1635         if (state2IntChanged) {
1636             firstToken |= BatteryStatsHistory.DELTA_STATE2_FLAG;
1637         }
1638         if (cur.wakelockTag != null || cur.wakeReasonTag != null) {
1639             firstToken |= BatteryStatsHistory.DELTA_WAKELOCK_FLAG;
1640         }
1641         if (cur.eventCode != HistoryItem.EVENT_NONE) {
1642             firstToken |= BatteryStatsHistory.DELTA_EVENT_FLAG;
1643         }
1644 
1645         final boolean batteryChargeChanged = cur.batteryChargeUah != last.batteryChargeUah;
1646         if (batteryChargeChanged) {
1647             firstToken |= BatteryStatsHistory.DELTA_BATTERY_CHARGE_FLAG;
1648         }
1649         dest.writeInt(firstToken);
1650         if (DEBUG) {
1651             Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken)
1652                     + " deltaTime=" + deltaTime);
1653         }
1654 
1655         if (deltaTimeToken >= BatteryStatsHistory.DELTA_TIME_INT) {
1656             if (deltaTimeToken == BatteryStatsHistory.DELTA_TIME_INT) {
1657                 if (DEBUG) Slog.i(TAG, "WRITE DELTA: int deltaTime=" + (int) deltaTime);
1658                 dest.writeInt((int) deltaTime);
1659             } else {
1660                 if (DEBUG) Slog.i(TAG, "WRITE DELTA: long deltaTime=" + deltaTime);
1661                 dest.writeLong(deltaTime);
1662             }
1663         }
1664         if (batteryLevelIntChanged) {
1665             dest.writeInt(batteryLevelInt);
1666             if (DEBUG) {
1667                 Slog.i(TAG, "WRITE DELTA: batteryToken=0x"
1668                         + Integer.toHexString(batteryLevelInt)
1669                         + " batteryLevel=" + cur.batteryLevel
1670                         + " batteryTemp=" + cur.batteryTemperature
1671                         + " batteryVolt=" + (int) cur.batteryVoltage);
1672             }
1673         }
1674         if (stateIntChanged) {
1675             dest.writeInt(stateInt);
1676             if (DEBUG) {
1677                 Slog.i(TAG, "WRITE DELTA: stateToken=0x"
1678                         + Integer.toHexString(stateInt)
1679                         + " batteryStatus=" + cur.batteryStatus
1680                         + " batteryHealth=" + cur.batteryHealth
1681                         + " batteryPlugType=" + cur.batteryPlugType
1682                         + " states=0x" + Integer.toHexString(cur.states));
1683             }
1684         }
1685         if (state2IntChanged) {
1686             dest.writeInt(cur.states2);
1687             if (DEBUG) {
1688                 Slog.i(TAG, "WRITE DELTA: states2=0x"
1689                         + Integer.toHexString(cur.states2));
1690             }
1691         }
1692         if (cur.wakelockTag != null || cur.wakeReasonTag != null) {
1693             int wakeLockIndex;
1694             int wakeReasonIndex;
1695             if (cur.wakelockTag != null) {
1696                 wakeLockIndex = writeHistoryTag(cur.wakelockTag);
1697                 if (DEBUG) {
1698                     Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
1699                             + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
1700                 }
1701             } else {
1702                 wakeLockIndex = 0xffff;
1703             }
1704             if (cur.wakeReasonTag != null) {
1705                 wakeReasonIndex = writeHistoryTag(cur.wakeReasonTag);
1706                 if (DEBUG) {
1707                     Slog.i(TAG, "WRITE DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx
1708                             + " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string);
1709                 }
1710             } else {
1711                 wakeReasonIndex = 0xffff;
1712             }
1713             dest.writeInt((wakeReasonIndex << 16) | wakeLockIndex);
1714             if (cur.wakelockTag != null
1715                     && (wakeLockIndex & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) {
1716                 cur.wakelockTag.writeToParcel(dest, 0);
1717                 cur.tagsFirstOccurrence = true;
1718             }
1719             if (cur.wakeReasonTag != null
1720                     && (wakeReasonIndex & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) {
1721                 cur.wakeReasonTag.writeToParcel(dest, 0);
1722                 cur.tagsFirstOccurrence = true;
1723             }
1724         }
1725         if (cur.eventCode != HistoryItem.EVENT_NONE) {
1726             final int index = writeHistoryTag(cur.eventTag);
1727             final int codeAndIndex = setBitField(cur.eventCode & 0xffff, index, 16, 0xFFFF0000);
1728             dest.writeInt(codeAndIndex);
1729             if ((index & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) {
1730                 cur.eventTag.writeToParcel(dest, 0);
1731                 cur.tagsFirstOccurrence = true;
1732             }
1733             if (DEBUG) {
1734                 Slog.i(TAG, "WRITE DELTA: event=" + cur.eventCode + " tag=#"
1735                         + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
1736                         + cur.eventTag.string);
1737             }
1738         }
1739 
1740         if (cur.stepDetails != null) {
1741             cur.stepDetails.writeToParcel(dest);
1742         }
1743 
1744         if (batteryChargeChanged) {
1745             if (DEBUG) Slog.i(TAG, "WRITE DELTA: batteryChargeUah=" + cur.batteryChargeUah);
1746             dest.writeInt(cur.batteryChargeUah);
1747         }
1748         dest.writeDouble(cur.modemRailChargeMah);
1749         dest.writeDouble(cur.wifiRailChargeMah);
1750         if (extensionFlags != 0) {
1751             dest.writeInt(extensionFlags);
1752             if (cur.energyConsumerDetails != null) {
1753                 if (DEBUG) {
1754                     Slog.i(TAG, "WRITE DELTA: measuredEnergyDetails=" + cur.energyConsumerDetails);
1755                 }
1756                 if (!mMeasuredEnergyHeaderWritten) {
1757                     EnergyConsumerDetails.EnergyConsumer[] consumers =
1758                             cur.energyConsumerDetails.consumers;
1759                     dest.writeInt(consumers.length);
1760                     for (EnergyConsumerDetails.EnergyConsumer consumer : consumers) {
1761                         dest.writeInt(consumer.type);
1762                         dest.writeInt(consumer.ordinal);
1763                         dest.writeString(consumer.name);
1764                     }
1765                     mMeasuredEnergyHeaderWritten = true;
1766                 }
1767                 mVarintParceler.writeLongArray(dest, cur.energyConsumerDetails.chargeUC);
1768             }
1769 
1770             if (cur.cpuUsageDetails != null) {
1771                 if (DEBUG) {
1772                     Slog.i(TAG, "WRITE DELTA: cpuUsageDetails=" + cur.cpuUsageDetails);
1773                 }
1774                 if (!mCpuUsageHeaderWritten) {
1775                     dest.writeInt(cur.cpuUsageDetails.cpuBracketDescriptions.length);
1776                     for (String desc: cur.cpuUsageDetails.cpuBracketDescriptions) {
1777                         dest.writeString(desc);
1778                     }
1779                     mCpuUsageHeaderWritten = true;
1780                 }
1781                 dest.writeInt(cur.cpuUsageDetails.uid);
1782                 mVarintParceler.writeLongArray(dest, cur.cpuUsageDetails.cpuUsageMs);
1783             }
1784         }
1785     }
1786 
buildBatteryLevelInt(HistoryItem h)1787     private int buildBatteryLevelInt(HistoryItem h) {
1788         int bits = 0;
1789         bits = setBitField(bits, h.batteryLevel, 25, 0xfe000000 /* 7F << 25 */);
1790         bits = setBitField(bits, h.batteryTemperature, 15, 0x01ff8000 /* 3FF << 15 */);
1791         bits = setBitField(bits, h.batteryVoltage, 1, 0x00007ffe /* 3FFF << 1 */);
1792         return bits;
1793     }
1794 
buildStateInt(HistoryItem h)1795     private int buildStateInt(HistoryItem h) {
1796         int plugType = 0;
1797         if ((h.batteryPlugType & BatteryManager.BATTERY_PLUGGED_AC) != 0) {
1798             plugType = 1;
1799         } else if ((h.batteryPlugType & BatteryManager.BATTERY_PLUGGED_USB) != 0) {
1800             plugType = 2;
1801         } else if ((h.batteryPlugType & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0) {
1802             plugType = 3;
1803         }
1804         return ((h.batteryStatus & BatteryStatsHistory.STATE_BATTERY_STATUS_MASK)
1805                 << BatteryStatsHistory.STATE_BATTERY_STATUS_SHIFT)
1806                 | ((h.batteryHealth & BatteryStatsHistory.STATE_BATTERY_HEALTH_MASK)
1807                 << BatteryStatsHistory.STATE_BATTERY_HEALTH_SHIFT)
1808                 | ((plugType & BatteryStatsHistory.STATE_BATTERY_PLUG_MASK)
1809                 << BatteryStatsHistory.STATE_BATTERY_PLUG_SHIFT)
1810                 | (h.states & (~BatteryStatsHistory.STATE_BATTERY_MASK));
1811     }
1812 
1813     /**
1814      * Returns the index for the specified tag. If this is the first time the tag is encountered
1815      * while writing the current history buffer, the method returns
1816      * <code>(index | TAG_FIRST_OCCURRENCE_FLAG)</code>
1817      */
writeHistoryTag(HistoryTag tag)1818     private int writeHistoryTag(HistoryTag tag) {
1819         if (tag.string == null) {
1820             Slog.wtfStack(TAG, "writeHistoryTag called with null name");
1821         }
1822 
1823         final int stringLength = tag.string.length();
1824         if (stringLength > MAX_HISTORY_TAG_STRING_LENGTH) {
1825             Slog.e(TAG, "Long battery history tag: " + tag.string);
1826             tag.string = tag.string.substring(0, MAX_HISTORY_TAG_STRING_LENGTH);
1827         }
1828 
1829         Integer idxObj = mHistoryTagPool.get(tag);
1830         int idx;
1831         if (idxObj != null) {
1832             idx = idxObj;
1833             if ((idx & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) {
1834                 mHistoryTagPool.put(tag, idx & ~BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG);
1835             }
1836             return idx;
1837         } else if (mNextHistoryTagIdx < HISTORY_TAG_INDEX_LIMIT) {
1838             idx = mNextHistoryTagIdx;
1839             HistoryTag key = new HistoryTag();
1840             key.setTo(tag);
1841             tag.poolIdx = idx;
1842             mHistoryTagPool.put(key, idx);
1843             mNextHistoryTagIdx++;
1844 
1845             mNumHistoryTagChars += stringLength + 1;
1846             if (mHistoryTags != null) {
1847                 mHistoryTags.put(idx, key);
1848             }
1849             return idx | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG;
1850         } else {
1851             tag.poolIdx = HistoryTag.HISTORY_TAG_POOL_OVERFLOW;
1852             // Tag pool overflow: include the tag itself in the parcel
1853             return HISTORY_TAG_INDEX_LIMIT | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG;
1854         }
1855     }
1856 
1857     /**
1858      * Don't allow any more batching in to the current history event.
1859      */
commitCurrentHistoryBatchLocked()1860     public void commitCurrentHistoryBatchLocked() {
1861         mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
1862     }
1863 
1864     /**
1865      * Saves the accumulated history buffer in the active file, see {@link #getActiveFile()} .
1866      */
writeHistory()1867     public void writeHistory() {
1868         if (isReadOnly()) {
1869             Slog.w(TAG, "writeHistory: this instance instance is read-only");
1870             return;
1871         }
1872 
1873         Parcel p = Parcel.obtain();
1874         try {
1875             final long start = SystemClock.uptimeMillis();
1876             writeHistoryBuffer(p);
1877             if (DEBUG) {
1878                 Slog.d(TAG, "writeHistoryBuffer duration ms:"
1879                         + (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize());
1880             }
1881             writeParcelToFileLocked(p, mActiveFile);
1882         } finally {
1883             p.recycle();
1884         }
1885     }
1886 
1887     /**
1888      * Reads history buffer from a persisted Parcel.
1889      */
readHistoryBuffer(Parcel in)1890     public void readHistoryBuffer(Parcel in) throws ParcelFormatException {
1891         final int version = in.readInt();
1892         if (version != BatteryStatsHistory.VERSION) {
1893             Slog.w("BatteryStats", "readHistoryBuffer: version got " + version
1894                     + ", expected " + BatteryStatsHistory.VERSION + "; erasing old stats");
1895             return;
1896         }
1897 
1898         final long historyBaseTime = in.readLong();
1899 
1900         mHistoryBuffer.setDataSize(0);
1901         mHistoryBuffer.setDataPosition(0);
1902 
1903         int bufSize = in.readInt();
1904         int curPos = in.dataPosition();
1905         if (bufSize >= (mMaxHistoryBufferSize * 100)) {
1906             throw new ParcelFormatException(
1907                     "File corrupt: history data buffer too large " + bufSize);
1908         } else if ((bufSize & ~3) != bufSize) {
1909             throw new ParcelFormatException(
1910                     "File corrupt: history data buffer not aligned " + bufSize);
1911         } else {
1912             if (DEBUG) {
1913                 Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
1914                         + " bytes at " + curPos);
1915             }
1916             mHistoryBuffer.appendFrom(in, curPos, bufSize);
1917             in.setDataPosition(curPos + bufSize);
1918         }
1919 
1920         mHistoryBaseTimeMs = historyBaseTime;
1921         if (DEBUG) {
1922             StringBuilder sb = new StringBuilder(128);
1923             sb.append("****************** NEW mHistoryBaseTimeMs: ");
1924             TimeUtils.formatDuration(mHistoryBaseTimeMs, sb);
1925             Slog.i(TAG, sb.toString());
1926         }
1927 
1928         if (mHistoryBaseTimeMs > 0) {
1929             long elapsedRealtimeMs = mClock.elapsedRealtime();
1930             mLastHistoryElapsedRealtimeMs = elapsedRealtimeMs;
1931             mHistoryBaseTimeMs = mHistoryBaseTimeMs - elapsedRealtimeMs + 1;
1932             if (DEBUG) {
1933                 StringBuilder sb = new StringBuilder(128);
1934                 sb.append("****************** ADJUSTED mHistoryBaseTimeMs: ");
1935                 TimeUtils.formatDuration(mHistoryBaseTimeMs, sb);
1936                 Slog.i(TAG, sb.toString());
1937             }
1938         }
1939     }
1940 
writeHistoryBuffer(Parcel out)1941     private void writeHistoryBuffer(Parcel out) {
1942         if (DEBUG) {
1943             StringBuilder sb = new StringBuilder(128);
1944             sb.append("****************** WRITING mHistoryBaseTimeMs: ");
1945             TimeUtils.formatDuration(mHistoryBaseTimeMs, sb);
1946             sb.append(" mLastHistoryElapsedRealtimeMs: ");
1947             TimeUtils.formatDuration(mLastHistoryElapsedRealtimeMs, sb);
1948             Slog.i(TAG, sb.toString());
1949         }
1950         out.writeInt(BatteryStatsHistory.VERSION);
1951         out.writeLong(mHistoryBaseTimeMs + mLastHistoryElapsedRealtimeMs);
1952         out.writeInt(mHistoryBuffer.dataSize());
1953         if (DEBUG) {
1954             Slog.i(TAG, "***************** WRITING HISTORY: "
1955                     + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition());
1956         }
1957         out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
1958     }
1959 
writeParcelToFileLocked(Parcel p, AtomicFile file)1960     private void writeParcelToFileLocked(Parcel p, AtomicFile file) {
1961         FileOutputStream fos = null;
1962         mWriteLock.lock();
1963         try {
1964             final long startTimeMs = SystemClock.uptimeMillis();
1965             fos = file.startWrite();
1966             fos.write(p.marshall());
1967             fos.flush();
1968             file.finishWrite(fos);
1969             if (DEBUG) {
1970                 Slog.d(TAG, "writeParcelToFileLocked file:" + file.getBaseFile().getPath()
1971                         + " duration ms:" + (SystemClock.uptimeMillis() - startTimeMs)
1972                         + " bytes:" + p.dataSize());
1973             }
1974             com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
1975                     "batterystats", SystemClock.uptimeMillis() - startTimeMs);
1976         } catch (IOException e) {
1977             Slog.w(TAG, "Error writing battery statistics", e);
1978             file.failWrite(fos);
1979         } finally {
1980             mWriteLock.unlock();
1981         }
1982     }
1983 
1984     /**
1985      * Returns the total number of history tags in the tag pool.
1986      */
getHistoryStringPoolSize()1987     public int getHistoryStringPoolSize() {
1988         return mHistoryTagPool.size();
1989     }
1990 
1991     /**
1992      * Returns the total number of bytes occupied by the history tag pool.
1993      */
getHistoryStringPoolBytes()1994     public int getHistoryStringPoolBytes() {
1995         return mNumHistoryTagChars;
1996     }
1997 
1998     /**
1999      * Returns the string held by the requested history tag.
2000      */
getHistoryTagPoolString(int index)2001     public String getHistoryTagPoolString(int index) {
2002         ensureHistoryTagArray();
2003         HistoryTag historyTag = mHistoryTags.get(index);
2004         return historyTag != null ? historyTag.string : null;
2005     }
2006 
2007     /**
2008      * Returns the UID held by the requested history tag.
2009      */
getHistoryTagPoolUid(int index)2010     public int getHistoryTagPoolUid(int index) {
2011         ensureHistoryTagArray();
2012         HistoryTag historyTag = mHistoryTags.get(index);
2013         return historyTag != null ? historyTag.uid : Process.INVALID_UID;
2014     }
2015 
ensureHistoryTagArray()2016     private void ensureHistoryTagArray() {
2017         if (mHistoryTags != null) {
2018             return;
2019         }
2020 
2021         mHistoryTags = new SparseArray<>(mHistoryTagPool.size());
2022         for (Map.Entry<HistoryTag, Integer> entry : mHistoryTagPool.entrySet()) {
2023             mHistoryTags.put(entry.getValue() & ~BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG,
2024                     entry.getKey());
2025         }
2026     }
2027 
2028     /**
2029      * Writes/reads an array of longs into Parcel using a compact format, where small integers use
2030      * fewer bytes.  It is a bit more expensive than just writing the long into the parcel,
2031      * but at scale saves a lot of storage and allows recording of longer battery history.
2032      */
2033     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
2034     public static final class VarintParceler {
2035         /**
2036          * Writes an array of longs into Parcel using the varint format, see
2037          * https://developers.google.com/protocol-buffers/docs/encoding#varints
2038          */
writeLongArray(Parcel parcel, long[] values)2039         public void writeLongArray(Parcel parcel, long[] values) {
2040             int out = 0;
2041             int shift = 0;
2042             for (long value : values) {
2043                 boolean done = false;
2044                 while (!done) {
2045                     final byte b;
2046                     if ((value & ~0x7FL) == 0) {
2047                         b = (byte) value;
2048                         done = true;
2049                     } else {
2050                         b = (byte) (((int) value & 0x7F) | 0x80);
2051                         value >>>= 7;
2052                     }
2053                     if (shift == 32) {
2054                         parcel.writeInt(out);
2055                         shift = 0;
2056                         out = 0;
2057                     }
2058                     out |= (b & 0xFF) << shift;
2059                     shift += 8;
2060                 }
2061             }
2062             if (shift != 0) {
2063                 parcel.writeInt(out);
2064             }
2065         }
2066 
2067         /**
2068          * Reads a long written with {@link #writeLongArray}
2069          */
readLongArray(Parcel parcel, long[] values)2070         public void readLongArray(Parcel parcel, long[] values) {
2071             int in = parcel.readInt();
2072             int available = 4;
2073             for (int i = 0; i < values.length; i++) {
2074                 long result = 0;
2075                 int shift;
2076                 for (shift = 0; shift < 64; shift += 7) {
2077                     if (available == 0) {
2078                         in = parcel.readInt();
2079                         available = 4;
2080                     }
2081                     final byte b = (byte) in;
2082                     in >>= 8;
2083                     available--;
2084 
2085                     result |= (long) (b & 0x7F) << shift;
2086                     if ((b & 0x80) == 0) {
2087                         values[i] = result;
2088                         break;
2089                     }
2090                 }
2091                 if (shift >= 64) {
2092                     throw new ParcelFormatException("Invalid varint format");
2093                 }
2094             }
2095         }
2096     }
2097 }
2098