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:
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user