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