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