• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.os.BatteryStats.HistoryItem.EVENT_FLAG_FINISH;
20 import static android.os.BatteryStats.HistoryItem.EVENT_FLAG_START;
21 import static android.os.BatteryStats.HistoryItem.EVENT_STATE_CHANGE;
22 import static android.os.Trace.TRACE_TAG_SYSTEM_SERVER;
23 
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.os.BatteryConsumer;
27 import android.os.BatteryManager;
28 import android.os.BatteryStats;
29 import android.os.BatteryStats.BitDescription;
30 import android.os.BatteryStats.HistoryItem;
31 import android.os.BatteryStats.HistoryStepDetails;
32 import android.os.BatteryStats.HistoryTag;
33 import android.os.Build;
34 import android.os.Parcel;
35 import android.os.ParcelFormatException;
36 import android.os.Process;
37 import android.os.SystemClock;
38 import android.os.SystemProperties;
39 import android.os.Trace;
40 import android.util.ArraySet;
41 import android.util.Slog;
42 import android.util.SparseArray;
43 
44 import com.android.internal.annotations.GuardedBy;
45 import com.android.internal.annotations.VisibleForTesting;
46 
47 import java.io.PrintWriter;
48 import java.util.ArrayDeque;
49 import java.util.ArrayList;
50 import java.util.ConcurrentModificationException;
51 import java.util.HashMap;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.Queue;
55 import java.util.concurrent.locks.ReentrantLock;
56 
57 /**
58  * BatteryStatsHistory encapsulates battery history files.
59  * Battery history record is appended into buffer {@link #mHistoryBuffer} and backed up into
60  * {@link #mActiveFragment}.
61  * When {@link #mHistoryBuffer} size reaches {@link #mMaxHistoryBufferSize},
62  * current mActiveFile is closed and a new mActiveFile is open.
63  * History files are under directory /data/system/battery-history/.
64  * History files have name <num>.bf. The file number <num> corresponds to the
65  * monotonic time when the file was started.
66  * The mActiveFile is always the highest numbered history file.
67  * The lowest number file is always the oldest file.
68  * The highest number file is always the newest file.
69  * The file number grows monotonically and we never skip number.
70  * When the total size of history files exceeds the maximum allowed value,
71  * the lowest numbered file is deleted and a new file is open.
72  *
73  * All interfaces in BatteryStatsHistory should only be called by BatteryStatsImpl and protected by
74  * locks on BatteryStatsImpl object.
75  */
76 @android.ravenwood.annotation.RavenwoodKeepWholeClass
77 public class BatteryStatsHistory {
78     private static final boolean DEBUG = false;
79     private static final String TAG = "BatteryStatsHistory";
80 
81     // Current on-disk Parcel version. Must be updated when the format of the parcelable changes
82     private static final int VERSION = 214;
83 
84     // Part of initial delta int that specifies the time delta.
85     static final int DELTA_TIME_MASK = 0x7ffff;
86     static final int DELTA_TIME_LONG = 0x7ffff;   // The delta is a following long
87     static final int DELTA_TIME_INT = 0x7fffe;    // The delta is a following int
88     static final int DELTA_TIME_ABS = 0x7fffd;    // Following is an entire abs update.
89     // Flag in delta int: a new battery level int follows.
90     static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000;
91     // Flag in delta int: a new full state and battery status int follows.
92     static final int DELTA_STATE_FLAG = 0x00100000;
93     // Flag in delta int: a new full state2 int follows.
94     static final int DELTA_STATE2_FLAG = 0x00200000;
95     // Flag in delta int: contains a wakelock or wakeReason tag.
96     static final int DELTA_WAKELOCK_FLAG = 0x00400000;
97     // Flag in delta int: contains an event description.
98     static final int DELTA_EVENT_FLAG = 0x00800000;
99     // Flag in delta int: contains the battery charge count in uAh.
100     static final int DELTA_BATTERY_CHARGE_FLAG = 0x01000000;
101     // These upper bits are the frequently changing state bits.
102     static final int DELTA_STATE_MASK = 0xfe000000;
103     // These are the pieces of battery state that are packed in to the upper bits of
104     // the state int that have been packed in to the first delta int.  They must fit
105     // in STATE_BATTERY_MASK.
106     static final int STATE_BATTERY_MASK = 0xff000000;
107     static final int STATE_BATTERY_STATUS_MASK = 0x00000007;
108     static final int STATE_BATTERY_STATUS_SHIFT = 29;
109     static final int STATE_BATTERY_HEALTH_MASK = 0x00000007;
110     static final int STATE_BATTERY_HEALTH_SHIFT = 26;
111     static final int STATE_BATTERY_PLUG_MASK = 0x00000003;
112     static final int STATE_BATTERY_PLUG_SHIFT = 24;
113 
114     // Pieces of data that are packed into the battery level int
115     static final int BATTERY_LEVEL_LEVEL_MASK = 0xFF000000;
116     static final int BATTERY_LEVEL_LEVEL_SHIFT = 24;
117     static final int BATTERY_LEVEL_TEMP_MASK = 0x00FF8000;
118     static final int BATTERY_LEVEL_TEMP_SHIFT = 15;
119     static final int BATTERY_LEVEL_VOLT_MASK = 0x00007FFC;
120     static final int BATTERY_LEVEL_VOLT_SHIFT = 2;
121     // Flag indicating that the voltage and temperature deltas are too large to
122     // store in the battery level int and full volt/temp values are instead
123     // stored in a following int.
124     static final int BATTERY_LEVEL_OVERFLOW_FLAG = 0x00000002;
125     // We use the low bit of the battery state int to indicate that we have full details
126     // from a battery level change.
127     static final int BATTERY_LEVEL_DETAILS_FLAG = 0x00000001;
128 
129     // Pieces of data that are packed into the extended battery level int
130     static final int BATTERY_LEVEL2_TEMP_MASK = 0xFFFF0000;
131     static final int BATTERY_LEVEL2_TEMP_SHIFT = 16;
132     static final int BATTERY_LEVEL2_VOLT_MASK = 0x0000FFFF;
133     static final int BATTERY_LEVEL2_VOLT_SHIFT = 0;
134 
135     // Flag in history tag index: indicates that this is the first occurrence of this tag,
136     // therefore the tag value is written in the parcel
137     static final int TAG_FIRST_OCCURRENCE_FLAG = 0x8000;
138 
139     static final int EXTENSION_POWER_STATS_DESCRIPTOR_FLAG = 0x00000001;
140     static final int EXTENSION_POWER_STATS_FLAG = 0x00000002;
141     static final int EXTENSION_PROCESS_STATE_CHANGE_FLAG = 0x00000004;
142 
143     // For state1, trace everything except the wakelock bit (which can race with
144     // suspend) and the running bit (which isn't meaningful in traces).
145     static final int STATE1_TRACE_MASK = ~(HistoryItem.STATE_WAKE_LOCK_FLAG
146             | HistoryItem.STATE_CPU_RUNNING_FLAG);
147     // For state2, trace all bit changes.
148     static final int STATE2_TRACE_MASK = ~0;
149 
150     /**
151      * Number of overflow bytes that can be written into the history buffer if the history
152      * directory is locked. This is done to prevent a long lock contention and a potential
153      * kill by a watchdog.
154      */
155     private static final int EXTRA_BUFFER_SIZE_WHEN_DIR_LOCKED = 100_000;
156 
157     public abstract static class BatteryHistoryFragment
158             implements Comparable<BatteryHistoryFragment> {
159         public final long monotonicTimeMs;
160 
BatteryHistoryFragment(long monotonicTimeMs)161         public BatteryHistoryFragment(long monotonicTimeMs) {
162             this.monotonicTimeMs = monotonicTimeMs;
163         }
164 
165         @Override
compareTo(BatteryHistoryFragment o)166         public int compareTo(BatteryHistoryFragment o) {
167             return Long.compare(monotonicTimeMs, o.monotonicTimeMs);
168         }
169 
170         @Override
equals(Object o)171         public boolean equals(Object o) {
172             return monotonicTimeMs == ((BatteryHistoryFragment) o).monotonicTimeMs;
173         }
174 
175         @Override
hashCode()176         public int hashCode() {
177             return Long.hashCode(monotonicTimeMs);
178         }
179     }
180 
181     /**
182      * Persistent storage for battery history fragments
183      */
184     public interface BatteryHistoryStore {
185         /**
186          * Returns the maximum amount of storage that can be occupied by the battery history story.
187          */
getMaxHistorySize()188         int getMaxHistorySize();
189 
190         /**
191          * Returns the table of contents, in the chronological order.
192          */
getFragments()193         List<BatteryHistoryFragment> getFragments();
194 
195         /**
196          * Returns the earliest available fragment
197          */
198         @Nullable
getEarliestFragment()199         BatteryHistoryFragment getEarliestFragment();
200 
201         /**
202          * Returns the latest available fragment
203          */
204         @Nullable
getLatestFragment()205         BatteryHistoryFragment getLatestFragment();
206 
207         /**
208          * Acquires a lock on the entire store.
209          */
lock()210         void lock();
211 
212         /**
213          * Acquires a lock unless the store is already locked by a different thread. Returns true
214          * if the lock has been successfully acquired.
215          */
tryLock()216         boolean tryLock();
217 
218         /**
219          * Unlocks the store.
220          */
unlock()221         void unlock();
222 
223         /**
224          * Returns true if the store is currently locked.
225          */
isLocked()226         boolean isLocked();
227 
228         /**
229          * Returns the total amount of storage occupied by history fragments, in bytes.
230          */
getSize()231         int getSize();
232 
233         /**
234          * Returns true if the store contains any history fragments, excluding the currently
235          * active partial fragment.
236          */
hasCompletedFragments()237         boolean hasCompletedFragments();
238 
239         /**
240          * Creates a new empty history fragment starting at the specified time.
241          */
createFragment(long monotonicStartTime)242         BatteryHistoryFragment createFragment(long monotonicStartTime);
243 
244         /**
245          * Writes a fragment to disk as raw bytes.
246          *
247          * @param fragmentComplete indicates if this fragment is done or still partial.
248          */
writeFragment(BatteryHistoryFragment fragment, @NonNull byte[] bytes, boolean fragmentComplete)249         void writeFragment(BatteryHistoryFragment fragment, @NonNull byte[] bytes,
250                 boolean fragmentComplete);
251 
252         /**
253          * Reads a fragment as raw bytes.
254          */
255         @Nullable
readFragment(BatteryHistoryFragment fragment)256         byte[] readFragment(BatteryHistoryFragment fragment);
257 
258         /**
259          * Removes all persistent fragments
260          */
reset()261         void reset();
262     }
263 
264     class BatteryHistoryParcelContainer {
265         private boolean mParcelReadyForReading;
266         private Parcel mParcel;
267         private BatteryStatsHistory.BatteryHistoryFragment mFragment;
268         private long mMonotonicStartTime;
269 
BatteryHistoryParcelContainer(@onNull Parcel parcel, long monotonicStartTime)270         BatteryHistoryParcelContainer(@NonNull Parcel parcel, long monotonicStartTime) {
271             mParcel = parcel;
272             mMonotonicStartTime = monotonicStartTime;
273             mParcelReadyForReading = true;
274         }
275 
BatteryHistoryParcelContainer(@onNull BatteryHistoryFragment fragment)276         BatteryHistoryParcelContainer(@NonNull BatteryHistoryFragment fragment) {
277             mFragment = fragment;
278             mMonotonicStartTime = fragment.monotonicTimeMs;
279             mParcelReadyForReading = false;
280         }
281 
282         @Nullable
getParcel()283         Parcel getParcel() {
284             if (mParcelReadyForReading) {
285                 return mParcel;
286             }
287 
288             Parcel parcel = Parcel.obtain();
289             if (readFragmentToParcel(parcel, mFragment)) {
290                 parcel.readInt();       // skip buffer size
291                 mParcel = parcel;
292             } else {
293                 parcel.recycle();
294             }
295             mParcelReadyForReading = true;
296             return mParcel;
297         }
298 
getMonotonicStartTime()299         long getMonotonicStartTime() {
300             return mMonotonicStartTime;
301         }
302 
303         /**
304          * Recycles the parcel (if appropriate). Should be called after the parcel has been
305          * processed by the iterator.
306          */
close()307         void close() {
308             if (mParcel != null && mFragment != null) {
309                 mParcel.recycle();
310             }
311             // ParcelContainers are not meant to be reusable. To prevent any unintentional
312             // access to the parcel after it has been recycled, clear the references to it.
313             mParcel = null;
314             mFragment = null;
315         }
316     }
317 
318     private final Parcel mHistoryBuffer;
319     private final Clock mClock;
320 
321     private int mMaxHistoryBufferSize;
322 
323     /**
324      * The active history fragment that the history buffer is backed up into.
325      */
326     private BatteryHistoryFragment mActiveFragment;
327 
328     /**
329      * Persistent storage of history files.
330      */
331     private final BatteryHistoryStore mStore;
332 
333     /**
334      * A list of small history parcels, used when BatteryStatsImpl object is created from
335      * deserialization of a parcel, such as Settings app or checkin file.
336      */
337     private List<Parcel> mHistoryParcels = null;
338 
339     private final ReentrantLock mWriteLock = new ReentrantLock();
340 
341     private final HistoryItem mHistoryCur = new HistoryItem();
342 
343     private boolean mHaveBatteryLevel;
344     private boolean mRecordingHistory;
345 
346     static final int HISTORY_TAG_INDEX_LIMIT = 0x7ffe;
347     private static final int MAX_HISTORY_TAG_STRING_LENGTH = 1024;
348 
349     private final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>();
350     private SparseArray<HistoryTag> mHistoryTags;
351     private final HistoryItem mHistoryLastWritten = new HistoryItem();
352     private final HistoryItem mHistoryLastLastWritten = new HistoryItem();
353     private final HistoryItem mHistoryAddTmp = new HistoryItem();
354     private int mNextHistoryTagIdx = 0;
355     private int mNumHistoryTagChars = 0;
356     private int mHistoryBufferLastPos = -1;
357     private long mTrackRunningHistoryElapsedRealtimeMs = 0;
358     private long mTrackRunningHistoryUptimeMs = 0;
359     private final MonotonicClock mMonotonicClock;
360     // Monotonic time when we started writing to the history buffer
361     private long mHistoryBufferStartTime;
362     // Monotonic time when the last event was written to the history buffer
363     private long mHistoryMonotonicEndTime;
364     // Monotonically increasing size of written history
365     private long mMonotonicHistorySize;
366     private final ArraySet<PowerStats.Descriptor> mWrittenPowerStatsDescriptors = new ArraySet<>();
367     private boolean mMutable = true;
368     private int mIteratorCookie;
369     private final BatteryStatsHistory mWritableHistory;
370 
371     /**
372      * A delegate for android.os.Trace to allow testing static calls. Due to
373      * limitations in Android Tracing (b/153319140), the delegate also records
374      * counter values in system properties which allows reading the value at the
375      * start of a tracing session. This overhead is limited to userdebug builds.
376      * On user builds, tracing still occurs but the counter value will be missing
377      * until the first change occurs.
378      */
379     @VisibleForTesting
380     @android.ravenwood.annotation.RavenwoodKeepWholeClass
381     public static class TraceDelegate {
382         // Note: certain tests currently run as platform_app which is not allowed
383         // to set debug system properties. To ensure that system properties are set
384         // only when allowed, we check the current UID.
385         private final boolean mShouldSetProperty =
386                 Build.IS_USERDEBUG && (Process.myUid() == Process.SYSTEM_UID);
387 
388         /**
389          * Returns true if trace counters should be recorded.
390          */
tracingEnabled()391         public boolean tracingEnabled() {
392             return Trace.isTagEnabled(Trace.TRACE_TAG_POWER) || mShouldSetProperty;
393         }
394 
395         /**
396          * Records the counter value with the given name.
397          */
traceCounter(@onNull String name, int value)398         public void traceCounter(@NonNull String name, int value) {
399             Trace.traceCounter(Trace.TRACE_TAG_POWER, name, value);
400             if (mShouldSetProperty) {
401                 try {
402                     SystemProperties.set("debug.tracing." + name, Integer.toString(value));
403                 } catch (RuntimeException e) {
404                     Slog.e(TAG, "Failed to set debug.tracing." + name, e);
405                 }
406             }
407         }
408 
409         /**
410          * Records an instant event (one with no duration).
411          */
traceInstantEvent(@onNull String track, @NonNull String name)412         public void traceInstantEvent(@NonNull String track, @NonNull String name) {
413             Trace.instantForTrack(Trace.TRACE_TAG_POWER, track, name);
414         }
415     }
416 
417     public static class EventLogger {
418         /**
419          * Records a statsd event when the batterystats config file is written to disk.
420          */
writeCommitSysConfigFile(long startTimeMs)421         public void writeCommitSysConfigFile(long startTimeMs) {
422             com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
423                     "batterystats", SystemClock.uptimeMillis() - startTimeMs);
424         }
425     }
426 
427     private TraceDelegate mTracer;
428     private int mTraceLastState = 0;
429     private int mTraceLastState2 = 0;
430     private final EventLogger mEventLogger;
431 
432     /**
433      * Constructor
434      *
435      * @param maxHistoryBufferSize the most amount of RAM to used for buffering of history steps
436      */
BatteryStatsHistory(Parcel historyBuffer, int maxHistoryBufferSize, @Nullable BatteryHistoryStore store, Clock clock, MonotonicClock monotonicClock, TraceDelegate tracer, EventLogger eventLogger)437     public BatteryStatsHistory(Parcel historyBuffer, int maxHistoryBufferSize,
438             @Nullable BatteryHistoryStore store, Clock clock, MonotonicClock monotonicClock,
439             TraceDelegate tracer, EventLogger eventLogger) {
440         this(historyBuffer, maxHistoryBufferSize, store, clock, monotonicClock, tracer, eventLogger,
441                 null);
442     }
443 
BatteryStatsHistory(@ullable Parcel historyBuffer, int maxHistoryBufferSize, @Nullable BatteryHistoryStore store, @NonNull Clock clock, @NonNull MonotonicClock monotonicClock, @NonNull TraceDelegate tracer, @NonNull EventLogger eventLogger, @Nullable BatteryStatsHistory writableHistory)444     private BatteryStatsHistory(@Nullable Parcel historyBuffer, int maxHistoryBufferSize,
445             @Nullable BatteryHistoryStore store, @NonNull Clock clock,
446             @NonNull MonotonicClock monotonicClock, @NonNull TraceDelegate tracer,
447             @NonNull EventLogger eventLogger, @Nullable BatteryStatsHistory writableHistory) {
448         mMaxHistoryBufferSize = maxHistoryBufferSize;
449         mTracer = tracer;
450         mClock = clock;
451         mMonotonicClock = monotonicClock;
452         mEventLogger = eventLogger;
453         mWritableHistory = writableHistory;
454         if (mWritableHistory != null) {
455             mMutable = false;
456             mHistoryBufferStartTime = mWritableHistory.mHistoryBufferStartTime;
457             mHistoryMonotonicEndTime = mWritableHistory.mHistoryMonotonicEndTime;
458         }
459 
460         if (historyBuffer != null) {
461             mHistoryBuffer = historyBuffer;
462         } else {
463             mHistoryBuffer = Parcel.obtain();
464             initHistoryBuffer();
465         }
466 
467         if (writableHistory != null) {
468             mStore = writableHistory.mStore;
469         } else {
470             mStore = store;
471             if (mStore != null) {
472                 BatteryHistoryFragment activeFile = mStore.getLatestFragment();
473                 if (activeFile == null) {
474                     activeFile = mStore.createFragment(mMonotonicClock.monotonicTime());
475                 }
476                 setActiveFragment(activeFile);
477             }
478         }
479     }
480 
481     /**
482      * Used when BatteryStatsHistory object is created from deserialization of a BatteryUsageStats
483      * parcel.
484      */
BatteryStatsHistory(Parcel parcel)485     private BatteryStatsHistory(Parcel parcel) {
486         mClock = Clock.SYSTEM_CLOCK;
487         mTracer = null;
488         mStore = null;
489         mEventLogger = new EventLogger();
490         mWritableHistory = null;
491         mMutable = false;
492 
493         final byte[] historyBlob = parcel.readBlob();
494 
495         mHistoryBuffer = Parcel.obtain();
496         mHistoryBuffer.unmarshall(historyBlob, 0, historyBlob.length);
497 
498         mMonotonicClock = null;
499         readFromParcel(parcel, true /* useBlobs */);
500     }
501 
initHistoryBuffer()502     private void initHistoryBuffer() {
503         mTrackRunningHistoryElapsedRealtimeMs = 0;
504         mTrackRunningHistoryUptimeMs = 0;
505         mWrittenPowerStatsDescriptors.clear();
506 
507         mHistoryBufferStartTime = mMonotonicClock.monotonicTime();
508         mHistoryBuffer.setDataSize(0);
509         mHistoryBuffer.setDataPosition(0);
510         mHistoryBuffer.setDataCapacity(mMaxHistoryBufferSize / 2);
511         mHistoryLastLastWritten.clear();
512         mHistoryLastWritten.clear();
513         mHistoryTagPool.clear();
514         mNextHistoryTagIdx = 0;
515         mNumHistoryTagChars = 0;
516         mHistoryBufferLastPos = -1;
517     }
518 
519     /**
520      * Changes the maximum size of the history buffer, in bytes.
521      */
setMaxHistoryBufferSize(int maxHistoryBufferSize)522     public void setMaxHistoryBufferSize(int maxHistoryBufferSize) {
523         mMaxHistoryBufferSize = maxHistoryBufferSize;
524     }
525 
526     /**
527      * Returns a high estimate of how many items are currently included in the battery history.
528      */
getEstimatedItemCount()529     public int getEstimatedItemCount() {
530         int estimatedBytes = mHistoryBuffer.dataSize();
531         if (mStore != null) {
532             estimatedBytes += mStore.getMaxHistorySize() * 10;  // account for the compression ratio
533         }
534         if (mHistoryParcels != null) {
535             for (int i = mHistoryParcels.size() - 1; i >= 0; i--) {
536                 estimatedBytes += mHistoryParcels.get(i).dataSize();
537             }
538         }
539         return estimatedBytes / 4;    // Minimum size of a history item is 4 bytes
540     }
541 
542     /**
543      * Creates a read-only copy of the battery history.  Does not copy the files stored
544      * in the system directory, so it is not safe while actively writing history.
545      */
copy()546     public BatteryStatsHistory copy() {
547         Trace.traceBegin(TRACE_TAG_SYSTEM_SERVER, "BatteryStatsHistory.copy");
548         try {
549             synchronized (this) {
550                 // Make a copy of battery history to avoid concurrent modification.
551                 Parcel historyBufferCopy = Parcel.obtain();
552                 historyBufferCopy.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
553 
554                 return new BatteryStatsHistory(historyBufferCopy, 0, mStore,
555                         null, null, null, mEventLogger, this);
556             }
557         } finally {
558             Trace.traceEnd(TRACE_TAG_SYSTEM_SERVER);
559         }
560     }
561 
562     /**
563      * Returns true if this instance only supports reading history.
564      */
isReadOnly()565     public boolean isReadOnly() {
566         return !mMutable || mActiveFragment == null || mStore == null;
567     }
568 
569     /**
570      * Set the active file that mHistoryBuffer is backed up into.
571      */
setActiveFragment(BatteryHistoryFragment file)572     private void setActiveFragment(BatteryHistoryFragment file) {
573         mActiveFragment = file;
574         if (DEBUG) {
575             Slog.d(TAG, "activeHistoryFile:" + mActiveFragment);
576         }
577     }
578 
579     /**
580      * When {@link #mHistoryBuffer} reaches {@link #mMaxHistoryBufferSize},
581      * create next history fragment.
582      */
startNextFragment(long elapsedRealtimeMs)583     public void startNextFragment(long elapsedRealtimeMs) {
584         synchronized (this) {
585             startNextFragmentLocked(elapsedRealtimeMs);
586         }
587     }
588 
589     @GuardedBy("this")
startNextFragmentLocked(long elapsedRealtimeMs)590     private void startNextFragmentLocked(long elapsedRealtimeMs) {
591         final long start = SystemClock.uptimeMillis();
592         writeHistory(true /* fragmentComplete */);
593         if (DEBUG) {
594             Slog.d(TAG, "writeHistory took ms:" + (SystemClock.uptimeMillis() - start));
595         }
596 
597         long monotonicStartTime = mMonotonicClock.monotonicTime(elapsedRealtimeMs);
598         setActiveFragment(mStore.createFragment(monotonicStartTime));
599         mHistoryBufferStartTime = monotonicStartTime;
600         mHistoryBuffer.setDataSize(0);
601         mHistoryBuffer.setDataPosition(0);
602         mHistoryBuffer.setDataCapacity(mMaxHistoryBufferSize / 2);
603         mHistoryBufferLastPos = -1;
604         mHistoryLastWritten.clear();
605         mHistoryLastLastWritten.clear();
606 
607         // Mark every entry in the pool with a flag indicating that the tag
608         // has not yet been encountered while writing the current history buffer.
609         for (Map.Entry<HistoryTag, Integer> entry : mHistoryTagPool.entrySet()) {
610             entry.setValue(entry.getValue() | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG);
611         }
612 
613         mWrittenPowerStatsDescriptors.clear();
614     }
615 
616     /**
617      * Returns true if it is safe to reset history. It will return false if the history is
618      * currently being read.
619      */
isResetEnabled()620     public boolean isResetEnabled() {
621         return mStore == null || !mStore.isLocked();
622     }
623 
624     /**
625      * Clear history buffer and delete all existing history files. Active history file start from
626      * number 0 again.
627      */
reset()628     public void reset() {
629         synchronized (this) {
630             mMonotonicHistorySize = 0;
631             initHistoryBuffer();
632             if (mStore != null) {
633                 mStore.reset();
634                 setActiveFragment(mStore.createFragment(mHistoryBufferStartTime));
635             }
636         }
637     }
638 
639     /**
640      * Returns the monotonic clock time when the available battery history collection started.
641      */
getStartTime()642     public long getStartTime() {
643         synchronized (this) {
644             BatteryHistoryFragment firstFragment = mStore.getEarliestFragment();
645             if (firstFragment != null) {
646                 return firstFragment.monotonicTimeMs;
647             } else {
648                 return mHistoryBufferStartTime;
649             }
650         }
651     }
652 
653     /**
654      * Start iterating history files and history buffer.
655      *
656      * @param startTimeMs monotonic time (the HistoryItem.time field) to start iterating from,
657      *                    inclusive
658      * @param endTimeMs monotonic time to stop iterating, exclusive.
659      *                  Pass {@link MonotonicClock#UNDEFINED} to indicate current time.
660      */
661     @NonNull
iterate(long startTimeMs, long endTimeMs)662     public BatteryStatsHistoryIterator iterate(long startTimeMs, long endTimeMs) {
663         if (mMutable || mIteratorCookie != 0) {
664             return copy().iterate(startTimeMs, endTimeMs);
665         }
666 
667         if (mStore != null) {
668             mStore.lock();
669         }
670         BatteryStatsHistoryIterator iterator = new BatteryStatsHistoryIterator(
671                 this, startTimeMs, endTimeMs);
672         mIteratorCookie = System.identityHashCode(iterator);
673         Trace.asyncTraceBegin(TRACE_TAG_SYSTEM_SERVER, "BatteryStatsHistory.iterate",
674                 mIteratorCookie);
675         return iterator;
676     }
677 
678     /**
679      * Finish iterating history files and history buffer.
680      */
iteratorFinished()681     void iteratorFinished() {
682         mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
683         if (mStore != null) {
684             mStore.unlock();
685         }
686         Trace.asyncTraceEnd(TRACE_TAG_SYSTEM_SERVER, "BatteryStatsHistory.iterate",
687                 mIteratorCookie);
688         mIteratorCookie = 0;
689     }
690 
691     /**
692      * Returns all chunks of accumulated history that contain items within the range between
693      * `startTimeMs` (inclusive) and `endTimeMs` (exclusive)
694      */
getParcelContainers(long startTimeMs, long endTimeMs)695     Queue<BatteryHistoryParcelContainer> getParcelContainers(long startTimeMs, long endTimeMs) {
696         if (mMutable) {
697             throw new IllegalStateException("Iterating over a mutable battery history");
698         }
699 
700         if (endTimeMs == MonotonicClock.UNDEFINED || endTimeMs == 0) {
701             endTimeMs = Long.MAX_VALUE;
702         }
703 
704         Queue<BatteryHistoryParcelContainer> containers = new ArrayDeque<>();
705 
706         if (mStore != null) {
707             List<BatteryHistoryFragment> fragments = mStore.getFragments();
708             for (int i = 0; i < fragments.size(); i++) {
709                 BatteryHistoryFragment fragment = fragments.get(i);
710                 if (fragment.monotonicTimeMs >= endTimeMs) {
711                     break;
712                 }
713 
714                 if (fragment.monotonicTimeMs >= mHistoryBufferStartTime) {
715                     // Do not include the backup of the current buffer, which is explicitly
716                     // included later
717                     continue;
718                 }
719 
720                 if (i < fragments.size() - 1
721                         && fragments.get(i + 1).monotonicTimeMs < startTimeMs) {
722                     // Since fragments are ordered, an early start of next fragment implies an
723                     // early end for this one.
724                     continue;
725                 }
726 
727                 containers.add(new BatteryHistoryParcelContainer(fragment));
728             }
729         }
730 
731         if (mHistoryParcels != null) {
732             for (int i = 0; i < mHistoryParcels.size(); i++) {
733                 final Parcel p = mHistoryParcels.get(i);
734                 if (!verifyVersion(p)) {
735                     continue;
736                 }
737 
738                 long monotonicStartTime = p.readLong();
739                 if (monotonicStartTime >= endTimeMs) {
740                     continue;
741                 }
742 
743                 long monotonicEndTime = p.readLong();
744                 if (monotonicEndTime < startTimeMs) {
745                     continue;
746                 }
747 
748                 // skip monotonic size field
749                 p.readLong();
750                 // skip buffer size field
751                 p.readInt();
752 
753                 containers.add(new BatteryHistoryParcelContainer(p, monotonicStartTime));
754             }
755         }
756 
757         if (mHistoryBufferStartTime < endTimeMs) {
758             mHistoryBuffer.setDataPosition(0);
759             containers.add(
760                     new BatteryHistoryParcelContainer(mHistoryBuffer, mHistoryBufferStartTime));
761         }
762         return containers;
763     }
764 
765     /**
766      * Read history file into a parcel.
767      *
768      * @param out  the Parcel read into.
769      * @param fragment the fragment to read from.
770      * @return true if success, false otherwise.
771      */
readFragmentToParcel(Parcel out, BatteryHistoryFragment fragment)772     public boolean readFragmentToParcel(Parcel out, BatteryHistoryFragment fragment) {
773         byte[] data = mStore.readFragment(fragment);
774         if (data == null || data.length == 0) {
775             return false;
776         }
777         out.unmarshall(data, 0, data.length);
778         out.setDataPosition(0);
779         if (!verifyVersion(out)) {
780             return false;
781         }
782         // skip monotonic time field.
783         out.readLong();
784         // skip monotonic end time field
785         out.readLong();
786         // skip monotonic size field
787         out.readLong();
788         return true;
789     }
790 
791     /**
792      * Verify header part of history parcel.
793      *
794      * @return true if version match, false if not.
795      */
verifyVersion(Parcel p)796     private boolean verifyVersion(Parcel p) {
797         p.setDataPosition(0);
798         final int version = p.readInt();
799         return version == VERSION;
800     }
801 
802     /**
803      * Writes the battery history contents for persistence.
804      */
writeSummaryToParcel(Parcel out, boolean inclHistory)805     public void writeSummaryToParcel(Parcel out, boolean inclHistory) {
806         out.writeBoolean(inclHistory);
807         if (inclHistory) {
808             writeToParcel(out);
809         }
810 
811         out.writeInt(mHistoryTagPool.size());
812         for (Map.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) {
813             HistoryTag tag = ent.getKey();
814             out.writeInt(ent.getValue());
815             out.writeString(tag.string);
816             out.writeInt(tag.uid);
817         }
818     }
819 
820     /**
821      * Reads battery history contents from a persisted parcel.
822      */
readSummaryFromParcel(Parcel in)823     public void readSummaryFromParcel(Parcel in) {
824         boolean inclHistory = in.readBoolean();
825         if (inclHistory) {
826             readFromParcel(in);
827         }
828 
829         mHistoryTagPool.clear();
830         mNextHistoryTagIdx = 0;
831         mNumHistoryTagChars = 0;
832 
833         int numTags = in.readInt();
834         for (int i = 0; i < numTags; i++) {
835             int idx = in.readInt();
836             String str = in.readString();
837             int uid = in.readInt();
838             HistoryTag tag = new HistoryTag();
839             tag.string = str;
840             tag.uid = uid;
841             tag.poolIdx = idx;
842             mHistoryTagPool.put(tag, idx);
843             if (idx >= mNextHistoryTagIdx) {
844                 mNextHistoryTagIdx = idx + 1;
845             }
846             mNumHistoryTagChars += tag.string.length() + 1;
847         }
848     }
849 
850     /**
851      * Read all history files and serialize into a big Parcel.
852      * Checkin file calls this method.
853      *
854      * @param out the output parcel
855      */
writeToParcel(Parcel out)856     public void writeToParcel(Parcel out) {
857         synchronized (this) {
858             writeHistoryBuffer(out);
859             if (mStore != null) {
860                 writeToParcel(out, false /* useBlobs */, 0);
861             }
862         }
863     }
864 
865     /**
866      * This is for Settings app, when Settings app receives big history parcel, it call
867      * this method to parse it into list of parcels.
868      *
869      * @param out the output parcel
870      */
writeToBatteryUsageStatsParcel(Parcel out, long preferredHistoryDurationMs)871     public void writeToBatteryUsageStatsParcel(Parcel out, long preferredHistoryDurationMs) {
872         synchronized (this) {
873             out.writeBlob(mHistoryBuffer.marshall());
874             if (mStore != null) {
875                 writeToParcel(out, true /* useBlobs */,
876                         mHistoryMonotonicEndTime - preferredHistoryDurationMs);
877             }
878         }
879     }
880 
writeToParcel(Parcel out, boolean useBlobs, long preferredEarliestIncludedTimestampMs)881     private void writeToParcel(Parcel out, boolean useBlobs,
882             long preferredEarliestIncludedTimestampMs) {
883         Trace.traceBegin(TRACE_TAG_SYSTEM_SERVER, "BatteryStatsHistory.writeToParcel");
884         mStore.lock();
885         try {
886             final long start = SystemClock.uptimeMillis();
887             List<BatteryHistoryFragment> fragments = mStore.getFragments();
888             for (int i = 0; i < fragments.size() - 1; i++) {
889                 long monotonicEndTime = Long.MAX_VALUE;
890                 if (i < fragments.size() - 1) {
891                     monotonicEndTime = fragments.get(i + 1).monotonicTimeMs;
892                 }
893 
894                 if (monotonicEndTime < preferredEarliestIncludedTimestampMs) {
895                     continue;
896                 }
897 
898                 byte[] data = mStore.readFragment(fragments.get(i));
899                 if (data == null) {
900                     Slog.e(TAG, "Error reading history fragment " + fragments.get(i));
901                     continue;
902                 }
903 
904                 if (data.length == 0) {
905                     continue;
906                 }
907 
908                 out.writeBoolean(true);
909                 if (useBlobs) {
910                     out.writeBlob(data, 0, data.length);
911                 } else {
912                     // Avoiding blobs in the check-in file for compatibility
913                     out.writeByteArray(data, 0, data.length);
914                 }
915             }
916             out.writeBoolean(false);
917             if (DEBUG) {
918                 Slog.d(TAG, "writeToParcel duration ms:" + (SystemClock.uptimeMillis() - start));
919             }
920         } finally {
921             mStore.unlock();
922             Trace.traceEnd(TRACE_TAG_SYSTEM_SERVER);
923         }
924     }
925 
926     /**
927      * Reads a BatteryStatsHistory from a parcel written with
928      * the {@link #writeToBatteryUsageStatsParcel} method.
929      */
createFromBatteryUsageStatsParcel(Parcel in)930     public static BatteryStatsHistory createFromBatteryUsageStatsParcel(Parcel in) {
931         return new BatteryStatsHistory(in);
932     }
933 
934     /**
935      * Read history from a check-in file.
936      */
readSummary()937     public boolean readSummary() {
938         if (mActiveFragment == null) {
939             Slog.w(TAG, "readSummary: no history file associated with this instance");
940             return false;
941         }
942 
943         Parcel parcel = Parcel.obtain();
944         try {
945             byte[] data = mStore.readFragment(mActiveFragment);
946             if (data == null) {
947                 return false;
948             }
949 
950             if (data.length > 0) {
951                 parcel.unmarshall(data, 0, data.length);
952                 parcel.setDataPosition(0);
953                 readHistoryBuffer(parcel);
954             }
955         } catch (Exception e) {
956             Slog.e(TAG, "Error reading battery history", e);
957             reset();
958             return false;
959         } finally {
960             parcel.recycle();
961         }
962         return true;
963     }
964 
965     /**
966      * This is for the check-in file, which has all history files embedded.
967      *
968      * @param in the input parcel.
969      */
readFromParcel(Parcel in)970     public void readFromParcel(Parcel in) {
971         readHistoryBuffer(in);
972         readFromParcel(in, false /* useBlobs */);
973     }
974 
readFromParcel(Parcel in, boolean useBlobs)975     private void readFromParcel(Parcel in, boolean useBlobs) {
976         final long start = SystemClock.uptimeMillis();
977         mHistoryParcels = new ArrayList<>();
978         while (in.readBoolean()) {
979             byte[] temp = useBlobs ? in.readBlob() : in.createByteArray();
980             if (temp == null || temp.length == 0) {
981                 continue;
982             }
983             Parcel p = Parcel.obtain();
984             p.unmarshall(temp, 0, temp.length);
985             p.setDataPosition(0);
986             mHistoryParcels.add(p);
987         }
988         if (DEBUG) {
989             Slog.d(TAG, "readFromParcel duration ms:" + (SystemClock.uptimeMillis() - start));
990         }
991     }
992 
993     @VisibleForTesting
getBatteryHistoryStore()994     public BatteryHistoryStore getBatteryHistoryStore() {
995         return mStore;
996     }
997 
998     @VisibleForTesting
getActiveFragment()999     public BatteryHistoryFragment getActiveFragment() {
1000         return mActiveFragment;
1001     }
1002 
1003     /**
1004      * @return the total size of all history files and history buffer.
1005      */
getHistoryUsedSize()1006     public int getHistoryUsedSize() {
1007         int ret = mStore.getSize();
1008         ret += mHistoryBuffer.dataSize();
1009         if (mHistoryParcels != null) {
1010             for (int i = 0; i < mHistoryParcels.size(); i++) {
1011                 ret += mHistoryParcels.get(i).dataSize();
1012             }
1013         }
1014         return ret;
1015     }
1016 
1017     /**
1018      * Enables/disables recording of history.  When disabled, all "record*" calls are a no-op.
1019      */
setHistoryRecordingEnabled(boolean enabled)1020     public void setHistoryRecordingEnabled(boolean enabled) {
1021         synchronized (this) {
1022             mRecordingHistory = enabled;
1023         }
1024     }
1025 
1026     /**
1027      * Returns true if history recording is enabled.
1028      */
isRecordingHistory()1029     public boolean isRecordingHistory() {
1030         synchronized (this) {
1031             return mRecordingHistory;
1032         }
1033     }
1034 
1035     /**
1036      * Forces history recording regardless of charging state.
1037      */
1038     @VisibleForTesting
forceRecordAllHistory()1039     public void forceRecordAllHistory() {
1040         synchronized (this) {
1041             mHaveBatteryLevel = true;
1042             mRecordingHistory = true;
1043         }
1044     }
1045 
1046     /**
1047      * Starts a history buffer by recording the current wall-clock time.
1048      */
startRecordingHistory(final long elapsedRealtimeMs, final long uptimeMs, boolean reset)1049     public void startRecordingHistory(final long elapsedRealtimeMs, final long uptimeMs,
1050             boolean reset) {
1051         synchronized (this) {
1052             mRecordingHistory = true;
1053             mHistoryCur.currentTime = mClock.currentTimeMillis();
1054             writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
1055                     reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME);
1056             mHistoryCur.currentTime = 0;
1057         }
1058     }
1059 
1060     /**
1061      * Prepares to continue recording after restoring previous history from persistent storage.
1062      */
continueRecordingHistory()1063     public void continueRecordingHistory() {
1064         synchronized (this) {
1065             if (mHistoryBuffer.dataPosition() <= 0 && !mStore.hasCompletedFragments()) {
1066                 return;
1067             }
1068 
1069             mRecordingHistory = true;
1070             final long elapsedRealtimeMs = mClock.elapsedRealtime();
1071             final long uptimeMs = mClock.uptimeMillis();
1072             writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_START);
1073             startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
1074         }
1075     }
1076 
1077     /**
1078      * Notes the current battery state to be reflected in the next written history item.
1079      */
setBatteryState(boolean charging, int status, int level, int chargeUah)1080     public void setBatteryState(boolean charging, int status, int level, int chargeUah) {
1081         synchronized (this) {
1082             mHaveBatteryLevel = true;
1083             setChargingState(charging);
1084             mHistoryCur.batteryStatus = (byte) status;
1085             mHistoryCur.batteryLevel = (byte) level;
1086             mHistoryCur.batteryChargeUah = chargeUah;
1087         }
1088     }
1089 
1090     /**
1091      * Notes the current battery state to be reflected in the next written history item.
1092      */
setBatteryState(int status, int level, int health, int plugType, int temperature, int voltageMv, int chargeUah)1093     public void setBatteryState(int status, int level, int health, int plugType, int temperature,
1094             int voltageMv, int chargeUah) {
1095         synchronized (this) {
1096             mHaveBatteryLevel = true;
1097             mHistoryCur.batteryStatus = (byte) status;
1098             mHistoryCur.batteryLevel = (byte) level;
1099             mHistoryCur.batteryHealth = (byte) health;
1100             mHistoryCur.batteryPlugType = (byte) plugType;
1101             mHistoryCur.batteryTemperature = (short) temperature;
1102             mHistoryCur.batteryVoltage = (short) voltageMv;
1103             mHistoryCur.batteryChargeUah = chargeUah;
1104         }
1105     }
1106 
1107     /**
1108      * Notes the current power plugged-in state to be reflected in the next written history item.
1109      */
setPluggedInState(boolean pluggedIn)1110     public void setPluggedInState(boolean pluggedIn) {
1111         synchronized (this) {
1112             if (pluggedIn) {
1113                 mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
1114             } else {
1115                 mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
1116             }
1117         }
1118     }
1119 
1120     /**
1121      * Notes the current battery charging state to be reflected in the next written history item.
1122      */
setChargingState(boolean charging)1123     public void setChargingState(boolean charging) {
1124         synchronized (this) {
1125             if (charging) {
1126                 mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
1127             } else {
1128                 mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG;
1129             }
1130         }
1131     }
1132 
1133     /**
1134      * Records a history event with the given code, name and UID.
1135      */
recordEvent(long elapsedRealtimeMs, long uptimeMs, int code, String name, int uid)1136     public void recordEvent(long elapsedRealtimeMs, long uptimeMs, int code, String name,
1137             int uid) {
1138         synchronized (this) {
1139             mHistoryCur.eventCode = code;
1140             mHistoryCur.eventTag = mHistoryCur.localEventTag;
1141             mHistoryCur.eventTag.string = name;
1142             mHistoryCur.eventTag.uid = uid;
1143             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1144         }
1145     }
1146 
1147     /**
1148      * Records a time change event.
1149      */
recordCurrentTimeChange(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs)1150     public void recordCurrentTimeChange(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) {
1151         synchronized (this) {
1152             if (!mRecordingHistory) {
1153                 return;
1154             }
1155 
1156             mHistoryCur.currentTime = currentTimeMs;
1157             writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
1158                     HistoryItem.CMD_CURRENT_TIME);
1159             mHistoryCur.currentTime = 0;
1160         }
1161     }
1162 
1163     /**
1164      * Records a system shutdown event.
1165      */
recordShutdownEvent(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs)1166     public void recordShutdownEvent(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) {
1167         synchronized (this) {
1168             if (!mRecordingHistory) {
1169                 return;
1170             }
1171 
1172             mHistoryCur.currentTime = currentTimeMs;
1173             writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_SHUTDOWN);
1174             mHistoryCur.currentTime = 0;
1175         }
1176     }
1177 
1178     /**
1179      * Records a battery state change event.
1180      */
recordBatteryState(long elapsedRealtimeMs, long uptimeMs, int batteryLevel, boolean isPlugged)1181     public void recordBatteryState(long elapsedRealtimeMs, long uptimeMs, int batteryLevel,
1182             boolean isPlugged) {
1183         synchronized (this) {
1184             mHistoryCur.batteryLevel = (byte) batteryLevel;
1185             setPluggedInState(isPlugged);
1186             if (DEBUG) {
1187                 Slog.v(TAG, "Battery unplugged to: "
1188                         + Integer.toHexString(mHistoryCur.states));
1189             }
1190             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1191         }
1192     }
1193 
1194     /**
1195      * Records a PowerStats snapshot.
1196      */
recordPowerStats(long elapsedRealtimeMs, long uptimeMs, PowerStats powerStats)1197     public void recordPowerStats(long elapsedRealtimeMs, long uptimeMs,
1198             PowerStats powerStats) {
1199         synchronized (this) {
1200             mHistoryCur.powerStats = powerStats;
1201             mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
1202             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1203         }
1204     }
1205 
1206     /**
1207      * Records the change of a UID's proc state.
1208      */
recordProcessStateChange(long elapsedRealtimeMs, long uptimeMs, int uid, @BatteryConsumer.ProcessState int processState)1209     public void recordProcessStateChange(long elapsedRealtimeMs, long uptimeMs,
1210             int uid, @BatteryConsumer.ProcessState int processState) {
1211         synchronized (this) {
1212             mHistoryCur.processStateChange = mHistoryCur.localProcessStateChange;
1213             mHistoryCur.processStateChange.uid = uid;
1214             mHistoryCur.processStateChange.processState = processState;
1215             mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
1216             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1217         }
1218     }
1219 
1220     /**
1221      * Records a history item with the amount of charge consumed by WiFi.  Used on certain devices
1222      * equipped with on-device power metering.
1223      */
recordWifiConsumedCharge(long elapsedRealtimeMs, long uptimeMs, double monitoredRailChargeMah)1224     public void recordWifiConsumedCharge(long elapsedRealtimeMs, long uptimeMs,
1225             double monitoredRailChargeMah) {
1226         synchronized (this) {
1227             mHistoryCur.wifiRailChargeMah += monitoredRailChargeMah;
1228             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1229         }
1230     }
1231 
1232     /**
1233      * Records a wakelock start event.
1234      */
recordWakelockStartEvent(long elapsedRealtimeMs, long uptimeMs, String historyName, int uid)1235     public void recordWakelockStartEvent(long elapsedRealtimeMs, long uptimeMs, String historyName,
1236             int uid) {
1237         synchronized (this) {
1238             mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
1239             mHistoryCur.wakelockTag.string = historyName;
1240             mHistoryCur.wakelockTag.uid = uid;
1241             recordStateStartEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
1242         }
1243     }
1244 
1245     /**
1246      * Updates the previous history event with a wakelock name and UID.
1247      */
maybeUpdateWakelockTag(long elapsedRealtimeMs, long uptimeMs, String historyName, int uid)1248     public boolean maybeUpdateWakelockTag(long elapsedRealtimeMs, long uptimeMs, String historyName,
1249             int uid) {
1250         synchronized (this) {
1251             if (mHistoryLastWritten.cmd != HistoryItem.CMD_UPDATE) {
1252                 return false;
1253             }
1254             if (mHistoryLastWritten.wakelockTag != null) {
1255                 // We'll try to update the last tag.
1256                 mHistoryLastWritten.wakelockTag = null;
1257                 mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
1258                 mHistoryCur.wakelockTag.string = historyName;
1259                 mHistoryCur.wakelockTag.uid = uid;
1260                 writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1261             }
1262             return true;
1263         }
1264     }
1265 
1266     /**
1267      * Records a wakelock release event.
1268      */
recordWakelockStopEvent(long elapsedRealtimeMs, long uptimeMs, String historyName, int uid)1269     public void recordWakelockStopEvent(long elapsedRealtimeMs, long uptimeMs, String historyName,
1270             int uid) {
1271         synchronized (this) {
1272             mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
1273             mHistoryCur.wakelockTag.string = historyName != null ? historyName : "";
1274             mHistoryCur.wakelockTag.uid = uid;
1275             recordStateStopEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
1276         }
1277     }
1278 
1279     /**
1280      * Records an event when some state flag changes to true.
1281      */
recordStateStartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags)1282     public void recordStateStartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
1283         synchronized (this) {
1284             mHistoryCur.states |= stateFlags;
1285             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1286         }
1287     }
1288 
1289     /**
1290      * Records an event when some state flag changes to true.
1291      */
recordStateStartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags, int uid, String name)1292     public void recordStateStartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags,
1293             int uid, String name) {
1294         synchronized (this) {
1295             mHistoryCur.states |= stateFlags;
1296             mHistoryCur.eventCode = EVENT_STATE_CHANGE | EVENT_FLAG_START;
1297             mHistoryCur.eventTag = mHistoryCur.localEventTag;
1298             mHistoryCur.eventTag.uid = uid;
1299             mHistoryCur.eventTag.string = name;
1300             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1301         }
1302     }
1303 
1304     /**
1305      * Records an event when some state flag changes to false.
1306      */
recordStateStopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags)1307     public void recordStateStopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
1308         synchronized (this) {
1309             mHistoryCur.states &= ~stateFlags;
1310             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1311         }
1312     }
1313 
1314     /**
1315      * Records an event when some state flag changes to false.
1316      */
recordStateStopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags, int uid, String name)1317     public void recordStateStopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags,
1318             int uid, String name) {
1319         synchronized (this) {
1320             mHistoryCur.states &= ~stateFlags;
1321             mHistoryCur.eventCode = EVENT_STATE_CHANGE | EVENT_FLAG_FINISH;
1322             mHistoryCur.eventTag = mHistoryCur.localEventTag;
1323             mHistoryCur.eventTag.uid = uid;
1324             mHistoryCur.eventTag.string = name;
1325             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1326         }
1327     }
1328 
1329     /**
1330      * Records an event when some state flags change to true and some to false.
1331      */
recordStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int stateStartFlags, int stateStopFlags)1332     public void recordStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int stateStartFlags,
1333             int stateStopFlags) {
1334         synchronized (this) {
1335             mHistoryCur.states = (mHistoryCur.states | stateStartFlags) & ~stateStopFlags;
1336             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1337         }
1338     }
1339 
1340     /**
1341      * Records an event when some state2 flag changes to true.
1342      */
recordState2StartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags)1343     public void recordState2StartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
1344         synchronized (this) {
1345             mHistoryCur.states2 |= stateFlags;
1346             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1347         }
1348     }
1349 
1350     /**
1351      * Records an event when some state2 flag changes to true.
1352      */
recordState2StartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags, int uid, String name)1353     public void recordState2StartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags,
1354             int uid, String name) {
1355         synchronized (this) {
1356             mHistoryCur.states2 |= stateFlags;
1357             mHistoryCur.eventCode = EVENT_STATE_CHANGE | EVENT_FLAG_START;
1358             mHistoryCur.eventTag = mHistoryCur.localEventTag;
1359             mHistoryCur.eventTag.uid = uid;
1360             mHistoryCur.eventTag.string = name;
1361             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1362         }
1363     }
1364 
1365     /**
1366      * Records an event when some state2 flag changes to false.
1367      */
recordState2StopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags, int uid, String name)1368     public void recordState2StopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags,
1369             int uid, String name) {
1370         synchronized (this) {
1371             mHistoryCur.states2 &= ~stateFlags;
1372             mHistoryCur.eventCode = EVENT_STATE_CHANGE | EVENT_FLAG_FINISH;
1373             mHistoryCur.eventTag = mHistoryCur.localEventTag;
1374             mHistoryCur.eventTag.uid = uid;
1375             mHistoryCur.eventTag.string = name;
1376             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1377         }
1378     }
1379 
1380     /**
1381      * Records an event when some state2 flag changes to false.
1382      */
recordState2StopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags)1383     public void recordState2StopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
1384         synchronized (this) {
1385             mHistoryCur.states2 &= ~stateFlags;
1386             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1387         }
1388     }
1389 
1390     /**
1391      * Records an wakeup event.
1392      */
recordWakeupEvent(long elapsedRealtimeMs, long uptimeMs, String reason)1393     public void recordWakeupEvent(long elapsedRealtimeMs, long uptimeMs, String reason) {
1394         synchronized (this) {
1395             mHistoryCur.wakeReasonTag = mHistoryCur.localWakeReasonTag;
1396             mHistoryCur.wakeReasonTag.string = reason;
1397             mHistoryCur.wakeReasonTag.uid = 0;
1398             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1399         }
1400     }
1401 
1402     /**
1403      * Records a screen brightness change event.
1404      */
recordScreenBrightnessEvent(long elapsedRealtimeMs, long uptimeMs, int brightnessBin)1405     public void recordScreenBrightnessEvent(long elapsedRealtimeMs, long uptimeMs,
1406             int brightnessBin) {
1407         synchronized (this) {
1408             mHistoryCur.states = setBitField(mHistoryCur.states, brightnessBin,
1409                     HistoryItem.STATE_BRIGHTNESS_SHIFT,
1410                     HistoryItem.STATE_BRIGHTNESS_MASK);
1411             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1412         }
1413     }
1414 
1415     /**
1416      * Records a GNSS signal level change event.
1417      */
recordGpsSignalQualityEvent(long elapsedRealtimeMs, long uptimeMs, int signalLevel)1418     public void recordGpsSignalQualityEvent(long elapsedRealtimeMs, long uptimeMs,
1419             int signalLevel) {
1420         synchronized (this) {
1421             mHistoryCur.states2 = setBitField(mHistoryCur.states2, signalLevel,
1422                     HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT,
1423                     HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK);
1424             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1425         }
1426     }
1427 
1428     /**
1429      * Records a device idle mode change event.
1430      */
recordDeviceIdleEvent(long elapsedRealtimeMs, long uptimeMs, int mode)1431     public void recordDeviceIdleEvent(long elapsedRealtimeMs, long uptimeMs, int mode) {
1432         synchronized (this) {
1433             mHistoryCur.states2 = setBitField(mHistoryCur.states2, mode,
1434                     HistoryItem.STATE2_DEVICE_IDLE_SHIFT,
1435                     HistoryItem.STATE2_DEVICE_IDLE_MASK);
1436             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1437         }
1438     }
1439 
1440     /**
1441      * Records a telephony state change event.
1442      */
recordPhoneStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int addStateFlag, int removeStateFlag, int state, int signalStrength)1443     public void recordPhoneStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int addStateFlag,
1444             int removeStateFlag, int state, int signalStrength) {
1445         synchronized (this) {
1446             mHistoryCur.states = (mHistoryCur.states | addStateFlag) & ~removeStateFlag;
1447             if (state != -1) {
1448                 mHistoryCur.states =
1449                         setBitField(mHistoryCur.states, state,
1450                                 HistoryItem.STATE_PHONE_STATE_SHIFT,
1451                                 HistoryItem.STATE_PHONE_STATE_MASK);
1452             }
1453             if (signalStrength != -1) {
1454                 mHistoryCur.states =
1455                         setBitField(mHistoryCur.states, signalStrength,
1456                                 HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT,
1457                                 HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK);
1458             }
1459             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1460         }
1461     }
1462 
1463     /**
1464      * Records a data connection type change event.
1465      */
recordDataConnectionTypeChangeEvent(long elapsedRealtimeMs, long uptimeMs, int dataConnectionType)1466     public void recordDataConnectionTypeChangeEvent(long elapsedRealtimeMs, long uptimeMs,
1467             int dataConnectionType) {
1468         synchronized (this) {
1469             mHistoryCur.states = setBitField(mHistoryCur.states, dataConnectionType,
1470                     HistoryItem.STATE_DATA_CONNECTION_SHIFT,
1471                     HistoryItem.STATE_DATA_CONNECTION_MASK);
1472             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1473         }
1474     }
1475 
1476     /**
1477      * Records a data connection type change event.
1478      */
recordNrStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int nrState)1479     public void recordNrStateChangeEvent(long elapsedRealtimeMs, long uptimeMs,
1480             int nrState) {
1481         synchronized (this) {
1482             mHistoryCur.states2 = setBitField(mHistoryCur.states2, nrState,
1483                     HistoryItem.STATE2_NR_STATE_SHIFT,
1484                     HistoryItem.STATE2_NR_STATE_MASK);
1485             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1486         }
1487     }
1488 
1489     /**
1490      * Records a WiFi supplicant state change event.
1491      */
recordWifiSupplicantStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int supplState)1492     public void recordWifiSupplicantStateChangeEvent(long elapsedRealtimeMs, long uptimeMs,
1493             int supplState) {
1494         synchronized (this) {
1495             mHistoryCur.states2 =
1496                     setBitField(mHistoryCur.states2, supplState,
1497                             HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT,
1498                             HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK);
1499             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1500         }
1501     }
1502 
1503     /**
1504      * Records a WiFi signal strength change event.
1505      */
recordWifiSignalStrengthChangeEvent(long elapsedRealtimeMs, long uptimeMs, int strengthBin)1506     public void recordWifiSignalStrengthChangeEvent(long elapsedRealtimeMs, long uptimeMs,
1507             int strengthBin) {
1508         synchronized (this) {
1509             mHistoryCur.states2 =
1510                     setBitField(mHistoryCur.states2, strengthBin,
1511                             HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT,
1512                             HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK);
1513             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1514         }
1515     }
1516 
1517     /**
1518      * Writes event details into Atrace.
1519      */
recordTraceEvents(int code, HistoryTag tag)1520     private void recordTraceEvents(int code, HistoryTag tag) {
1521         if (code == HistoryItem.EVENT_NONE) return;
1522 
1523         final int idx = code & HistoryItem.EVENT_TYPE_MASK;
1524         final String prefix = (code & HistoryItem.EVENT_FLAG_START) != 0 ? "+" :
1525                 (code & HistoryItem.EVENT_FLAG_FINISH) != 0 ? "-" : "";
1526 
1527         final String[] names = BatteryStats.HISTORY_EVENT_NAMES;
1528         if (idx < 0 || idx >= names.length) return;
1529 
1530         final String track = "battery_stats." + names[idx];
1531         final String name = prefix + names[idx] + "=" + tag.uid + ":\"" + tag.string + "\"";
1532         mTracer.traceInstantEvent(track, name);
1533     }
1534 
1535     /**
1536      * Writes changes to a HistoryItem state bitmap to Atrace.
1537      */
recordTraceCounters(int oldval, int newval, int mask, BitDescription[] descriptions)1538     private void recordTraceCounters(int oldval, int newval, int mask,
1539             BitDescription[] descriptions) {
1540         int diff = (oldval ^ newval) & mask;
1541         if (diff == 0) return;
1542 
1543         for (int i = 0; i < descriptions.length; i++) {
1544             BitDescription bd = descriptions[i];
1545             if ((diff & bd.mask) == 0) continue;
1546 
1547             int value;
1548             if (bd.shift < 0) {
1549                 value = (newval & bd.mask) != 0 ? 1 : 0;
1550             } else {
1551                 value = (newval & bd.mask) >> bd.shift;
1552             }
1553             mTracer.traceCounter("battery_stats." + bd.name, value);
1554         }
1555     }
1556 
setBitField(int bits, int value, int shift, int mask)1557     private int setBitField(int bits, int value, int shift, int mask) {
1558         int shiftedValue = value << shift;
1559         if ((shiftedValue & ~mask) != 0) {
1560             Slog.wtfStack(TAG, "Value " + Integer.toHexString(value)
1561                     + " does not fit in the bit field: " + Integer.toHexString(mask));
1562             shiftedValue &= mask;
1563         }
1564         return (bits & ~mask) | shiftedValue;
1565     }
1566 
1567     /**
1568      * Records an update containing HistoryStepDetails, except if the details are empty.
1569      */
recordHistoryStepDetails(HistoryStepDetails details, long elapsedRealtimeMs, long uptimeMs)1570     public void recordHistoryStepDetails(HistoryStepDetails details, long elapsedRealtimeMs,
1571             long uptimeMs) {
1572         if (details.isEmpty()) {
1573             return;
1574         }
1575         synchronized (this) {
1576             mHistoryCur.stepDetails = details;
1577             writeHistoryItem(elapsedRealtimeMs, uptimeMs);
1578             mHistoryCur.stepDetails = null;
1579         }
1580     }
1581 
1582     /**
1583      * Writes the current history item to history.
1584      */
writeHistoryItem(long elapsedRealtimeMs, long uptimeMs)1585     public void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs) {
1586         synchronized (this) {
1587             if (mTrackRunningHistoryElapsedRealtimeMs != 0) {
1588                 final long diffElapsedMs =
1589                         elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtimeMs;
1590                 final long diffUptimeMs = uptimeMs - mTrackRunningHistoryUptimeMs;
1591                 if (diffUptimeMs < (diffElapsedMs - 20)) {
1592                     final long wakeElapsedTimeMs =
1593                             elapsedRealtimeMs - (diffElapsedMs - diffUptimeMs);
1594                     mHistoryAddTmp.setTo(mHistoryLastWritten);
1595                     mHistoryAddTmp.wakelockTag = null;
1596                     mHistoryAddTmp.wakeReasonTag = null;
1597                     mHistoryAddTmp.powerStats = null;
1598                     mHistoryAddTmp.processStateChange = null;
1599                     mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE;
1600                     mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG;
1601                     mHistoryAddTmp.stepDetails = null;
1602                     writeHistoryItem(wakeElapsedTimeMs, uptimeMs, mHistoryAddTmp);
1603                 }
1604             }
1605             mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG;
1606             mTrackRunningHistoryElapsedRealtimeMs = elapsedRealtimeMs;
1607             mTrackRunningHistoryUptimeMs = uptimeMs;
1608             writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur);
1609         }
1610     }
1611 
1612     @GuardedBy("this")
writeHistoryItem(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur)1613     private void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
1614         if (cur.eventCode != HistoryItem.EVENT_NONE && cur.eventTag.string == null) {
1615             Slog.wtfStack(TAG, "Event " + Integer.toHexString(cur.eventCode) + " without a name");
1616         }
1617 
1618         if (mTracer != null && mTracer.tracingEnabled()) {
1619             recordTraceEvents(cur.eventCode, cur.eventTag);
1620             recordTraceCounters(mTraceLastState, cur.states, STATE1_TRACE_MASK,
1621                     BatteryStats.HISTORY_STATE_DESCRIPTIONS);
1622             recordTraceCounters(mTraceLastState2, cur.states2, STATE2_TRACE_MASK,
1623                     BatteryStats.HISTORY_STATE2_DESCRIPTIONS);
1624             mTraceLastState = cur.states;
1625             mTraceLastState2 = cur.states2;
1626         }
1627 
1628         if ((!mHaveBatteryLevel || !mRecordingHistory)
1629                 && cur.powerStats == null
1630                 && cur.processStateChange == null) {
1631             return;
1632         }
1633 
1634         if (!mMutable) {
1635             throw new ConcurrentModificationException("Battery history is not writable");
1636         }
1637 
1638         final long timeDiffMs = mMonotonicClock.monotonicTime(elapsedRealtimeMs)
1639                 - mHistoryLastWritten.time;
1640         final int diffStates = mHistoryLastWritten.states ^ cur.states;
1641         final int diffStates2 = mHistoryLastWritten.states2 ^ cur.states2;
1642         final int lastDiffStates = mHistoryLastWritten.states ^ mHistoryLastLastWritten.states;
1643         final int lastDiffStates2 = mHistoryLastWritten.states2 ^ mHistoryLastLastWritten.states2;
1644         if (DEBUG) {
1645             Slog.i(TAG, "ADD: tdelta=" + timeDiffMs + " diff="
1646                     + Integer.toHexString(diffStates) + " lastDiff="
1647                     + Integer.toHexString(lastDiffStates) + " diff2="
1648                     + Integer.toHexString(diffStates2) + " lastDiff2="
1649                     + Integer.toHexString(lastDiffStates2));
1650         }
1651 
1652         if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
1653                 && timeDiffMs < 1000 && (diffStates & lastDiffStates) == 0
1654                 && (diffStates2 & lastDiffStates2) == 0
1655                 && (!mHistoryLastWritten.tagsFirstOccurrence && !cur.tagsFirstOccurrence)
1656                 && (mHistoryLastWritten.wakelockTag == null || cur.wakelockTag == null)
1657                 && (mHistoryLastWritten.wakeReasonTag == null || cur.wakeReasonTag == null)
1658                 && mHistoryLastWritten.stepDetails == null
1659                 && (mHistoryLastWritten.eventCode == HistoryItem.EVENT_NONE
1660                 || cur.eventCode == HistoryItem.EVENT_NONE)
1661                 && mHistoryLastWritten.batteryLevel == cur.batteryLevel
1662                 && mHistoryLastWritten.batteryStatus == cur.batteryStatus
1663                 && mHistoryLastWritten.batteryHealth == cur.batteryHealth
1664                 && mHistoryLastWritten.batteryPlugType == cur.batteryPlugType
1665                 && mHistoryLastWritten.batteryTemperature == cur.batteryTemperature
1666                 && mHistoryLastWritten.batteryVoltage == cur.batteryVoltage
1667                 && mHistoryLastWritten.powerStats == null
1668                 && mHistoryLastWritten.processStateChange == null) {
1669             // We can merge this new change in with the last one.  Merging is
1670             // allowed as long as only the states have changed, and within those states
1671             // as long as no bit has changed both between now and the last entry, as
1672             // well as the last entry and the one before it (so we capture any toggles).
1673             if (DEBUG) Slog.i(TAG, "ADD: rewinding back to " + mHistoryBufferLastPos);
1674             mMonotonicHistorySize -= (mHistoryBuffer.dataSize() - mHistoryBufferLastPos);
1675             mHistoryBuffer.setDataSize(mHistoryBufferLastPos);
1676             mHistoryBuffer.setDataPosition(mHistoryBufferLastPos);
1677             mHistoryBufferLastPos = -1;
1678 
1679             elapsedRealtimeMs -= timeDiffMs;
1680 
1681             // If the last written history had a wakelock tag, we need to retain it.
1682             // Note that the condition above made sure that we aren't in a case where
1683             // both it and the current history item have a wakelock tag.
1684             if (mHistoryLastWritten.wakelockTag != null) {
1685                 cur.wakelockTag = cur.localWakelockTag;
1686                 cur.wakelockTag.setTo(mHistoryLastWritten.wakelockTag);
1687             }
1688             // If the last written history had a wake reason tag, we need to retain it.
1689             // Note that the condition above made sure that we aren't in a case where
1690             // both it and the current history item have a wakelock tag.
1691             if (mHistoryLastWritten.wakeReasonTag != null) {
1692                 cur.wakeReasonTag = cur.localWakeReasonTag;
1693                 cur.wakeReasonTag.setTo(mHistoryLastWritten.wakeReasonTag);
1694             }
1695             // If the last written history had an event, we need to retain it.
1696             // Note that the condition above made sure that we aren't in a case where
1697             // both it and the current history item have an event.
1698             if (mHistoryLastWritten.eventCode != HistoryItem.EVENT_NONE) {
1699                 cur.eventCode = mHistoryLastWritten.eventCode;
1700                 cur.eventTag = cur.localEventTag;
1701                 cur.eventTag.setTo(mHistoryLastWritten.eventTag);
1702             }
1703             mHistoryLastWritten.setTo(mHistoryLastLastWritten);
1704         }
1705 
1706         if (maybeFlushBufferAndWriteHistoryItem(cur, elapsedRealtimeMs, uptimeMs)) {
1707             return;
1708         }
1709 
1710         if (mHistoryBuffer.dataSize() == 0) {
1711             // The history is currently empty; we need it to start with a time stamp.
1712             HistoryItem copy = new HistoryItem();
1713             copy.setTo(cur);
1714             copy.currentTime = mClock.currentTimeMillis();
1715             copy.wakelockTag = null;
1716             copy.wakeReasonTag = null;
1717             copy.eventCode = HistoryItem.EVENT_NONE;
1718             copy.eventTag = null;
1719             copy.tagsFirstOccurrence = false;
1720             copy.powerStats = null;
1721             copy.processStateChange = null;
1722             writeHistoryItem(elapsedRealtimeMs, uptimeMs, copy, HistoryItem.CMD_RESET);
1723         }
1724         writeHistoryItem(elapsedRealtimeMs, uptimeMs, cur, HistoryItem.CMD_UPDATE);
1725     }
1726 
1727     @GuardedBy("this")
maybeFlushBufferAndWriteHistoryItem(HistoryItem cur, long elapsedRealtimeMs, long uptimeMs)1728     private boolean maybeFlushBufferAndWriteHistoryItem(HistoryItem cur, long elapsedRealtimeMs,
1729             long uptimeMs) {
1730         int dataSize = mHistoryBuffer.dataSize();
1731         if (dataSize < mMaxHistoryBufferSize) {
1732             return false;
1733         }
1734 
1735         if (mMaxHistoryBufferSize == 0) {
1736             Slog.wtf(TAG, "mMaxHistoryBufferSize should not be zero when writing history");
1737             mMaxHistoryBufferSize = 1024;
1738         }
1739 
1740         boolean successfullyLocked = mStore.tryLock();
1741         if (!successfullyLocked) {      // Already locked by another thread
1742             // If the buffer size is below the allowed overflow limit, just keep going
1743             if (dataSize < mMaxHistoryBufferSize + EXTRA_BUFFER_SIZE_WHEN_DIR_LOCKED) {
1744                 return false;
1745             }
1746 
1747             // Report the long contention as a WTF and flush the buffer anyway, potentially
1748             // triggering a watchdog kill, which is still better than spinning forever.
1749             Slog.wtf(TAG, "History buffer overflow exceeds " + EXTRA_BUFFER_SIZE_WHEN_DIR_LOCKED
1750                     + " bytes");
1751         }
1752 
1753         // Make a copy of mHistoryCur before starting a new file
1754         HistoryItem copy = new HistoryItem();
1755         copy.setTo(cur);
1756 
1757         try {
1758             startNextFragment(elapsedRealtimeMs);
1759         } finally {
1760             if (successfullyLocked) {
1761                 mStore.unlock();
1762             }
1763         }
1764 
1765         // startRecordingHistory will reset mHistoryCur.
1766         startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
1767 
1768         // Add the copy into history buffer.
1769         writeHistoryItem(elapsedRealtimeMs, uptimeMs, copy, HistoryItem.CMD_UPDATE);
1770         return true;
1771     }
1772 
1773     @GuardedBy("this")
writeHistoryItem(long elapsedRealtimeMs, @SuppressWarnings("UnusedVariable") long uptimeMs, HistoryItem cur, byte cmd)1774     private void writeHistoryItem(long elapsedRealtimeMs,
1775             @SuppressWarnings("UnusedVariable") long uptimeMs, HistoryItem cur, byte cmd) {
1776         if (!mMutable) {
1777             throw new ConcurrentModificationException("Battery history is not writable");
1778         }
1779         mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
1780         mHistoryLastLastWritten.setTo(mHistoryLastWritten);
1781         final boolean hasTags = mHistoryLastWritten.tagsFirstOccurrence || cur.tagsFirstOccurrence;
1782         mHistoryLastWritten.setTo(mMonotonicClock.monotonicTime(elapsedRealtimeMs), cmd, cur);
1783         if (mHistoryLastWritten.time < mHistoryLastLastWritten.time - 60000) {
1784             Slog.wtf(TAG, "Significantly earlier event written to battery history:"
1785                     + " time=" + mHistoryLastWritten.time
1786                     + " previous=" + mHistoryLastLastWritten.time);
1787         }
1788         mHistoryLastWritten.tagsFirstOccurrence = hasTags;
1789         writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);
1790         mMonotonicHistorySize += (mHistoryBuffer.dataSize() - mHistoryBufferLastPos);
1791         cur.wakelockTag = null;
1792         cur.wakeReasonTag = null;
1793         cur.eventCode = HistoryItem.EVENT_NONE;
1794         cur.eventTag = null;
1795         cur.tagsFirstOccurrence = false;
1796         cur.powerStats = null;
1797         cur.processStateChange = null;
1798         if (DEBUG) {
1799             Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
1800                     + " now " + mHistoryBuffer.dataPosition()
1801                     + " size is now " + mHistoryBuffer.dataSize());
1802         }
1803     }
1804 
1805     /*
1806         The history delta format uses flags to denote further data in subsequent ints in the parcel.
1807 
1808         There is always the first token, which may contain the delta time, or an indicator of
1809         the length of the time (int or long) following this token.
1810 
1811         First token: always present,
1812         31              23              15               7             0
1813         █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█
1814 
1815         T: the delta time if it is <= 0x7fffd. Otherwise 0x7fffe indicates an int immediately
1816            follows containing the time, and 0x7ffff indicates a long immediately follows with the
1817            delta time.
1818         A: battery level changed and an int follows with battery data.
1819         B: state changed and an int follows with state change data.
1820         C: state2 has changed and an int follows with state2 change data.
1821         D: wakelock/wakereason has changed and an wakelock/wakereason struct follows.
1822         E: event data has changed and an event struct follows.
1823         F: battery charge in coulombs has changed and an int with the charge follows.
1824         G: state flag denoting that the mobile radio was active.
1825         H: state flag denoting that the wifi radio was active.
1826         I: state flag denoting that a wifi scan occurred.
1827         J: state flag denoting that a wifi full lock was held.
1828         K: state flag denoting that the gps was on.
1829         L: state flag denoting that a wakelock was held.
1830         M: state flag denoting that the cpu was running.
1831 
1832         Time int/long: if T in the first token is 0x7ffff or 0x7fffe, then an int or long follows
1833         with the time delta.
1834 
1835         Battery level int: if A in the first token is set,
1836         31              23              15               7             0
1837         █L|L|L|L|L|L|L|L█T|T|T|T|T|T|T|T█T|V|V|V|V|V|V|V█V|V|V|V|V|V|E|D█
1838 
1839         D: indicates that extra history details follow.
1840         E: indicates that the voltage delta or temperature delta is too large to fit in the
1841            respective V or T field of this int. If this flag is set, an extended battery level
1842            int containing the complete voltage and temperature values immediately follows.
1843         V: the signed battery voltage delta in millivolts.
1844         T: the signed battery temperature delta in tenths of a degree Celsius.
1845         L: the signed battery level delta (out of 100).
1846 
1847         Extended battery level int: if E in the battery level int is set,
1848         31              23              15               7             0
1849         █T|T|T|T|T|T|T|T█T|T|T|T|T|T|T|T█V|V|V|V|V|V|V|V█V|V|V|V|V|V|V|V█
1850 
1851         V: the current battery voltage (complete 16-bit value, not a delta).
1852         T: the current battery temperature (complete 16-bit value, not a delta).
1853 
1854         State change int: if B in the first token is set,
1855         31              23              15               7             0
1856         █S|S|S|H|H|H|P|P█F|E|D|C|B| | |A█ | | | | | | | █ | | | | | | | █
1857 
1858         A: wifi multicast was on.
1859         B: battery was plugged in.
1860         C: screen was on.
1861         D: phone was scanning for signal.
1862         E: audio was on.
1863         F: a sensor was active.
1864 
1865         State2 change int: if C in the first token is set,
1866         31              23              15               7             0
1867         █M|L|K|J|I|H|H|G█F|E|D|C| | | | █ | | | | |O|O|N█N|B|B|B|A|A|A|A█
1868 
1869         A: 4 bits indicating the wifi supplicant state: {@link BatteryStats#WIFI_SUPPL_STATE_NAMES}.
1870         B: 3 bits indicating the wifi signal strength: 0, 1, 2, 3, 4.
1871         C: a bluetooth scan was active.
1872         D: the camera was active.
1873         E: bluetooth was on.
1874         F: a phone call was active.
1875         G: the device was charging.
1876         H: 2 bits indicating the device-idle (doze) state: off, light, full
1877         I: the flashlight was on.
1878         J: wifi was on.
1879         K: wifi was running.
1880         L: video was playing.
1881         M: power save mode was on.
1882         N: 2 bits indicating the gps signal strength: poor, good, none.
1883         O: 2 bits indicating nr state: none, restricted, not restricted, connected.
1884 
1885         Wakelock/wakereason struct: if D in the first token is set,
1886         Event struct: if E in the first token is set,
1887         History step details struct: if D in the battery level int is set,
1888 
1889         Battery charge int: if F in the first token is set, an int representing the battery charge
1890         in coulombs follows.
1891      */
1892 
1893     /**
1894      * Writes the delta between the previous and current history items into history buffer.
1895      */
1896     @GuardedBy("this")
writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last)1897     private void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
1898         mHistoryMonotonicEndTime = cur.time;
1899 
1900         if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
1901             dest.writeInt(BatteryStatsHistory.DELTA_TIME_ABS);
1902             cur.writeToParcel(dest, 0);
1903             return;
1904         }
1905 
1906         int extensionFlags = 0;
1907         final long deltaTime = cur.time - last.time;
1908         int batteryLevelInt = buildBatteryLevelInt(cur, last);
1909         final int lastStateInt = buildStateInt(last);
1910 
1911         int deltaTimeToken;
1912         if (deltaTime < 0 || deltaTime > Integer.MAX_VALUE) {
1913             deltaTimeToken = BatteryStatsHistory.DELTA_TIME_LONG;
1914         } else if (deltaTime >= BatteryStatsHistory.DELTA_TIME_ABS) {
1915             deltaTimeToken = BatteryStatsHistory.DELTA_TIME_INT;
1916         } else {
1917             deltaTimeToken = (int) deltaTime;
1918         }
1919         int firstToken = deltaTimeToken | (cur.states & BatteryStatsHistory.DELTA_STATE_MASK);
1920 
1921         if (cur.stepDetails != null) {
1922             batteryLevelInt |= BatteryStatsHistory.BATTERY_LEVEL_DETAILS_FLAG;
1923         }
1924 
1925         final boolean batteryLevelIntChanged = batteryLevelInt != 0;
1926         if (batteryLevelIntChanged) {
1927             firstToken |= BatteryStatsHistory.DELTA_BATTERY_LEVEL_FLAG;
1928         }
1929         final int stateInt = buildStateInt(cur);
1930         final boolean stateIntChanged = stateInt != lastStateInt;
1931         if (stateIntChanged) {
1932             firstToken |= BatteryStatsHistory.DELTA_STATE_FLAG;
1933         }
1934         if (cur.powerStats != null) {
1935             extensionFlags |= BatteryStatsHistory.EXTENSION_POWER_STATS_FLAG;
1936             if (!mWrittenPowerStatsDescriptors.contains(cur.powerStats.descriptor)) {
1937                 extensionFlags |= BatteryStatsHistory.EXTENSION_POWER_STATS_DESCRIPTOR_FLAG;
1938             }
1939         }
1940         if (cur.processStateChange != null) {
1941             extensionFlags |= BatteryStatsHistory.EXTENSION_PROCESS_STATE_CHANGE_FLAG;
1942         }
1943         if (extensionFlags != 0) {
1944             cur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
1945         } else {
1946             cur.states2 &= ~HistoryItem.STATE2_EXTENSIONS_FLAG;
1947         }
1948         final boolean state2IntChanged = cur.states2 != last.states2 || extensionFlags != 0;
1949         if (state2IntChanged) {
1950             firstToken |= BatteryStatsHistory.DELTA_STATE2_FLAG;
1951         }
1952         if (cur.wakelockTag != null || cur.wakeReasonTag != null) {
1953             firstToken |= BatteryStatsHistory.DELTA_WAKELOCK_FLAG;
1954         }
1955         if (cur.eventCode != HistoryItem.EVENT_NONE) {
1956             firstToken |= BatteryStatsHistory.DELTA_EVENT_FLAG;
1957         }
1958 
1959         final boolean batteryChargeChanged = cur.batteryChargeUah != last.batteryChargeUah;
1960         if (batteryChargeChanged) {
1961             firstToken |= BatteryStatsHistory.DELTA_BATTERY_CHARGE_FLAG;
1962         }
1963         dest.writeInt(firstToken);
1964         if (DEBUG) {
1965             Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken)
1966                     + " deltaTime=" + deltaTime);
1967         }
1968 
1969         if (deltaTimeToken >= BatteryStatsHistory.DELTA_TIME_INT) {
1970             if (deltaTimeToken == BatteryStatsHistory.DELTA_TIME_INT) {
1971                 if (DEBUG) Slog.i(TAG, "WRITE DELTA: int deltaTime=" + (int) deltaTime);
1972                 dest.writeInt((int) deltaTime);
1973             } else {
1974                 if (DEBUG) Slog.i(TAG, "WRITE DELTA: long deltaTime=" + deltaTime);
1975                 dest.writeLong(deltaTime);
1976             }
1977         }
1978         if (batteryLevelIntChanged) {
1979             boolean overflow = (batteryLevelInt & BATTERY_LEVEL_OVERFLOW_FLAG) != 0;
1980             int extendedBatteryLevelInt = 0;
1981 
1982             dest.writeInt(batteryLevelInt);
1983             if (overflow) {
1984                 extendedBatteryLevelInt = buildExtendedBatteryLevelInt(cur);
1985                 dest.writeInt(extendedBatteryLevelInt);
1986             }
1987 
1988             if (DEBUG) {
1989                 Slog.i(TAG, "WRITE DELTA: batteryToken=0x"
1990                         + Integer.toHexString(batteryLevelInt)
1991                         + (overflow
1992                                 ? " batteryToken2=0x" + Integer.toHexString(extendedBatteryLevelInt)
1993                                 : "")
1994                         + " batteryLevel=" + cur.batteryLevel
1995                         + " batteryTemp=" + cur.batteryTemperature
1996                         + " batteryVolt=" + (int) cur.batteryVoltage);
1997             }
1998         }
1999         if (stateIntChanged) {
2000             dest.writeInt(stateInt);
2001             if (DEBUG) {
2002                 Slog.i(TAG, "WRITE DELTA: stateToken=0x"
2003                         + Integer.toHexString(stateInt)
2004                         + " batteryStatus=" + cur.batteryStatus
2005                         + " batteryHealth=" + cur.batteryHealth
2006                         + " batteryPlugType=" + cur.batteryPlugType
2007                         + " states=0x" + Integer.toHexString(cur.states));
2008             }
2009         }
2010         if (state2IntChanged) {
2011             dest.writeInt(cur.states2);
2012             if (DEBUG) {
2013                 Slog.i(TAG, "WRITE DELTA: states2=0x"
2014                         + Integer.toHexString(cur.states2));
2015             }
2016         }
2017         cur.tagsFirstOccurrence = false;
2018         if (cur.wakelockTag != null || cur.wakeReasonTag != null) {
2019             int wakeLockIndex;
2020             int wakeReasonIndex;
2021             if (cur.wakelockTag != null) {
2022                 wakeLockIndex = writeHistoryTag(cur.wakelockTag);
2023                 if (DEBUG) {
2024                     Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
2025                             + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
2026                 }
2027             } else {
2028                 wakeLockIndex = 0xffff;
2029             }
2030             if (cur.wakeReasonTag != null) {
2031                 wakeReasonIndex = writeHistoryTag(cur.wakeReasonTag);
2032                 if (DEBUG) {
2033                     Slog.i(TAG, "WRITE DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx
2034                             + " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string);
2035                 }
2036             } else {
2037                 wakeReasonIndex = 0xffff;
2038             }
2039             dest.writeInt((wakeReasonIndex << 16) | wakeLockIndex);
2040             if (cur.wakelockTag != null
2041                     && (wakeLockIndex & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) {
2042                 cur.wakelockTag.writeToParcel(dest, 0);
2043                 cur.tagsFirstOccurrence = true;
2044             }
2045             if (cur.wakeReasonTag != null
2046                     && (wakeReasonIndex & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) {
2047                 cur.wakeReasonTag.writeToParcel(dest, 0);
2048                 cur.tagsFirstOccurrence = true;
2049             }
2050         }
2051         if (cur.eventCode != HistoryItem.EVENT_NONE) {
2052             final int index = writeHistoryTag(cur.eventTag);
2053             final int codeAndIndex = setBitField(cur.eventCode & 0xffff, index, 16, 0xFFFF0000);
2054             dest.writeInt(codeAndIndex);
2055             if ((index & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) {
2056                 cur.eventTag.writeToParcel(dest, 0);
2057                 cur.tagsFirstOccurrence = true;
2058             }
2059             if (DEBUG) {
2060                 Slog.i(TAG, "WRITE DELTA: event=" + cur.eventCode + " tag=#"
2061                         + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
2062                         + cur.eventTag.string);
2063             }
2064         }
2065 
2066         if (cur.stepDetails != null) {
2067             cur.stepDetails.writeToParcel(dest);
2068         }
2069 
2070         if (batteryChargeChanged) {
2071             if (DEBUG) Slog.i(TAG, "WRITE DELTA: batteryChargeUah=" + cur.batteryChargeUah);
2072             dest.writeInt(cur.batteryChargeUah);
2073         }
2074         dest.writeDouble(cur.modemRailChargeMah);
2075         dest.writeDouble(cur.wifiRailChargeMah);
2076         if (extensionFlags != 0) {
2077             dest.writeInt(extensionFlags);
2078             if (cur.powerStats != null) {
2079                 if ((extensionFlags & BatteryStatsHistory.EXTENSION_POWER_STATS_DESCRIPTOR_FLAG)
2080                         != 0) {
2081                     cur.powerStats.descriptor.writeSummaryToParcel(dest);
2082                     mWrittenPowerStatsDescriptors.add(cur.powerStats.descriptor);
2083                 }
2084                 cur.powerStats.writeToParcel(dest);
2085             }
2086             if (cur.processStateChange != null) {
2087                 cur.processStateChange.writeToParcel(dest);
2088             }
2089         }
2090     }
2091 
signedValueFits(int value, int mask, int shift)2092     private boolean signedValueFits(int value, int mask, int shift) {
2093         mask >>>= shift;
2094         // The original value can only be restored if all of the lost
2095         // high-order bits match the MSB of the packed value. Extract both the
2096         // MSB and the lost bits, and check if they match (i.e. they are all
2097         // zeros or all ones).
2098         int msbAndLostBitsMask = ~(mask >>> 1);
2099         int msbAndLostBits = value & msbAndLostBitsMask;
2100 
2101         return msbAndLostBits == 0 || msbAndLostBits == msbAndLostBitsMask;
2102     }
2103 
buildBatteryLevelInt(HistoryItem cur, HistoryItem prev)2104     private int buildBatteryLevelInt(HistoryItem cur, HistoryItem prev) {
2105         final int levelDelta = (int) cur.batteryLevel - (int) prev.batteryLevel;
2106         final int tempDelta = (int) cur.batteryTemperature - (int) prev.batteryTemperature;
2107         final int voltDelta = (int) cur.batteryVoltage - (int) prev.batteryVoltage;
2108         final boolean overflow =
2109                 !signedValueFits(tempDelta, BATTERY_LEVEL_TEMP_MASK, BATTERY_LEVEL_VOLT_SHIFT)
2110                 || !signedValueFits(voltDelta, BATTERY_LEVEL_VOLT_MASK, BATTERY_LEVEL_TEMP_SHIFT);
2111 
2112         int batt = 0;
2113         batt |= (levelDelta << BATTERY_LEVEL_LEVEL_SHIFT) & BATTERY_LEVEL_LEVEL_MASK;
2114         if (overflow) {
2115             batt |= BATTERY_LEVEL_OVERFLOW_FLAG;
2116         } else {
2117             batt |= (tempDelta << BATTERY_LEVEL_TEMP_SHIFT) & BATTERY_LEVEL_TEMP_MASK;
2118             batt |= (voltDelta << BATTERY_LEVEL_VOLT_SHIFT) & BATTERY_LEVEL_VOLT_MASK;
2119         }
2120 
2121         return batt;
2122     }
2123 
buildExtendedBatteryLevelInt(HistoryItem cur)2124     private int buildExtendedBatteryLevelInt(HistoryItem cur) {
2125         int battExt = 0;
2126         battExt |= (cur.batteryTemperature << BATTERY_LEVEL2_TEMP_SHIFT) & BATTERY_LEVEL2_TEMP_MASK;
2127         battExt |= (cur.batteryVoltage << BATTERY_LEVEL2_VOLT_SHIFT) & BATTERY_LEVEL2_VOLT_MASK;
2128         return battExt;
2129     }
2130 
buildStateInt(HistoryItem h)2131     private int buildStateInt(HistoryItem h) {
2132         int plugType = 0;
2133         if ((h.batteryPlugType & BatteryManager.BATTERY_PLUGGED_AC) != 0) {
2134             plugType = 1;
2135         } else if ((h.batteryPlugType & BatteryManager.BATTERY_PLUGGED_USB) != 0) {
2136             plugType = 2;
2137         } else if ((h.batteryPlugType & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0) {
2138             plugType = 3;
2139         }
2140         return ((h.batteryStatus & BatteryStatsHistory.STATE_BATTERY_STATUS_MASK)
2141                 << BatteryStatsHistory.STATE_BATTERY_STATUS_SHIFT)
2142                 | ((h.batteryHealth & BatteryStatsHistory.STATE_BATTERY_HEALTH_MASK)
2143                 << BatteryStatsHistory.STATE_BATTERY_HEALTH_SHIFT)
2144                 | ((plugType & BatteryStatsHistory.STATE_BATTERY_PLUG_MASK)
2145                 << BatteryStatsHistory.STATE_BATTERY_PLUG_SHIFT)
2146                 | (h.states & (~BatteryStatsHistory.STATE_BATTERY_MASK));
2147     }
2148 
2149     /**
2150      * Returns the index for the specified tag. If this is the first time the tag is encountered
2151      * while writing the current history buffer, the method returns
2152      * <code>(index | TAG_FIRST_OCCURRENCE_FLAG)</code>
2153      */
2154     @GuardedBy("this")
writeHistoryTag(HistoryTag tag)2155     private int writeHistoryTag(HistoryTag tag) {
2156         if (tag.string == null) {
2157             Slog.wtfStack(TAG, "writeHistoryTag called with null name");
2158             tag.string = "";
2159         }
2160 
2161         final int stringLength = tag.string.length();
2162         if (stringLength > MAX_HISTORY_TAG_STRING_LENGTH) {
2163             Slog.e(TAG, "Long battery history tag: " + tag.string);
2164             tag.string = tag.string.substring(0, MAX_HISTORY_TAG_STRING_LENGTH);
2165         }
2166 
2167         Integer idxObj = mHistoryTagPool.get(tag);
2168         int idx;
2169         if (idxObj != null) {
2170             idx = idxObj;
2171             if ((idx & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) {
2172                 mHistoryTagPool.put(tag, idx & ~BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG);
2173             }
2174             return idx;
2175         } else if (mNextHistoryTagIdx < HISTORY_TAG_INDEX_LIMIT) {
2176             idx = mNextHistoryTagIdx;
2177             HistoryTag key = new HistoryTag();
2178             key.setTo(tag);
2179             tag.poolIdx = idx;
2180             mHistoryTagPool.put(key, idx);
2181             mNextHistoryTagIdx++;
2182 
2183             mNumHistoryTagChars += stringLength + 1;
2184             if (mHistoryTags != null) {
2185                 mHistoryTags.put(idx, key);
2186             }
2187             return idx | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG;
2188         } else {
2189             tag.poolIdx = HistoryTag.HISTORY_TAG_POOL_OVERFLOW;
2190             // Tag pool overflow: include the tag itself in the parcel
2191             return HISTORY_TAG_INDEX_LIMIT | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG;
2192         }
2193     }
2194 
2195     /**
2196      * Don't allow any more batching in to the current history event.
2197      */
commitCurrentHistoryBatchLocked()2198     public void commitCurrentHistoryBatchLocked() {
2199         synchronized (this) {
2200             mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
2201         }
2202     }
2203 
2204     /**
2205      * Saves the accumulated history buffer in the active file, see {@link #getActiveFragment()} .
2206      */
writeHistory()2207     public void writeHistory() {
2208         writeHistory(false /* fragmentComplete */);
2209     }
2210 
writeHistory(boolean fragmentComplete)2211     private void writeHistory(boolean fragmentComplete) {
2212         synchronized (this) {
2213             if (isReadOnly()) {
2214                 Slog.w(TAG, "writeHistory: this instance instance is read-only");
2215                 return;
2216             }
2217 
2218             // Save the monotonic time first, so that even if the history write below fails,
2219             // we still wouldn't end up with overlapping history timelines.
2220             mMonotonicClock.write();
2221 
2222             Parcel p = Parcel.obtain();
2223             try {
2224                 final long start = SystemClock.uptimeMillis();
2225                 writeHistoryBuffer(p);
2226                 if (DEBUG) {
2227                     Slog.d(TAG, "writeHistoryBuffer duration ms:"
2228                             + (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize());
2229                 }
2230                 writeParcelLocked(p, mActiveFragment, fragmentComplete);
2231             } finally {
2232                 p.recycle();
2233             }
2234         }
2235     }
2236 
2237     /**
2238      * Reads history buffer from a persisted Parcel.
2239      */
readHistoryBuffer(Parcel in)2240     public void readHistoryBuffer(Parcel in) throws ParcelFormatException {
2241         synchronized (this) {
2242             final int version = in.readInt();
2243             if (version != BatteryStatsHistory.VERSION) {
2244                 Slog.w("BatteryStats", "readHistoryBuffer: version got " + version
2245                         + ", expected " + BatteryStatsHistory.VERSION + "; erasing old stats");
2246                 return;
2247             }
2248 
2249             mHistoryBufferStartTime = in.readLong();
2250             mHistoryMonotonicEndTime = in.readLong();
2251             mMonotonicHistorySize = in.readLong();
2252 
2253             mHistoryBuffer.setDataSize(0);
2254             mHistoryBuffer.setDataPosition(0);
2255 
2256             int bufSize = in.readInt();
2257             int curPos = in.dataPosition();
2258             if (bufSize >= (mMaxHistoryBufferSize * 100)) {
2259                 throw new ParcelFormatException(
2260                         "File corrupt: history data buffer too large " + bufSize);
2261             } else if ((bufSize & ~3) != bufSize) {
2262                 throw new ParcelFormatException(
2263                         "File corrupt: history data buffer not aligned " + bufSize);
2264             } else {
2265                 if (DEBUG) {
2266                     Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
2267                             + " bytes at " + curPos);
2268                 }
2269                 mHistoryBuffer.appendFrom(in, curPos, bufSize);
2270                 in.setDataPosition(curPos + bufSize);
2271             }
2272         }
2273     }
2274 
2275     @GuardedBy("this")
writeHistoryBuffer(Parcel out)2276     private void writeHistoryBuffer(Parcel out) {
2277         out.writeInt(BatteryStatsHistory.VERSION);
2278         out.writeLong(mHistoryBufferStartTime);
2279         out.writeLong(mHistoryMonotonicEndTime);
2280         out.writeLong(mMonotonicHistorySize);
2281         out.writeInt(mHistoryBuffer.dataSize());
2282         if (DEBUG) {
2283             Slog.i(TAG, "***************** WRITING HISTORY: "
2284                     + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition());
2285         }
2286         out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
2287     }
2288 
2289     @GuardedBy("this")
writeParcelLocked(Parcel p, BatteryHistoryFragment fragment, boolean fragmentComplete)2290     private void writeParcelLocked(Parcel p, BatteryHistoryFragment fragment,
2291             boolean fragmentComplete) {
2292         mWriteLock.lock();
2293         try {
2294             final long startTimeMs = SystemClock.uptimeMillis();
2295             mStore.writeFragment(fragment, p.marshall(), fragmentComplete);
2296             mEventLogger.writeCommitSysConfigFile(startTimeMs);
2297         } finally {
2298             mWriteLock.unlock();
2299         }
2300     }
2301 
2302     /**
2303      * Returns the total number of history tags in the tag pool.
2304      */
getHistoryStringPoolSize()2305     public int getHistoryStringPoolSize() {
2306         synchronized (this) {
2307             return mHistoryTagPool.size();
2308         }
2309     }
2310 
2311     /**
2312      * Returns the total number of bytes occupied by the history tag pool.
2313      */
getHistoryStringPoolBytes()2314     public int getHistoryStringPoolBytes() {
2315         synchronized (this) {
2316             return mNumHistoryTagChars;
2317         }
2318     }
2319 
2320     /**
2321      * Returns the string held by the requested history tag.
2322      */
getHistoryTagPoolString(int index)2323     public String getHistoryTagPoolString(int index) {
2324         synchronized (this) {
2325             ensureHistoryTagArray();
2326             HistoryTag historyTag = mHistoryTags.get(index);
2327             return historyTag != null ? historyTag.string : null;
2328         }
2329     }
2330 
2331     /**
2332      * Returns the UID held by the requested history tag.
2333      */
getHistoryTagPoolUid(int index)2334     public int getHistoryTagPoolUid(int index) {
2335         synchronized (this) {
2336             ensureHistoryTagArray();
2337             HistoryTag historyTag = mHistoryTags.get(index);
2338             return historyTag != null ? historyTag.uid : Process.INVALID_UID;
2339         }
2340     }
2341 
2342     @GuardedBy("this")
ensureHistoryTagArray()2343     private void ensureHistoryTagArray() {
2344         if (mHistoryTags != null) {
2345             return;
2346         }
2347 
2348         mHistoryTags = new SparseArray<>(mHistoryTagPool.size());
2349         for (Map.Entry<HistoryTag, Integer> entry : mHistoryTagPool.entrySet()) {
2350             mHistoryTags.put(entry.getValue() & ~BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG,
2351                     entry.getKey());
2352         }
2353     }
2354 
2355     /**
2356      * Returns the monotonically increasing size of written history, including the buffers
2357      * that have already been discarded.
2358      */
getMonotonicHistorySize()2359     public long getMonotonicHistorySize() {
2360         return mMonotonicHistorySize;
2361     }
2362 
2363     /**
2364      * Prints battery stats history for debugging.
2365      */
dump(PrintWriter pw, long startTimeMs, long endTimeMs)2366     public void dump(PrintWriter pw, long startTimeMs, long endTimeMs) {
2367         BatteryStats.HistoryPrinter printer = new BatteryStats.HistoryPrinter();
2368         try (BatteryStatsHistoryIterator iterate = iterate(startTimeMs, endTimeMs)) {
2369             while (iterate.hasNext()) {
2370                 HistoryItem next = iterate.next();
2371                 printer.printNextItem(pw, next, 0, false, true);
2372             }
2373         }
2374         pw.flush();
2375     }
2376 
2377     /**
2378      * Writes/reads an array of longs into Parcel using a compact format, where small integers use
2379      * fewer bytes.  It is a bit more expensive than just writing the long into the parcel,
2380      * but at scale saves a lot of storage and allows recording of longer battery history.
2381      */
2382     @android.ravenwood.annotation.RavenwoodKeepWholeClass
2383     public static final class VarintParceler {
2384         /**
2385          * Writes an array of longs into Parcel using the varint format, see
2386          * https://developers.google.com/protocol-buffers/docs/encoding#varints
2387          */
writeLongArray(Parcel parcel, long[] values)2388         public void writeLongArray(Parcel parcel, long[] values) {
2389             if (values.length == 0) {
2390                 return;
2391             }
2392             int out = 0;
2393             int shift = 0;
2394             for (long value : values) {
2395                 boolean done = false;
2396                 while (!done) {
2397                     final byte b;
2398                     if ((value & ~0x7FL) == 0) {
2399                         b = (byte) value;
2400                         done = true;
2401                     } else {
2402                         b = (byte) (((int) value & 0x7F) | 0x80);
2403                         value >>>= 7;
2404                     }
2405                     if (shift == 32) {
2406                         parcel.writeInt(out);
2407                         shift = 0;
2408                         out = 0;
2409                     }
2410                     out |= (b & 0xFF) << shift;
2411                     shift += 8;
2412                 }
2413             }
2414             if (shift != 0) {
2415                 parcel.writeInt(out);
2416             }
2417         }
2418 
2419         /**
2420          * Reads a long written with {@link #writeLongArray}
2421          */
readLongArray(Parcel parcel, long[] values)2422         public void readLongArray(Parcel parcel, long[] values) {
2423             if (values.length == 0) {
2424                 return;
2425             }
2426             int in = parcel.readInt();
2427             int available = 4;
2428             for (int i = 0; i < values.length; i++) {
2429                 long result = 0;
2430                 int shift;
2431                 for (shift = 0; shift < 64; shift += 7) {
2432                     if (available == 0) {
2433                         in = parcel.readInt();
2434                         available = 4;
2435                     }
2436                     final byte b = (byte) in;
2437                     in >>= 8;
2438                     available--;
2439 
2440                     result |= (long) (b & 0x7F) << shift;
2441                     if ((b & 0x80) == 0) {
2442                         values[i] = result;
2443                         break;
2444                     }
2445                 }
2446                 if (shift >= 64) {
2447                     throw new ParcelFormatException("Invalid varint format");
2448                 }
2449             }
2450         }
2451     }
2452 }
2453