• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.android.settings.fuelgauge;
17 
18 import android.content.Context;
19 import android.os.BatteryStats;
20 import android.os.Process;
21 import android.text.format.DateUtils;
22 
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;
28 
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;
37 
38 import java.util.ArrayList;
39 import java.util.List;
40 
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;
46 
47 import static com.google.common.truth.Truth.assertThat;
48 
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;
59 
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 
74     private static final int UID = 123;
75     private static final long TIME_EXPECTED_FOREGROUND = 1500;
76     private static final long TIME_EXPECTED_BACKGROUND = 6000;
77     private static final long TIME_EXPECTED_ALL = 7500;
78     private static final double BATTERY_SCREEN_USAGE = 300;
79     private static final double BATTERY_SYSTEM_USAGE = 600;
80     private static final double BATTERY_OVERACCOUNTED_USAGE = 500;
81     private static final double BATTERY_UNACCOUNTED_USAGE = 700;
82     private static final double BATTERY_APP_USAGE = 100;
83     private static final double BATTERY_WIFI_USAGE = 200;
84     private static final double BATTERY_BLUETOOTH_USAGE = 300;
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;
90 
91     @Mock
92     private BatteryStats.Uid mUid;
93     @Mock
94     private BatterySipper mNormalBatterySipper;
95     @Mock
96     private BatterySipper mWifiBatterySipper;
97     @Mock
98     private BatterySipper mBluetoothBatterySipper;
99     @Mock
100     private BatterySipper mScreenBatterySipper;
101     @Mock
102     private BatterySipper mOvercountedBatterySipper;
103     @Mock
104     private BatterySipper mUnaccountedBatterySipper;
105     @Mock
106     private BatterySipper mSystemBatterySipper;
107     @Mock
108     private BatterySipper mCellBatterySipper;
109     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
110     private Context mContext;
111     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
112     private BatteryStatsHelper mBatteryStatsHelper;
113     private BatteryUtils mBatteryUtils;
114     private FakeFeatureFactory mFeatureFactory;
115     private PowerUsageFeatureProvider mProvider;
116 
117     @Before
setUp()118     public void setUp() {
119         MockitoAnnotations.initMocks(this);
120 
121         FakeFeatureFactory.setupForTest(mContext);
122         mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
123         mProvider = mFeatureFactory.powerUsageFeatureProvider;
124 
125         doReturn(TIME_STATE_TOP).when(mUid).getProcessStateTime(eq(PROCESS_STATE_TOP), anyLong(),
126                 anyInt());
127         doReturn(TIME_STATE_FOREGROUND_SERVICE).when(mUid).getProcessStateTime(
128                 eq(PROCESS_STATE_FOREGROUND_SERVICE), anyLong(), anyInt());
129         doReturn(TIME_STATE_TOP_SLEEPING).when(mUid).getProcessStateTime(
130                 eq(PROCESS_STATE_TOP_SLEEPING), anyLong(), anyInt());
131         doReturn(TIME_STATE_FOREGROUND).when(mUid).getProcessStateTime(eq(PROCESS_STATE_FOREGROUND),
132                 anyLong(), anyInt());
133         doReturn(TIME_STATE_BACKGROUND).when(mUid).getProcessStateTime(eq(PROCESS_STATE_BACKGROUND),
134                 anyLong(), anyInt());
135 
136         mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
137         mNormalBatterySipper.totalPowerMah = TOTAL_BATTERY_USAGE;
138 
139         mWifiBatterySipper.drainType = BatterySipper.DrainType.WIFI;
140         mWifiBatterySipper.totalPowerMah = BATTERY_WIFI_USAGE;
141 
142         mBluetoothBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH;
143         mBluetoothBatterySipper.totalPowerMah = BATTERY_BLUETOOTH_USAGE;
144 
145         mScreenBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
146         mScreenBatterySipper.totalPowerMah = BATTERY_SCREEN_USAGE;
147 
148         mSystemBatterySipper.drainType = BatterySipper.DrainType.APP;
149         mSystemBatterySipper.totalPowerMah = BATTERY_SYSTEM_USAGE;
150         when(mSystemBatterySipper.getUid()).thenReturn(Process.SYSTEM_UID);
151 
152         mOvercountedBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
153         mOvercountedBatterySipper.totalPowerMah = BATTERY_OVERACCOUNTED_USAGE;
154 
155         mUnaccountedBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
156         mUnaccountedBatterySipper.totalPowerMah = BATTERY_UNACCOUNTED_USAGE;
157 
158         mBatteryUtils = BatteryUtils.getInstance(RuntimeEnvironment.application);
159         mBatteryUtils.mPowerUsageFeatureProvider = mProvider;
160 
161         mBatteryUtils = spy(new BatteryUtils(RuntimeEnvironment.application));
162     }
163 
164     @Test
testGetProcessTimeMs_typeForeground_timeCorrect()165     public void testGetProcessTimeMs_typeForeground_timeCorrect() {
166         final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.FOREGROUND, mUid,
167                 BatteryStats.STATS_SINCE_CHARGED);
168 
169         assertThat(time).isEqualTo(TIME_EXPECTED_FOREGROUND);
170     }
171 
172     @Test
testGetProcessTimeMs_typeBackground_timeCorrect()173     public void testGetProcessTimeMs_typeBackground_timeCorrect() {
174         final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.BACKGROUND, mUid,
175                 BatteryStats.STATS_SINCE_CHARGED);
176 
177         assertThat(time).isEqualTo(TIME_EXPECTED_BACKGROUND);
178     }
179 
180     @Test
testGetProcessTimeMs_typeAll_timeCorrect()181     public void testGetProcessTimeMs_typeAll_timeCorrect() {
182         final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.ALL, mUid,
183                 BatteryStats.STATS_SINCE_CHARGED);
184 
185         assertThat(time).isEqualTo(TIME_EXPECTED_ALL);
186     }
187 
188     @Test
testGetProcessTimeMs_uidNull_returnZero()189     public void testGetProcessTimeMs_uidNull_returnZero() {
190         final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.ALL, null,
191                 BatteryStats.STATS_SINCE_CHARGED);
192 
193         assertThat(time).isEqualTo(0);
194     }
195 
196     @Test
testRemoveHiddenBatterySippers_ContainsHiddenSippers_RemoveAndReturnValue()197     public void testRemoveHiddenBatterySippers_ContainsHiddenSippers_RemoveAndReturnValue() {
198         final List<BatterySipper> sippers = new ArrayList<>();
199         sippers.add(mNormalBatterySipper);
200         sippers.add(mScreenBatterySipper);
201         sippers.add(mSystemBatterySipper);
202         sippers.add(mOvercountedBatterySipper);
203         sippers.add(mUnaccountedBatterySipper);
204         sippers.add(mWifiBatterySipper);
205         sippers.add(mBluetoothBatterySipper);
206         when(mProvider.isTypeSystem(mSystemBatterySipper))
207                 .thenReturn(true);
208         doNothing().when(mBatteryUtils).smearScreenBatterySipper(any(), any());
209 
210         final double totalUsage = mBatteryUtils.removeHiddenBatterySippers(sippers);
211 
212         assertThat(sippers).containsExactly(mNormalBatterySipper);
213         assertThat(totalUsage).isWithin(PRECISION).of(BATTERY_SYSTEM_USAGE);
214     }
215 
216     @Test
testShouldHideSipper_TypeUnAccounted_ReturnTrue()217     public void testShouldHideSipper_TypeUnAccounted_ReturnTrue() {
218         mNormalBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
219         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
220     }
221 
222     @Test
testShouldHideSipper_TypeOverAccounted_ReturnTrue()223     public void testShouldHideSipper_TypeOverAccounted_ReturnTrue() {
224         mNormalBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
225         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
226     }
227 
228     @Test
testShouldHideSipper_TypeIdle_ReturnTrue()229     public void testShouldHideSipper_TypeIdle_ReturnTrue() {
230         mNormalBatterySipper.drainType = BatterySipper.DrainType.IDLE;
231         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
232     }
233 
234     @Test
testShouldHideSipper_TypeCell_ReturnTrue()235     public void testShouldHideSipper_TypeCell_ReturnTrue() {
236         mNormalBatterySipper.drainType = BatterySipper.DrainType.CELL;
237         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
238     }
239 
240     @Test
testShouldHideSipper_TypeScreen_ReturnTrue()241     public void testShouldHideSipper_TypeScreen_ReturnTrue() {
242         mNormalBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
243         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
244     }
245 
246     @Test
testShouldHideSipper_TypeWifi_ReturnTrue()247     public void testShouldHideSipper_TypeWifi_ReturnTrue() {
248         mNormalBatterySipper.drainType = BatterySipper.DrainType.WIFI;
249         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
250     }
251 
252     @Test
testShouldHideSipper_TypeBluetooth_ReturnTrue()253     public void testShouldHideSipper_TypeBluetooth_ReturnTrue() {
254         mNormalBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH;
255         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
256     }
257 
258     @Test
testShouldHideSipper_TypeSystem_ReturnTrue()259     public void testShouldHideSipper_TypeSystem_ReturnTrue() {
260         mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
261         when(mNormalBatterySipper.getUid()).thenReturn(Process.ROOT_UID);
262         when(mProvider.isTypeSystem(any())).thenReturn(true);
263         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
264     }
265 
266     @Test
testShouldHideSipper_UidNormal_ReturnFalse()267     public void testShouldHideSipper_UidNormal_ReturnFalse() {
268         mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
269         when(mNormalBatterySipper.getUid()).thenReturn(UID);
270         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isFalse();
271     }
272 
273     @Test
testShouldHideSipper_TypeService_ReturnTrue()274     public void testShouldHideSipper_TypeService_ReturnTrue() {
275         mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
276         when(mNormalBatterySipper.getUid()).thenReturn(UID);
277         when(mProvider.isTypeService(any())).thenReturn(true);
278 
279         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
280     }
281 
282     @Test
testCalculateBatteryPercent()283     public void testCalculateBatteryPercent() {
284         assertThat(mBatteryUtils.calculateBatteryPercent(BATTERY_SYSTEM_USAGE, TOTAL_BATTERY_USAGE,
285                 HIDDEN_USAGE, DISCHARGE_AMOUNT))
286                 .isWithin(PRECISION).of(PERCENT_SYSTEM_USAGE);
287     }
288 
289     @Test
testSmearScreenBatterySipper()290     public void testSmearScreenBatterySipper() {
291         final BatterySipper sipperNull = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
292                 BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */);
293         final BatterySipper sipperBg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
294                 BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */);
295         final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY,
296                 BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */);
297 
298         final List<BatterySipper> sippers = new ArrayList<>();
299         sippers.add(sipperNull);
300         sippers.add(sipperBg);
301         sippers.add(sipperFg);
302 
303         mBatteryUtils.smearScreenBatterySipper(sippers, mScreenBatterySipper);
304 
305         assertThat(sipperNull.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE);
306         assertThat(sipperBg.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE);
307         assertThat(sipperFg.totalPowerMah).isWithin(PRECISION).of(
308                 BATTERY_APP_USAGE + BATTERY_SCREEN_USAGE);
309     }
310 
311     @Test
testSortUsageList()312     public void testSortUsageList() {
313         final List<BatterySipper> sippers = new ArrayList<>();
314         sippers.add(mNormalBatterySipper);
315         sippers.add(mScreenBatterySipper);
316         sippers.add(mSystemBatterySipper);
317 
318         mBatteryUtils.sortUsageList(sippers);
319 
320         assertThat(sippers).containsExactly(mNormalBatterySipper, mSystemBatterySipper,
321                 mScreenBatterySipper);
322     }
323 
324     @Test
testCalculateLastFullChargeTime()325     public void testCalculateLastFullChargeTime() {
326         final long currentTimeMs = System.currentTimeMillis();
327         when(mBatteryStatsHelper.getStats().getStartClockTime()).thenReturn(
328                 currentTimeMs - TIME_SINCE_LAST_FULL_CHARGE_MS);
329 
330         assertThat(mBatteryUtils.calculateLastFullChargeTime(
331                 mBatteryStatsHelper, currentTimeMs)).isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS);
332     }
333 
createTestSmearBatterySipper(long activityTime, double totalPowerMah, int uidCode, boolean isUidNull)334     private BatterySipper createTestSmearBatterySipper(long activityTime, double totalPowerMah,
335             int uidCode, boolean isUidNull) {
336         final BatterySipper sipper = mock(BatterySipper.class);
337         sipper.drainType = BatterySipper.DrainType.APP;
338         sipper.totalPowerMah = totalPowerMah;
339         doReturn(uidCode).when(sipper).getUid();
340         if (!isUidNull) {
341             final BatteryStats.Uid uid = mock(BatteryStats.Uid.class, RETURNS_DEEP_STUBS);
342             doReturn(activityTime).when(mBatteryUtils).getForegroundActivityTotalTimeMs(eq(uid),
343                     anyLong());
344             doReturn(uidCode).when(uid).getUid();
345             sipper.uidObj = uid;
346         }
347 
348         return sipper;
349     }
350 }
351