Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a3724f98 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add state residency logging to power stats"

parents b929fb19 723784a0
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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,
+103 −0
Original line number Diff line number Diff line
@@ -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
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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();
+59 −3
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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();
@@ -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
@@ -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;
        }
    }
@@ -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);
    }
}
+12 −3
Original line number Diff line number Diff line
@@ -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;

@@ -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) {
@@ -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");
@@ -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