diff options
| author | 2024-07-08 22:14:38 +0000 | |
|---|---|---|
| committer | 2024-07-23 13:09:46 +0000 | |
| commit | 7704c982c761734aa1479baf156483f9d59a08da (patch) | |
| tree | 238dec99687d0b788abe9cfa36ee3d132ab83898 | |
| parent | ac5399b70e0f9a6bb55693bd51b1708ea0696ec3 (diff) | |
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
| -rw-r--r-- | services/core/java/com/android/server/PackageWatchdog.java | 29 | ||||
| -rw-r--r-- | tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java | 324 |
2 files changed, 351 insertions, 2 deletions
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index eb037095c6c9..d9926a4a0f0d 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -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, diff --git a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java index 3722fefb12ad..c0e90f9232d6 100644 --- a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java +++ b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java @@ -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); + } + } } |