• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.os;
18 
19 
20 import android.annotation.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         return mCpuClusters[cluster].numCpus;
397     }
398 
399     @UnsupportedAppUsage
getNumSpeedStepsInCpuCluster(int cluster)400     public int getNumSpeedStepsInCpuCluster(int cluster) {
401         if (cluster < 0 || cluster >= mCpuClusters.length) {
402             return 0; // index out of bound
403         }
404         if (sPowerArrayMap.containsKey(mCpuClusters[cluster].freqKey)) {
405             return sPowerArrayMap.get(mCpuClusters[cluster].freqKey).length;
406         }
407         return 1; // Only one speed
408     }
409 
getAveragePowerForCpuCluster(int cluster)410     public double getAveragePowerForCpuCluster(int cluster) {
411         if (cluster >= 0 && cluster < mCpuClusters.length) {
412             return getAveragePower(mCpuClusters[cluster].clusterPowerKey);
413         }
414         return 0;
415     }
416 
getAveragePowerForCpuCore(int cluster, int step)417     public double getAveragePowerForCpuCore(int cluster, int step) {
418         if (cluster >= 0 && cluster < mCpuClusters.length) {
419             return getAveragePower(mCpuClusters[cluster].corePowerKey, step);
420         }
421         return 0;
422     }
423 
424     /**
425      * Returns the number of memory bandwidth buckets defined in power_profile.xml, or a
426      * default value if the subsystem has no recorded value.
427      *
428      * @return the number of memory bandwidth buckets.
429      */
getNumElements(String key)430     public int getNumElements(String key) {
431         if (sPowerItemMap.containsKey(key)) {
432             return 1;
433         } else if (sPowerArrayMap.containsKey(key)) {
434             return sPowerArrayMap.get(key).length;
435         }
436         return 0;
437     }
438 
439     /**
440      * Returns the average current in mA consumed by the subsystem, or the given
441      * default value if the subsystem has no recorded value.
442      *
443      * @param type         the subsystem type
444      * @param defaultValue the value to return if the subsystem has no recorded value.
445      * @return the average current in milliAmps.
446      */
getAveragePowerOrDefault(String type, double defaultValue)447     public double getAveragePowerOrDefault(String type, double defaultValue) {
448         if (sPowerItemMap.containsKey(type)) {
449             return sPowerItemMap.get(type);
450         } else if (sPowerArrayMap.containsKey(type)) {
451             return sPowerArrayMap.get(type)[0];
452         } else {
453             return defaultValue;
454         }
455     }
456 
457     /**
458      * Returns the average current in mA consumed by the subsystem
459      *
460      * @param type the subsystem type
461      * @return the average current in milliAmps.
462      */
463     @UnsupportedAppUsage
getAveragePower(String type)464     public double getAveragePower(String type) {
465         return getAveragePowerOrDefault(type, 0);
466     }
467 
468     /**
469      * Returns the average current in mA consumed by the subsystem for the given level.
470      *
471      * @param type  the subsystem type
472      * @param level the level of power at which the subsystem is running. For instance, the
473      *              signal strength of the cell network between 0 and 4 (if there are 4 bars max.)
474      *              If there is no data for multiple levels, the level is ignored.
475      * @return the average current in milliAmps.
476      */
477     @UnsupportedAppUsage
getAveragePower(String type, int level)478     public double getAveragePower(String type, int level) {
479         if (sPowerItemMap.containsKey(type)) {
480             return sPowerItemMap.get(type);
481         } else if (sPowerArrayMap.containsKey(type)) {
482             final Double[] values = sPowerArrayMap.get(type);
483             if (values.length > level && level >= 0) {
484                 return values[level];
485             } else if (level < 0 || values.length == 0) {
486                 return 0;
487             } else {
488                 return values[values.length - 1];
489             }
490         } else {
491             return 0;
492         }
493     }
494 
495     /**
496      * Returns the battery capacity, if available, in milli Amp Hours. If not available,
497      * it returns zero.
498      *
499      * @return the battery capacity in mAh
500      */
501     @UnsupportedAppUsage
getBatteryCapacity()502     public double getBatteryCapacity() {
503         return getAveragePower(POWER_BATTERY_CAPACITY);
504     }
505 
506     /**
507      * Dump power constants into PowerProfileProto
508      */
writeToProto(ProtoOutputStream proto)509     public void writeToProto(ProtoOutputStream proto) {
510         // cpu.suspend
511         writePowerConstantToProto(proto, POWER_CPU_SUSPEND, PowerProfileProto.CPU_SUSPEND);
512 
513         // cpu.idle
514         writePowerConstantToProto(proto, POWER_CPU_IDLE, PowerProfileProto.CPU_IDLE);
515 
516         // cpu.active
517         writePowerConstantToProto(proto, POWER_CPU_ACTIVE, PowerProfileProto.CPU_ACTIVE);
518 
519         // cpu.clusters.cores
520         // cpu.cluster_power.cluster
521         // cpu.core_speeds.cluster
522         // cpu.core_power.cluster
523         for (int cluster = 0; cluster < mCpuClusters.length; cluster++) {
524             final long token = proto.start(PowerProfileProto.CPU_CLUSTER);
525             proto.write(PowerProfileProto.CpuCluster.ID, cluster);
526             proto.write(PowerProfileProto.CpuCluster.CLUSTER_POWER,
527                     sPowerItemMap.get(mCpuClusters[cluster].clusterPowerKey));
528             proto.write(PowerProfileProto.CpuCluster.CORES, mCpuClusters[cluster].numCpus);
529             for (Double speed : sPowerArrayMap.get(mCpuClusters[cluster].freqKey)) {
530                 proto.write(PowerProfileProto.CpuCluster.SPEED, speed);
531             }
532             for (Double corePower : sPowerArrayMap.get(mCpuClusters[cluster].corePowerKey)) {
533                 proto.write(PowerProfileProto.CpuCluster.CORE_POWER, corePower);
534             }
535             proto.end(token);
536         }
537 
538         // wifi.scan
539         writePowerConstantToProto(proto, POWER_WIFI_SCAN, PowerProfileProto.WIFI_SCAN);
540 
541         // wifi.on
542         writePowerConstantToProto(proto, POWER_WIFI_ON, PowerProfileProto.WIFI_ON);
543 
544         // wifi.active
545         writePowerConstantToProto(proto, POWER_WIFI_ACTIVE, PowerProfileProto.WIFI_ACTIVE);
546 
547         // wifi.controller.idle
548         writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_IDLE,
549                 PowerProfileProto.WIFI_CONTROLLER_IDLE);
550 
551         // wifi.controller.rx
552         writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_RX,
553                 PowerProfileProto.WIFI_CONTROLLER_RX);
554 
555         // wifi.controller.tx
556         writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_TX,
557                 PowerProfileProto.WIFI_CONTROLLER_TX);
558 
559         // wifi.controller.tx_levels
560         writePowerConstantArrayToProto(proto, POWER_WIFI_CONTROLLER_TX_LEVELS,
561                 PowerProfileProto.WIFI_CONTROLLER_TX_LEVELS);
562 
563         // wifi.controller.voltage
564         writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE,
565                 PowerProfileProto.WIFI_CONTROLLER_OPERATING_VOLTAGE);
566 
567         // bluetooth.controller.idle
568         writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_IDLE,
569                 PowerProfileProto.BLUETOOTH_CONTROLLER_IDLE);
570 
571         // bluetooth.controller.rx
572         writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_RX,
573                 PowerProfileProto.BLUETOOTH_CONTROLLER_RX);
574 
575         // bluetooth.controller.tx
576         writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_TX,
577                 PowerProfileProto.BLUETOOTH_CONTROLLER_TX);
578 
579         // bluetooth.controller.voltage
580         writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE,
581                 PowerProfileProto.BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE);
582 
583         // modem.controller.sleep
584         writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_SLEEP,
585                 PowerProfileProto.MODEM_CONTROLLER_SLEEP);
586 
587         // modem.controller.idle
588         writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_IDLE,
589                 PowerProfileProto.MODEM_CONTROLLER_IDLE);
590 
591         // modem.controller.rx
592         writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_RX,
593                 PowerProfileProto.MODEM_CONTROLLER_RX);
594 
595         // modem.controller.tx
596         writePowerConstantArrayToProto(proto, POWER_MODEM_CONTROLLER_TX,
597                 PowerProfileProto.MODEM_CONTROLLER_TX);
598 
599         // modem.controller.voltage
600         writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE,
601                 PowerProfileProto.MODEM_CONTROLLER_OPERATING_VOLTAGE);
602 
603         // gps.on
604         writePowerConstantToProto(proto, POWER_GPS_ON, PowerProfileProto.GPS_ON);
605 
606         // gps.signalqualitybased
607         writePowerConstantArrayToProto(proto, POWER_GPS_SIGNAL_QUALITY_BASED,
608                 PowerProfileProto.GPS_SIGNAL_QUALITY_BASED);
609 
610         // gps.voltage
611         writePowerConstantToProto(proto, POWER_GPS_OPERATING_VOLTAGE,
612                 PowerProfileProto.GPS_OPERATING_VOLTAGE);
613 
614         // bluetooth.on
615         writePowerConstantToProto(proto, POWER_BLUETOOTH_ON, PowerProfileProto.BLUETOOTH_ON);
616 
617         // bluetooth.active
618         writePowerConstantToProto(proto, POWER_BLUETOOTH_ACTIVE,
619                 PowerProfileProto.BLUETOOTH_ACTIVE);
620 
621         // bluetooth.at
622         writePowerConstantToProto(proto, POWER_BLUETOOTH_AT_CMD,
623                 PowerProfileProto.BLUETOOTH_AT_CMD);
624 
625         // ambient.on
626         writePowerConstantToProto(proto, POWER_AMBIENT_DISPLAY, PowerProfileProto.AMBIENT_DISPLAY);
627 
628         // screen.on
629         writePowerConstantToProto(proto, POWER_SCREEN_ON, PowerProfileProto.SCREEN_ON);
630 
631         // radio.on
632         writePowerConstantToProto(proto, POWER_RADIO_ON, PowerProfileProto.RADIO_ON);
633 
634         // radio.scanning
635         writePowerConstantToProto(proto, POWER_RADIO_SCANNING, PowerProfileProto.RADIO_SCANNING);
636 
637         // radio.active
638         writePowerConstantToProto(proto, POWER_RADIO_ACTIVE, PowerProfileProto.RADIO_ACTIVE);
639 
640         // screen.full
641         writePowerConstantToProto(proto, POWER_SCREEN_FULL, PowerProfileProto.SCREEN_FULL);
642 
643         // audio
644         writePowerConstantToProto(proto, POWER_AUDIO, PowerProfileProto.AUDIO);
645 
646         // video
647         writePowerConstantToProto(proto, POWER_VIDEO, PowerProfileProto.VIDEO);
648 
649         // camera.flashlight
650         writePowerConstantToProto(proto, POWER_FLASHLIGHT, PowerProfileProto.FLASHLIGHT);
651 
652         // memory.bandwidths
653         writePowerConstantToProto(proto, POWER_MEMORY, PowerProfileProto.MEMORY);
654 
655         // camera.avg
656         writePowerConstantToProto(proto, POWER_CAMERA, PowerProfileProto.CAMERA);
657 
658         // wifi.batchedscan
659         writePowerConstantToProto(proto, POWER_WIFI_BATCHED_SCAN,
660                 PowerProfileProto.WIFI_BATCHED_SCAN);
661 
662         // battery.capacity
663         writePowerConstantToProto(proto, POWER_BATTERY_CAPACITY,
664                 PowerProfileProto.BATTERY_CAPACITY);
665     }
666 
667     // Writes items in sPowerItemMap to proto if exists.
writePowerConstantToProto(ProtoOutputStream proto, String key, long fieldId)668     private void writePowerConstantToProto(ProtoOutputStream proto, String key, long fieldId) {
669         if (sPowerItemMap.containsKey(key)) {
670             proto.write(fieldId, sPowerItemMap.get(key));
671         }
672     }
673 
674     // Writes items in sPowerArrayMap to proto if exists.
writePowerConstantArrayToProto(ProtoOutputStream proto, String key, long fieldId)675     private void writePowerConstantArrayToProto(ProtoOutputStream proto, String key, long fieldId) {
676         if (sPowerArrayMap.containsKey(key)) {
677             for (Double d : sPowerArrayMap.get(key)) {
678                 proto.write(fieldId, d);
679             }
680         }
681     }
682 }
683