Add special check for excessive bg anomaly

To check whether this app has battery usage more than x%

Bug: 72385333
Test: RunSettingsRoboTests
Change-Id: I87e6b01c866a053658f84ce3486120ae82963fd9
This commit is contained in:
jackqdyulei
2018-02-22 10:22:08 -08:00
parent 3ee28c810d
commit 457fb842eb
5 changed files with 81 additions and 10 deletions

View File

@@ -44,6 +44,7 @@ import com.android.settings.fuelgauge.anomaly.Anomaly;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.utils.PowerUtil; import com.android.settingslib.utils.PowerUtil;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.Collections; import java.util.Collections;
@@ -69,6 +70,7 @@ public class BatteryUtils {
int BACKGROUND = 2; int BACKGROUND = 2;
int ALL = 3; int ALL = 3;
} }
private static final String TAG = "BatteryUtils"; private static final String TAG = "BatteryUtils";
private static final int MIN_POWER_THRESHOLD_MILLI_AMP = 5; private static final int MIN_POWER_THRESHOLD_MILLI_AMP = 5;
@@ -81,6 +83,7 @@ public class BatteryUtils {
private Context mContext; private Context mContext;
@VisibleForTesting @VisibleForTesting
PowerUsageFeatureProvider mPowerUsageFeatureProvider; PowerUsageFeatureProvider mPowerUsageFeatureProvider;
public static BatteryUtils getInstance(Context context) { public static BatteryUtils getInstance(Context context) {
if (sInstance == null || sInstance.isDataCorrupted()) { if (sInstance == null || sInstance.isDataCorrupted()) {
sInstance = new BatteryUtils(context); sInstance = new BatteryUtils(context);
@@ -153,8 +156,7 @@ public class BatteryUtils {
private long getProcessForegroundTimeMs(BatteryStats.Uid uid, int which) { private long getProcessForegroundTimeMs(BatteryStats.Uid uid, int which) {
final long rawRealTimeUs = PowerUtil.convertMsToUs(SystemClock.elapsedRealtime()); final long rawRealTimeUs = PowerUtil.convertMsToUs(SystemClock.elapsedRealtime());
return getScreenUsageTimeMs(uid, which, rawRealTimeUs) return getScreenUsageTimeMs(uid, which, rawRealTimeUs)
+ PowerUtil.convertUsToMs( + PowerUtil.convertUsToMs(getForegroundServiceTotalTimeUs(uid, rawRealTimeUs));
getForegroundServiceTotalTimeUs(uid, rawRealTimeUs));
} }
/** /**
@@ -349,6 +351,7 @@ public class BatteryUtils {
/** /**
* Calculate the screen usage time since last full charge. * Calculate the screen usage time since last full charge.
*
* @param batteryStatsHelper utility class that contains the screen usage data * @param batteryStatsHelper utility class that contains the screen usage data
* @return time in millis * @return time in millis
*/ */
@@ -500,5 +503,35 @@ public class BatteryUtils {
return false; return false;
} }
/**
* Check if the app represented by {@code uid} has battery usage more than {@code threshold}
*
* @param batteryStatsHelper used to check the battery usage
* @param userManager used to init the {@code batteryStatsHelper}
* @param uid represent the app
* @param threshold battery percentage threshold(e.g. 10 means 10% battery usage )
* @return {@code true} if battery drain is more than the threshold
*/
public boolean isAppHeavilyUsed(BatteryStatsHelper batteryStatsHelper, UserManager userManager,
int uid, int threshold) {
initBatteryStatsHelper(batteryStatsHelper, null /* bundle */, userManager);
final int dischargeAmount = batteryStatsHelper.getStats().getDischargeAmount(
BatteryStats.STATS_SINCE_CHARGED);
List<BatterySipper> batterySippers = batteryStatsHelper.getUsageList();
final double hiddenAmount = removeHiddenBatterySippers(batterySippers);
for (int i = 0, size = batterySippers.size(); i < size; i++) {
final BatterySipper batterySipper = batterySippers.get(i);
if (batterySipper.getUid() == uid) {
final int percent = (int) calculateBatteryPercent(
batterySipper.totalPowerMah, batteryStatsHelper.getTotalPower(),
hiddenAmount,
dischargeAmount);
return percent >= threshold;
}
}
return false;
}
} }

View File

@@ -33,10 +33,12 @@ import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.StatsDimensionsValue; import android.os.StatsDimensionsValue;
import android.os.SystemPropertiesProto; import android.os.SystemPropertiesProto;
import android.os.UserManager;
import android.provider.Settings; import android.provider.Settings;
import android.support.annotation.VisibleForTesting; import android.support.annotation.VisibleForTesting;
import android.util.Log; import android.util.Log;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.utils.ThreadUtils;
@@ -76,10 +78,14 @@ public class AnomalyDetectionJobService extends JobService {
final BatteryTipPolicy policy = new BatteryTipPolicy(this); final BatteryTipPolicy policy = new BatteryTipPolicy(this);
final BatteryUtils batteryUtils = BatteryUtils.getInstance(this); final BatteryUtils batteryUtils = BatteryUtils.getInstance(this);
final ContentResolver contentResolver = getContentResolver(); final ContentResolver contentResolver = getContentResolver();
final BatteryStatsHelper batteryStatsHelper = new BatteryStatsHelper(this,
true /* collectBatteryBroadcast */);
final UserManager userManager = getSystemService(UserManager.class);
for (JobWorkItem item = params.dequeueWork(); item != null; for (JobWorkItem item = params.dequeueWork(); item != null;
item = params.dequeueWork()) { item = params.dequeueWork()) {
saveAnomalyToDatabase(batteryDatabaseManager, batteryUtils, policy, contentResolver, saveAnomalyToDatabase(batteryStatsHelper, userManager, batteryDatabaseManager,
batteryUtils, policy, contentResolver,
item.getIntent().getExtras()); item.getIntent().getExtras());
} }
jobFinished(params, false /* wantsReschedule */); jobFinished(params, false /* wantsReschedule */);
@@ -94,9 +100,9 @@ public class AnomalyDetectionJobService extends JobService {
} }
@VisibleForTesting @VisibleForTesting
void saveAnomalyToDatabase(BatteryDatabaseManager databaseManager, void saveAnomalyToDatabase(BatteryStatsHelper batteryStatsHelper, UserManager userManager,
BatteryUtils batteryUtils, BatteryTipPolicy policy, ContentResolver contentResolver, BatteryDatabaseManager databaseManager, BatteryUtils batteryUtils,
Bundle bundle) { BatteryTipPolicy policy, ContentResolver contentResolver, Bundle bundle) {
// The Example of intentDimsValue is: 35:{1:{1:{1:10013|}|}|} // The Example of intentDimsValue is: 35:{1:{1:{1:10013|}|}|}
final StatsDimensionsValue intentDimsValue = final StatsDimensionsValue intentDimsValue =
bundle.getParcelable(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE); bundle.getParcelable(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE);
@@ -116,7 +122,9 @@ public class AnomalyDetectionJobService extends JobService {
if (anomalyType == StatsManagerConfig.AnomalyType.EXCESSIVE_BG) { if (anomalyType == StatsManagerConfig.AnomalyType.EXCESSIVE_BG) {
// TODO(b/72385333): check battery percentage draining in batterystats // TODO(b/72385333): check battery percentage draining in batterystats
if (batteryUtils.isLegacyApp(packageName)) { if (batteryUtils.isLegacyApp(packageName) && batteryUtils.isAppHeavilyUsed(
batteryStatsHelper, userManager, uid,
policy.excessiveBgDrainPercentage)) {
Log.e(TAG, "Excessive detected uid=" + uid); Log.e(TAG, "Excessive detected uid=" + uid);
batteryUtils.setForceAppStandby(uid, packageName, batteryUtils.setForceAppStandby(uid, packageName,
AppOpsManager.MODE_IGNORED); AppOpsManager.MODE_IGNORED);

View File

@@ -44,6 +44,7 @@ public class BatteryTipPolicy {
private static final String KEY_LOW_BATTERY_ENABLED = "low_battery_enabled"; private static final String KEY_LOW_BATTERY_ENABLED = "low_battery_enabled";
private static final String KEY_LOW_BATTERY_HOUR = "low_battery_hour"; private static final String KEY_LOW_BATTERY_HOUR = "low_battery_hour";
private static final String KEY_DATA_HISTORY_RETAIN_HOUR = "data_history_retain_hour"; private static final String KEY_DATA_HISTORY_RETAIN_HOUR = "data_history_retain_hour";
private static final String KEY_EXCESSIVE_BG_DRAIN_PERCENTAGE = "excessive_bg_drain_percentage";
/** /**
* {@code true} if general battery tip is enabled * {@code true} if general battery tip is enabled
@@ -151,6 +152,16 @@ public class BatteryTipPolicy {
*/ */
public final int dataHistoryRetainHour; public final int dataHistoryRetainHour;
/**
* Battery drain percentage threshold for excessive background anomaly(i.e. 10%)
*
* This is an additional check for excessive background, to check whether battery drain
* for an app is larger than x%
* @see Settings.Global#BATTERY_TIP_CONSTANTS
* @see #KEY_EXCESSIVE_BG_DRAIN_PERCENTAGE
*/
public final int excessiveBgDrainPercentage;
private final KeyValueListParser mParser; private final KeyValueListParser mParser;
public BatteryTipPolicy(Context context) { public BatteryTipPolicy(Context context) {
@@ -183,6 +194,7 @@ public class BatteryTipPolicy {
lowBatteryEnabled = mParser.getBoolean(KEY_LOW_BATTERY_ENABLED, false); lowBatteryEnabled = mParser.getBoolean(KEY_LOW_BATTERY_ENABLED, false);
lowBatteryHour = mParser.getInt(KEY_LOW_BATTERY_HOUR, 16); lowBatteryHour = mParser.getInt(KEY_LOW_BATTERY_HOUR, 16);
dataHistoryRetainHour = mParser.getInt(KEY_DATA_HISTORY_RETAIN_HOUR, 72); dataHistoryRetainHour = mParser.getInt(KEY_DATA_HISTORY_RETAIN_HOUR, 72);
excessiveBgDrainPercentage = mParser.getInt(KEY_EXCESSIVE_BG_DRAIN_PERCENTAGE, 10);
} }
} }

View File

@@ -177,9 +177,9 @@ public class BatteryUtilsTest {
mHighApplicationInfo.targetSdkVersion = Build.VERSION_CODES.O; mHighApplicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
mLowApplicationInfo.targetSdkVersion = Build.VERSION_CODES.L; mLowApplicationInfo.targetSdkVersion = Build.VERSION_CODES.L;
mNormalBatterySipper.drainType = BatterySipper.DrainType.APP; mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
mNormalBatterySipper.totalPowerMah = TOTAL_BATTERY_USAGE; mNormalBatterySipper.totalPowerMah = TOTAL_BATTERY_USAGE;
doReturn(UID).when(mNormalBatterySipper).getUid();
mWifiBatterySipper.drainType = BatterySipper.DrainType.WIFI; mWifiBatterySipper.drainType = BatterySipper.DrainType.WIFI;
mWifiBatterySipper.totalPowerMah = BATTERY_WIFI_USAGE; mWifiBatterySipper.totalPowerMah = BATTERY_WIFI_USAGE;
@@ -216,6 +216,10 @@ public class BatteryUtilsTest {
mUsageList.add(mScreenBatterySipper); mUsageList.add(mScreenBatterySipper);
mUsageList.add(mCellBatterySipper); mUsageList.add(mCellBatterySipper);
doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList(); doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList();
doReturn(TOTAL_BATTERY_USAGE + BATTERY_SCREEN_USAGE).when(
mBatteryStatsHelper).getTotalPower();
when(mBatteryStatsHelper.getStats().getDischargeAmount(anyInt())).thenReturn(
DISCHARGE_AMOUNT);
} }
@Test @Test
@@ -547,4 +551,16 @@ public class BatteryUtilsTest {
verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID, verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
HIGH_SDK_PACKAGE, AppOpsManager.MODE_IGNORED); HIGH_SDK_PACKAGE, AppOpsManager.MODE_IGNORED);
} }
@Test
public void testIsAppHeavilyUsed_usageMoreThanThreshold_returnTrue() {
assertThat(mBatteryUtils.isAppHeavilyUsed(mBatteryStatsHelper, mUserManager, UID,
10 /* threshold */ )).isTrue();
}
@Test
public void testIsAppHeavilyUsed_usageLessThanThreshold_returnFalse() {
assertThat(mBatteryUtils.isAppHeavilyUsed(mBatteryStatsHelper, mUserManager, UID,
DISCHARGE_AMOUNT /* threshold */ )).isFalse();
}
} }

View File

@@ -50,7 +50,8 @@ public class BatteryTipPolicyTest {
+ ",reduced_battery_percent=30" + ",reduced_battery_percent=30"
+ ",low_battery_enabled=false" + ",low_battery_enabled=false"
+ ",low_battery_hour=10" + ",low_battery_hour=10"
+ ",data_history_retain_hour=24"; + ",data_history_retain_hour=24"
+ ",excessive_bg_drain_percentage=25";
private Context mContext; private Context mContext;
@Before @Before
@@ -78,6 +79,7 @@ public class BatteryTipPolicyTest {
assertThat(batteryTipPolicy.lowBatteryEnabled).isFalse(); assertThat(batteryTipPolicy.lowBatteryEnabled).isFalse();
assertThat(batteryTipPolicy.lowBatteryHour).isEqualTo(10); assertThat(batteryTipPolicy.lowBatteryHour).isEqualTo(10);
assertThat(batteryTipPolicy.dataHistoryRetainHour).isEqualTo(24); assertThat(batteryTipPolicy.dataHistoryRetainHour).isEqualTo(24);
assertThat(batteryTipPolicy.excessiveBgDrainPercentage).isEqualTo(25);
} }
@Test @Test
@@ -100,6 +102,6 @@ public class BatteryTipPolicyTest {
assertThat(batteryTipPolicy.lowBatteryEnabled).isFalse(); assertThat(batteryTipPolicy.lowBatteryEnabled).isFalse();
assertThat(batteryTipPolicy.lowBatteryHour).isEqualTo(16); assertThat(batteryTipPolicy.lowBatteryHour).isEqualTo(16);
assertThat(batteryTipPolicy.dataHistoryRetainHour).isEqualTo(72); assertThat(batteryTipPolicy.dataHistoryRetainHour).isEqualTo(72);
assertThat(batteryTipPolicy.excessiveBgDrainPercentage).isEqualTo(10);
} }
} }