Add random noise to power monitor readings
Bug: 273310268 Test: atest FrameworksServicesTests:PowerStatsServiceTest Change-Id: I12127999edcff0609fbccee4db91de86ff338838
This commit is contained in:
@@ -26,6 +26,7 @@ import android.hardware.power.stats.EnergyConsumerType;
|
||||
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.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
@@ -41,6 +42,7 @@ import android.os.UserHandle;
|
||||
import android.power.PowerStatsInternal;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.provider.DeviceConfigInterface;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -58,6 +60,7 @@ import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@@ -82,6 +85,11 @@ public class PowerStatsService extends SystemService {
|
||||
|
||||
static final String KEY_POWER_MONITOR_API_ENABLED = "power_monitor_api_enabled";
|
||||
|
||||
// The alpha parameter of the Beta distribution used by the random noise generator.
|
||||
// The higher this value, the smaller the amount of added noise.
|
||||
private static final double INTERVAL_RANDOM_NOISE_GENERATION_ALPHA = 50;
|
||||
private static final long MAX_RANDOM_NOISE_UWS = 10_000_000;
|
||||
|
||||
private final Injector mInjector;
|
||||
private final Clock mClock;
|
||||
private final DeviceConfigInterface mDeviceConfig;
|
||||
@@ -189,6 +197,10 @@ public class PowerStatsService extends SystemService {
|
||||
DeviceConfigInterface getDeviceConfig() {
|
||||
return DeviceConfigInterface.REAL;
|
||||
}
|
||||
|
||||
IntervalRandomNoiseGenerator createIntervalRandomNoiseGenerator() {
|
||||
return new IntervalRandomNoiseGenerator(INTERVAL_RANDOM_NOISE_GENERATION_ALPHA);
|
||||
}
|
||||
}
|
||||
|
||||
private final IBinder mService = new IPowerStatsService.Stub() {
|
||||
@@ -200,7 +212,9 @@ public class PowerStatsService extends SystemService {
|
||||
|
||||
@Override
|
||||
public void getPowerMonitorReadings(int[] powerMonitorIds, ResultReceiver resultReceiver) {
|
||||
getHandler().post(() -> getPowerMonitorReadingsImpl(powerMonitorIds, resultReceiver));
|
||||
int callingUid = Binder.getCallingUid();
|
||||
getHandler().post(() ->
|
||||
getPowerMonitorReadingsImpl(powerMonitorIds, resultReceiver, callingUid));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -493,6 +507,7 @@ public class PowerStatsService extends SystemService {
|
||||
public final int id;
|
||||
public long timestampMs;
|
||||
public long energyUws = PowerMonitorReadings.ENERGY_UNAVAILABLE;
|
||||
public long prevEnergyUws;
|
||||
|
||||
private PowerMonitorState(PowerMonitor powerMonitor, int id) {
|
||||
this.powerMonitor = powerMonitor;
|
||||
@@ -502,7 +517,8 @@ public class PowerStatsService extends SystemService {
|
||||
|
||||
private boolean mPowerMonitorApiEnabled = true;
|
||||
private volatile PowerMonitor[] mPowerMonitors;
|
||||
private volatile PowerMonitorState[] mPowerMonitorStates;
|
||||
private PowerMonitorState[] mPowerMonitorStates;
|
||||
private IntervalRandomNoiseGenerator mIntervalRandomNoiseGenerator;
|
||||
|
||||
private void setPowerMonitorApiEnabled(boolean powerMonitorApiEnabled) {
|
||||
if (powerMonitorApiEnabled != mPowerMonitorApiEnabled) {
|
||||
@@ -522,6 +538,10 @@ public class PowerStatsService extends SystemService {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIntervalRandomNoiseGenerator == null) {
|
||||
mIntervalRandomNoiseGenerator = mInjector.createIntervalRandomNoiseGenerator();
|
||||
}
|
||||
|
||||
if (!mPowerMonitorApiEnabled) {
|
||||
mPowerMonitors = new PowerMonitor[0];
|
||||
mPowerMonitorStates = new PowerMonitorState[0];
|
||||
@@ -621,7 +641,7 @@ public class PowerStatsService extends SystemService {
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public void getPowerMonitorReadingsImpl(@NonNull int[] powerMonitorIndices,
|
||||
ResultReceiver resultReceiver) {
|
||||
ResultReceiver resultReceiver, int callingUid) {
|
||||
ensurePowerMonitors();
|
||||
|
||||
long earliestTimestamp = Long.MAX_VALUE;
|
||||
@@ -644,15 +664,35 @@ public class PowerStatsService extends SystemService {
|
||||
|| mClock.elapsedRealtime() - earliestTimestamp > MAX_POWER_MONITOR_AGE_MILLIS) {
|
||||
updateEnergyConsumers(powerMonitorStates);
|
||||
updateEnergyMeasurements(powerMonitorStates);
|
||||
mIntervalRandomNoiseGenerator.refresh();
|
||||
}
|
||||
|
||||
long[] energy = new long[powerMonitorStates.length];
|
||||
long[] timestamps = new long[powerMonitorStates.length];
|
||||
for (int i = 0; i < powerMonitorStates.length; i++) {
|
||||
PowerMonitorState state = powerMonitorStates[i];
|
||||
|
||||
// TODO(273310268): add random noise
|
||||
energy[i] = state.energyUws;
|
||||
if (state.energyUws != PowerMonitorReadings.ENERGY_UNAVAILABLE
|
||||
&& state.prevEnergyUws != PowerMonitorReadings.ENERGY_UNAVAILABLE) {
|
||||
energy[i] = mIntervalRandomNoiseGenerator.addNoise(
|
||||
Math.max(state.prevEnergyUws, state.energyUws - MAX_RANDOM_NOISE_UWS),
|
||||
state.energyUws, callingUid);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, String.format(Locale.ENGLISH,
|
||||
"Monitor=%s timestamp=%d energy=%d"
|
||||
+ " uid=%d noise=%.1f%% returned=%d",
|
||||
state.powerMonitor.name,
|
||||
state.timestampMs,
|
||||
state.energyUws,
|
||||
callingUid,
|
||||
state.energyUws != state.prevEnergyUws
|
||||
? (state.energyUws - energy[i]) * 100.0
|
||||
/ (state.energyUws - state.prevEnergyUws)
|
||||
: 0,
|
||||
energy[i]));
|
||||
}
|
||||
} else {
|
||||
energy[i] = state.energyUws;
|
||||
}
|
||||
timestamps[i] = state.timestampMs;
|
||||
}
|
||||
|
||||
@@ -678,6 +718,7 @@ public class PowerStatsService extends SystemService {
|
||||
== PowerMonitor.POWER_MONITOR_TYPE_CONSUMER) {
|
||||
for (EnergyConsumerResult energyConsumerResult : energyConsumerResults) {
|
||||
if (energyConsumerResult.id == powerMonitorState.id) {
|
||||
powerMonitorState.prevEnergyUws = powerMonitorState.energyUws;
|
||||
powerMonitorState.energyUws = energyConsumerResult.energyUWs;
|
||||
powerMonitorState.timestampMs = energyConsumerResult.timestampMs;
|
||||
break;
|
||||
@@ -703,6 +744,7 @@ public class PowerStatsService extends SystemService {
|
||||
== PowerMonitor.POWER_MONITOR_TYPE_MEASUREMENT) {
|
||||
for (EnergyMeasurement energyMeasurement : energyMeasurements) {
|
||||
if (energyMeasurement.id == powerMonitorState.id) {
|
||||
powerMonitorState.prevEnergyUws = powerMonitorState.energyUws;
|
||||
powerMonitorState.energyUws = energyMeasurement.energyUWs;
|
||||
powerMonitorState.timestampMs = energyMeasurement.timestampMs;
|
||||
break;
|
||||
|
||||
@@ -99,6 +99,7 @@ public class PowerStatsServiceTest {
|
||||
private static final int POWER_ENTITY_COUNT = 3;
|
||||
private static final int STATE_INFO_COUNT = 5;
|
||||
private static final int STATE_RESIDENCY_COUNT = 4;
|
||||
private static final int APP_UID = 10042;
|
||||
|
||||
private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
|
||||
private PowerStatsService mService;
|
||||
@@ -109,6 +110,7 @@ public class PowerStatsServiceTest {
|
||||
private PowerStatsLogger mPowerStatsLogger;
|
||||
private MockClock mMockClock = new MockClock();
|
||||
private DeviceConfigInterface mMockDeviceConfig = new FakeDeviceConfigInterface();
|
||||
private IntervalRandomNoiseGenerator mMockNoiseGenerator = new IntervalRandomNoiseGenerator(42);
|
||||
|
||||
private class MockClock extends Clock {
|
||||
public long realtime;
|
||||
@@ -205,6 +207,11 @@ public class PowerStatsServiceTest {
|
||||
DeviceConfigInterface getDeviceConfig() {
|
||||
return mMockDeviceConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
IntervalRandomNoiseGenerator createIntervalRandomNoiseGenerator() {
|
||||
return mMockNoiseGenerator;
|
||||
}
|
||||
};
|
||||
|
||||
public static final class TestPowerStatsHALWrapper implements IPowerStatsHALWrapper {
|
||||
@@ -1102,6 +1109,7 @@ public class PowerStatsServiceTest {
|
||||
@Test
|
||||
public void getPowerMonitors() {
|
||||
mMockClock.realtime = 10 * 60_000;
|
||||
mMockNoiseGenerator.reseed(314);
|
||||
|
||||
mPowerStatsHALWrapper.buildEnergyConsumerResult();
|
||||
EnergyConsumerResult[] energyConsumerResults = mPowerStatsHALWrapper.energyConsumerResults;
|
||||
@@ -1131,7 +1139,7 @@ public class PowerStatsServiceTest {
|
||||
GetPowerMonitorsResult result = new GetPowerMonitorsResult();
|
||||
mService.getPowerMonitorReadingsImpl(
|
||||
new int[]{consumer1.index, consumer2.index, measurement1.index,
|
||||
measurement2.index}, result);
|
||||
measurement2.index}, result, APP_UID);
|
||||
|
||||
assertThat(result.energyUws).isEqualTo(new long[]{42, 142, 314, 514});
|
||||
assertThat(result.timestamps).isEqualTo(new long[]{600_000, 600_100, 600_000, 600_200});
|
||||
@@ -1150,7 +1158,7 @@ public class PowerStatsServiceTest {
|
||||
}
|
||||
|
||||
mService.getPowerMonitorReadingsImpl(new int[]{consumer1.index, measurement1.index},
|
||||
result);
|
||||
result, APP_UID);
|
||||
|
||||
assertThat(result.energyUws).isEqualTo(new long[]{42, 314});
|
||||
assertThat(result.timestamps).isEqualTo(new long[]{600_000, 600_000});
|
||||
@@ -1158,9 +1166,10 @@ public class PowerStatsServiceTest {
|
||||
mMockClock.realtime += 10 * 60000;
|
||||
|
||||
mService.getPowerMonitorReadingsImpl(new int[]{consumer1.index, measurement1.index},
|
||||
result);
|
||||
result, APP_UID);
|
||||
|
||||
assertThat(result.energyUws).isEqualTo(new long[]{300, 400});
|
||||
// This time, random noise is added
|
||||
assertThat(result.energyUws).isEqualTo(new long[]{298, 399});
|
||||
assertThat(result.timestamps).isEqualTo(new long[]{600_301, 600_401});
|
||||
}
|
||||
|
||||
@@ -1178,7 +1187,7 @@ public class PowerStatsServiceTest {
|
||||
assertThat(supportedPowerMonitorsResult.powerMonitors).isEmpty();
|
||||
|
||||
GetPowerMonitorsResult getPowerMonitorsResult = new GetPowerMonitorsResult();
|
||||
mService.getPowerMonitorReadingsImpl(new int[]{0}, getPowerMonitorsResult);
|
||||
mService.getPowerMonitorReadingsImpl(new int[]{0}, getPowerMonitorsResult, APP_UID);
|
||||
assertThat(getPowerMonitorsResult.resultCode).isEqualTo(
|
||||
IPowerStatsService.RESULT_UNSUPPORTED_POWER_MONITOR);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user