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