Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 457fb842 authored by jackqdyulei's avatar jackqdyulei
Browse files

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
parent 3ee28c81
Loading
Loading
Loading
Loading
+35 −2
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import com.android.settings.fuelgauge.anomaly.Anomaly;
import com.android.settings.overlay.FeatureFactory;

import com.android.settingslib.utils.PowerUtil;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collections;
@@ -69,6 +70,7 @@ public class BatteryUtils {
        int BACKGROUND = 2;
        int ALL = 3;
    }

    private static final String TAG = "BatteryUtils";

    private static final int MIN_POWER_THRESHOLD_MILLI_AMP = 5;
@@ -81,6 +83,7 @@ public class BatteryUtils {
    private Context mContext;
    @VisibleForTesting
    PowerUsageFeatureProvider mPowerUsageFeatureProvider;

    public static BatteryUtils getInstance(Context context) {
        if (sInstance == null || sInstance.isDataCorrupted()) {
            sInstance = new BatteryUtils(context);
@@ -153,8 +156,7 @@ public class BatteryUtils {
    private long getProcessForegroundTimeMs(BatteryStats.Uid uid, int which) {
        final long rawRealTimeUs = PowerUtil.convertMsToUs(SystemClock.elapsedRealtime());
        return getScreenUsageTimeMs(uid, which, rawRealTimeUs)
                + PowerUtil.convertUsToMs(
                        getForegroundServiceTotalTimeUs(uid, rawRealTimeUs));
                + PowerUtil.convertUsToMs(getForegroundServiceTotalTimeUs(uid, rawRealTimeUs));
    }

    /**
@@ -349,6 +351,7 @@ public class BatteryUtils {

    /**
     * Calculate the screen usage time since last full charge.
     *
     * @param batteryStatsHelper utility class that contains the screen usage data
     * @return time in millis
     */
@@ -500,5 +503,35 @@ public class BatteryUtils {
        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;
    }
}
+13 −5
Original line number Diff line number Diff line
@@ -33,10 +33,12 @@ import android.content.Intent;
import android.os.Bundle;
import android.os.StatsDimensionsValue;
import android.os.SystemPropertiesProto;
import android.os.UserManager;
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import android.util.Log;

import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.R;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settingslib.utils.ThreadUtils;
@@ -76,10 +78,14 @@ public class AnomalyDetectionJobService extends JobService {
            final BatteryTipPolicy policy = new BatteryTipPolicy(this);
            final BatteryUtils batteryUtils = BatteryUtils.getInstance(this);
            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;
                    item = params.dequeueWork()) {
                saveAnomalyToDatabase(batteryDatabaseManager, batteryUtils, policy, contentResolver,
                saveAnomalyToDatabase(batteryStatsHelper, userManager, batteryDatabaseManager,
                        batteryUtils, policy, contentResolver,
                        item.getIntent().getExtras());
            }
            jobFinished(params, false /* wantsReschedule */);
@@ -94,9 +100,9 @@ public class AnomalyDetectionJobService extends JobService {
    }

    @VisibleForTesting
    void saveAnomalyToDatabase(BatteryDatabaseManager databaseManager,
            BatteryUtils batteryUtils, BatteryTipPolicy policy, ContentResolver contentResolver,
            Bundle bundle) {
    void saveAnomalyToDatabase(BatteryStatsHelper batteryStatsHelper, UserManager userManager,
            BatteryDatabaseManager databaseManager, BatteryUtils batteryUtils,
            BatteryTipPolicy policy, ContentResolver contentResolver, Bundle bundle) {
        // The Example of intentDimsValue is: 35:{1:{1:{1:10013|}|}|}
        final StatsDimensionsValue intentDimsValue =
                bundle.getParcelable(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE);
@@ -116,7 +122,9 @@ public class AnomalyDetectionJobService extends JobService {

            if (anomalyType == StatsManagerConfig.AnomalyType.EXCESSIVE_BG) {
                // 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);
                    batteryUtils.setForceAppStandby(uid, packageName,
                            AppOpsManager.MODE_IGNORED);
+12 −0
Original line number Diff line number Diff line
@@ -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_HOUR = "low_battery_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
@@ -151,6 +152,16 @@ public class BatteryTipPolicy {
     */
    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;

    public BatteryTipPolicy(Context context) {
@@ -183,6 +194,7 @@ public class BatteryTipPolicy {
        lowBatteryEnabled = mParser.getBoolean(KEY_LOW_BATTERY_ENABLED, false);
        lowBatteryHour = mParser.getInt(KEY_LOW_BATTERY_HOUR, 16);
        dataHistoryRetainHour = mParser.getInt(KEY_DATA_HISTORY_RETAIN_HOUR, 72);
        excessiveBgDrainPercentage = mParser.getInt(KEY_EXCESSIVE_BG_DRAIN_PERCENTAGE, 10);
    }

}
+17 −1
Original line number Diff line number Diff line
@@ -177,9 +177,9 @@ public class BatteryUtilsTest {
        mHighApplicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
        mLowApplicationInfo.targetSdkVersion = Build.VERSION_CODES.L;


        mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
        mNormalBatterySipper.totalPowerMah = TOTAL_BATTERY_USAGE;
        doReturn(UID).when(mNormalBatterySipper).getUid();

        mWifiBatterySipper.drainType = BatterySipper.DrainType.WIFI;
        mWifiBatterySipper.totalPowerMah = BATTERY_WIFI_USAGE;
@@ -216,6 +216,10 @@ public class BatteryUtilsTest {
        mUsageList.add(mScreenBatterySipper);
        mUsageList.add(mCellBatterySipper);
        doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList();
        doReturn(TOTAL_BATTERY_USAGE + BATTERY_SCREEN_USAGE).when(
                mBatteryStatsHelper).getTotalPower();
        when(mBatteryStatsHelper.getStats().getDischargeAmount(anyInt())).thenReturn(
                DISCHARGE_AMOUNT);
    }

    @Test
@@ -547,4 +551,16 @@ public class BatteryUtilsTest {
        verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
                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();
    }
}
+4 −2
Original line number Diff line number Diff line
@@ -50,7 +50,8 @@ public class BatteryTipPolicyTest {
            + ",reduced_battery_percent=30"
            + ",low_battery_enabled=false"
            + ",low_battery_hour=10"
            + ",data_history_retain_hour=24";
            + ",data_history_retain_hour=24"
            + ",excessive_bg_drain_percentage=25";
    private Context mContext;

    @Before
@@ -78,6 +79,7 @@ public class BatteryTipPolicyTest {
        assertThat(batteryTipPolicy.lowBatteryEnabled).isFalse();
        assertThat(batteryTipPolicy.lowBatteryHour).isEqualTo(10);
        assertThat(batteryTipPolicy.dataHistoryRetainHour).isEqualTo(24);
        assertThat(batteryTipPolicy.excessiveBgDrainPercentage).isEqualTo(25);
    }

    @Test
@@ -100,6 +102,6 @@ public class BatteryTipPolicyTest {
        assertThat(batteryTipPolicy.lowBatteryEnabled).isFalse();
        assertThat(batteryTipPolicy.lowBatteryHour).isEqualTo(16);
        assertThat(batteryTipPolicy.dataHistoryRetainHour).isEqualTo(72);
        assertThat(batteryTipPolicy.excessiveBgDrainPercentage).isEqualTo(10);
    }

}