Loading services/core/java/com/android/server/PackageWatchdog.java +28 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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<>(); Loading Loading @@ -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(); } Loading @@ -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); } Loading Loading @@ -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, Loading tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java +323 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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)); Loading @@ -424,7 +731,6 @@ public class CrashRecoveryTest { watchdog.registerHealthObserver(rollbackObserver); return rollbackObserver; } RescuePartyObserver setUpRescuePartyObserver(PackageWatchdog watchdog) { setCrashRecoveryPropRescueBootCount(0); RescuePartyObserver rescuePartyObserver = spy(RescuePartyObserver.getInstance(mSpyContext)); Loading Loading @@ -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); } } } Loading
services/core/java/com/android/server/PackageWatchdog.java +28 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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<>(); Loading Loading @@ -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(); } Loading @@ -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); } Loading Loading @@ -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, Loading
tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java +323 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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)); Loading @@ -424,7 +731,6 @@ public class CrashRecoveryTest { watchdog.registerHealthObserver(rollbackObserver); return rollbackObserver; } RescuePartyObserver setUpRescuePartyObserver(PackageWatchdog watchdog) { setCrashRecoveryPropRescueBootCount(0); RescuePartyObserver rescuePartyObserver = spy(RescuePartyObserver.getInstance(mSpyContext)); Loading Loading @@ -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); } } }