2 * Copyright (C) 2017 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.android.settings.fuelgauge;
18 import android.content.Context;
19 import android.os.BatteryStats;
20 import android.os.Process;
21 import android.text.format.DateUtils;
23 import com.android.internal.os.BatterySipper;
24 import com.android.internal.os.BatteryStatsHelper;
25 import com.android.settings.SettingsRobolectricTestRunner;
26 import com.android.settings.TestConfig;
27 import com.android.settings.testutils.FakeFeatureFactory;
29 import org.junit.Before;
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 import org.mockito.Answers;
33 import org.mockito.Mock;
34 import org.mockito.MockitoAnnotations;
35 import org.robolectric.RuntimeEnvironment;
36 import org.robolectric.annotation.Config;
38 import java.util.ArrayList;
39 import java.util.List;
41 import static android.os.BatteryStats.Uid.PROCESS_STATE_BACKGROUND;
42 import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND;
43 import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE;
44 import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
45 import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING;
47 import static com.google.common.truth.Truth.assertThat;
49 import static org.mockito.Matchers.any;
50 import static org.mockito.Matchers.anyInt;
51 import static org.mockito.Matchers.anyLong;
52 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
53 import static org.mockito.Mockito.doNothing;
54 import static org.mockito.Mockito.doReturn;
55 import static org.mockito.Matchers.eq;
56 import static org.mockito.Mockito.mock;
57 import static org.mockito.Mockito.when;
58 import static org.mockito.Mockito.spy;
60 @RunWith(SettingsRobolectricTestRunner.class)
61 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
62 public class BatteryUtilsTest {
63 // unit that used to converted ms to us
64 private static final long UNIT = 1000;
65 private static final long TIME_STATE_TOP = 1500 * UNIT;
66 private static final long TIME_STATE_FOREGROUND_SERVICE = 2000 * UNIT;
67 private static final long TIME_STATE_TOP_SLEEPING = 2500 * UNIT;
68 private static final long TIME_STATE_FOREGROUND = 3000 * UNIT;
69 private static final long TIME_STATE_BACKGROUND = 6000 * UNIT;
70 private static final long TIME_FOREGROUND_ACTIVITY_ZERO = 0;
71 private static final long TIME_FOREGROUND_ACTIVITY = 100 * DateUtils.MINUTE_IN_MILLIS;
72 private static final long TIME_SINCE_LAST_FULL_CHARGE_MS = 120 * 60 * 1000;
73 private static final long TIME_SINCE_LAST_FULL_CHARGE_US =
74 TIME_SINCE_LAST_FULL_CHARGE_MS * 1000;
76 private static final int UID = 123;
77 private static final long TIME_EXPECTED_FOREGROUND = 1500;
78 private static final long TIME_EXPECTED_BACKGROUND = 6000;
79 private static final long TIME_EXPECTED_ALL = 7500;
80 private static final double BATTERY_SCREEN_USAGE = 300;
81 private static final double BATTERY_SYSTEM_USAGE = 600;
82 private static final double BATTERY_OVERACCOUNTED_USAGE = 500;
83 private static final double BATTERY_UNACCOUNTED_USAGE = 700;
84 private static final double BATTERY_APP_USAGE = 100;
85 private static final double TOTAL_BATTERY_USAGE = 1000;
86 private static final double HIDDEN_USAGE = 200;
87 private static final int DISCHARGE_AMOUNT = 80;
88 private static final double PERCENT_SYSTEM_USAGE = 60;
89 private static final double PRECISION = 0.001;
92 private BatteryStats.Uid mUid;
94 private BatterySipper mNormalBatterySipper;
96 private BatterySipper mScreenBatterySipper;
98 private BatterySipper mOvercountedBatterySipper;
100 private BatterySipper mUnaccountedBatterySipper;
102 private BatterySipper mSystemBatterySipper;
104 private BatterySipper mCellBatterySipper;
105 @Mock(answer = Answers.RETURNS_DEEP_STUBS)
106 private Context mContext;
107 @Mock(answer = Answers.RETURNS_DEEP_STUBS)
108 private BatteryStatsHelper mBatteryStatsHelper;
109 private BatteryUtils mBatteryUtils;
110 private FakeFeatureFactory mFeatureFactory;
111 private PowerUsageFeatureProvider mProvider;
114 public void setUp() {
115 MockitoAnnotations.initMocks(this);
117 FakeFeatureFactory.setupForTest(mContext);
118 mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
119 mProvider = mFeatureFactory.powerUsageFeatureProvider;
121 doReturn(TIME_STATE_TOP).when(mUid).getProcessStateTime(eq(PROCESS_STATE_TOP), anyLong(),
123 doReturn(TIME_STATE_FOREGROUND_SERVICE).when(mUid).getProcessStateTime(
124 eq(PROCESS_STATE_FOREGROUND_SERVICE), anyLong(), anyInt());
125 doReturn(TIME_STATE_TOP_SLEEPING).when(mUid).getProcessStateTime(
126 eq(PROCESS_STATE_TOP_SLEEPING), anyLong(), anyInt());
127 doReturn(TIME_STATE_FOREGROUND).when(mUid).getProcessStateTime(eq(PROCESS_STATE_FOREGROUND),
128 anyLong(), anyInt());
129 doReturn(TIME_STATE_BACKGROUND).when(mUid).getProcessStateTime(eq(PROCESS_STATE_BACKGROUND),
130 anyLong(), anyInt());
131 when(mBatteryStatsHelper.getStats().computeBatteryRealtime(anyLong(), anyInt())).thenReturn(
132 TIME_SINCE_LAST_FULL_CHARGE_US);
134 mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
135 mNormalBatterySipper.totalPowerMah = TOTAL_BATTERY_USAGE;
137 mScreenBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
138 mScreenBatterySipper.totalPowerMah = BATTERY_SCREEN_USAGE;
140 mSystemBatterySipper.drainType = BatterySipper.DrainType.APP;
141 mSystemBatterySipper.totalPowerMah = BATTERY_SYSTEM_USAGE;
142 when(mSystemBatterySipper.getUid()).thenReturn(Process.SYSTEM_UID);
144 mOvercountedBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
145 mOvercountedBatterySipper.totalPowerMah = BATTERY_OVERACCOUNTED_USAGE;
147 mUnaccountedBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
148 mUnaccountedBatterySipper.totalPowerMah = BATTERY_UNACCOUNTED_USAGE;
150 mBatteryUtils = BatteryUtils.getInstance(RuntimeEnvironment.application);
151 mBatteryUtils.mPowerUsageFeatureProvider = mProvider;
153 mBatteryUtils = spy(new BatteryUtils(RuntimeEnvironment.application));
157 public void testGetProcessTimeMs_typeForeground_timeCorrect() {
158 final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.FOREGROUND, mUid,
159 BatteryStats.STATS_SINCE_CHARGED);
161 assertThat(time).isEqualTo(TIME_EXPECTED_FOREGROUND);
165 public void testGetProcessTimeMs_typeBackground_timeCorrect() {
166 final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.BACKGROUND, mUid,
167 BatteryStats.STATS_SINCE_CHARGED);
169 assertThat(time).isEqualTo(TIME_EXPECTED_BACKGROUND);
173 public void testGetProcessTimeMs_typeAll_timeCorrect() {
174 final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.ALL, mUid,
175 BatteryStats.STATS_SINCE_CHARGED);
177 assertThat(time).isEqualTo(TIME_EXPECTED_ALL);
181 public void testGetProcessTimeMs_uidNull_returnZero() {
182 final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.ALL, null,
183 BatteryStats.STATS_SINCE_CHARGED);
185 assertThat(time).isEqualTo(0);
189 public void testRemoveHiddenBatterySippers_ContainsHiddenSippers_RemoveAndReturnValue() {
190 final List<BatterySipper> sippers = new ArrayList<>();
191 sippers.add(mNormalBatterySipper);
192 sippers.add(mScreenBatterySipper);
193 sippers.add(mSystemBatterySipper);
194 sippers.add(mOvercountedBatterySipper);
195 sippers.add(mUnaccountedBatterySipper);
196 when(mProvider.isTypeSystem(mSystemBatterySipper))
198 doNothing().when(mBatteryUtils).smearScreenBatterySipper(any(), any());
200 final double totalUsage = mBatteryUtils.removeHiddenBatterySippers(sippers);
202 assertThat(sippers).containsExactly(mNormalBatterySipper);
203 assertThat(totalUsage).isWithin(PRECISION).of(BATTERY_SYSTEM_USAGE);
207 public void testShouldHideSipper_TypeUnAccounted_ReturnTrue() {
208 mNormalBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
209 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
213 public void testShouldHideSipper_TypeOverAccounted_ReturnTrue() {
214 mNormalBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
215 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
219 public void testShouldHideSipper_TypeIdle_ReturnTrue() {
220 mNormalBatterySipper.drainType = BatterySipper.DrainType.IDLE;
221 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
225 public void testShouldHideSipper_TypeCell_ReturnTrue() {
226 mNormalBatterySipper.drainType = BatterySipper.DrainType.CELL;
227 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
231 public void testShouldHideSipper_TypeScreen_ReturnTrue() {
232 mNormalBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
233 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
237 public void testShouldHideSipper_TypeSystem_ReturnTrue() {
238 mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
239 when(mNormalBatterySipper.getUid()).thenReturn(Process.ROOT_UID);
240 when(mProvider.isTypeSystem(any())).thenReturn(true);
241 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
245 public void testShouldHideSipper_UidNormal_ReturnFalse() {
246 mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
247 when(mNormalBatterySipper.getUid()).thenReturn(UID);
248 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isFalse();
252 public void testShouldHideSipper_TypeService_ReturnTrue() {
253 mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
254 when(mNormalBatterySipper.getUid()).thenReturn(UID);
255 when(mProvider.isTypeService(any())).thenReturn(true);
257 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
261 public void testCalculateBatteryPercent() {
262 assertThat(mBatteryUtils.calculateBatteryPercent(BATTERY_SYSTEM_USAGE, TOTAL_BATTERY_USAGE,
263 HIDDEN_USAGE, DISCHARGE_AMOUNT))
264 .isWithin(PRECISION).of(PERCENT_SYSTEM_USAGE);
268 public void testSmearScreenBatterySipper() {
269 final BatterySipper sipperNull = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
270 BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */);
271 final BatterySipper sipperBg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
272 BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */);
273 final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY,
274 BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */);
276 final List<BatterySipper> sippers = new ArrayList<>();
277 sippers.add(sipperNull);
278 sippers.add(sipperBg);
279 sippers.add(sipperFg);
281 mBatteryUtils.smearScreenBatterySipper(sippers, mScreenBatterySipper);
283 assertThat(sipperNull.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE);
284 assertThat(sipperBg.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE);
285 assertThat(sipperFg.totalPowerMah).isWithin(PRECISION).of(
286 BATTERY_APP_USAGE + BATTERY_SCREEN_USAGE);
290 public void testCalculateRunningTimeBasedOnStatsType() {
291 assertThat(mBatteryUtils.calculateRunningTimeBasedOnStatsType(mBatteryStatsHelper,
292 BatteryStats.STATS_SINCE_CHARGED)).isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS);
296 public void testSortUsageList() {
297 final List<BatterySipper> sippers = new ArrayList<>();
298 sippers.add(mNormalBatterySipper);
299 sippers.add(mScreenBatterySipper);
300 sippers.add(mSystemBatterySipper);
302 mBatteryUtils.sortUsageList(sippers);
304 assertThat(sippers).containsExactly(mNormalBatterySipper, mSystemBatterySipper,
305 mScreenBatterySipper);
309 public void testCalculateLastFullChargeTime() {
310 final long currentTimeMs = System.currentTimeMillis();
311 when(mBatteryStatsHelper.getStats().getStartClockTime()).thenReturn(
312 currentTimeMs - TIME_SINCE_LAST_FULL_CHARGE_MS);
314 assertThat(mBatteryUtils.calculateLastFullChargeTime(
315 mBatteryStatsHelper, currentTimeMs)).isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS);
318 private BatterySipper createTestSmearBatterySipper(long activityTime, double totalPowerMah,
319 int uidCode, boolean isUidNull) {
320 final BatterySipper sipper = mock(BatterySipper.class);
321 sipper.drainType = BatterySipper.DrainType.APP;
322 sipper.totalPowerMah = totalPowerMah;
323 doReturn(uidCode).when(sipper).getUid();
325 final BatteryStats.Uid uid = mock(BatteryStats.Uid.class, RETURNS_DEEP_STUBS);
326 doReturn(activityTime).when(mBatteryUtils).getForegroundActivityTotalTimeMs(eq(uid),
328 doReturn(uidCode).when(uid).getUid();