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

Commit b5eac9b4 authored by YK Hung's avatar YK Hung Committed by Android (Google) Code Review
Browse files

Merge "Clean up the legacy anomaly detection mechanism in the Settings" into main

parents a05c1e52 9ccd8d8d
Loading
Loading
Loading
Loading
+0 −75
Original line number Diff line number Diff line
@@ -22,17 +22,14 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Build;
import android.os.Process;
import android.os.SystemClock;
import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.format.DateUtils;
@@ -47,14 +44,11 @@ import androidx.annotation.WorkerThread;
import com.android.internal.util.ArrayUtils;
import com.android.settings.R;
import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
import com.android.settings.fuelgauge.batterytip.AnomalyInfo;
import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
import com.android.settings.fuelgauge.batterytip.StatsManagerConfig;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.fuelgauge.Estimate;
import com.android.settingslib.fuelgauge.EstimateKt;
import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
import com.android.settingslib.utils.PowerUtil;
import com.android.settingslib.utils.StringUtil;
import com.android.settingslib.utils.ThreadUtils;
@@ -68,7 +62,6 @@ import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.List;

/** Utils for battery operation */
public class BatteryUtils {
@@ -548,74 +541,6 @@ public class BatteryUtils {
        return false;
    }

    /** Return {@code true} if we should hide anomaly app represented by {@code uid} */
    public boolean shouldHideAnomaly(
            PowerAllowlistBackend powerAllowlistBackend, int uid, AnomalyInfo anomalyInfo) {
        final String[] packageNames = mPackageManager.getPackagesForUid(uid);
        if (ArrayUtils.isEmpty(packageNames)) {
            // Don't show it if app has been uninstalled
            return true;
        }

        return isSystemUid(uid)
                || powerAllowlistBackend.isAllowlisted(packageNames, uid)
                || (isSystemApp(mPackageManager, packageNames) && !hasLauncherEntry(packageNames))
                || (isExcessiveBackgroundAnomaly(anomalyInfo) && !isPreOApp(packageNames));
    }

    private boolean isExcessiveBackgroundAnomaly(AnomalyInfo anomalyInfo) {
        return anomalyInfo.anomalyType
                == StatsManagerConfig.AnomalyType.EXCESSIVE_BACKGROUND_SERVICE;
    }

    private boolean isSystemUid(int uid) {
        final int appUid = UserHandle.getAppId(uid);
        return appUid >= Process.ROOT_UID && appUid < Process.FIRST_APPLICATION_UID;
    }

    private boolean isSystemApp(PackageManager packageManager, String[] packageNames) {
        for (String packageName : packageNames) {
            try {
                final ApplicationInfo info =
                        packageManager.getApplicationInfo(packageName, 0 /* flags */);
                if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                    return true;
                }
            } catch (PackageManager.NameNotFoundException e) {
                Log.e(TAG, "Package not found: " + packageName, e);
            }
        }

        return false;
    }

    private boolean hasLauncherEntry(String[] packageNames) {
        final Intent launchIntent = new Intent(Intent.ACTION_MAIN, null);
        launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);

        // If we do not specify MATCH_DIRECT_BOOT_AWARE or
        // MATCH_DIRECT_BOOT_UNAWARE, system will derive and update the flags
        // according to the user's lock state. When the user is locked,
        // components
        // with ComponentInfo#directBootAware == false will be filtered. We should
        // explicitly include both direct boot aware and unaware components here.
        final List<ResolveInfo> resolveInfos =
                mPackageManager.queryIntentActivities(
                        launchIntent,
                        PackageManager.MATCH_DISABLED_COMPONENTS
                                | PackageManager.MATCH_DIRECT_BOOT_AWARE
                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                                | PackageManager.MATCH_SYSTEM_ONLY);
        for (int i = 0, size = resolveInfos.size(); i < size; i++) {
            final ResolveInfo resolveInfo = resolveInfos.get(i);
            if (ArrayUtils.contains(packageNames, resolveInfo.activityInfo.packageName)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Return version number of an app represented by {@code packageName}, and return -1 if not
     * found.
+0 −38
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.batterytip;

import android.util.KeyValueListParser;
import android.util.Log;

/** Model class to parse and store anomaly info from statsd. */
public class AnomalyInfo {
    private static final String TAG = "AnomalyInfo";

    private static final String KEY_ANOMALY_TYPE = "anomaly_type";
    private static final String KEY_AUTO_RESTRICTION = "auto_restriction";
    public final Integer anomalyType;
    public final boolean autoRestriction;

    public AnomalyInfo(String info) {
        Log.i(TAG, "anomalyInfo: " + info);
        KeyValueListParser parser = new KeyValueListParser(',');
        parser.setString(info);
        anomalyType = parser.getInt(KEY_ANOMALY_TYPE, -1);
        autoRestriction = parser.getBoolean(KEY_AUTO_RESTRICTION, false);
    }
}
+0 −82
Original line number Diff line number Diff line
@@ -40,20 +40,16 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats;
import android.os.Build;
import android.os.Process;
import android.os.SystemClock;

import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
import com.android.settings.fuelgauge.batterytip.AnomalyInfo;
import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowThreadUtils;
@@ -70,9 +66,6 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;

import java.util.ArrayList;
import java.util.List;

@RunWith(RobolectricTestRunner.class)
public class BatteryUtilsTest {

@@ -122,7 +115,6 @@ public class BatteryUtilsTest {
    @Mock private ApplicationInfo mLowApplicationInfo;
    @Mock private PowerAllowlistBackend mPowerAllowlistBackend;
    @Mock private BatteryDatabaseManager mBatteryDatabaseManager;
    private AnomalyInfo mAnomalyInfo;
    private BatteryUtils mBatteryUtils;
    private FakeFeatureFactory mFeatureFactory;
    private PowerUsageFeatureProvider mProvider;
@@ -169,7 +161,6 @@ public class BatteryUtilsTest {
        doReturn(0L)
                .when(mBatteryUtils)
                .getForegroundServiceTotalTimeUs(any(BatteryStats.Uid.class), anyLong());
        mAnomalyInfo = new AnomalyInfo(INFO_WAKELOCK);

        BatteryDatabaseManager.setUpForTest(mBatteryDatabaseManager);
        ShadowThreadUtils.setIsMainThread(true);
@@ -390,79 +381,6 @@ public class BatteryUtilsTest {
        assertThat(mBatteryUtils.isForceAppStandbyEnabled(UID, PACKAGE_NAME)).isFalse();
    }

    @Test
    public void testShouldHideAnomaly_systemAppWithLauncher_returnTrue() {
        final List<ResolveInfo> resolveInfos = new ArrayList<>();
        final ResolveInfo resolveInfo = new ResolveInfo();
        resolveInfo.activityInfo = new ActivityInfo();
        resolveInfo.activityInfo.packageName = HIGH_SDK_PACKAGE;

        doReturn(resolveInfos).when(mPackageManager).queryIntentActivities(any(), anyInt());
        doReturn(new String[] {HIGH_SDK_PACKAGE}).when(mPackageManager).getPackagesForUid(UID);
        mHighApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;

        assertThat(mBatteryUtils.shouldHideAnomaly(mPowerAllowlistBackend, UID, mAnomalyInfo))
                .isTrue();
    }

    @Test
    public void testShouldHideAnomaly_systemAppWithoutLauncher_returnTrue() {
        doReturn(new ArrayList<>()).when(mPackageManager).queryIntentActivities(any(), anyInt());
        doReturn(new String[] {HIGH_SDK_PACKAGE}).when(mPackageManager).getPackagesForUid(UID);
        mHighApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;

        assertThat(mBatteryUtils.shouldHideAnomaly(mPowerAllowlistBackend, UID, mAnomalyInfo))
                .isTrue();
    }

    @Test
    public void testShouldHideAnomaly_systemUid_returnTrue() {
        final int systemUid = Process.ROOT_UID;
        doReturn(new String[] {HIGH_SDK_PACKAGE})
                .when(mPackageManager)
                .getPackagesForUid(systemUid);

        assertThat(mBatteryUtils.shouldHideAnomaly(mPowerAllowlistBackend, systemUid, mAnomalyInfo))
                .isTrue();
    }

    @Test
    public void testShouldHideAnomaly_AppInDozeList_returnTrue() {
        doReturn(new String[] {HIGH_SDK_PACKAGE}).when(mPackageManager).getPackagesForUid(UID);
        doReturn(true)
                .when(mPowerAllowlistBackend)
                .isAllowlisted(new String[] {HIGH_SDK_PACKAGE}, UID);

        assertThat(mBatteryUtils.shouldHideAnomaly(mPowerAllowlistBackend, UID, mAnomalyInfo))
                .isTrue();
    }

    @Test
    public void testShouldHideAnomaly_normalApp_returnFalse() {
        doReturn(new String[] {HIGH_SDK_PACKAGE}).when(mPackageManager).getPackagesForUid(UID);

        assertThat(mBatteryUtils.shouldHideAnomaly(mPowerAllowlistBackend, UID, mAnomalyInfo))
                .isFalse();
    }

    @Test
    public void testShouldHideAnomaly_excessivePriorOApp_returnFalse() {
        doReturn(new String[] {LOW_SDK_PACKAGE}).when(mPackageManager).getPackagesForUid(UID);
        mAnomalyInfo = new AnomalyInfo(INFO_EXCESSIVE);

        assertThat(mBatteryUtils.shouldHideAnomaly(mPowerAllowlistBackend, UID, mAnomalyInfo))
                .isFalse();
    }

    @Test
    public void testShouldHideAnomaly_excessiveOApp_returnTrue() {
        doReturn(new String[] {HIGH_SDK_PACKAGE}).when(mPackageManager).getPackagesForUid(UID);
        mAnomalyInfo = new AnomalyInfo(INFO_EXCESSIVE);

        assertThat(mBatteryUtils.shouldHideAnomaly(mPowerAllowlistBackend, UID, mAnomalyInfo))
                .isTrue();
    }

    @Test
    public void clearForceAppStandby_appRestricted_clearAndReturnTrue() {
        when(mBatteryUtils.getPackageUid(HIGH_SDK_PACKAGE)).thenReturn(UID);
+2 −0
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ import com.android.settingslib.search.SearchIndexableRaw;

import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.AdditionalMatchers;
@@ -709,6 +710,7 @@ public class UserSettingsTest {
        verify(mUserManager).getAliveUsers();
    }

    @Ignore
    @Test
    public void updateUserList_userIconMissing_shouldLoadIcon() {
        UserInfo currentUser = getAdminUser(true);