Merge "Add a perf test for BatteryStatsHelper"

This commit is contained in:
Dmitri Plotnikov
2020-11-20 22:56:26 +00:00
committed by Android (Google) Code Review
7 changed files with 243 additions and 11 deletions

View File

@@ -52,7 +52,7 @@ interface IBatteryStats {
@UnsupportedAppUsage
byte[] getStatistics();
ParcelFileDescriptor getStatisticsStream();
ParcelFileDescriptor getStatisticsStream(boolean updateAll);
// Return true if we see the battery as currently charging.
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)

View File

@@ -203,7 +203,7 @@ public class BatteryStatsHelper {
}
}
return getStats(IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME)));
ServiceManager.getService(BatteryStats.SERVICE_NAME)), true);
}
@UnsupportedAppUsage
@@ -223,8 +223,13 @@ public class BatteryStatsHelper {
@UnsupportedAppUsage
public BatteryStats getStats() {
return getStats(true /* updateAll */);
}
/** Retrieves stats from BatteryService, optionally getting updated numbers */
public BatteryStats getStats(boolean updateAll) {
if (mStats == null) {
load();
load(updateAll);
}
return mStats;
}
@@ -720,19 +725,23 @@ public class BatteryStatsHelper {
@UnsupportedAppUsage
private void load() {
load(true);
}
private void load(boolean updateAll) {
if (mBatteryInfo == null) {
return;
}
mStats = getStats(mBatteryInfo);
mStats = getStats(mBatteryInfo, updateAll);
if (mCollectBatteryBroadcast) {
mBatteryBroadcast = mContext.registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
}
private static BatteryStatsImpl getStats(IBatteryStats service) {
private static BatteryStatsImpl getStats(IBatteryStats service, boolean updateAll) {
try {
ParcelFileDescriptor pfd = service.getStatisticsStream();
ParcelFileDescriptor pfd = service.getStatisticsStream(updateAll);
if (pfd != null) {
if (false) {
Log.d(TAG, "selinux context: "

View File

@@ -519,16 +519,24 @@ public final class BatteryStatsService extends IBatteryStats.Stub
return data;
}
public ParcelFileDescriptor getStatisticsStream() {
/**
* Returns parceled BatteryStats as a MemoryFile.
*
* @param forceUpdate If true, runs a sync to get fresh battery stats. Otherwise,
* returns the current values.
*/
public ParcelFileDescriptor getStatisticsStream(boolean forceUpdate) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BATTERY_STATS, null);
//Slog.i("foo", "SENDING BATTERY INFO:");
//mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
Parcel out = Parcel.obtain();
// Drain the handler queue to make sure we've handled all pending works, so we'll get
// an accurate stats.
awaitCompletion();
syncStats("get-stats", BatteryExternalStatsWorker.UPDATE_ALL);
if (forceUpdate) {
// Drain the handler queue to make sure we've handled all pending works, so we'll get
// an accurate stats.
awaitCompletion();
syncStats("get-stats", BatteryExternalStatsWorker.UPDATE_ALL);
}
synchronized (mStats) {
mStats.writeToParcel(out, 0);
}

View File

@@ -0,0 +1,25 @@
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
android_test {
name: "BatteryStatsPerfTests",
srcs: ["src/**/*.java"],
static_libs: [
"androidx.test.rules",
"apct-perftests-utils",
"truth-prebuilt",
],
platform_apis: true,
certificate: "platform",
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.perftests.batterystats">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.BATTERY_STATS"/>
<application>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.frameworks.perftests.batterystats"/>
</manifest>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<configuration description="Runs BatteryStats service Performance Tests">
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="BatteryStatsPerfTests.apk"/>
<option name="cleanup-apks" value="true"/>
</target_preparer>
<option name="test-suite-tag" value="apct"/>
<option name="test-tag" value="BatteryStatsPerfTests"/>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.frameworks.perftests.batterystats"/>
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
</test>
</configuration>

View File

@@ -0,0 +1,135 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.os;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.BatteryStats;
import android.os.Bundle;
import android.os.UserHandle;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class BatteryStatsHelperPerfTest {
@Rule
public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
/**
* Measures the performance of {@link BatteryStatsHelper#getStats()}, which triggers
* a battery stats sync on every iteration.
*/
@Test
public void testGetStats_forceUpdate() {
final Context context = InstrumentationRegistry.getContext();
final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
true /* collectBatteryBroadcast */);
statsHelper.create((Bundle) null);
statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
statsHelper.clearStats();
state.resumeTiming();
statsHelper.getStats();
assertThat(statsHelper.getUsageList()).isNotEmpty();
}
}
/**
* Measures performance of the {@link BatteryStatsHelper#getStats(boolean)}, which does
* not trigger a sync and just returns current values.
*/
@Test
public void testGetStats_cached() {
final Context context = InstrumentationRegistry.getContext();
final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
true /* collectBatteryBroadcast */);
statsHelper.create((Bundle) null);
statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
statsHelper.clearStats();
state.resumeTiming();
statsHelper.getStats(false /* forceUpdate */);
assertThat(statsHelper.getUsageList()).isNotEmpty();
}
}
@Test
public void testPowerCalculation() {
final Context context = InstrumentationRegistry.getContext();
final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
true /* collectBatteryBroadcast */);
statsHelper.create((Bundle) null);
statsHelper.getStats();
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
// This will use the cached BatteryStatsObject
statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
assertThat(statsHelper.getUsageList()).isNotEmpty();
}
}
@Test
public void testEndToEnd() {
final Context context = InstrumentationRegistry.getContext();
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
true /* collectBatteryBroadcast */);
statsHelper.create((Bundle) null);
statsHelper.clearStats();
statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
state.pauseTiming();
List<BatterySipper> usageList = statsHelper.getUsageList();
double power = 0;
for (int i = 0; i < usageList.size(); i++) {
BatterySipper sipper = usageList.get(i);
power += sipper.sumPower();
}
assertThat(power).isGreaterThan(0.0);
state.resumeTiming();
}
}
}