• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.server.powerstats;
18 
19 import android.hardware.power.stats.Channel;
20 import android.hardware.power.stats.EnergyConsumer;
21 import android.hardware.power.stats.EnergyConsumerAttribution;
22 import android.hardware.power.stats.EnergyConsumerResult;
23 import android.hardware.power.stats.EnergyMeasurement;
24 import android.hardware.power.stats.PowerEntity;
25 import android.hardware.power.stats.State;
26 import android.hardware.power.stats.StateResidency;
27 import android.hardware.power.stats.StateResidencyResult;
28 import android.util.Slog;
29 import android.util.proto.ProtoInputStream;
30 import android.util.proto.ProtoOutputStream;
31 import android.util.proto.ProtoUtils;
32 import android.util.proto.WireTypeMismatchException;
33 
34 import java.io.ByteArrayInputStream;
35 import java.io.IOException;
36 import java.io.PrintWriter;
37 import java.util.ArrayList;
38 import java.util.List;
39 
40 /**
41  * ProtoStreamUtils provides helper functions for the PowerStats HAL objects returned from calls
42  * to the PowerStats HAL APIs.  It provides functions to pack/unpack object arrays to/from protobuf
43  * format.  These helper functions are required since frameworks code uses the genstream option
44  * when generating source code and therefore, getter/setter helper functions are not available.  The
45  * protobufs need to be packed/unpacked in a more manual way using
46  * ProtoOutputStream/ProtoInputStream.  It also provides print() functions for debugging purposes.
47  */
48 public class ProtoStreamUtils {
49     private static final String TAG = ProtoStreamUtils.class.getSimpleName();
50 
51     static class PowerEntityUtils {
getProtoBytes(PowerEntity[] powerEntity)52         public static byte[] getProtoBytes(PowerEntity[] powerEntity) {
53             ProtoOutputStream pos = new ProtoOutputStream();
54             packProtoMessage(powerEntity, pos);
55             return pos.getBytes();
56         }
57 
packProtoMessage(PowerEntity[] powerEntity, ProtoOutputStream pos)58         public static void packProtoMessage(PowerEntity[] powerEntity,
59                 ProtoOutputStream pos) {
60             if (powerEntity == null) return;
61 
62             for (int i = 0; i < powerEntity.length; i++) {
63                 long peToken = pos.start(PowerStatsServiceResidencyProto.POWER_ENTITY);
64                 pos.write(PowerEntityProto.ID, powerEntity[i].id);
65                 pos.write(PowerEntityProto.NAME, powerEntity[i].name);
66                 if (powerEntity[i].states != null) {
67                     final int statesLength = powerEntity[i].states.length;
68                     for (int j = 0; j < statesLength; j++) {
69                         final State state = powerEntity[i].states[j];
70                         long stateToken = pos.start(PowerEntityProto.STATES);
71                         pos.write(StateProto.ID, state.id);
72                         pos.write(StateProto.NAME, state.name);
73                         pos.end(stateToken);
74                     }
75                 }
76                 pos.end(peToken);
77             }
78         }
79 
print(PowerEntity[] powerEntity)80         public static void print(PowerEntity[] powerEntity) {
81             if (powerEntity == null) return;
82 
83             for (int i = 0; i < powerEntity.length; i++) {
84                 Slog.d(TAG, "powerEntityId: " + powerEntity[i].id
85                         + ", powerEntityName: " + powerEntity[i].name);
86                 if (powerEntity[i].states != null) {
87                     for (int j = 0; j < powerEntity[i].states.length; j++) {
88                         Slog.d(TAG, "  StateId: " + powerEntity[i].states[j].id
89                                 + ", StateName: " + powerEntity[i].states[j].name);
90                     }
91                 }
92             }
93         }
94 
dumpsys(PowerEntity[] powerEntity, PrintWriter pw)95         public static void dumpsys(PowerEntity[] powerEntity, PrintWriter pw) {
96             if (powerEntity == null) return;
97 
98             for (int i = 0; i < powerEntity.length; i++) {
99                 pw.println("PowerEntityId: " + powerEntity[i].id
100                         + ", PowerEntityName: " + powerEntity[i].name);
101                 if (powerEntity[i].states != null) {
102                     for (int j = 0; j < powerEntity[i].states.length; j++) {
103                         pw.println("  StateId: " + powerEntity[i].states[j].id
104                                 + ", StateName: " + powerEntity[i].states[j].name);
105                     }
106                 }
107             }
108         }
109     }
110 
111     static class StateResidencyResultUtils {
adjustTimeSinceBootToEpoch(StateResidencyResult[] stateResidencyResult, long startWallTime)112         public static void adjustTimeSinceBootToEpoch(StateResidencyResult[] stateResidencyResult,
113                 long startWallTime) {
114             if (stateResidencyResult == null) return;
115 
116             for (int i = 0; i < stateResidencyResult.length; i++) {
117                 final int stateLength = stateResidencyResult[i].stateResidencyData.length;
118                 for (int j = 0; j < stateLength; j++) {
119                     final StateResidency stateResidencyData =
120                             stateResidencyResult[i].stateResidencyData[j];
121                     stateResidencyData.lastEntryTimestampMs += startWallTime;
122                 }
123             }
124         }
125 
getProtoBytes(StateResidencyResult[] stateResidencyResult)126         public static byte[] getProtoBytes(StateResidencyResult[] stateResidencyResult) {
127             ProtoOutputStream pos = new ProtoOutputStream();
128             packProtoMessage(stateResidencyResult, pos);
129             return pos.getBytes();
130         }
131 
packProtoMessage(StateResidencyResult[] stateResidencyResult, ProtoOutputStream pos)132         public static void packProtoMessage(StateResidencyResult[] stateResidencyResult,
133                 ProtoOutputStream pos) {
134             if (stateResidencyResult == null) return;
135 
136             for (int i = 0; i < stateResidencyResult.length; i++) {
137                 final int stateLength = stateResidencyResult[i].stateResidencyData.length;
138                 long srrToken = pos.start(PowerStatsServiceResidencyProto.STATE_RESIDENCY_RESULT);
139                 pos.write(StateResidencyResultProto.ID,
140                         stateResidencyResult[i].id);
141                 for (int j = 0; j < stateLength; j++) {
142                     final StateResidency stateResidencyData =
143                             stateResidencyResult[i].stateResidencyData[j];
144                     long srdToken = pos.start(StateResidencyResultProto.STATE_RESIDENCY_DATA);
145                     pos.write(StateResidencyProto.ID, stateResidencyData.id);
146                     pos.write(StateResidencyProto.TOTAL_TIME_IN_STATE_MS,
147                             stateResidencyData.totalTimeInStateMs);
148                     pos.write(StateResidencyProto.TOTAL_STATE_ENTRY_COUNT,
149                             stateResidencyData.totalStateEntryCount);
150                     pos.write(StateResidencyProto.LAST_ENTRY_TIMESTAMP_MS,
151                             stateResidencyData.lastEntryTimestampMs);
152                     pos.end(srdToken);
153                 }
154                 pos.end(srrToken);
155             }
156         }
157 
unpackProtoMessage(byte[] data)158         public static StateResidencyResult[] unpackProtoMessage(byte[] data) throws IOException {
159             final ProtoInputStream pis = new ProtoInputStream(new ByteArrayInputStream(data));
160             List<StateResidencyResult> stateResidencyResultList =
161                     new ArrayList<StateResidencyResult>();
162             while (true) {
163                 try {
164                     int nextField = pis.nextField();
165                     StateResidencyResult stateResidencyResult = new StateResidencyResult();
166 
167                     if (nextField == (int) PowerStatsServiceResidencyProto.STATE_RESIDENCY_RESULT) {
168                         long token =
169                                 pis.start(PowerStatsServiceResidencyProto.STATE_RESIDENCY_RESULT);
170                         stateResidencyResultList.add(unpackStateResidencyResultProto(pis));
171                         pis.end(token);
172                     } else if (nextField == ProtoInputStream.NO_MORE_FIELDS) {
173                         return stateResidencyResultList.toArray(
174                             new StateResidencyResult[stateResidencyResultList.size()]);
175                     } else {
176                         Slog.e(TAG, "Unhandled field in PowerStatsServiceResidencyProto: "
177                                 + ProtoUtils.currentFieldToString(pis));
178                     }
179                 } catch (WireTypeMismatchException wtme) {
180                     Slog.e(TAG, "Wire Type mismatch in PowerStatsServiceResidencyProto: "
181                             + ProtoUtils.currentFieldToString(pis));
182                 }
183             }
184         }
185 
unpackStateResidencyResultProto(ProtoInputStream pis)186         private static StateResidencyResult unpackStateResidencyResultProto(ProtoInputStream pis)
187                 throws IOException {
188             StateResidencyResult stateResidencyResult = new StateResidencyResult();
189             List<StateResidency> stateResidencyList = new ArrayList<StateResidency>();
190 
191             while (true) {
192                 try {
193                     switch (pis.nextField()) {
194                         case (int) StateResidencyResultProto.ID:
195                             stateResidencyResult.id = pis.readInt(StateResidencyResultProto.ID);
196                             break;
197 
198                         case (int) StateResidencyResultProto.STATE_RESIDENCY_DATA:
199                             long token = pis.start(StateResidencyResultProto.STATE_RESIDENCY_DATA);
200                             stateResidencyList.add(unpackStateResidencyProto(pis));
201                             pis.end(token);
202                             break;
203 
204                         case ProtoInputStream.NO_MORE_FIELDS:
205                             stateResidencyResult.stateResidencyData = stateResidencyList.toArray(
206                                 new StateResidency[stateResidencyList.size()]);
207                             return stateResidencyResult;
208 
209                         default:
210                             Slog.e(TAG, "Unhandled field in StateResidencyResultProto: "
211                                     + ProtoUtils.currentFieldToString(pis));
212                             break;
213                     }
214                 } catch (WireTypeMismatchException wtme) {
215                     Slog.e(TAG, "Wire Type mismatch in StateResidencyResultProto: "
216                             + ProtoUtils.currentFieldToString(pis));
217                 }
218             }
219         }
220 
unpackStateResidencyProto(ProtoInputStream pis)221         private static StateResidency unpackStateResidencyProto(ProtoInputStream pis)
222                 throws IOException {
223             StateResidency stateResidency = new StateResidency();
224 
225             while (true) {
226                 try {
227                     switch (pis.nextField()) {
228                         case (int) StateResidencyProto.ID:
229                             stateResidency.id = pis.readInt(StateResidencyProto.ID);
230                             break;
231 
232                         case (int) StateResidencyProto.TOTAL_TIME_IN_STATE_MS:
233                             stateResidency.totalTimeInStateMs =
234                                 pis.readLong(StateResidencyProto.TOTAL_TIME_IN_STATE_MS);
235                             break;
236 
237                         case (int) StateResidencyProto.TOTAL_STATE_ENTRY_COUNT:
238                             stateResidency.totalStateEntryCount =
239                                 pis.readLong(StateResidencyProto.TOTAL_STATE_ENTRY_COUNT);
240                             break;
241 
242                         case (int) StateResidencyProto.LAST_ENTRY_TIMESTAMP_MS:
243                             stateResidency.lastEntryTimestampMs =
244                                 pis.readLong(StateResidencyProto.LAST_ENTRY_TIMESTAMP_MS);
245                             break;
246 
247                         case ProtoInputStream.NO_MORE_FIELDS:
248                             return stateResidency;
249 
250                         default:
251                             Slog.e(TAG, "Unhandled field in StateResidencyProto: "
252                                     + ProtoUtils.currentFieldToString(pis));
253                             break;
254 
255                     }
256                 } catch (WireTypeMismatchException wtme) {
257                     Slog.e(TAG, "Wire Type mismatch in StateResidencyProto: "
258                             + ProtoUtils.currentFieldToString(pis));
259                 }
260             }
261         }
262 
print(StateResidencyResult[] stateResidencyResult)263         public static void print(StateResidencyResult[] stateResidencyResult) {
264             if (stateResidencyResult == null) return;
265 
266             for (int i = 0; i < stateResidencyResult.length; i++) {
267                 Slog.d(TAG, "PowerEntityId: " + stateResidencyResult[i].id);
268                 for (int j = 0; j < stateResidencyResult[i].stateResidencyData.length; j++) {
269                     Slog.d(TAG, "  StateId: "
270                             + stateResidencyResult[i].stateResidencyData[j].id
271                             + ", TotalTimeInStateMs: "
272                             + stateResidencyResult[i].stateResidencyData[j].totalTimeInStateMs
273                             + ", TotalStateEntryCount: "
274                             + stateResidencyResult[i].stateResidencyData[j].totalStateEntryCount
275                             + ", LastEntryTimestampMs: "
276                             + stateResidencyResult[i].stateResidencyData[j].lastEntryTimestampMs);
277                 }
278             }
279         }
280     }
281 
282     static class ChannelUtils {
getProtoBytes(Channel[] channel)283         public static byte[] getProtoBytes(Channel[] channel) {
284             ProtoOutputStream pos = new ProtoOutputStream();
285             packProtoMessage(channel, pos);
286             return pos.getBytes();
287         }
288 
packProtoMessage(Channel[] channel, ProtoOutputStream pos)289         public static void packProtoMessage(Channel[] channel, ProtoOutputStream pos) {
290             if (channel == null) return;
291 
292             for (int i = 0; i < channel.length; i++) {
293                 long token = pos.start(PowerStatsServiceMeterProto.CHANNEL);
294                 pos.write(ChannelProto.ID, channel[i].id);
295                 pos.write(ChannelProto.NAME, channel[i].name);
296                 pos.write(ChannelProto.SUBSYSTEM, channel[i].subsystem);
297                 pos.end(token);
298             }
299         }
300 
print(Channel[] channel)301         public static void print(Channel[] channel) {
302             if (channel == null) return;
303 
304             for (int i = 0; i < channel.length; i++) {
305                 Slog.d(TAG, "ChannelId: " + channel[i].id
306                         + ", ChannelName: " + channel[i].name
307                         + ", ChannelSubsystem: " + channel[i].subsystem);
308             }
309         }
310 
dumpsys(Channel[] channel, PrintWriter pw)311         public static void dumpsys(Channel[] channel, PrintWriter pw) {
312             if (channel == null) return;
313 
314             for (int i = 0; i < channel.length; i++) {
315                 pw.println("ChannelId: " + channel[i].id
316                         + ", ChannelName: " + channel[i].name
317                         + ", ChannelSubsystem: " + channel[i].subsystem);
318             }
319         }
320     }
321 
322     static class EnergyMeasurementUtils {
adjustTimeSinceBootToEpoch(EnergyMeasurement[] energyMeasurement, long startWallTime)323         public static void adjustTimeSinceBootToEpoch(EnergyMeasurement[] energyMeasurement,
324                 long startWallTime) {
325             if (energyMeasurement == null) return;
326 
327             for (int i = 0; i < energyMeasurement.length; i++) {
328                 energyMeasurement[i].timestampMs += startWallTime;
329             }
330         }
331 
getProtoBytes(EnergyMeasurement[] energyMeasurement)332         public static byte[] getProtoBytes(EnergyMeasurement[] energyMeasurement) {
333             ProtoOutputStream pos = new ProtoOutputStream();
334             packProtoMessage(energyMeasurement, pos);
335             return pos.getBytes();
336         }
337 
packProtoMessage(EnergyMeasurement[] energyMeasurement, ProtoOutputStream pos)338         public static void packProtoMessage(EnergyMeasurement[] energyMeasurement,
339                 ProtoOutputStream pos) {
340             if (energyMeasurement == null) return;
341 
342             for (int i = 0; i < energyMeasurement.length; i++) {
343                 long token = pos.start(PowerStatsServiceMeterProto.ENERGY_MEASUREMENT);
344                 pos.write(EnergyMeasurementProto.ID, energyMeasurement[i].id);
345                 pos.write(EnergyMeasurementProto.TIMESTAMP_MS, energyMeasurement[i].timestampMs);
346                 pos.write(EnergyMeasurementProto.DURATION_MS, energyMeasurement[i].durationMs);
347                 pos.write(EnergyMeasurementProto.ENERGY_UWS, energyMeasurement[i].energyUWs);
348                 pos.end(token);
349             }
350         }
351 
unpackProtoMessage(byte[] data)352         public static EnergyMeasurement[] unpackProtoMessage(byte[] data) throws IOException {
353             final ProtoInputStream pis = new ProtoInputStream(new ByteArrayInputStream(data));
354             List<EnergyMeasurement> energyMeasurementList = new ArrayList<EnergyMeasurement>();
355 
356             while (true) {
357                 try {
358                     int nextField = pis.nextField();
359                     EnergyMeasurement energyMeasurement = new EnergyMeasurement();
360 
361                     if (nextField == (int) PowerStatsServiceMeterProto.ENERGY_MEASUREMENT) {
362                         long token = pis.start(PowerStatsServiceMeterProto.ENERGY_MEASUREMENT);
363                         energyMeasurementList.add(unpackEnergyMeasurementProto(pis));
364                         pis.end(token);
365                     } else if (nextField == ProtoInputStream.NO_MORE_FIELDS) {
366                         return energyMeasurementList.toArray(
367                             new EnergyMeasurement[energyMeasurementList.size()]);
368                     } else {
369                         Slog.e(TAG, "Unhandled field in proto: "
370                                 + ProtoUtils.currentFieldToString(pis));
371                     }
372                 } catch (WireTypeMismatchException wtme) {
373                     Slog.e(TAG, "Wire Type mismatch in proto: "
374                             + ProtoUtils.currentFieldToString(pis));
375                 }
376             }
377         }
378 
unpackEnergyMeasurementProto(ProtoInputStream pis)379         private static EnergyMeasurement unpackEnergyMeasurementProto(ProtoInputStream pis)
380                 throws IOException {
381             EnergyMeasurement energyMeasurement = new EnergyMeasurement();
382 
383             while (true) {
384                 try {
385                     switch (pis.nextField()) {
386                         case (int) EnergyMeasurementProto.ID:
387                             energyMeasurement.id =
388                                 pis.readInt(EnergyMeasurementProto.ID);
389                             break;
390 
391                         case (int) EnergyMeasurementProto.TIMESTAMP_MS:
392                             energyMeasurement.timestampMs =
393                                 pis.readLong(EnergyMeasurementProto.TIMESTAMP_MS);
394                             break;
395 
396                         case (int) EnergyMeasurementProto.DURATION_MS:
397                             energyMeasurement.durationMs =
398                                 pis.readLong(EnergyMeasurementProto.DURATION_MS);
399                             break;
400 
401                         case (int) EnergyMeasurementProto.ENERGY_UWS:
402                             energyMeasurement.energyUWs =
403                                 pis.readLong(EnergyMeasurementProto.ENERGY_UWS);
404                             break;
405 
406                         case ProtoInputStream.NO_MORE_FIELDS:
407                             return energyMeasurement;
408 
409                         default:
410                             Slog.e(TAG, "Unhandled field in EnergyMeasurementProto: "
411                                     + ProtoUtils.currentFieldToString(pis));
412                             break;
413                     }
414                 } catch (WireTypeMismatchException wtme) {
415                     Slog.e(TAG, "Wire Type mismatch in EnergyMeasurementProto: "
416                             + ProtoUtils.currentFieldToString(pis));
417                 }
418             }
419         }
420 
print(EnergyMeasurement[] energyMeasurement)421         public static void print(EnergyMeasurement[] energyMeasurement) {
422             if (energyMeasurement == null) return;
423 
424             for (int i = 0; i < energyMeasurement.length; i++) {
425                 Slog.d(TAG, "ChannelId: " + energyMeasurement[i].id
426                         + ", Timestamp (ms): " + energyMeasurement[i].timestampMs
427                         + ", Duration (ms): " + energyMeasurement[i].durationMs
428                         + ", Energy (uWs): " + energyMeasurement[i].energyUWs);
429             }
430         }
431     }
432 
433     static class EnergyConsumerUtils {
getProtoBytes(EnergyConsumer[] energyConsumer)434         public static byte[] getProtoBytes(EnergyConsumer[] energyConsumer) {
435             ProtoOutputStream pos = new ProtoOutputStream();
436             packProtoMessage(energyConsumer, pos);
437             return pos.getBytes();
438         }
439 
packProtoMessage(EnergyConsumer[] energyConsumer, ProtoOutputStream pos)440         public static void packProtoMessage(EnergyConsumer[] energyConsumer,
441                 ProtoOutputStream pos) {
442             if (energyConsumer == null) return;
443 
444             for (int i = 0; i < energyConsumer.length; i++) {
445                 long token = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER);
446                 pos.write(EnergyConsumerProto.ID, energyConsumer[i].id);
447                 pos.write(EnergyConsumerProto.ORDINAL, energyConsumer[i].ordinal);
448                 pos.write(EnergyConsumerProto.TYPE, energyConsumer[i].type);
449                 pos.write(EnergyConsumerProto.NAME, energyConsumer[i].name);
450                 pos.end(token);
451             }
452         }
453 
unpackProtoMessage(byte[] data)454         public static EnergyConsumer[] unpackProtoMessage(byte[] data) throws IOException {
455             final ProtoInputStream pis = new ProtoInputStream(new ByteArrayInputStream(data));
456             List<EnergyConsumer> energyConsumerList = new ArrayList<EnergyConsumer>();
457 
458             while (true) {
459                 try {
460                     int nextField = pis.nextField();
461                     EnergyConsumer energyConsumer = new EnergyConsumer();
462 
463                     if (nextField == (int) PowerStatsServiceModelProto.ENERGY_CONSUMER) {
464                         long token = pis.start(PowerStatsServiceModelProto.ENERGY_CONSUMER);
465                         energyConsumerList.add(unpackEnergyConsumerProto(pis));
466                         pis.end(token);
467                     } else if (nextField == ProtoInputStream.NO_MORE_FIELDS) {
468                         return energyConsumerList.toArray(
469                             new EnergyConsumer[energyConsumerList.size()]);
470                     } else {
471                         Slog.e(TAG, "Unhandled field in proto: "
472                                 + ProtoUtils.currentFieldToString(pis));
473                     }
474                 } catch (WireTypeMismatchException wtme) {
475                     Slog.e(TAG, "Wire Type mismatch in proto: "
476                             + ProtoUtils.currentFieldToString(pis));
477                 }
478             }
479         }
480 
unpackEnergyConsumerProto(ProtoInputStream pis)481         private static EnergyConsumer unpackEnergyConsumerProto(ProtoInputStream pis)
482                 throws IOException {
483             final EnergyConsumer energyConsumer = new EnergyConsumer();
484 
485             while (true) {
486                 try {
487                     switch (pis.nextField()) {
488                         case (int) EnergyConsumerProto.ID:
489                             energyConsumer.id = pis.readInt(EnergyConsumerProto.ID);
490                             break;
491 
492                         case (int) EnergyConsumerProto.ORDINAL:
493                             energyConsumer.ordinal = pis.readInt(EnergyConsumerProto.ORDINAL);
494                             break;
495 
496                         case (int) EnergyConsumerProto.TYPE:
497                             energyConsumer.type = (byte) pis.readInt(EnergyConsumerProto.TYPE);
498                             break;
499 
500                         case (int) EnergyConsumerProto.NAME:
501                             energyConsumer.name = pis.readString(EnergyConsumerProto.NAME);
502                             break;
503 
504                         case ProtoInputStream.NO_MORE_FIELDS:
505                             return energyConsumer;
506 
507                         default:
508                             Slog.e(TAG, "Unhandled field in EnergyConsumerProto: "
509                                     + ProtoUtils.currentFieldToString(pis));
510                             break;
511 
512                     }
513                 } catch (WireTypeMismatchException wtme) {
514                     Slog.e(TAG, "Wire Type mismatch in EnergyConsumerProto: "
515                             + ProtoUtils.currentFieldToString(pis));
516                 }
517             }
518         }
519 
print(EnergyConsumer[] energyConsumer)520         public static void print(EnergyConsumer[] energyConsumer) {
521             if (energyConsumer == null) return;
522 
523             for (int i = 0; i < energyConsumer.length; i++) {
524                 Slog.d(TAG, "EnergyConsumerId: " + energyConsumer[i].id
525                         + ", Ordinal: " + energyConsumer[i].ordinal
526                         + ", Type: " + energyConsumer[i].type
527                         + ", Name: " + energyConsumer[i].name);
528             }
529         }
530 
dumpsys(EnergyConsumer[] energyConsumer, PrintWriter pw)531         public static void dumpsys(EnergyConsumer[] energyConsumer, PrintWriter pw) {
532             if (energyConsumer == null) return;
533 
534             for (int i = 0; i < energyConsumer.length; i++) {
535                 pw.println("EnergyConsumerId: " + energyConsumer[i].id
536                         + ", Ordinal: " + energyConsumer[i].ordinal
537                         + ", Type: " + energyConsumer[i].type
538                         + ", Name: " + energyConsumer[i].name);
539             }
540         }
541     }
542 
543     static class EnergyConsumerResultUtils {
adjustTimeSinceBootToEpoch(EnergyConsumerResult[] energyConsumerResult, long startWallTime)544         public static void adjustTimeSinceBootToEpoch(EnergyConsumerResult[] energyConsumerResult,
545                 long startWallTime) {
546             if (energyConsumerResult == null) return;
547 
548             for (int i = 0; i < energyConsumerResult.length; i++) {
549                 energyConsumerResult[i].timestampMs += startWallTime;
550             }
551         }
552 
getProtoBytes(EnergyConsumerResult[] energyConsumerResult, boolean includeAttribution)553         public static byte[] getProtoBytes(EnergyConsumerResult[] energyConsumerResult,
554                 boolean includeAttribution) {
555             ProtoOutputStream pos = new ProtoOutputStream();
556             packProtoMessage(energyConsumerResult, pos, includeAttribution);
557             return pos.getBytes();
558         }
559 
packProtoMessage(EnergyConsumerResult[] energyConsumerResult, ProtoOutputStream pos, boolean includeAttribution)560         public static void packProtoMessage(EnergyConsumerResult[] energyConsumerResult,
561                 ProtoOutputStream pos, boolean includeAttribution) {
562             if (energyConsumerResult == null) return;
563 
564             for (int i = 0; i < energyConsumerResult.length; i++) {
565                 long ecrToken = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_RESULT);
566                 pos.write(EnergyConsumerResultProto.ID, energyConsumerResult[i].id);
567                 pos.write(EnergyConsumerResultProto.TIMESTAMP_MS,
568                         energyConsumerResult[i].timestampMs);
569                 pos.write(EnergyConsumerResultProto.ENERGY_UWS, energyConsumerResult[i].energyUWs);
570 
571                 if (includeAttribution) {
572                     final int attributionLength = energyConsumerResult[i].attribution.length;
573 
574                     for (int j = 0; j < attributionLength; j++) {
575                         final EnergyConsumerAttribution energyConsumerAttribution =
576                                 energyConsumerResult[i].attribution[j];
577                         final long ecaToken = pos.start(EnergyConsumerResultProto.ATTRIBUTION);
578                         pos.write(EnergyConsumerAttributionProto.UID,
579                                 energyConsumerAttribution.uid);
580                         pos.write(EnergyConsumerAttributionProto.ENERGY_UWS,
581                                 energyConsumerAttribution.energyUWs);
582                         pos.end(ecaToken);
583                     }
584                 }
585 
586                 pos.end(ecrToken);
587             }
588         }
589 
unpackProtoMessage(byte[] data)590         public static EnergyConsumerResult[] unpackProtoMessage(byte[] data) throws IOException {
591             final ProtoInputStream pis = new ProtoInputStream(new ByteArrayInputStream(data));
592             List<EnergyConsumerResult> energyConsumerResultList =
593                     new ArrayList<EnergyConsumerResult>();
594             while (true) {
595                 try {
596                     int nextField = pis.nextField();
597                     EnergyConsumerResult energyConsumerResult = new EnergyConsumerResult();
598 
599                     if (nextField == (int) PowerStatsServiceModelProto.ENERGY_CONSUMER_RESULT) {
600                         long token = pis.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_RESULT);
601                         energyConsumerResultList.add(unpackEnergyConsumerResultProto(pis));
602                         pis.end(token);
603                     } else if (nextField == ProtoInputStream.NO_MORE_FIELDS) {
604                         return energyConsumerResultList.toArray(
605                             new EnergyConsumerResult[energyConsumerResultList.size()]);
606                     } else {
607                         Slog.e(TAG, "Unhandled field in proto: "
608                                 + ProtoUtils.currentFieldToString(pis));
609                     }
610                 } catch (WireTypeMismatchException wtme) {
611                     Slog.e(TAG, "Wire Type mismatch in proto: "
612                             + ProtoUtils.currentFieldToString(pis));
613                 }
614             }
615         }
616 
unpackEnergyConsumerAttributionProto( ProtoInputStream pis)617         private static EnergyConsumerAttribution unpackEnergyConsumerAttributionProto(
618                 ProtoInputStream pis) throws IOException {
619             final EnergyConsumerAttribution energyConsumerAttribution =
620                     new EnergyConsumerAttribution();
621 
622             while (true) {
623                 try {
624                     switch (pis.nextField()) {
625                         case (int) EnergyConsumerAttributionProto.UID:
626                             energyConsumerAttribution.uid =
627                                 pis.readInt(EnergyConsumerAttributionProto.UID);
628                             break;
629 
630                         case (int) EnergyConsumerAttributionProto.ENERGY_UWS:
631                             energyConsumerAttribution.energyUWs =
632                                 pis.readLong(EnergyConsumerAttributionProto.ENERGY_UWS);
633                             break;
634 
635                         case ProtoInputStream.NO_MORE_FIELDS:
636                             return energyConsumerAttribution;
637 
638                         default:
639                             Slog.e(TAG, "Unhandled field in EnergyConsumerAttributionProto: "
640                                     + ProtoUtils.currentFieldToString(pis));
641                             break;
642 
643                     }
644                 } catch (WireTypeMismatchException wtme) {
645                     Slog.e(TAG, "Wire Type mismatch in EnergyConsumerAttributionProto: "
646                             + ProtoUtils.currentFieldToString(pis));
647                 }
648             }
649         }
650 
unpackEnergyConsumerResultProto(ProtoInputStream pis)651         private static EnergyConsumerResult unpackEnergyConsumerResultProto(ProtoInputStream pis)
652                 throws IOException {
653             EnergyConsumerResult energyConsumerResult = new EnergyConsumerResult();
654             final List<EnergyConsumerAttribution> energyConsumerAttributionList =
655                     new ArrayList<EnergyConsumerAttribution>();
656 
657             while (true) {
658                 try {
659                     switch (pis.nextField()) {
660                         case (int) EnergyConsumerResultProto.ID:
661                             energyConsumerResult.id = pis.readInt(EnergyConsumerResultProto.ID);
662                             break;
663 
664                         case (int) EnergyConsumerResultProto.TIMESTAMP_MS:
665                             energyConsumerResult.timestampMs =
666                                 pis.readLong(EnergyConsumerResultProto.TIMESTAMP_MS);
667                             break;
668 
669                         case (int) EnergyConsumerResultProto.ENERGY_UWS:
670                             energyConsumerResult.energyUWs =
671                                 pis.readLong(EnergyConsumerResultProto.ENERGY_UWS);
672                             break;
673 
674                         case (int) EnergyConsumerResultProto.ATTRIBUTION:
675                             final long token = pis.start(EnergyConsumerResultProto.ATTRIBUTION);
676                             energyConsumerAttributionList.add(
677                                     unpackEnergyConsumerAttributionProto(pis));
678                             pis.end(token);
679                             break;
680 
681                         case ProtoInputStream.NO_MORE_FIELDS:
682                             energyConsumerResult.attribution =
683                                 energyConsumerAttributionList.toArray(
684                                     new EnergyConsumerAttribution[
685                                         energyConsumerAttributionList.size()]);
686                             return energyConsumerResult;
687 
688                         default:
689                             Slog.e(TAG, "Unhandled field in EnergyConsumerResultProto: "
690                                     + ProtoUtils.currentFieldToString(pis));
691                             break;
692                     }
693                 } catch (WireTypeMismatchException wtme) {
694                     Slog.e(TAG, "Wire Type mismatch in EnergyConsumerResultProto: "
695                             + ProtoUtils.currentFieldToString(pis));
696                 }
697             }
698         }
699 
print(EnergyConsumerResult[] energyConsumerResult)700         public static void print(EnergyConsumerResult[] energyConsumerResult) {
701             if (energyConsumerResult == null) return;
702 
703             for (int i = 0; i < energyConsumerResult.length; i++) {
704                 final EnergyConsumerResult result = energyConsumerResult[i];
705                 Slog.d(TAG, "EnergyConsumerId: " + result.id
706                         + ", Timestamp (ms): " + result.timestampMs
707                         + ", Energy (uWs): " + result.energyUWs);
708                 final int attributionLength = result.attribution.length;
709                 for (int j = 0; j < attributionLength; j++) {
710                     final EnergyConsumerAttribution attribution = result.attribution[j];
711                     Slog.d(TAG, "  UID: " + attribution.uid
712                             + "  Energy (uWs): " + attribution.energyUWs);
713                 }
714             }
715         }
716     }
717 }
718