Merge "Add anomaly detector for unoptimized bt scanning" into oc-dr1-dev
am: 37da099df1
Change-Id: I76dccf645d50c1160010ad59607a4ffeba6a3035
This commit is contained in:
@@ -35,10 +35,12 @@ import java.util.Objects;
|
|||||||
public class Anomaly implements Parcelable {
|
public class Anomaly implements Parcelable {
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@IntDef({AnomalyType.WAKE_LOCK,
|
@IntDef({AnomalyType.WAKE_LOCK,
|
||||||
AnomalyType.WAKEUP_ALARM})
|
AnomalyType.WAKEUP_ALARM,
|
||||||
|
AnomalyType.BLUETOOTH_SCAN})
|
||||||
public @interface AnomalyType {
|
public @interface AnomalyType {
|
||||||
int WAKE_LOCK = 0;
|
int WAKE_LOCK = 0;
|
||||||
int WAKEUP_ALARM = 1;
|
int WAKEUP_ALARM = 1;
|
||||||
|
int BLUETOOTH_SCAN = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@@ -52,7 +54,8 @@ public class Anomaly implements Parcelable {
|
|||||||
@AnomalyType
|
@AnomalyType
|
||||||
public static final int[] ANOMALY_TYPE_LIST =
|
public static final int[] ANOMALY_TYPE_LIST =
|
||||||
{AnomalyType.WAKE_LOCK,
|
{AnomalyType.WAKE_LOCK,
|
||||||
AnomalyType.WAKEUP_ALARM};
|
AnomalyType.WAKEUP_ALARM,
|
||||||
|
AnomalyType.BLUETOOTH_SCAN};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type of this this anomaly
|
* Type of this this anomaly
|
||||||
|
@@ -22,9 +22,9 @@ import android.os.BatteryStats;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.support.annotation.VisibleForTesting;
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.internal.os.BatteryStatsHelper;
|
import com.android.internal.os.BatteryStatsHelper;
|
||||||
import com.android.settings.Utils;
|
|
||||||
import com.android.settings.utils.AsyncLoader;
|
import com.android.settings.utils.AsyncLoader;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -35,6 +35,8 @@ import java.util.List;
|
|||||||
* an empty list if there is no anomaly.
|
* an empty list if there is no anomaly.
|
||||||
*/
|
*/
|
||||||
public class AnomalyLoader extends AsyncLoader<List<Anomaly>> {
|
public class AnomalyLoader extends AsyncLoader<List<Anomaly>> {
|
||||||
|
private static final String TAG = "AnomalyLoader";
|
||||||
|
|
||||||
private static final boolean USE_FAKE_DATA = false;
|
private static final boolean USE_FAKE_DATA = false;
|
||||||
private BatteryStatsHelper mBatteryStatsHelper;
|
private BatteryStatsHelper mBatteryStatsHelper;
|
||||||
private String mPackageName;
|
private String mPackageName;
|
||||||
@@ -108,9 +110,9 @@ public class AnomalyLoader extends AsyncLoader<List<Anomaly>> {
|
|||||||
List<Anomaly> generateFakeData() {
|
List<Anomaly> generateFakeData() {
|
||||||
final List<Anomaly> anomalies = new ArrayList<>();
|
final List<Anomaly> anomalies = new ArrayList<>();
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
try {
|
|
||||||
final String packageName = "com.android.settings";
|
final String packageName = "com.android.settings";
|
||||||
final CharSequence displayName = "Settings";
|
final CharSequence displayName = "Settings";
|
||||||
|
try {
|
||||||
final int uid = context.getPackageManager().getPackageUid(packageName, 0);
|
final int uid = context.getPackageManager().getPackageUid(packageName, 0);
|
||||||
|
|
||||||
anomalies.add(new Anomaly.Builder()
|
anomalies.add(new Anomaly.Builder()
|
||||||
@@ -125,8 +127,14 @@ public class AnomalyLoader extends AsyncLoader<List<Anomaly>> {
|
|||||||
.setPackageName(packageName)
|
.setPackageName(packageName)
|
||||||
.setDisplayName(displayName)
|
.setDisplayName(displayName)
|
||||||
.build());
|
.build());
|
||||||
|
anomalies.add(new Anomaly.Builder()
|
||||||
|
.setUid(uid)
|
||||||
|
.setType(Anomaly.AnomalyType.BLUETOOTH_SCAN)
|
||||||
|
.setPackageName(packageName)
|
||||||
|
.setDisplayName(displayName)
|
||||||
|
.build());
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
e.printStackTrace();
|
Log.e(TAG, "Cannot find package by name: " + packageName, e);
|
||||||
}
|
}
|
||||||
return anomalies;
|
return anomalies;
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@ import com.android.settings.fuelgauge.anomaly.action.AnomalyAction;
|
|||||||
import com.android.settings.fuelgauge.anomaly.action.BackgroundCheckAction;
|
import com.android.settings.fuelgauge.anomaly.action.BackgroundCheckAction;
|
||||||
import com.android.settings.fuelgauge.anomaly.action.ForceStopAction;
|
import com.android.settings.fuelgauge.anomaly.action.ForceStopAction;
|
||||||
import com.android.settings.fuelgauge.anomaly.checker.AnomalyDetector;
|
import com.android.settings.fuelgauge.anomaly.checker.AnomalyDetector;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.checker.BluetoothScanAnomalyDetector;
|
||||||
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.fuelgauge.anomaly.checker.WakeupAlarmAnomalyDetector;
|
||||||
|
|
||||||
@@ -56,6 +57,7 @@ public class AnomalyUtils {
|
|||||||
case Anomaly.AnomalyType.WAKE_LOCK:
|
case Anomaly.AnomalyType.WAKE_LOCK:
|
||||||
return new ForceStopAction(mContext);
|
return new ForceStopAction(mContext);
|
||||||
case Anomaly.AnomalyType.WAKEUP_ALARM:
|
case Anomaly.AnomalyType.WAKEUP_ALARM:
|
||||||
|
case Anomaly.AnomalyType.BLUETOOTH_SCAN:
|
||||||
return new BackgroundCheckAction(mContext);
|
return new BackgroundCheckAction(mContext);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
@@ -74,6 +76,8 @@ public class AnomalyUtils {
|
|||||||
return new WakeLockAnomalyDetector(mContext);
|
return new WakeLockAnomalyDetector(mContext);
|
||||||
case Anomaly.AnomalyType.WAKEUP_ALARM:
|
case Anomaly.AnomalyType.WAKEUP_ALARM:
|
||||||
return new WakeupAlarmAnomalyDetector(mContext);
|
return new WakeupAlarmAnomalyDetector(mContext);
|
||||||
|
case Anomaly.AnomalyType.BLUETOOTH_SCAN:
|
||||||
|
return new BluetoothScanAnomalyDetector(mContext);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.fuelgauge.anomaly.checker;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.BatteryStats;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
|
import android.util.ArrayMap;
|
||||||
|
|
||||||
|
import com.android.internal.os.BatterySipper;
|
||||||
|
import com.android.internal.os.BatteryStatsHelper;
|
||||||
|
import com.android.settings.Utils;
|
||||||
|
import com.android.settings.fuelgauge.BatteryUtils;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.Anomaly;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.AnomalyDetectionPolicy;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.AnomalyUtils;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.action.AnomalyAction;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether apps have unoptimized bluetooth scanning in the background
|
||||||
|
*/
|
||||||
|
public class BluetoothScanAnomalyDetector implements AnomalyDetector {
|
||||||
|
private static final String TAG = "BluetoothScanAnomalyDetector";
|
||||||
|
@VisibleForTesting
|
||||||
|
BatteryUtils mBatteryUtils;
|
||||||
|
@VisibleForTesting
|
||||||
|
AnomalyAction mAnomalyAction;
|
||||||
|
private long mBluetoothScanningThreshold;
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
public BluetoothScanAnomalyDetector(Context context) {
|
||||||
|
this(context, new AnomalyDetectionPolicy(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
BluetoothScanAnomalyDetector(Context context, AnomalyDetectionPolicy policy) {
|
||||||
|
mContext = context;
|
||||||
|
mBatteryUtils = BatteryUtils.getInstance(context);
|
||||||
|
mAnomalyAction = AnomalyUtils.getInstance(context).getAnomalyAction(
|
||||||
|
Anomaly.AnomalyType.BLUETOOTH_SCAN);
|
||||||
|
//TODO(b/36921532): hook up it to AnomalyDectionPolicy
|
||||||
|
mBluetoothScanningThreshold = 30 * DateUtils.MINUTE_IN_MILLIS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper) {
|
||||||
|
// Detect all apps if targetPackageName is null
|
||||||
|
return detectAnomalies(batteryStatsHelper, null /* targetPackageName */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper,
|
||||||
|
String targetPackageName) {
|
||||||
|
final List<BatterySipper> batterySippers = batteryStatsHelper.getUsageList();
|
||||||
|
final List<Anomaly> anomalies = new ArrayList<>();
|
||||||
|
final int targetUid = mBatteryUtils.getPackageUid(targetPackageName);
|
||||||
|
final long elapsedRealtimeMs = SystemClock.elapsedRealtime();
|
||||||
|
|
||||||
|
for (int i = 0, size = batterySippers.size(); i < size; i++) {
|
||||||
|
final BatterySipper sipper = batterySippers.get(i);
|
||||||
|
final BatteryStats.Uid uid = sipper.uidObj;
|
||||||
|
if (uid == null
|
||||||
|
|| mBatteryUtils.shouldHideSipper(sipper)
|
||||||
|
|| (targetUid != BatteryUtils.UID_NULL && targetUid != uid.getUid())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final long bluetoothTimeMs = getBluetoothUnoptimizedBgTimeMs(uid, elapsedRealtimeMs);
|
||||||
|
if (bluetoothTimeMs > mBluetoothScanningThreshold) {
|
||||||
|
final String packageName = mBatteryUtils.getPackageName(uid.getUid());
|
||||||
|
final CharSequence displayName = Utils.getApplicationLabel(mContext,
|
||||||
|
packageName);
|
||||||
|
|
||||||
|
Anomaly anomaly = new Anomaly.Builder()
|
||||||
|
.setUid(uid.getUid())
|
||||||
|
.setType(Anomaly.AnomalyType.BLUETOOTH_SCAN)
|
||||||
|
.setDisplayName(displayName)
|
||||||
|
.setPackageName(packageName)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if (mAnomalyAction.isActionActive(anomaly)) {
|
||||||
|
anomalies.add(anomaly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return anomalies;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public long getBluetoothUnoptimizedBgTimeMs(BatteryStats.Uid uid, long elapsedRealtimeMs) {
|
||||||
|
BatteryStats.Timer timer = uid.getBluetoothUnoptimizedScanBackgroundTimer();
|
||||||
|
|
||||||
|
return timer != null ? timer.getTotalDurationMsLocked(elapsedRealtimeMs) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -65,7 +65,8 @@ public class WakeLockAnomalyDetector implements AnomalyDetector {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper) {
|
public List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper) {
|
||||||
return detectAnomalies(batteryStatsHelper, null);
|
// Detect all apps if targetPackageName is null
|
||||||
|
return detectAnomalies(batteryStatsHelper, null /* targetPackageName */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -61,7 +61,8 @@ public class WakeupAlarmAnomalyDetector implements AnomalyDetector {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper) {
|
public List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper) {
|
||||||
return detectAnomalies(batteryStatsHelper, null);
|
// Detect all apps if targetPackageName is null
|
||||||
|
return detectAnomalies(batteryStatsHelper, null /* targetPackageName */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -30,6 +30,7 @@ import android.content.pm.PackageManager;
|
|||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
|
|
||||||
import com.android.internal.os.BatteryStatsHelper;
|
import com.android.internal.os.BatteryStatsHelper;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.checker.BluetoothScanAnomalyDetector;
|
||||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
import com.android.settings.testutils.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;
|
||||||
@@ -62,13 +63,17 @@ public class AnomalyLoaderTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private WakeupAlarmAnomalyDetector mWakeupAlarmAnomalyDetector;
|
private WakeupAlarmAnomalyDetector mWakeupAlarmAnomalyDetector;
|
||||||
@Mock
|
@Mock
|
||||||
|
private BluetoothScanAnomalyDetector mBluetoothScanAnomalyDetector;
|
||||||
|
@Mock
|
||||||
private AnomalyDetectionPolicy mAnomalyDetectionPolicy;
|
private AnomalyDetectionPolicy mAnomalyDetectionPolicy;
|
||||||
@Mock
|
@Mock
|
||||||
private UserManager mUserManager;
|
private UserManager mUserManager;
|
||||||
private Anomaly mWakeLockAnomaly;
|
private Anomaly mWakeLockAnomaly;
|
||||||
private Anomaly mWakeupAlarmAnomaly;
|
private Anomaly mWakeupAlarmAnomaly;
|
||||||
|
private Anomaly mBluetoothScanAnomaly;
|
||||||
private List<Anomaly> mWakeLockAnomalies;
|
private List<Anomaly> mWakeLockAnomalies;
|
||||||
private List<Anomaly> mWakeupAlarmAnomalies;
|
private List<Anomaly> mWakeupAlarmAnomalies;
|
||||||
|
private List<Anomaly> mBluetoothScanAnomalies;
|
||||||
private AnomalyLoader mAnomalyLoader;
|
private AnomalyLoader mAnomalyLoader;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -91,6 +96,12 @@ public class AnomalyLoaderTest {
|
|||||||
doReturn(mWakeupAlarmAnomalies).when(mWakeupAlarmAnomalyDetector).detectAnomalies(any(),
|
doReturn(mWakeupAlarmAnomalies).when(mWakeupAlarmAnomalyDetector).detectAnomalies(any(),
|
||||||
any());
|
any());
|
||||||
|
|
||||||
|
mBluetoothScanAnomalies = new ArrayList<>();
|
||||||
|
mBluetoothScanAnomaly = createAnomaly(Anomaly.AnomalyType.BLUETOOTH_SCAN);
|
||||||
|
mBluetoothScanAnomalies.add(mBluetoothScanAnomaly);
|
||||||
|
doReturn(mBluetoothScanAnomalies).when(mBluetoothScanAnomalyDetector).detectAnomalies(any(),
|
||||||
|
any());
|
||||||
|
|
||||||
mAnomalyLoader = new AnomalyLoader(mContext, mBatteryStatsHelper, null,
|
mAnomalyLoader = new AnomalyLoader(mContext, mBatteryStatsHelper, null,
|
||||||
mAnomalyDetectionPolicy);
|
mAnomalyDetectionPolicy);
|
||||||
mAnomalyLoader.mAnomalyUtils = spy(new AnomalyUtils(mContext));
|
mAnomalyLoader.mAnomalyUtils = spy(new AnomalyUtils(mContext));
|
||||||
@@ -102,10 +113,14 @@ public class AnomalyLoaderTest {
|
|||||||
Anomaly.AnomalyType.WAKE_LOCK);
|
Anomaly.AnomalyType.WAKE_LOCK);
|
||||||
doReturn(mWakeupAlarmAnomalyDetector).when(mAnomalyLoader.mAnomalyUtils).getAnomalyDetector(
|
doReturn(mWakeupAlarmAnomalyDetector).when(mAnomalyLoader.mAnomalyUtils).getAnomalyDetector(
|
||||||
Anomaly.AnomalyType.WAKEUP_ALARM);
|
Anomaly.AnomalyType.WAKEUP_ALARM);
|
||||||
|
doReturn(mBluetoothScanAnomalyDetector).when(
|
||||||
|
mAnomalyLoader.mAnomalyUtils).getAnomalyDetector(
|
||||||
|
Anomaly.AnomalyType.BLUETOOTH_SCAN);
|
||||||
|
|
||||||
List<Anomaly> anomalies = mAnomalyLoader.loadInBackground();
|
List<Anomaly> anomalies = mAnomalyLoader.loadInBackground();
|
||||||
|
|
||||||
assertThat(anomalies).containsExactly(mWakeLockAnomaly, mWakeupAlarmAnomaly);
|
assertThat(anomalies).containsExactly(mWakeLockAnomaly, mWakeupAlarmAnomaly,
|
||||||
|
mBluetoothScanAnomaly);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Anomaly createAnomaly(@Anomaly.AnomalyType int type) {
|
private Anomaly createAnomaly(@Anomaly.AnomalyType int type) {
|
||||||
@@ -121,6 +136,7 @@ public class AnomalyLoaderTest {
|
|||||||
public void testGenerateFakeData() {
|
public void testGenerateFakeData() {
|
||||||
List<Anomaly> anomalies = mAnomalyLoader.generateFakeData();
|
List<Anomaly> anomalies = mAnomalyLoader.generateFakeData();
|
||||||
|
|
||||||
assertThat(anomalies).containsExactly(mWakeLockAnomaly, mWakeupAlarmAnomaly);
|
assertThat(anomalies).containsExactly(mWakeLockAnomaly, mWakeupAlarmAnomaly,
|
||||||
|
mBluetoothScanAnomaly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.fuelgauge.anomaly.checker;
|
||||||
|
|
||||||
|
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.anyLong;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.os.BatteryStats;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
|
|
||||||
|
import com.android.internal.os.BatterySipper;
|
||||||
|
import com.android.internal.os.BatteryStatsHelper;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.fuelgauge.BatteryUtils;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.Anomaly;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.AnomalyDetectionPolicy;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.action.AnomalyAction;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class BluetoothScanAnomalyDetectorTest {
|
||||||
|
private static final String TARGET_PACKAGE_NAME = "com.android.app";
|
||||||
|
private static final int ANOMALY_UID = 111;
|
||||||
|
private static final int NORMAL_UID = 222;
|
||||||
|
private static final int TARGET_UID = 333;
|
||||||
|
private static final long ANOMALY_BLUETOOTH_SCANNING_TIME = DateUtils.HOUR_IN_MILLIS;
|
||||||
|
private static final long NORMAL_BLUETOOTH_SCANNING_TIME = DateUtils.MINUTE_IN_MILLIS;
|
||||||
|
@Mock
|
||||||
|
private BatteryStatsHelper mBatteryStatsHelper;
|
||||||
|
@Mock
|
||||||
|
private BatterySipper mAnomalySipper;
|
||||||
|
@Mock
|
||||||
|
private BatterySipper mNormalSipper;
|
||||||
|
@Mock
|
||||||
|
private BatterySipper mTargetSipper;
|
||||||
|
@Mock
|
||||||
|
private BatteryStats.Uid mAnomalyUid;
|
||||||
|
@Mock
|
||||||
|
private BatteryStats.Uid mNormalUid;
|
||||||
|
@Mock
|
||||||
|
private BatteryStats.Uid mTargetUid;
|
||||||
|
@Mock
|
||||||
|
private BatteryUtils mBatteryUtils;
|
||||||
|
@Mock
|
||||||
|
private AnomalyDetectionPolicy mPolicy;
|
||||||
|
@Mock
|
||||||
|
private AnomalyAction mAnomalyAction;
|
||||||
|
|
||||||
|
private BluetoothScanAnomalyDetector mBluetoothScanAnomalyDetector;
|
||||||
|
private Context mContext;
|
||||||
|
private List<BatterySipper> mUsageList;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
mContext = spy(RuntimeEnvironment.application);
|
||||||
|
|
||||||
|
mAnomalySipper.uidObj = mAnomalyUid;
|
||||||
|
doReturn(ANOMALY_UID).when(mAnomalyUid).getUid();
|
||||||
|
mNormalSipper.uidObj = mNormalUid;
|
||||||
|
doReturn(NORMAL_UID).when(mNormalUid).getUid();
|
||||||
|
mTargetSipper.uidObj = mTargetUid;
|
||||||
|
doReturn(TARGET_UID).when(mTargetUid).getUid();
|
||||||
|
|
||||||
|
mUsageList = new ArrayList<>();
|
||||||
|
mUsageList.add(mAnomalySipper);
|
||||||
|
mUsageList.add(mNormalSipper);
|
||||||
|
mUsageList.add(mTargetSipper);
|
||||||
|
doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList();
|
||||||
|
|
||||||
|
mBluetoothScanAnomalyDetector = spy(new BluetoothScanAnomalyDetector(mContext, mPolicy));
|
||||||
|
mBluetoothScanAnomalyDetector.mBatteryUtils = mBatteryUtils;
|
||||||
|
mBluetoothScanAnomalyDetector.mAnomalyAction = mAnomalyAction;
|
||||||
|
doReturn(false).when(mBatteryUtils).shouldHideSipper(any());
|
||||||
|
doReturn(true).when(mAnomalyAction).isActionActive(any());
|
||||||
|
|
||||||
|
doReturn(ANOMALY_BLUETOOTH_SCANNING_TIME).when(
|
||||||
|
mBluetoothScanAnomalyDetector).getBluetoothUnoptimizedBgTimeMs(eq(mAnomalyUid),
|
||||||
|
anyLong());
|
||||||
|
doReturn(ANOMALY_BLUETOOTH_SCANNING_TIME).when(
|
||||||
|
mBluetoothScanAnomalyDetector).getBluetoothUnoptimizedBgTimeMs(eq(mTargetUid),
|
||||||
|
anyLong());
|
||||||
|
doReturn(NORMAL_BLUETOOTH_SCANNING_TIME).when(
|
||||||
|
mBluetoothScanAnomalyDetector).getBluetoothUnoptimizedBgTimeMs(eq(mNormalUid),
|
||||||
|
anyLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDetectAnomalies_containsAnomaly_detectIt() {
|
||||||
|
doReturn(-1).when(mBatteryUtils).getPackageUid(nullable(String.class));
|
||||||
|
final Anomaly anomaly = createBluetoothAnomaly(ANOMALY_UID);
|
||||||
|
final Anomaly targetAnomaly = createBluetoothAnomaly(TARGET_UID);
|
||||||
|
|
||||||
|
List<Anomaly> mAnomalies = mBluetoothScanAnomalyDetector.detectAnomalies(
|
||||||
|
mBatteryStatsHelper);
|
||||||
|
|
||||||
|
assertThat(mAnomalies).containsExactly(anomaly, targetAnomaly);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDetectAnomalies_detectTargetAnomaly_detectIt() {
|
||||||
|
doReturn(TARGET_UID).when(mBatteryUtils).getPackageUid(TARGET_PACKAGE_NAME);
|
||||||
|
final Anomaly targetAnomaly = createBluetoothAnomaly(TARGET_UID);
|
||||||
|
|
||||||
|
List<Anomaly> mAnomalies = mBluetoothScanAnomalyDetector.detectAnomalies(
|
||||||
|
mBatteryStatsHelper, TARGET_PACKAGE_NAME);
|
||||||
|
|
||||||
|
assertThat(mAnomalies).containsExactly(targetAnomaly);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Anomaly createBluetoothAnomaly(int uid) {
|
||||||
|
return new Anomaly.Builder()
|
||||||
|
.setUid(uid)
|
||||||
|
.setType(Anomaly.AnomalyType.BLUETOOTH_SCAN)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user