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