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