1 /* 2 * Copyright (C) 2020 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 android.os; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.database.Cursor; 22 import android.database.CursorWindow; 23 import android.util.Range; 24 import android.util.SparseArray; 25 import android.util.TypedXmlPullParser; 26 import android.util.TypedXmlSerializer; 27 import android.util.proto.ProtoOutputStream; 28 29 import com.android.internal.os.BatteryStatsHistory; 30 import com.android.internal.os.BatteryStatsHistoryIterator; 31 import com.android.internal.os.PowerCalculator; 32 33 import org.xmlpull.v1.XmlPullParser; 34 import org.xmlpull.v1.XmlPullParserException; 35 36 import java.io.Closeable; 37 import java.io.FileDescriptor; 38 import java.io.IOException; 39 import java.io.PrintWriter; 40 import java.lang.annotation.Retention; 41 import java.lang.annotation.RetentionPolicy; 42 import java.util.ArrayList; 43 import java.util.Arrays; 44 import java.util.Comparator; 45 import java.util.List; 46 47 /** 48 * Contains a snapshot of battery attribution data, on a per-subsystem and per-UID basis. 49 * <p> 50 * The totals for the entire device are returned as AggregateBatteryConsumers, which can be 51 * obtained by calling {@link #getAggregateBatteryConsumer(int)}. 52 * <p> 53 * Power attributed to individual apps is returned as UidBatteryConsumers, see 54 * {@link #getUidBatteryConsumers()}. 55 * 56 * @hide 57 */ 58 public final class BatteryUsageStats implements Parcelable, Closeable { 59 60 /** 61 * Scope of battery stats included in a BatteryConsumer: the entire device, just 62 * the apps, etc. 63 * 64 * @hide 65 */ 66 @IntDef(prefix = {"AGGREGATE_BATTERY_CONSUMER_SCOPE_"}, value = { 67 AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE, 68 AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS, 69 }) 70 @Retention(RetentionPolicy.SOURCE) 71 public static @interface AggregateBatteryConsumerScope { 72 } 73 74 /** 75 * Power consumption by the entire device, since last charge. The power usage in this 76 * scope includes both the power attributed to apps and the power unattributed to any 77 * apps. 78 */ 79 public static final int AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE = 0; 80 81 /** 82 * Aggregated power consumed by all applications, combined, since last charge. This is 83 * the sum of power reported in UidBatteryConsumers. 84 */ 85 public static final int AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS = 1; 86 87 public static final int AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT = 2; 88 89 // XML tags and attributes for BatteryUsageStats persistence 90 static final String XML_TAG_BATTERY_USAGE_STATS = "battery_usage_stats"; 91 static final String XML_TAG_AGGREGATE = "aggregate"; 92 static final String XML_TAG_UID = "uid"; 93 static final String XML_TAG_USER = "user"; 94 static final String XML_TAG_POWER_COMPONENTS = "power_components"; 95 static final String XML_TAG_COMPONENT = "component"; 96 static final String XML_TAG_CUSTOM_COMPONENT = "custom_component"; 97 static final String XML_ATTR_ID = "id"; 98 static final String XML_ATTR_UID = "uid"; 99 static final String XML_ATTR_USER_ID = "user_id"; 100 static final String XML_ATTR_SCOPE = "scope"; 101 static final String XML_ATTR_PREFIX_CUSTOM_COMPONENT = "custom_component_"; 102 static final String XML_ATTR_PREFIX_INCLUDES_PROC_STATE_DATA = "includes_proc_state_data"; 103 static final String XML_ATTR_START_TIMESTAMP = "start_timestamp"; 104 static final String XML_ATTR_END_TIMESTAMP = "end_timestamp"; 105 static final String XML_ATTR_PROCESS_STATE = "process_state"; 106 static final String XML_ATTR_POWER = "power"; 107 static final String XML_ATTR_DURATION = "duration"; 108 static final String XML_ATTR_MODEL = "model"; 109 static final String XML_ATTR_BATTERY_CAPACITY = "battery_capacity"; 110 static final String XML_ATTR_DISCHARGE_PERCENT = "discharge_pct"; 111 static final String XML_ATTR_DISCHARGE_LOWER = "discharge_lower"; 112 static final String XML_ATTR_DISCHARGE_UPPER = "discharge_upper"; 113 static final String XML_ATTR_DISCHARGE_DURATION = "discharge_duration"; 114 static final String XML_ATTR_BATTERY_REMAINING = "battery_remaining"; 115 static final String XML_ATTR_CHARGE_REMAINING = "charge_remaining"; 116 static final String XML_ATTR_HIGHEST_DRAIN_PACKAGE = "highest_drain_package"; 117 static final String XML_ATTR_TIME_IN_FOREGROUND = "time_in_foreground"; 118 static final String XML_ATTR_TIME_IN_BACKGROUND = "time_in_background"; 119 120 // We need about 700 bytes per UID 121 private static final long BATTERY_CONSUMER_CURSOR_WINDOW_SIZE = 5_000 * 700; 122 123 private static final int STATSD_PULL_ATOM_MAX_BYTES = 45000; 124 125 private final int mDischargePercentage; 126 private final double mBatteryCapacityMah; 127 private final long mStatsStartTimestampMs; 128 private final long mStatsEndTimestampMs; 129 private final long mStatsDurationMs; 130 private final double mDischargedPowerLowerBound; 131 private final double mDischargedPowerUpperBound; 132 private final long mDischargeDurationMs; 133 private final long mBatteryTimeRemainingMs; 134 private final long mChargeTimeRemainingMs; 135 private final String[] mCustomPowerComponentNames; 136 private final boolean mIncludesPowerModels; 137 private final boolean mIncludesProcessStateData; 138 private final List<UidBatteryConsumer> mUidBatteryConsumers; 139 private final List<UserBatteryConsumer> mUserBatteryConsumers; 140 private final AggregateBatteryConsumer[] mAggregateBatteryConsumers; 141 private final BatteryStatsHistory mBatteryStatsHistory; 142 private CursorWindow mBatteryConsumersCursorWindow; 143 BatteryUsageStats(@onNull Builder builder)144 private BatteryUsageStats(@NonNull Builder builder) { 145 mStatsStartTimestampMs = builder.mStatsStartTimestampMs; 146 mStatsEndTimestampMs = builder.mStatsEndTimestampMs; 147 mStatsDurationMs = builder.getStatsDuration(); 148 mBatteryCapacityMah = builder.mBatteryCapacityMah; 149 mDischargePercentage = builder.mDischargePercentage; 150 mDischargedPowerLowerBound = builder.mDischargedPowerLowerBoundMah; 151 mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah; 152 mDischargeDurationMs = builder.mDischargeDurationMs; 153 mBatteryStatsHistory = builder.mBatteryStatsHistory; 154 mBatteryTimeRemainingMs = builder.mBatteryTimeRemainingMs; 155 mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs; 156 mCustomPowerComponentNames = builder.mCustomPowerComponentNames; 157 mIncludesPowerModels = builder.mIncludePowerModels; 158 mIncludesProcessStateData = builder.mIncludesProcessStateData; 159 mBatteryConsumersCursorWindow = builder.mBatteryConsumersCursorWindow; 160 161 double totalPowerMah = 0; 162 final int uidBatteryConsumerCount = builder.mUidBatteryConsumerBuilders.size(); 163 mUidBatteryConsumers = new ArrayList<>(uidBatteryConsumerCount); 164 for (int i = 0; i < uidBatteryConsumerCount; i++) { 165 final UidBatteryConsumer.Builder uidBatteryConsumerBuilder = 166 builder.mUidBatteryConsumerBuilders.valueAt(i); 167 if (!uidBatteryConsumerBuilder.isExcludedFromBatteryUsageStats()) { 168 final UidBatteryConsumer consumer = uidBatteryConsumerBuilder.build(); 169 totalPowerMah += consumer.getConsumedPower(); 170 mUidBatteryConsumers.add(consumer); 171 } 172 } 173 174 final int userBatteryConsumerCount = builder.mUserBatteryConsumerBuilders.size(); 175 mUserBatteryConsumers = new ArrayList<>(userBatteryConsumerCount); 176 for (int i = 0; i < userBatteryConsumerCount; i++) { 177 final UserBatteryConsumer consumer = 178 builder.mUserBatteryConsumerBuilders.valueAt(i).build(); 179 totalPowerMah += consumer.getConsumedPower(); 180 mUserBatteryConsumers.add(consumer); 181 } 182 183 builder.getAggregateBatteryConsumerBuilder(AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) 184 .setConsumedPower(totalPowerMah); 185 186 mAggregateBatteryConsumers = 187 new AggregateBatteryConsumer[AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT]; 188 for (int i = 0; i < AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; i++) { 189 mAggregateBatteryConsumers[i] = builder.mAggregateBatteryConsumersBuilders[i].build(); 190 } 191 } 192 193 /** 194 * Timestamp (as returned by System.currentTimeMillis()) of the latest battery stats reset, in 195 * milliseconds. 196 */ getStatsStartTimestamp()197 public long getStatsStartTimestamp() { 198 return mStatsStartTimestampMs; 199 } 200 201 /** 202 * Timestamp (as returned by System.currentTimeMillis()) of when the stats snapshot was taken, 203 * in milliseconds. 204 */ getStatsEndTimestamp()205 public long getStatsEndTimestamp() { 206 return mStatsEndTimestampMs; 207 } 208 209 /** 210 * Returns the duration of the stats session captured by this BatteryUsageStats. 211 * In rare cases, statsDuration != statsEndTimestamp - statsStartTimestamp. This may 212 * happen when BatteryUsageStats represents an accumulation of data across multiple 213 * non-contiguous sessions. 214 */ getStatsDuration()215 public long getStatsDuration() { 216 return mStatsDurationMs; 217 } 218 219 /** 220 * Total amount of battery charge drained since BatteryStats reset (e.g. due to being fully 221 * charged), in mAh 222 */ getConsumedPower()223 public double getConsumedPower() { 224 return mAggregateBatteryConsumers[AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE] 225 .getConsumedPower(); 226 } 227 228 /** 229 * Returns battery capacity in milli-amp-hours. 230 */ getBatteryCapacity()231 public double getBatteryCapacity() { 232 return mBatteryCapacityMah; 233 } 234 235 /** 236 * Portion of battery charge drained since BatteryStats reset (e.g. due to being fully 237 * charged), as percentage of the full charge in the range [0:100]. May exceed 100 if 238 * the device repeatedly charged and discharged prior to the reset. 239 */ getDischargePercentage()240 public int getDischargePercentage() { 241 return mDischargePercentage; 242 } 243 244 /** 245 * Returns the discharged power since BatteryStats were last reset, in mAh as an estimated 246 * range. 247 */ getDischargedPowerRange()248 public Range<Double> getDischargedPowerRange() { 249 return Range.create(mDischargedPowerLowerBound, mDischargedPowerUpperBound); 250 } 251 252 /** 253 * Returns the total amount of time the battery was discharging. 254 */ getDischargeDurationMs()255 public long getDischargeDurationMs() { 256 return mDischargeDurationMs; 257 } 258 259 /** 260 * Returns an approximation for how much run time (in milliseconds) is remaining on 261 * the battery. Returns -1 if no time can be computed: either there is not 262 * enough current data to make a decision, or the battery is currently 263 * charging. 264 */ getBatteryTimeRemainingMs()265 public long getBatteryTimeRemainingMs() { 266 return mBatteryTimeRemainingMs; 267 } 268 269 /** 270 * Returns an approximation for how much time (in milliseconds) remains until the battery 271 * is fully charged. Returns -1 if no time can be computed: either there is not 272 * enough current data to make a decision, or the battery is currently discharging. 273 */ getChargeTimeRemainingMs()274 public long getChargeTimeRemainingMs() { 275 return mChargeTimeRemainingMs; 276 } 277 278 /** 279 * Returns a battery consumer for the specified battery consumer type. 280 */ getAggregateBatteryConsumer( @ggregateBatteryConsumerScope int scope)281 public BatteryConsumer getAggregateBatteryConsumer( 282 @AggregateBatteryConsumerScope int scope) { 283 return mAggregateBatteryConsumers[scope]; 284 } 285 286 @NonNull getUidBatteryConsumers()287 public List<UidBatteryConsumer> getUidBatteryConsumers() { 288 return mUidBatteryConsumers; 289 } 290 291 @NonNull getUserBatteryConsumers()292 public List<UserBatteryConsumer> getUserBatteryConsumers() { 293 return mUserBatteryConsumers; 294 } 295 296 /** 297 * Returns the names of custom power components in order, so the first name in the array 298 * corresponds to the custom componentId 299 * {@link BatteryConsumer#FIRST_CUSTOM_POWER_COMPONENT_ID}. 300 */ 301 @NonNull getCustomPowerComponentNames()302 public String[] getCustomPowerComponentNames() { 303 return mCustomPowerComponentNames; 304 } 305 isProcessStateDataIncluded()306 public boolean isProcessStateDataIncluded() { 307 return mIncludesProcessStateData; 308 } 309 310 /** 311 * Returns an iterator for {@link android.os.BatteryStats.HistoryItem}'s. 312 */ 313 @NonNull iterateBatteryStatsHistory()314 public BatteryStatsHistoryIterator iterateBatteryStatsHistory() { 315 if (mBatteryStatsHistory == null) { 316 throw new IllegalStateException( 317 "Battery history was not requested in the BatteryUsageStatsQuery"); 318 } 319 return new BatteryStatsHistoryIterator(mBatteryStatsHistory); 320 } 321 322 @Override describeContents()323 public int describeContents() { 324 return 0; 325 } 326 BatteryUsageStats(@onNull Parcel source)327 private BatteryUsageStats(@NonNull Parcel source) { 328 mStatsStartTimestampMs = source.readLong(); 329 mStatsEndTimestampMs = source.readLong(); 330 mStatsDurationMs = source.readLong(); 331 mBatteryCapacityMah = source.readDouble(); 332 mDischargePercentage = source.readInt(); 333 mDischargedPowerLowerBound = source.readDouble(); 334 mDischargedPowerUpperBound = source.readDouble(); 335 mDischargeDurationMs = source.readLong(); 336 mBatteryTimeRemainingMs = source.readLong(); 337 mChargeTimeRemainingMs = source.readLong(); 338 mCustomPowerComponentNames = source.readStringArray(); 339 mIncludesPowerModels = source.readBoolean(); 340 mIncludesProcessStateData = source.readBoolean(); 341 342 mBatteryConsumersCursorWindow = CursorWindow.newFromParcel(source); 343 BatteryConsumer.BatteryConsumerDataLayout dataLayout = 344 BatteryConsumer.createBatteryConsumerDataLayout(mCustomPowerComponentNames, 345 mIncludesPowerModels, mIncludesProcessStateData); 346 347 final int numRows = mBatteryConsumersCursorWindow.getNumRows(); 348 349 mAggregateBatteryConsumers = 350 new AggregateBatteryConsumer[AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT]; 351 mUidBatteryConsumers = new ArrayList<>(numRows); 352 mUserBatteryConsumers = new ArrayList<>(); 353 354 for (int i = 0; i < numRows; i++) { 355 final BatteryConsumer.BatteryConsumerData data = 356 new BatteryConsumer.BatteryConsumerData(mBatteryConsumersCursorWindow, i, 357 dataLayout); 358 359 int consumerType = mBatteryConsumersCursorWindow.getInt(i, 360 BatteryConsumer.COLUMN_INDEX_BATTERY_CONSUMER_TYPE); 361 switch (consumerType) { 362 case AggregateBatteryConsumer.CONSUMER_TYPE_AGGREGATE: { 363 final AggregateBatteryConsumer consumer = new AggregateBatteryConsumer(data); 364 mAggregateBatteryConsumers[consumer.getScope()] = consumer; 365 break; 366 } 367 case UidBatteryConsumer.CONSUMER_TYPE_UID: { 368 mUidBatteryConsumers.add(new UidBatteryConsumer(data)); 369 break; 370 } 371 case UserBatteryConsumer.CONSUMER_TYPE_USER: 372 mUserBatteryConsumers.add(new UserBatteryConsumer(data)); 373 break; 374 } 375 } 376 377 if (source.readBoolean()) { 378 mBatteryStatsHistory = BatteryStatsHistory.createFromBatteryUsageStatsParcel(source); 379 } else { 380 mBatteryStatsHistory = null; 381 } 382 } 383 384 @Override writeToParcel(@onNull Parcel dest, int flags)385 public void writeToParcel(@NonNull Parcel dest, int flags) { 386 dest.writeLong(mStatsStartTimestampMs); 387 dest.writeLong(mStatsEndTimestampMs); 388 dest.writeLong(mStatsDurationMs); 389 dest.writeDouble(mBatteryCapacityMah); 390 dest.writeInt(mDischargePercentage); 391 dest.writeDouble(mDischargedPowerLowerBound); 392 dest.writeDouble(mDischargedPowerUpperBound); 393 dest.writeLong(mDischargeDurationMs); 394 dest.writeLong(mBatteryTimeRemainingMs); 395 dest.writeLong(mChargeTimeRemainingMs); 396 dest.writeStringArray(mCustomPowerComponentNames); 397 dest.writeBoolean(mIncludesPowerModels); 398 dest.writeBoolean(mIncludesProcessStateData); 399 400 mBatteryConsumersCursorWindow.writeToParcel(dest, flags); 401 402 if (mBatteryStatsHistory != null) { 403 dest.writeBoolean(true); 404 mBatteryStatsHistory.writeToBatteryUsageStatsParcel(dest); 405 } else { 406 dest.writeBoolean(false); 407 } 408 } 409 410 @NonNull 411 public static final Creator<BatteryUsageStats> CREATOR = new Creator<BatteryUsageStats>() { 412 public BatteryUsageStats createFromParcel(@NonNull Parcel source) { 413 return new BatteryUsageStats(source); 414 } 415 416 public BatteryUsageStats[] newArray(int size) { 417 return new BatteryUsageStats[size]; 418 } 419 }; 420 421 /** Returns a proto (as used for atoms.proto) corresponding to this BatteryUsageStats. */ getStatsProto()422 public byte[] getStatsProto() { 423 // ProtoOutputStream.getRawSize() returns the buffer size before compaction. 424 // BatteryUsageStats contains a lot of integers, so compaction of integers to 425 // varint reduces the size of the proto buffer by as much as 50%. 426 int maxRawSize = (int) (STATSD_PULL_ATOM_MAX_BYTES * 1.75); 427 // Limit the number of attempts in order to prevent an infinite loop 428 for (int i = 0; i < 3; i++) { 429 final ProtoOutputStream proto = new ProtoOutputStream(); 430 writeStatsProto(proto, maxRawSize); 431 432 final int rawSize = proto.getRawSize(); 433 final byte[] protoOutput = proto.getBytes(); 434 435 if (protoOutput.length <= STATSD_PULL_ATOM_MAX_BYTES) { 436 return protoOutput; 437 } 438 439 // Adjust maxRawSize proportionately and try again. 440 maxRawSize = 441 (int) ((long) STATSD_PULL_ATOM_MAX_BYTES * rawSize / protoOutput.length - 1024); 442 } 443 444 // Fallback: if we have failed to generate a proto smaller than STATSD_PULL_ATOM_MAX_BYTES, 445 // just generate a proto with the _rawSize_ of STATSD_PULL_ATOM_MAX_BYTES, which is 446 // guaranteed to produce a compacted proto (significantly) smaller than 447 // STATSD_PULL_ATOM_MAX_BYTES. 448 final ProtoOutputStream proto = new ProtoOutputStream(); 449 writeStatsProto(proto, STATSD_PULL_ATOM_MAX_BYTES); 450 return proto.getBytes(); 451 } 452 453 /** 454 * Writes contents in a binary protobuffer format, using 455 * the android.os.BatteryUsageStatsAtomsProto proto. 456 */ dumpToProto(FileDescriptor fd)457 public void dumpToProto(FileDescriptor fd) { 458 final ProtoOutputStream proto = new ProtoOutputStream(fd); 459 writeStatsProto(proto, /* max size */ Integer.MAX_VALUE); 460 proto.flush(); 461 } 462 463 @NonNull writeStatsProto(ProtoOutputStream proto, int maxRawSize)464 private void writeStatsProto(ProtoOutputStream proto, int maxRawSize) { 465 final BatteryConsumer deviceBatteryConsumer = getAggregateBatteryConsumer( 466 AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE); 467 468 proto.write(BatteryUsageStatsAtomsProto.SESSION_START_MILLIS, getStatsStartTimestamp()); 469 proto.write(BatteryUsageStatsAtomsProto.SESSION_END_MILLIS, getStatsEndTimestamp()); 470 proto.write(BatteryUsageStatsAtomsProto.SESSION_DURATION_MILLIS, getStatsDuration()); 471 proto.write(BatteryUsageStatsAtomsProto.SESSION_DISCHARGE_PERCENTAGE, 472 getDischargePercentage()); 473 proto.write(BatteryUsageStatsAtomsProto.DISCHARGE_DURATION_MILLIS, 474 getDischargeDurationMs()); 475 deviceBatteryConsumer.writeStatsProto(proto, 476 BatteryUsageStatsAtomsProto.DEVICE_BATTERY_CONSUMER); 477 writeUidBatteryConsumersProto(proto, maxRawSize); 478 } 479 480 /** 481 * Writes the UidBatteryConsumers data, held by this BatteryUsageStats, to the proto (as used 482 * for atoms.proto). 483 */ writeUidBatteryConsumersProto(ProtoOutputStream proto, int maxRawSize)484 private void writeUidBatteryConsumersProto(ProtoOutputStream proto, int maxRawSize) { 485 final List<UidBatteryConsumer> consumers = getUidBatteryConsumers(); 486 // Order consumers by descending weight (a combination of consumed power and usage time) 487 consumers.sort(Comparator.comparingDouble(this::getUidBatteryConsumerWeight).reversed()); 488 489 final int size = consumers.size(); 490 for (int i = 0; i < size; i++) { 491 final UidBatteryConsumer consumer = consumers.get(i); 492 493 final long fgMs = consumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND); 494 final long bgMs = consumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND); 495 final boolean hasBaseData = consumer.hasStatsProtoData(); 496 497 if (fgMs == 0 && bgMs == 0 && !hasBaseData) { 498 continue; 499 } 500 501 final long token = proto.start(BatteryUsageStatsAtomsProto.UID_BATTERY_CONSUMERS); 502 proto.write( 503 BatteryUsageStatsAtomsProto.UidBatteryConsumer.UID, 504 consumer.getUid()); 505 if (hasBaseData) { 506 consumer.writeStatsProto(proto, 507 BatteryUsageStatsAtomsProto.UidBatteryConsumer.BATTERY_CONSUMER_DATA); 508 } 509 proto.write( 510 BatteryUsageStatsAtomsProto.UidBatteryConsumer.TIME_IN_FOREGROUND_MILLIS, 511 fgMs); 512 proto.write( 513 BatteryUsageStatsAtomsProto.UidBatteryConsumer.TIME_IN_BACKGROUND_MILLIS, 514 bgMs); 515 proto.end(token); 516 517 if (proto.getRawSize() >= maxRawSize) { 518 break; 519 } 520 } 521 } 522 523 private static final double WEIGHT_CONSUMED_POWER = 1; 524 // Weight one hour in foreground the same as 100 mAh of power drain 525 private static final double WEIGHT_FOREGROUND_STATE = 100.0 / (1 * 60 * 60 * 1000); 526 // Weight one hour in background the same as 300 mAh of power drain 527 private static final double WEIGHT_BACKGROUND_STATE = 300.0 / (1 * 60 * 60 * 1000); 528 529 /** 530 * Computes the weight associated with a UidBatteryConsumer, which is used for sorting. 531 * We want applications with the largest consumed power as well as applications 532 * with the highest usage time to be included in the statsd atom. 533 */ getUidBatteryConsumerWeight(UidBatteryConsumer uidBatteryConsumer)534 private double getUidBatteryConsumerWeight(UidBatteryConsumer uidBatteryConsumer) { 535 final double consumedPower = uidBatteryConsumer.getConsumedPower(); 536 final long timeInForeground = 537 uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND); 538 final long timeInBackground = 539 uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND); 540 return consumedPower * WEIGHT_CONSUMED_POWER 541 + timeInForeground * WEIGHT_FOREGROUND_STATE 542 + timeInBackground * WEIGHT_BACKGROUND_STATE; 543 } 544 545 /** 546 * Prints the stats in a human-readable format. 547 */ dump(PrintWriter pw, String prefix)548 public void dump(PrintWriter pw, String prefix) { 549 pw.print(prefix); 550 pw.println(" Estimated power use (mAh):"); 551 pw.print(prefix); 552 pw.print(" Capacity: "); 553 PowerCalculator.printPowerMah(pw, getBatteryCapacity()); 554 pw.print(", Computed drain: "); 555 PowerCalculator.printPowerMah(pw, getConsumedPower()); 556 final Range<Double> dischargedPowerRange = getDischargedPowerRange(); 557 pw.print(", actual drain: "); 558 PowerCalculator.printPowerMah(pw, dischargedPowerRange.getLower()); 559 if (!dischargedPowerRange.getLower().equals(dischargedPowerRange.getUpper())) { 560 pw.print("-"); 561 PowerCalculator.printPowerMah(pw, dischargedPowerRange.getUpper()); 562 } 563 pw.println(); 564 565 pw.println(" Global"); 566 final BatteryConsumer deviceConsumer = getAggregateBatteryConsumer( 567 AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE); 568 final BatteryConsumer appsConsumer = getAggregateBatteryConsumer( 569 AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS); 570 571 for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT; 572 componentId++) { 573 for (BatteryConsumer.Key key : deviceConsumer.getKeys(componentId)) { 574 final double devicePowerMah = deviceConsumer.getConsumedPower(key); 575 final double appsPowerMah = appsConsumer.getConsumedPower(key); 576 if (devicePowerMah == 0 && appsPowerMah == 0) { 577 continue; 578 } 579 580 String label = BatteryConsumer.powerComponentIdToString(componentId); 581 if (key.processState != BatteryConsumer.PROCESS_STATE_UNSPECIFIED) { 582 label = label 583 + "(" + BatteryConsumer.processStateToString(key.processState) + ")"; 584 } 585 printPowerComponent(pw, prefix, label, devicePowerMah, appsPowerMah, 586 deviceConsumer.getPowerModel(key), 587 deviceConsumer.getUsageDurationMillis(key)); 588 } 589 } 590 591 for (int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID; 592 componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID 593 + mCustomPowerComponentNames.length; 594 componentId++) { 595 final double devicePowerMah = 596 deviceConsumer.getConsumedPowerForCustomComponent(componentId); 597 final double appsPowerMah = 598 appsConsumer.getConsumedPowerForCustomComponent(componentId); 599 if (devicePowerMah == 0 && appsPowerMah == 0) { 600 continue; 601 } 602 603 printPowerComponent(pw, prefix, deviceConsumer.getCustomPowerComponentName(componentId), 604 devicePowerMah, appsPowerMah, 605 BatteryConsumer.POWER_MODEL_UNDEFINED, 606 deviceConsumer.getUsageDurationForCustomComponentMillis(componentId)); 607 } 608 609 dumpSortedBatteryConsumers(pw, prefix, getUidBatteryConsumers()); 610 dumpSortedBatteryConsumers(pw, prefix, getUserBatteryConsumers()); 611 pw.println(); 612 } 613 printPowerComponent(PrintWriter pw, String prefix, String label, double devicePowerMah, double appsPowerMah, int powerModel, long durationMs)614 private void printPowerComponent(PrintWriter pw, String prefix, String label, 615 double devicePowerMah, double appsPowerMah, int powerModel, long durationMs) { 616 StringBuilder sb = new StringBuilder(); 617 sb.append(prefix).append(" ").append(label).append(": ") 618 .append(BatteryStats.formatCharge(devicePowerMah)); 619 if (powerModel != BatteryConsumer.POWER_MODEL_UNDEFINED 620 && powerModel != BatteryConsumer.POWER_MODEL_POWER_PROFILE) { 621 sb.append(" ["); 622 sb.append(BatteryConsumer.powerModelToString(powerModel)); 623 sb.append("]"); 624 } 625 sb.append(" apps: ").append(BatteryStats.formatCharge(appsPowerMah)); 626 if (durationMs != 0) { 627 sb.append(" duration: "); 628 BatteryStats.formatTimeMs(sb, durationMs); 629 } 630 631 pw.println(sb.toString()); 632 } 633 dumpSortedBatteryConsumers(PrintWriter pw, String prefix, List<? extends BatteryConsumer> batteryConsumers)634 private void dumpSortedBatteryConsumers(PrintWriter pw, String prefix, 635 List<? extends BatteryConsumer> batteryConsumers) { 636 batteryConsumers.sort( 637 Comparator.<BatteryConsumer>comparingDouble(BatteryConsumer::getConsumedPower) 638 .reversed()); 639 for (BatteryConsumer consumer : batteryConsumers) { 640 if (consumer.getConsumedPower() == 0) { 641 continue; 642 } 643 pw.print(prefix); 644 pw.print(" "); 645 consumer.dump(pw); 646 pw.println(); 647 } 648 } 649 650 /** Serializes this object to XML */ writeXml(TypedXmlSerializer serializer)651 public void writeXml(TypedXmlSerializer serializer) throws IOException { 652 serializer.startTag(null, XML_TAG_BATTERY_USAGE_STATS); 653 654 for (int i = 0; i < mCustomPowerComponentNames.length; i++) { 655 serializer.attribute(null, XML_ATTR_PREFIX_CUSTOM_COMPONENT + i, 656 mCustomPowerComponentNames[i]); 657 } 658 serializer.attributeBoolean(null, XML_ATTR_PREFIX_INCLUDES_PROC_STATE_DATA, 659 mIncludesProcessStateData); 660 serializer.attributeLong(null, XML_ATTR_START_TIMESTAMP, mStatsStartTimestampMs); 661 serializer.attributeLong(null, XML_ATTR_END_TIMESTAMP, mStatsEndTimestampMs); 662 serializer.attributeLong(null, XML_ATTR_DURATION, mStatsDurationMs); 663 serializer.attributeDouble(null, XML_ATTR_BATTERY_CAPACITY, mBatteryCapacityMah); 664 serializer.attributeInt(null, XML_ATTR_DISCHARGE_PERCENT, mDischargePercentage); 665 serializer.attributeDouble(null, XML_ATTR_DISCHARGE_LOWER, mDischargedPowerLowerBound); 666 serializer.attributeDouble(null, XML_ATTR_DISCHARGE_UPPER, mDischargedPowerUpperBound); 667 serializer.attributeLong(null, XML_ATTR_DISCHARGE_DURATION, mDischargeDurationMs); 668 serializer.attributeLong(null, XML_ATTR_BATTERY_REMAINING, mBatteryTimeRemainingMs); 669 serializer.attributeLong(null, XML_ATTR_CHARGE_REMAINING, mChargeTimeRemainingMs); 670 671 for (int scope = 0; scope < BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; 672 scope++) { 673 mAggregateBatteryConsumers[scope].writeToXml(serializer, scope); 674 } 675 for (UidBatteryConsumer consumer : mUidBatteryConsumers) { 676 consumer.writeToXml(serializer); 677 } 678 for (UserBatteryConsumer consumer : mUserBatteryConsumers) { 679 consumer.writeToXml(serializer); 680 } 681 serializer.endTag(null, XML_TAG_BATTERY_USAGE_STATS); 682 } 683 684 /** Parses an XML representation of BatteryUsageStats */ createFromXml(TypedXmlPullParser parser)685 public static BatteryUsageStats createFromXml(TypedXmlPullParser parser) 686 throws XmlPullParserException, IOException { 687 Builder builder = null; 688 int eventType = parser.getEventType(); 689 while (eventType != XmlPullParser.END_DOCUMENT) { 690 if (eventType == XmlPullParser.START_TAG 691 && parser.getName().equals(XML_TAG_BATTERY_USAGE_STATS)) { 692 List<String> customComponentNames = new ArrayList<>(); 693 int i = 0; 694 while (true) { 695 int index = parser.getAttributeIndex(null, 696 XML_ATTR_PREFIX_CUSTOM_COMPONENT + i); 697 if (index == -1) { 698 break; 699 } 700 customComponentNames.add(parser.getAttributeValue(index)); 701 i++; 702 } 703 704 final boolean includesProcStateData = parser.getAttributeBoolean(null, 705 XML_ATTR_PREFIX_INCLUDES_PROC_STATE_DATA, false); 706 707 builder = new Builder(customComponentNames.toArray(new String[0]), true, 708 includesProcStateData); 709 710 builder.setStatsStartTimestamp( 711 parser.getAttributeLong(null, XML_ATTR_START_TIMESTAMP)); 712 builder.setStatsEndTimestamp( 713 parser.getAttributeLong(null, XML_ATTR_END_TIMESTAMP)); 714 builder.setStatsDuration( 715 parser.getAttributeLong(null, XML_ATTR_DURATION)); 716 builder.setBatteryCapacity( 717 parser.getAttributeDouble(null, XML_ATTR_BATTERY_CAPACITY)); 718 builder.setDischargePercentage( 719 parser.getAttributeInt(null, XML_ATTR_DISCHARGE_PERCENT)); 720 builder.setDischargedPowerRange( 721 parser.getAttributeDouble(null, XML_ATTR_DISCHARGE_LOWER), 722 parser.getAttributeDouble(null, XML_ATTR_DISCHARGE_UPPER)); 723 builder.setDischargeDurationMs( 724 parser.getAttributeLong(null, XML_ATTR_DISCHARGE_DURATION)); 725 builder.setBatteryTimeRemainingMs( 726 parser.getAttributeLong(null, XML_ATTR_BATTERY_REMAINING)); 727 builder.setChargeTimeRemainingMs( 728 parser.getAttributeLong(null, XML_ATTR_CHARGE_REMAINING)); 729 730 eventType = parser.next(); 731 break; 732 } 733 eventType = parser.next(); 734 } 735 736 if (builder == null) { 737 throw new XmlPullParserException("No root element"); 738 } 739 740 while (eventType != XmlPullParser.END_DOCUMENT) { 741 if (eventType == XmlPullParser.START_TAG) { 742 switch (parser.getName()) { 743 case XML_TAG_AGGREGATE: 744 AggregateBatteryConsumer.parseXml(parser, builder); 745 break; 746 case XML_TAG_UID: 747 UidBatteryConsumer.createFromXml(parser, builder); 748 break; 749 case XML_TAG_USER: 750 UserBatteryConsumer.createFromXml(parser, builder); 751 break; 752 } 753 } 754 eventType = parser.next(); 755 } 756 757 return builder.build(); 758 } 759 760 @Override close()761 public void close() throws IOException { 762 mBatteryConsumersCursorWindow.close(); 763 mBatteryConsumersCursorWindow = null; 764 } 765 766 @Override finalize()767 protected void finalize() throws Throwable { 768 if (mBatteryConsumersCursorWindow != null) { 769 mBatteryConsumersCursorWindow.close(); 770 } 771 super.finalize(); 772 } 773 774 /** 775 * Builder for BatteryUsageStats. 776 */ 777 public static final class Builder { 778 private final CursorWindow mBatteryConsumersCursorWindow; 779 @NonNull 780 private final String[] mCustomPowerComponentNames; 781 private final boolean mIncludePowerModels; 782 private final boolean mIncludesProcessStateData; 783 private final BatteryConsumer.BatteryConsumerDataLayout mBatteryConsumerDataLayout; 784 private long mStatsStartTimestampMs; 785 private long mStatsEndTimestampMs; 786 private long mStatsDurationMs = -1; 787 private double mBatteryCapacityMah; 788 private int mDischargePercentage; 789 private double mDischargedPowerLowerBoundMah; 790 private double mDischargedPowerUpperBoundMah; 791 private long mDischargeDurationMs; 792 private long mBatteryTimeRemainingMs = -1; 793 private long mChargeTimeRemainingMs = -1; 794 private final AggregateBatteryConsumer.Builder[] mAggregateBatteryConsumersBuilders = 795 new AggregateBatteryConsumer.Builder[AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT]; 796 private final SparseArray<UidBatteryConsumer.Builder> mUidBatteryConsumerBuilders = 797 new SparseArray<>(); 798 private final SparseArray<UserBatteryConsumer.Builder> mUserBatteryConsumerBuilders = 799 new SparseArray<>(); 800 private BatteryStatsHistory mBatteryStatsHistory; 801 Builder(@onNull String[] customPowerComponentNames)802 public Builder(@NonNull String[] customPowerComponentNames) { 803 this(customPowerComponentNames, false, false); 804 } 805 Builder(@onNull String[] customPowerComponentNames, boolean includePowerModels, boolean includeProcessStateData)806 public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels, 807 boolean includeProcessStateData) { 808 mBatteryConsumersCursorWindow = 809 new CursorWindow(null, BATTERY_CONSUMER_CURSOR_WINDOW_SIZE); 810 mBatteryConsumerDataLayout = 811 BatteryConsumer.createBatteryConsumerDataLayout(customPowerComponentNames, 812 includePowerModels, includeProcessStateData); 813 mBatteryConsumersCursorWindow.setNumColumns(mBatteryConsumerDataLayout.columnCount); 814 815 mCustomPowerComponentNames = customPowerComponentNames; 816 mIncludePowerModels = includePowerModels; 817 mIncludesProcessStateData = includeProcessStateData; 818 for (int scope = 0; scope < AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; scope++) { 819 final BatteryConsumer.BatteryConsumerData data = 820 BatteryConsumer.BatteryConsumerData.create(mBatteryConsumersCursorWindow, 821 mBatteryConsumerDataLayout); 822 mAggregateBatteryConsumersBuilders[scope] = 823 new AggregateBatteryConsumer.Builder(data, scope); 824 } 825 } 826 isProcessStateDataNeeded()827 public boolean isProcessStateDataNeeded() { 828 return mIncludesProcessStateData; 829 } 830 831 /** 832 * Constructs a read-only object using the Builder values. 833 */ 834 @NonNull build()835 public BatteryUsageStats build() { 836 return new BatteryUsageStats(this); 837 } 838 839 /** 840 * Sets the battery capacity in milli-amp-hours. 841 */ setBatteryCapacity(double batteryCapacityMah)842 public Builder setBatteryCapacity(double batteryCapacityMah) { 843 mBatteryCapacityMah = batteryCapacityMah; 844 return this; 845 } 846 847 /** 848 * Sets the timestamp of the latest battery stats reset, in milliseconds. 849 */ setStatsStartTimestamp(long statsStartTimestampMs)850 public Builder setStatsStartTimestamp(long statsStartTimestampMs) { 851 mStatsStartTimestampMs = statsStartTimestampMs; 852 return this; 853 } 854 855 /** 856 * Sets the timestamp of when the battery stats snapshot was taken, in milliseconds. 857 */ setStatsEndTimestamp(long statsEndTimestampMs)858 public Builder setStatsEndTimestamp(long statsEndTimestampMs) { 859 mStatsEndTimestampMs = statsEndTimestampMs; 860 return this; 861 } 862 863 /** 864 * Sets the duration of the stats session. The default value of this field is 865 * statsEndTimestamp - statsStartTimestamp. 866 */ setStatsDuration(long statsDurationMs)867 public Builder setStatsDuration(long statsDurationMs) { 868 mStatsDurationMs = statsDurationMs; 869 return this; 870 } 871 getStatsDuration()872 private long getStatsDuration() { 873 if (mStatsDurationMs != -1) { 874 return mStatsDurationMs; 875 } else { 876 return mStatsEndTimestampMs - mStatsStartTimestampMs; 877 } 878 } 879 880 /** 881 * Sets the battery discharge amount since BatteryStats reset as percentage of the full 882 * charge. 883 */ 884 @NonNull setDischargePercentage(int dischargePercentage)885 public Builder setDischargePercentage(int dischargePercentage) { 886 mDischargePercentage = dischargePercentage; 887 return this; 888 } 889 890 /** 891 * Sets the estimated battery discharge range. 892 */ 893 @NonNull setDischargedPowerRange(double dischargedPowerLowerBoundMah, double dischargedPowerUpperBoundMah)894 public Builder setDischargedPowerRange(double dischargedPowerLowerBoundMah, 895 double dischargedPowerUpperBoundMah) { 896 mDischargedPowerLowerBoundMah = dischargedPowerLowerBoundMah; 897 mDischargedPowerUpperBoundMah = dischargedPowerUpperBoundMah; 898 return this; 899 } 900 901 /** 902 * Sets the total battery discharge time, in milliseconds. 903 */ 904 @NonNull setDischargeDurationMs(long durationMs)905 public Builder setDischargeDurationMs(long durationMs) { 906 mDischargeDurationMs = durationMs; 907 return this; 908 } 909 910 /** 911 * Sets an approximation for how much time (in milliseconds) remains until the battery 912 * is fully discharged. 913 */ 914 @NonNull setBatteryTimeRemainingMs(long batteryTimeRemainingMs)915 public Builder setBatteryTimeRemainingMs(long batteryTimeRemainingMs) { 916 mBatteryTimeRemainingMs = batteryTimeRemainingMs; 917 return this; 918 } 919 920 /** 921 * Sets an approximation for how much time (in milliseconds) remains until the battery 922 * is fully charged. 923 */ 924 @NonNull setChargeTimeRemainingMs(long chargeTimeRemainingMs)925 public Builder setChargeTimeRemainingMs(long chargeTimeRemainingMs) { 926 mChargeTimeRemainingMs = chargeTimeRemainingMs; 927 return this; 928 } 929 930 /** 931 * Sets the parceled recent history. 932 */ 933 @NonNull setBatteryHistory(BatteryStatsHistory batteryStatsHistory)934 public Builder setBatteryHistory(BatteryStatsHistory batteryStatsHistory) { 935 mBatteryStatsHistory = batteryStatsHistory; 936 return this; 937 } 938 939 /** 940 * Creates or returns an AggregateBatteryConsumer builder, which represents aggregate 941 * battery consumption data for the specified scope. 942 */ 943 @NonNull getAggregateBatteryConsumerBuilder( @ggregateBatteryConsumerScope int scope)944 public AggregateBatteryConsumer.Builder getAggregateBatteryConsumerBuilder( 945 @AggregateBatteryConsumerScope int scope) { 946 return mAggregateBatteryConsumersBuilders[scope]; 947 } 948 949 /** 950 * Creates or returns a UidBatteryConsumer, which represents battery attribution 951 * data for an individual UID. 952 */ 953 @NonNull getOrCreateUidBatteryConsumerBuilder( @onNull BatteryStats.Uid batteryStatsUid)954 public UidBatteryConsumer.Builder getOrCreateUidBatteryConsumerBuilder( 955 @NonNull BatteryStats.Uid batteryStatsUid) { 956 int uid = batteryStatsUid.getUid(); 957 UidBatteryConsumer.Builder builder = mUidBatteryConsumerBuilders.get(uid); 958 if (builder == null) { 959 final BatteryConsumer.BatteryConsumerData data = 960 BatteryConsumer.BatteryConsumerData.create(mBatteryConsumersCursorWindow, 961 mBatteryConsumerDataLayout); 962 builder = new UidBatteryConsumer.Builder(data, batteryStatsUid); 963 mUidBatteryConsumerBuilders.put(uid, builder); 964 } 965 return builder; 966 } 967 968 /** 969 * Creates or returns a UidBatteryConsumer, which represents battery attribution 970 * data for an individual UID. This version of the method is not suitable for use 971 * with PowerCalculators. 972 */ 973 @NonNull getOrCreateUidBatteryConsumerBuilder(int uid)974 public UidBatteryConsumer.Builder getOrCreateUidBatteryConsumerBuilder(int uid) { 975 UidBatteryConsumer.Builder builder = mUidBatteryConsumerBuilders.get(uid); 976 if (builder == null) { 977 final BatteryConsumer.BatteryConsumerData data = 978 BatteryConsumer.BatteryConsumerData.create(mBatteryConsumersCursorWindow, 979 mBatteryConsumerDataLayout); 980 builder = new UidBatteryConsumer.Builder(data, uid); 981 mUidBatteryConsumerBuilders.put(uid, builder); 982 } 983 return builder; 984 } 985 986 /** 987 * Creates or returns a UserBatteryConsumer, which represents battery attribution 988 * data for an individual {@link UserHandle}. 989 */ 990 @NonNull getOrCreateUserBatteryConsumerBuilder(int userId)991 public UserBatteryConsumer.Builder getOrCreateUserBatteryConsumerBuilder(int userId) { 992 UserBatteryConsumer.Builder builder = mUserBatteryConsumerBuilders.get(userId); 993 if (builder == null) { 994 final BatteryConsumer.BatteryConsumerData data = 995 BatteryConsumer.BatteryConsumerData.create(mBatteryConsumersCursorWindow, 996 mBatteryConsumerDataLayout); 997 builder = new UserBatteryConsumer.Builder(data, userId); 998 mUserBatteryConsumerBuilders.put(userId, builder); 999 } 1000 return builder; 1001 } 1002 1003 @NonNull getUidBatteryConsumerBuilders()1004 public SparseArray<UidBatteryConsumer.Builder> getUidBatteryConsumerBuilders() { 1005 return mUidBatteryConsumerBuilders; 1006 } 1007 1008 /** 1009 * Adds battery usage stats from another snapshots. The two snapshots are assumed to be 1010 * non-overlapping, meaning that the power consumption estimates and session durations 1011 * can be simply summed across the two snapshots. This remains true even if the timestamps 1012 * seem to indicate that the sessions are in fact overlapping: timestamps may be off as a 1013 * result of realtime clock adjustments by the user or the system. 1014 */ 1015 @NonNull add(BatteryUsageStats stats)1016 public Builder add(BatteryUsageStats stats) { 1017 if (!Arrays.equals(mCustomPowerComponentNames, stats.mCustomPowerComponentNames)) { 1018 throw new IllegalArgumentException( 1019 "BatteryUsageStats have different custom power components"); 1020 } 1021 1022 if (mIncludesProcessStateData && !stats.mIncludesProcessStateData) { 1023 throw new IllegalArgumentException( 1024 "Added BatteryUsageStats does not include process state data"); 1025 } 1026 1027 if (mUserBatteryConsumerBuilders.size() != 0 1028 || !stats.getUserBatteryConsumers().isEmpty()) { 1029 throw new UnsupportedOperationException( 1030 "Combining UserBatteryConsumers is not supported"); 1031 } 1032 1033 mDischargedPowerLowerBoundMah += stats.mDischargedPowerLowerBound; 1034 mDischargedPowerUpperBoundMah += stats.mDischargedPowerUpperBound; 1035 mDischargePercentage += stats.mDischargePercentage; 1036 mDischargeDurationMs += stats.mDischargeDurationMs; 1037 1038 mStatsDurationMs = getStatsDuration() + stats.getStatsDuration(); 1039 1040 if (mStatsStartTimestampMs == 0 1041 || stats.mStatsStartTimestampMs < mStatsStartTimestampMs) { 1042 mStatsStartTimestampMs = stats.mStatsStartTimestampMs; 1043 } 1044 1045 final boolean addingLaterSnapshot = stats.mStatsEndTimestampMs > mStatsEndTimestampMs; 1046 if (addingLaterSnapshot) { 1047 mStatsEndTimestampMs = stats.mStatsEndTimestampMs; 1048 } 1049 1050 for (int scope = 0; scope < AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; scope++) { 1051 getAggregateBatteryConsumerBuilder(scope) 1052 .add(stats.mAggregateBatteryConsumers[scope]); 1053 } 1054 1055 for (UidBatteryConsumer consumer : stats.getUidBatteryConsumers()) { 1056 getOrCreateUidBatteryConsumerBuilder(consumer.getUid()).add(consumer); 1057 } 1058 1059 if (addingLaterSnapshot) { 1060 mBatteryCapacityMah = stats.mBatteryCapacityMah; 1061 mBatteryTimeRemainingMs = stats.mBatteryTimeRemainingMs; 1062 mChargeTimeRemainingMs = stats.mChargeTimeRemainingMs; 1063 } 1064 1065 return this; 1066 } 1067 1068 /** 1069 * Dumps raw contents of the cursor window for debugging. 1070 */ dump(PrintWriter writer)1071 void dump(PrintWriter writer) { 1072 final int numRows = mBatteryConsumersCursorWindow.getNumRows(); 1073 int numColumns = mBatteryConsumerDataLayout.columnCount; 1074 for (int i = 0; i < numRows; i++) { 1075 StringBuilder sb = new StringBuilder(); 1076 for (int j = 0; j < numColumns; j++) { 1077 final int type = mBatteryConsumersCursorWindow.getType(i, j); 1078 switch (type) { 1079 case Cursor.FIELD_TYPE_NULL: 1080 sb.append("null, "); 1081 break; 1082 case Cursor.FIELD_TYPE_INTEGER: 1083 sb.append(mBatteryConsumersCursorWindow.getInt(i, j)).append(", "); 1084 break; 1085 case Cursor.FIELD_TYPE_FLOAT: 1086 sb.append(mBatteryConsumersCursorWindow.getFloat(i, j)).append(", "); 1087 break; 1088 case Cursor.FIELD_TYPE_STRING: 1089 sb.append(mBatteryConsumersCursorWindow.getString(i, j)).append(", "); 1090 break; 1091 case Cursor.FIELD_TYPE_BLOB: 1092 sb.append("BLOB, "); 1093 break; 1094 } 1095 } 1096 sb.setLength(sb.length() - 2); 1097 writer.println(sb); 1098 } 1099 } 1100 } 1101 } 1102