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