Loading core/proto/android/os/incident.proto +5 −0 Original line number Diff line number Diff line Loading @@ -521,6 +521,11 @@ message IncidentProto { (section).args = "power_stats --proto model" ]; optional com.android.server.powerstats.PowerStatsServiceResidencyProto powerstats_residency = 3056 [ (section).type = SECTION_DUMPSYS, (section).args = "power_stats --proto residency" ]; // Dumps in text format (on userdebug and eng builds only): 4000 ~ 4999 optional android.util.TextDumpProto textdump_wifi = 4000 [ (section).type = SECTION_TEXT_DUMPSYS, Loading core/proto/android/server/powerstatsservice.proto +103 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,16 @@ message IncidentReportModelProto { optional PowerStatsServiceModelProto incident_report = 3055; } /** * IncidentReportResidencyProto is used only in the parsing tool located * in frameworks/base/tools which is used to parse this data out of * incident reports. */ message IncidentReportResidencyProto { /** Section number matches that in incident.proto */ optional PowerStatsServiceResidencyProto incident_report = 3056; } /** * EnergyConsumer (model) data is exposed by the PowerStats HAL. This data * represents modeled energy consumption estimates and is provided per Loading @@ -62,6 +72,99 @@ message PowerStatsServiceMeterProto { repeated EnergyMeasurementProto energy_measurement = 2; } /** * A PowerEntity is defined as a platform subsystem, peripheral, or power domain * that impacts the total device power consumption. PowerEntityInfo is * information related to each power entity. Each PowerEntity may reside in one * of multiple states. It may also transition from one state to another. * StateResidency is defined as an accumulation of time that a PowerEntity * resided in each of its possible states, the number of times that each state * was entered, and a timestamp corresponding to the last time that state was * entered. */ message PowerStatsServiceResidencyProto { repeated PowerEntityInfoProto power_entity_info = 1; repeated StateResidencyResultProto state_residency_result = 2; } /** * Information about the possible states for a particular PowerEntity. */ message StateInfoProto { /** * Unique (for a given PowerEntityInfo) ID of this StateInfo */ optional int32 state_id = 1; /** * Unique (for a given PowerEntityInfo) name of the state. Vendor/device specific. * Opaque to framework */ optional string state_name = 2; } /** * A PowerEntity is defined as a platform subsystem, peripheral, or power domain * that impacts the total device power consumption. PowerEntityInfo is * information about a PowerEntity. It includes an array of information about * each possible state of the PowerEntity. */ message PowerEntityInfoProto { /** * Unique ID of this PowerEntityInfo */ optional int32 power_entity_id = 1; /** * Unique name of the PowerEntity. Vendor/device specific. Opaque to framework */ optional string power_entity_name = 2; /** * List of states that the PowerEntity may reside in */ repeated StateInfoProto states = 3; } /** * StateResidency is defined as an accumulation of time that a PowerEntity * resided in each of its possible states, the number of times that each state * was entered, and a timestamp corresponding to the last time that state was * entered. Data is accumulated starting at device boot. */ message StateResidencyProto { /** * ID of the state associated with this residency */ optional int32 state_id = 1; /** * Total time in milliseconds that the corresponding PowerEntity resided * in this state since boot */ optional int64 total_time_in_state_ms = 2; /** * Total number of times that the state was entered since boot */ optional int64 total_state_entry_count = 3; /** * Last time this state was entered. Time in milliseconds since boot */ optional int64 last_entry_timestamp_ms = 4; } /** * A StateResidencyResult is an array of StateResidencies for a particular * PowerEntity. The StateResidencyResult can be matched to its corresponding * PowerEntityInfo through the power_entity_id field. */ message StateResidencyResultProto { /** * ID of the PowerEntity associated with this result */ optional int32 power_entity_id = 1; /** * Residency for each state in the PowerEntity's state space */ repeated StateResidencyProto state_residency_data = 2; } /** * Energy consumer ID: * A list of default subsystems for which energy consumption estimates Loading services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java +1 −1 Original line number Diff line number Diff line Loading @@ -218,7 +218,7 @@ public class PowerStatsDataStorage { * array and written to on-device storage. */ public void write(byte[] data) { if (data.length > 0) { if (data != null && data.length > 0) { mLock.lock(); long currentTimeMillis = System.currentTimeMillis(); Loading services/core/java/com/android/server/powerstats/PowerStatsLogger.java +59 −3 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import android.content.Context; import android.hardware.power.stats.ChannelInfo; import android.hardware.power.stats.EnergyConsumerResult; import android.hardware.power.stats.EnergyMeasurement; import android.hardware.power.stats.PowerEntityInfo; import android.hardware.power.stats.StateResidencyResult; import android.os.Handler; import android.os.Looper; import android.os.Message; Loading @@ -32,6 +34,8 @@ import com.android.server.powerstats.ProtoStreamUtils.ChannelInfoUtils; import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerIdUtils; import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerResultUtils; import com.android.server.powerstats.ProtoStreamUtils.EnergyMeasurementUtils; import com.android.server.powerstats.ProtoStreamUtils.PowerEntityInfoUtils; import com.android.server.powerstats.ProtoStreamUtils.StateResidencyResultUtils; import java.io.ByteArrayInputStream; import java.io.File; Loading @@ -42,8 +46,8 @@ import java.io.IOException; * PowerStatsLogger is responsible for logging model and meter energy data to on-device storage. * Messages are sent to its message handler to request that energy data be logged, at which time it * queries the PowerStats HAL and logs the data to on-device storage. The on-device storage is * dumped to file by calling writeModelDataToFile or writeMeterDataToFile with a file descriptor * that points to the output file. * dumped to file by calling writeModelDataToFile, writeMeterDataToFile, or writeResidencyDataToFile * with a file descriptor that points to the output file. */ public final class PowerStatsLogger extends Handler { private static final String TAG = PowerStatsLogger.class.getSimpleName(); Loading @@ -52,6 +56,7 @@ public final class PowerStatsLogger extends Handler { private final PowerStatsDataStorage mPowerStatsMeterStorage; private final PowerStatsDataStorage mPowerStatsModelStorage; private final PowerStatsDataStorage mPowerStatsResidencyStorage; private final IPowerStatsHALWrapper mPowerStatsHALWrapper; @Override Loading @@ -73,6 +78,13 @@ public final class PowerStatsLogger extends Handler { mPowerStatsModelStorage.write( EnergyConsumerResultUtils.getProtoBytes(energyConsumerResults)); if (DEBUG) EnergyConsumerResultUtils.print(energyConsumerResults); // Log state residency data. StateResidencyResult[] stateResidencyResults = mPowerStatsHALWrapper.getStateResidency(new int[0]); mPowerStatsResidencyStorage.write( StateResidencyResultUtils.getProtoBytes(stateResidencyResults)); if (DEBUG) StateResidencyResultUtils.print(stateResidencyResults); break; } } Loading Loading @@ -159,13 +171,57 @@ public final class PowerStatsLogger extends Handler { pos.flush(); } /** * Writes residency data stored in PowerStatsDataStorage to a file descriptor. * * @param fd FileDescriptor where residency data stored in PowerStatsDataStorage is written. * Data is written in protobuf format as defined by powerstatsservice.proto. */ public void writeResidencyDataToFile(FileDescriptor fd) { if (DEBUG) Slog.d(TAG, "Writing residency data to file"); final ProtoOutputStream pos = new ProtoOutputStream(fd); try { PowerEntityInfo[] powerEntityInfo = mPowerStatsHALWrapper.getPowerEntityInfo(); PowerEntityInfoUtils.packProtoMessage(powerEntityInfo, pos); if (DEBUG) PowerEntityInfoUtils.print(powerEntityInfo); mPowerStatsResidencyStorage.read(new PowerStatsDataStorage.DataElementReadCallback() { @Override public void onReadDataElement(byte[] data) { try { final ProtoInputStream pis = new ProtoInputStream(new ByteArrayInputStream(data)); // TODO(b/166535853): ProtoOutputStream doesn't provide a method to write // a byte array that already contains a serialized proto, so I have to // deserialize, then re-serialize. This is computationally inefficient. StateResidencyResult[] stateResidencyResult = StateResidencyResultUtils.unpackProtoMessage(data); StateResidencyResultUtils.packProtoMessage(stateResidencyResult, pos); if (DEBUG) StateResidencyResultUtils.print(stateResidencyResult); } catch (IOException e) { Slog.e(TAG, "Failed to write residency data to incident report."); } } }); } catch (IOException e) { Slog.e(TAG, "Failed to write residency data to incident report."); } pos.flush(); } public PowerStatsLogger(Context context, File dataStoragePath, String meterFilename, String modelFilename, IPowerStatsHALWrapper powerStatsHALWrapper) { String modelFilename, String residencyFilename, IPowerStatsHALWrapper powerStatsHALWrapper) { super(Looper.getMainLooper()); mPowerStatsHALWrapper = powerStatsHALWrapper; mPowerStatsMeterStorage = new PowerStatsDataStorage(context, dataStoragePath, meterFilename); mPowerStatsModelStorage = new PowerStatsDataStorage(context, dataStoragePath, modelFilename); mPowerStatsResidencyStorage = new PowerStatsDataStorage(context, dataStoragePath, residencyFilename); } } services/core/java/com/android/server/powerstats/PowerStatsService.java +12 −3 Original line number Diff line number Diff line Loading @@ -49,6 +49,8 @@ public class PowerStatsService extends SystemService { private static final int DATA_STORAGE_VERSION = 0; private static final String METER_FILENAME = "log.powerstats.meter." + DATA_STORAGE_VERSION; private static final String MODEL_FILENAME = "log.powerstats.model." + DATA_STORAGE_VERSION; private static final String RESIDENCY_FILENAME = "log.powerstats.residency." + DATA_STORAGE_VERSION; private final Injector mInjector; Loading Loading @@ -76,15 +78,19 @@ public class PowerStatsService extends SystemService { return MODEL_FILENAME; } String createResidencyFilename() { return RESIDENCY_FILENAME; } IPowerStatsHALWrapper createPowerStatsHALWrapperImpl() { return PowerStatsHALWrapper.getPowerStatsHalImpl(); } PowerStatsLogger createPowerStatsLogger(Context context, File dataStoragePath, String meterFilename, String modelFilename, String meterFilename, String modelFilename, String residencyFilename, IPowerStatsHALWrapper powerStatsHALWrapper) { return new PowerStatsLogger(context, dataStoragePath, meterFilename, modelFilename, powerStatsHALWrapper); modelFilename, residencyFilename, powerStatsHALWrapper); } BatteryTrigger createBatteryTrigger(Context context, PowerStatsLogger powerStatsLogger) { Loading @@ -109,6 +115,8 @@ public class PowerStatsService extends SystemService { mPowerStatsLogger.writeModelDataToFile(fd); } else if ("meter".equals(args[1])) { mPowerStatsLogger.writeMeterDataToFile(fd); } else if ("residency".equals(args[1])) { mPowerStatsLogger.writeResidencyDataToFile(fd); } } else if (args.length == 0) { pw.println("PowerStatsService dumpsys: available PowerEntityInfos"); Loading Loading @@ -148,7 +156,8 @@ public class PowerStatsService extends SystemService { // Only start logger and triggers if initialization is successful. mPowerStatsLogger = mInjector.createPowerStatsLogger(mContext, mInjector.createDataStoragePath(), mInjector.createMeterFilename(), mInjector.createModelFilename(), mPowerStatsHALWrapper); mInjector.createModelFilename(), mInjector.createResidencyFilename(), mPowerStatsHALWrapper); mBatteryTrigger = mInjector.createBatteryTrigger(mContext, mPowerStatsLogger); mTimerTrigger = mInjector.createTimerTrigger(mContext, mPowerStatsLogger); } else { Loading Loading
core/proto/android/os/incident.proto +5 −0 Original line number Diff line number Diff line Loading @@ -521,6 +521,11 @@ message IncidentProto { (section).args = "power_stats --proto model" ]; optional com.android.server.powerstats.PowerStatsServiceResidencyProto powerstats_residency = 3056 [ (section).type = SECTION_DUMPSYS, (section).args = "power_stats --proto residency" ]; // Dumps in text format (on userdebug and eng builds only): 4000 ~ 4999 optional android.util.TextDumpProto textdump_wifi = 4000 [ (section).type = SECTION_TEXT_DUMPSYS, Loading
core/proto/android/server/powerstatsservice.proto +103 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,16 @@ message IncidentReportModelProto { optional PowerStatsServiceModelProto incident_report = 3055; } /** * IncidentReportResidencyProto is used only in the parsing tool located * in frameworks/base/tools which is used to parse this data out of * incident reports. */ message IncidentReportResidencyProto { /** Section number matches that in incident.proto */ optional PowerStatsServiceResidencyProto incident_report = 3056; } /** * EnergyConsumer (model) data is exposed by the PowerStats HAL. This data * represents modeled energy consumption estimates and is provided per Loading @@ -62,6 +72,99 @@ message PowerStatsServiceMeterProto { repeated EnergyMeasurementProto energy_measurement = 2; } /** * A PowerEntity is defined as a platform subsystem, peripheral, or power domain * that impacts the total device power consumption. PowerEntityInfo is * information related to each power entity. Each PowerEntity may reside in one * of multiple states. It may also transition from one state to another. * StateResidency is defined as an accumulation of time that a PowerEntity * resided in each of its possible states, the number of times that each state * was entered, and a timestamp corresponding to the last time that state was * entered. */ message PowerStatsServiceResidencyProto { repeated PowerEntityInfoProto power_entity_info = 1; repeated StateResidencyResultProto state_residency_result = 2; } /** * Information about the possible states for a particular PowerEntity. */ message StateInfoProto { /** * Unique (for a given PowerEntityInfo) ID of this StateInfo */ optional int32 state_id = 1; /** * Unique (for a given PowerEntityInfo) name of the state. Vendor/device specific. * Opaque to framework */ optional string state_name = 2; } /** * A PowerEntity is defined as a platform subsystem, peripheral, or power domain * that impacts the total device power consumption. PowerEntityInfo is * information about a PowerEntity. It includes an array of information about * each possible state of the PowerEntity. */ message PowerEntityInfoProto { /** * Unique ID of this PowerEntityInfo */ optional int32 power_entity_id = 1; /** * Unique name of the PowerEntity. Vendor/device specific. Opaque to framework */ optional string power_entity_name = 2; /** * List of states that the PowerEntity may reside in */ repeated StateInfoProto states = 3; } /** * StateResidency is defined as an accumulation of time that a PowerEntity * resided in each of its possible states, the number of times that each state * was entered, and a timestamp corresponding to the last time that state was * entered. Data is accumulated starting at device boot. */ message StateResidencyProto { /** * ID of the state associated with this residency */ optional int32 state_id = 1; /** * Total time in milliseconds that the corresponding PowerEntity resided * in this state since boot */ optional int64 total_time_in_state_ms = 2; /** * Total number of times that the state was entered since boot */ optional int64 total_state_entry_count = 3; /** * Last time this state was entered. Time in milliseconds since boot */ optional int64 last_entry_timestamp_ms = 4; } /** * A StateResidencyResult is an array of StateResidencies for a particular * PowerEntity. The StateResidencyResult can be matched to its corresponding * PowerEntityInfo through the power_entity_id field. */ message StateResidencyResultProto { /** * ID of the PowerEntity associated with this result */ optional int32 power_entity_id = 1; /** * Residency for each state in the PowerEntity's state space */ repeated StateResidencyProto state_residency_data = 2; } /** * Energy consumer ID: * A list of default subsystems for which energy consumption estimates Loading
services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java +1 −1 Original line number Diff line number Diff line Loading @@ -218,7 +218,7 @@ public class PowerStatsDataStorage { * array and written to on-device storage. */ public void write(byte[] data) { if (data.length > 0) { if (data != null && data.length > 0) { mLock.lock(); long currentTimeMillis = System.currentTimeMillis(); Loading
services/core/java/com/android/server/powerstats/PowerStatsLogger.java +59 −3 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import android.content.Context; import android.hardware.power.stats.ChannelInfo; import android.hardware.power.stats.EnergyConsumerResult; import android.hardware.power.stats.EnergyMeasurement; import android.hardware.power.stats.PowerEntityInfo; import android.hardware.power.stats.StateResidencyResult; import android.os.Handler; import android.os.Looper; import android.os.Message; Loading @@ -32,6 +34,8 @@ import com.android.server.powerstats.ProtoStreamUtils.ChannelInfoUtils; import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerIdUtils; import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerResultUtils; import com.android.server.powerstats.ProtoStreamUtils.EnergyMeasurementUtils; import com.android.server.powerstats.ProtoStreamUtils.PowerEntityInfoUtils; import com.android.server.powerstats.ProtoStreamUtils.StateResidencyResultUtils; import java.io.ByteArrayInputStream; import java.io.File; Loading @@ -42,8 +46,8 @@ import java.io.IOException; * PowerStatsLogger is responsible for logging model and meter energy data to on-device storage. * Messages are sent to its message handler to request that energy data be logged, at which time it * queries the PowerStats HAL and logs the data to on-device storage. The on-device storage is * dumped to file by calling writeModelDataToFile or writeMeterDataToFile with a file descriptor * that points to the output file. * dumped to file by calling writeModelDataToFile, writeMeterDataToFile, or writeResidencyDataToFile * with a file descriptor that points to the output file. */ public final class PowerStatsLogger extends Handler { private static final String TAG = PowerStatsLogger.class.getSimpleName(); Loading @@ -52,6 +56,7 @@ public final class PowerStatsLogger extends Handler { private final PowerStatsDataStorage mPowerStatsMeterStorage; private final PowerStatsDataStorage mPowerStatsModelStorage; private final PowerStatsDataStorage mPowerStatsResidencyStorage; private final IPowerStatsHALWrapper mPowerStatsHALWrapper; @Override Loading @@ -73,6 +78,13 @@ public final class PowerStatsLogger extends Handler { mPowerStatsModelStorage.write( EnergyConsumerResultUtils.getProtoBytes(energyConsumerResults)); if (DEBUG) EnergyConsumerResultUtils.print(energyConsumerResults); // Log state residency data. StateResidencyResult[] stateResidencyResults = mPowerStatsHALWrapper.getStateResidency(new int[0]); mPowerStatsResidencyStorage.write( StateResidencyResultUtils.getProtoBytes(stateResidencyResults)); if (DEBUG) StateResidencyResultUtils.print(stateResidencyResults); break; } } Loading Loading @@ -159,13 +171,57 @@ public final class PowerStatsLogger extends Handler { pos.flush(); } /** * Writes residency data stored in PowerStatsDataStorage to a file descriptor. * * @param fd FileDescriptor where residency data stored in PowerStatsDataStorage is written. * Data is written in protobuf format as defined by powerstatsservice.proto. */ public void writeResidencyDataToFile(FileDescriptor fd) { if (DEBUG) Slog.d(TAG, "Writing residency data to file"); final ProtoOutputStream pos = new ProtoOutputStream(fd); try { PowerEntityInfo[] powerEntityInfo = mPowerStatsHALWrapper.getPowerEntityInfo(); PowerEntityInfoUtils.packProtoMessage(powerEntityInfo, pos); if (DEBUG) PowerEntityInfoUtils.print(powerEntityInfo); mPowerStatsResidencyStorage.read(new PowerStatsDataStorage.DataElementReadCallback() { @Override public void onReadDataElement(byte[] data) { try { final ProtoInputStream pis = new ProtoInputStream(new ByteArrayInputStream(data)); // TODO(b/166535853): ProtoOutputStream doesn't provide a method to write // a byte array that already contains a serialized proto, so I have to // deserialize, then re-serialize. This is computationally inefficient. StateResidencyResult[] stateResidencyResult = StateResidencyResultUtils.unpackProtoMessage(data); StateResidencyResultUtils.packProtoMessage(stateResidencyResult, pos); if (DEBUG) StateResidencyResultUtils.print(stateResidencyResult); } catch (IOException e) { Slog.e(TAG, "Failed to write residency data to incident report."); } } }); } catch (IOException e) { Slog.e(TAG, "Failed to write residency data to incident report."); } pos.flush(); } public PowerStatsLogger(Context context, File dataStoragePath, String meterFilename, String modelFilename, IPowerStatsHALWrapper powerStatsHALWrapper) { String modelFilename, String residencyFilename, IPowerStatsHALWrapper powerStatsHALWrapper) { super(Looper.getMainLooper()); mPowerStatsHALWrapper = powerStatsHALWrapper; mPowerStatsMeterStorage = new PowerStatsDataStorage(context, dataStoragePath, meterFilename); mPowerStatsModelStorage = new PowerStatsDataStorage(context, dataStoragePath, modelFilename); mPowerStatsResidencyStorage = new PowerStatsDataStorage(context, dataStoragePath, residencyFilename); } }
services/core/java/com/android/server/powerstats/PowerStatsService.java +12 −3 Original line number Diff line number Diff line Loading @@ -49,6 +49,8 @@ public class PowerStatsService extends SystemService { private static final int DATA_STORAGE_VERSION = 0; private static final String METER_FILENAME = "log.powerstats.meter." + DATA_STORAGE_VERSION; private static final String MODEL_FILENAME = "log.powerstats.model." + DATA_STORAGE_VERSION; private static final String RESIDENCY_FILENAME = "log.powerstats.residency." + DATA_STORAGE_VERSION; private final Injector mInjector; Loading Loading @@ -76,15 +78,19 @@ public class PowerStatsService extends SystemService { return MODEL_FILENAME; } String createResidencyFilename() { return RESIDENCY_FILENAME; } IPowerStatsHALWrapper createPowerStatsHALWrapperImpl() { return PowerStatsHALWrapper.getPowerStatsHalImpl(); } PowerStatsLogger createPowerStatsLogger(Context context, File dataStoragePath, String meterFilename, String modelFilename, String meterFilename, String modelFilename, String residencyFilename, IPowerStatsHALWrapper powerStatsHALWrapper) { return new PowerStatsLogger(context, dataStoragePath, meterFilename, modelFilename, powerStatsHALWrapper); modelFilename, residencyFilename, powerStatsHALWrapper); } BatteryTrigger createBatteryTrigger(Context context, PowerStatsLogger powerStatsLogger) { Loading @@ -109,6 +115,8 @@ public class PowerStatsService extends SystemService { mPowerStatsLogger.writeModelDataToFile(fd); } else if ("meter".equals(args[1])) { mPowerStatsLogger.writeMeterDataToFile(fd); } else if ("residency".equals(args[1])) { mPowerStatsLogger.writeResidencyDataToFile(fd); } } else if (args.length == 0) { pw.println("PowerStatsService dumpsys: available PowerEntityInfos"); Loading Loading @@ -148,7 +156,8 @@ public class PowerStatsService extends SystemService { // Only start logger and triggers if initialization is successful. mPowerStatsLogger = mInjector.createPowerStatsLogger(mContext, mInjector.createDataStoragePath(), mInjector.createMeterFilename(), mInjector.createModelFilename(), mPowerStatsHALWrapper); mInjector.createModelFilename(), mInjector.createResidencyFilename(), mPowerStatsHALWrapper); mBatteryTrigger = mInjector.createBatteryTrigger(mContext, mPowerStatsLogger); mTimerTrigger = mInjector.createTimerTrigger(mContext, mPowerStatsLogger); } else { Loading