From 381754364732793b9a4f911a515dc44a59979058 Mon Sep 17 00:00:00 2001 From: Dmitri Plotnikov Date: Fri, 31 Mar 2023 11:37:08 -0700 Subject: [PATCH] Add feature flag for PowerMonitor API Bug: 273308894 Test: atest FrameworksServicesTests:PowerStatsServiceTest Change-Id: I1b027c2f24cb6aeeba7e790fc279fc4d69d33ef8 --- .../server/powerstats/PowerStatsService.java | 49 +++++++++++++++++++ .../powerstats/PowerStatsServiceTest.java | 42 +++++++++++++++- 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/powerstats/PowerStatsService.java b/services/core/java/com/android/server/powerstats/PowerStatsService.java index 994d36c97dcb6..6d4c5a7891903 100644 --- a/services/core/java/com/android/server/powerstats/PowerStatsService.java +++ b/services/core/java/com/android/server/powerstats/PowerStatsService.java @@ -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 monitors = new ArrayList<>(); List states = new ArrayList<>(); 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 e1da41b16cf4a..0034597a1d6aa 100644 --- a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java @@ -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,8 +1091,11 @@ public class PowerStatsServiceTest { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { - energyUws = resultData.getLongArray(IPowerStatsService.KEY_ENERGY); - timestamps = resultData.getLongArray(IPowerStatsService.KEY_TIMESTAMPS); + this.resultCode = resultCode; + if (resultData != null) { + energyUws = resultData.getLongArray(IPowerStatsService.KEY_ENERGY); + timestamps = resultData.getLongArray(IPowerStatsService.KEY_TIMESTAMPS); + } } } @@ -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"); + } }