From bfc2b11b9357c4508756243f540760458611b3b8 Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Thu, 29 Jun 2017 14:20:46 -0700 Subject: [PATCH] Update Anomaly detection framework This cl make it could have multiple actions for each anomaly type. This includes: 1. Add field "targetSdkVersion", "bgRestrictionEnabled" in Anomaly 2. Add new action which includes "force stop" and "background check" 3. Add "sdkVersion" and "bgRestrictionEnabled" method in BatteryUtils 4. Update BackgroundCheckAction to check sdkVersion first 5. Update serveral tests and add new test Bug: 63037765 Test: RunSettingsRoboTests Change-Id: Iea7a131ee57d501f7737ae4a3ba672d948d05cd8 --- .../settings/fuelgauge/BatteryUtils.java | 39 +++++++- .../settings/fuelgauge/anomaly/Anomaly.java | 40 +++++++- .../anomaly/AnomalyDialogFragment.java | 10 +- .../fuelgauge/anomaly/AnomalyUtils.java | 17 +++- .../anomaly/action/BackgroundCheckAction.java | 19 ++-- .../action/StopAndBackgroundCheckAction.java | 63 +++++++++++++ .../checker/BluetoothScanAnomalyDetector.java | 13 +-- .../checker/WakeLockAnomalyDetector.java | 24 ++--- .../checker/WakeupAlarmAnomalyDetector.java | 13 ++- .../applications/InstalledAppDetailsTest.java | 4 + .../AdvancedPowerUsageDetailTest.java | 4 + .../settings/fuelgauge/BatteryUtilsTest.java | 58 +++++++++++- .../anomaly/AnomalyDialogFragmentTest.java | 35 ++++++- .../fuelgauge/anomaly/AnomalyTest.java | 7 ++ .../fuelgauge/anomaly/AnomalyUtilsTest.java | 47 ++++++++-- .../action/BackgroundCheckActionTest.java | 21 +++-- .../action/StopAndBackgroundActionTest.java | 93 +++++++++++++++++++ .../BluetoothScanAnomalyDetectorTest.java | 9 +- .../checker/WakeLockAnomalyDetectorTest.java | 8 +- .../WakeupAlarmAnomalyDetectorTest.java | 8 +- 20 files changed, 457 insertions(+), 75 deletions(-) create mode 100644 src/com/android/settings/fuelgauge/anomaly/action/StopAndBackgroundCheckAction.java create mode 100644 tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/StopAndBackgroundActionTest.java diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java index b579fd9d176..e98ed82cd12 100644 --- a/src/com/android/settings/fuelgauge/BatteryUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryUtils.java @@ -15,10 +15,13 @@ */ package com.android.settings.fuelgauge; +import android.app.AppOpsManager; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.BatteryStats; import android.os.Bundle; +import android.os.Build; import android.os.SystemClock; import android.os.UserManager; import android.support.annotation.IntDef; @@ -47,6 +50,7 @@ import java.util.List; */ public class BatteryUtils { public static final int UID_NULL = -1; + public static final int SDK_NULL = -1; @Retention(RetentionPolicy.SOURCE) @IntDef({StatusType.FOREGROUND, @@ -66,6 +70,7 @@ public class BatteryUtils { private static BatteryUtils sInstance; private PackageManager mPackageManager; + private AppOpsManager mAppOpsManager; @VisibleForTesting PowerUsageFeatureProvider mPowerUsageFeatureProvider; @@ -79,6 +84,7 @@ public class BatteryUtils { @VisibleForTesting BatteryUtils(Context context) { mPackageManager = context.getPackageManager(); + mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); mPowerUsageFeatureProvider = FeatureFactory.getFactory( context).getPowerUsageFeatureProvider(context); } @@ -263,6 +269,37 @@ public class BatteryUtils { return ArrayUtils.isEmpty(packageNames) ? null : packageNames[0]; } + /** + * Find the targetSdkVersion for package with name {@code packageName} + * + * @return the targetSdkVersion, or {@link #SDK_NULL} if {@code packageName} doesn't exist + */ + public int getTargetSdkVersion(final String packageName) { + try { + ApplicationInfo info = mPackageManager.getApplicationInfo(packageName, + PackageManager.GET_META_DATA); + + return info.targetSdkVersion; + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Cannot find package: " + packageName, e); + } + + return SDK_NULL; + } + + /** + * Check whether background restriction is enabled + */ + public boolean isBackgroundRestrictionEnabled(final int targetSdkVersion, final int uid, + final String packageName) { + if (targetSdkVersion >= Build.VERSION_CODES.O) { + return true; + } + final int mode = mAppOpsManager + .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, packageName); + return mode == AppOpsManager.MODE_IGNORED || mode == AppOpsManager.MODE_ERRORED; + } + /** * Sort the {@code usageList} based on {@link BatterySipper#totalPowerMah} */ @@ -337,7 +374,7 @@ public class BatteryUtils { } private boolean isDataCorrupted() { - return mPackageManager == null; + return mPackageManager == null || mAppOpsManager == null; } @VisibleForTesting diff --git a/src/com/android/settings/fuelgauge/anomaly/Anomaly.java b/src/com/android/settings/fuelgauge/anomaly/Anomaly.java index 2a4282a0789..dba964ffd48 100644 --- a/src/com/android/settings/fuelgauge/anomaly/Anomaly.java +++ b/src/com/android/settings/fuelgauge/anomaly/Anomaly.java @@ -46,16 +46,18 @@ public class Anomaly implements Parcelable { @Retention(RetentionPolicy.SOURCE) @IntDef({AnomalyActionType.FORCE_STOP, AnomalyActionType.BACKGROUND_CHECK, - AnomalyActionType.LOCATION_CHECK}) + AnomalyActionType.LOCATION_CHECK, + AnomalyActionType.STOP_AND_BACKGROUND_CHECK}) public @interface AnomalyActionType { int FORCE_STOP = 0; int BACKGROUND_CHECK = 1; int LOCATION_CHECK = 2; + int STOP_AND_BACKGROUND_CHECK = 3; } @AnomalyType - public static final int[] ANOMALY_TYPE_LIST = - {AnomalyType.WAKE_LOCK, + public static final int[] ANOMALY_TYPE_LIST = { + AnomalyType.WAKE_LOCK, AnomalyType.WAKEUP_ALARM, AnomalyType.BLUETOOTH_SCAN}; @@ -64,7 +66,14 @@ public class Anomaly implements Parcelable { */ public final int type; public final int uid; + public final int targetSdkVersion; public final long wakelockTimeMs; + /** + * {@code true} if background restriction is enabled + * + * @see android.app.AppOpsManager.OP_RUN_IN_BACKGROUND + */ + public final boolean backgroundRestrictionEnabled; /** * Display name of this anomaly, usually it is the app name */ @@ -77,6 +86,8 @@ public class Anomaly implements Parcelable { displayName = builder.mDisplayName; packageName = builder.mPackageName; wakelockTimeMs = builder.mWakeLockTimeMs; + targetSdkVersion = builder.mTargetSdkVersion; + backgroundRestrictionEnabled = builder.mBgRestrictionEnabled; } private Anomaly(Parcel in) { @@ -85,6 +96,8 @@ public class Anomaly implements Parcelable { displayName = in.readCharSequence(); packageName = in.readString(); wakelockTimeMs = in.readLong(); + targetSdkVersion = in.readInt(); + backgroundRestrictionEnabled = in.readBoolean(); } @Override @@ -99,6 +112,8 @@ public class Anomaly implements Parcelable { dest.writeCharSequence(displayName); dest.writeString(packageName); dest.writeLong(wakelockTimeMs); + dest.writeInt(targetSdkVersion); + dest.writeBoolean(backgroundRestrictionEnabled); } @Override @@ -115,12 +130,15 @@ public class Anomaly implements Parcelable { && uid == other.uid && wakelockTimeMs == other.wakelockTimeMs && TextUtils.equals(displayName, other.displayName) - && TextUtils.equals(packageName, other.packageName); + && TextUtils.equals(packageName, other.packageName) + && targetSdkVersion == other.targetSdkVersion + && backgroundRestrictionEnabled == other.backgroundRestrictionEnabled; } @Override public int hashCode() { - return Objects.hash(type, uid, displayName, packageName, wakelockTimeMs); + return Objects.hash(type, uid, displayName, packageName, wakelockTimeMs, targetSdkVersion, + backgroundRestrictionEnabled); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @@ -137,9 +155,11 @@ public class Anomaly implements Parcelable { @AnomalyType private int mType; private int mUid; + private int mTargetSdkVersion; private CharSequence mDisplayName; private String mPackageName; private long mWakeLockTimeMs; + private boolean mBgRestrictionEnabled; public Builder setType(@AnomalyType int type) { mType = type; @@ -166,6 +186,16 @@ public class Anomaly implements Parcelable { return this; } + public Builder setTargetSdkVersion(int targetSdkVersion) { + mTargetSdkVersion = targetSdkVersion; + return this; + } + + public Builder setBackgroundRestrictionEnabled(boolean bgRestrictionEnabled) { + mBgRestrictionEnabled = bgRestrictionEnabled; + return this; + } + public Anomaly build() { return new Anomaly(this); } diff --git a/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragment.java b/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragment.java index 452cc35f30a..69d03b94c1b 100644 --- a/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragment.java +++ b/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragment.java @@ -90,7 +90,7 @@ public class AnomalyDialogFragment extends InstrumentedDialogFragment implements return; } - final AnomalyAction anomalyAction = mAnomalyUtils.getAnomalyAction(mAnomaly.type); + final AnomalyAction anomalyAction = mAnomalyUtils.getAnomalyAction(mAnomaly); final int metricsKey = getArguments().getInt(ARG_METRICS_KEY); anomalyAction.handlePositiveAction(mAnomaly, metricsKey); @@ -103,16 +103,18 @@ public class AnomalyDialogFragment extends InstrumentedDialogFragment implements mAnomaly = bundle.getParcelable(ARG_ANOMALY); final Context context = getContext(); - final AnomalyAction anomalyAction = mAnomalyUtils.getAnomalyAction(mAnomaly.type); + final AnomalyAction anomalyAction = mAnomalyUtils.getAnomalyAction(mAnomaly); switch (anomalyAction.getActionType()) { case Anomaly.AnomalyActionType.FORCE_STOP: return new AlertDialog.Builder(context) .setTitle(R.string.dialog_stop_title) - .setMessage(getString(R.string.dialog_stop_message, mAnomaly.displayName)) + .setMessage(getString(mAnomaly.type == Anomaly.AnomalyType.WAKE_LOCK + ? R.string.dialog_stop_message + : R.string.dialog_stop_message_wakeup_alarm, mAnomaly.displayName)) .setPositiveButton(R.string.dialog_stop_ok, this) .setNegativeButton(R.string.dlg_cancel, null) .create(); - case Anomaly.AnomalyActionType.BACKGROUND_CHECK: + case Anomaly.AnomalyActionType.STOP_AND_BACKGROUND_CHECK: return new AlertDialog.Builder(context) .setTitle(R.string.dialog_background_check_title) .setMessage(getString(R.string.dialog_background_check_message, diff --git a/src/com/android/settings/fuelgauge/anomaly/AnomalyUtils.java b/src/com/android/settings/fuelgauge/anomaly/AnomalyUtils.java index 9d0e1d0c871..8ac9e6f2983 100644 --- a/src/com/android/settings/fuelgauge/anomaly/AnomalyUtils.java +++ b/src/com/android/settings/fuelgauge/anomaly/AnomalyUtils.java @@ -17,12 +17,13 @@ package com.android.settings.fuelgauge.anomaly; import android.content.Context; +import android.os.Build; import android.support.annotation.VisibleForTesting; import com.android.settings.fuelgauge.anomaly.action.AnomalyAction; -import com.android.settings.fuelgauge.anomaly.action.BackgroundCheckAction; import com.android.settings.fuelgauge.anomaly.action.ForceStopAction; import com.android.settings.fuelgauge.anomaly.action.LocationCheckAction; +import com.android.settings.fuelgauge.anomaly.action.StopAndBackgroundCheckAction; import com.android.settings.fuelgauge.anomaly.checker.AnomalyDetector; import com.android.settings.fuelgauge.anomaly.checker.BluetoothScanAnomalyDetector; import com.android.settings.fuelgauge.anomaly.checker.WakeLockAnomalyDetector; @@ -49,16 +50,22 @@ public class AnomalyUtils { /** * Return the corresponding {@link AnomalyAction} according to - * {@link com.android.settings.fuelgauge.anomaly.Anomaly.AnomalyType} + * {@link com.android.settings.fuelgauge.anomaly.Anomaly} * * @return corresponding {@link AnomalyAction}, or null if cannot find it. */ - public AnomalyAction getAnomalyAction(@Anomaly.AnomalyType int anomalyType) { - switch (anomalyType) { + public AnomalyAction getAnomalyAction(Anomaly anomaly) { + switch (anomaly.type) { case Anomaly.AnomalyType.WAKE_LOCK: return new ForceStopAction(mContext); case Anomaly.AnomalyType.WAKEUP_ALARM: - return new BackgroundCheckAction(mContext); + if (anomaly.targetSdkVersion >= Build.VERSION_CODES.O + || (anomaly.targetSdkVersion < Build.VERSION_CODES.O + && anomaly.backgroundRestrictionEnabled)) { + return new ForceStopAction(mContext); + } else { + return new StopAndBackgroundCheckAction(mContext); + } case Anomaly.AnomalyType.BLUETOOTH_SCAN: return new LocationCheckAction(mContext); default: diff --git a/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckAction.java b/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckAction.java index 799bddcd85a..5526cc903b3 100644 --- a/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckAction.java +++ b/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckAction.java @@ -18,8 +18,11 @@ package com.android.settings.fuelgauge.anomaly.action; import android.app.AppOpsManager; import android.content.Context; +import android.os.Build; +import android.support.annotation.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.fuelgauge.anomaly.Anomaly; /** @@ -28,6 +31,8 @@ import com.android.settings.fuelgauge.anomaly.Anomaly; public class BackgroundCheckAction extends AnomalyAction { private AppOpsManager mAppOpsManager; + @VisibleForTesting + BatteryUtils mBatteryUtils; public BackgroundCheckAction(Context context) { super(context); @@ -38,17 +43,17 @@ public class BackgroundCheckAction extends AnomalyAction { @Override public void handlePositiveAction(Anomaly anomaly, int contextMetricsKey) { super.handlePositiveAction(anomaly, contextMetricsKey); - - mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, anomaly.uid, anomaly.packageName, - AppOpsManager.MODE_IGNORED); + if (anomaly.targetSdkVersion < Build.VERSION_CODES.O) { + mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, anomaly.uid, + anomaly.packageName, + AppOpsManager.MODE_IGNORED); + } } @Override public boolean isActionActive(Anomaly anomaly) { - final int mode = mAppOpsManager - .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, anomaly.uid, - anomaly.packageName); - return mode != AppOpsManager.MODE_IGNORED && mode != AppOpsManager.MODE_ERRORED; + return !mBatteryUtils.isBackgroundRestrictionEnabled(anomaly.targetSdkVersion, anomaly.uid, + anomaly.packageName); } @Override diff --git a/src/com/android/settings/fuelgauge/anomaly/action/StopAndBackgroundCheckAction.java b/src/com/android/settings/fuelgauge/anomaly/action/StopAndBackgroundCheckAction.java new file mode 100644 index 00000000000..dba221a35f2 --- /dev/null +++ b/src/com/android/settings/fuelgauge/anomaly/action/StopAndBackgroundCheckAction.java @@ -0,0 +1,63 @@ +/* + * 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.action; + +import android.content.Context; +import android.support.annotation.VisibleForTesting; + +import com.android.settings.fuelgauge.anomaly.Anomaly; + +/** + * Force stop and background check action for anomaly app, this action will + * 1. Force stop the app + * 2. Turn on background check + */ +public class StopAndBackgroundCheckAction extends AnomalyAction { + @VisibleForTesting + ForceStopAction mForceStopAction; + @VisibleForTesting + BackgroundCheckAction mBackgroundCheckAction; + + public StopAndBackgroundCheckAction(Context context) { + this(context, new ForceStopAction(context), new BackgroundCheckAction(context)); + } + + @VisibleForTesting + StopAndBackgroundCheckAction(Context context, ForceStopAction forceStopAction, + BackgroundCheckAction backgroundCheckAction) { + super(context); + mForceStopAction = forceStopAction; + mBackgroundCheckAction = backgroundCheckAction; + } + + @Override + public void handlePositiveAction(Anomaly anomaly, int metricsKey) { + mForceStopAction.handlePositiveAction(anomaly, metricsKey); + mBackgroundCheckAction.handlePositiveAction(anomaly, metricsKey); + } + + @Override + public boolean isActionActive(Anomaly anomaly) { + return mForceStopAction.isActionActive(anomaly) + && mBackgroundCheckAction.isActionActive(anomaly); + } + + @Override + public int getActionType() { + return Anomaly.AnomalyActionType.STOP_AND_BACKGROUND_CHECK; + } +} diff --git a/src/com/android/settings/fuelgauge/anomaly/checker/BluetoothScanAnomalyDetector.java b/src/com/android/settings/fuelgauge/anomaly/checker/BluetoothScanAnomalyDetector.java index 4281743bfd5..f66c61c165c 100644 --- a/src/com/android/settings/fuelgauge/anomaly/checker/BluetoothScanAnomalyDetector.java +++ b/src/com/android/settings/fuelgauge/anomaly/checker/BluetoothScanAnomalyDetector.java @@ -42,24 +42,21 @@ public class BluetoothScanAnomalyDetector implements AnomalyDetector { private static final String TAG = "BluetoothScanAnomalyDetector"; @VisibleForTesting BatteryUtils mBatteryUtils; - @VisibleForTesting - AnomalyAction mAnomalyAction; private long mBluetoothScanningThreshold; private Context mContext; + private AnomalyUtils mAnomalyUtils; public BluetoothScanAnomalyDetector(Context context) { - this(context, new AnomalyDetectionPolicy(context), - AnomalyUtils.getInstance(context).getAnomalyAction( - Anomaly.AnomalyType.BLUETOOTH_SCAN)); + this(context, new AnomalyDetectionPolicy(context), AnomalyUtils.getInstance(context)); } @VisibleForTesting BluetoothScanAnomalyDetector(Context context, AnomalyDetectionPolicy policy, - AnomalyAction anomalyAction) { + AnomalyUtils anomalyUtils) { mContext = context; mBatteryUtils = BatteryUtils.getInstance(context); - mAnomalyAction = anomalyAction; mBluetoothScanningThreshold = policy.bluetoothScanThreshold; + mAnomalyUtils = anomalyUtils; } @Override @@ -98,7 +95,7 @@ public class BluetoothScanAnomalyDetector implements AnomalyDetector { .setPackageName(packageName) .build(); - if (mAnomalyAction.isActionActive(anomaly)) { + if (mAnomalyUtils.getAnomalyAction(anomaly).isActionActive(anomaly)) { anomalies.add(anomaly); } } diff --git a/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetector.java b/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetector.java index 5fa0e4164c4..959ceb5bbe1 100644 --- a/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetector.java +++ b/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetector.java @@ -29,7 +29,6 @@ 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; @@ -39,27 +38,25 @@ import java.util.List; */ public class WakeLockAnomalyDetector implements AnomalyDetector { private static final String TAG = "WakeLockAnomalyChecker"; - private PackageManager mPackageManager; - private Context mContext; @VisibleForTesting BatteryUtils mBatteryUtils; @VisibleForTesting long mWakeLockThresholdMs; - @VisibleForTesting - AnomalyAction mAnomalyAction; + private PackageManager mPackageManager; + private Context mContext; + private AnomalyUtils mAnomalyUtils; public WakeLockAnomalyDetector(Context context) { - this(context, new AnomalyDetectionPolicy(context)); + this(context, new AnomalyDetectionPolicy(context), AnomalyUtils.getInstance(context)); } @VisibleForTesting - WakeLockAnomalyDetector(Context context, AnomalyDetectionPolicy policy) { + WakeLockAnomalyDetector(Context context, AnomalyDetectionPolicy policy, + AnomalyUtils anomalyUtils) { mContext = context; mPackageManager = context.getPackageManager(); mBatteryUtils = BatteryUtils.getInstance(context); - mAnomalyAction = AnomalyUtils.getInstance(context).getAnomalyAction( - Anomaly.AnomalyType.WAKE_LOCK); - + mAnomalyUtils = anomalyUtils; mWakeLockThresholdMs = policy.wakeLockThreshold; } @@ -94,15 +91,20 @@ public class WakeLockAnomalyDetector implements AnomalyDetector { final String packageName = mBatteryUtils.getPackageName(uid.getUid()); final CharSequence displayName = Utils.getApplicationLabel(mContext, packageName); + final int targetSdkVersion = mBatteryUtils.getTargetSdkVersion(packageName); Anomaly anomaly = new Anomaly.Builder() .setUid(uid.getUid()) .setType(Anomaly.AnomalyType.WAKE_LOCK) .setDisplayName(displayName) .setPackageName(packageName) + .setTargetSdkVersion(targetSdkVersion) + .setBackgroundRestrictionEnabled( + mBatteryUtils.isBackgroundRestrictionEnabled(targetSdkVersion, + uid.getUid(), packageName)) .build(); - if (mAnomalyAction.isActionActive(anomaly)) { + if (mAnomalyUtils.getAnomalyAction(anomaly).isActionActive(anomaly)) { anomalies.add(anomaly); } } diff --git a/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java b/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java index 55686e01483..f6ff7aa8f51 100644 --- a/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java +++ b/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java @@ -41,21 +41,20 @@ public class WakeupAlarmAnomalyDetector implements AnomalyDetector { private static final String TAG = "WakeupAlarmAnomalyDetector"; @VisibleForTesting BatteryUtils mBatteryUtils; - @VisibleForTesting - AnomalyAction mAnomalyAction; private long mWakeupAlarmThreshold; private Context mContext; + private AnomalyUtils mAnomalyUtils; public WakeupAlarmAnomalyDetector(Context context) { - this(context, new AnomalyDetectionPolicy(context)); + this(context, new AnomalyDetectionPolicy(context), AnomalyUtils.getInstance(context)); } @VisibleForTesting - WakeupAlarmAnomalyDetector(Context context, AnomalyDetectionPolicy policy) { + WakeupAlarmAnomalyDetector(Context context, AnomalyDetectionPolicy policy, + AnomalyUtils anomalyUtils) { mContext = context; mBatteryUtils = BatteryUtils.getInstance(context); - mAnomalyAction = AnomalyUtils.getInstance(context).getAnomalyAction( - Anomaly.AnomalyType.WAKEUP_ALARM); + mAnomalyUtils = anomalyUtils; mWakeupAlarmThreshold = policy.wakeupAlarmThreshold; } @@ -98,7 +97,7 @@ public class WakeupAlarmAnomalyDetector implements AnomalyDetector { .setPackageName(packageName) .build(); - if (mAnomalyAction.isActionActive(anomaly)) { + if (mAnomalyUtils.getAnomalyAction(anomaly).isActionActive(anomaly)) { anomalies.add(anomaly); } } diff --git a/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java b/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java index a57036161ba..e20a43556ab 100644 --- a/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java +++ b/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java @@ -18,6 +18,7 @@ package com.android.settings.applications; import android.app.AlertDialog; +import android.app.AppOpsManager; import android.app.Fragment; import android.app.LoaderManager; import android.app.admin.DevicePolicyManager; @@ -113,6 +114,8 @@ public final class InstalledAppDetailsTest { private BatteryUtils mBatteryUtils; @Mock private LoaderManager mLoaderManager; + @Mock + private AppOpsManager mAppOpsManager; private FakeFeatureFactory mFeatureFactory; private InstalledAppDetails mAppDetail; @@ -138,6 +141,7 @@ public final class InstalledAppDetailsTest { doReturn(mActivity).when(mAppDetail).getActivity(); doReturn(mShadowContext).when(mAppDetail).getContext(); doReturn(mPackageManager).when(mActivity).getPackageManager(); + doReturn(mAppOpsManager).when(mActivity).getSystemService(Context.APP_OPS_SERVICE); // Default to not considering any apps to be instant (individual tests can override this). ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java index 0cabb05ff3d..7f2aeb68f4e 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java @@ -30,6 +30,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.app.Activity; +import android.app.AppOpsManager; import android.app.Fragment; import android.app.LoaderManager; import android.content.Context; @@ -116,6 +117,8 @@ public class AdvancedPowerUsageDetailTest { @Mock private PackageManager mPackageManager; @Mock + private AppOpsManager mAppOpsManager; + @Mock private LoaderManager mLoaderManager; @Mock private AnomalySummaryPreferenceController mAnomalySummaryPreferenceController; @@ -184,6 +187,7 @@ public class AdvancedPowerUsageDetailTest { mTestActivity = spy(new SettingsActivity()); doReturn(mPackageManager).when(mTestActivity).getPackageManager(); + doReturn(mAppOpsManager).when(mTestActivity).getSystemService(Context.APP_OPS_SERVICE); final ArgumentCaptor captor = ArgumentCaptor.forClass(Bundle.class); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java index 034028aa9f9..aa19055f1b7 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java @@ -15,9 +15,13 @@ */ package com.android.settings.fuelgauge; +import android.app.AppOpsManager; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.os.BatteryStats; import android.os.Bundle; +import android.os.Build; import android.os.Process; import android.os.SystemClock; import android.os.UserManager; @@ -58,6 +62,7 @@ import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -96,6 +101,8 @@ public class BatteryUtilsTest { private static final int DISCHARGE_AMOUNT = 80; private static final double PERCENT_SYSTEM_USAGE = 60; private static final double PRECISION = 0.001; + private static final int SDK_VERSION = Build.VERSION_CODES.L; + private static final String PACKAGE_NAME = "com.android.app"; @Mock private BatteryStats.Uid mUid; @@ -123,6 +130,12 @@ public class BatteryUtilsTest { private Bundle mBundle; @Mock private UserManager mUserManager; + @Mock + private PackageManager mPackageManager; + @Mock + private AppOpsManager mAppOpsManager; + @Mock + private ApplicationInfo mApplicationInfo; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock(answer = Answers.RETURNS_DEEP_STUBS) @@ -177,10 +190,11 @@ public class BatteryUtilsTest { mIdleBatterySipper.drainType = BatterySipper.DrainType.IDLE; mIdleBatterySipper.totalPowerMah = BATTERY_IDLE_USAGE; - mBatteryUtils = BatteryUtils.getInstance(RuntimeEnvironment.application); + final Context shadowContext = spy(RuntimeEnvironment.application); + doReturn(mPackageManager).when(shadowContext).getPackageManager(); + doReturn(mAppOpsManager).when(shadowContext).getSystemService(Context.APP_OPS_SERVICE); + mBatteryUtils = spy(new BatteryUtils(shadowContext)); mBatteryUtils.mPowerUsageFeatureProvider = mProvider; - - mBatteryUtils = spy(new BatteryUtils(RuntimeEnvironment.application)); } @Test @@ -392,6 +406,44 @@ public class BatteryUtilsTest { TIME_SINCE_LAST_FULL_CHARGE_US); } + @Test + public void testGetTargetSdkVersion_packageExist_returnSdk() throws + PackageManager.NameNotFoundException { + doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(PACKAGE_NAME, + PackageManager.GET_META_DATA); + mApplicationInfo.targetSdkVersion = SDK_VERSION; + + assertThat(mBatteryUtils.getTargetSdkVersion(PACKAGE_NAME)).isEqualTo(SDK_VERSION); + } + + @Test + public void testGetTargetSdkVersion_packageNotExist_returnSdkNull() throws + PackageManager.NameNotFoundException { + doThrow(new PackageManager.NameNotFoundException()).when( + mPackageManager).getApplicationInfo(PACKAGE_NAME, PackageManager.GET_META_DATA); + + assertThat(mBatteryUtils.getTargetSdkVersion(PACKAGE_NAME)).isEqualTo( + BatteryUtils.SDK_NULL); + } + + @Test + public void testBackgroundRestrictionOn_restrictionOn_returnTrue() { + doReturn(AppOpsManager.MODE_IGNORED).when(mAppOpsManager).checkOpNoThrow( + AppOpsManager.OP_RUN_IN_BACKGROUND, UID, PACKAGE_NAME); + + assertThat(mBatteryUtils.isBackgroundRestrictionEnabled(SDK_VERSION, UID, + PACKAGE_NAME)).isTrue(); + } + + @Test + public void testBackgroundRestrictionOn_restrictionOff_returnFalse() { + doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager).checkOpNoThrow( + AppOpsManager.OP_RUN_IN_BACKGROUND, UID, PACKAGE_NAME); + + assertThat(mBatteryUtils.isBackgroundRestrictionEnabled(SDK_VERSION, UID, + PACKAGE_NAME)).isFalse(); + } + private BatterySipper createTestSmearBatterySipper(long topTime, double totalPowerMah, int uidCode, boolean isUidNull) { final BatterySipper sipper = mock(BatterySipper.class); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragmentTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragmentTest.java index e8e4bab8b16..1111804dd8d 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragmentTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragmentTest.java @@ -18,6 +18,7 @@ package com.android.settings.fuelgauge.anomaly; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -27,6 +28,7 @@ import static org.robolectric.Shadows.shadowOf; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; +import android.os.Build; import com.android.settings.R; import com.android.settings.fuelgauge.anomaly.action.AnomalyAction; @@ -57,6 +59,7 @@ public class AnomalyDialogFragmentTest { private AnomalyAction mAnomalyAction; private Anomaly mWakeLockAnomaly; private Anomaly mWakeupAlarmAnomaly; + private Anomaly mWakeupAlarmAnomaly2; private Anomaly mBluetoothAnomaly; private AnomalyDialogFragment mAnomalyDialogFragment; private Context mContext; @@ -78,6 +81,13 @@ public class AnomalyDialogFragmentTest { .setPackageName(PACKAGE_NAME) .setDisplayName(DISPLAY_NAME) .build(); + mWakeupAlarmAnomaly2 = new Anomaly.Builder() + .setType(Anomaly.AnomalyType.WAKEUP_ALARM) + .setUid(UID) + .setPackageName(PACKAGE_NAME) + .setDisplayName(DISPLAY_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .build(); mBluetoothAnomaly = new Anomaly.Builder() .setType(Anomaly.AnomalyType.BLUETOOTH_SCAN) .setUid(UID) @@ -116,7 +126,7 @@ public class AnomalyDialogFragmentTest { } @Test - public void testOnCreateDialog_wakeupAlarmAnomaly_fireBackgroundCheckDialog() { + public void testOnCreateDialog_wakeupAlarmAnomalyPriorO_fireStopAndBackgroundCheckDialog() { mAnomalyDialogFragment = AnomalyDialogFragment.newInstance(mWakeupAlarmAnomaly, 0 /* metricskey */); @@ -136,12 +146,33 @@ public class AnomalyDialogFragmentTest { mContext.getString(R.string.dlg_cancel)); } + @Test + public void testOnCreateDialog_wakeupAlarmAnomalyTargetingO_fireForceStopDialog() { + mAnomalyDialogFragment = AnomalyDialogFragment.newInstance(mWakeupAlarmAnomaly2, + 0 /* metricskey */); + + FragmentTestUtil.startFragment(mAnomalyDialogFragment); + + final AlertDialog dialog = (AlertDialog) ShadowDialog.getLatestDialog(); + ShadowAlertDialog shadowDialog = shadowOf(dialog); + + assertThat(shadowDialog.getMessage()).isEqualTo( + mContext.getString(R.string.dialog_stop_message_wakeup_alarm, + mWakeLockAnomaly.displayName)); + assertThat(shadowDialog.getTitle()).isEqualTo( + mContext.getString(R.string.dialog_stop_title)); + assertThat(dialog.getButton(DialogInterface.BUTTON_POSITIVE).getText()).isEqualTo( + mContext.getString(R.string.dialog_stop_ok)); + assertThat(dialog.getButton(DialogInterface.BUTTON_NEGATIVE).getText()).isEqualTo( + mContext.getString(R.string.dlg_cancel)); + } + @Test public void testOnCreateDialog_bluetoothAnomaly_fireLocationCheckDialog() { mAnomalyDialogFragment = spy(AnomalyDialogFragment.newInstance(mBluetoothAnomaly, 0 /* metricskey */)); mAnomalyDialogFragment.mAnomalyUtils = mAnomalyUtils; - doReturn(mAnomalyAction).when(mAnomalyUtils).getAnomalyAction(anyInt()); + doReturn(mAnomalyAction).when(mAnomalyUtils).getAnomalyAction(any()); doNothing().when(mAnomalyDialogFragment).initAnomalyUtils(); doReturn(Anomaly.AnomalyActionType.LOCATION_CHECK).when(mAnomalyAction).getActionType(); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyTest.java index 55b8308a964..759f0fd91c5 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyTest.java @@ -18,6 +18,8 @@ package com.android.settings.fuelgauge.anomaly; import static com.google.common.truth.Truth.assertThat; +import android.os.Build; + import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; @@ -30,6 +32,7 @@ import org.robolectric.annotation.Config; public class AnomalyTest { private static int TYPE = Anomaly.AnomalyType.WAKE_LOCK; private static int UID = 111; + private static int SDK_VERSION = Build.VERSION_CODES.L; private static long WAKE_LOCK_TIME_MS = 1500; private static String PACKAGE_NAME = "com.android.settings"; private static String DISPLAY_NAME = "settings"; @@ -42,6 +45,8 @@ public class AnomalyTest { .setWakeLockTimeMs(WAKE_LOCK_TIME_MS) .setPackageName(PACKAGE_NAME) .setDisplayName(DISPLAY_NAME) + .setTargetSdkVersion(SDK_VERSION) + .setBackgroundRestrictionEnabled(true) .build(); assertThat(anomaly.type).isEqualTo(TYPE); @@ -49,5 +54,7 @@ public class AnomalyTest { assertThat(anomaly.wakelockTimeMs).isEqualTo(WAKE_LOCK_TIME_MS); assertThat(anomaly.packageName).isEqualTo(PACKAGE_NAME); assertThat(anomaly.displayName).isEqualTo(DISPLAY_NAME); + assertThat(anomaly.targetSdkVersion).isEqualTo(SDK_VERSION); + assertThat(anomaly.backgroundRestrictionEnabled).isTrue(); } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyUtilsTest.java index 15bca7e1712..8cd5a063b72 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyUtilsTest.java @@ -18,9 +18,11 @@ package com.android.settings.fuelgauge.anomaly; import static com.google.common.truth.Truth.assertThat; +import android.os.Build; + +import com.android.settings.fuelgauge.anomaly.action.StopAndBackgroundCheckAction; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; -import com.android.settings.fuelgauge.anomaly.action.BackgroundCheckAction; import com.android.settings.fuelgauge.anomaly.action.ForceStopAction; import com.android.settings.fuelgauge.anomaly.checker.WakeLockAnomalyDetector; import com.android.settings.testutils.shadow.ShadowKeyValueListParserWrapperImpl; @@ -45,22 +47,51 @@ public class AnomalyUtilsTest { @Test public void testGetAnomalyAction_typeWakeLock_returnForceStop() { - assertThat(mAnomalyUtils.getAnomalyAction(Anomaly.AnomalyType.WAKE_LOCK)).isInstanceOf( + Anomaly anomaly = new Anomaly.Builder() + .setType(Anomaly.AnomalyType.WAKE_LOCK) + .build(); + assertThat(mAnomalyUtils.getAnomalyAction(anomaly)).isInstanceOf( ForceStopAction.class); } - @Test - public void testGetAnomalyAction_typeWakeUpAlarm_returnBackgroundCheck() { - assertThat(mAnomalyUtils.getAnomalyAction(Anomaly.AnomalyType.WAKEUP_ALARM)).isInstanceOf( - BackgroundCheckAction.class); - } - @Test public void testGetAnomalyDetector_typeWakeLock_returnWakeLockDetector() { assertThat(mAnomalyUtils.getAnomalyDetector(Anomaly.AnomalyType.WAKE_LOCK)).isInstanceOf( WakeLockAnomalyDetector.class); } + @Test + public void testGetAnomalyAction_typeWakeUpAlarmTargetO_returnForceStop() { + Anomaly anomaly = new Anomaly.Builder() + .setType(Anomaly.AnomalyType.WAKEUP_ALARM) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .build(); + assertThat(mAnomalyUtils.getAnomalyAction(anomaly)).isInstanceOf( + ForceStopAction.class); + } + + @Test + public void testGetAnomalyAction_typeWakeUpAlarmTargetPriorOAndBgOff_returnStopAndBackground() { + Anomaly anomaly = new Anomaly.Builder() + .setType(Anomaly.AnomalyType.WAKEUP_ALARM) + .setTargetSdkVersion(Build.VERSION_CODES.L) + .setBackgroundRestrictionEnabled(false) + .build(); + assertThat(mAnomalyUtils.getAnomalyAction(anomaly)).isInstanceOf( + StopAndBackgroundCheckAction.class); + } + + @Test + public void testGetAnomalyAction_typeWakeUpAlarmTargetPriorOAndBgOn_returnForceStop() { + Anomaly anomaly = new Anomaly.Builder() + .setType(Anomaly.AnomalyType.WAKEUP_ALARM) + .setTargetSdkVersion(Build.VERSION_CODES.L) + .setBackgroundRestrictionEnabled(true) + .build(); + assertThat(mAnomalyUtils.getAnomalyAction(anomaly)).isInstanceOf( + ForceStopAction.class); + } + @Test public void testGetAnomalyDetector_typeWakeUpAlarm_returnWakeUpAlarmDetector() { assertThat(mAnomalyUtils.getAnomalyDetector(Anomaly.AnomalyType.WAKEUP_ALARM)).isInstanceOf( diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckActionTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckActionTest.java index ae783ab4e49..e2b8656c5cf 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckActionTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckActionTest.java @@ -23,7 +23,9 @@ import static org.mockito.Mockito.verify; import android.app.AppOpsManager; import android.content.Context; +import android.os.Build; +import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.fuelgauge.anomaly.Anomaly; @@ -42,11 +44,14 @@ import org.robolectric.annotation.Config; public class BackgroundCheckActionTest { private static final String PACKAGE_NAME = "com.android.app"; private static final int UID = 111; + private static final int SDK_VERSION = Build.VERSION_CODES.L; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock - private AppOpsManager mAppOpsManagerr; + private AppOpsManager mAppOpsManager; + @Mock + private BatteryUtils mBatteryUtils; private Anomaly mAnomaly; private BackgroundCheckAction mBackgroundCheckAction; @@ -55,35 +60,37 @@ public class BackgroundCheckActionTest { MockitoAnnotations.initMocks(this); FakeFeatureFactory.setupForTest(mContext); - doReturn(mAppOpsManagerr).when(mContext).getSystemService(Context.APP_OPS_SERVICE); + doReturn(mAppOpsManager).when(mContext).getSystemService(Context.APP_OPS_SERVICE); mAnomaly = new Anomaly.Builder() .setUid(UID) .setPackageName(PACKAGE_NAME) + .setTargetSdkVersion(SDK_VERSION) .build(); mBackgroundCheckAction = new BackgroundCheckAction(mContext); + mBackgroundCheckAction.mBatteryUtils = mBatteryUtils; } @Test public void testHandlePositiveAction_forceStopPackage() { mBackgroundCheckAction.handlePositiveAction(mAnomaly, 0 /* metricskey */); - verify(mAppOpsManagerr).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, UID, PACKAGE_NAME, + verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, UID, PACKAGE_NAME, AppOpsManager.MODE_IGNORED); } @Test public void testIsActionActive_modeAllowed_returnTrue() { - doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManagerr).checkOpNoThrow( - AppOpsManager.OP_RUN_IN_BACKGROUND, UID, PACKAGE_NAME); + doReturn(false).when(mBatteryUtils).isBackgroundRestrictionEnabled(SDK_VERSION, UID, + PACKAGE_NAME); assertThat(mBackgroundCheckAction.isActionActive(mAnomaly)).isTrue(); } @Test public void testIsActionActive_modeIgnored_returnFalse() { - doReturn(AppOpsManager.MODE_IGNORED).when(mAppOpsManagerr).checkOpNoThrow( - AppOpsManager.OP_RUN_IN_BACKGROUND, UID, PACKAGE_NAME); + doReturn(true).when(mBatteryUtils).isBackgroundRestrictionEnabled(SDK_VERSION, UID, + PACKAGE_NAME); assertThat(mBackgroundCheckAction.isActionActive(mAnomaly)).isFalse(); } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/StopAndBackgroundActionTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/StopAndBackgroundActionTest.java new file mode 100644 index 00000000000..c06bddd92c4 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/StopAndBackgroundActionTest.java @@ -0,0 +1,93 @@ +/* + * 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.action; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import android.content.Context; + +import com.android.settings.TestConfig; +import com.android.settings.fuelgauge.anomaly.Anomaly; +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class StopAndBackgroundActionTest { + private static final String PACKAGE_NAME = "com.android.app"; + private static final int UID = 111; + private static final int METRICS_KEY = 3; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Context mContext; + @Mock + private BackgroundCheckAction mBackgroundCheckAction; + @Mock + private ForceStopAction mForceStopAction; + private StopAndBackgroundCheckAction mStopAndBackgroundCheckAction; + private Anomaly mAnomaly; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mAnomaly = new Anomaly.Builder() + .setUid(UID) + .setPackageName(PACKAGE_NAME) + .build(); + + FakeFeatureFactory.setupForTest(mContext); + mStopAndBackgroundCheckAction = new StopAndBackgroundCheckAction(mContext, mForceStopAction, + mBackgroundCheckAction); + } + + @Test + public void testHandlePositiveAction_stopAndBackgroundCheck() { + mStopAndBackgroundCheckAction.handlePositiveAction(mAnomaly, METRICS_KEY); + + verify(mBackgroundCheckAction).handlePositiveAction(mAnomaly, METRICS_KEY); + verify(mForceStopAction).handlePositiveAction(mAnomaly, METRICS_KEY); + } + + @Test + public void testIsActionActive_restrictionEnabled_returnFalse() { + doReturn(true).when(mForceStopAction).isActionActive(mAnomaly); + + assertThat(mStopAndBackgroundCheckAction.isActionActive(mAnomaly)).isFalse(); + } + + @Test + public void testIsActionActive_appNotRunning_returnFalse() { + doReturn(true).when(mBackgroundCheckAction).isActionActive(mAnomaly); + + assertThat(mStopAndBackgroundCheckAction.isActionActive(mAnomaly)).isFalse(); + } + + @Test + public void testIsActionActive_appStoppedAndRestrictionOn_returnFalse() { + assertThat(mStopAndBackgroundCheckAction.isActionActive(mAnomaly)).isFalse(); + } +} diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/BluetoothScanAnomalyDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/BluetoothScanAnomalyDetectorTest.java index a687e2f49e1..d21687c19cd 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/BluetoothScanAnomalyDetectorTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/BluetoothScanAnomalyDetectorTest.java @@ -36,6 +36,7 @@ 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.AnomalyUtils; import com.android.settings.fuelgauge.anomaly.action.AnomalyAction; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -80,6 +81,8 @@ public class BluetoothScanAnomalyDetectorTest { private AnomalyDetectionPolicy mPolicy; @Mock private AnomalyAction mAnomalyAction; + @Mock + private AnomalyUtils mAnomalyUtils; private BluetoothScanAnomalyDetector mBluetoothScanAnomalyDetector; private Context mContext; @@ -92,6 +95,7 @@ public class BluetoothScanAnomalyDetectorTest { mContext = spy(RuntimeEnvironment.application); ReflectionHelpers.setField(mPolicy, "bluetoothScanThreshold", 30 * DateUtils.MINUTE_IN_MILLIS); + doReturn(mAnomalyAction).when(mAnomalyUtils).getAnomalyAction(any()); mAnomalySipper.uidObj = mAnomalyUid; doReturn(ANOMALY_UID).when(mAnomalyUid).getUid(); @@ -106,10 +110,9 @@ public class BluetoothScanAnomalyDetectorTest { mUsageList.add(mTargetSipper); doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList(); - mBluetoothScanAnomalyDetector = spy( - new BluetoothScanAnomalyDetector(mContext, mPolicy, mAnomalyAction)); + mBluetoothScanAnomalyDetector = spy(new BluetoothScanAnomalyDetector(mContext, mPolicy, + mAnomalyUtils)); mBluetoothScanAnomalyDetector.mBatteryUtils = mBatteryUtils; - mBluetoothScanAnomalyDetector.mAnomalyAction = mAnomalyAction; doReturn(false).when(mBatteryUtils).shouldHideSipper(any()); doReturn(true).when(mAnomalyAction).isActionActive(any()); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetectorTest.java index 19ab7d61cba..f53e8a04447 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetectorTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetectorTest.java @@ -34,6 +34,7 @@ import android.text.format.DateUtils; import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; +import com.android.settings.fuelgauge.anomaly.AnomalyUtils; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.fuelgauge.BatteryUtils; @@ -92,6 +93,8 @@ public class WakeLockAnomalyDetectorTest { private AnomalyDetectionPolicy mPolicy; @Mock private AnomalyAction mAnomalyAction; + @Mock + private AnomalyUtils mAnomalyUtils; private WakeLockAnomalyDetector mWakelockAnomalyDetector; private Context mContext; @@ -109,10 +112,11 @@ public class WakeLockAnomalyDetectorTest { doReturn(mApplicationInfo).when(mPackageManager) .getApplicationInfo(nullable(String.class), anyInt()); doReturn(true).when(mAnomalyAction).isActionActive(any()); + doReturn(mAnomalyAction).when(mAnomalyUtils).getAnomalyAction(any()); - mWakelockAnomalyDetector = spy(new WakeLockAnomalyDetector(mContext, mPolicy)); + mWakelockAnomalyDetector = spy( + new WakeLockAnomalyDetector(mContext, mPolicy, mAnomalyUtils)); mWakelockAnomalyDetector.mBatteryUtils = mBatteryUtils; - mWakelockAnomalyDetector.mAnomalyAction = mAnomalyAction; mAnomalySipper.uidObj = mAnomalyUid; doReturn(ANOMALY_WAKELOCK_TIME_MS).when(mWakelockAnomalyDetector) diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java index e7c26641e6c..a16db6e924d 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java @@ -33,6 +33,7 @@ import android.util.ArrayMap; import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; +import com.android.settings.fuelgauge.anomaly.AnomalyUtils; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.fuelgauge.BatteryUtils; @@ -89,6 +90,8 @@ public class WakeupAlarmAnomalyDetectorTest { private AnomalyDetectionPolicy mPolicy; @Mock private AnomalyAction mAnomalyAction; + @Mock + private AnomalyUtils mAnomalyUtils; private WakeupAlarmAnomalyDetector mWakeupAlarmAnomalyDetector; private Context mContext; @@ -105,6 +108,7 @@ public class WakeupAlarmAnomalyDetectorTest { doReturn(RUNNING_TIME_MS).when(mBatteryUtils).calculateRunningTimeBasedOnStatsType(any(), anyInt()); doReturn(true).when(mAnomalyAction).isActionActive(any()); + doReturn(mAnomalyAction).when(mAnomalyUtils).getAnomalyAction(any()); mAnomalySipper.uidObj = mAnomalyUid; doReturn(ANOMALY_UID).when(mAnomalyUid).getUid(); @@ -119,9 +123,9 @@ public class WakeupAlarmAnomalyDetectorTest { mUsageList.add(mTargetSipper); doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList(); - mWakeupAlarmAnomalyDetector = spy(new WakeupAlarmAnomalyDetector(mContext, mPolicy)); + mWakeupAlarmAnomalyDetector = spy( + new WakeupAlarmAnomalyDetector(mContext, mPolicy, mAnomalyUtils)); mWakeupAlarmAnomalyDetector.mBatteryUtils = mBatteryUtils; - mWakeupAlarmAnomalyDetector.mAnomalyAction = mAnomalyAction; } @Test