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 17 package com.android.settings.fuelgauge.anomaly.checker; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.ArgumentMatchers.nullable; 22 import static org.mockito.Matchers.any; 23 import static org.mockito.Matchers.anyInt; 24 import static org.mockito.Matchers.anyLong; 25 import static org.mockito.Matchers.eq; 26 import static org.mockito.Mockito.doReturn; 27 import static org.mockito.Mockito.spy; 28 29 import android.content.Context; 30 import android.content.pm.ApplicationInfo; 31 import android.content.pm.PackageManager; 32 import android.os.BatteryStats; 33 import android.text.format.DateUtils; 34 35 import com.android.internal.os.BatterySipper; 36 import com.android.internal.os.BatteryStatsHelper; 37 import com.android.settings.fuelgauge.anomaly.AnomalyUtils; 38 import com.android.settings.testutils.SettingsRobolectricTestRunner; 39 import com.android.settings.TestConfig; 40 import com.android.settings.fuelgauge.BatteryUtils; 41 import com.android.settings.fuelgauge.anomaly.Anomaly; 42 import com.android.settings.fuelgauge.anomaly.AnomalyDetectionPolicy; 43 import com.android.settings.fuelgauge.anomaly.action.AnomalyAction; 44 45 import org.junit.Before; 46 import org.junit.Test; 47 import org.junit.runner.RunWith; 48 import org.mockito.Mock; 49 import org.mockito.MockitoAnnotations; 50 import org.robolectric.RuntimeEnvironment; 51 import org.robolectric.annotation.Config; 52 import org.robolectric.util.ReflectionHelpers; 53 54 import java.util.ArrayList; 55 import java.util.List; 56 57 @RunWith(SettingsRobolectricTestRunner.class) 58 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) 59 public class WakeLockAnomalyDetectorTest { 60 private static final String TARGET_PACKAGE_NAME = "com.android.app"; 61 private static final long ANOMALY_WAKELOCK_TIME_MS = 2 * DateUtils.HOUR_IN_MILLIS; 62 private static final long NORMAL_WAKELOCK_TIME_MS = DateUtils.SECOND_IN_MILLIS; 63 private static final long WAKELOCK_THRESHOLD_MS = DateUtils.HOUR_IN_MILLIS; 64 private static final int ANOMALY_UID = 111; 65 private static final int NORMAL_UID = 222; 66 private static final int TARGET_UID = 333; 67 private static final int INACTIVE_UID = 444; 68 @Mock 69 private BatteryStatsHelper mBatteryStatsHelper; 70 @Mock 71 private BatterySipper mAnomalySipper; 72 @Mock 73 private BatterySipper mTargetSipper; 74 @Mock 75 private BatterySipper mNormalSipper; 76 @Mock 77 private BatterySipper mInactiveSipper; 78 @Mock 79 private BatteryStats.Uid mAnomalyUid; 80 @Mock 81 private BatteryStats.Uid mNormalUid; 82 @Mock 83 private BatteryStats.Uid mTargetUid; 84 @Mock 85 private BatteryStats.Uid mInactiveUid; 86 @Mock 87 private BatteryUtils mBatteryUtils; 88 @Mock 89 private PackageManager mPackageManager; 90 @Mock 91 private ApplicationInfo mApplicationInfo; 92 @Mock 93 private AnomalyDetectionPolicy mPolicy; 94 @Mock 95 private AnomalyAction mAnomalyAction; 96 @Mock 97 private AnomalyUtils mAnomalyUtils; 98 99 private WakeLockAnomalyDetector mWakelockAnomalyDetector; 100 private Context mContext; 101 private List<BatterySipper> mUsageList; 102 private Anomaly mAnomaly; 103 private Anomaly mTargetAnomaly; 104 105 @Before 106 public void setUp() throws Exception { 107 MockitoAnnotations.initMocks(this); 108 109 mContext = spy(RuntimeEnvironment.application); 110 ReflectionHelpers.setField(mPolicy, "wakeLockThreshold", WAKELOCK_THRESHOLD_MS); 111 112 doReturn(false).when(mBatteryUtils).shouldHideSipper(nullable(BatterySipper.class)); 113 doReturn(mPackageManager).when(mContext).getPackageManager(); 114 doReturn(mApplicationInfo).when(mPackageManager) 115 .getApplicationInfo(nullable(String.class), anyInt()); 116 doReturn(true).when(mAnomalyAction).isActionActive(any()); 117 doReturn(mAnomalyAction).when(mAnomalyUtils).getAnomalyAction(any()); 118 119 mWakelockAnomalyDetector = spy( 120 new WakeLockAnomalyDetector(mContext, mPolicy, mAnomalyUtils)); 121 mWakelockAnomalyDetector.mBatteryUtils = mBatteryUtils; 122 123 mAnomalySipper.uidObj = mAnomalyUid; 124 doReturn(ANOMALY_WAKELOCK_TIME_MS).when(mWakelockAnomalyDetector) 125 .getBackgroundTotalDurationMs(eq(mAnomalyUid), anyLong()); 126 doReturn(ANOMALY_WAKELOCK_TIME_MS).when(mWakelockAnomalyDetector).getCurrentDurationMs( 127 eq(mAnomalyUid), anyLong()); 128 doReturn(ANOMALY_UID).when(mAnomalyUid).getUid(); 129 130 mNormalSipper.uidObj = mNormalUid; 131 doReturn(NORMAL_WAKELOCK_TIME_MS).when(mWakelockAnomalyDetector) 132 .getBackgroundTotalDurationMs(eq(mNormalUid), anyLong()); 133 doReturn(0L).when(mWakelockAnomalyDetector).getCurrentDurationMs(eq(mNormalUid), 134 anyLong()); 135 doReturn(NORMAL_UID).when(mNormalUid).getUid(); 136 137 mTargetSipper.uidObj = mTargetUid; 138 doReturn(ANOMALY_WAKELOCK_TIME_MS).when(mWakelockAnomalyDetector) 139 .getBackgroundTotalDurationMs(eq(mTargetUid), anyLong()); 140 doReturn(ANOMALY_WAKELOCK_TIME_MS).when(mWakelockAnomalyDetector).getCurrentDurationMs( 141 eq(mTargetUid), anyLong()); 142 doReturn(TARGET_UID).when(mTargetUid).getUid(); 143 144 mInactiveSipper.uidObj = mInactiveUid; 145 doReturn(ANOMALY_WAKELOCK_TIME_MS).when(mWakelockAnomalyDetector) 146 .getBackgroundTotalDurationMs(eq(mInactiveUid), anyLong()); 147 doReturn(0L).when(mWakelockAnomalyDetector).getCurrentDurationMs(eq(mInactiveUid), 148 anyLong()); 149 doReturn(INACTIVE_UID).when(mInactiveUid).getUid(); 150 151 mUsageList = new ArrayList<>(); 152 mUsageList.add(mAnomalySipper); 153 mUsageList.add(mNormalSipper); 154 mUsageList.add(mTargetSipper); 155 mUsageList.add(mInactiveSipper); 156 doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList(); 157 158 mAnomaly = createWakeLockAnomaly(ANOMALY_UID); 159 mTargetAnomaly = createWakeLockAnomaly(TARGET_UID); 160 } 161 162 @Test 163 public void testDetectAnomalies_containsAnomaly_detectIt() { 164 doReturn(BatteryUtils.UID_NULL).when(mBatteryUtils).getPackageUid(nullable(String.class)); 165 166 List<Anomaly> mAnomalies = mWakelockAnomalyDetector.detectAnomalies(mBatteryStatsHelper); 167 168 assertThat(mAnomalies).containsExactly(mAnomaly, mTargetAnomaly); 169 } 170 171 @Test 172 public void testDetectAnomalies_containsTargetPackage_detectIt() { 173 doReturn(TARGET_UID).when(mBatteryUtils).getPackageUid(TARGET_PACKAGE_NAME); 174 175 List<Anomaly> mAnomalies = mWakelockAnomalyDetector.detectAnomalies(mBatteryStatsHelper, 176 TARGET_PACKAGE_NAME); 177 178 assertThat(mAnomalies).containsExactly(mTargetAnomaly); 179 } 180 181 @Test 182 public void testContainsThresholdFromPolicy() { 183 assertThat(mWakelockAnomalyDetector.mWakeLockThresholdMs).isEqualTo(WAKELOCK_THRESHOLD_MS); 184 } 185 186 private Anomaly createWakeLockAnomaly(int uid) { 187 return new Anomaly.Builder() 188 .setUid(uid) 189 .setType(Anomaly.AnomalyType.WAKE_LOCK) 190 .setWakeLockTimeMs(ANOMALY_WAKELOCK_TIME_MS) 191 .build(); 192 } 193 } 194