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

Commit 38175436 authored by Dmitri Plotnikov's avatar Dmitri Plotnikov
Browse files

Add feature flag for PowerMonitor API

Bug: 273308894
Test: atest FrameworksServicesTests:PowerStatsServiceTest
Change-Id: I1b027c2f24cb6aeeba7e790fc279fc4d69d33ef8
parent 77491b99
Loading
Loading
Loading
Loading
+49 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.hardware.power.stats.StateResidencyResult;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.IPowerStatsService;
@@ -38,6 +39,8 @@ import android.os.PowerMonitorReadings;
import android.os.ResultReceiver;
import android.os.UserHandle;
import android.power.PowerStatsInternal;
import android.provider.DeviceConfig;
import android.provider.DeviceConfigInterface;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
@@ -56,6 +59,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;

/**
 * This class provides a system service that estimates system power usage
@@ -76,8 +80,12 @@ public class PowerStatsService extends SystemService {
    private static final String RESIDENCY_CACHE_FILENAME = "residencyCache";
    private static final long MAX_POWER_MONITOR_AGE_MILLIS = 30_000;

    static final String KEY_POWER_MONITOR_API_ENABLED = "power_monitor_api_enabled";

    private final Injector mInjector;
    private final Clock mClock;
    private final DeviceConfigInterface mDeviceConfig;
    private final DeviceConfigListener mDeviceConfigListener = new DeviceConfigListener();
    private File mDataStoragePath;

    private Context mContext;
@@ -177,6 +185,10 @@ public class PowerStatsService extends SystemService {
                PowerStatsInternal powerStatsInternal) {
            return new StatsPullAtomCallbackImpl(context, powerStatsInternal);
        }

        DeviceConfigInterface getDeviceConfig() {
            return DeviceConfigInterface.REAL;
        }
    }

    private final IBinder mService = new IPowerStatsService.Stub() {
@@ -223,6 +235,20 @@ public class PowerStatsService extends SystemService {
        }
    };

    private class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener {
        public Executor mExecutor = new HandlerExecutor(getHandler());

        void startListening() {
            mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_BATTERY_STATS,
                    mExecutor, this);
        }

        @Override
        public void onPropertiesChanged(DeviceConfig.Properties properties) {
            refreshFlags();
        }
    }

    @Override
    public void onBootPhase(int phase) {
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
@@ -243,6 +269,8 @@ public class PowerStatsService extends SystemService {

    private void onSystemServicesReady() {
        mPullAtomCallback = mInjector.createStatsPullerImpl(mContext, mPowerStatsInternal);
        mDeviceConfigListener.startListening();
        refreshFlags();
    }

    @VisibleForTesting
@@ -330,6 +358,12 @@ public class PowerStatsService extends SystemService {
        mContext = context;
        mInjector = injector;
        mClock = injector.getClock();
        mDeviceConfig = injector.getDeviceConfig();
    }

    void refreshFlags() {
        setPowerMonitorApiEnabled(mDeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BATTERY_STATS,
                KEY_POWER_MONITOR_API_ENABLED, true));
    }

    private final class LocalService extends PowerStatsInternal {
@@ -466,9 +500,18 @@ public class PowerStatsService extends SystemService {
        }
    }

    private boolean mPowerMonitorApiEnabled = true;
    private volatile PowerMonitor[] mPowerMonitors;
    private volatile PowerMonitorState[] mPowerMonitorStates;

    private void setPowerMonitorApiEnabled(boolean powerMonitorApiEnabled) {
        if (powerMonitorApiEnabled != mPowerMonitorApiEnabled) {
            mPowerMonitorApiEnabled = powerMonitorApiEnabled;
            mPowerMonitors = null;
            mPowerMonitorStates = null;
        }
    }

    private void ensurePowerMonitors() {
        if (mPowerMonitors != null) {
            return;
@@ -479,6 +522,12 @@ public class PowerStatsService extends SystemService {
                return;
            }

            if (!mPowerMonitorApiEnabled) {
                mPowerMonitors = new PowerMonitor[0];
                mPowerMonitorStates = new PowerMonitorState[0];
                return;
            }

            List<PowerMonitor> monitors = new ArrayList<>();
            List<PowerMonitorState> states = new ArrayList<>();

+40 −2
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@ import android.os.IPowerStatsService;
import android.os.Looper;
import android.os.PowerMonitor;
import android.os.ResultReceiver;
import android.provider.DeviceConfig;
import android.provider.DeviceConfigInterface;

import androidx.test.InstrumentationRegistry;

@@ -53,6 +55,7 @@ import com.android.server.powerstats.nano.PowerStatsServiceResidencyProto;
import com.android.server.powerstats.nano.StateProto;
import com.android.server.powerstats.nano.StateResidencyProto;
import com.android.server.powerstats.nano.StateResidencyResultProto;
import com.android.server.testutils.FakeDeviceConfigInterface;

import org.junit.Before;
import org.junit.Test;
@@ -105,6 +108,7 @@ public class PowerStatsServiceTest {
    private BatteryTrigger mBatteryTrigger;
    private PowerStatsLogger mPowerStatsLogger;
    private MockClock mMockClock = new MockClock();
    private DeviceConfigInterface mMockDeviceConfig = new FakeDeviceConfigInterface();

    private class MockClock extends Clock {
        public long realtime;
@@ -197,6 +201,10 @@ public class PowerStatsServiceTest {
                    false /* trigger enabled */);
            return mTimerTrigger;
        }

        DeviceConfigInterface getDeviceConfig() {
            return mMockDeviceConfig;
        }
    };

    public static final class TestPowerStatsHALWrapper implements IPowerStatsHALWrapper {
@@ -1073,6 +1081,7 @@ public class PowerStatsServiceTest {
    }

    private static class GetPowerMonitorsResult extends ResultReceiver {
        public int resultCode;
        public long[] energyUws;
        public long[] timestamps;

@@ -1082,10 +1091,13 @@ public class PowerStatsServiceTest {

        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            this.resultCode = resultCode;
            if (resultData != null) {
                energyUws = resultData.getLongArray(IPowerStatsService.KEY_ENERGY);
                timestamps = resultData.getLongArray(IPowerStatsService.KEY_TIMESTAMPS);
            }
        }
    }

    @Test
    public void getPowerMonitors() {
@@ -1151,4 +1163,30 @@ public class PowerStatsServiceTest {
        assertThat(result.energyUws).isEqualTo(new long[]{300, 400});
        assertThat(result.timestamps).isEqualTo(new long[]{600_301, 600_401});
    }

    @Test
    public void featureFlag() {
        mMockDeviceConfig.setProperty(DeviceConfig.NAMESPACE_BATTERY_STATS,
                PowerStatsService.KEY_POWER_MONITOR_API_ENABLED, "false", false);

        mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);

        GetSupportedPowerMonitorsResult supportedPowerMonitorsResult =
                new GetSupportedPowerMonitorsResult();
        mService.getSupportedPowerMonitorsImpl(supportedPowerMonitorsResult);
        assertThat(supportedPowerMonitorsResult.powerMonitors).isNotNull();
        assertThat(supportedPowerMonitorsResult.powerMonitors).isEmpty();

        GetPowerMonitorsResult getPowerMonitorsResult = new GetPowerMonitorsResult();
        mService.getPowerMonitorReadingsImpl(new int[]{0}, getPowerMonitorsResult);
        assertThat(getPowerMonitorsResult.resultCode).isEqualTo(
                IPowerStatsService.RESULT_UNSUPPORTED_POWER_MONITOR);

        mMockDeviceConfig.setProperty(DeviceConfig.NAMESPACE_BATTERY_STATS,
                PowerStatsService.KEY_POWER_MONITOR_API_ENABLED, "true", false);
        supportedPowerMonitorsResult = new GetSupportedPowerMonitorsResult();
        mService.getSupportedPowerMonitorsImpl(supportedPowerMonitorsResult);
        assertThat(Arrays.stream(supportedPowerMonitorsResult.powerMonitors)
                .map(pm -> pm.name).toList()).contains("energyconsumer0");
    }
}