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