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