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