Add feature flag for PowerMonitor API

Bug: 273308894
Test: atest FrameworksServicesTests:PowerStatsServiceTest
Change-Id: I1b027c2f24cb6aeeba7e790fc279fc4d69d33ef8
This commit is contained in:
Dmitri Plotnikov
2023-03-31 11:37:08 -07:00
parent 77491b99bd
commit 3817543647
2 changed files with 89 additions and 2 deletions

View File

@@ -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<>();

View File

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