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