1 /*
2  * Copyright (C) 2009 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 com.android.internal.os;
18 
19 
20 import android.annotation.StringDef;
21 import android.compat.annotation.UnsupportedAppUsage;
22 import android.content.Context;
23 import android.content.res.Resources;
24 import android.content.res.XmlResourceParser;
25 import android.util.Slog;
26 import android.util.proto.ProtoOutputStream;
27 
28 import com.android.internal.annotations.VisibleForTesting;
29 import com.android.internal.util.XmlUtils;
30 
31 import org.xmlpull.v1.XmlPullParser;
32 import org.xmlpull.v1.XmlPullParserException;
33 
34 import java.io.IOException;
35 import java.lang.annotation.Retention;
36 import java.lang.annotation.RetentionPolicy;
37 import java.util.ArrayList;
38 import java.util.HashMap;
39 
40 /**
41  * Reports power consumption values for various device activities. Reads values from an XML file.
42  * Customize the XML file for different devices.
43  * [hidden]
44  */
45 public class PowerProfile {
46 
47     public static final String TAG = "PowerProfile";
48 
49     /*
50      * POWER_CPU_SUSPEND: Power consumption when CPU is in power collapse mode.
51      * POWER_CPU_IDLE: Power consumption when CPU is awake (when a wake lock is held). This should
52      *                 be zero on devices that can go into full CPU power collapse even when a wake
53      *                 lock is held. Otherwise, this is the power consumption in addition to
54      * POWER_CPU_SUSPEND due to a wake lock being held but with no CPU activity.
55      * POWER_CPU_ACTIVE: Power consumption when CPU is running, excluding power consumed by clusters
56      *                   and cores.
57      *
58      * CPU Power Equation (assume two clusters):
59      * Total power = POWER_CPU_SUSPEND  (always added)
60      *               + POWER_CPU_IDLE   (skip this and below if in power collapse mode)
61      *               + POWER_CPU_ACTIVE (skip this and below if CPU is not running, but a wakelock
62      *                                   is held)
63      *               + cluster_power.cluster0 + cluster_power.cluster1 (skip cluster not running)
64      *               + core_power.cluster0 * num running cores in cluster 0
65      *               + core_power.cluster1 * num running cores in cluster 1
66      */
67     public static final String POWER_CPU_SUSPEND = "cpu.suspend";
68     @UnsupportedAppUsage
69     public static final String POWER_CPU_IDLE = "cpu.idle";
70     @UnsupportedAppUsage
71     public static final String POWER_CPU_ACTIVE = "cpu.active";
72 
73     /**
74      * Power consumption when WiFi driver is scanning for networks.
75      */
76     @UnsupportedAppUsage
77     public static final String POWER_WIFI_SCAN = "wifi.scan";
78 
79     /**
80      * Power consumption when WiFi driver is on.
81      */
82     @UnsupportedAppUsage
83     public static final String POWER_WIFI_ON = "wifi.on";
84 
85     /**
86      * Power consumption when WiFi driver is transmitting/receiving.
87      */
88     @UnsupportedAppUsage
89     public static final String POWER_WIFI_ACTIVE = "wifi.active";
90 
91     //
92     // Updated power constants. These are not estimated, they are real world
93     // currents and voltages for the underlying bluetooth and wifi controllers.
94     //
95     public static final String POWER_WIFI_CONTROLLER_IDLE = "wifi.controller.idle";
96     public static final String POWER_WIFI_CONTROLLER_RX = "wifi.controller.rx";
97     public static final String POWER_WIFI_CONTROLLER_TX = "wifi.controller.tx";
98     public static final String POWER_WIFI_CONTROLLER_TX_LEVELS = "wifi.controller.tx_levels";
99     public static final String POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE = "wifi.controller.voltage";
100 
101     public static final String POWER_BLUETOOTH_CONTROLLER_IDLE = "bluetooth.controller.idle";
102     public static final String POWER_BLUETOOTH_CONTROLLER_RX = "bluetooth.controller.rx";
103     public static final String POWER_BLUETOOTH_CONTROLLER_TX = "bluetooth.controller.tx";
104     public static final String POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE =
105             "bluetooth.controller.voltage";
106 
107     public static final String POWER_MODEM_CONTROLLER_SLEEP = "modem.controller.sleep";
108     public static final String POWER_MODEM_CONTROLLER_IDLE = "modem.controller.idle";
109     public static final String POWER_MODEM_CONTROLLER_RX = "modem.controller.rx";
110     public static final String POWER_MODEM_CONTROLLER_TX = "modem.controller.tx";
111     public static final String POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE =
112             "modem.controller.voltage";
113 
114     /**
115      * Power consumption when GPS is on.
116      */
117     @UnsupportedAppUsage
118     public static final String POWER_GPS_ON = "gps.on";
119 
120     /**
121      * GPS power parameters based on signal quality
122      */
123     public static final String POWER_GPS_SIGNAL_QUALITY_BASED = "gps.signalqualitybased";
124     public static final String POWER_GPS_OPERATING_VOLTAGE = "gps.voltage";
125 
126     /**
127      * Power consumption when Bluetooth driver is on.
128      *
129      * @deprecated
130      */
131     @Deprecated
132     @UnsupportedAppUsage
133     public static final String POWER_BLUETOOTH_ON = "bluetooth.on";
134 
135     /**
136      * Power consumption when Bluetooth driver is transmitting/receiving.
137      *
138      * @deprecated
139      */
140     @Deprecated
141     public static final String POWER_BLUETOOTH_ACTIVE = "bluetooth.active";
142 
143     /**
144      * Power consumption when Bluetooth driver gets an AT command.
145      *
146      * @deprecated
147      */
148     @Deprecated
149     @UnsupportedAppUsage
150     public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at";
151 
152     /**
153      * Power consumption when screen is in doze/ambient/always-on mode, including backlight power.
154      *
155      * @deprecated Use {@link #POWER_GROUP_DISPLAY_AMBIENT} instead.
156      */
157     @Deprecated
158     public static final String POWER_AMBIENT_DISPLAY = "ambient.on";
159 
160     /**
161      * Power consumption when screen is on, not including the backlight power.
162      *
163      * @deprecated Use {@link #POWER_GROUP_DISPLAY_SCREEN_ON} instead.
164      */
165     @Deprecated
166     @UnsupportedAppUsage
167     public static final String POWER_SCREEN_ON = "screen.on";
168 
169     /**
170      * Power consumption when cell radio is on but not on a call.
171      */
172     @UnsupportedAppUsage
173     public static final String POWER_RADIO_ON = "radio.on";
174 
175     /**
176      * Power consumption when cell radio is hunting for a signal.
177      */
178     @UnsupportedAppUsage
179     public static final String POWER_RADIO_SCANNING = "radio.scanning";
180 
181     /**
182      * Power consumption when talking on the phone.
183      */
184     @UnsupportedAppUsage
185     public static final String POWER_RADIO_ACTIVE = "radio.active";
186 
187     /**
188      * Power consumption at full backlight brightness. If the backlight is at
189      * 50% brightness, then this should be multiplied by 0.5
190      *
191      * @deprecated Use {@link #POWER_GROUP_DISPLAY_SCREEN_FULL} instead.
192      */
193     @Deprecated
194     @UnsupportedAppUsage
195     public static final String POWER_SCREEN_FULL = "screen.full";
196 
197     /**
198      * Power consumed by the audio hardware when playing back audio content. This is in addition
199      * to the CPU power, probably due to a DSP and / or amplifier.
200      */
201     public static final String POWER_AUDIO = "audio";
202 
203     /**
204      * Power consumed by any media hardware when playing back video content. This is in addition
205      * to the CPU power, probably due to a DSP.
206      */
207     public static final String POWER_VIDEO = "video";
208 
209     /**
210      * Average power consumption when camera flashlight is on.
211      */
212     public static final String POWER_FLASHLIGHT = "camera.flashlight";
213 
214     /**
215      * Power consumption when DDR is being used.
216      */
217     public static final String POWER_MEMORY = "memory.bandwidths";
218 
219     /**
220      * Average power consumption when the camera is on over all standard use cases.
221      *
222      * TODO: Add more fine-grained camera power metrics.
223      */
224     public static final String POWER_CAMERA = "camera.avg";
225 
226     /**
227      * Power consumed by wif batched scaning.  Broken down into bins by
228      * Channels Scanned per Hour.  May do 1-720 scans per hour of 1-100 channels
229      * for a range of 1-72,000.  Going logrithmic (1-8, 9-64, 65-512, 513-4096, 4097-)!
230      */
231     public static final String POWER_WIFI_BATCHED_SCAN = "wifi.batchedscan";
232 
233     /**
234      * Battery capacity in milliAmpHour (mAh).
235      */
236     public static final String POWER_BATTERY_CAPACITY = "battery.capacity";
237 
238     /**
239      * Power consumption when a screen is in doze/ambient/always-on mode, including backlight power.
240      */
241     public static final String POWER_GROUP_DISPLAY_AMBIENT = "ambient.on.display";
242 
243     /**
244      * Power consumption when a screen is on, not including the backlight power.
245      */
246     public static final String POWER_GROUP_DISPLAY_SCREEN_ON = "screen.on.display";
247 
248     /**
249      * Power consumption of a screen at full backlight brightness.
250      */
251     public static final String POWER_GROUP_DISPLAY_SCREEN_FULL = "screen.full.display";
252 
253     @StringDef(prefix = { "POWER_GROUP_" }, value = {
254             POWER_GROUP_DISPLAY_AMBIENT,
255             POWER_GROUP_DISPLAY_SCREEN_ON,
256             POWER_GROUP_DISPLAY_SCREEN_FULL,
257     })
258     @Retention(RetentionPolicy.SOURCE)
259     public @interface PowerGroup {}
260 
261     /**
262      * A map from Power Use Item to its power consumption.
263      */
264     static final HashMap<String, Double> sPowerItemMap = new HashMap<>();
265     /**
266      * A map from Power Use Item to an array of its power consumption
267      * (for items with variable power e.g. CPU).
268      */
269     static final HashMap<String, Double[]> sPowerArrayMap = new HashMap<>();
270 
271     private static final String TAG_DEVICE = "device";
272     private static final String TAG_ITEM = "item";
273     private static final String TAG_ARRAY = "array";
274     private static final String TAG_ARRAYITEM = "value";
275     private static final String ATTR_NAME = "name";
276 
277     private static final Object sLock = new Object();
278 
279     @VisibleForTesting
280     @UnsupportedAppUsage
PowerProfile(Context context)281     public PowerProfile(Context context) {
282         this(context, false);
283     }
284 
285     /**
286      * For PowerProfileTest
287      */
288     @VisibleForTesting
PowerProfile(Context context, boolean forTest)289     public PowerProfile(Context context, boolean forTest) {
290         // Read the XML file for the given profile (normally only one per device)
291         synchronized (sLock) {
292             if (sPowerItemMap.size() == 0 && sPowerArrayMap.size() == 0) {
293                 readPowerValuesFromXml(context, forTest);
294             }
295             initCpuClusters();
296             initDisplays();
297         }
298     }
299 
readPowerValuesFromXml(Context context, boolean forTest)300     private void readPowerValuesFromXml(Context context, boolean forTest) {
301         final int id = forTest ? com.android.internal.R.xml.power_profile_test :
302                 com.android.internal.R.xml.power_profile;
303         final Resources resources = context.getResources();
304         XmlResourceParser parser = resources.getXml(id);
305         boolean parsingArray = false;
306         ArrayList<Double> array = new ArrayList<>();
307         String arrayName = null;
308 
309         try {
310             XmlUtils.beginDocument(parser, TAG_DEVICE);
311 
312             while (true) {
313                 XmlUtils.nextElement(parser);
314 
315                 String element = parser.getName();
316                 if (element == null) break;
317 
318                 if (parsingArray && !element.equals(TAG_ARRAYITEM)) {
319                     // Finish array
320                     sPowerArrayMap.put(arrayName, array.toArray(new Double[array.size()]));
321                     parsingArray = false;
322                 }
323                 if (element.equals(TAG_ARRAY)) {
324                     parsingArray = true;
325                     array.clear();
326                     arrayName = parser.getAttributeValue(null, ATTR_NAME);
327                 } else if (element.equals(TAG_ITEM) || element.equals(TAG_ARRAYITEM)) {
328                     String name = null;
329                     if (!parsingArray) name = parser.getAttributeValue(null, ATTR_NAME);
330                     if (parser.next() == XmlPullParser.TEXT) {
331                         String power = parser.getText();
332                         double value = 0;
333                         try {
334                             value = Double.valueOf(power);
335                         } catch (NumberFormatException nfe) {
336                         }
337                         if (element.equals(TAG_ITEM)) {
338                             sPowerItemMap.put(name, value);
339                         } else if (parsingArray) {
340                             array.add(value);
341                         }
342                     }
343                 }
344             }
345             if (parsingArray) {
346                 sPowerArrayMap.put(arrayName, array.toArray(new Double[array.size()]));
347             }
348         } catch (XmlPullParserException e) {
349             throw new RuntimeException(e);
350         } catch (IOException e) {
351             throw new RuntimeException(e);
352         } finally {
353             parser.close();
354         }
355 
356         // Now collect other config variables.
357         int[] configResIds = new int[]{
358                 com.android.internal.R.integer.config_bluetooth_idle_cur_ma,
359                 com.android.internal.R.integer.config_bluetooth_rx_cur_ma,
360                 com.android.internal.R.integer.config_bluetooth_tx_cur_ma,
361                 com.android.internal.R.integer.config_bluetooth_operating_voltage_mv,
362         };
363 
364         String[] configResIdKeys = new String[]{
365                 POWER_BLUETOOTH_CONTROLLER_IDLE,
366                 POWER_BLUETOOTH_CONTROLLER_RX,
367                 POWER_BLUETOOTH_CONTROLLER_TX,
368                 POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE,
369         };
370 
371         for (int i = 0; i < configResIds.length; i++) {
372             String key = configResIdKeys[i];
373             // if we already have some of these parameters in power_profile.xml, ignore the
374             // value in config.xml
375             if ((sPowerItemMap.containsKey(key) && sPowerItemMap.get(key) > 0)) {
376                 continue;
377             }
378             int value = resources.getInteger(configResIds[i]);
379             if (value > 0) {
380                 sPowerItemMap.put(key, (double) value);
381             }
382         }
383     }
384 
385     private CpuClusterKey[] mCpuClusters;
386 
387     private static final String CPU_PER_CLUSTER_CORE_COUNT = "cpu.clusters.cores";
388     private static final String CPU_CLUSTER_POWER_COUNT = "cpu.cluster_power.cluster";
389     private static final String CPU_CORE_SPEED_PREFIX = "cpu.core_speeds.cluster";
390     private static final String CPU_CORE_POWER_PREFIX = "cpu.core_power.cluster";
391 
initCpuClusters()392     private void initCpuClusters() {
393         if (sPowerArrayMap.containsKey(CPU_PER_CLUSTER_CORE_COUNT)) {
394             final Double[] data = sPowerArrayMap.get(CPU_PER_CLUSTER_CORE_COUNT);
395             mCpuClusters = new CpuClusterKey[data.length];
396             for (int cluster = 0; cluster < data.length; cluster++) {
397                 int numCpusInCluster = (int) Math.round(data[cluster]);
398                 mCpuClusters[cluster] = new CpuClusterKey(
399                         CPU_CORE_SPEED_PREFIX + cluster, CPU_CLUSTER_POWER_COUNT + cluster,
400                         CPU_CORE_POWER_PREFIX + cluster, numCpusInCluster);
401             }
402         } else {
403             // Default to single.
404             mCpuClusters = new CpuClusterKey[1];
405             int numCpus = 1;
406             if (sPowerItemMap.containsKey(CPU_PER_CLUSTER_CORE_COUNT)) {
407                 numCpus = (int) Math.round(sPowerItemMap.get(CPU_PER_CLUSTER_CORE_COUNT));
408             }
409             mCpuClusters[0] = new CpuClusterKey(CPU_CORE_SPEED_PREFIX + 0,
410                     CPU_CLUSTER_POWER_COUNT + 0, CPU_CORE_POWER_PREFIX + 0, numCpus);
411         }
412     }
413 
414     public static class CpuClusterKey {
415         private final String freqKey;
416         private final String clusterPowerKey;
417         private final String corePowerKey;
418         private final int numCpus;
419 
CpuClusterKey(String freqKey, String clusterPowerKey, String corePowerKey, int numCpus)420         private CpuClusterKey(String freqKey, String clusterPowerKey,
421                 String corePowerKey, int numCpus) {
422             this.freqKey = freqKey;
423             this.clusterPowerKey = clusterPowerKey;
424             this.corePowerKey = corePowerKey;
425             this.numCpus = numCpus;
426         }
427     }
428 
429     @UnsupportedAppUsage
getNumCpuClusters()430     public int getNumCpuClusters() {
431         return mCpuClusters.length;
432     }
433 
getNumCoresInCpuCluster(int cluster)434     public int getNumCoresInCpuCluster(int cluster) {
435         if (cluster < 0 || cluster >= mCpuClusters.length) {
436             return 0; // index out of bound
437         }
438         return mCpuClusters[cluster].numCpus;
439     }
440 
441     @UnsupportedAppUsage
getNumSpeedStepsInCpuCluster(int cluster)442     public int getNumSpeedStepsInCpuCluster(int cluster) {
443         if (cluster < 0 || cluster >= mCpuClusters.length) {
444             return 0; // index out of bound
445         }
446         if (sPowerArrayMap.containsKey(mCpuClusters[cluster].freqKey)) {
447             return sPowerArrayMap.get(mCpuClusters[cluster].freqKey).length;
448         }
449         return 1; // Only one speed
450     }
451 
getAveragePowerForCpuCluster(int cluster)452     public double getAveragePowerForCpuCluster(int cluster) {
453         if (cluster >= 0 && cluster < mCpuClusters.length) {
454             return getAveragePower(mCpuClusters[cluster].clusterPowerKey);
455         }
456         return 0;
457     }
458 
getAveragePowerForCpuCore(int cluster, int step)459     public double getAveragePowerForCpuCore(int cluster, int step) {
460         if (cluster >= 0 && cluster < mCpuClusters.length) {
461             return getAveragePower(mCpuClusters[cluster].corePowerKey, step);
462         }
463         return 0;
464     }
465 
466     private int mNumDisplays;
467 
initDisplays()468     private void initDisplays() {
469         // Figure out how many displays are listed in the power profile.
470         mNumDisplays = 0;
471         while (!Double.isNaN(
472                 getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, mNumDisplays, Double.NaN))
473                 || !Double.isNaN(
474                 getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, mNumDisplays, Double.NaN))
475                 || !Double.isNaN(
476                 getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, mNumDisplays,
477                         Double.NaN))) {
478             mNumDisplays++;
479         }
480 
481         // Handle legacy display power constants.
482         final Double deprecatedAmbientDisplay = sPowerItemMap.get(POWER_AMBIENT_DISPLAY);
483         boolean legacy = false;
484         if (deprecatedAmbientDisplay != null && mNumDisplays == 0) {
485             final String key = getOrdinalPowerType(POWER_GROUP_DISPLAY_AMBIENT, 0);
486             Slog.w(TAG, POWER_AMBIENT_DISPLAY + " is deprecated! Use " + key + " instead.");
487             sPowerItemMap.put(key, deprecatedAmbientDisplay);
488             legacy = true;
489         }
490 
491         final Double deprecatedScreenOn = sPowerItemMap.get(POWER_SCREEN_ON);
492         if (deprecatedScreenOn != null && mNumDisplays == 0) {
493             final String key = getOrdinalPowerType(POWER_GROUP_DISPLAY_SCREEN_ON, 0);
494             Slog.w(TAG, POWER_SCREEN_ON + " is deprecated! Use " + key + " instead.");
495             sPowerItemMap.put(key, deprecatedScreenOn);
496             legacy = true;
497         }
498 
499         final Double deprecatedScreenFull = sPowerItemMap.get(POWER_SCREEN_FULL);
500         if (deprecatedScreenFull != null && mNumDisplays == 0) {
501             final String key = getOrdinalPowerType(POWER_GROUP_DISPLAY_SCREEN_FULL, 0);
502             Slog.w(TAG, POWER_SCREEN_FULL + " is deprecated! Use " + key + " instead.");
503             sPowerItemMap.put(key, deprecatedScreenFull);
504             legacy = true;
505         }
506         if (legacy) {
507             mNumDisplays = 1;
508         }
509     }
510 
511     /**
512      * Returns the number built in displays on the device as defined in the power_profile.xml.
513      */
getNumDisplays()514     public int getNumDisplays() {
515         return mNumDisplays;
516     }
517 
518     /**
519      * Returns the number of memory bandwidth buckets defined in power_profile.xml, or a
520      * default value if the subsystem has no recorded value.
521      *
522      * @return the number of memory bandwidth buckets.
523      */
getNumElements(String key)524     public int getNumElements(String key) {
525         if (sPowerItemMap.containsKey(key)) {
526             return 1;
527         } else if (sPowerArrayMap.containsKey(key)) {
528             return sPowerArrayMap.get(key).length;
529         }
530         return 0;
531     }
532 
533     /**
534      * Returns the average current in mA consumed by the subsystem, or the given
535      * default value if the subsystem has no recorded value.
536      *
537      * @param type         the subsystem type
538      * @param defaultValue the value to return if the subsystem has no recorded value.
539      * @return the average current in milliAmps.
540      */
getAveragePowerOrDefault(String type, double defaultValue)541     public double getAveragePowerOrDefault(String type, double defaultValue) {
542         if (sPowerItemMap.containsKey(type)) {
543             return sPowerItemMap.get(type);
544         } else if (sPowerArrayMap.containsKey(type)) {
545             return sPowerArrayMap.get(type)[0];
546         } else {
547             return defaultValue;
548         }
549     }
550 
551     /**
552      * Returns the average current in mA consumed by the subsystem
553      *
554      * @param type the subsystem type
555      * @return the average current in milliAmps.
556      */
557     @UnsupportedAppUsage
getAveragePower(String type)558     public double getAveragePower(String type) {
559         return getAveragePowerOrDefault(type, 0);
560     }
561 
562     /**
563      * Returns the average current in mA consumed by the subsystem for the given level.
564      *
565      * @param type  the subsystem type
566      * @param level the level of power at which the subsystem is running. For instance, the
567      *              signal strength of the cell network between 0 and 4 (if there are 4 bars max.)
568      *              If there is no data for multiple levels, the level is ignored.
569      * @return the average current in milliAmps.
570      */
571     @UnsupportedAppUsage
getAveragePower(String type, int level)572     public double getAveragePower(String type, int level) {
573         if (sPowerItemMap.containsKey(type)) {
574             return sPowerItemMap.get(type);
575         } else if (sPowerArrayMap.containsKey(type)) {
576             final Double[] values = sPowerArrayMap.get(type);
577             if (values.length > level && level >= 0) {
578                 return values[level];
579             } else if (level < 0 || values.length == 0) {
580                 return 0;
581             } else {
582                 return values[values.length - 1];
583             }
584         } else {
585             return 0;
586         }
587     }
588 
589     /**
590      * Returns the average current in mA consumed by an ordinaled subsystem, or the given
591      * default value if the subsystem has no recorded value.
592      *
593      * @param group        the subsystem {@link PowerGroup}.
594      * @param ordinal      which entity in the {@link PowerGroup}.
595      * @param defaultValue the value to return if the subsystem has no recorded value.
596      * @return the average current in milliAmps.
597      */
getAveragePowerForOrdinal(@owerGroup String group, int ordinal, double defaultValue)598     public double getAveragePowerForOrdinal(@PowerGroup String group, int ordinal,
599             double defaultValue) {
600         final String type = getOrdinalPowerType(group, ordinal);
601         return getAveragePowerOrDefault(type, defaultValue);
602     }
603 
604     /**
605      * Returns the average current in mA consumed by an ordinaled subsystem.
606      *
607      * @param group        the subsystem {@link PowerGroup}.
608      * @param ordinal      which entity in the {@link PowerGroup}.
609      * @return the average current in milliAmps.
610      */
getAveragePowerForOrdinal(@owerGroup String group, int ordinal)611     public double getAveragePowerForOrdinal(@PowerGroup String group, int ordinal) {
612         return getAveragePowerForOrdinal(group, ordinal, 0);
613     }
614 
615     /**
616      * Returns the battery capacity, if available, in milli Amp Hours. If not available,
617      * it returns zero.
618      *
619      * @return the battery capacity in mAh
620      */
621     @UnsupportedAppUsage
getBatteryCapacity()622     public double getBatteryCapacity() {
623         return getAveragePower(POWER_BATTERY_CAPACITY);
624     }
625 
626     /**
627      * Dump power constants into PowerProfileProto
628      */
dumpDebug(ProtoOutputStream proto)629     public void dumpDebug(ProtoOutputStream proto) {
630         // cpu.suspend
631         writePowerConstantToProto(proto, POWER_CPU_SUSPEND, PowerProfileProto.CPU_SUSPEND);
632 
633         // cpu.idle
634         writePowerConstantToProto(proto, POWER_CPU_IDLE, PowerProfileProto.CPU_IDLE);
635 
636         // cpu.active
637         writePowerConstantToProto(proto, POWER_CPU_ACTIVE, PowerProfileProto.CPU_ACTIVE);
638 
639         // cpu.clusters.cores
640         // cpu.cluster_power.cluster
641         // cpu.core_speeds.cluster
642         // cpu.core_power.cluster
643         for (int cluster = 0; cluster < mCpuClusters.length; cluster++) {
644             final long token = proto.start(PowerProfileProto.CPU_CLUSTER);
645             proto.write(PowerProfileProto.CpuCluster.ID, cluster);
646             proto.write(PowerProfileProto.CpuCluster.CLUSTER_POWER,
647                     sPowerItemMap.get(mCpuClusters[cluster].clusterPowerKey));
648             proto.write(PowerProfileProto.CpuCluster.CORES, mCpuClusters[cluster].numCpus);
649             for (Double speed : sPowerArrayMap.get(mCpuClusters[cluster].freqKey)) {
650                 proto.write(PowerProfileProto.CpuCluster.SPEED, speed);
651             }
652             for (Double corePower : sPowerArrayMap.get(mCpuClusters[cluster].corePowerKey)) {
653                 proto.write(PowerProfileProto.CpuCluster.CORE_POWER, corePower);
654             }
655             proto.end(token);
656         }
657 
658         // wifi.scan
659         writePowerConstantToProto(proto, POWER_WIFI_SCAN, PowerProfileProto.WIFI_SCAN);
660 
661         // wifi.on
662         writePowerConstantToProto(proto, POWER_WIFI_ON, PowerProfileProto.WIFI_ON);
663 
664         // wifi.active
665         writePowerConstantToProto(proto, POWER_WIFI_ACTIVE, PowerProfileProto.WIFI_ACTIVE);
666 
667         // wifi.controller.idle
668         writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_IDLE,
669                 PowerProfileProto.WIFI_CONTROLLER_IDLE);
670 
671         // wifi.controller.rx
672         writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_RX,
673                 PowerProfileProto.WIFI_CONTROLLER_RX);
674 
675         // wifi.controller.tx
676         writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_TX,
677                 PowerProfileProto.WIFI_CONTROLLER_TX);
678 
679         // wifi.controller.tx_levels
680         writePowerConstantArrayToProto(proto, POWER_WIFI_CONTROLLER_TX_LEVELS,
681                 PowerProfileProto.WIFI_CONTROLLER_TX_LEVELS);
682 
683         // wifi.controller.voltage
684         writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE,
685                 PowerProfileProto.WIFI_CONTROLLER_OPERATING_VOLTAGE);
686 
687         // bluetooth.controller.idle
688         writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_IDLE,
689                 PowerProfileProto.BLUETOOTH_CONTROLLER_IDLE);
690 
691         // bluetooth.controller.rx
692         writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_RX,
693                 PowerProfileProto.BLUETOOTH_CONTROLLER_RX);
694 
695         // bluetooth.controller.tx
696         writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_TX,
697                 PowerProfileProto.BLUETOOTH_CONTROLLER_TX);
698 
699         // bluetooth.controller.voltage
700         writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE,
701                 PowerProfileProto.BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE);
702 
703         // modem.controller.sleep
704         writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_SLEEP,
705                 PowerProfileProto.MODEM_CONTROLLER_SLEEP);
706 
707         // modem.controller.idle
708         writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_IDLE,
709                 PowerProfileProto.MODEM_CONTROLLER_IDLE);
710 
711         // modem.controller.rx
712         writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_RX,
713                 PowerProfileProto.MODEM_CONTROLLER_RX);
714 
715         // modem.controller.tx
716         writePowerConstantArrayToProto(proto, POWER_MODEM_CONTROLLER_TX,
717                 PowerProfileProto.MODEM_CONTROLLER_TX);
718 
719         // modem.controller.voltage
720         writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE,
721                 PowerProfileProto.MODEM_CONTROLLER_OPERATING_VOLTAGE);
722 
723         // gps.on
724         writePowerConstantToProto(proto, POWER_GPS_ON, PowerProfileProto.GPS_ON);
725 
726         // gps.signalqualitybased
727         writePowerConstantArrayToProto(proto, POWER_GPS_SIGNAL_QUALITY_BASED,
728                 PowerProfileProto.GPS_SIGNAL_QUALITY_BASED);
729 
730         // gps.voltage
731         writePowerConstantToProto(proto, POWER_GPS_OPERATING_VOLTAGE,
732                 PowerProfileProto.GPS_OPERATING_VOLTAGE);
733 
734         // bluetooth.on
735         writePowerConstantToProto(proto, POWER_BLUETOOTH_ON, PowerProfileProto.BLUETOOTH_ON);
736 
737         // bluetooth.active
738         writePowerConstantToProto(proto, POWER_BLUETOOTH_ACTIVE,
739                 PowerProfileProto.BLUETOOTH_ACTIVE);
740 
741         // bluetooth.at
742         writePowerConstantToProto(proto, POWER_BLUETOOTH_AT_CMD,
743                 PowerProfileProto.BLUETOOTH_AT_CMD);
744 
745         // ambient.on
746         writePowerConstantToProto(proto, POWER_AMBIENT_DISPLAY, PowerProfileProto.AMBIENT_DISPLAY);
747 
748         // screen.on
749         writePowerConstantToProto(proto, POWER_SCREEN_ON, PowerProfileProto.SCREEN_ON);
750 
751         // radio.on
752         writePowerConstantToProto(proto, POWER_RADIO_ON, PowerProfileProto.RADIO_ON);
753 
754         // radio.scanning
755         writePowerConstantToProto(proto, POWER_RADIO_SCANNING, PowerProfileProto.RADIO_SCANNING);
756 
757         // radio.active
758         writePowerConstantToProto(proto, POWER_RADIO_ACTIVE, PowerProfileProto.RADIO_ACTIVE);
759 
760         // screen.full
761         writePowerConstantToProto(proto, POWER_SCREEN_FULL, PowerProfileProto.SCREEN_FULL);
762 
763         // audio
764         writePowerConstantToProto(proto, POWER_AUDIO, PowerProfileProto.AUDIO);
765 
766         // video
767         writePowerConstantToProto(proto, POWER_VIDEO, PowerProfileProto.VIDEO);
768 
769         // camera.flashlight
770         writePowerConstantToProto(proto, POWER_FLASHLIGHT, PowerProfileProto.FLASHLIGHT);
771 
772         // memory.bandwidths
773         writePowerConstantToProto(proto, POWER_MEMORY, PowerProfileProto.MEMORY);
774 
775         // camera.avg
776         writePowerConstantToProto(proto, POWER_CAMERA, PowerProfileProto.CAMERA);
777 
778         // wifi.batchedscan
779         writePowerConstantToProto(proto, POWER_WIFI_BATCHED_SCAN,
780                 PowerProfileProto.WIFI_BATCHED_SCAN);
781 
782         // battery.capacity
783         writePowerConstantToProto(proto, POWER_BATTERY_CAPACITY,
784                 PowerProfileProto.BATTERY_CAPACITY);
785     }
786 
787     // Writes items in sPowerItemMap to proto if exists.
writePowerConstantToProto(ProtoOutputStream proto, String key, long fieldId)788     private void writePowerConstantToProto(ProtoOutputStream proto, String key, long fieldId) {
789         if (sPowerItemMap.containsKey(key)) {
790             proto.write(fieldId, sPowerItemMap.get(key));
791         }
792     }
793 
794     // Writes items in sPowerArrayMap to proto if exists.
writePowerConstantArrayToProto(ProtoOutputStream proto, String key, long fieldId)795     private void writePowerConstantArrayToProto(ProtoOutputStream proto, String key, long fieldId) {
796         if (sPowerArrayMap.containsKey(key)) {
797             for (Double d : sPowerArrayMap.get(key)) {
798                 proto.write(fieldId, d);
799             }
800         }
801     }
802 
803     // Creates the key for an ordinaled power constant from the group and ordinal.
getOrdinalPowerType(@owerGroup String group, int ordinal)804     private static String getOrdinalPowerType(@PowerGroup String group, int ordinal) {
805         return group + ordinal;
806     }
807 }
808