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

Commit d42057fc authored by Benjamin Schwartz's avatar Benjamin Schwartz Committed by Android (Google) Code Review
Browse files

Merge "BatteryStats: Pull subsystem stats from Power Stats Service" into sc-dev

parents 1d55f0d4 3bdc8385
Loading
Loading
Loading
Loading
+1 −13
Original line number Diff line number Diff line
@@ -1556,8 +1556,7 @@ public abstract class BatteryStats implements Parcelable {
        public int statSoftIrqTime;
        public int statIdlTime;

        // Platform-level low power state stats
        public String statPlatformIdleState;
        // Low power state stats
        public String statSubsystemPowerState;

        public HistoryStepDetails() {
@@ -1589,7 +1588,6 @@ public abstract class BatteryStats implements Parcelable {
            out.writeInt(statIrqTime);
            out.writeInt(statSoftIrqTime);
            out.writeInt(statIdlTime);
            out.writeString(statPlatformIdleState);
            out.writeString(statSubsystemPowerState);
        }

@@ -1611,7 +1609,6 @@ public abstract class BatteryStats implements Parcelable {
            statIrqTime = in.readInt();
            statSoftIrqTime = in.readInt();
            statIdlTime = in.readInt();
            statPlatformIdleState = in.readString();
            statSubsystemPowerState = in.readString();
        }
    }
@@ -6600,9 +6597,6 @@ public abstract class BatteryStats implements Parcelable {
                            item.append(sb);
                            item.append(")");
                        }
                        item.append(", PlatformIdleStat ");
                        item.append(rec.stepDetails.statPlatformIdleState);
                        item.append("\n");

                        item.append(", SubsystemPowerState ");
                        item.append(rec.stepDetails.statSubsystemPowerState);
@@ -6640,12 +6634,6 @@ public abstract class BatteryStats implements Parcelable {
                        item.append(',');
                        item.append(rec.stepDetails.statIdlTime);
                        item.append(',');
                        if (rec.stepDetails.statPlatformIdleState != null) {
                            item.append(rec.stepDetails.statPlatformIdleState);
                            if (rec.stepDetails.statSubsystemPowerState != null) {
                                item.append(',');
                            }
                        }

                        if (rec.stepDetails.statSubsystemPowerState != null) {
                            item.append(rec.stepDetails.statSubsystemPowerState);
+1 −7
Original line number Diff line number Diff line
@@ -173,7 +173,7 @@ public class BatteryStatsImpl extends BatteryStats {
    private static final int MAGIC = 0xBA757475; // 'BATSTATS'
    // Current on-disk Parcel version
    static final int VERSION = 191 + (USE_OLD_HISTORY ? 1000 : 0);
    static final int VERSION = 192 + (USE_OLD_HISTORY ? 1000 : 0);
    // The maximum number of names wakelocks we will keep track of
    // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -362,7 +362,6 @@ public class BatteryStatsImpl extends BatteryStats {
    public interface PlatformIdleStateCallback {
        public void fillLowPowerStats(RpmStats rpmStats);
        public String getPlatformLowPowerStats();
        public String getSubsystemLowPowerStats();
    }
@@ -3482,11 +3481,6 @@ public class BatteryStatsImpl extends BatteryStats {
        }
        if (computeStepDetails) {
            if (mPlatformIdleStateCallback != null) {
                mCurHistoryStepDetails.statPlatformIdleState =
                        mPlatformIdleStateCallback.getPlatformLowPowerStats();
                if (DEBUG) Slog.i(TAG, "WRITE PlatformIdleState:" +
                        mCurHistoryStepDetails.statPlatformIdleState);
                mCurHistoryStepDetails.statSubsystemPowerState =
                        mPlatformIdleStateCallback.getSubsystemLowPowerStats();
                if (DEBUG) Slog.i(TAG, "WRITE SubsystemPowerState:" +
+45 −0
Original line number Diff line number Diff line
@@ -18,8 +18,12 @@ package android.power;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.power.stats.Channel;
import android.hardware.power.stats.EnergyConsumer;
import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyMeasurement;
import android.hardware.power.stats.PowerEntity;
import android.hardware.power.stats.StateResidencyResult;

import java.util.concurrent.CompletableFuture;

@@ -51,4 +55,45 @@ public abstract class PowerStatsInternal {
    @NonNull
    public abstract CompletableFuture<EnergyConsumerResult[]> getEnergyConsumedAsync(
            int[] energyConsumerIds);

    /**
     * Returns the power entity info for all available {@link PowerEntity}
     *
     * @return List of available {@link PowerEntity}
     */
    public abstract PowerEntity[] getPowerEntityInfo();

    /**
     * Returns a CompletableFuture that will get a {@link StateResidencyResult} array for the
     * available requested power entities.
     *
     * @param powerEntityIds Array of {@link PowerEntity.id} for which state residency is being
     *                          requested.
     *
     * @return A Future containing a list of {@link StateResidencyResult} objects containing state
     *         residency results for all listed {@link PowerEntity.id}.
     */
    @NonNull
    public abstract CompletableFuture<StateResidencyResult[]> getStateResidencyAsync(
            int[] powerEntityIds);

    /**
     * Returns the channel info for all available {@link Channel}
     *
     * @return List of available {@link Channel}
     */
    public abstract Channel[] getEnergyMeterInfo();

    /**
     * Returns a CompletableFuture that will get a {@link EnergyMeasurement} array for the
     * available requested channels.
     *
     * @param channelIds Array of {@link Channel.id} for accumulated energy is being requested.
     *
     * @return A Future containing a list of {@link EnergyMeasurement} objects containing
     *         accumulated energy measurements for all listed {@link Channel.id}.
     */
    @NonNull
    public abstract CompletableFuture<EnergyMeasurement[]> readEnergyMeterAsync(
            int[] channelIds);
}
+98 −45
Original line number Diff line number Diff line
@@ -21,6 +21,10 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.hardware.power.stats.PowerEntity;
import android.hardware.power.stats.State;
import android.hardware.power.stats.StateResidency;
import android.hardware.power.stats.StateResidencyResult;
import android.net.INetworkManagementEventObserver;
import android.net.NetworkCapabilities;
import android.os.BatteryStats;
@@ -51,6 +55,7 @@ import android.os.connectivity.WifiBatteryStats;
import android.os.health.HealthStatsParceler;
import android.os.health.HealthStatsWriter;
import android.os.health.UidHealthStats;
import android.power.PowerStatsInternal;
import android.provider.Settings;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ModemActivityInfo;
@@ -87,10 +92,13 @@ import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * All information we are collecting about things that can happen that impact
@@ -112,23 +120,23 @@ public final class BatteryStatsService extends IBatteryStats.Stub
    private final BatteryExternalStatsWorker mWorker;
    private final BatteryUsageStatsProvider mBatteryUsageStatsProvider;

    private native void getLowPowerStats(RpmStats rpmStats);
    private native int getPlatformLowPowerStats(ByteBuffer outBuffer);
    private native int getSubsystemLowPowerStats(ByteBuffer outBuffer);
    private native void getRailEnergyPowerStats(RailStats railStats);
    private CharsetDecoder mDecoderStat = StandardCharsets.UTF_8
                    .newDecoder()
                    .onMalformedInput(CodingErrorAction.REPLACE)
                    .onUnmappableCharacter(CodingErrorAction.REPLACE)
                    .replaceWith("?");
    private ByteBuffer mUtf8BufferStat = ByteBuffer.allocateDirect(MAX_LOW_POWER_STATS_SIZE);
    private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE);
    private static final int MAX_LOW_POWER_STATS_SIZE = 4096;
    private static final int POWER_STATS_QUERY_TIMEOUT_MILLIS = 2000;

    private final HandlerThread mHandlerThread;
    private final Handler mHandler;
    private final Object mLock = new Object();

    private PowerStatsInternal mPowerStatsInternal = null;
    private Map<Integer, String> mEntityNames = new HashMap();
    private Map<Integer, Map<Integer, String>> mStateNames = new HashMap();

    @GuardedBy("mStats")
    private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
    @GuardedBy("mStats")
@@ -163,16 +171,57 @@ public final class BatteryStatsService extends IBatteryStats.Stub
                }
            };

    private void populatePowerEntityMaps() {
        if (mPowerStatsInternal == null) {
            // PowerStatsInternal unavailable, don't bother populating maps.
            mEntityNames = null;
            mStateNames = null;
            return;
        }

        PowerEntity[] entities = mPowerStatsInternal.getPowerEntityInfo();
        if (entities == null) {
            return;
        }

        for (int i = 0; i < entities.length; i++) {
            final PowerEntity entity = entities[i];
            Map<Integer, String> states = new HashMap();
            for (int j = 0; j < entity.states.length; j++) {
                final State state = entity.states[j];
                states.put(state.id, state.name);
            }

            mEntityNames.put(entity.id, entity.name);
            mStateNames.put(entity.id, states);
        }
    }

    /**
     * Replaces the information in the given rpmStats with up-to-date information.
     */
    @Override
    public void fillLowPowerStats(RpmStats rpmStats) {
        if (DBG) Slog.d(TAG, "begin getLowPowerStats");
        final StateResidencyResult[] results;
        try {
            getLowPowerStats(rpmStats);
        } finally {
            if (DBG) Slog.d(TAG, "end getLowPowerStats");
            results = mPowerStatsInternal.getStateResidencyAsync(new int[0])
                    .get(POWER_STATS_QUERY_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            Slog.e(TAG, "Failed to getStateResidencyAsync", e);
            return;
        }

        for (int i = 0; i < results.length; i++) {
            final StateResidencyResult result = results[i];
            RpmStats.PowerStateSubsystem subsystem =
                    rpmStats.getSubsystem(mEntityNames.get(result.id));

            for (int j = 0; j < result.stateResidencyData.length; j++) {
                final StateResidency stateResidency = result.stateResidencyData[j];
                subsystem.putState(mStateNames.get(result.id).get(stateResidency.id),
                        stateResidency.totalTimeInStateMs,
                        (int) stateResidency.totalStateEntryCount);
            }
        }
    }

@@ -187,47 +236,46 @@ public final class BatteryStatsService extends IBatteryStats.Stub
    }

    @Override
    public String getPlatformLowPowerStats() {
        if (DBG) Slog.d(TAG, "begin getPlatformLowPowerStats");
    public String getSubsystemLowPowerStats() {
        final StateResidencyResult[] results;
        try {
            mUtf8BufferStat.clear();
            mUtf16BufferStat.clear();
            mDecoderStat.reset();
            int bytesWritten = getPlatformLowPowerStats(mUtf8BufferStat);
            if (bytesWritten < 0) {
                return null;
            } else if (bytesWritten == 0) {
            results = mPowerStatsInternal.getStateResidencyAsync(new int[0])
                    .get(POWER_STATS_QUERY_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            Slog.e(TAG, "Failed to getStateResidencyAsync", e);
            return "Empty";
        }
            mUtf8BufferStat.limit(bytesWritten);
            mDecoderStat.decode(mUtf8BufferStat, mUtf16BufferStat, true);
            mUtf16BufferStat.flip();
            return mUtf16BufferStat.toString();
        } finally {
            if (DBG) Slog.d(TAG, "end getPlatformLowPowerStats");
        }

        if (results.length == 0) return "Empty";

        int charsLeft = MAX_LOW_POWER_STATS_SIZE;
        StringBuilder builder = new StringBuilder("SubsystemPowerState");
        for (int i = 0; i < results.length; i++) {
            final StateResidencyResult result = results[i];
            StringBuilder subsystemBuilder = new StringBuilder();
            subsystemBuilder.append(" subsystem_" + i);
            subsystemBuilder.append(" name=" + mEntityNames.get(result.id));

            for (int j = 0; j < result.stateResidencyData.length; j++) {
                final StateResidency stateResidency = result.stateResidencyData[j];
                subsystemBuilder.append(" state_" + j);
                subsystemBuilder.append(" name=" + mStateNames.get(result.id).get(
                        stateResidency.id));
                subsystemBuilder.append(" time=" + stateResidency.totalTimeInStateMs);
                subsystemBuilder.append(" count=" + stateResidency.totalStateEntryCount);
                subsystemBuilder.append(" last entry=" + stateResidency.lastEntryTimestampMs);
            }

    @Override
    public String getSubsystemLowPowerStats() {
        if (DBG) Slog.d(TAG, "begin getSubsystemLowPowerStats");
        try {
            mUtf8BufferStat.clear();
            mUtf16BufferStat.clear();
            mDecoderStat.reset();
            int bytesWritten = getSubsystemLowPowerStats(mUtf8BufferStat);
            if (bytesWritten < 0) {
                return null;
            } else if (bytesWritten == 0) {
                return "Empty";
            if (subsystemBuilder.length() <= charsLeft) {
                charsLeft -= subsystemBuilder.length();
                builder.append(subsystemBuilder);
            } else {
                Slog.e(TAG, "getSubsystemLowPowerStats: buffer not enough");
                break;
            }
            mUtf8BufferStat.limit(bytesWritten);
            mDecoderStat.decode(mUtf8BufferStat, mUtf16BufferStat, true);
            mUtf16BufferStat.flip();
            return mUtf16BufferStat.toString();
        } finally {
            if (DBG) Slog.d(TAG, "end getSubsystemLowPowerStats");
        }

        return builder.toString();
    }

    BatteryStatsService(Context context, File systemDir, Handler handler) {
@@ -274,6 +322,11 @@ public final class BatteryStatsService extends IBatteryStats.Stub
        } catch (RemoteException e) {
            Slog.e(TAG, "Could not register INetworkManagement event observer " + e);
        }
        mPowerStatsInternal = LocalServices.getService(PowerStatsInternal.class);
        if (mPowerStatsInternal != null) {
            populatePowerEntityMaps();
        }

        Watchdog.getInstance().addMonitor(this);
    }

+42 −0
Original line number Diff line number Diff line
@@ -21,7 +21,9 @@ import android.content.Context;
import android.hardware.power.stats.Channel;
import android.hardware.power.stats.EnergyConsumer;
import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyMeasurement;
import android.hardware.power.stats.PowerEntity;
import android.hardware.power.stats.StateResidencyResult;
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
@@ -245,10 +247,50 @@ public class PowerStatsService extends SystemService {
                            future, energyConsumerIds));
            return future;
        }

        @Override
        public PowerEntity[] getPowerEntityInfo() {
            return getPowerStatsHal().getPowerEntityInfo();
        }

        @Override
        public CompletableFuture<StateResidencyResult[]> getStateResidencyAsync(
                int[] powerEntityIds) {
            final CompletableFuture<StateResidencyResult[]> future = new CompletableFuture<>();
            mHandler.sendMessage(
                    PooledLambda.obtainMessage(PowerStatsService.this::getStateResidencyAsync,
                            future, powerEntityIds));
            return future;
        }

        @Override
        public Channel[] getEnergyMeterInfo() {
            return getPowerStatsHal().getEnergyMeterInfo();
        }

        @Override
        public CompletableFuture<EnergyMeasurement[]> readEnergyMeterAsync(
                int[] channelIds) {
            final CompletableFuture<EnergyMeasurement[]> future = new CompletableFuture<>();
            mHandler.sendMessage(
                    PooledLambda.obtainMessage(PowerStatsService.this::readEnergyMeterAsync,
                            future, channelIds));
            return future;
        }
    }

    private void getEnergyConsumedAsync(CompletableFuture<EnergyConsumerResult[]> future,
            int[] energyConsumerIds) {
        future.complete(getPowerStatsHal().getEnergyConsumed(energyConsumerIds));
    }

    private void getStateResidencyAsync(CompletableFuture<StateResidencyResult[]> future,
            int[] powerEntityIds) {
        future.complete(getPowerStatsHal().getStateResidency(powerEntityIds));
    }

    private void readEnergyMeterAsync(CompletableFuture<EnergyMeasurement[]> future,
            int[] channelIds) {
        future.complete(getPowerStatsHal().readEnergyMeters(channelIds));
    }
}
Loading