Transition BatteryStatsLoadTests to BatteryUsageStats API
Also, return metrics to the instrumentation instead of just logging. Also, clean up handling of the BATTERY_CHANGED broadcast. Bug: 175324611 Test: mp :BatteryStatsLoadTests && ash am instrument -w -e class com.android.frameworks.core.batterystatsloadtests.SystemServiceCallLoadTest com.android.frameworks.core.batterystatsloadtests/androidx.test.runner.AndroidJUnitRunner Change-Id: I9bc7ad361fb31fa7d53a7e383c09b1f1770db530
This commit is contained in:
@@ -16,261 +16,99 @@
|
||||
|
||||
package com.android.frameworks.core.batterystatsloadtests;
|
||||
|
||||
import android.os.Process;
|
||||
|
||||
import com.android.internal.os.BatterySipper;
|
||||
import com.android.internal.os.BatteryStatsHelper;
|
||||
import android.os.BatteryConsumer;
|
||||
import android.os.BatteryUsageStats;
|
||||
import android.os.UidBatteryConsumer;
|
||||
import android.util.DebugUtils;
|
||||
import android.util.Range;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PowerMetrics {
|
||||
private static final String PACKAGE_CALENDAR_PROVIDER = "com.android.providers.calendar";
|
||||
private static final String PACKAGE_MEDIA_PROVIDER = "com.android.providers.media";
|
||||
private static final String PACKAGE_SYSTEMUI = "com.android.systemui";
|
||||
private static final String[] PACKAGES_SYSTEM = {PACKAGE_MEDIA_PROVIDER,
|
||||
PACKAGE_CALENDAR_PROVIDER, PACKAGE_SYSTEMUI};
|
||||
|
||||
enum MetricKind {
|
||||
POWER,
|
||||
DURATION,
|
||||
}
|
||||
|
||||
public static final String METRIC_APP_POWER = "appPower";
|
||||
public static final String METRIC_APP_POWER_EXCLUDE_SYSTEM_FROM_TOTAL = "appPowerExcludeSystem";
|
||||
public static final String METRIC_APP_POWER_EXCLUDE_SMEARED = "appPowerExcludeSmeared";
|
||||
public static final String METRIC_SCREEN_POWER = "screenPower";
|
||||
public static final String METRIC_WIFI_POWER = "wifiPower";
|
||||
public static final String METRIC_SYSTEM_SERVICE_CPU_POWER = "systemService";
|
||||
public static final String METRIC_OTHER_POWER = "otherPower";
|
||||
public static final String METRIC_CPU_POWER = "cpuPower";
|
||||
public static final String METRIC_RAM_POWER = "ramPower";
|
||||
public static final String METRIC_WAKELOCK_POWER = "wakelockPower";
|
||||
public static final String METRIC_MOBILE_RADIO_POWER = "mobileRadioPower";
|
||||
public static final String METRIC_BLUETOOTH_POWER = "bluetoothPower";
|
||||
public static final String METRIC_GPS_POWER = "gpsPower";
|
||||
public static final String METRIC_CAMERA_POWER = "cameraPower";
|
||||
public static final String METRIC_FLASHLIGHT_POWER = "flashlightPower";
|
||||
public static final String METRIC_SENSORS_POWER = "sensorsPower";
|
||||
public static final String METRIC_AUDIO_POWER = "audioPower";
|
||||
public static final String METRIC_VIDEO_POWER = "videoPower";
|
||||
public static final String METRIC_CPU_TIME = "cpuTime";
|
||||
public static final String METRIC_CPU_FOREGROUND_TIME = "cpuForegroundTime";
|
||||
public static final String METRIC_WAKELOCK_TIME = "wakelockTime";
|
||||
public static final String METRIC_WIFI_RUNNING_TIME = "wifiRunningTime";
|
||||
public static final String METRIC_BLUETOOTH_RUNNING_TIME = "bluetoothRunningTime";
|
||||
public static final String METRIC_GPS_TIME = "gpsTime";
|
||||
public static final String METRIC_CAMERA_TIME = "cameraTime";
|
||||
public static final String METRIC_FLASHLIGHT_TIME = "flashlightTime";
|
||||
public static final String METRIC_AUDIO_TIME = "audioTime";
|
||||
public static final String METRIC_VIDEO_TIME = "videoTime";
|
||||
|
||||
public static class Metric {
|
||||
public String metricType;
|
||||
public String metricName;
|
||||
public MetricKind metricKind;
|
||||
public String title;
|
||||
public String statusKeyPrefix;
|
||||
public double value;
|
||||
public double total;
|
||||
}
|
||||
|
||||
private final double mMinDrainedPower;
|
||||
private final double mMaxDrainedPower;
|
||||
private final double mDrainedPower;
|
||||
|
||||
private List<Metric> mMetrics = new ArrayList<>();
|
||||
|
||||
public PowerMetrics(BatteryStatsHelper batteryStatsHelper, int uid) {
|
||||
mMinDrainedPower = batteryStatsHelper.getMinDrainedPower();
|
||||
mMaxDrainedPower = batteryStatsHelper.getMaxDrainedPower();
|
||||
public PowerMetrics(BatteryUsageStats batteryUsageStats, int uid) {
|
||||
final Range<Double> dischargedPowerRange = batteryUsageStats.getDischargedPowerRange();
|
||||
mDrainedPower = (dischargedPowerRange.getLower() + dischargedPowerRange.getUpper()) / 2;
|
||||
double[] totalPowerPerComponentMah = new double[BatteryConsumer.POWER_COMPONENT_COUNT];
|
||||
long[] totalDurationPerComponentMs = new long[BatteryConsumer.POWER_COMPONENT_COUNT];
|
||||
|
||||
List<BatterySipper> usageList = batteryStatsHelper.getUsageList();
|
||||
|
||||
double totalPowerMah = 0;
|
||||
double totalSmearedPowerMah = 0;
|
||||
double totalPowerExcludeSystemMah = 0;
|
||||
double totalScreenPower = 0;
|
||||
double totalProportionalSmearMah = 0;
|
||||
double totalCpuPowerMah = 0;
|
||||
double totalSystemServiceCpuPowerMah = 0;
|
||||
double totalUsagePowerMah = 0;
|
||||
double totalWakeLockPowerMah = 0;
|
||||
double totalMobileRadioPowerMah = 0;
|
||||
double totalWifiPowerMah = 0;
|
||||
double totalBluetoothPowerMah = 0;
|
||||
double totalGpsPowerMah = 0;
|
||||
double totalCameraPowerMah = 0;
|
||||
double totalFlashlightPowerMah = 0;
|
||||
double totalSensorPowerMah = 0;
|
||||
double totalAudioPowerMah = 0;
|
||||
double totalVideoPowerMah = 0;
|
||||
|
||||
long totalCpuTimeMs = 0;
|
||||
long totalCpuFgTimeMs = 0;
|
||||
long totalWakeLockTimeMs = 0;
|
||||
long totalWifiRunningTimeMs = 0;
|
||||
long totalBluetoothRunningTimeMs = 0;
|
||||
long totalGpsTimeMs = 0;
|
||||
long totalCameraTimeMs = 0;
|
||||
long totalFlashlightTimeMs = 0;
|
||||
long totalAudioTimeMs = 0;
|
||||
long totalVideoTimeMs = 0;
|
||||
|
||||
BatterySipper uidSipper = null;
|
||||
for (BatterySipper sipper : usageList) {
|
||||
if (sipper.drainType == BatterySipper.DrainType.SCREEN) {
|
||||
totalScreenPower = sipper.sumPower();
|
||||
UidBatteryConsumer selectedBatteryConsumer = null;
|
||||
for (UidBatteryConsumer uidBatteryConsumer : batteryUsageStats.getUidBatteryConsumers()) {
|
||||
if (uidBatteryConsumer.getUid() == uid) {
|
||||
selectedBatteryConsumer = uidBatteryConsumer;
|
||||
}
|
||||
|
||||
if (isHiddenDrainType(sipper.drainType)) {
|
||||
continue;
|
||||
for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT;
|
||||
component++) {
|
||||
totalPowerPerComponentMah[component] += uidBatteryConsumer.getConsumedPower(
|
||||
component);
|
||||
}
|
||||
|
||||
if (sipper.drainType == BatterySipper.DrainType.APP && sipper.getUid() == uid) {
|
||||
uidSipper = sipper;
|
||||
for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT; component++) {
|
||||
totalDurationPerComponentMs[component] +=
|
||||
uidBatteryConsumer.getUsageDurationMillis(component);
|
||||
}
|
||||
|
||||
totalPowerMah += sipper.sumPower();
|
||||
totalSmearedPowerMah += sipper.totalSmearedPowerMah;
|
||||
totalProportionalSmearMah += sipper.proportionalSmearMah;
|
||||
|
||||
if (!isSystemSipper(sipper)) {
|
||||
totalPowerExcludeSystemMah += sipper.totalSmearedPowerMah;
|
||||
}
|
||||
|
||||
totalCpuPowerMah += sipper.cpuPowerMah;
|
||||
totalSystemServiceCpuPowerMah += sipper.systemServiceCpuPowerMah;
|
||||
totalUsagePowerMah += sipper.usagePowerMah;
|
||||
totalWakeLockPowerMah += sipper.wakeLockPowerMah;
|
||||
totalMobileRadioPowerMah += sipper.mobileRadioPowerMah;
|
||||
totalWifiPowerMah += sipper.wifiPowerMah;
|
||||
totalBluetoothPowerMah += sipper.bluetoothPowerMah;
|
||||
totalGpsPowerMah += sipper.gpsPowerMah;
|
||||
totalCameraPowerMah += sipper.cameraPowerMah;
|
||||
totalFlashlightPowerMah += sipper.flashlightPowerMah;
|
||||
totalSensorPowerMah += sipper.sensorPowerMah;
|
||||
totalAudioPowerMah += sipper.audioPowerMah;
|
||||
totalVideoPowerMah += sipper.videoPowerMah;
|
||||
|
||||
totalCpuTimeMs += sipper.cpuTimeMs;
|
||||
totalCpuFgTimeMs += sipper.cpuFgTimeMs;
|
||||
totalWakeLockTimeMs += sipper.wakeLockTimeMs;
|
||||
totalWifiRunningTimeMs += sipper.wifiRunningTimeMs;
|
||||
totalBluetoothRunningTimeMs += sipper.bluetoothRunningTimeMs;
|
||||
totalGpsTimeMs += sipper.gpsTimeMs;
|
||||
totalCameraTimeMs += sipper.cameraTimeMs;
|
||||
totalFlashlightTimeMs += sipper.flashlightTimeMs;
|
||||
totalAudioTimeMs += sipper.audioTimeMs;
|
||||
totalVideoTimeMs += sipper.videoTimeMs;
|
||||
}
|
||||
|
||||
if (uidSipper == null) {
|
||||
if (selectedBatteryConsumer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
addMetric(METRIC_APP_POWER, MetricKind.POWER, "Total power",
|
||||
uidSipper.totalSmearedPowerMah, totalSmearedPowerMah);
|
||||
addMetric(METRIC_APP_POWER_EXCLUDE_SYSTEM_FROM_TOTAL, MetricKind.POWER,
|
||||
"Total power excluding system",
|
||||
uidSipper.totalSmearedPowerMah, totalPowerExcludeSystemMah);
|
||||
addMetric(METRIC_SCREEN_POWER, MetricKind.POWER, "Screen, smeared",
|
||||
uidSipper.screenPowerMah, totalScreenPower);
|
||||
addMetric(METRIC_OTHER_POWER, MetricKind.POWER, "Other, smeared",
|
||||
uidSipper.proportionalSmearMah, totalProportionalSmearMah);
|
||||
addMetric(METRIC_APP_POWER_EXCLUDE_SMEARED, MetricKind.POWER, "Excluding smeared",
|
||||
uidSipper.totalPowerMah, totalPowerMah);
|
||||
addMetric(METRIC_CPU_POWER, MetricKind.POWER, "CPU",
|
||||
uidSipper.cpuPowerMah, totalCpuPowerMah);
|
||||
addMetric(METRIC_SYSTEM_SERVICE_CPU_POWER, MetricKind.POWER, "System services",
|
||||
uidSipper.systemServiceCpuPowerMah, totalSystemServiceCpuPowerMah);
|
||||
addMetric(METRIC_RAM_POWER, MetricKind.POWER, "RAM",
|
||||
uidSipper.usagePowerMah, totalUsagePowerMah);
|
||||
addMetric(METRIC_WAKELOCK_POWER, MetricKind.POWER, "Wake lock",
|
||||
uidSipper.wakeLockPowerMah, totalWakeLockPowerMah);
|
||||
addMetric(METRIC_MOBILE_RADIO_POWER, MetricKind.POWER, "Mobile radio",
|
||||
uidSipper.mobileRadioPowerMah, totalMobileRadioPowerMah);
|
||||
addMetric(METRIC_WIFI_POWER, MetricKind.POWER, "WiFi",
|
||||
uidSipper.wifiPowerMah, totalWifiPowerMah);
|
||||
addMetric(METRIC_BLUETOOTH_POWER, MetricKind.POWER, "Bluetooth",
|
||||
uidSipper.bluetoothPowerMah, totalBluetoothPowerMah);
|
||||
addMetric(METRIC_GPS_POWER, MetricKind.POWER, "GPS",
|
||||
uidSipper.gpsPowerMah, totalGpsPowerMah);
|
||||
addMetric(METRIC_CAMERA_POWER, MetricKind.POWER, "Camera",
|
||||
uidSipper.cameraPowerMah, totalCameraPowerMah);
|
||||
addMetric(METRIC_FLASHLIGHT_POWER, MetricKind.POWER, "Flashlight",
|
||||
uidSipper.flashlightPowerMah, totalFlashlightPowerMah);
|
||||
addMetric(METRIC_SENSORS_POWER, MetricKind.POWER, "Sensors",
|
||||
uidSipper.sensorPowerMah, totalSensorPowerMah);
|
||||
addMetric(METRIC_AUDIO_POWER, MetricKind.POWER, "Audio",
|
||||
uidSipper.audioPowerMah, totalAudioPowerMah);
|
||||
addMetric(METRIC_VIDEO_POWER, MetricKind.POWER, "Video",
|
||||
uidSipper.videoPowerMah, totalVideoPowerMah);
|
||||
for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
|
||||
addMetric(getPowerMetricName(component), MetricKind.POWER,
|
||||
selectedBatteryConsumer.getConsumedPower(component),
|
||||
totalPowerPerComponentMah[component]);
|
||||
}
|
||||
|
||||
addMetric(METRIC_CPU_TIME, MetricKind.DURATION, "CPU time",
|
||||
uidSipper.cpuTimeMs, totalCpuTimeMs);
|
||||
addMetric(METRIC_CPU_FOREGROUND_TIME, MetricKind.DURATION, "CPU foreground time",
|
||||
uidSipper.cpuFgTimeMs, totalCpuFgTimeMs);
|
||||
addMetric(METRIC_WAKELOCK_TIME, MetricKind.DURATION, "Wake lock time",
|
||||
uidSipper.wakeLockTimeMs, totalWakeLockTimeMs);
|
||||
addMetric(METRIC_WIFI_RUNNING_TIME, MetricKind.DURATION, "WiFi running time",
|
||||
uidSipper.wifiRunningTimeMs, totalWifiRunningTimeMs);
|
||||
addMetric(METRIC_BLUETOOTH_RUNNING_TIME, MetricKind.DURATION, "Bluetooth time",
|
||||
uidSipper.bluetoothRunningTimeMs, totalBluetoothRunningTimeMs);
|
||||
addMetric(METRIC_GPS_TIME, MetricKind.DURATION, "GPS time",
|
||||
uidSipper.gpsTimeMs, totalGpsTimeMs);
|
||||
addMetric(METRIC_CAMERA_TIME, MetricKind.DURATION, "Camera time",
|
||||
uidSipper.cameraTimeMs, totalCameraTimeMs);
|
||||
addMetric(METRIC_FLASHLIGHT_TIME, MetricKind.DURATION, "Flashlight time",
|
||||
uidSipper.flashlightTimeMs, totalFlashlightTimeMs);
|
||||
addMetric(METRIC_AUDIO_TIME, MetricKind.DURATION, "Audio time",
|
||||
uidSipper.audioTimeMs, totalAudioTimeMs);
|
||||
addMetric(METRIC_VIDEO_TIME, MetricKind.DURATION, "Video time",
|
||||
uidSipper.videoTimeMs, totalVideoTimeMs);
|
||||
for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT; component++) {
|
||||
addMetric(getTimeMetricName(component), MetricKind.DURATION,
|
||||
selectedBatteryConsumer.getUsageDurationMillis(component),
|
||||
totalDurationPerComponentMs[component]);
|
||||
}
|
||||
}
|
||||
|
||||
static String getTimeMetricName(int componentId) {
|
||||
return "TIME_" + DebugUtils.constantToString(BatteryConsumer.class,
|
||||
"TIME_COMPONENT_", componentId);
|
||||
}
|
||||
|
||||
static String getPowerMetricName(int componentId) {
|
||||
return "POWER_" + DebugUtils.constantToString(BatteryConsumer.class,
|
||||
"POWER_COMPONENT_", componentId);
|
||||
}
|
||||
|
||||
public List<Metric> getMetrics() {
|
||||
return mMetrics;
|
||||
}
|
||||
|
||||
public double getMinDrainedPower() {
|
||||
return mMinDrainedPower;
|
||||
public double getDrainedPower() {
|
||||
return mDrainedPower;
|
||||
}
|
||||
|
||||
public double getMaxDrainedPower() {
|
||||
return mMaxDrainedPower;
|
||||
}
|
||||
|
||||
protected boolean isHiddenDrainType(BatterySipper.DrainType drainType) {
|
||||
return drainType == BatterySipper.DrainType.IDLE
|
||||
|| drainType == BatterySipper.DrainType.CELL
|
||||
|| drainType == BatterySipper.DrainType.SCREEN
|
||||
|| drainType == BatterySipper.DrainType.UNACCOUNTED
|
||||
|| drainType == BatterySipper.DrainType.OVERCOUNTED
|
||||
|| drainType == BatterySipper.DrainType.BLUETOOTH
|
||||
|| drainType == BatterySipper.DrainType.WIFI;
|
||||
}
|
||||
|
||||
private boolean isSystemSipper(BatterySipper sipper) {
|
||||
final int uid = sipper.uidObj == null ? -1 : sipper.getUid();
|
||||
if (uid >= Process.ROOT_UID && uid < Process.FIRST_APPLICATION_UID) {
|
||||
return true;
|
||||
} else if (sipper.mPackages != null) {
|
||||
for (final String packageName : sipper.mPackages) {
|
||||
for (final String systemPackage : PACKAGES_SYSTEM) {
|
||||
if (systemPackage.equals(packageName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void addMetric(String metricType, MetricKind metricKind, String title, double amount,
|
||||
private void addMetric(String metricType, MetricKind metricKind, double amount,
|
||||
double totalAmount) {
|
||||
Metric metric = new Metric();
|
||||
metric.metricType = metricType;
|
||||
metric.metricName = metricType;
|
||||
metric.metricKind = metricKind;
|
||||
metric.title = title;
|
||||
metric.statusKeyPrefix = metricKind.toString().toLowerCase();
|
||||
metric.value = amount;
|
||||
metric.total = totalAmount;
|
||||
mMetrics.add(metric);
|
||||
|
||||
@@ -19,47 +19,43 @@ package com.android.frameworks.core.batterystatsloadtests;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Instrumentation;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.BatteryConsumer;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.BatteryStatsManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.ConditionVariable;
|
||||
import android.os.Process;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserManager;
|
||||
import android.util.IndentingPrintWriter;
|
||||
import android.util.Log;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.compatibility.common.util.SystemUtil;
|
||||
import com.android.internal.os.BatteryStatsHelper;
|
||||
import com.android.internal.os.LoggingPrintStream;
|
||||
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class PowerMetricsCollector implements TestRule {
|
||||
private final String mTag;
|
||||
private final float mBatteryDrainThresholdPct;
|
||||
private final int mTimeoutMillis;
|
||||
|
||||
private final Instrumentation mInstrumentation;
|
||||
private final Context mContext;
|
||||
private final UserManager mUserManager;
|
||||
private final int mUid;
|
||||
private final BatteryStatsHelper mStatsHelper;
|
||||
private final CountDownLatch mSuspendingBatteryInput = new CountDownLatch(1);
|
||||
private final ConditionVariable mSuspendingBatteryInput = new ConditionVariable();
|
||||
|
||||
private long mStartTime;
|
||||
private volatile float mInitialBatteryLevel;
|
||||
@@ -68,29 +64,34 @@ public class PowerMetricsCollector implements TestRule {
|
||||
private PowerMetrics mInitialPowerMetrics;
|
||||
private PowerMetrics mFinalPowerMetrics;
|
||||
private List<PowerMetrics.Metric> mPowerMetricsDelta;
|
||||
private Intent mBatteryStatus;
|
||||
private final BatteryStatsManager mBatteryStatsManager;
|
||||
private final BroadcastReceiver mBatteryLevelReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
handleBatteryStatus(intent);
|
||||
}
|
||||
};
|
||||
private final Bundle mStatus = new Bundle();
|
||||
private final StringWriter mReportStringWriter = new StringWriter();
|
||||
private final IndentingPrintWriter mReportWriter =
|
||||
new IndentingPrintWriter(mReportStringWriter);
|
||||
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
return new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
BroadcastReceiver batteryBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
handleBatteryStatus(intent);
|
||||
}
|
||||
};
|
||||
mBatteryStatus = mContext.registerReceiver(batteryBroadcastReceiver,
|
||||
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||
disableCharger();
|
||||
try {
|
||||
prepareBatteryLevelMonitor();
|
||||
mStartTime = SystemClock.uptimeMillis();
|
||||
mContext.registerReceiver(mBatteryLevelReceiver,
|
||||
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||
base.evaluate();
|
||||
captureFinalPowerStatsData();
|
||||
mStatus.putString("report", mReportStringWriter.toString());
|
||||
mInstrumentation.sendStatus(Activity.RESULT_OK, mStatus);
|
||||
} finally {
|
||||
mContext.unregisterReceiver(batteryBroadcastReceiver);
|
||||
mContext.unregisterReceiver(mBatteryLevelReceiver);
|
||||
enableCharger();
|
||||
}
|
||||
}
|
||||
@@ -102,35 +103,41 @@ public class PowerMetricsCollector implements TestRule {
|
||||
mBatteryDrainThresholdPct = batteryDrainThresholdPct;
|
||||
mTimeoutMillis = timeoutMillis;
|
||||
|
||||
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
mContext = instrumentation.getContext();
|
||||
mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
mContext = mInstrumentation.getContext();
|
||||
mUid = Process.myUid();
|
||||
mUserManager = mContext.getSystemService(UserManager.class);
|
||||
// TODO(b/175324611): Use BatteryUsageStats instead
|
||||
mStatsHelper = new BatteryStatsHelper(mContext, false /* collectBatteryBroadcast */);
|
||||
mStatsHelper.create((Bundle) null);
|
||||
mBatteryStatsManager = mContext.getSystemService(BatteryStatsManager.class);
|
||||
}
|
||||
|
||||
private void disableCharger() throws InterruptedException {
|
||||
SystemUtil.runShellCommand("dumpsys battery suspend_input");
|
||||
final boolean success = mSuspendingBatteryInput.await(10, TimeUnit.SECONDS);
|
||||
assertTrue("Timed out waiting for battery input to be suspended", success);
|
||||
private void disableCharger() {
|
||||
final BroadcastReceiver receiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (!isCharging(intent)) {
|
||||
mInitialBatteryLevel = mCurrentBatteryLevel = getBatteryLevel(intent);
|
||||
mSuspendingBatteryInput.open();
|
||||
}
|
||||
}
|
||||
};
|
||||
final Intent intent = mContext.registerReceiver(
|
||||
receiver,
|
||||
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||
|
||||
if (isCharging(intent)) {
|
||||
mBatteryStatsManager.suspendBatteryInput();
|
||||
final boolean success = mSuspendingBatteryInput.block(10000);
|
||||
assertTrue("Timed out waiting for battery input to be suspended", success);
|
||||
}
|
||||
|
||||
mContext.unregisterReceiver(receiver);
|
||||
}
|
||||
|
||||
private void enableCharger() {
|
||||
SystemUtil.runShellCommand("dumpsys battery reset");
|
||||
mBatteryStatsManager.resetBattery(/* forceUpdate */false);
|
||||
}
|
||||
|
||||
private PowerMetrics readBatteryStatsData() {
|
||||
mStatsHelper.clearStats();
|
||||
mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
|
||||
mUserManager.getUserProfiles());
|
||||
return new PowerMetrics(mStatsHelper, mUid);
|
||||
}
|
||||
|
||||
protected void prepareBatteryLevelMonitor() {
|
||||
handleBatteryStatus(mBatteryStatus);
|
||||
mInitialBatteryLevel = mCurrentBatteryLevel;
|
||||
return new PowerMetrics(mBatteryStatsManager.getBatteryUsageStats(), mUid);
|
||||
}
|
||||
|
||||
protected void handleBatteryStatus(Intent intent) {
|
||||
@@ -138,36 +145,35 @@ public class PowerMetricsCollector implements TestRule {
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean isCharging = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) != 0;
|
||||
|
||||
if (mSuspendingBatteryInput.getCount() > 0) {
|
||||
if (!isCharging) {
|
||||
mSuspendingBatteryInput.countDown();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCharging) {
|
||||
if (isCharging(intent)) {
|
||||
fail("Device must remain disconnected from the power source "
|
||||
+ "for the duration of the test");
|
||||
}
|
||||
|
||||
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
|
||||
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
|
||||
|
||||
mCurrentBatteryLevel = level * 100 / (float) scale;
|
||||
mCurrentBatteryLevel = getBatteryLevel(intent);
|
||||
Log.i(mTag, "Battery level = " + mCurrentBatteryLevel);
|
||||
|
||||
// We delay tracking until the battery level drops. If the resolution of
|
||||
// battery level is 1%, and the initially reported level is 73, we don't know whether
|
||||
// it's 73.1 or 73.7. Once it drops to 72, we can be confident that the real battery
|
||||
// level it is very close to 72.0 and can start tracking.
|
||||
// level is very close to 72.0 and can start tracking.
|
||||
if (mInitialPowerMetrics == null && mCurrentBatteryLevel < mInitialBatteryLevel) {
|
||||
mInitialBatteryLevel = mCurrentBatteryLevel;
|
||||
mInitialPowerMetrics = readBatteryStatsData();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCharging(Intent intent) {
|
||||
return intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) != 0;
|
||||
}
|
||||
|
||||
private float getBatteryLevel(Intent intent) {
|
||||
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
|
||||
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
|
||||
|
||||
return level * 100 / (float) scale;
|
||||
}
|
||||
|
||||
private void captureFinalPowerStatsData() {
|
||||
if (mFinalPowerMetrics != null) {
|
||||
return;
|
||||
@@ -181,7 +187,7 @@ public class PowerMetricsCollector implements TestRule {
|
||||
for (PowerMetrics.Metric initialMetric : initialPowerMetrics) {
|
||||
PowerMetrics.Metric finalMetric = null;
|
||||
for (PowerMetrics.Metric metric : finalPowerMetrics) {
|
||||
if (metric.title.equals(initialMetric.title)) {
|
||||
if (metric.metricName.equals(initialMetric.metricName)) {
|
||||
finalMetric = metric;
|
||||
break;
|
||||
}
|
||||
@@ -189,9 +195,9 @@ public class PowerMetricsCollector implements TestRule {
|
||||
|
||||
if (finalMetric != null) {
|
||||
PowerMetrics.Metric delta = new PowerMetrics.Metric();
|
||||
delta.metricType = initialMetric.metricType;
|
||||
delta.metricName = initialMetric.metricName;
|
||||
delta.metricKind = initialMetric.metricKind;
|
||||
delta.title = initialMetric.title;
|
||||
delta.statusKeyPrefix = initialMetric.statusKeyPrefix;
|
||||
delta.total = finalMetric.total - initialMetric.total;
|
||||
delta.value = finalMetric.value - initialMetric.value;
|
||||
mPowerMetricsDelta.add(delta);
|
||||
@@ -230,73 +236,80 @@ public class PowerMetricsCollector implements TestRule {
|
||||
return mIterations;
|
||||
}
|
||||
|
||||
public void dumpMetrics() {
|
||||
dumpMetrics(new LoggingPrintStream() {
|
||||
@Override
|
||||
protected void log(String line) {
|
||||
Log.i(mTag, line);
|
||||
}
|
||||
});
|
||||
public void report(String line) {
|
||||
mReportWriter.println(line);
|
||||
}
|
||||
|
||||
public void dumpMetrics(PrintStream out) {
|
||||
public void reportMetrics() {
|
||||
List<PowerMetrics.Metric> initialPowerMetrics = mInitialPowerMetrics.getMetrics();
|
||||
List<PowerMetrics.Metric> finalPowerMetrics = mFinalPowerMetrics.getMetrics();
|
||||
|
||||
out.println("== Power metrics at test start");
|
||||
dumpPowerStatsData(out, initialPowerMetrics);
|
||||
mReportWriter.println("Power metrics at test start");
|
||||
mReportWriter.increaseIndent();
|
||||
reportPowerStatsData(initialPowerMetrics);
|
||||
mReportWriter.decreaseIndent();
|
||||
|
||||
out.println("== Power metrics at test end");
|
||||
dumpPowerStatsData(out, finalPowerMetrics);
|
||||
mReportWriter.println("Power metrics at test end");
|
||||
mReportWriter.increaseIndent();
|
||||
reportPowerStatsData(finalPowerMetrics);
|
||||
mReportWriter.decreaseIndent();
|
||||
|
||||
out.println("== Power metrics delta");
|
||||
dumpPowerStatsData(out, mPowerMetricsDelta);
|
||||
mReportWriter.println("Power metrics delta");
|
||||
mReportWriter.increaseIndent();
|
||||
reportPowerStatsData(mPowerMetricsDelta);
|
||||
mReportWriter.decreaseIndent();
|
||||
}
|
||||
|
||||
protected void dumpPowerStatsData(PrintStream out, List<PowerMetrics.Metric> metrics) {
|
||||
protected void reportPowerStatsData(List<PowerMetrics.Metric> metrics) {
|
||||
Locale locale = Locale.getDefault();
|
||||
for (PowerMetrics.Metric metric : metrics) {
|
||||
double proportion = metric.total != 0 ? metric.value * 100 / metric.total : 0;
|
||||
switch (metric.metricKind) {
|
||||
case POWER:
|
||||
out.println(
|
||||
String.format(locale, " %-30s %7.1f mAh %4.1f%%", metric.title,
|
||||
mReportWriter.println(
|
||||
String.format(locale, "%-40s %7.1f mAh %4.1f%%", metric.metricName,
|
||||
metric.value, proportion));
|
||||
break;
|
||||
case DURATION:
|
||||
out.println(
|
||||
String.format(locale, " %-30s %,7d ms %4.1f%%", metric.title,
|
||||
mReportWriter.println(
|
||||
String.format(locale, "%-40s %,7d ms %4.1f%%", metric.metricName,
|
||||
(long) metric.value, proportion));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpMetricAsPercentageOfDrainedPower(String metricType) {
|
||||
double minDrainedPower =
|
||||
mFinalPowerMetrics.getMinDrainedPower() - mInitialPowerMetrics.getMinDrainedPower();
|
||||
double maxDrainedPower =
|
||||
mFinalPowerMetrics.getMaxDrainedPower() - mInitialPowerMetrics.getMaxDrainedPower();
|
||||
public void reportMetricAsPercentageOfDrainedPower(
|
||||
@BatteryConsumer.PowerComponent int component) {
|
||||
double drainedPower =
|
||||
mFinalPowerMetrics.getDrainedPower() - mInitialPowerMetrics.getDrainedPower();
|
||||
|
||||
PowerMetrics.Metric metric = getMetric(metricType);
|
||||
PowerMetrics.Metric metric = getPowerMetric(component);
|
||||
double metricDelta = metric.value;
|
||||
|
||||
if (maxDrainedPower - minDrainedPower < 0.1f) {
|
||||
Log.i(mTag, String.format(Locale.getDefault(),
|
||||
"%s power consumed by the test: %.1f of %.1f mAh (%.1f%%)",
|
||||
metric.title, metricDelta, maxDrainedPower,
|
||||
metricDelta / maxDrainedPower * 100));
|
||||
} else {
|
||||
Log.i(mTag, String.format(Locale.getDefault(),
|
||||
"%s power consumed by the test: %.1f of %.1f - %.1f mAh (%.1f%% - %.1f%%)",
|
||||
metric.title, metricDelta, minDrainedPower, maxDrainedPower,
|
||||
metricDelta / minDrainedPower * 100, metricDelta / maxDrainedPower * 100));
|
||||
}
|
||||
final double percent = metricDelta / drainedPower * 100;
|
||||
mStatus.putDouble(metric.statusKeyPrefix, metricDelta);
|
||||
mStatus.putDouble(metric.statusKeyPrefix + "_pct", percent);
|
||||
|
||||
mReportWriter.println(String.format(Locale.getDefault(),
|
||||
"%s power consumed by the test: %.1f of %.1f mAh (%.1f%%)",
|
||||
metric.metricName, metricDelta, drainedPower, percent));
|
||||
}
|
||||
|
||||
public PowerMetrics.Metric getMetric(String metricType) {
|
||||
public PowerMetrics.Metric getPowerMetric(@BatteryConsumer.PowerComponent int component) {
|
||||
final String name = PowerMetrics.getPowerMetricName(component);
|
||||
for (PowerMetrics.Metric metric : mPowerMetricsDelta) {
|
||||
if (metric.metricType.equals(metricType)) {
|
||||
if (metric.metricName.equals(name)) {
|
||||
return metric;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public PowerMetrics.Metric getTimeMetric(@BatteryConsumer.TimeComponent int component) {
|
||||
final String name = PowerMetrics.getTimeMetricName(component);
|
||||
for (PowerMetrics.Metric metric : mPowerMetricsDelta) {
|
||||
if (metric.metricName.equals(name)) {
|
||||
return metric;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.os.BatteryConsumer;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
@@ -58,12 +58,12 @@ public class SystemServiceCallLoadTest {
|
||||
assertNotNull(resolveInfo);
|
||||
}
|
||||
|
||||
mPowerMetricsCollector.dumpMetrics();
|
||||
mPowerMetricsCollector.reportMetrics();
|
||||
|
||||
Log.i(TAG, "==");
|
||||
Log.i(TAG, "Total system server calls made " + mPowerMetricsCollector.getIterationCount());
|
||||
mPowerMetricsCollector.report(
|
||||
"Total system server calls made: " + mPowerMetricsCollector.getIterationCount());
|
||||
|
||||
mPowerMetricsCollector.dumpMetricAsPercentageOfDrainedPower(
|
||||
PowerMetrics.METRIC_SYSTEM_SERVICE_CPU_POWER);
|
||||
mPowerMetricsCollector.reportMetricAsPercentageOfDrainedPower(
|
||||
BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.android.frameworks.core.batterystatsloadtests;
|
||||
|
||||
import android.util.Log;
|
||||
import android.os.BatteryConsumer;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@@ -59,14 +59,15 @@ public class WiFiLoadTest {
|
||||
}
|
||||
}
|
||||
|
||||
mPowerMetricsCollector.dumpMetrics();
|
||||
mPowerMetricsCollector.reportMetrics();
|
||||
|
||||
Log.i(TAG, "==");
|
||||
Log.i(TAG, "WiFi running time: " + (long) mPowerMetricsCollector.getMetric(
|
||||
PowerMetrics.METRIC_WIFI_RUNNING_TIME).value);
|
||||
Log.i(TAG, "Total bytes read over WiFi: " + totalBytesRead);
|
||||
mPowerMetricsCollector.report(
|
||||
"WiFi running time: " + (long) mPowerMetricsCollector.getTimeMetric(
|
||||
BatteryConsumer.POWER_COMPONENT_WIFI).value);
|
||||
|
||||
mPowerMetricsCollector.dumpMetricAsPercentageOfDrainedPower(
|
||||
PowerMetrics.METRIC_WIFI_POWER);
|
||||
mPowerMetricsCollector.report("Total bytes read over WiFi: " + totalBytesRead);
|
||||
|
||||
mPowerMetricsCollector.reportMetricAsPercentageOfDrainedPower(
|
||||
BatteryConsumer.POWER_COMPONENT_WIFI);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user