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