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