• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_MEASURED_ENERGY,
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 measured by on-device power monitors.
154      */
155     public static final int POWER_MODEL_MEASURED_ENERGY = 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_MEASURED_ENERGY:
473                 return "measured energy";
474             case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
475                 return "power profile";
476             default:
477                 return "";
478         }
479     }
480 
481     /**
482      * Returns the name of the specified process state.  Intended for logging and debugging.
483      */
processStateToString(@atteryConsumer.ProcessState int processState)484     public static String processStateToString(@BatteryConsumer.ProcessState int processState) {
485         return sProcessStateNames[processState];
486     }
487 
488     /**
489      * Prints the stats in a human-readable format.
490      */
dump(PrintWriter pw)491     public void dump(PrintWriter pw) {
492         dump(pw, true);
493     }
494 
495     /**
496      * Prints the stats in a human-readable format.
497      *
498      * @param skipEmptyComponents if true, omit any power components with a zero amount.
499      */
dump(PrintWriter pw, boolean skipEmptyComponents)500     public abstract void dump(PrintWriter pw, boolean skipEmptyComponents);
501 
502     /** Returns whether there are any atoms.proto BATTERY_CONSUMER_DATA data to write to a proto. */
hasStatsProtoData()503     boolean hasStatsProtoData() {
504         return writeStatsProtoImpl(null, /* Irrelevant fieldId: */ 0);
505     }
506 
507     /** Writes the atoms.proto BATTERY_CONSUMER_DATA for this BatteryConsumer to the given proto. */
writeStatsProto(@onNull ProtoOutputStream proto, long fieldId)508     void writeStatsProto(@NonNull ProtoOutputStream proto, long fieldId) {
509         writeStatsProtoImpl(proto, fieldId);
510     }
511 
512     /**
513      * Returns whether there are any atoms.proto BATTERY_CONSUMER_DATA data to write to a proto,
514      * and writes it to the given proto if it is non-null.
515      */
writeStatsProtoImpl(@ullable ProtoOutputStream proto, long fieldId)516     private boolean writeStatsProtoImpl(@Nullable ProtoOutputStream proto, long fieldId) {
517         final long totalConsumedPowerDeciCoulombs = convertMahToDeciCoulombs(getConsumedPower());
518 
519         if (totalConsumedPowerDeciCoulombs == 0) {
520             // NOTE: Strictly speaking we should also check !mPowerComponents.hasStatsProtoData().
521             // However, that call is a bit expensive (a for loop). And the only way that
522             // totalConsumedPower can be 0 while mPowerComponents.hasStatsProtoData() is true is
523             // if POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS (which is the only negative
524             // allowed) happens to exactly equal the sum of all other components, which
525             // can't really happen in practice.
526             // So we'll just adopt the rule "if total==0, don't write any details".
527             // If negative values are used for other things in the future, this can be revisited.
528             return false;
529         }
530         if (proto == null) {
531             // We're just asked whether there is data, not to actually write it. And there is.
532             return true;
533         }
534 
535         final long token = proto.start(fieldId);
536         proto.write(
537                 BatteryUsageStatsAtomsProto.BatteryConsumerData.TOTAL_CONSUMED_POWER_DECI_COULOMBS,
538                 totalConsumedPowerDeciCoulombs);
539         mPowerComponents.writeStatsProto(proto);
540         proto.end(token);
541 
542         return true;
543     }
544 
545     /** Converts charge from milliamp hours (mAh) to decicoulombs (dC). */
convertMahToDeciCoulombs(double powerMah)546     static long convertMahToDeciCoulombs(double powerMah) {
547         return (long) (powerMah * (10 * 3600 / 1000) + 0.5);
548     }
549 
550     static class BatteryConsumerData {
551         private final CursorWindow mCursorWindow;
552         private final int mCursorRow;
553         public final BatteryConsumerDataLayout layout;
554 
BatteryConsumerData(CursorWindow cursorWindow, int cursorRow, BatteryConsumerDataLayout layout)555         BatteryConsumerData(CursorWindow cursorWindow, int cursorRow,
556                 BatteryConsumerDataLayout layout) {
557             mCursorWindow = cursorWindow;
558             mCursorRow = cursorRow;
559             this.layout = layout;
560         }
561 
562         @Nullable
create(CursorWindow cursorWindow, BatteryConsumerDataLayout layout)563         static BatteryConsumerData create(CursorWindow cursorWindow,
564                 BatteryConsumerDataLayout layout) {
565             int cursorRow = cursorWindow.getNumRows();
566             if (!cursorWindow.allocRow()) {
567                 Slog.e(TAG, "Cannot allocate BatteryConsumerData: too many UIDs: " + cursorRow);
568                 cursorRow = -1;
569             }
570             return new BatteryConsumerData(cursorWindow, cursorRow, layout);
571         }
572 
getKeys(int componentId)573         public Key[] getKeys(int componentId) {
574             return layout.keys[componentId];
575         }
576 
getKeyOrThrow(int componentId, int processState)577         Key getKeyOrThrow(int componentId, int processState) {
578             Key key = getKey(componentId, processState);
579             if (key == null) {
580                 if (processState == PROCESS_STATE_ANY) {
581                     throw new IllegalArgumentException(
582                             "Unsupported power component ID: " + componentId);
583                 } else {
584                     throw new IllegalArgumentException(
585                             "Unsupported power component ID: " + componentId
586                                     + " process state: " + processState);
587                 }
588             }
589             return key;
590         }
591 
getKey(int componentId, int processState)592         Key getKey(int componentId, int processState) {
593             if (componentId >= POWER_COMPONENT_COUNT) {
594                 return null;
595             }
596 
597             if (processState == PROCESS_STATE_ANY) {
598                 // The 0-th key for each component corresponds to the roll-up,
599                 // across all dimensions. We might as well skip the iteration over the array.
600                 return layout.keys[componentId][0];
601             } else {
602                 for (Key key : layout.keys[componentId]) {
603                     if (key.processState == processState) {
604                         return key;
605                     }
606                 }
607             }
608             return null;
609         }
610 
putInt(int columnIndex, int value)611         void putInt(int columnIndex, int value) {
612             if (mCursorRow == -1) {
613                 return;
614             }
615             mCursorWindow.putLong(value, mCursorRow, columnIndex);
616         }
617 
getInt(int columnIndex)618         int getInt(int columnIndex) {
619             if (mCursorRow == -1) {
620                 return 0;
621             }
622             return mCursorWindow.getInt(mCursorRow, columnIndex);
623         }
624 
putDouble(int columnIndex, double value)625         void putDouble(int columnIndex, double value) {
626             if (mCursorRow == -1) {
627                 return;
628             }
629             mCursorWindow.putDouble(value, mCursorRow, columnIndex);
630         }
631 
getDouble(int columnIndex)632         double getDouble(int columnIndex) {
633             if (mCursorRow == -1) {
634                 return 0;
635             }
636             return mCursorWindow.getDouble(mCursorRow, columnIndex);
637         }
638 
putLong(int columnIndex, long value)639         void putLong(int columnIndex, long value) {
640             if (mCursorRow == -1) {
641                 return;
642             }
643             mCursorWindow.putLong(value, mCursorRow, columnIndex);
644         }
645 
getLong(int columnIndex)646         long getLong(int columnIndex) {
647             if (mCursorRow == -1) {
648                 return 0;
649             }
650             return mCursorWindow.getLong(mCursorRow, columnIndex);
651         }
652 
putString(int columnIndex, String value)653         void putString(int columnIndex, String value) {
654             if (mCursorRow == -1) {
655                 return;
656             }
657             mCursorWindow.putString(value, mCursorRow, columnIndex);
658         }
659 
getString(int columnIndex)660         String getString(int columnIndex) {
661             if (mCursorRow == -1) {
662                 return null;
663             }
664             return mCursorWindow.getString(mCursorRow, columnIndex);
665         }
666     }
667 
668     static class BatteryConsumerDataLayout {
669         private static final Key[] KEY_ARRAY = new Key[0];
670         public final String[] customPowerComponentNames;
671         public final int customPowerComponentCount;
672         public final boolean powerModelsIncluded;
673         public final boolean processStateDataIncluded;
674         public final Key[][] keys;
675         public final int totalConsumedPowerColumnIndex;
676         public final int firstCustomConsumedPowerColumn;
677         public final int firstCustomUsageDurationColumn;
678         public final int columnCount;
679         public final Key[][] processStateKeys;
680 
BatteryConsumerDataLayout(int firstColumn, String[] customPowerComponentNames, boolean powerModelsIncluded, boolean includeProcessStateData)681         private BatteryConsumerDataLayout(int firstColumn, String[] customPowerComponentNames,
682                 boolean powerModelsIncluded, boolean includeProcessStateData) {
683             this.customPowerComponentNames = customPowerComponentNames;
684             this.customPowerComponentCount = customPowerComponentNames.length;
685             this.powerModelsIncluded = powerModelsIncluded;
686             this.processStateDataIncluded = includeProcessStateData;
687 
688             int columnIndex = firstColumn;
689 
690             totalConsumedPowerColumnIndex = columnIndex++;
691 
692             keys = new Key[POWER_COMPONENT_COUNT][];
693 
694             ArrayList<Key> perComponentKeys = new ArrayList<>();
695             for (int componentId = 0; componentId < POWER_COMPONENT_COUNT; componentId++) {
696                 perComponentKeys.clear();
697 
698                 // Declare the Key for the power component, ignoring other dimensions.
699                 perComponentKeys.add(
700                         new Key(componentId, PROCESS_STATE_ANY,
701                                 powerModelsIncluded ? columnIndex++ : -1,  // power model
702                                 columnIndex++,      // power
703                                 columnIndex++       // usage duration
704                         ));
705 
706                 // Declare Keys for all process states, if needed
707                 if (includeProcessStateData) {
708                     boolean isSupported = false;
709                     for (int id : SUPPORTED_POWER_COMPONENTS_PER_PROCESS_STATE) {
710                         if (id == componentId) {
711                             isSupported = true;
712                             break;
713                         }
714                     }
715                     if (isSupported) {
716                         for (int processState = 0; processState < PROCESS_STATE_COUNT;
717                                 processState++) {
718                             if (processState == PROCESS_STATE_UNSPECIFIED) {
719                                 continue;
720                             }
721 
722                             perComponentKeys.add(
723                                     new Key(componentId, processState,
724                                             powerModelsIncluded ? columnIndex++ : -1, // power model
725                                             columnIndex++,      // power
726                                             columnIndex++       // usage duration
727                                     ));
728                         }
729                     }
730                 }
731 
732                 keys[componentId] = perComponentKeys.toArray(KEY_ARRAY);
733             }
734 
735             if (includeProcessStateData) {
736                 processStateKeys = new Key[BatteryConsumer.PROCESS_STATE_COUNT][];
737                 ArrayList<Key> perProcStateKeys = new ArrayList<>();
738                 for (int processState = 0; processState < PROCESS_STATE_COUNT; processState++) {
739                     if (processState == PROCESS_STATE_UNSPECIFIED) {
740                         continue;
741                     }
742 
743                     perProcStateKeys.clear();
744                     for (int i = 0; i < keys.length; i++) {
745                         for (int j = 0; j < keys[i].length; j++) {
746                             if (keys[i][j].processState == processState) {
747                                 perProcStateKeys.add(keys[i][j]);
748                             }
749                         }
750                     }
751                     processStateKeys[processState] = perProcStateKeys.toArray(KEY_ARRAY);
752                 }
753             } else {
754                 processStateKeys = null;
755             }
756 
757             firstCustomConsumedPowerColumn = columnIndex;
758             columnIndex += customPowerComponentCount;
759 
760             firstCustomUsageDurationColumn = columnIndex;
761             columnIndex += customPowerComponentCount;
762 
763             columnCount = columnIndex;
764         }
765     }
766 
createBatteryConsumerDataLayout( String[] customPowerComponentNames, boolean includePowerModels, boolean includeProcessStateData)767     static BatteryConsumerDataLayout createBatteryConsumerDataLayout(
768             String[] customPowerComponentNames, boolean includePowerModels,
769             boolean includeProcessStateData) {
770         int columnCount = BatteryConsumer.COLUMN_COUNT;
771         columnCount = Math.max(columnCount, AggregateBatteryConsumer.COLUMN_COUNT);
772         columnCount = Math.max(columnCount, UidBatteryConsumer.COLUMN_COUNT);
773         columnCount = Math.max(columnCount, UserBatteryConsumer.COLUMN_COUNT);
774 
775         return new BatteryConsumerDataLayout(columnCount, customPowerComponentNames,
776                 includePowerModels, includeProcessStateData);
777     }
778 
779     protected abstract static class BaseBuilder<T extends BaseBuilder<?>> {
780         protected final BatteryConsumer.BatteryConsumerData mData;
781         protected final PowerComponents.Builder mPowerComponentsBuilder;
782 
BaseBuilder(BatteryConsumer.BatteryConsumerData data, int consumerType)783         public BaseBuilder(BatteryConsumer.BatteryConsumerData data, int consumerType) {
784             mData = data;
785             data.putLong(COLUMN_INDEX_BATTERY_CONSUMER_TYPE, consumerType);
786 
787             mPowerComponentsBuilder = new PowerComponents.Builder(data);
788         }
789 
790         @Nullable
getKeys(@owerComponent int componentId)791         public Key[] getKeys(@PowerComponent int componentId) {
792             return mData.getKeys(componentId);
793         }
794 
795         @Nullable
getKey(@owerComponent int componentId, @ProcessState int processState)796         public Key getKey(@PowerComponent int componentId, @ProcessState int processState) {
797             return mData.getKey(componentId, processState);
798         }
799 
800         /**
801          * Sets the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc.
802          *
803          * @param componentId    The ID of the power component, e.g.
804          *                       {@link BatteryConsumer#POWER_COMPONENT_CPU}.
805          * @param componentPower Amount of consumed power in mAh.
806          */
807         @NonNull
setConsumedPower(@owerComponent int componentId, double componentPower)808         public T setConsumedPower(@PowerComponent int componentId, double componentPower) {
809             return setConsumedPower(componentId, componentPower, POWER_MODEL_POWER_PROFILE);
810         }
811 
812         /**
813          * Sets the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc.
814          *
815          * @param componentId    The ID of the power component, e.g.
816          *                       {@link BatteryConsumer#POWER_COMPONENT_CPU}.
817          * @param componentPower Amount of consumed power in mAh.
818          */
819         @SuppressWarnings("unchecked")
820         @NonNull
setConsumedPower(@owerComponent int componentId, double componentPower, @PowerModel int powerModel)821         public T setConsumedPower(@PowerComponent int componentId, double componentPower,
822                 @PowerModel int powerModel) {
823             mPowerComponentsBuilder.setConsumedPower(getKey(componentId, PROCESS_STATE_UNSPECIFIED),
824                     componentPower, powerModel);
825             return (T) this;
826         }
827 
828         @SuppressWarnings("unchecked")
829         @NonNull
setConsumedPower(Key key, double componentPower, @PowerModel int powerModel)830         public T setConsumedPower(Key key, double componentPower, @PowerModel int powerModel) {
831             mPowerComponentsBuilder.setConsumedPower(key, componentPower, powerModel);
832             return (T) this;
833         }
834 
835         /**
836          * Sets the amount of drain attributed to the specified custom drain type.
837          *
838          * @param componentId    The ID of the custom power component.
839          * @param componentPower Amount of consumed power in mAh.
840          */
841         @SuppressWarnings("unchecked")
842         @NonNull
setConsumedPowerForCustomComponent(int componentId, double componentPower)843         public T setConsumedPowerForCustomComponent(int componentId, double componentPower) {
844             mPowerComponentsBuilder.setConsumedPowerForCustomComponent(componentId, componentPower);
845             return (T) this;
846         }
847 
848         /**
849          * Sets the amount of time used by the specified component, e.g. CPU, WiFi etc.
850          *
851          * @param componentId              The ID of the power component, e.g.
852          *                                 {@link UidBatteryConsumer#POWER_COMPONENT_CPU}.
853          * @param componentUsageTimeMillis Amount of time in microseconds.
854          */
855         @SuppressWarnings("unchecked")
856         @NonNull
setUsageDurationMillis(@idBatteryConsumer.PowerComponent int componentId, long componentUsageTimeMillis)857         public T setUsageDurationMillis(@UidBatteryConsumer.PowerComponent int componentId,
858                 long componentUsageTimeMillis) {
859             mPowerComponentsBuilder
860                     .setUsageDurationMillis(getKey(componentId, PROCESS_STATE_UNSPECIFIED),
861                             componentUsageTimeMillis);
862             return (T) this;
863         }
864 
865 
866         @SuppressWarnings("unchecked")
867         @NonNull
setUsageDurationMillis(Key key, long componentUsageTimeMillis)868         public T setUsageDurationMillis(Key key, long componentUsageTimeMillis) {
869             mPowerComponentsBuilder.setUsageDurationMillis(key, componentUsageTimeMillis);
870             return (T) this;
871         }
872 
873         /**
874          * Sets the amount of time used by the specified custom component.
875          *
876          * @param componentId              The ID of the custom power component.
877          * @param componentUsageTimeMillis Amount of time in microseconds.
878          */
879         @SuppressWarnings("unchecked")
880         @NonNull
setUsageDurationForCustomComponentMillis(int componentId, long componentUsageTimeMillis)881         public T setUsageDurationForCustomComponentMillis(int componentId,
882                 long componentUsageTimeMillis) {
883             mPowerComponentsBuilder.setUsageDurationForCustomComponentMillis(componentId,
884                     componentUsageTimeMillis);
885             return (T) this;
886         }
887 
888         /**
889          * Returns the total power accumulated by this builder so far. It may change
890          * by the time the {@code build()} method is called.
891          */
getTotalPower()892         public double getTotalPower() {
893             return mPowerComponentsBuilder.getTotalPower();
894         }
895     }
896 }
897