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
|
||||
*/
|
||||
public class BatteryUtils {
|
||||
public static final int UID_NULL = -1;
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({StatusType.FOREGROUND,
|
||||
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) {
|
||||
return timeUs / 1000;
|
||||
}
|
||||
|
@@ -90,6 +90,7 @@ public interface PowerUsageFeatureProvider {
|
||||
/**
|
||||
* Check whether a specific anomaly detector is enabled
|
||||
*/
|
||||
//TODO(b/62096650): remove this method and use AnomalyDetectionPolicy instead
|
||||
boolean isAnomalyDetectorEnabled(@Anomaly.AnomalyType int type);
|
||||
|
||||
/**
|
||||
|
@@ -108,4 +108,14 @@ public class AnomalyDetectionPolicy {
|
||||
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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserManager;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
|
||||
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 java.util.ArrayList;
|
||||
@@ -33,16 +34,45 @@ import java.util.List;
|
||||
*/
|
||||
public class AnomalyLoader extends AsyncLoader<List<Anomaly>> {
|
||||
private BatteryStatsHelper mBatteryStatsHelper;
|
||||
private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
|
||||
private String mPackageName;
|
||||
private UserManager mUserManager;
|
||||
@VisibleForTesting
|
||||
AnomalyUtils mAnomalyUtils;
|
||||
@VisibleForTesting
|
||||
AnomalyDetectionPolicy mPolicy;
|
||||
|
||||
/**
|
||||
* Create {@link AnomalyLoader} that runs anomaly check for all apps.
|
||||
*/
|
||||
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);
|
||||
mBatteryStatsHelper = batteryStatsHelper;
|
||||
mPowerUsageFeatureProvider = FeatureFactory.getFactory(
|
||||
context).getPowerUsageFeatureProvider(context);
|
||||
mPackageName = packageName;
|
||||
mAnomalyUtils = AnomalyUtils.getInstance(context);
|
||||
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||
mPolicy = policy;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,11 +81,18 @@ public class AnomalyLoader extends AsyncLoader<List<Anomaly>> {
|
||||
|
||||
@Override
|
||||
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<>();
|
||||
for (@Anomaly.AnomalyType int type : Anomaly.ANOMALY_TYPE_LIST) {
|
||||
if (mPowerUsageFeatureProvider.isAnomalyDetectorEnabled(type)) {
|
||||
if (mPolicy.isAnomalyDetectorEnabled(type)) {
|
||||
anomalies.addAll(mAnomalyUtils.getAnomalyDetector(type).detectAnomalies(
|
||||
mBatteryStatsHelper));
|
||||
mBatteryStatsHelper, mPackageName));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -17,11 +17,30 @@
|
||||
|
||||
package com.android.settings.fuelgauge.anomaly.checker;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import com.android.internal.os.BatteryStatsHelper;
|
||||
import com.android.settings.fuelgauge.anomaly.Anomaly;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
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<Anomaly> anomalies = new ArrayList<>();
|
||||
final long rawRealtime = SystemClock.elapsedRealtime();
|
||||
final int targetUid = mBatteryUtils.getPackageUid(targetPackageName);
|
||||
|
||||
// Check the app one by one
|
||||
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) {
|
||||
if (uid == null
|
||||
|| mBatteryUtils.shouldHideSipper(sipper)
|
||||
|| (targetUid != BatteryUtils.UID_NULL && targetUid != uid.getUid())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks =
|
||||
uid.getWakelockStats();
|
||||
long maxPartialWakeLockMs = 0;
|
||||
@@ -88,10 +98,9 @@ public class WakeLockAnomalyDetector implements AnomalyDetector {
|
||||
getTotalDurationMs(timer, rawRealtime));
|
||||
}
|
||||
|
||||
// Report it if wakelock time is too long and it is not a hidden batterysipper
|
||||
// TODO: add more attributes to detect wakelock anomaly
|
||||
if (maxPartialWakeLockMs > mWakeLockThresholdMs
|
||||
&& !mBatteryUtils.shouldHideSipper(sipper)) {
|
||||
// Report application as anomaly if wakelock time is too long
|
||||
// TODO(b/38233034): add more attributes to detect wakelock anomaly
|
||||
if (maxPartialWakeLockMs > mWakeLockThresholdMs) {
|
||||
final String packageName = mBatteryUtils.getPackageName(uid.getUid());
|
||||
final CharSequence displayName = Utils.getApplicationLabel(mContext,
|
||||
packageName);
|
||||
|
@@ -57,16 +57,25 @@ public class WakeupAlarmAnomalyDetector implements AnomalyDetector {
|
||||
|
||||
@Override
|
||||
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<Anomaly> anomalies = new ArrayList<>();
|
||||
final long totalRunningHours = mBatteryUtils.calculateRunningTimeBasedOnStatsType(
|
||||
batteryStatsHelper, BatteryStats.STATS_SINCE_CHARGED) / DateUtils.HOUR_IN_MILLIS;
|
||||
final int targetUid = mBatteryUtils.getPackageUid(targetPackageName);
|
||||
|
||||
if (totalRunningHours != 0) {
|
||||
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)) {
|
||||
if (uid == null
|
||||
|| mBatteryUtils.shouldHideSipper(sipper)
|
||||
|| (targetUid != BatteryUtils.UID_NULL && targetUid != uid.getUid())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user