Merge "Refactor anomaly detection"
This commit is contained in:
committed by
Android (Google) Code Review
commit
b424cf771b
@@ -41,6 +41,7 @@ import java.util.List;
|
|||||||
* Utils for battery operation
|
* Utils for battery operation
|
||||||
*/
|
*/
|
||||||
public class BatteryUtils {
|
public class BatteryUtils {
|
||||||
|
public static final int UID_NULL = -1;
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@IntDef({StatusType.FOREGROUND,
|
@IntDef({StatusType.FOREGROUND,
|
||||||
StatusType.BACKGROUND,
|
StatusType.BACKGROUND,
|
||||||
@@ -274,6 +275,22 @@ public class BatteryUtils {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find package uid from package name
|
||||||
|
*
|
||||||
|
* @param packageName used to find the uid
|
||||||
|
* @return uid for packageName, or {@link #UID_NULL} if exception happens or
|
||||||
|
* {@code packageName} is null
|
||||||
|
*/
|
||||||
|
public int getPackageUid(String packageName) {
|
||||||
|
try {
|
||||||
|
return packageName == null ? UID_NULL : mPackageManager.getPackageUid(packageName,
|
||||||
|
PackageManager.GET_META_DATA);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
return UID_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public long convertUsToMs(long timeUs) {
|
public long convertUsToMs(long timeUs) {
|
||||||
return timeUs / 1000;
|
return timeUs / 1000;
|
||||||
}
|
}
|
||||||
|
@@ -90,6 +90,7 @@ public interface PowerUsageFeatureProvider {
|
|||||||
/**
|
/**
|
||||||
* Check whether a specific anomaly detector is enabled
|
* Check whether a specific anomaly detector is enabled
|
||||||
*/
|
*/
|
||||||
|
//TODO(b/62096650): remove this method and use AnomalyDetectionPolicy instead
|
||||||
boolean isAnomalyDetectorEnabled(@Anomaly.AnomalyType int type);
|
boolean isAnomalyDetectorEnabled(@Anomaly.AnomalyType int type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -108,4 +108,14 @@ public class AnomalyDetectionPolicy {
|
|||||||
wakeupAlarmThreshold = mParserWrapper.getLong(KEY_WAKEUP_ALARM_THRESHOLD, 60);
|
wakeupAlarmThreshold = mParserWrapper.getLong(KEY_WAKEUP_ALARM_THRESHOLD, 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isAnomalyDetectorEnabled(@Anomaly.AnomalyType int type) {
|
||||||
|
switch (type) {
|
||||||
|
case Anomaly.AnomalyType.WAKE_LOCK:
|
||||||
|
return wakeLockDetectionEnabled;
|
||||||
|
case Anomaly.AnomalyType.WAKEUP_ALARM:
|
||||||
|
return wakeupAlarmDetectionEnabled;
|
||||||
|
default:
|
||||||
|
return false; // Disabled when no this type
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,11 +17,12 @@
|
|||||||
package com.android.settings.fuelgauge.anomaly;
|
package com.android.settings.fuelgauge.anomaly;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.BatteryStats;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.UserManager;
|
||||||
import android.support.annotation.VisibleForTesting;
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.android.internal.os.BatteryStatsHelper;
|
import com.android.internal.os.BatteryStatsHelper;
|
||||||
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
|
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
|
||||||
import com.android.settings.utils.AsyncLoader;
|
import com.android.settings.utils.AsyncLoader;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -33,16 +34,45 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class AnomalyLoader extends AsyncLoader<List<Anomaly>> {
|
public class AnomalyLoader extends AsyncLoader<List<Anomaly>> {
|
||||||
private BatteryStatsHelper mBatteryStatsHelper;
|
private BatteryStatsHelper mBatteryStatsHelper;
|
||||||
private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
|
private String mPackageName;
|
||||||
|
private UserManager mUserManager;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
AnomalyUtils mAnomalyUtils;
|
AnomalyUtils mAnomalyUtils;
|
||||||
|
@VisibleForTesting
|
||||||
|
AnomalyDetectionPolicy mPolicy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create {@link AnomalyLoader} that runs anomaly check for all apps.
|
||||||
|
*/
|
||||||
public AnomalyLoader(Context context, BatteryStatsHelper batteryStatsHelper) {
|
public AnomalyLoader(Context context, BatteryStatsHelper batteryStatsHelper) {
|
||||||
|
this(context, batteryStatsHelper, null, new AnomalyDetectionPolicy(context));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create {@link AnomalyLoader} with {@code packageName}, so this loader will only
|
||||||
|
* detect anomalies related to {@code packageName}, or check all apps if {@code packageName}
|
||||||
|
* is {@code null}.
|
||||||
|
*
|
||||||
|
* This constructor will create {@link BatteryStatsHelper} in background thread.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param packageName if set, only finds anomalies for this package. If {@code null},
|
||||||
|
* detects all anomalies of this type.
|
||||||
|
*/
|
||||||
|
public AnomalyLoader(Context context, String packageName) {
|
||||||
|
this(context, null, packageName, new AnomalyDetectionPolicy(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
AnomalyLoader(Context context, BatteryStatsHelper batteryStatsHelper,
|
||||||
|
String packageName, AnomalyDetectionPolicy policy) {
|
||||||
super(context);
|
super(context);
|
||||||
mBatteryStatsHelper = batteryStatsHelper;
|
mBatteryStatsHelper = batteryStatsHelper;
|
||||||
mPowerUsageFeatureProvider = FeatureFactory.getFactory(
|
mPackageName = packageName;
|
||||||
context).getPowerUsageFeatureProvider(context);
|
|
||||||
mAnomalyUtils = AnomalyUtils.getInstance(context);
|
mAnomalyUtils = AnomalyUtils.getInstance(context);
|
||||||
|
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||||
|
mPolicy = policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -51,11 +81,18 @@ public class AnomalyLoader extends AsyncLoader<List<Anomaly>> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Anomaly> loadInBackground() {
|
public List<Anomaly> loadInBackground() {
|
||||||
|
if (mBatteryStatsHelper == null) {
|
||||||
|
mBatteryStatsHelper = new BatteryStatsHelper(getContext());
|
||||||
|
mBatteryStatsHelper.create((Bundle) null);
|
||||||
|
mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
|
||||||
|
mUserManager.getUserProfiles());
|
||||||
|
}
|
||||||
|
|
||||||
final List<Anomaly> anomalies = new ArrayList<>();
|
final List<Anomaly> anomalies = new ArrayList<>();
|
||||||
for (@Anomaly.AnomalyType int type : Anomaly.ANOMALY_TYPE_LIST) {
|
for (@Anomaly.AnomalyType int type : Anomaly.ANOMALY_TYPE_LIST) {
|
||||||
if (mPowerUsageFeatureProvider.isAnomalyDetectorEnabled(type)) {
|
if (mPolicy.isAnomalyDetectorEnabled(type)) {
|
||||||
anomalies.addAll(mAnomalyUtils.getAnomalyDetector(type).detectAnomalies(
|
anomalies.addAll(mAnomalyUtils.getAnomalyDetector(type).detectAnomalies(
|
||||||
mBatteryStatsHelper));
|
mBatteryStatsHelper, mPackageName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,11 +17,30 @@
|
|||||||
|
|
||||||
package com.android.settings.fuelgauge.anomaly.checker;
|
package com.android.settings.fuelgauge.anomaly.checker;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.internal.os.BatteryStatsHelper;
|
import com.android.internal.os.BatteryStatsHelper;
|
||||||
import com.android.settings.fuelgauge.anomaly.Anomaly;
|
import com.android.settings.fuelgauge.anomaly.Anomaly;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface AnomalyDetector {
|
public interface AnomalyDetector {
|
||||||
|
/**
|
||||||
|
* Detect whether there is anomaly among all the applications in the device
|
||||||
|
*
|
||||||
|
* @param batteryStatsHelper used to detect the anomaly
|
||||||
|
* @return anomaly list
|
||||||
|
*/
|
||||||
List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper);
|
List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect whether application with {@code targetPackageName} has anomaly. When
|
||||||
|
* {@code targetPackageName} is null, start detection among all the applications.
|
||||||
|
*
|
||||||
|
* @param batteryStatsHelper used to detect the anomaly
|
||||||
|
* @param targetPackageName represents the app need to be detected
|
||||||
|
* @return anomaly list
|
||||||
|
*/
|
||||||
|
List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper,
|
||||||
|
@Nullable String targetPackageName);
|
||||||
}
|
}
|
||||||
|
@@ -63,17 +63,27 @@ public class WakeLockAnomalyDetector implements AnomalyDetector {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper) {
|
public List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper) {
|
||||||
|
return detectAnomalies(batteryStatsHelper, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper,
|
||||||
|
String targetPackageName) {
|
||||||
final List<BatterySipper> batterySippers = batteryStatsHelper.getUsageList();
|
final List<BatterySipper> batterySippers = batteryStatsHelper.getUsageList();
|
||||||
final List<Anomaly> anomalies = new ArrayList<>();
|
final List<Anomaly> anomalies = new ArrayList<>();
|
||||||
final long rawRealtime = SystemClock.elapsedRealtime();
|
final long rawRealtime = SystemClock.elapsedRealtime();
|
||||||
|
final int targetUid = mBatteryUtils.getPackageUid(targetPackageName);
|
||||||
|
|
||||||
// Check the app one by one
|
// Check the app one by one
|
||||||
for (int i = 0, size = batterySippers.size(); i < size; i++) {
|
for (int i = 0, size = batterySippers.size(); i < size; i++) {
|
||||||
final BatterySipper sipper = batterySippers.get(i);
|
final BatterySipper sipper = batterySippers.get(i);
|
||||||
final BatteryStats.Uid uid = sipper.uidObj;
|
final BatteryStats.Uid uid = sipper.uidObj;
|
||||||
if (uid == null) {
|
if (uid == null
|
||||||
|
|| mBatteryUtils.shouldHideSipper(sipper)
|
||||||
|
|| (targetUid != BatteryUtils.UID_NULL && targetUid != uid.getUid())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks =
|
final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks =
|
||||||
uid.getWakelockStats();
|
uid.getWakelockStats();
|
||||||
long maxPartialWakeLockMs = 0;
|
long maxPartialWakeLockMs = 0;
|
||||||
@@ -88,10 +98,9 @@ public class WakeLockAnomalyDetector implements AnomalyDetector {
|
|||||||
getTotalDurationMs(timer, rawRealtime));
|
getTotalDurationMs(timer, rawRealtime));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report it if wakelock time is too long and it is not a hidden batterysipper
|
// Report application as anomaly if wakelock time is too long
|
||||||
// TODO: add more attributes to detect wakelock anomaly
|
// TODO(b/38233034): add more attributes to detect wakelock anomaly
|
||||||
if (maxPartialWakeLockMs > mWakeLockThresholdMs
|
if (maxPartialWakeLockMs > mWakeLockThresholdMs) {
|
||||||
&& !mBatteryUtils.shouldHideSipper(sipper)) {
|
|
||||||
final String packageName = mBatteryUtils.getPackageName(uid.getUid());
|
final String packageName = mBatteryUtils.getPackageName(uid.getUid());
|
||||||
final CharSequence displayName = Utils.getApplicationLabel(mContext,
|
final CharSequence displayName = Utils.getApplicationLabel(mContext,
|
||||||
packageName);
|
packageName);
|
||||||
|
@@ -57,16 +57,25 @@ public class WakeupAlarmAnomalyDetector implements AnomalyDetector {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper) {
|
public List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper) {
|
||||||
|
return detectAnomalies(batteryStatsHelper, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper,
|
||||||
|
String targetPackageName) {
|
||||||
final List<BatterySipper> batterySippers = batteryStatsHelper.getUsageList();
|
final List<BatterySipper> batterySippers = batteryStatsHelper.getUsageList();
|
||||||
final List<Anomaly> anomalies = new ArrayList<>();
|
final List<Anomaly> anomalies = new ArrayList<>();
|
||||||
final long totalRunningHours = mBatteryUtils.calculateRunningTimeBasedOnStatsType(
|
final long totalRunningHours = mBatteryUtils.calculateRunningTimeBasedOnStatsType(
|
||||||
batteryStatsHelper, BatteryStats.STATS_SINCE_CHARGED) / DateUtils.HOUR_IN_MILLIS;
|
batteryStatsHelper, BatteryStats.STATS_SINCE_CHARGED) / DateUtils.HOUR_IN_MILLIS;
|
||||||
|
final int targetUid = mBatteryUtils.getPackageUid(targetPackageName);
|
||||||
|
|
||||||
if (totalRunningHours != 0) {
|
if (totalRunningHours != 0) {
|
||||||
for (int i = 0, size = batterySippers.size(); i < size; i++) {
|
for (int i = 0, size = batterySippers.size(); i < size; i++) {
|
||||||
final BatterySipper sipper = batterySippers.get(i);
|
final BatterySipper sipper = batterySippers.get(i);
|
||||||
final BatteryStats.Uid uid = sipper.uidObj;
|
final BatteryStats.Uid uid = sipper.uidObj;
|
||||||
if (uid == null || mBatteryUtils.shouldHideSipper(sipper)) {
|
if (uid == null
|
||||||
|
|| mBatteryUtils.shouldHideSipper(sipper)
|
||||||
|
|| (targetUid != BatteryUtils.UID_NULL && targetUid != uid.getUid())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -36,6 +36,7 @@ import org.junit.Test;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.util.ReflectionHelpers;
|
||||||
|
|
||||||
@RunWith(SettingsRobolectricTestRunner.class)
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
@@ -57,18 +58,7 @@ public class AnomalyDetectionPolicyTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInit_containsDataFromSettings() {
|
public void testInit_containsDataFromSettings() {
|
||||||
Settings.Global.putString(mContext.getContentResolver(),
|
AnomalyDetectionPolicy anomalyDetectionPolicy = createAnomalyPolicyWithConfig();
|
||||||
Settings.Global.ANOMALY_DETECTION_CONSTANTS, ANOMALY_DETECTION_CONSTANTS_VALUE);
|
|
||||||
// Mock it to avoid noSuchMethodError
|
|
||||||
doReturn(true).when(mKeyValueListParserWrapper).getBoolean(
|
|
||||||
AnomalyDetectionPolicy.KEY_ANOMALY_DETECTION_ENABLED, true);
|
|
||||||
doReturn(false).when(mKeyValueListParserWrapper).getBoolean(
|
|
||||||
AnomalyDetectionPolicy.KEY_WAKELOCK_DETECTION_ENABLED, true);
|
|
||||||
doReturn(true).when(mKeyValueListParserWrapper).getBoolean(
|
|
||||||
AnomalyDetectionPolicy.KEY_WAKEUP_ALARM_DETECTION_ENABLED, true);
|
|
||||||
|
|
||||||
AnomalyDetectionPolicy anomalyDetectionPolicy = new AnomalyDetectionPolicy(mContext,
|
|
||||||
mKeyValueListParserWrapper);
|
|
||||||
|
|
||||||
assertThat(anomalyDetectionPolicy.anomalyDetectionEnabled).isTrue();
|
assertThat(anomalyDetectionPolicy.anomalyDetectionEnabled).isTrue();
|
||||||
assertThat(anomalyDetectionPolicy.wakeLockDetectionEnabled).isFalse();
|
assertThat(anomalyDetectionPolicy.wakeLockDetectionEnabled).isFalse();
|
||||||
@@ -94,4 +84,30 @@ public class AnomalyDetectionPolicyTest {
|
|||||||
assertThat(anomalyDetectionPolicy.wakeupAlarmDetectionEnabled).isTrue();
|
assertThat(anomalyDetectionPolicy.wakeupAlarmDetectionEnabled).isTrue();
|
||||||
assertThat(anomalyDetectionPolicy.wakeupAlarmThreshold).isEqualTo(60);
|
assertThat(anomalyDetectionPolicy.wakeupAlarmThreshold).isEqualTo(60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAnomalyDetectorEnabled() {
|
||||||
|
AnomalyDetectionPolicy anomalyDetectionPolicy = createAnomalyPolicyWithConfig();
|
||||||
|
|
||||||
|
assertThat(anomalyDetectionPolicy.isAnomalyDetectorEnabled(
|
||||||
|
Anomaly.AnomalyType.WAKE_LOCK)).isFalse();
|
||||||
|
assertThat(anomalyDetectionPolicy.isAnomalyDetectorEnabled(
|
||||||
|
Anomaly.AnomalyType.WAKEUP_ALARM)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnomalyDetectionPolicy createAnomalyPolicyWithConfig() {
|
||||||
|
Settings.Global.putString(mContext.getContentResolver(),
|
||||||
|
Settings.Global.ANOMALY_DETECTION_CONSTANTS, ANOMALY_DETECTION_CONSTANTS_VALUE);
|
||||||
|
// Mock it to avoid noSuchMethodError
|
||||||
|
doReturn(true).when(mKeyValueListParserWrapper).getBoolean(
|
||||||
|
AnomalyDetectionPolicy.KEY_ANOMALY_DETECTION_ENABLED, true);
|
||||||
|
doReturn(false).when(mKeyValueListParserWrapper).getBoolean(
|
||||||
|
AnomalyDetectionPolicy.KEY_WAKELOCK_DETECTION_ENABLED, true);
|
||||||
|
doReturn(true).when(mKeyValueListParserWrapper).getBoolean(
|
||||||
|
AnomalyDetectionPolicy.KEY_WAKEUP_ALARM_DETECTION_ENABLED, true);
|
||||||
|
|
||||||
|
return new AnomalyDetectionPolicy(mContext, mKeyValueListParserWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -19,16 +19,19 @@ package com.android.settings.fuelgauge.anomaly;
|
|||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyInt;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.UserManager;
|
||||||
|
|
||||||
import com.android.internal.os.BatteryStatsHelper;
|
import com.android.internal.os.BatteryStatsHelper;
|
||||||
import com.android.settings.SettingsRobolectricTestRunner;
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
import com.android.settings.TestConfig;
|
import com.android.settings.TestConfig;
|
||||||
import com.android.settings.fuelgauge.anomaly.checker.WakeLockAnomalyDetector;
|
import com.android.settings.fuelgauge.anomaly.checker.WakeLockAnomalyDetector;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.checker.WakeupAlarmAnomalyDetector;
|
||||||
import com.android.settings.testutils.FakeFeatureFactory;
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -51,25 +54,39 @@ public class AnomalyLoaderTest {
|
|||||||
private BatteryStatsHelper mBatteryStatsHelper;
|
private BatteryStatsHelper mBatteryStatsHelper;
|
||||||
@Mock
|
@Mock
|
||||||
private WakeLockAnomalyDetector mWakeLockAnomalyDetector;
|
private WakeLockAnomalyDetector mWakeLockAnomalyDetector;
|
||||||
|
@Mock
|
||||||
|
private WakeupAlarmAnomalyDetector mWakeupAlarmAnomalyDetector;
|
||||||
|
@Mock
|
||||||
|
private AnomalyDetectionPolicy mAnomalyDetectionPolicy;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUserManager;
|
||||||
private Anomaly mWakeLockAnomaly;
|
private Anomaly mWakeLockAnomaly;
|
||||||
|
private Anomaly mWakeupAlarmAnomaly;
|
||||||
private List<Anomaly> mWakeLockAnomalies;
|
private List<Anomaly> mWakeLockAnomalies;
|
||||||
|
private List<Anomaly> mWakeupAlarmAnomalies;
|
||||||
private AnomalyLoader mAnomalyLoader;
|
private AnomalyLoader mAnomalyLoader;
|
||||||
private FakeFeatureFactory mFeatureFactory;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
FakeFeatureFactory.setupForTest(mContext);
|
FakeFeatureFactory.setupForTest(mContext);
|
||||||
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
|
doReturn(true).when(mAnomalyDetectionPolicy).isAnomalyDetectorEnabled(anyInt());
|
||||||
|
doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE);
|
||||||
|
|
||||||
mWakeLockAnomalies = new ArrayList<>();
|
mWakeLockAnomalies = new ArrayList<>();
|
||||||
mWakeLockAnomaly = new Anomaly.Builder()
|
mWakeLockAnomaly = createAnomaly(Anomaly.AnomalyType.WAKE_LOCK);
|
||||||
.setType(Anomaly.AnomalyType.WAKE_LOCK)
|
|
||||||
.build();
|
|
||||||
mWakeLockAnomalies.add(mWakeLockAnomaly);
|
mWakeLockAnomalies.add(mWakeLockAnomaly);
|
||||||
|
doReturn(mWakeLockAnomalies).when(mWakeLockAnomalyDetector).detectAnomalies(any(), any());
|
||||||
|
|
||||||
mAnomalyLoader = new AnomalyLoader(mContext, mBatteryStatsHelper);
|
mWakeupAlarmAnomalies = new ArrayList<>();
|
||||||
|
mWakeupAlarmAnomaly = createAnomaly(Anomaly.AnomalyType.WAKEUP_ALARM);
|
||||||
|
mWakeupAlarmAnomalies.add(mWakeupAlarmAnomaly);
|
||||||
|
doReturn(mWakeupAlarmAnomalies).when(mWakeupAlarmAnomalyDetector).detectAnomalies(any(),
|
||||||
|
any());
|
||||||
|
|
||||||
|
mAnomalyLoader = new AnomalyLoader(mContext, mBatteryStatsHelper, null,
|
||||||
|
mAnomalyDetectionPolicy);
|
||||||
mAnomalyLoader.mAnomalyUtils = spy(new AnomalyUtils(mContext));
|
mAnomalyLoader.mAnomalyUtils = spy(new AnomalyUtils(mContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,12 +94,17 @@ public class AnomalyLoaderTest {
|
|||||||
public void testLoadInBackground_containsValidAnomalies() {
|
public void testLoadInBackground_containsValidAnomalies() {
|
||||||
doReturn(mWakeLockAnomalyDetector).when(mAnomalyLoader.mAnomalyUtils).getAnomalyDetector(
|
doReturn(mWakeLockAnomalyDetector).when(mAnomalyLoader.mAnomalyUtils).getAnomalyDetector(
|
||||||
Anomaly.AnomalyType.WAKE_LOCK);
|
Anomaly.AnomalyType.WAKE_LOCK);
|
||||||
doReturn(mWakeLockAnomalies).when(mWakeLockAnomalyDetector).detectAnomalies(any());
|
doReturn(mWakeupAlarmAnomalyDetector).when(mAnomalyLoader.mAnomalyUtils).getAnomalyDetector(
|
||||||
when(mFeatureFactory.powerUsageFeatureProvider.isAnomalyDetectorEnabled(
|
Anomaly.AnomalyType.WAKEUP_ALARM);
|
||||||
Anomaly.AnomalyType.WAKE_LOCK)).thenReturn(true);
|
|
||||||
|
|
||||||
List<Anomaly> anomalies = mAnomalyLoader.loadInBackground();
|
List<Anomaly> anomalies = mAnomalyLoader.loadInBackground();
|
||||||
|
|
||||||
assertThat(anomalies).containsExactly(mWakeLockAnomaly);
|
assertThat(anomalies).containsExactly(mWakeLockAnomaly, mWakeupAlarmAnomaly);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Anomaly createAnomaly(@Anomaly.AnomalyType int type) {
|
||||||
|
return new Anomaly.Builder()
|
||||||
|
.setType(type)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -55,16 +55,20 @@ import java.util.List;
|
|||||||
@RunWith(SettingsRobolectricTestRunner.class)
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
public class WakeLockAnomalyDetectorTest {
|
public class WakeLockAnomalyDetectorTest {
|
||||||
|
private static final String TARGET_PACKAGE_NAME = "com.android.app";
|
||||||
private static final long ANOMALY_WAKELOCK_TIME_MS = 2 * DateUtils.HOUR_IN_MILLIS;
|
private static final long ANOMALY_WAKELOCK_TIME_MS = 2 * DateUtils.HOUR_IN_MILLIS;
|
||||||
private static final long NORMAL_WAKELOCK_TIME_MS = DateUtils.SECOND_IN_MILLIS;
|
private static final long NORMAL_WAKELOCK_TIME_MS = DateUtils.SECOND_IN_MILLIS;
|
||||||
private static final long WAKELOCK_THRESHOLD_MS = DateUtils.HOUR_IN_MILLIS;
|
private static final long WAKELOCK_THRESHOLD_MS = DateUtils.HOUR_IN_MILLIS;
|
||||||
private static final int ANOMALY_UID = 111;
|
private static final int ANOMALY_UID = 111;
|
||||||
private static final int NORMAL_UID = 222;
|
private static final int NORMAL_UID = 222;
|
||||||
|
private static final int TARGET_UID = 333;
|
||||||
@Mock
|
@Mock
|
||||||
private BatteryStatsHelper mBatteryStatsHelper;
|
private BatteryStatsHelper mBatteryStatsHelper;
|
||||||
@Mock
|
@Mock
|
||||||
private BatterySipper mAnomalySipper;
|
private BatterySipper mAnomalySipper;
|
||||||
@Mock
|
@Mock
|
||||||
|
private BatterySipper mTargetSipper;
|
||||||
|
@Mock
|
||||||
private BatteryStats.Timer mAnomalyTimer;
|
private BatteryStats.Timer mAnomalyTimer;
|
||||||
@Mock
|
@Mock
|
||||||
private BatteryStats.Uid.Wakelock mAnomalyWakelock;
|
private BatteryStats.Uid.Wakelock mAnomalyWakelock;
|
||||||
@@ -73,12 +77,18 @@ public class WakeLockAnomalyDetectorTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private BatteryStats.Timer mNormalTimer;
|
private BatteryStats.Timer mNormalTimer;
|
||||||
@Mock
|
@Mock
|
||||||
|
private BatteryStats.Timer mTargetTimer;
|
||||||
|
@Mock
|
||||||
private BatteryStats.Uid.Wakelock mNormalWakelock;
|
private BatteryStats.Uid.Wakelock mNormalWakelock;
|
||||||
@Mock
|
@Mock
|
||||||
|
private BatteryStats.Uid.Wakelock mTargetWakelock;
|
||||||
|
@Mock
|
||||||
private BatteryStats.Uid mAnomalyUid;
|
private BatteryStats.Uid mAnomalyUid;
|
||||||
@Mock
|
@Mock
|
||||||
private BatteryStats.Uid mNormalUid;
|
private BatteryStats.Uid mNormalUid;
|
||||||
@Mock
|
@Mock
|
||||||
|
private BatteryStats.Uid mTargetUid;
|
||||||
|
@Mock
|
||||||
private BatteryUtils mBatteryUtils;
|
private BatteryUtils mBatteryUtils;
|
||||||
@Mock
|
@Mock
|
||||||
private PackageManager mPackageManager;
|
private PackageManager mPackageManager;
|
||||||
@@ -89,6 +99,7 @@ public class WakeLockAnomalyDetectorTest {
|
|||||||
|
|
||||||
private ArrayMap<String, BatteryStats.Uid.Wakelock> mAnomalyWakelocks;
|
private ArrayMap<String, BatteryStats.Uid.Wakelock> mAnomalyWakelocks;
|
||||||
private ArrayMap<String, BatteryStats.Uid.Wakelock> mNormalWakelocks;
|
private ArrayMap<String, BatteryStats.Uid.Wakelock> mNormalWakelocks;
|
||||||
|
private ArrayMap<String, BatteryStats.Uid.Wakelock> mTargetWakelocks;
|
||||||
private WakeLockAnomalyDetector mWakelockAnomalyDetector;
|
private WakeLockAnomalyDetector mWakelockAnomalyDetector;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private List<BatterySipper> mUsageList;
|
private List<BatterySipper> mUsageList;
|
||||||
@@ -119,29 +130,58 @@ public class WakeLockAnomalyDetectorTest {
|
|||||||
doReturn(mNormalWakelocks).when(mNormalUid).getWakelockStats();
|
doReturn(mNormalWakelocks).when(mNormalUid).getWakelockStats();
|
||||||
doReturn(NORMAL_UID).when(mNormalUid).getUid();
|
doReturn(NORMAL_UID).when(mNormalUid).getUid();
|
||||||
|
|
||||||
|
mTargetSipper.uidObj = mTargetUid;
|
||||||
|
mTargetWakelocks = new ArrayMap<>();
|
||||||
|
mTargetWakelocks.put("", mTargetWakelock);
|
||||||
|
doReturn(mTargetTimer).when(mTargetWakelock).getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL);
|
||||||
|
doReturn(mTargetWakelocks).when(mTargetUid).getWakelockStats();
|
||||||
|
doReturn(TARGET_UID).when(mTargetUid).getUid();
|
||||||
|
|
||||||
mUsageList = new ArrayList<>();
|
mUsageList = new ArrayList<>();
|
||||||
mUsageList.add(mAnomalySipper);
|
mUsageList.add(mAnomalySipper);
|
||||||
mUsageList.add(mNormalSipper);
|
mUsageList.add(mNormalSipper);
|
||||||
|
mUsageList.add(mTargetSipper);
|
||||||
doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList();
|
doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList();
|
||||||
|
|
||||||
mWakelockAnomalyDetector = spy(new WakeLockAnomalyDetector(mContext, mPolicy));
|
mWakelockAnomalyDetector = spy(new WakeLockAnomalyDetector(mContext, mPolicy));
|
||||||
mWakelockAnomalyDetector.mBatteryUtils = mBatteryUtils;
|
mWakelockAnomalyDetector.mBatteryUtils = mBatteryUtils;
|
||||||
doReturn(ANOMALY_WAKELOCK_TIME_MS).when(mWakelockAnomalyDetector).getTotalDurationMs(
|
doReturn(ANOMALY_WAKELOCK_TIME_MS).when(mWakelockAnomalyDetector).getTotalDurationMs(
|
||||||
eq(mAnomalyTimer), anyLong());
|
eq(mAnomalyTimer), anyLong());
|
||||||
|
doReturn(ANOMALY_WAKELOCK_TIME_MS).when(mWakelockAnomalyDetector).getTotalDurationMs(
|
||||||
|
eq(mTargetTimer), anyLong());
|
||||||
doReturn(NORMAL_WAKELOCK_TIME_MS).when(mWakelockAnomalyDetector).getTotalDurationMs(
|
doReturn(NORMAL_WAKELOCK_TIME_MS).when(mWakelockAnomalyDetector).getTotalDurationMs(
|
||||||
eq(mNormalTimer), anyLong());
|
eq(mNormalTimer), anyLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDetectAnomalies_containsAnomaly_detectIt() {
|
public void testDetectAnomalies_containsAnomaly_detectIt() {
|
||||||
|
doReturn(BatteryUtils.UID_NULL).when(mBatteryUtils).getPackageUid(nullable(String.class));
|
||||||
final Anomaly anomaly = new Anomaly.Builder()
|
final Anomaly anomaly = new Anomaly.Builder()
|
||||||
.setUid(ANOMALY_UID)
|
.setUid(ANOMALY_UID)
|
||||||
.setType(Anomaly.AnomalyType.WAKE_LOCK)
|
.setType(Anomaly.AnomalyType.WAKE_LOCK)
|
||||||
.build();
|
.build();
|
||||||
|
final Anomaly targetAnomaly = new Anomaly.Builder()
|
||||||
|
.setUid(TARGET_UID)
|
||||||
|
.setType(Anomaly.AnomalyType.WAKE_LOCK)
|
||||||
|
.build();
|
||||||
|
|
||||||
List<Anomaly> mAnomalies = mWakelockAnomalyDetector.detectAnomalies(mBatteryStatsHelper);
|
List<Anomaly> mAnomalies = mWakelockAnomalyDetector.detectAnomalies(mBatteryStatsHelper);
|
||||||
|
|
||||||
assertThat(mAnomalies).containsExactly(anomaly);
|
assertThat(mAnomalies).containsExactly(anomaly, targetAnomaly);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDetectAnomalies_containsTargetpackage_detectIt() {
|
||||||
|
doReturn(TARGET_UID).when(mBatteryUtils).getPackageUid(TARGET_PACKAGE_NAME);
|
||||||
|
final Anomaly targetAnomaly = new Anomaly.Builder()
|
||||||
|
.setUid(TARGET_UID)
|
||||||
|
.setType(Anomaly.AnomalyType.WAKE_LOCK)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
List<Anomaly> mAnomalies = mWakelockAnomalyDetector.detectAnomalies(mBatteryStatsHelper,
|
||||||
|
TARGET_PACKAGE_NAME);
|
||||||
|
|
||||||
|
assertThat(mAnomalies).containsExactly(targetAnomaly);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge.anomaly.checker;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.nullable;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyInt;
|
import static org.mockito.Matchers.anyInt;
|
||||||
import static org.mockito.Matchers.anyLong;
|
import static org.mockito.Matchers.anyLong;
|
||||||
@@ -56,8 +57,10 @@ import java.util.List;
|
|||||||
@RunWith(SettingsRobolectricTestRunner.class)
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
public class WakeupAlarmAnomalyDetectorTest {
|
public class WakeupAlarmAnomalyDetectorTest {
|
||||||
|
private static final String TARGET_PACKAGE_NAME = "com.android.app";
|
||||||
private static final int ANOMALY_UID = 111;
|
private static final int ANOMALY_UID = 111;
|
||||||
private static final int NORMAL_UID = 222;
|
private static final int NORMAL_UID = 222;
|
||||||
|
private static final int TARGET_UID = 333;
|
||||||
private static final long RUNNING_TIME_MS = 2 * DateUtils.HOUR_IN_MILLIS;
|
private static final long RUNNING_TIME_MS = 2 * DateUtils.HOUR_IN_MILLIS;
|
||||||
private static final int ANOMALY_WAKEUP_COUNT = 500;
|
private static final int ANOMALY_WAKEUP_COUNT = 500;
|
||||||
private static final int NORMAL_WAKEUP_COUNT = 50;
|
private static final int NORMAL_WAKEUP_COUNT = 50;
|
||||||
@@ -68,10 +71,14 @@ public class WakeupAlarmAnomalyDetectorTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private BatterySipper mNormalSipper;
|
private BatterySipper mNormalSipper;
|
||||||
@Mock
|
@Mock
|
||||||
|
private BatterySipper mTargetSipper;
|
||||||
|
@Mock
|
||||||
private BatteryStats.Uid mAnomalyUid;
|
private BatteryStats.Uid mAnomalyUid;
|
||||||
@Mock
|
@Mock
|
||||||
private BatteryStats.Uid mNormalUid;
|
private BatteryStats.Uid mNormalUid;
|
||||||
@Mock
|
@Mock
|
||||||
|
private BatteryStats.Uid mTargetUid;
|
||||||
|
@Mock
|
||||||
private BatteryUtils mBatteryUtils;
|
private BatteryUtils mBatteryUtils;
|
||||||
@Mock
|
@Mock
|
||||||
private ApplicationInfo mApplicationInfo;
|
private ApplicationInfo mApplicationInfo;
|
||||||
@@ -101,10 +108,13 @@ public class WakeupAlarmAnomalyDetectorTest {
|
|||||||
doReturn(ANOMALY_UID).when(mAnomalyUid).getUid();
|
doReturn(ANOMALY_UID).when(mAnomalyUid).getUid();
|
||||||
mNormalSipper.uidObj = mNormalUid;
|
mNormalSipper.uidObj = mNormalUid;
|
||||||
doReturn(NORMAL_UID).when(mNormalUid).getUid();
|
doReturn(NORMAL_UID).when(mNormalUid).getUid();
|
||||||
|
mTargetSipper.uidObj = mTargetUid;
|
||||||
|
doReturn(TARGET_UID).when(mTargetUid).getUid();
|
||||||
|
|
||||||
mUsageList = new ArrayList<>();
|
mUsageList = new ArrayList<>();
|
||||||
mUsageList.add(mAnomalySipper);
|
mUsageList.add(mAnomalySipper);
|
||||||
mUsageList.add(mNormalSipper);
|
mUsageList.add(mNormalSipper);
|
||||||
|
mUsageList.add(mTargetSipper);
|
||||||
doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList();
|
doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList();
|
||||||
|
|
||||||
mWakeupAlarmAnomalyDetector = spy(new WakeupAlarmAnomalyDetector(mContext, mPolicy));
|
mWakeupAlarmAnomalyDetector = spy(new WakeupAlarmAnomalyDetector(mContext, mPolicy));
|
||||||
@@ -113,18 +123,45 @@ public class WakeupAlarmAnomalyDetectorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDetectAnomalies_containsAnomaly_detectIt() {
|
public void testDetectAnomalies_containsAnomaly_detectIt() {
|
||||||
|
doReturn(-1).when(mBatteryUtils).getPackageUid(nullable(String.class));
|
||||||
doReturn(ANOMALY_WAKEUP_COUNT).when(mWakeupAlarmAnomalyDetector).getWakeupAlarmCountFromUid(
|
doReturn(ANOMALY_WAKEUP_COUNT).when(mWakeupAlarmAnomalyDetector).getWakeupAlarmCountFromUid(
|
||||||
mAnomalyUid);
|
mAnomalyUid);
|
||||||
|
doReturn(ANOMALY_WAKEUP_COUNT).when(mWakeupAlarmAnomalyDetector).getWakeupAlarmCountFromUid(
|
||||||
|
mTargetUid);
|
||||||
doReturn(NORMAL_WAKEUP_COUNT).when(mWakeupAlarmAnomalyDetector).getWakeupAlarmCountFromUid(
|
doReturn(NORMAL_WAKEUP_COUNT).when(mWakeupAlarmAnomalyDetector).getWakeupAlarmCountFromUid(
|
||||||
mNormalUid);
|
mNormalUid);
|
||||||
final Anomaly anomaly = new Anomaly.Builder()
|
final Anomaly anomaly = new Anomaly.Builder()
|
||||||
.setUid(ANOMALY_UID)
|
.setUid(ANOMALY_UID)
|
||||||
.setType(Anomaly.AnomalyType.WAKEUP_ALARM)
|
.setType(Anomaly.AnomalyType.WAKEUP_ALARM)
|
||||||
.build();
|
.build();
|
||||||
|
final Anomaly targetAnomaly = new Anomaly.Builder()
|
||||||
|
.setUid(TARGET_UID)
|
||||||
|
.setType(Anomaly.AnomalyType.WAKEUP_ALARM)
|
||||||
|
.build();
|
||||||
|
|
||||||
List<Anomaly> mAnomalies = mWakeupAlarmAnomalyDetector.detectAnomalies(mBatteryStatsHelper);
|
List<Anomaly> mAnomalies = mWakeupAlarmAnomalyDetector.detectAnomalies(mBatteryStatsHelper);
|
||||||
|
|
||||||
assertThat(mAnomalies).containsExactly(anomaly);
|
assertThat(mAnomalies).containsExactly(anomaly, targetAnomaly);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDetectAnomalies_detectTargetAnomaly_detectIt() {
|
||||||
|
doReturn(TARGET_UID).when(mBatteryUtils).getPackageUid(TARGET_PACKAGE_NAME);
|
||||||
|
doReturn(ANOMALY_WAKEUP_COUNT).when(mWakeupAlarmAnomalyDetector).getWakeupAlarmCountFromUid(
|
||||||
|
mAnomalyUid);
|
||||||
|
doReturn(ANOMALY_WAKEUP_COUNT).when(mWakeupAlarmAnomalyDetector).getWakeupAlarmCountFromUid(
|
||||||
|
mTargetUid);
|
||||||
|
doReturn(NORMAL_WAKEUP_COUNT).when(mWakeupAlarmAnomalyDetector).getWakeupAlarmCountFromUid(
|
||||||
|
mNormalUid);
|
||||||
|
final Anomaly targetAnomaly = new Anomaly.Builder()
|
||||||
|
.setUid(TARGET_UID)
|
||||||
|
.setType(Anomaly.AnomalyType.WAKEUP_ALARM)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
List<Anomaly> mAnomalies = mWakeupAlarmAnomalyDetector.detectAnomalies(mBatteryStatsHelper,
|
||||||
|
TARGET_PACKAGE_NAME);
|
||||||
|
|
||||||
|
assertThat(mAnomalies).containsExactly(targetAnomaly);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Reference in New Issue
Block a user