Log energy consumer result attribution data
Bug: 175723658
Test: atest FrameworksServicesTests:PowerStatsServiceTest
Change-Id: I4d0dccd440b02a35e086b08e31b1bf1f087f61e3
diff --git a/core/proto/android/server/powerstatsservice.proto b/core/proto/android/server/powerstatsservice.proto
index 0c5a360..4b1ee02 100644
--- a/core/proto/android/server/powerstatsservice.proto
+++ b/core/proto/android/server/powerstatsservice.proto
@@ -191,6 +191,14 @@
optional string name = 4;
}
+message EnergyConsumerAttributionProto {
+ /** Android ID / Linux UID, the accumulated energy should be attributed to. */
+ optional int32 uid = 1;
+
+ /** Accumulated energy since boot in microwatt-seconds (uWs) for this AID. */
+ optional int64 energy_uws = 2;
+}
+
/**
* Energy consumer result:
* An estimate of energy consumption since boot for the subsystem identified
@@ -205,6 +213,9 @@
/** Accumulated energy since device boot in microwatt-seconds (uWs) */
optional int64 energy_uws = 3;
+
+ /** Optional attribution per UID for this EnergyConsumer. */
+ repeated EnergyConsumerAttributionProto attribution = 4;
}
/**
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
index 78a227e..88090b3 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
@@ -53,8 +53,9 @@
public final class PowerStatsLogger extends Handler {
private static final String TAG = PowerStatsLogger.class.getSimpleName();
private static final boolean DEBUG = false;
- protected static final int MSG_LOG_TO_DATA_STORAGE_TIMER = 0;
- protected static final int MSG_LOG_TO_DATA_STORAGE_BATTERY_DROP = 1;
+ protected static final int MSG_LOG_TO_DATA_STORAGE_BATTERY_DROP = 0;
+ protected static final int MSG_LOG_TO_DATA_STORAGE_LOW_FREQUENCY = 1;
+ protected static final int MSG_LOG_TO_DATA_STORAGE_HIGH_FREQUENCY = 2;
private final PowerStatsDataStorage mPowerStatsMeterStorage;
private final PowerStatsDataStorage mPowerStatsModelStorage;
@@ -64,8 +65,8 @@
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_LOG_TO_DATA_STORAGE_TIMER:
- if (DEBUG) Slog.d(TAG, "Logging to data storage on timer");
+ case MSG_LOG_TO_DATA_STORAGE_HIGH_FREQUENCY:
+ if (DEBUG) Slog.d(TAG, "Logging to data storage on high frequency timer");
// Log power meter data.
EnergyMeasurement[] energyMeasurements =
@@ -74,12 +75,23 @@
EnergyMeasurementUtils.getProtoBytes(energyMeasurements));
if (DEBUG) EnergyMeasurementUtils.print(energyMeasurements);
- // Log power model data.
- EnergyConsumerResult[] energyConsumerResults =
+ // Log power model data without attribution data.
+ EnergyConsumerResult[] ecrNoAttribution =
mPowerStatsHALWrapper.getEnergyConsumed(new int[0]);
mPowerStatsModelStorage.write(
- EnergyConsumerResultUtils.getProtoBytes(energyConsumerResults));
- if (DEBUG) EnergyConsumerResultUtils.print(energyConsumerResults);
+ EnergyConsumerResultUtils.getProtoBytes(ecrNoAttribution, false));
+ if (DEBUG) EnergyConsumerResultUtils.print(ecrNoAttribution);
+ break;
+
+ case MSG_LOG_TO_DATA_STORAGE_LOW_FREQUENCY:
+ if (DEBUG) Slog.d(TAG, "Logging to data storage on low frequency timer");
+
+ // Log power model data with attribution data.
+ EnergyConsumerResult[] ecrAttribution =
+ mPowerStatsHALWrapper.getEnergyConsumed(new int[0]);
+ mPowerStatsModelStorage.write(
+ EnergyConsumerResultUtils.getProtoBytes(ecrAttribution, true));
+ if (DEBUG) EnergyConsumerResultUtils.print(ecrAttribution);
break;
case MSG_LOG_TO_DATA_STORAGE_BATTERY_DROP:
@@ -163,7 +175,7 @@
// deserialize, then re-serialize. This is computationally inefficient.
EnergyConsumerResult[] energyConsumerResult =
EnergyConsumerResultUtils.unpackProtoMessage(data);
- EnergyConsumerResultUtils.packProtoMessage(energyConsumerResult, pos);
+ EnergyConsumerResultUtils.packProtoMessage(energyConsumerResult, pos, true);
if (DEBUG) EnergyConsumerResultUtils.print(energyConsumerResult);
} catch (IOException e) {
Slog.e(TAG, "Failed to write energy model data to incident report.");
diff --git a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
index 766cf9c..bd003d3 100644
--- a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
+++ b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
@@ -18,6 +18,7 @@
import android.hardware.power.stats.Channel;
import android.hardware.power.stats.EnergyConsumer;
+import android.hardware.power.stats.EnergyConsumerAttribution;
import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyMeasurement;
import android.hardware.power.stats.PowerEntity;
@@ -433,23 +434,40 @@
}
static class EnergyConsumerResultUtils {
- public static byte[] getProtoBytes(EnergyConsumerResult[] energyConsumerResult) {
+ public static byte[] getProtoBytes(EnergyConsumerResult[] energyConsumerResult,
+ boolean includeAttribution) {
ProtoOutputStream pos = new ProtoOutputStream();
- packProtoMessage(energyConsumerResult, pos);
+ packProtoMessage(energyConsumerResult, pos, includeAttribution);
return pos.getBytes();
}
public static void packProtoMessage(EnergyConsumerResult[] energyConsumerResult,
- ProtoOutputStream pos) {
+ ProtoOutputStream pos, boolean includeAttribution) {
if (energyConsumerResult == null) return;
for (int i = 0; i < energyConsumerResult.length; i++) {
- long token = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_RESULT);
+ long ecrToken = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_RESULT);
pos.write(EnergyConsumerResultProto.ID, energyConsumerResult[i].id);
pos.write(EnergyConsumerResultProto.TIMESTAMP_MS,
energyConsumerResult[i].timestampMs);
pos.write(EnergyConsumerResultProto.ENERGY_UWS, energyConsumerResult[i].energyUWs);
- pos.end(token);
+
+ if (includeAttribution) {
+ final int attributionLength = energyConsumerResult[i].attribution.length;
+
+ for (int j = 0; j < attributionLength; j++) {
+ final EnergyConsumerAttribution energyConsumerAttribution =
+ energyConsumerResult[i].attribution[j];
+ final long ecaToken = pos.start(EnergyConsumerResultProto.ATTRIBUTION);
+ pos.write(EnergyConsumerAttributionProto.UID,
+ energyConsumerAttribution.uid);
+ pos.write(EnergyConsumerAttributionProto.ENERGY_UWS,
+ energyConsumerAttribution.energyUWs);
+ pos.end(ecaToken);
+ }
+ }
+
+ pos.end(ecrToken);
}
}
@@ -480,9 +498,45 @@
}
}
+ private static EnergyConsumerAttribution unpackEnergyConsumerAttributionProto(
+ ProtoInputStream pis) throws IOException {
+ final EnergyConsumerAttribution energyConsumerAttribution =
+ new EnergyConsumerAttribution();
+
+ while (true) {
+ try {
+ switch (pis.nextField()) {
+ case (int) EnergyConsumerAttributionProto.UID:
+ energyConsumerAttribution.uid =
+ pis.readInt(EnergyConsumerAttributionProto.UID);
+ break;
+
+ case (int) EnergyConsumerAttributionProto.ENERGY_UWS:
+ energyConsumerAttribution.energyUWs =
+ pis.readLong(EnergyConsumerAttributionProto.ENERGY_UWS);
+ break;
+
+ case ProtoInputStream.NO_MORE_FIELDS:
+ return energyConsumerAttribution;
+
+ default:
+ Slog.e(TAG, "Unhandled field in EnergyConsumerAttributionProto: "
+ + ProtoUtils.currentFieldToString(pis));
+ break;
+
+ }
+ } catch (WireTypeMismatchException wtme) {
+ Slog.e(TAG, "Wire Type mismatch in EnergyConsumerAttributionProto: "
+ + ProtoUtils.currentFieldToString(pis));
+ }
+ }
+ }
+
private static EnergyConsumerResult unpackEnergyConsumerResultProto(ProtoInputStream pis)
throws IOException {
EnergyConsumerResult energyConsumerResult = new EnergyConsumerResult();
+ final List<EnergyConsumerAttribution> energyConsumerAttributionList =
+ new ArrayList<EnergyConsumerAttribution>();
while (true) {
try {
@@ -501,7 +555,18 @@
pis.readLong(EnergyConsumerResultProto.ENERGY_UWS);
break;
+ case (int) EnergyConsumerResultProto.ATTRIBUTION:
+ final long token = pis.start(EnergyConsumerResultProto.ATTRIBUTION);
+ energyConsumerAttributionList.add(
+ unpackEnergyConsumerAttributionProto(pis));
+ pis.end(token);
+ break;
+
case ProtoInputStream.NO_MORE_FIELDS:
+ energyConsumerResult.attribution =
+ energyConsumerAttributionList.toArray(
+ new EnergyConsumerAttribution[
+ energyConsumerAttributionList.size()]);
return energyConsumerResult;
default:
@@ -520,9 +585,16 @@
if (energyConsumerResult == null) return;
for (int i = 0; i < energyConsumerResult.length; i++) {
- Slog.d(TAG, "EnergyConsumerId: " + energyConsumerResult[i].id
- + ", Timestamp (ms): " + energyConsumerResult[i].timestampMs
- + ", Energy (uWs): " + energyConsumerResult[i].energyUWs);
+ final EnergyConsumerResult result = energyConsumerResult[i];
+ Slog.d(TAG, "EnergyConsumerId: " + result.id
+ + ", Timestamp (ms): " + result.timestampMs
+ + ", Energy (uWs): " + result.energyUWs);
+ final int attributionLength = result.attribution.length;
+ for (int j = 0; j < attributionLength; j++) {
+ final EnergyConsumerAttribution attribution = result.attribution[j];
+ Slog.d(TAG, " UID: " + attribution.uid
+ + " Energy (uWs): " + attribution.energyUWs);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/powerstats/TimerTrigger.java b/services/core/java/com/android/server/powerstats/TimerTrigger.java
index 7cba00f..f8a4135 100644
--- a/services/core/java/com/android/server/powerstats/TimerTrigger.java
+++ b/services/core/java/com/android/server/powerstats/TimerTrigger.java
@@ -29,18 +29,30 @@
private static final String TAG = TimerTrigger.class.getSimpleName();
private static final boolean DEBUG = false;
// TODO(b/166689029): Make configurable through global settings.
- private static final long LOG_PERIOD_MS = 120 * 1000;
+ private static final long LOG_PERIOD_MS_LOW_FREQUENCY = 60 * 60 * 1000; // 1 hour
+ private static final long LOG_PERIOD_MS_HIGH_FREQUENCY = 2 * 60 * 1000; // 2 minutes
private final Handler mHandler;
- private Runnable mLogData = new Runnable() {
+ private Runnable mLogDataLowFrequency = new Runnable() {
@Override
public void run() {
// Do not wake the device for these messages. Opportunistically log rail data every
- // LOG_PERIOD_MS.
- mHandler.postDelayed(mLogData, LOG_PERIOD_MS);
- if (DEBUG) Slog.d(TAG, "Received delayed message. Log rail data");
- logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_TIMER);
+ // LOG_PERIOD_MS_LOW_FREQUENCY.
+ mHandler.postDelayed(mLogDataLowFrequency, LOG_PERIOD_MS_LOW_FREQUENCY);
+ if (DEBUG) Slog.d(TAG, "Received delayed message. Log rail data low frequency");
+ logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_LOW_FREQUENCY);
+ }
+ };
+
+ private Runnable mLogDataHighFrequency = new Runnable() {
+ @Override
+ public void run() {
+ // Do not wake the device for these messages. Opportunistically log rail data every
+ // LOG_PERIOD_MS_HIGH_FREQUENCY.
+ mHandler.postDelayed(mLogDataHighFrequency, LOG_PERIOD_MS_HIGH_FREQUENCY);
+ if (DEBUG) Slog.d(TAG, "Received delayed message. Log rail data high frequency");
+ logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_HIGH_FREQUENCY);
}
};
@@ -50,7 +62,8 @@
mHandler = mContext.getMainThreadHandler();
if (triggerEnabled) {
- mLogData.run();
+ mLogDataLowFrequency.run();
+ mLogDataHighFrequency.run();
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
index 84b690f..49ee565 100644
--- a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.hardware.power.stats.Channel;
import android.hardware.power.stats.EnergyConsumer;
+import android.hardware.power.stats.EnergyConsumerAttribution;
import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyMeasurement;
import android.hardware.power.stats.PowerEntity;
@@ -73,6 +74,7 @@
private static final String ENERGY_CONSUMER_NAME = "energyconsumer";
private static final int ENERGY_METER_COUNT = 8;
private static final int ENERGY_CONSUMER_COUNT = 2;
+ private static final int ENERGY_CONSUMER_ATTRIBUTION_COUNT = 5;
private static final int POWER_ENTITY_COUNT = 3;
private static final int STATE_INFO_COUNT = 5;
private static final int STATE_RESIDENCY_COUNT = 4;
@@ -204,6 +206,13 @@
energyConsumedList[i].id = i;
energyConsumedList[i].timestampMs = i;
energyConsumedList[i].energyUWs = i;
+ energyConsumedList[i].attribution =
+ new EnergyConsumerAttribution[ENERGY_CONSUMER_ATTRIBUTION_COUNT];
+ for (int j = 0; j < energyConsumedList[i].attribution.length; j++) {
+ energyConsumedList[i].attribution[j] = new EnergyConsumerAttribution();
+ energyConsumedList[i].attribution[j].uid = j;
+ energyConsumedList[i].attribution[j].energyUWs = j;
+ }
}
return energyConsumedList;
}
@@ -250,7 +259,7 @@
mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
// Write data to on-device storage.
- mTimerTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_TIMER);
+ mTimerTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_HIGH_FREQUENCY);
// The above call puts a message on a handler. Wait for
// it to be processed.
@@ -293,7 +302,7 @@
mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
// Write data to on-device storage.
- mTimerTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_TIMER);
+ mTimerTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_LOW_FREQUENCY);
// The above call puts a message on a handler. Wait for
// it to be processed.
@@ -324,6 +333,12 @@
assertTrue(pssProto.energyConsumerResult[i].id == i);
assertTrue(pssProto.energyConsumerResult[i].timestampMs == i);
assertTrue(pssProto.energyConsumerResult[i].energyUws == i);
+ assertTrue(pssProto.energyConsumerResult[i].attribution.length
+ == ENERGY_CONSUMER_ATTRIBUTION_COUNT);
+ for (int j = 0; j < pssProto.energyConsumerResult[i].attribution.length; j++) {
+ assertTrue(pssProto.energyConsumerResult[i].attribution[j].uid == j);
+ assertTrue(pssProto.energyConsumerResult[i].attribution[j].energyUws == j);
+ }
}
}
diff --git a/tools/powerstats/PowerStatsServiceProtoParser.java b/tools/powerstats/PowerStatsServiceProtoParser.java
index 2140954..04f9bf2 100644
--- a/tools/powerstats/PowerStatsServiceProtoParser.java
+++ b/tools/powerstats/PowerStatsServiceProtoParser.java
@@ -86,6 +86,12 @@
csvRow += energyConsumerResult.getId() + ","
+ energyConsumerResult.getTimestampMs() + ","
+ energyConsumerResult.getEnergyUws() + ",";
+ for (int k = 0; k < energyConsumerResult.getAttributionCount(); k++) {
+ final EnergyConsumerAttributionProto energyConsumerAttribution =
+ energyConsumerResult.getAttribution(k);
+ csvRow += energyConsumerAttribution.getUid() + ","
+ + energyConsumerAttribution.getEnergyUws() + ",";
+ }
}
System.out.println(csvRow);
}