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.annotation.Nullable; 22 import android.database.CursorWindow; 23 import android.util.Slog; 24 import android.util.proto.ProtoOutputStream; 25 26 import java.io.PrintWriter; 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 import java.util.ArrayList; 30 31 /** 32 * Interface for objects containing battery attribution data. 33 * 34 * @hide 35 */ 36 public abstract class BatteryConsumer { 37 38 private static final String TAG = "BatteryConsumer"; 39 40 /** 41 * Power usage component, describing the particular part of the system 42 * responsible for power drain. 43 * 44 * @hide 45 */ 46 @IntDef(prefix = {"POWER_COMPONENT_"}, value = { 47 POWER_COMPONENT_ANY, 48 POWER_COMPONENT_SCREEN, 49 POWER_COMPONENT_CPU, 50 POWER_COMPONENT_BLUETOOTH, 51 POWER_COMPONENT_CAMERA, 52 POWER_COMPONENT_AUDIO, 53 POWER_COMPONENT_VIDEO, 54 POWER_COMPONENT_FLASHLIGHT, 55 POWER_COMPONENT_MOBILE_RADIO, 56 POWER_COMPONENT_SYSTEM_SERVICES, 57 POWER_COMPONENT_SENSORS, 58 POWER_COMPONENT_GNSS, 59 POWER_COMPONENT_WIFI, 60 POWER_COMPONENT_WAKELOCK, 61 POWER_COMPONENT_MEMORY, 62 POWER_COMPONENT_PHONE, 63 POWER_COMPONENT_IDLE, 64 POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS, 65 }) 66 @Retention(RetentionPolicy.SOURCE) 67 public static @interface PowerComponent { 68 } 69 70 public static final int POWER_COMPONENT_ANY = -1; 71 public static final int POWER_COMPONENT_SCREEN = OsProtoEnums.POWER_COMPONENT_SCREEN; // 0 72 public static final int POWER_COMPONENT_CPU = OsProtoEnums.POWER_COMPONENT_CPU; // 1 73 public static final int POWER_COMPONENT_BLUETOOTH = OsProtoEnums.POWER_COMPONENT_BLUETOOTH; // 2 74 public static final int POWER_COMPONENT_CAMERA = OsProtoEnums.POWER_COMPONENT_CAMERA; // 3 75 public static final int POWER_COMPONENT_AUDIO = OsProtoEnums.POWER_COMPONENT_AUDIO; // 4 76 public static final int POWER_COMPONENT_VIDEO = OsProtoEnums.POWER_COMPONENT_VIDEO; // 5 77 public static final int POWER_COMPONENT_FLASHLIGHT = 78 OsProtoEnums.POWER_COMPONENT_FLASHLIGHT; // 6 79 public static final int POWER_COMPONENT_SYSTEM_SERVICES = 80 OsProtoEnums.POWER_COMPONENT_SYSTEM_SERVICES; // 7 81 public static final int POWER_COMPONENT_MOBILE_RADIO = 82 OsProtoEnums.POWER_COMPONENT_MOBILE_RADIO; // 8 83 public static final int POWER_COMPONENT_SENSORS = OsProtoEnums.POWER_COMPONENT_SENSORS; // 9 84 public static final int POWER_COMPONENT_GNSS = OsProtoEnums.POWER_COMPONENT_GNSS; // 10 85 public static final int POWER_COMPONENT_WIFI = OsProtoEnums.POWER_COMPONENT_WIFI; // 11 86 public static final int POWER_COMPONENT_WAKELOCK = OsProtoEnums.POWER_COMPONENT_WAKELOCK; // 12 87 public static final int POWER_COMPONENT_MEMORY = OsProtoEnums.POWER_COMPONENT_MEMORY; // 13 88 public static final int POWER_COMPONENT_PHONE = OsProtoEnums.POWER_COMPONENT_PHONE; // 14 89 public static final int POWER_COMPONENT_AMBIENT_DISPLAY = 90 OsProtoEnums.POWER_COMPONENT_AMBIENT_DISPLAY; // 15 91 public static final int POWER_COMPONENT_IDLE = OsProtoEnums.POWER_COMPONENT_IDLE; // 16 92 // Power that is re-attributed to other battery consumers. For example, for System Server 93 // this represents the power attributed to apps requesting system services. 94 // The value should be negative or zero. 95 public static final int POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS = 96 OsProtoEnums.POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS; // 17 97 98 public static final int POWER_COMPONENT_COUNT = 18; 99 100 public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000; 101 public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999; 102 103 private static final String[] sPowerComponentNames = new String[POWER_COMPONENT_COUNT]; 104 105 static { 106 // Assign individually to avoid future mismatch 107 sPowerComponentNames[POWER_COMPONENT_SCREEN] = "screen"; 108 sPowerComponentNames[POWER_COMPONENT_CPU] = "cpu"; 109 sPowerComponentNames[POWER_COMPONENT_BLUETOOTH] = "bluetooth"; 110 sPowerComponentNames[POWER_COMPONENT_CAMERA] = "camera"; 111 sPowerComponentNames[POWER_COMPONENT_AUDIO] = "audio"; 112 sPowerComponentNames[POWER_COMPONENT_VIDEO] = "video"; 113 sPowerComponentNames[POWER_COMPONENT_FLASHLIGHT] = "flashlight"; 114 sPowerComponentNames[POWER_COMPONENT_SYSTEM_SERVICES] = "system_services"; 115 sPowerComponentNames[POWER_COMPONENT_MOBILE_RADIO] = "mobile_radio"; 116 sPowerComponentNames[POWER_COMPONENT_SENSORS] = "sensors"; 117 sPowerComponentNames[POWER_COMPONENT_GNSS] = "gnss"; 118 sPowerComponentNames[POWER_COMPONENT_WIFI] = "wifi"; 119 sPowerComponentNames[POWER_COMPONENT_WAKELOCK] = "wakelock"; 120 sPowerComponentNames[POWER_COMPONENT_MEMORY] = "memory"; 121 sPowerComponentNames[POWER_COMPONENT_PHONE] = "phone"; 122 sPowerComponentNames[POWER_COMPONENT_AMBIENT_DISPLAY] = "ambient_display"; 123 sPowerComponentNames[POWER_COMPONENT_IDLE] = "idle"; 124 sPowerComponentNames[POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS] = "reattributed"; 125 } 126 127 /** 128 * Identifiers of models used for power estimation. 129 * 130 * @hide 131 */ 132 @IntDef(prefix = {"POWER_MODEL_"}, value = { 133 POWER_MODEL_UNDEFINED, 134 POWER_MODEL_POWER_PROFILE, 135 POWER_MODEL_ENERGY_CONSUMPTION, 136 }) 137 @Retention(RetentionPolicy.SOURCE) 138 public @interface PowerModel { 139 } 140 141 /** 142 * Unspecified power model. 143 */ 144 public static final int POWER_MODEL_UNDEFINED = 0; 145 146 /** 147 * Power model that is based on average consumption rates that hardware components 148 * consume in various states. 149 */ 150 public static final int POWER_MODEL_POWER_PROFILE = 1; 151 152 /** 153 * Power model that is based on energy consumption stats provided by PowerStats HAL. 154 */ 155 public static final int POWER_MODEL_ENERGY_CONSUMPTION = 2; 156 157 /** 158 * Identifiers of consumed power aggregations. 159 * 160 * @hide 161 */ 162 @IntDef(prefix = {"PROCESS_STATE_"}, value = { 163 PROCESS_STATE_ANY, 164 PROCESS_STATE_UNSPECIFIED, 165 PROCESS_STATE_FOREGROUND, 166 PROCESS_STATE_BACKGROUND, 167 PROCESS_STATE_FOREGROUND_SERVICE, 168 PROCESS_STATE_CACHED, 169 }) 170 @Retention(RetentionPolicy.SOURCE) 171 public @interface ProcessState { 172 } 173 174 public static final int PROCESS_STATE_UNSPECIFIED = 0; 175 public static final int PROCESS_STATE_ANY = PROCESS_STATE_UNSPECIFIED; 176 public static final int PROCESS_STATE_FOREGROUND = 1; 177 public static final int PROCESS_STATE_BACKGROUND = 2; 178 public static final int PROCESS_STATE_FOREGROUND_SERVICE = 3; 179 public static final int PROCESS_STATE_CACHED = 4; 180 181 public static final int PROCESS_STATE_COUNT = 5; 182 183 private static final String[] sProcessStateNames = new String[PROCESS_STATE_COUNT]; 184 185 static { 186 // Assign individually to avoid future mismatch 187 sProcessStateNames[PROCESS_STATE_UNSPECIFIED] = "unspecified"; 188 sProcessStateNames[PROCESS_STATE_FOREGROUND] = "fg"; 189 sProcessStateNames[PROCESS_STATE_BACKGROUND] = "bg"; 190 sProcessStateNames[PROCESS_STATE_FOREGROUND_SERVICE] = "fgs"; 191 sProcessStateNames[PROCESS_STATE_CACHED] = "cached"; 192 } 193 194 private static final int[] SUPPORTED_POWER_COMPONENTS_PER_PROCESS_STATE = { 195 POWER_COMPONENT_CPU, 196 POWER_COMPONENT_MOBILE_RADIO, 197 POWER_COMPONENT_WIFI, 198 POWER_COMPONENT_BLUETOOTH, 199 }; 200 201 static final int COLUMN_INDEX_BATTERY_CONSUMER_TYPE = 0; 202 static final int COLUMN_COUNT = 1; 203 204 /** 205 * Identifies power attribution dimensions that a caller is interested in. 206 */ 207 public static final class Dimensions { 208 public final @PowerComponent int powerComponent; 209 public final @ProcessState int processState; 210 Dimensions(int powerComponent, int processState)211 public Dimensions(int powerComponent, int processState) { 212 this.powerComponent = powerComponent; 213 this.processState = processState; 214 } 215 216 @Override toString()217 public String toString() { 218 boolean dimensionSpecified = false; 219 StringBuilder sb = new StringBuilder(); 220 if (powerComponent != POWER_COMPONENT_ANY) { 221 sb.append("powerComponent=").append(sPowerComponentNames[powerComponent]); 222 dimensionSpecified = true; 223 } 224 if (processState != PROCESS_STATE_UNSPECIFIED) { 225 if (dimensionSpecified) { 226 sb.append(", "); 227 } 228 sb.append("processState=").append(sProcessStateNames[processState]); 229 dimensionSpecified = true; 230 } 231 if (!dimensionSpecified) { 232 sb.append("any components and process states"); 233 } 234 return sb.toString(); 235 } 236 } 237 238 public static final Dimensions UNSPECIFIED_DIMENSIONS = 239 new Dimensions(POWER_COMPONENT_ANY, PROCESS_STATE_ANY); 240 241 /** 242 * Identifies power attribution dimensions that are captured by an data element of 243 * a BatteryConsumer. These Keys are used to access those values and to set them using 244 * Builders. See for example {@link #getConsumedPower(Key)}. 245 * 246 * Keys cannot be allocated by the client - they can only be obtained by calling 247 * {@link #getKeys} or {@link #getKey}. All BatteryConsumers that are part of the 248 * same BatteryUsageStats share the same set of keys, therefore it is safe to obtain 249 * the keys from one BatteryConsumer and apply them to other BatteryConsumers 250 * in the same BatteryUsageStats. 251 */ 252 public static final class Key { 253 public final @PowerComponent int powerComponent; 254 public final @ProcessState int processState; 255 256 final int mPowerModelColumnIndex; 257 final int mPowerColumnIndex; 258 final int mDurationColumnIndex; 259 private String mShortString; 260 Key(int powerComponent, int processState, int powerModelColumnIndex, int powerColumnIndex, int durationColumnIndex)261 private Key(int powerComponent, int processState, int powerModelColumnIndex, 262 int powerColumnIndex, int durationColumnIndex) { 263 this.powerComponent = powerComponent; 264 this.processState = processState; 265 266 mPowerModelColumnIndex = powerModelColumnIndex; 267 mPowerColumnIndex = powerColumnIndex; 268 mDurationColumnIndex = durationColumnIndex; 269 } 270 271 @SuppressWarnings("EqualsUnsafeCast") 272 @Override equals(Object o)273 public boolean equals(Object o) { 274 // Skipping null and class check for performance 275 final Key key = (Key) o; 276 return powerComponent == key.powerComponent 277 && processState == key.processState; 278 } 279 280 @Override hashCode()281 public int hashCode() { 282 int result = powerComponent; 283 result = 31 * result + processState; 284 return result; 285 } 286 287 /** 288 * Returns a string suitable for use in dumpsys. 289 */ toShortString()290 public String toShortString() { 291 if (mShortString == null) { 292 StringBuilder sb = new StringBuilder(); 293 sb.append(powerComponentIdToString(powerComponent)); 294 if (processState != PROCESS_STATE_UNSPECIFIED) { 295 sb.append(':'); 296 sb.append(processStateToString(processState)); 297 } 298 mShortString = sb.toString(); 299 } 300 return mShortString; 301 } 302 } 303 304 protected final BatteryConsumerData mData; 305 protected final PowerComponents mPowerComponents; 306 BatteryConsumer(BatteryConsumerData data, @NonNull PowerComponents powerComponents)307 protected BatteryConsumer(BatteryConsumerData data, @NonNull PowerComponents powerComponents) { 308 mData = data; 309 mPowerComponents = powerComponents; 310 } 311 BatteryConsumer(BatteryConsumerData data)312 public BatteryConsumer(BatteryConsumerData data) { 313 mData = data; 314 mPowerComponents = new PowerComponents(data); 315 } 316 317 /** 318 * Total power consumed by this consumer, in mAh. 319 */ getConsumedPower()320 public double getConsumedPower() { 321 return mPowerComponents.getConsumedPower(UNSPECIFIED_DIMENSIONS); 322 } 323 324 /** 325 * Returns power consumed aggregated over the specified dimensions, in mAh. 326 */ getConsumedPower(Dimensions dimensions)327 public double getConsumedPower(Dimensions dimensions) { 328 return mPowerComponents.getConsumedPower(dimensions); 329 } 330 331 /** 332 * Returns keys for various power values attributed to the specified component 333 * held by this BatteryUsageStats object. 334 */ getKeys(@owerComponent int componentId)335 public Key[] getKeys(@PowerComponent int componentId) { 336 return mData.getKeys(componentId); 337 } 338 339 /** 340 * Returns the key for the power attributed to the specified component, 341 * for all values of other dimensions such as process state. 342 */ getKey(@owerComponent int componentId)343 public Key getKey(@PowerComponent int componentId) { 344 return mData.getKey(componentId, PROCESS_STATE_UNSPECIFIED); 345 } 346 347 /** 348 * Returns the key for the power attributed to the specified component and process state. 349 */ getKey(@owerComponent int componentId, @ProcessState int processState)350 public Key getKey(@PowerComponent int componentId, @ProcessState int processState) { 351 return mData.getKey(componentId, processState); 352 } 353 354 /** 355 * Returns the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc. 356 * 357 * @param componentId The ID of the power component, e.g. 358 * {@link BatteryConsumer#POWER_COMPONENT_CPU}. 359 * @return Amount of consumed power in mAh. 360 */ getConsumedPower(@owerComponent int componentId)361 public double getConsumedPower(@PowerComponent int componentId) { 362 return mPowerComponents.getConsumedPower( 363 mData.getKeyOrThrow(componentId, PROCESS_STATE_UNSPECIFIED)); 364 } 365 366 /** 367 * Returns the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc. 368 * 369 * @param key The key of the power component, obtained by calling {@link #getKey} or 370 * {@link #getKeys} method. 371 * @return Amount of consumed power in mAh. 372 */ getConsumedPower(@onNull Key key)373 public double getConsumedPower(@NonNull Key key) { 374 return mPowerComponents.getConsumedPower(key); 375 } 376 377 /** 378 * Returns the ID of the model that was used for power estimation. 379 * 380 * @param componentId The ID of the power component, e.g. 381 * {@link BatteryConsumer#POWER_COMPONENT_CPU}. 382 */ getPowerModel(@atteryConsumer.PowerComponent int componentId)383 public @PowerModel int getPowerModel(@BatteryConsumer.PowerComponent int componentId) { 384 return mPowerComponents.getPowerModel( 385 mData.getKeyOrThrow(componentId, PROCESS_STATE_UNSPECIFIED)); 386 } 387 388 /** 389 * Returns the ID of the model that was used for power estimation. 390 * 391 * @param key The key of the power component, obtained by calling {@link #getKey} or 392 * {@link #getKeys} method. 393 */ getPowerModel(@onNull BatteryConsumer.Key key)394 public @PowerModel int getPowerModel(@NonNull BatteryConsumer.Key key) { 395 return mPowerComponents.getPowerModel(key); 396 } 397 398 /** 399 * Returns the amount of drain attributed to the specified custom drain type. 400 * 401 * @param componentId The ID of the custom power component. 402 * @return Amount of consumed power in mAh. 403 */ getConsumedPowerForCustomComponent(int componentId)404 public double getConsumedPowerForCustomComponent(int componentId) { 405 return mPowerComponents.getConsumedPowerForCustomComponent(componentId); 406 } 407 getCustomPowerComponentCount()408 public int getCustomPowerComponentCount() { 409 return mData.layout.customPowerComponentCount; 410 } 411 412 /** 413 * Returns the name of the specified power component. 414 * 415 * @param componentId The ID of the custom power component. 416 */ getCustomPowerComponentName(int componentId)417 public String getCustomPowerComponentName(int componentId) { 418 return mPowerComponents.getCustomPowerComponentName(componentId); 419 } 420 421 /** 422 * Returns the amount of time since BatteryStats reset used by the specified component, e.g. 423 * CPU, WiFi etc. 424 * 425 * @param componentId The ID of the power component, e.g. 426 * {@link UidBatteryConsumer#POWER_COMPONENT_CPU}. 427 * @return Amount of time in milliseconds. 428 */ getUsageDurationMillis(@owerComponent int componentId)429 public long getUsageDurationMillis(@PowerComponent int componentId) { 430 return mPowerComponents.getUsageDurationMillis(getKey(componentId)); 431 } 432 433 /** 434 * Returns the amount of time since BatteryStats reset used by the specified component, e.g. 435 * CPU, WiFi etc. 436 * 437 * 438 * @param key The key of the power component, obtained by calling {@link #getKey} or 439 * {@link #getKeys} method. 440 * @return Amount of time in milliseconds. 441 */ getUsageDurationMillis(@onNull Key key)442 public long getUsageDurationMillis(@NonNull Key key) { 443 return mPowerComponents.getUsageDurationMillis(key); 444 } 445 446 /** 447 * Returns the amount of usage time attributed to the specified custom component 448 * since BatteryStats reset. 449 * 450 * @param componentId The ID of the custom power component. 451 * @return Amount of time in milliseconds. 452 */ getUsageDurationForCustomComponentMillis(int componentId)453 public long getUsageDurationForCustomComponentMillis(int componentId) { 454 return mPowerComponents.getUsageDurationForCustomComponentMillis(componentId); 455 } 456 457 /** 458 * Returns the name of the specified component. Intended for logging and debugging. 459 */ powerComponentIdToString(@atteryConsumer.PowerComponent int componentId)460 public static String powerComponentIdToString(@BatteryConsumer.PowerComponent int componentId) { 461 if (componentId == POWER_COMPONENT_ANY) { 462 return "all"; 463 } 464 return sPowerComponentNames[componentId]; 465 } 466 467 /** 468 * Returns the name of the specified power model. Intended for logging and debugging. 469 */ powerModelToString(@atteryConsumer.PowerModel int powerModel)470 public static String powerModelToString(@BatteryConsumer.PowerModel int powerModel) { 471 switch (powerModel) { 472 case BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION: 473 return "energy consumption"; 474 case BatteryConsumer.POWER_MODEL_POWER_PROFILE: 475 return "power profile"; 476 default: 477 return ""; 478 } 479 } 480 481 /** 482 * Returns the equivalent PowerModel enum for the specified power model. 483 * {@see BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsage.PowerModel} 484 */ powerModelToProtoEnum(@atteryConsumer.PowerModel int powerModel)485 public static int powerModelToProtoEnum(@BatteryConsumer.PowerModel int powerModel) { 486 switch (powerModel) { 487 case BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION: 488 return BatteryUsageStatsAtomsProto.PowerComponentModel.MEASURED_ENERGY; 489 case BatteryConsumer.POWER_MODEL_POWER_PROFILE: 490 return BatteryUsageStatsAtomsProto.PowerComponentModel.POWER_PROFILE; 491 default: 492 return BatteryUsageStatsAtomsProto.PowerComponentModel.UNDEFINED; 493 } 494 } 495 496 /** 497 * Returns the name of the specified process state. Intended for logging and debugging. 498 */ processStateToString(@atteryConsumer.ProcessState int processState)499 public static String processStateToString(@BatteryConsumer.ProcessState int processState) { 500 return sProcessStateNames[processState]; 501 } 502 503 /** 504 * Prints the stats in a human-readable format. 505 */ dump(PrintWriter pw)506 public void dump(PrintWriter pw) { 507 dump(pw, true); 508 } 509 510 /** 511 * Prints the stats in a human-readable format. 512 * 513 * @param skipEmptyComponents if true, omit any power components with a zero amount. 514 */ dump(PrintWriter pw, boolean skipEmptyComponents)515 public abstract void dump(PrintWriter pw, boolean skipEmptyComponents); 516 517 /** Returns whether there are any atoms.proto BATTERY_CONSUMER_DATA data to write to a proto. */ hasStatsProtoData()518 boolean hasStatsProtoData() { 519 return writeStatsProtoImpl(null, /* Irrelevant fieldId: */ 0); 520 } 521 522 /** Writes the atoms.proto BATTERY_CONSUMER_DATA for this BatteryConsumer to the given proto. */ writeStatsProto(@onNull ProtoOutputStream proto, long fieldId)523 void writeStatsProto(@NonNull ProtoOutputStream proto, long fieldId) { 524 writeStatsProtoImpl(proto, fieldId); 525 } 526 527 /** 528 * Returns whether there are any atoms.proto BATTERY_CONSUMER_DATA data to write to a proto, 529 * and writes it to the given proto if it is non-null. 530 */ writeStatsProtoImpl(@ullable ProtoOutputStream proto, long fieldId)531 private boolean writeStatsProtoImpl(@Nullable ProtoOutputStream proto, long fieldId) { 532 final long totalConsumedPowerDeciCoulombs = convertMahToDeciCoulombs(getConsumedPower()); 533 534 if (totalConsumedPowerDeciCoulombs == 0) { 535 // NOTE: Strictly speaking we should also check !mPowerComponents.hasStatsProtoData(). 536 // However, that call is a bit expensive (a for loop). And the only way that 537 // totalConsumedPower can be 0 while mPowerComponents.hasStatsProtoData() is true is 538 // if POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS (which is the only negative 539 // allowed) happens to exactly equal the sum of all other components, which 540 // can't really happen in practice. 541 // So we'll just adopt the rule "if total==0, don't write any details". 542 // If negative values are used for other things in the future, this can be revisited. 543 return false; 544 } 545 if (proto == null) { 546 // We're just asked whether there is data, not to actually write it. And there is. 547 return true; 548 } 549 550 final long token = proto.start(fieldId); 551 proto.write( 552 BatteryUsageStatsAtomsProto.BatteryConsumerData.TOTAL_CONSUMED_POWER_DECI_COULOMBS, 553 totalConsumedPowerDeciCoulombs); 554 mPowerComponents.writeStatsProto(proto); 555 proto.end(token); 556 557 return true; 558 } 559 560 /** Converts charge from milliamp hours (mAh) to decicoulombs (dC). */ convertMahToDeciCoulombs(double powerMah)561 static long convertMahToDeciCoulombs(double powerMah) { 562 return (long) (powerMah * (10 * 3600 / 1000) + 0.5); 563 } 564 565 static class BatteryConsumerData { 566 private final CursorWindow mCursorWindow; 567 private final int mCursorRow; 568 public final BatteryConsumerDataLayout layout; 569 BatteryConsumerData(CursorWindow cursorWindow, int cursorRow, BatteryConsumerDataLayout layout)570 BatteryConsumerData(CursorWindow cursorWindow, int cursorRow, 571 BatteryConsumerDataLayout layout) { 572 mCursorWindow = cursorWindow; 573 mCursorRow = cursorRow; 574 this.layout = layout; 575 } 576 577 @Nullable create(CursorWindow cursorWindow, BatteryConsumerDataLayout layout)578 static BatteryConsumerData create(CursorWindow cursorWindow, 579 BatteryConsumerDataLayout layout) { 580 int cursorRow = cursorWindow.getNumRows(); 581 if (!cursorWindow.allocRow()) { 582 Slog.e(TAG, "Cannot allocate BatteryConsumerData: too many UIDs: " + cursorRow); 583 cursorRow = -1; 584 } 585 return new BatteryConsumerData(cursorWindow, cursorRow, layout); 586 } 587 getKeys(int componentId)588 public Key[] getKeys(int componentId) { 589 return layout.keys[componentId]; 590 } 591 getKeyOrThrow(int componentId, int processState)592 Key getKeyOrThrow(int componentId, int processState) { 593 Key key = getKey(componentId, processState); 594 if (key == null) { 595 if (processState == PROCESS_STATE_ANY) { 596 throw new IllegalArgumentException( 597 "Unsupported power component ID: " + componentId); 598 } else { 599 throw new IllegalArgumentException( 600 "Unsupported power component ID: " + componentId 601 + " process state: " + processState); 602 } 603 } 604 return key; 605 } 606 getKey(int componentId, int processState)607 Key getKey(int componentId, int processState) { 608 if (componentId >= POWER_COMPONENT_COUNT) { 609 return null; 610 } 611 612 if (processState == PROCESS_STATE_ANY) { 613 // The 0-th key for each component corresponds to the roll-up, 614 // across all dimensions. We might as well skip the iteration over the array. 615 return layout.keys[componentId][0]; 616 } else { 617 for (Key key : layout.keys[componentId]) { 618 if (key.processState == processState) { 619 return key; 620 } 621 } 622 } 623 return null; 624 } 625 putInt(int columnIndex, int value)626 void putInt(int columnIndex, int value) { 627 if (mCursorRow == -1) { 628 return; 629 } 630 mCursorWindow.putLong(value, mCursorRow, columnIndex); 631 } 632 getInt(int columnIndex)633 int getInt(int columnIndex) { 634 if (mCursorRow == -1) { 635 return 0; 636 } 637 return mCursorWindow.getInt(mCursorRow, columnIndex); 638 } 639 putDouble(int columnIndex, double value)640 void putDouble(int columnIndex, double value) { 641 if (mCursorRow == -1) { 642 return; 643 } 644 mCursorWindow.putDouble(value, mCursorRow, columnIndex); 645 } 646 getDouble(int columnIndex)647 double getDouble(int columnIndex) { 648 if (mCursorRow == -1) { 649 return 0; 650 } 651 return mCursorWindow.getDouble(mCursorRow, columnIndex); 652 } 653 putLong(int columnIndex, long value)654 void putLong(int columnIndex, long value) { 655 if (mCursorRow == -1) { 656 return; 657 } 658 mCursorWindow.putLong(value, mCursorRow, columnIndex); 659 } 660 getLong(int columnIndex)661 long getLong(int columnIndex) { 662 if (mCursorRow == -1) { 663 return 0; 664 } 665 return mCursorWindow.getLong(mCursorRow, columnIndex); 666 } 667 putString(int columnIndex, String value)668 void putString(int columnIndex, String value) { 669 if (mCursorRow == -1) { 670 return; 671 } 672 mCursorWindow.putString(value, mCursorRow, columnIndex); 673 } 674 getString(int columnIndex)675 String getString(int columnIndex) { 676 if (mCursorRow == -1) { 677 return null; 678 } 679 return mCursorWindow.getString(mCursorRow, columnIndex); 680 } 681 } 682 683 static class BatteryConsumerDataLayout { 684 private static final Key[] KEY_ARRAY = new Key[0]; 685 public final String[] customPowerComponentNames; 686 public final int customPowerComponentCount; 687 public final boolean powerModelsIncluded; 688 public final boolean processStateDataIncluded; 689 public final Key[][] keys; 690 public final int totalConsumedPowerColumnIndex; 691 public final int firstCustomConsumedPowerColumn; 692 public final int firstCustomUsageDurationColumn; 693 public final int columnCount; 694 public final Key[][] processStateKeys; 695 BatteryConsumerDataLayout(int firstColumn, String[] customPowerComponentNames, boolean powerModelsIncluded, boolean includeProcessStateData)696 private BatteryConsumerDataLayout(int firstColumn, String[] customPowerComponentNames, 697 boolean powerModelsIncluded, boolean includeProcessStateData) { 698 this.customPowerComponentNames = customPowerComponentNames; 699 this.customPowerComponentCount = customPowerComponentNames.length; 700 this.powerModelsIncluded = powerModelsIncluded; 701 this.processStateDataIncluded = includeProcessStateData; 702 703 int columnIndex = firstColumn; 704 705 totalConsumedPowerColumnIndex = columnIndex++; 706 707 keys = new Key[POWER_COMPONENT_COUNT][]; 708 709 ArrayList<Key> perComponentKeys = new ArrayList<>(); 710 for (int componentId = 0; componentId < POWER_COMPONENT_COUNT; componentId++) { 711 perComponentKeys.clear(); 712 713 // Declare the Key for the power component, ignoring other dimensions. 714 perComponentKeys.add( 715 new Key(componentId, PROCESS_STATE_ANY, 716 powerModelsIncluded ? columnIndex++ : -1, // power model 717 columnIndex++, // power 718 columnIndex++ // usage duration 719 )); 720 721 // Declare Keys for all process states, if needed 722 if (includeProcessStateData) { 723 boolean isSupported = false; 724 for (int id : SUPPORTED_POWER_COMPONENTS_PER_PROCESS_STATE) { 725 if (id == componentId) { 726 isSupported = true; 727 break; 728 } 729 } 730 if (isSupported) { 731 for (int processState = 0; processState < PROCESS_STATE_COUNT; 732 processState++) { 733 if (processState == PROCESS_STATE_UNSPECIFIED) { 734 continue; 735 } 736 737 perComponentKeys.add( 738 new Key(componentId, processState, 739 powerModelsIncluded ? columnIndex++ : -1, // power model 740 columnIndex++, // power 741 columnIndex++ // usage duration 742 )); 743 } 744 } 745 } 746 747 keys[componentId] = perComponentKeys.toArray(KEY_ARRAY); 748 } 749 750 if (includeProcessStateData) { 751 processStateKeys = new Key[BatteryConsumer.PROCESS_STATE_COUNT][]; 752 ArrayList<Key> perProcStateKeys = new ArrayList<>(); 753 for (int processState = 0; processState < PROCESS_STATE_COUNT; processState++) { 754 if (processState == PROCESS_STATE_UNSPECIFIED) { 755 continue; 756 } 757 758 perProcStateKeys.clear(); 759 for (int i = 0; i < keys.length; i++) { 760 for (int j = 0; j < keys[i].length; j++) { 761 if (keys[i][j].processState == processState) { 762 perProcStateKeys.add(keys[i][j]); 763 } 764 } 765 } 766 processStateKeys[processState] = perProcStateKeys.toArray(KEY_ARRAY); 767 } 768 } else { 769 processStateKeys = null; 770 } 771 772 firstCustomConsumedPowerColumn = columnIndex; 773 columnIndex += customPowerComponentCount; 774 775 firstCustomUsageDurationColumn = columnIndex; 776 columnIndex += customPowerComponentCount; 777 778 columnCount = columnIndex; 779 } 780 } 781 createBatteryConsumerDataLayout( String[] customPowerComponentNames, boolean includePowerModels, boolean includeProcessStateData)782 static BatteryConsumerDataLayout createBatteryConsumerDataLayout( 783 String[] customPowerComponentNames, boolean includePowerModels, 784 boolean includeProcessStateData) { 785 int columnCount = BatteryConsumer.COLUMN_COUNT; 786 columnCount = Math.max(columnCount, AggregateBatteryConsumer.COLUMN_COUNT); 787 columnCount = Math.max(columnCount, UidBatteryConsumer.COLUMN_COUNT); 788 columnCount = Math.max(columnCount, UserBatteryConsumer.COLUMN_COUNT); 789 790 return new BatteryConsumerDataLayout(columnCount, customPowerComponentNames, 791 includePowerModels, includeProcessStateData); 792 } 793 794 protected abstract static class BaseBuilder<T extends BaseBuilder<?>> { 795 protected final BatteryConsumer.BatteryConsumerData mData; 796 protected final PowerComponents.Builder mPowerComponentsBuilder; 797 BaseBuilder(BatteryConsumer.BatteryConsumerData data, int consumerType, double minConsumedPowerThreshold)798 public BaseBuilder(BatteryConsumer.BatteryConsumerData data, int consumerType, 799 double minConsumedPowerThreshold) { 800 mData = data; 801 data.putLong(COLUMN_INDEX_BATTERY_CONSUMER_TYPE, consumerType); 802 803 mPowerComponentsBuilder = new PowerComponents.Builder(data, minConsumedPowerThreshold); 804 } 805 806 @Nullable getKeys(@owerComponent int componentId)807 public Key[] getKeys(@PowerComponent int componentId) { 808 return mData.getKeys(componentId); 809 } 810 811 @Nullable getKey(@owerComponent int componentId, @ProcessState int processState)812 public Key getKey(@PowerComponent int componentId, @ProcessState int processState) { 813 return mData.getKey(componentId, processState); 814 } 815 816 /** 817 * Sets the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc. 818 * 819 * @param componentId The ID of the power component, e.g. 820 * {@link BatteryConsumer#POWER_COMPONENT_CPU}. 821 * @param componentPower Amount of consumed power in mAh. 822 */ 823 @NonNull setConsumedPower(@owerComponent int componentId, double componentPower)824 public T setConsumedPower(@PowerComponent int componentId, double componentPower) { 825 return setConsumedPower(componentId, componentPower, POWER_MODEL_POWER_PROFILE); 826 } 827 828 /** 829 * Sets the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc. 830 * 831 * @param componentId The ID of the power component, e.g. 832 * {@link BatteryConsumer#POWER_COMPONENT_CPU}. 833 * @param componentPower Amount of consumed power in mAh. 834 */ 835 @SuppressWarnings("unchecked") 836 @NonNull setConsumedPower(@owerComponent int componentId, double componentPower, @PowerModel int powerModel)837 public T setConsumedPower(@PowerComponent int componentId, double componentPower, 838 @PowerModel int powerModel) { 839 mPowerComponentsBuilder.setConsumedPower(getKey(componentId, PROCESS_STATE_UNSPECIFIED), 840 componentPower, powerModel); 841 return (T) this; 842 } 843 844 @SuppressWarnings("unchecked") 845 @NonNull setConsumedPower(Key key, double componentPower, @PowerModel int powerModel)846 public T setConsumedPower(Key key, double componentPower, @PowerModel int powerModel) { 847 mPowerComponentsBuilder.setConsumedPower(key, componentPower, powerModel); 848 return (T) this; 849 } 850 851 /** 852 * Sets the amount of drain attributed to the specified custom drain type. 853 * 854 * @param componentId The ID of the custom power component. 855 * @param componentPower Amount of consumed power in mAh. 856 */ 857 @SuppressWarnings("unchecked") 858 @NonNull setConsumedPowerForCustomComponent(int componentId, double componentPower)859 public T setConsumedPowerForCustomComponent(int componentId, double componentPower) { 860 mPowerComponentsBuilder.setConsumedPowerForCustomComponent(componentId, componentPower); 861 return (T) this; 862 } 863 864 /** 865 * Sets the amount of time used by the specified component, e.g. CPU, WiFi etc. 866 * 867 * @param componentId The ID of the power component, e.g. 868 * {@link UidBatteryConsumer#POWER_COMPONENT_CPU}. 869 * @param componentUsageTimeMillis Amount of time in microseconds. 870 */ 871 @SuppressWarnings("unchecked") 872 @NonNull setUsageDurationMillis(@idBatteryConsumer.PowerComponent int componentId, long componentUsageTimeMillis)873 public T setUsageDurationMillis(@UidBatteryConsumer.PowerComponent int componentId, 874 long componentUsageTimeMillis) { 875 mPowerComponentsBuilder 876 .setUsageDurationMillis(getKey(componentId, PROCESS_STATE_UNSPECIFIED), 877 componentUsageTimeMillis); 878 return (T) this; 879 } 880 881 882 @SuppressWarnings("unchecked") 883 @NonNull setUsageDurationMillis(Key key, long componentUsageTimeMillis)884 public T setUsageDurationMillis(Key key, long componentUsageTimeMillis) { 885 mPowerComponentsBuilder.setUsageDurationMillis(key, componentUsageTimeMillis); 886 return (T) this; 887 } 888 889 /** 890 * Sets the amount of time used by the specified custom component. 891 * 892 * @param componentId The ID of the custom power component. 893 * @param componentUsageTimeMillis Amount of time in microseconds. 894 */ 895 @SuppressWarnings("unchecked") 896 @NonNull setUsageDurationForCustomComponentMillis(int componentId, long componentUsageTimeMillis)897 public T setUsageDurationForCustomComponentMillis(int componentId, 898 long componentUsageTimeMillis) { 899 mPowerComponentsBuilder.setUsageDurationForCustomComponentMillis(componentId, 900 componentUsageTimeMillis); 901 return (T) this; 902 } 903 904 /** 905 * Returns the total power accumulated by this builder so far. It may change 906 * by the time the {@code build()} method is called. 907 */ getTotalPower()908 public double getTotalPower() { 909 return mPowerComponentsBuilder.getTotalPower(); 910 } 911 } 912 } 913