• 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 static android.os.BatteryStats.Uid.PROCESS_STATE_BACKGROUND;
19 import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND;
20 import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE;
21 import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
22 import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING;
23 
24 import static com.google.common.truth.Truth.assertThat;
25 
26 import static org.mockito.ArgumentMatchers.any;
27 import static org.mockito.ArgumentMatchers.anyInt;
28 import static org.mockito.ArgumentMatchers.anyLong;
29 import static org.mockito.ArgumentMatchers.eq;
30 import static org.mockito.ArgumentMatchers.nullable;
31 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
32 import static org.mockito.Mockito.doNothing;
33 import static org.mockito.Mockito.doReturn;
34 import static org.mockito.Mockito.doThrow;
35 import static org.mockito.Mockito.mock;
36 import static org.mockito.Mockito.never;
37 import static org.mockito.Mockito.spy;
38 import static org.mockito.Mockito.verify;
39 import static org.mockito.Mockito.when;
40 
41 import android.app.AppOpsManager;
42 import android.content.BroadcastReceiver;
43 import android.content.Context;
44 import android.content.Intent;
45 import android.content.IntentFilter;
46 import android.content.pm.ActivityInfo;
47 import android.content.pm.ApplicationInfo;
48 import android.content.pm.PackageManager;
49 import android.content.pm.ResolveInfo;
50 import android.os.BatteryStats;
51 import android.os.Build;
52 import android.os.Bundle;
53 import android.os.Process;
54 import android.os.SystemClock;
55 import android.os.UserManager;
56 import android.text.format.DateUtils;
57 
58 import com.android.internal.os.BatterySipper;
59 import com.android.internal.os.BatteryStatsHelper;
60 import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
61 import com.android.settings.fuelgauge.batterytip.AnomalyInfo;
62 import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
63 import com.android.settings.testutils.FakeFeatureFactory;
64 import com.android.settings.testutils.shadow.ShadowThreadUtils;
65 import com.android.settingslib.fuelgauge.Estimate;
66 import com.android.settingslib.fuelgauge.PowerWhitelistBackend;
67 
68 import org.junit.Before;
69 import org.junit.Test;
70 import org.junit.runner.RunWith;
71 import org.mockito.Answers;
72 import org.mockito.Mock;
73 import org.mockito.MockitoAnnotations;
74 import org.robolectric.RobolectricTestRunner;
75 import org.robolectric.RuntimeEnvironment;
76 
77 import java.util.ArrayList;
78 import java.util.List;
79 
80 @RunWith(RobolectricTestRunner.class)
81 public class BatteryUtilsTest {
82 
83     private static final String TAG = "BatteryUtilsTest";
84 
85     // unit that used to converted ms to us
86     private static final long UNIT = 1000;
87     private static final long TIME_STATE_TOP = 1500 * UNIT;
88     private static final long TIME_STATE_FOREGROUND_SERVICE = 2000 * UNIT;
89     private static final long TIME_STATE_TOP_SLEEPING = 2500 * UNIT;
90     private static final long TIME_STATE_FOREGROUND = 3000 * UNIT;
91     private static final long TIME_STATE_BACKGROUND = 6000 * UNIT;
92     private static final long TIME_FOREGROUND_ZERO = 0;
93     private static final long TIME_FOREGROUND = 100 * DateUtils.MINUTE_IN_MILLIS;
94     private static final long TIME_SINCE_LAST_FULL_CHARGE_MS = 120 * 60 * 1000;
95     private static final long TIME_SINCE_LAST_FULL_CHARGE_US =
96             TIME_SINCE_LAST_FULL_CHARGE_MS * 1000;
97 
98     private static final int UID = 12345;
99     private static final long TIME_EXPECTED_FOREGROUND = 1500;
100     private static final long TIME_EXPECTED_BACKGROUND = 6000;
101     private static final long TIME_EXPECTED_ALL = 7500;
102     private static final double BATTERY_SCREEN_USAGE = 300;
103     private static final double BATTERY_IDLE_USAGE = 600;
104     private static final double BATTERY_SYSTEM_USAGE = 600;
105     private static final double BATTERY_OVERACCOUNTED_USAGE = 500;
106     private static final double BATTERY_UNACCOUNTED_USAGE = 700;
107     private static final double BATTERY_APP_USAGE = 100;
108     private static final double BATTERY_WIFI_USAGE = 200;
109     private static final double BATTERY_BLUETOOTH_USAGE = 300;
110     private static final double TOTAL_BATTERY_USAGE = 1000;
111     private static final double HIDDEN_USAGE = 200;
112     private static final int DISCHARGE_AMOUNT = 80;
113     private static final double PERCENT_SYSTEM_USAGE = 60;
114     private static final double PRECISION = 0.001;
115     private static final int SDK_VERSION = Build.VERSION_CODES.L;
116     private static final String PACKAGE_NAME = "com.android.app";
117     private static final String HIGH_SDK_PACKAGE = "com.android.package.high";
118     private static final String LOW_SDK_PACKAGE = "com.android.package.low";
119 
120     private static final String INFO_EXCESSIVE = "anomaly_type=4,auto_restriction=false";
121     private static final String INFO_WAKELOCK = "anomaly_type=1,auto_restriction=false";
122 
123     @Mock
124     private BatteryStats.Uid mUid;
125     @Mock
126     private BatteryStats.Timer mTimer;
127     @Mock
128     private BatterySipper mNormalBatterySipper;
129     @Mock
130     private BatterySipper mWifiBatterySipper;
131     @Mock
132     private BatterySipper mBluetoothBatterySipper;
133     @Mock
134     private BatterySipper mScreenBatterySipper;
135     @Mock
136     private BatterySipper mOvercountedBatterySipper;
137     @Mock
138     private BatterySipper mUnaccountedBatterySipper;
139     @Mock
140     private BatterySipper mSystemBatterySipper;
141     @Mock
142     private BatterySipper mCellBatterySipper;
143     @Mock
144     private BatterySipper mIdleBatterySipper;
145     @Mock
146     private Bundle mBundle;
147     @Mock
148     private UserManager mUserManager;
149     @Mock
150     private PackageManager mPackageManager;
151     @Mock
152     private AppOpsManager mAppOpsManager;
153     @Mock
154     private ApplicationInfo mApplicationInfo;
155     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
156     private BatteryStatsHelper mBatteryStatsHelper;
157     @Mock
158     private ApplicationInfo mHighApplicationInfo;
159     @Mock
160     private ApplicationInfo mLowApplicationInfo;
161     @Mock
162     private PowerWhitelistBackend mPowerWhitelistBackend;
163     @Mock
164     private BatteryDatabaseManager mBatteryDatabaseManager;
165     private AnomalyInfo mAnomalyInfo;
166     private BatteryUtils mBatteryUtils;
167     private FakeFeatureFactory mFeatureFactory;
168     private PowerUsageFeatureProvider mProvider;
169     private List<BatterySipper> mUsageList;
170     private Context mContext;
171 
172     @Before
setUp()173     public void setUp() throws PackageManager.NameNotFoundException {
174         MockitoAnnotations.initMocks(this);
175 
176         mFeatureFactory = FakeFeatureFactory.setupForTest();
177         mProvider = mFeatureFactory.powerUsageFeatureProvider;
178 
179         doReturn(TIME_STATE_TOP).when(mUid).getProcessStateTime(eq(PROCESS_STATE_TOP), anyLong(),
180                 anyInt());
181         doReturn(TIME_STATE_FOREGROUND_SERVICE).when(mUid).getProcessStateTime(
182                 eq(PROCESS_STATE_FOREGROUND_SERVICE), anyLong(), anyInt());
183         doReturn(TIME_STATE_TOP_SLEEPING).when(mUid).getProcessStateTime(
184                 eq(PROCESS_STATE_TOP_SLEEPING), anyLong(), anyInt());
185         doReturn(TIME_STATE_FOREGROUND).when(mUid).getProcessStateTime(eq(PROCESS_STATE_FOREGROUND),
186                 anyLong(), anyInt());
187         doReturn(TIME_STATE_BACKGROUND).when(mUid).getProcessStateTime(eq(PROCESS_STATE_BACKGROUND),
188                 anyLong(), anyInt());
189         when(mBatteryStatsHelper.getStats().computeBatteryRealtime(anyLong(), anyInt())).thenReturn(
190                 TIME_SINCE_LAST_FULL_CHARGE_US);
191 
192         when(mPackageManager.getApplicationInfo(eq(HIGH_SDK_PACKAGE), anyInt()))
193                 .thenReturn(mHighApplicationInfo);
194         when(mPackageManager.getApplicationInfo(eq(LOW_SDK_PACKAGE), anyInt()))
195                 .thenReturn(mLowApplicationInfo);
196         mHighApplicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
197         mLowApplicationInfo.targetSdkVersion = Build.VERSION_CODES.L;
198 
199         mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
200         mNormalBatterySipper.totalPowerMah = TOTAL_BATTERY_USAGE;
201         doReturn(UID).when(mNormalBatterySipper).getUid();
202 
203         mWifiBatterySipper.drainType = BatterySipper.DrainType.WIFI;
204         mWifiBatterySipper.totalPowerMah = BATTERY_WIFI_USAGE;
205 
206         mBluetoothBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH;
207         mBluetoothBatterySipper.totalPowerMah = BATTERY_BLUETOOTH_USAGE;
208 
209         mScreenBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
210         mScreenBatterySipper.totalPowerMah = BATTERY_SCREEN_USAGE;
211 
212         mSystemBatterySipper.drainType = BatterySipper.DrainType.APP;
213         mSystemBatterySipper.totalPowerMah = BATTERY_SYSTEM_USAGE;
214         when(mSystemBatterySipper.getUid()).thenReturn(Process.SYSTEM_UID);
215 
216         mOvercountedBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
217         mOvercountedBatterySipper.totalPowerMah = BATTERY_OVERACCOUNTED_USAGE;
218 
219         mUnaccountedBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
220         mUnaccountedBatterySipper.totalPowerMah = BATTERY_UNACCOUNTED_USAGE;
221 
222         mIdleBatterySipper.drainType = BatterySipper.DrainType.IDLE;
223         mIdleBatterySipper.totalPowerMah = BATTERY_IDLE_USAGE;
224 
225         mContext = spy(RuntimeEnvironment.application);
226         doReturn(mPackageManager).when(mContext).getPackageManager();
227         doReturn(mAppOpsManager).when(mContext).getSystemService(Context.APP_OPS_SERVICE);
228         mBatteryUtils = spy(new BatteryUtils(mContext));
229         mBatteryUtils.mPowerUsageFeatureProvider = mProvider;
230         doReturn(0L).when(mBatteryUtils)
231             .getForegroundServiceTotalTimeUs(any(BatteryStats.Uid.class), anyLong());
232         mAnomalyInfo = new AnomalyInfo(INFO_WAKELOCK);
233 
234         mUsageList = new ArrayList<>();
235         mUsageList.add(mNormalBatterySipper);
236         mUsageList.add(mScreenBatterySipper);
237         mUsageList.add(mCellBatterySipper);
238         when(mBatteryStatsHelper.getUsageList()).thenReturn(mUsageList);
239         when(mBatteryStatsHelper.getTotalPower())
240             .thenReturn(TOTAL_BATTERY_USAGE + BATTERY_SCREEN_USAGE);
241         when(mBatteryStatsHelper.getStats().getDischargeAmount(anyInt()))
242             .thenReturn(DISCHARGE_AMOUNT);
243         BatteryDatabaseManager.setUpForTest(mBatteryDatabaseManager);
244         ShadowThreadUtils.setIsMainThread(true);
245     }
246 
247     @Test
testGetProcessTimeMs_typeForeground_timeCorrect()248     public void testGetProcessTimeMs_typeForeground_timeCorrect() {
249         doReturn(TIME_STATE_FOREGROUND + 500).when(mBatteryUtils)
250             .getForegroundActivityTotalTimeUs(eq(mUid), anyLong());
251 
252         final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.FOREGROUND, mUid,
253                 BatteryStats.STATS_SINCE_CHARGED);
254 
255         assertThat(time).isEqualTo(TIME_EXPECTED_FOREGROUND);
256     }
257 
258     @Test
testGetProcessTimeMs_typeBackground_timeCorrect()259     public void testGetProcessTimeMs_typeBackground_timeCorrect() {
260         final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.BACKGROUND, mUid,
261                 BatteryStats.STATS_SINCE_CHARGED);
262 
263         assertThat(time).isEqualTo(TIME_EXPECTED_BACKGROUND);
264     }
265 
266     @Test
testGetProcessTimeMs_typeAll_timeCorrect()267     public void testGetProcessTimeMs_typeAll_timeCorrect() {
268         doReturn(TIME_STATE_FOREGROUND + 500).when(mBatteryUtils)
269             .getForegroundActivityTotalTimeUs(eq(mUid), anyLong());
270 
271         final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.ALL, mUid,
272                 BatteryStats.STATS_SINCE_CHARGED);
273 
274         assertThat(time).isEqualTo(TIME_EXPECTED_ALL);
275     }
276 
277     @Test
testGetProcessTimeMs_uidNull_returnZero()278     public void testGetProcessTimeMs_uidNull_returnZero() {
279         final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.ALL, null,
280                 BatteryStats.STATS_SINCE_CHARGED);
281 
282         assertThat(time).isEqualTo(0);
283     }
284 
285     @Test
testRemoveHiddenBatterySippers_ContainsHiddenSippers_RemoveAndReturnValue()286     public void testRemoveHiddenBatterySippers_ContainsHiddenSippers_RemoveAndReturnValue() {
287         final List<BatterySipper> sippers = new ArrayList<>();
288         sippers.add(mNormalBatterySipper);
289         sippers.add(mScreenBatterySipper);
290         sippers.add(mSystemBatterySipper);
291         sippers.add(mOvercountedBatterySipper);
292         sippers.add(mUnaccountedBatterySipper);
293         sippers.add(mWifiBatterySipper);
294         sippers.add(mBluetoothBatterySipper);
295         sippers.add(mIdleBatterySipper);
296         when(mProvider.isTypeSystem(mSystemBatterySipper)).thenReturn(true);
297         doNothing().when(mBatteryUtils).smearScreenBatterySipper(any(), any());
298 
299         final double totalUsage = mBatteryUtils.removeHiddenBatterySippers(sippers);
300 
301         assertThat(sippers).containsExactly(mNormalBatterySipper);
302         assertThat(totalUsage).isWithin(PRECISION).of(BATTERY_SYSTEM_USAGE);
303     }
304 
305     @Test
testShouldHideSipper_TypeUnAccounted_ReturnTrue()306     public void testShouldHideSipper_TypeUnAccounted_ReturnTrue() {
307         mNormalBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
308         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
309     }
310 
311     @Test
testShouldHideSipper_TypeOverAccounted_ReturnTrue()312     public void testShouldHideSipper_TypeOverAccounted_ReturnTrue() {
313         mNormalBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
314         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
315     }
316 
317     @Test
testShouldHideSipper_TypeIdle_ReturnTrue()318     public void testShouldHideSipper_TypeIdle_ReturnTrue() {
319         mNormalBatterySipper.drainType = BatterySipper.DrainType.IDLE;
320         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
321     }
322 
323     @Test
testShouldHideSipper_TypeCell_ReturnTrue()324     public void testShouldHideSipper_TypeCell_ReturnTrue() {
325         mNormalBatterySipper.drainType = BatterySipper.DrainType.CELL;
326         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
327     }
328 
329     @Test
testShouldHideSipper_TypeScreen_ReturnTrue()330     public void testShouldHideSipper_TypeScreen_ReturnTrue() {
331         mNormalBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
332         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
333     }
334 
335     @Test
testShouldHideSipper_TypeWifi_ReturnTrue()336     public void testShouldHideSipper_TypeWifi_ReturnTrue() {
337         mNormalBatterySipper.drainType = BatterySipper.DrainType.WIFI;
338         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
339     }
340 
341     @Test
testShouldHideSipper_TypeBluetooth_ReturnTrue()342     public void testShouldHideSipper_TypeBluetooth_ReturnTrue() {
343         mNormalBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH;
344         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
345     }
346 
347     @Test
testShouldHideSipper_TypeSystem_ReturnTrue()348     public void testShouldHideSipper_TypeSystem_ReturnTrue() {
349         mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
350         when(mNormalBatterySipper.getUid()).thenReturn(Process.ROOT_UID);
351         when(mProvider.isTypeSystem(any())).thenReturn(true);
352         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
353     }
354 
355     @Test
testShouldHideSipper_UidNormal_ReturnFalse()356     public void testShouldHideSipper_UidNormal_ReturnFalse() {
357         mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
358         when(mNormalBatterySipper.getUid()).thenReturn(UID);
359         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isFalse();
360     }
361 
362     @Test
testShouldHideSipper_TypeService_ReturnTrue()363     public void testShouldHideSipper_TypeService_ReturnTrue() {
364         mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
365         when(mNormalBatterySipper.getUid()).thenReturn(UID);
366         when(mProvider.isTypeService(any())).thenReturn(true);
367 
368         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
369     }
370 
371     @Test
testShouldHideSipper_hiddenSystemModule_ReturnTrue()372     public void testShouldHideSipper_hiddenSystemModule_ReturnTrue() {
373         mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
374         when(mNormalBatterySipper.getUid()).thenReturn(UID);
375         when(mBatteryUtils.isHiddenSystemModule(mNormalBatterySipper)).thenReturn(true);
376 
377         assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
378     }
379 
380     @Test
testCalculateBatteryPercent()381     public void testCalculateBatteryPercent() {
382         assertThat(mBatteryUtils.calculateBatteryPercent(BATTERY_SYSTEM_USAGE, TOTAL_BATTERY_USAGE,
383                 HIDDEN_USAGE, DISCHARGE_AMOUNT))
384                 .isWithin(PRECISION).of(PERCENT_SYSTEM_USAGE);
385     }
386 
387     @Test
testSmearScreenBatterySipper()388     public void testSmearScreenBatterySipper() {
389         final BatterySipper sipperNull = createTestSmearBatterySipper(TIME_FOREGROUND_ZERO,
390                 BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */);
391         final BatterySipper sipperBg = createTestSmearBatterySipper(TIME_FOREGROUND_ZERO,
392                 BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */);
393         final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND,
394                 BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */);
395         final BatterySipper sipperFg2 = createTestSmearBatterySipper(TIME_FOREGROUND,
396                 BATTERY_APP_USAGE, 3 /* uid */, false /* isUidNull */);
397 
398         final List<BatterySipper> sippers = new ArrayList<>();
399         sippers.add(sipperNull);
400         sippers.add(sipperBg);
401         sippers.add(sipperFg);
402         sippers.add(sipperFg2);
403 
404         mBatteryUtils.smearScreenBatterySipper(sippers, mScreenBatterySipper);
405 
406         assertThat(sipperNull.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE);
407         assertThat(sipperBg.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE);
408         assertThat(sipperFg.totalPowerMah).isWithin(PRECISION).of(
409                 BATTERY_APP_USAGE + BATTERY_SCREEN_USAGE / 2);
410         assertThat(sipperFg2.totalPowerMah).isWithin(PRECISION).of(
411                 BATTERY_APP_USAGE + BATTERY_SCREEN_USAGE / 2);
412     }
413 
414     @Test
testSmearScreenBatterySipper_screenSipperNull_shouldNotCrash()415     public void testSmearScreenBatterySipper_screenSipperNull_shouldNotCrash() {
416         final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND,
417                 BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */);
418 
419         final List<BatterySipper> sippers = new ArrayList<>();
420         sippers.add(sipperFg);
421 
422         // Shouldn't crash
423         mBatteryUtils.smearScreenBatterySipper(sippers, null /* screenSipper */);
424     }
425 
426     @Test
testCalculateRunningTimeBasedOnStatsType()427     public void testCalculateRunningTimeBasedOnStatsType() {
428         assertThat(mBatteryUtils.calculateRunningTimeBasedOnStatsType(mBatteryStatsHelper,
429                 BatteryStats.STATS_SINCE_CHARGED)).isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS);
430     }
431 
432     @Test
testSortUsageList()433     public void testSortUsageList() {
434         final List<BatterySipper> sippers = new ArrayList<>();
435         sippers.add(mNormalBatterySipper);
436         sippers.add(mScreenBatterySipper);
437         sippers.add(mSystemBatterySipper);
438 
439         mBatteryUtils.sortUsageList(sippers);
440 
441         assertThat(sippers).containsExactly(mNormalBatterySipper, mSystemBatterySipper,
442                 mScreenBatterySipper);
443     }
444 
445     @Test
testCalculateLastFullChargeTime()446     public void testCalculateLastFullChargeTime() {
447         final long currentTimeMs = System.currentTimeMillis();
448         when(mBatteryStatsHelper.getStats().getStartClockTime()).thenReturn(
449                 currentTimeMs - TIME_SINCE_LAST_FULL_CHARGE_MS);
450 
451         assertThat(mBatteryUtils.calculateLastFullChargeTime(
452                 mBatteryStatsHelper, currentTimeMs)).isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS);
453     }
454 
455     @Test
testGetForegroundActivityTotalTimeMs_returnMilliseconds()456     public void testGetForegroundActivityTotalTimeMs_returnMilliseconds() {
457         final long rawRealtimeUs = SystemClock.elapsedRealtime() * 1000;
458         doReturn(mTimer).when(mUid).getForegroundActivityTimer();
459         doReturn(TIME_SINCE_LAST_FULL_CHARGE_US).when(mTimer)
460                 .getTotalTimeLocked(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
461 
462         assertThat(mBatteryUtils.getForegroundActivityTotalTimeUs(mUid, rawRealtimeUs)).isEqualTo(
463                 TIME_SINCE_LAST_FULL_CHARGE_US);
464     }
465 
466     @Test
testGetTargetSdkVersion_packageExist_returnSdk()467     public void testGetTargetSdkVersion_packageExist_returnSdk() throws
468             PackageManager.NameNotFoundException {
469         doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(PACKAGE_NAME,
470                 PackageManager.GET_META_DATA);
471         mApplicationInfo.targetSdkVersion = SDK_VERSION;
472 
473         assertThat(mBatteryUtils.getTargetSdkVersion(PACKAGE_NAME)).isEqualTo(SDK_VERSION);
474     }
475 
476     @Test
testGetTargetSdkVersion_packageNotExist_returnSdkNull()477     public void testGetTargetSdkVersion_packageNotExist_returnSdkNull() throws
478             PackageManager.NameNotFoundException {
479         doThrow(new PackageManager.NameNotFoundException()).when(
480                 mPackageManager).getApplicationInfo(PACKAGE_NAME, PackageManager.GET_META_DATA);
481 
482         assertThat(mBatteryUtils.getTargetSdkVersion(PACKAGE_NAME)).isEqualTo(
483                 BatteryUtils.SDK_NULL);
484     }
485 
486     @Test
testBackgroundRestrictionOn_restrictionOn_returnTrue()487     public void testBackgroundRestrictionOn_restrictionOn_returnTrue() {
488         doReturn(AppOpsManager.MODE_IGNORED).when(mAppOpsManager).checkOpNoThrow(
489                 AppOpsManager.OP_RUN_IN_BACKGROUND, UID, PACKAGE_NAME);
490 
491         assertThat(mBatteryUtils.isBackgroundRestrictionEnabled(SDK_VERSION, UID,
492                 PACKAGE_NAME)).isTrue();
493     }
494 
495     @Test
testBackgroundRestrictionOn_restrictionOff_returnFalse()496     public void testBackgroundRestrictionOn_restrictionOff_returnFalse() {
497         doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager).checkOpNoThrow(
498                 AppOpsManager.OP_RUN_IN_BACKGROUND, UID, PACKAGE_NAME);
499 
500         assertThat(mBatteryUtils.isBackgroundRestrictionEnabled(SDK_VERSION, UID, PACKAGE_NAME))
501             .isFalse();
502     }
503 
createTestSmearBatterySipper( long topTime, double totalPowerMah, int uidCode, boolean isUidNull)504     private BatterySipper createTestSmearBatterySipper(
505         long topTime, double totalPowerMah, int uidCode, boolean isUidNull) {
506         final BatterySipper sipper = mock(BatterySipper.class);
507         sipper.drainType = BatterySipper.DrainType.APP;
508         sipper.totalPowerMah = totalPowerMah;
509         doReturn(uidCode).when(sipper).getUid();
510         if (!isUidNull) {
511             final BatteryStats.Uid uid = mock(BatteryStats.Uid.class, RETURNS_DEEP_STUBS);
512             doReturn(topTime).when(mBatteryUtils).getProcessTimeMs(
513                     eq(BatteryUtils.StatusType.SCREEN_USAGE), eq(uid), anyInt());
514             doReturn(uidCode).when(uid).getUid();
515             sipper.uidObj = uid;
516         }
517 
518         return sipper;
519     }
520 
521     @Test
testInitBatteryStatsHelper_init()522     public void testInitBatteryStatsHelper_init() {
523         mBatteryUtils.initBatteryStatsHelper(mBatteryStatsHelper, mBundle, mUserManager);
524 
525         verify(mBatteryStatsHelper).create(mBundle);
526         verify(mBatteryStatsHelper).refreshStats(BatteryStats.STATS_SINCE_CHARGED,
527                 mUserManager.getUserProfiles());
528     }
529 
530     @Test
testFindBatterySipperByType_findTypeScreen()531     public void testFindBatterySipperByType_findTypeScreen() {
532         BatterySipper sipper = mBatteryUtils.findBatterySipperByType(mUsageList,
533                 BatterySipper.DrainType.SCREEN);
534 
535         assertThat(sipper).isSameAs(mScreenBatterySipper);
536     }
537 
538     @Test
testFindBatterySipperByType_findTypeApp()539     public void testFindBatterySipperByType_findTypeApp() {
540         BatterySipper sipper = mBatteryUtils.findBatterySipperByType(mUsageList,
541                 BatterySipper.DrainType.APP);
542 
543         assertThat(sipper).isSameAs(mNormalBatterySipper);
544     }
545 
546     @Test
testCalculateScreenUsageTime_returnCorrectTime()547     public void testCalculateScreenUsageTime_returnCorrectTime() {
548         mScreenBatterySipper.usageTimeMs = TIME_EXPECTED_FOREGROUND;
549 
550         assertThat(mBatteryUtils.calculateScreenUsageTime(mBatteryStatsHelper)).isEqualTo(
551                 TIME_EXPECTED_FOREGROUND);
552     }
553 
554     @Test
testIsPreOApp_SdkLowerThanO_ReturnTrue()555     public void testIsPreOApp_SdkLowerThanO_ReturnTrue() {
556         assertThat(mBatteryUtils.isPreOApp(LOW_SDK_PACKAGE)).isTrue();
557     }
558 
559     @Test
testIsPreOApp_SdkLargerOrEqualThanO_ReturnFalse()560     public void testIsPreOApp_SdkLargerOrEqualThanO_ReturnFalse() {
561         assertThat(mBatteryUtils.isPreOApp(HIGH_SDK_PACKAGE)).isFalse();
562     }
563 
564     @Test
testIsPreOApp_containPreOApp_ReturnTrue()565     public void testIsPreOApp_containPreOApp_ReturnTrue() {
566         assertThat(
567                 mBatteryUtils.isPreOApp(new String[]{HIGH_SDK_PACKAGE, LOW_SDK_PACKAGE})).isTrue();
568     }
569 
570     @Test
testIsPreOApp_emptyList_ReturnFalse()571     public void testIsPreOApp_emptyList_ReturnFalse() {
572         assertThat(mBatteryUtils.isPreOApp(new String[]{})).isFalse();
573     }
574 
575     @Test
testSetForceAppStandby_forcePreOApp_forceTwoRestrictions()576     public void testSetForceAppStandby_forcePreOApp_forceTwoRestrictions() {
577         mBatteryUtils.setForceAppStandby(UID, LOW_SDK_PACKAGE, AppOpsManager.MODE_IGNORED);
578 
579         // Restrict both OP_RUN_IN_BACKGROUND and OP_RUN_ANY_IN_BACKGROUND
580         verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, UID, LOW_SDK_PACKAGE,
581                 AppOpsManager.MODE_IGNORED);
582         verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID, LOW_SDK_PACKAGE,
583                 AppOpsManager.MODE_IGNORED);
584     }
585 
586     @Test
testSetForceAppStandby_forceOApp_forceOneRestriction()587     public void testSetForceAppStandby_forceOApp_forceOneRestriction() {
588         mBatteryUtils.setForceAppStandby(UID, HIGH_SDK_PACKAGE, AppOpsManager.MODE_IGNORED);
589 
590         // Don't restrict OP_RUN_IN_BACKGROUND because it is already been restricted for O app
591         verify(mAppOpsManager, never()).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, UID,
592                 HIGH_SDK_PACKAGE, AppOpsManager.MODE_IGNORED);
593         // Restrict OP_RUN_ANY_IN_BACKGROUND
594         verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
595                 HIGH_SDK_PACKAGE, AppOpsManager.MODE_IGNORED);
596     }
597 
598     @Test
testSetForceAppStandby_restrictApp_recordTime()599     public void testSetForceAppStandby_restrictApp_recordTime() {
600         mBatteryUtils.setForceAppStandby(UID, HIGH_SDK_PACKAGE, AppOpsManager.MODE_IGNORED);
601 
602         verify(mBatteryDatabaseManager).insertAction(
603                 eq(AnomalyDatabaseHelper.ActionType.RESTRICTION), eq(UID),
604                 eq(HIGH_SDK_PACKAGE), anyLong());
605     }
606 
607     @Test
testSetForceAppStandby_unrestrictApp_deleteTime()608     public void testSetForceAppStandby_unrestrictApp_deleteTime() {
609         mBatteryUtils.setForceAppStandby(UID, HIGH_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED);
610 
611         verify(mBatteryDatabaseManager).deleteAction(AnomalyDatabaseHelper.ActionType.RESTRICTION,
612                 UID, HIGH_SDK_PACKAGE);
613     }
614 
615     @Test
testIsForceAppStandbyEnabled_enabled_returnTrue()616     public void testIsForceAppStandbyEnabled_enabled_returnTrue() {
617         when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
618                 PACKAGE_NAME)).thenReturn(AppOpsManager.MODE_IGNORED);
619 
620         assertThat(mBatteryUtils.isForceAppStandbyEnabled(UID, PACKAGE_NAME)).isTrue();
621     }
622 
623     @Test
testIsForceAppStandbyEnabled_disabled_returnFalse()624     public void testIsForceAppStandbyEnabled_disabled_returnFalse() {
625         when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
626                 PACKAGE_NAME)).thenReturn(AppOpsManager.MODE_ALLOWED);
627 
628         assertThat(mBatteryUtils.isForceAppStandbyEnabled(UID, PACKAGE_NAME)).isFalse();
629     }
630 
631     @Test
testShouldHideAnomaly_systemAppWithLauncher_returnTrue()632     public void testShouldHideAnomaly_systemAppWithLauncher_returnTrue() {
633         final List<ResolveInfo> resolveInfos = new ArrayList<>();
634         final ResolveInfo resolveInfo = new ResolveInfo();
635         resolveInfo.activityInfo = new ActivityInfo();
636         resolveInfo.activityInfo.packageName = HIGH_SDK_PACKAGE;
637 
638         doReturn(resolveInfos).when(mPackageManager).queryIntentActivities(any(), anyInt());
639         doReturn(new String[]{HIGH_SDK_PACKAGE}).when(mPackageManager).getPackagesForUid(UID);
640         mHighApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
641 
642         assertThat(mBatteryUtils.shouldHideAnomaly(mPowerWhitelistBackend, UID,
643                 mAnomalyInfo)).isTrue();
644     }
645 
646     @Test
testShouldHideAnomaly_systemAppWithoutLauncher_returnTrue()647     public void testShouldHideAnomaly_systemAppWithoutLauncher_returnTrue() {
648         doReturn(new ArrayList<>()).when(mPackageManager).queryIntentActivities(any(), anyInt());
649         doReturn(new String[]{HIGH_SDK_PACKAGE}).when(mPackageManager).getPackagesForUid(UID);
650         mHighApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
651 
652         assertThat(mBatteryUtils.shouldHideAnomaly(mPowerWhitelistBackend, UID,
653                 mAnomalyInfo)).isTrue();
654     }
655 
656     @Test
testShouldHideAnomaly_systemUid_returnTrue()657     public void testShouldHideAnomaly_systemUid_returnTrue() {
658         final int systemUid = Process.ROOT_UID;
659         doReturn(new String[]{HIGH_SDK_PACKAGE}).when(mPackageManager).getPackagesForUid(systemUid);
660 
661         assertThat(mBatteryUtils.shouldHideAnomaly(mPowerWhitelistBackend, systemUid,
662                 mAnomalyInfo)).isTrue();
663     }
664 
665     @Test
testShouldHideAnomaly_AppInDozeList_returnTrue()666     public void testShouldHideAnomaly_AppInDozeList_returnTrue() {
667         doReturn(new String[]{HIGH_SDK_PACKAGE}).when(mPackageManager).getPackagesForUid(UID);
668         doReturn(true).when(mPowerWhitelistBackend).isWhitelisted(new String[]{HIGH_SDK_PACKAGE});
669 
670         assertThat(mBatteryUtils.shouldHideAnomaly(mPowerWhitelistBackend, UID,
671                 mAnomalyInfo)).isTrue();
672     }
673 
674     @Test
testShouldHideAnomaly_normalApp_returnFalse()675     public void testShouldHideAnomaly_normalApp_returnFalse() {
676         doReturn(new String[]{HIGH_SDK_PACKAGE}).when(mPackageManager).getPackagesForUid(UID);
677 
678         assertThat(mBatteryUtils.shouldHideAnomaly(mPowerWhitelistBackend, UID,
679                 mAnomalyInfo)).isFalse();
680     }
681 
682     @Test
testShouldHideAnomaly_excessivePriorOApp_returnFalse()683     public void testShouldHideAnomaly_excessivePriorOApp_returnFalse() {
684         doReturn(new String[]{LOW_SDK_PACKAGE}).when(mPackageManager).getPackagesForUid(UID);
685         mAnomalyInfo = new AnomalyInfo(INFO_EXCESSIVE);
686 
687         assertThat(mBatteryUtils.shouldHideAnomaly(mPowerWhitelistBackend, UID,
688                 mAnomalyInfo)).isFalse();
689     }
690 
691     @Test
testShouldHideAnomaly_excessiveOApp_returnTrue()692     public void testShouldHideAnomaly_excessiveOApp_returnTrue() {
693         doReturn(new String[]{HIGH_SDK_PACKAGE}).when(mPackageManager).getPackagesForUid(UID);
694         mAnomalyInfo = new AnomalyInfo(INFO_EXCESSIVE);
695 
696         assertThat(mBatteryUtils.shouldHideAnomaly(mPowerWhitelistBackend, UID,
697                 mAnomalyInfo)).isTrue();
698     }
699 
700     @Test
clearForceAppStandby_appRestricted_clearAndReturnTrue()701     public void clearForceAppStandby_appRestricted_clearAndReturnTrue() {
702         when(mBatteryUtils.getPackageUid(HIGH_SDK_PACKAGE)).thenReturn(UID);
703         when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
704                 HIGH_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_IGNORED);
705 
706         assertThat(mBatteryUtils.clearForceAppStandby(HIGH_SDK_PACKAGE)).isTrue();
707         verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
708                 HIGH_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED);
709     }
710 
711     @Test
clearForceAppStandby_appInvalid_returnFalse()712     public void clearForceAppStandby_appInvalid_returnFalse() {
713         when(mBatteryUtils.getPackageUid(PACKAGE_NAME)).thenReturn(BatteryUtils.UID_NULL);
714 
715         assertThat(mBatteryUtils.clearForceAppStandby(PACKAGE_NAME)).isFalse();
716         verify(mAppOpsManager, never()).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
717                 PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
718     }
719 
720     @Test
clearForceAppStandby_appUnrestricted_returnFalse()721     public void clearForceAppStandby_appUnrestricted_returnFalse() {
722         when(mBatteryUtils.getPackageUid(PACKAGE_NAME)).thenReturn(UID);
723         when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
724                 PACKAGE_NAME)).thenReturn(AppOpsManager.MODE_ALLOWED);
725 
726         assertThat(mBatteryUtils.clearForceAppStandby(PACKAGE_NAME)).isFalse();
727         verify(mAppOpsManager, never()).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
728                 PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
729     }
730 
731     @Test
getBatteryInfo_providerNull_shouldNotCrash()732     public void getBatteryInfo_providerNull_shouldNotCrash() {
733         when(mProvider.isEnhancedBatteryPredictionEnabled(mContext)).thenReturn(true);
734         when(mProvider.getEnhancedBatteryPrediction(mContext)).thenReturn(null);
735         when(mContext.registerReceiver(nullable(BroadcastReceiver.class),
736                 any(IntentFilter.class))).thenReturn(new Intent());
737 
738         //Should not crash
739         assertThat(mBatteryUtils.getBatteryInfo(mBatteryStatsHelper, TAG)).isNotNull();
740     }
741 
742     @Test
getEnhancedEstimate_doesNotUpdateCache_ifEstimateFresh()743     public void getEnhancedEstimate_doesNotUpdateCache_ifEstimateFresh() {
744         Estimate estimate = new Estimate(1000, true, 1000);
745         Estimate.storeCachedEstimate(mContext, estimate);
746 
747         estimate = mBatteryUtils.getEnhancedEstimate();
748 
749         // only pass if estimate has not changed
750         assertThat(estimate).isNotNull();
751         assertThat(estimate.isBasedOnUsage()).isTrue();
752         assertThat(estimate.getAverageDischargeTime()).isEqualTo(1000);
753     }
754 }
755