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

Commit 7704c982 authored by Shrinidhi Hegde's avatar Shrinidhi Hegde
Browse files

SystemUI as an exception to user impact level limit

Added SystemUI as an exception to User Impact Level limit since the device
would be unusable and the user would not be able to perform factory
reset themselves.

Bug: 349184283
Test: manual
Change-Id: I6746be06170dfe92ecd0e19f4f2297e05868b6d5
parent ac5399b7
Loading
Loading
Loading
Loading
+28 −1
Original line number Diff line number Diff line
@@ -150,6 +150,15 @@ public class PackageWatchdog {
    private static final int DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD =
            PackageHealthObserverImpact.USER_IMPACT_LEVEL_71;

    // Comma separated list of all packages exempt from user impact level threshold. If a package
    // in the list is crash looping, all the mitigations including factory reset will be performed.
    private static final String PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD =
            "persist.device_config.configuration.packages_exempt_from_impact_level_threshold";

    // Comma separated list of default packages exempt from user impact level threshold.
    private static final String DEFAULT_PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD =
            "com.android.systemui";

    private long mNumberOfNativeCrashPollsRemaining;

    private static final int DB_VERSION = 1;
@@ -196,6 +205,8 @@ public class PackageWatchdog {
    private final DeviceConfig.OnPropertiesChangedListener
            mOnPropertyChangedListener = this::onPropertyChanged;

    private final Set<String> mPackagesExemptFromImpactLevelThreshold = new ArraySet<>();

    // The set of packages that have been synced with the ExplicitHealthCheckController
    @GuardedBy("mLock")
    private Set<String> mRequestedHealthCheckPackages = new ArraySet<>();
@@ -518,7 +529,7 @@ public class PackageWatchdog {
                              @FailureReasons int failureReason,
                              int currentObserverImpact,
                              int mitigationCount) {
        if (currentObserverImpact < getUserImpactLevelLimit()) {
        if (allowMitigations(currentObserverImpact, versionedPackage)) {
            synchronized (mLock) {
                mLastMitigation = mSystemClock.uptimeMillis();
            }
@@ -526,6 +537,13 @@ public class PackageWatchdog {
        }
    }

    private boolean allowMitigations(int currentObserverImpact,
            VersionedPackage versionedPackage) {
        return currentObserverImpact < getUserImpactLevelLimit()
                || getPackagesExemptFromImpactLevelThreshold().contains(
                versionedPackage.getPackageName());
    }

    private long getMitigationWindowMs() {
        return SystemProperties.getLong(MITIGATION_WINDOW_MS, DEFAULT_MITIGATION_WINDOW_MS);
    }
@@ -657,6 +675,15 @@ public class PackageWatchdog {
                DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD);
    }

    private Set<String> getPackagesExemptFromImpactLevelThreshold() {
        if (mPackagesExemptFromImpactLevelThreshold.isEmpty()) {
            String packageNames = SystemProperties.get(PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD,
                    DEFAULT_PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD);
            return Set.of(packageNames.split("\\s*,\\s*"));
        }
        return mPackagesExemptFromImpactLevelThreshold;
    }

    /** Possible severity values of the user impact of a {@link PackageHealthObserver#execute}. */
    @Retention(SOURCE)
    @IntDef(value = {PackageHealthObserverImpact.USER_IMPACT_LEVEL_0,
+323 −1
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.when;

import android.Manifest;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
@@ -77,6 +78,7 @@ import org.mockito.stubbing.Answer;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -413,6 +415,311 @@ public class CrashRecoveryTest {
        verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
    }

    @Test
    @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
    public void testCrashLoopWithRescuePartyAndRollbackObserver() throws Exception {
        PackageWatchdog watchdog = createWatchdog();
        RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
        RollbackPackageHealthObserver rollbackObserver =
                setUpRollbackPackageHealthObserver(watchdog);
        VersionedPackage versionedPackageA = new VersionedPackage(APP_A, VERSION_CODE);

        when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).then(inv -> {
            ApplicationInfo info = new ApplicationInfo();
            info.flags |= ApplicationInfo.FLAG_PERSISTENT
                    | ApplicationInfo.FLAG_SYSTEM;
            return info;
        });

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: SCOPED_DEVICE_CONFIG_RESET
        verify(rescuePartyObserver).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
        verify(rescuePartyObserver, never()).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);
        verify(rollbackObserver, never()).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: ALL_DEVICE_CONFIG_RESET
        verify(rescuePartyObserver).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);
        verify(rescuePartyObserver, never()).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 3);
        verify(rollbackObserver, never()).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: WARM_REBOOT
        verify(rescuePartyObserver).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 3);
        verify(rescuePartyObserver, never()).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 4);
        verify(rollbackObserver, never()).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: Low impact rollback
        verify(rollbackObserver).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
        verify(rescuePartyObserver, never()).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 4);

        // update available rollbacks to mock rollbacks being applied after the call to
        // rollbackObserver.execute
        when(mRollbackManager.getAvailableRollbacks()).thenReturn(
                List.of(ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL));

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD reached. No more mitigations applied
        verify(rescuePartyObserver, never()).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 4);
        verify(rollbackObserver, never()).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);
    }

    @Test
    @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
    public void testCrashLoopWithRescuePartyAndRollbackObserverEnableDeprecateFlagReset()
            throws Exception {
        PackageWatchdog watchdog = createWatchdog();
        RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
        RollbackPackageHealthObserver rollbackObserver =
                setUpRollbackPackageHealthObserver(watchdog);
        VersionedPackage versionedPackageA = new VersionedPackage(APP_A, VERSION_CODE);

        when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).then(inv -> {
            ApplicationInfo info = new ApplicationInfo();
            info.flags |= ApplicationInfo.FLAG_PERSISTENT
                    | ApplicationInfo.FLAG_SYSTEM;
            return info;
        });


        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: WARM_REBOOT
        verify(rescuePartyObserver).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
        verify(rescuePartyObserver, never()).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);
        verify(rollbackObserver, never()).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: Low impact rollback
        verify(rollbackObserver).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
        verify(rescuePartyObserver, never()).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);

        // update available rollbacks to mock rollbacks being applied after the call to
        // rollbackObserver.execute
        when(mRollbackManager.getAvailableRollbacks()).thenReturn(
                List.of(ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL));

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD reached. No more mitigations applied
        verify(rescuePartyObserver, never()).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);
        verify(rollbackObserver, never()).execute(versionedPackageA,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);
    }

    @Test
    @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
    public void testCrashLoopSystemUIWithRescuePartyAndRollbackObserver() throws Exception {
        PackageWatchdog watchdog = createWatchdog();
        RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
        RollbackPackageHealthObserver rollbackObserver =
                setUpRollbackPackageHealthObserver(watchdog);
        String systemUi = "com.android.systemui";
        VersionedPackage versionedPackageUi = new VersionedPackage(
                systemUi, VERSION_CODE);
        RollbackInfo rollbackInfoUi = getRollbackInfo(systemUi, VERSION_CODE, 1,
                PackageManager.ROLLBACK_USER_IMPACT_LOW);
        when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_LOW,
                ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL, rollbackInfoUi));

        when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).then(inv -> {
            ApplicationInfo info = new ApplicationInfo();
            info.flags |= ApplicationInfo.FLAG_PERSISTENT
                    | ApplicationInfo.FLAG_SYSTEM;
            return info;
        });

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: SCOPED_DEVICE_CONFIG_RESET
        verify(rescuePartyObserver).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
        verify(rescuePartyObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);
        verify(rollbackObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: ALL_DEVICE_CONFIG_RESET
        verify(rescuePartyObserver).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);
        verify(rescuePartyObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 3);
        verify(rollbackObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: WARM_REBOOT
        verify(rescuePartyObserver).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 3);
        verify(rescuePartyObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 4);
        verify(rollbackObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: Low impact rollback
        verify(rollbackObserver).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
        verify(rescuePartyObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 4);
        verify(rollbackObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);

        // update available rollbacks to mock rollbacks being applied after the call to
        // rollbackObserver.execute
        when(mRollbackManager.getAvailableRollbacks()).thenReturn(
                List.of(ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL));

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: RESET_SETTINGS_UNTRUSTED_DEFAULTS
        verify(rescuePartyObserver).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 4);
        verify(rescuePartyObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 5);
        verify(rollbackObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: RESET_SETTINGS_UNTRUSTED_CHANGES
        verify(rescuePartyObserver).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 5);
        verify(rescuePartyObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 6);
        verify(rollbackObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: RESET_SETTINGS_TRUSTED_DEFAULTS
        verify(rescuePartyObserver).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 6);
        verify(rescuePartyObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 7);
        verify(rollbackObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: Factory reset. High impact rollbacks are performed only for boot loops.
        verify(rescuePartyObserver).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 7);
        verify(rescuePartyObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 8);
        verify(rollbackObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);
    }

    @Test
    @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
    public void testCrashLoopSystemUIWithRescuePartyAndRollbackObserverEnableDeprecateFlagReset()
            throws Exception {
        PackageWatchdog watchdog = createWatchdog();
        RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
        RollbackPackageHealthObserver rollbackObserver =
                setUpRollbackPackageHealthObserver(watchdog);
        String systemUi = "com.android.systemui";
        VersionedPackage versionedPackageUi = new VersionedPackage(
                systemUi, VERSION_CODE);
        RollbackInfo rollbackInfoUi = getRollbackInfo(systemUi, VERSION_CODE, 1,
                PackageManager.ROLLBACK_USER_IMPACT_LOW);
        when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_LOW,
                ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL, rollbackInfoUi));

        when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).then(inv -> {
            ApplicationInfo info = new ApplicationInfo();
            info.flags |= ApplicationInfo.FLAG_PERSISTENT
                    | ApplicationInfo.FLAG_SYSTEM;
            return info;
        });


        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: WARM_REBOOT
        verify(rescuePartyObserver).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
        verify(rescuePartyObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);
        verify(rollbackObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: Low impact rollback
        verify(rollbackObserver).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
        verify(rescuePartyObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);
        verify(rollbackObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);

        // update available rollbacks to mock rollbacks being applied after the call to
        // rollbackObserver.execute
        when(mRollbackManager.getAvailableRollbacks()).thenReturn(
                List.of(ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL));

        raiseFatalFailureAndDispatch(watchdog,
                Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH);

        // Mitigation: Factory reset. High impact rollbacks are performed only for boot loops.
        verify(rescuePartyObserver).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);
        verify(rescuePartyObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 3);
        verify(rollbackObserver, never()).execute(versionedPackageUi,
                PackageWatchdog.FAILURE_REASON_APP_CRASH, 2);
    }

    RollbackPackageHealthObserver setUpRollbackPackageHealthObserver(PackageWatchdog watchdog) {
        RollbackPackageHealthObserver rollbackObserver =
                spy(new RollbackPackageHealthObserver(mSpyContext, mApexManager));
@@ -424,7 +731,6 @@ public class CrashRecoveryTest {
        watchdog.registerHealthObserver(rollbackObserver);
        return rollbackObserver;
    }

    RescuePartyObserver setUpRescuePartyObserver(PackageWatchdog watchdog) {
        setCrashRecoveryPropRescueBootCount(0);
        RescuePartyObserver rescuePartyObserver = spy(RescuePartyObserver.getInstance(mSpyContext));
@@ -686,4 +992,20 @@ public class CrashRecoveryTest {
        mTestLooper.moveTimeForward(milliSeconds);
        mTestLooper.dispatchAll();
    }

    private void raiseFatalFailureAndDispatch(PackageWatchdog watchdog,
            List<VersionedPackage> packages, int failureReason) {
        long triggerFailureCount = watchdog.getTriggerFailureCount();
        if (failureReason == PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK
                || failureReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
            triggerFailureCount = 1;
        }
        for (int i = 0; i < triggerFailureCount; i++) {
            watchdog.onPackageFailure(packages, failureReason);
        }
        mTestLooper.dispatchAll();
        if (Flags.recoverabilityDetection()) {
            moveTimeForwardAndDispatch(watchdog.DEFAULT_MITIGATION_WINDOW_MS);
        }
    }
}