diff options
| author | 2024-07-23 18:37:24 +0000 | |
|---|---|---|
| committer | 2024-07-23 18:37:24 +0000 | |
| commit | 243f2905362c1f1a35e2db941e5921f2bc995893 (patch) | |
| tree | 3b303edbdbd303159fd7a1d1f022023d9b34a275 | |
| parent | e57a2b55c70c9720604b8bd8cbfb4611ed6cfccd (diff) | |
| parent | debe12db8d660925cbe8464818e65c8e01e66c3a (diff) | |
Merge "SystemUI as an exception to user impact level limit" into main am: debe12db8d
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/3162537
Change-Id: Iad04f94e40a3f6ef20e01e0dab1d501bc05a55c5
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
| -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); + } + } } |