| /* |
| * Copyright (C) 2021 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 android.cts.statsdatom.batterystats; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import android.cts.statsdatom.lib.AtomTestUtils; |
| import android.cts.statsdatom.lib.ConfigUtils; |
| import android.cts.statsdatom.lib.DeviceUtils; |
| import android.cts.statsdatom.lib.ReportUtils; |
| |
| import com.android.internal.os.StatsdConfigProto; |
| import com.android.os.AtomsProto; |
| import com.android.os.AtomsProto.BatteryUsageStatsAtomsProto; |
| import com.android.os.AtomsProto.BatteryUsageStatsAtomsProto.BatteryConsumerData; |
| import com.android.tradefed.build.IBuildInfo; |
| import com.android.tradefed.device.DeviceNotAvailableException; |
| import com.android.tradefed.testtype.DeviceTestCase; |
| import com.android.tradefed.testtype.IBuildReceiver; |
| |
| import java.util.List; |
| import java.util.function.Function; |
| |
| public class BatteryUsageStatsTests extends DeviceTestCase implements IBuildReceiver { |
| private IBuildInfo mCtsBuild; |
| |
| @Override |
| public void setBuild(IBuildInfo buildInfo) { |
| mCtsBuild = buildInfo; |
| } |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| assertThat(mCtsBuild).isNotNull(); |
| ConfigUtils.removeConfig(getDevice()); |
| ReportUtils.clearReports(getDevice()); |
| DeviceUtils.installStatsdTestApp(getDevice(), mCtsBuild); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| } |
| |
| @Override |
| protected void tearDown() throws Exception { |
| ConfigUtils.removeConfig(getDevice()); |
| ReportUtils.clearReports(getDevice()); |
| DeviceUtils.uninstallStatsdTestApp(getDevice()); |
| super.tearDown(); |
| } |
| |
| public void testBatteryUsageStatsSinceReset() throws Exception { |
| if (!hasBattery()) { |
| return; |
| } |
| |
| runBatteryUsageStatsAtomTest(AtomsProto.Atom.BATTERY_USAGE_STATS_SINCE_RESET_FIELD_NUMBER, |
| atom -> atom.getBatteryUsageStatsSinceReset().getBatteryUsageStats()); |
| } |
| |
| public void testBatteryUsageStatsSinceResetUsingPowerProfileModel() throws Exception { |
| if (!hasBattery()) { |
| return; |
| } |
| |
| runBatteryUsageStatsAtomTest( |
| AtomsProto.Atom.BATTERY_USAGE_STATS_SINCE_RESET_USING_POWER_PROFILE_MODEL_FIELD_NUMBER, |
| atom -> atom.getBatteryUsageStatsSinceResetUsingPowerProfileModel() |
| .getBatteryUsageStats()); |
| } |
| |
| private void runBatteryUsageStatsAtomTest(int atomFieldNumber, |
| Function<AtomsProto.Atom, BatteryUsageStatsAtomsProto> getter) throws Exception { |
| unplugDevice(); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| try { |
| DeviceUtils.runActivity(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| "StatsdCtsForegroundActivity", "action", "action.drain_power", 5_000); |
| } finally { |
| plugInDevice(); |
| } |
| |
| StatsdConfigProto.StatsdConfig.Builder config = |
| ConfigUtils.createConfigBuilder(DeviceUtils.STATSD_ATOM_TEST_PKG); |
| ConfigUtils.addGaugeMetric(config, atomFieldNumber); |
| ConfigUtils.uploadConfig(getDevice(), config); |
| |
| // Trigger atom pull. |
| AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| |
| final List<AtomsProto.Atom> atoms = ReportUtils.getGaugeMetricAtoms(getDevice()); |
| assertThat(atoms.size()).isAtLeast(1); |
| for (final AtomsProto.Atom atom : atoms) { |
| final BatteryUsageStatsAtomsProto batteryUsageStats = getter.apply(atom); |
| assertBatteryUsageStatsAtom(batteryUsageStats); |
| } |
| } |
| |
| private void assertBatteryUsageStatsAtom(BatteryUsageStatsAtomsProto batteryUsageStats) |
| throws Exception { |
| assertThat(batteryUsageStats.getSessionEndMillis()).isGreaterThan( |
| getDeviceTimeMs() - 5 * 60 * 1000); |
| assertThat(batteryUsageStats.getSessionDurationMillis()).isGreaterThan(0); |
| |
| final BatteryConsumerData deviceBatteryConsumer = |
| batteryUsageStats.getDeviceBatteryConsumer(); |
| assertThat(deviceBatteryConsumer.getTotalConsumedPowerDeciCoulombs()).isAtLeast(0); |
| for (BatteryConsumerData.PowerComponentUsage powerComponent : |
| deviceBatteryConsumer.getPowerComponentsList()) { |
| assertThat(powerComponent.getDurationMillis()).isAtLeast(0); |
| assertThat(powerComponent.getPowerDeciCoulombs()).isAtLeast(0); |
| } |
| |
| boolean hasAppData = false; |
| final List<BatteryUsageStatsAtomsProto.UidBatteryConsumer> uidBatteryConsumers = |
| batteryUsageStats.getUidBatteryConsumersList(); |
| for (BatteryUsageStatsAtomsProto.UidBatteryConsumer consumer : uidBatteryConsumers) { |
| if (consumer.getBatteryConsumerData().getTotalConsumedPowerDeciCoulombs() > 0 |
| || consumer.getTimeInForegroundMillis() > 0 |
| || consumer.getTimeInBackgroundMillis() > 0) { |
| hasAppData = true; |
| break; |
| } |
| } |
| |
| assertThat(hasAppData).isTrue(); |
| } |
| |
| private boolean hasBattery() throws DeviceNotAvailableException { |
| final String batteryinfo = getDevice().executeShellCommand("dumpsys battery"); |
| return batteryinfo.contains("present: true"); |
| } |
| |
| private void unplugDevice() throws Exception { |
| DeviceUtils.unplugDevice(getDevice()); |
| getDevice().executeShellCommand("dumpsys battery suspend_input"); |
| } |
| |
| private void plugInDevice() throws Exception { |
| DeviceUtils.resetBatteryStatus(getDevice()); |
| } |
| |
| private long getDeviceTimeMs() throws Exception { |
| final String timeMs = getDevice().executeShellCommand("date +%s%3N"); |
| return Long.parseLong(timeMs.trim()); |
| } |
| } |