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

Commit debe12db authored by Shrinidhi Hegde's avatar Shrinidhi Hegde Committed by Gerrit Code Review
Browse files

Merge "SystemUI as an exception to user impact level limit" into main

parents c53b898a 7704c982
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);
        }
    }
}