summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Hongyi Zhang <hongyiz@google.com> 2020-11-11 06:04:40 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-11-11 06:04:40 +0000
commit335397f1f13a5e9cb0f58166406e24612f4ba00b (patch)
tree008fd9b7f8dba145c592db31ad4d1a8df76ef094
parent05fca8173d9b90169094c9a707a501365b6d6fb9 (diff)
parentc8f1e2b38c176613d9d2388cb52d9c0b10fc4abd (diff)
Merge "Constrain Non-DeviceConfig settings reset times & unify DeviceConfig reset mode"
-rw-r--r--services/core/java/com/android/server/RescueParty.java92
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java107
2 files changed, 161 insertions, 38 deletions
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index 6206f7a583d1..d04949ac54db 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -78,6 +78,7 @@ public class RescueParty {
@VisibleForTesting
static final String PROP_RESCUE_LEVEL = "sys.rescue_level";
static final String PROP_ATTEMPTING_FACTORY_RESET = "sys.attempting_factory_reset";
+ static final String PROP_MAX_RESCUE_LEVEL_ATTEMPTED = "sys.max_rescue_level_attempted";
@VisibleForTesting
static final int LEVEL_NONE = 0;
@VisibleForTesting
@@ -94,6 +95,8 @@ public class RescueParty {
static final String TAG = "RescueParty";
@VisibleForTesting
static final long DEFAULT_OBSERVING_DURATION_MS = TimeUnit.DAYS.toMillis(2);
+ @VisibleForTesting
+ static final int DEVICE_CONFIG_RESET_MODE = Settings.RESET_MODE_TRUSTED_DEFAULTS;
private static final String NAME = "rescue-party-observer";
@@ -225,7 +228,7 @@ public class RescueParty {
if (NAMESPACE_CONFIGURATION.equals(resetNativeCategories[i])) {
continue;
}
- DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS,
+ DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE,
resetNativeCategories[i]);
}
}
@@ -300,15 +303,48 @@ public class RescueParty {
private static void executeRescueLevelInternal(Context context, int level, @Nullable
String failedPackage) throws Exception {
FrameworkStatsLog.write(FrameworkStatsLog.RESCUE_PARTY_RESET_REPORTED, level);
+ // Try our best to reset all settings possible, and once finished
+ // rethrow any exception that we encountered
+ Exception res = null;
switch (level) {
case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
- resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS, failedPackage);
+ try {
+ resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS,
+ level);
+ } catch (Exception e) {
+ res = e;
+ }
+ try {
+ resetDeviceConfig(context, /*isScoped=*/true, failedPackage);
+ } catch (Exception e) {
+ res = e;
+ }
break;
case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
- resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_CHANGES, failedPackage);
+ try {
+ resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_CHANGES,
+ level);
+ } catch (Exception e) {
+ res = e;
+ }
+ try {
+ resetDeviceConfig(context, /*isScoped=*/true, failedPackage);
+ } catch (Exception e) {
+ res = e;
+ }
break;
case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
- resetAllSettings(context, Settings.RESET_MODE_TRUSTED_DEFAULTS, failedPackage);
+ try {
+ resetAllSettingsIfNecessary(context, Settings.RESET_MODE_TRUSTED_DEFAULTS,
+ level);
+ } catch (Exception e) {
+ res = e;
+ }
+ try {
+ resetDeviceConfig(context, /*isScoped=*/false, failedPackage);
+ } catch (Exception e) {
+ res = e;
+ }
break;
case LEVEL_FACTORY_RESET:
// Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
@@ -328,6 +364,10 @@ public class RescueParty {
thread.start();
break;
}
+
+ if (res != null) {
+ throw res;
+ }
}
private static void logRescueException(int level, Throwable t) {
@@ -350,18 +390,18 @@ public class RescueParty {
}
}
- private static void resetAllSettings(Context context, int mode, @Nullable String failedPackage)
- throws Exception {
+ private static void resetAllSettingsIfNecessary(Context context, int mode,
+ int level) throws Exception {
+ // No need to reset Settings again if they are already reset in the current level once.
+ if (SystemProperties.getInt(PROP_MAX_RESCUE_LEVEL_ATTEMPTED, LEVEL_NONE) >= level) {
+ return;
+ }
+ SystemProperties.set(PROP_MAX_RESCUE_LEVEL_ATTEMPTED, Integer.toString(level));
// Try our best to reset all settings possible, and once finished
// rethrow any exception that we encountered
Exception res = null;
final ContentResolver resolver = context.getContentResolver();
try {
- resetDeviceConfig(context, mode, failedPackage);
- } catch (Exception e) {
- res = new RuntimeException("Failed to reset config settings", e);
- }
- try {
Settings.Global.resetToDefaultsAsUser(resolver, null, mode, UserHandle.USER_SYSTEM);
} catch (Exception e) {
res = new RuntimeException("Failed to reset global settings", e);
@@ -378,16 +418,21 @@ public class RescueParty {
}
}
- private static void resetDeviceConfig(Context context, int resetMode,
- @Nullable String failedPackage) {
- if (!shouldPerformScopedResets(resetMode) || failedPackage == null) {
- resetAllAffectedNamespaces(context, resetMode);
- } else {
- performScopedReset(context, resetMode, failedPackage);
+ private static void resetDeviceConfig(Context context, boolean isScoped,
+ @Nullable String failedPackage) throws Exception {
+ final ContentResolver resolver = context.getContentResolver();
+ try {
+ if (!isScoped || failedPackage == null) {
+ resetAllAffectedNamespaces(context);
+ } else {
+ performScopedReset(context, failedPackage);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to reset config settings", e);
}
}
- private static void resetAllAffectedNamespaces(Context context, int resetMode) {
+ private static void resetAllAffectedNamespaces(Context context) {
RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
Set<String> allAffectedNamespaces = rescuePartyObserver.getAllAffectedNamespaceSet();
@@ -401,16 +446,11 @@ public class RescueParty {
if (NAMESPACE_CONFIGURATION.equals(namespace)) {
continue;
}
- DeviceConfig.resetToDefaults(resetMode, namespace);
+ DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE, namespace);
}
}
- private static boolean shouldPerformScopedResets(int resetMode) {
- return resetMode <= Settings.RESET_MODE_UNTRUSTED_CHANGES;
- }
-
- private static void performScopedReset(Context context, int resetMode,
- @NonNull String failedPackage) {
+ private static void performScopedReset(Context context, @NonNull String failedPackage) {
RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
Set<String> affectedNamespaces = rescuePartyObserver.getAffectedNamespaceSet(
failedPackage);
@@ -428,7 +468,7 @@ public class RescueParty {
if (NAMESPACE_CONFIGURATION.equals(namespace)) {
continue;
}
- DeviceConfig.resetToDefaults(resetMode, namespace);
+ DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE, namespace);
}
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index da4071b6b9de..ebd4a4c5378f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -191,10 +191,12 @@ public class RescuePartyTest {
RescueParty.onSettingsProviderPublished(mMockContext);
verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
mMonitorCallbackCaptor.capture()));
+ HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
noteBoot();
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
+ verifiedTimesMap);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
@@ -208,13 +210,15 @@ public class RescuePartyTest {
noteBoot();
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, expectedAllResetNamespaces);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, expectedAllResetNamespaces,
+ verifiedTimesMap);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
noteBoot();
- verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces);
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces,
+ verifiedTimesMap);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
@@ -228,15 +232,18 @@ public class RescuePartyTest {
public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevels() {
notePersistentAppCrash(1);
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
+ /*configResetVerifiedTimesMap=*/ null);
notePersistentAppCrash(2);
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null,
+ /*configResetVerifiedTimesMap=*/ null);
notePersistentAppCrash(3);
- verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
+ /*configResetVerifiedTimesMap=*/ null);
notePersistentAppCrash(4);
assertTrue(RescueParty.isAttemptingFactoryReset());
@@ -272,17 +279,82 @@ public class RescuePartyTest {
final String[] expectedResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
final String[] expectedAllResetNamespaces =
new String[]{NAMESPACE1, NAMESPACE2, NAMESPACE3};
+ HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
observer.execute(new VersionedPackage(
CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, expectedResetNamespaces);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, expectedResetNamespaces,
+ verifiedTimesMap);
observer.execute(new VersionedPackage(
CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2);
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, expectedResetNamespaces);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, expectedResetNamespaces,
+ verifiedTimesMap);
observer.execute(new VersionedPackage(
CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3);
- verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces);
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces,
+ verifiedTimesMap);
+
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4);
+ assertTrue(RescueParty.isAttemptingFactoryReset());
+ }
+
+ @Test
+ public void testNonDeviceConfigSettingsOnlyResetOncePerLevel() {
+ RescueParty.onSettingsProviderPublished(mMockContext);
+ verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+ mMonitorCallbackCaptor.capture()));
+
+ // Record DeviceConfig accesses
+ RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+ RemoteCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE1));
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE2));
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE2));
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE3));
+ // Fake DeviceConfig value changes
+ monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE1));
+ monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE2));
+ monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE3));
+ // Perform and verify scoped resets
+ final String[] expectedPackage1ResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
+ final String[] expectedPackage2ResetNamespaces = new String[]{NAMESPACE2, NAMESPACE3};
+ final String[] expectedAllResetNamespaces =
+ new String[]{NAMESPACE1, NAMESPACE2, NAMESPACE3};
+ HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS,
+ expectedPackage1ResetNamespaces, verifiedTimesMap);
+
+ // Settings.Global & Settings.Secure should still remain the same execution times.
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE2, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS,
+ expectedPackage2ResetNamespaces, verifiedTimesMap);
+
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES,
+ expectedPackage1ResetNamespaces, verifiedTimesMap);
+
+ // Settings.Global & Settings.Secure should still remain the same execution times.
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE2, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES,
+ expectedPackage2ResetNamespaces, verifiedTimesMap);
+
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3);
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces,
+ verifiedTimesMap);
+
+ // Settings.Global & Settings.Secure should still remain the same execution times.
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE2, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3);
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces,
+ verifiedTimesMap);
observer.execute(new VersionedPackage(
CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4);
@@ -303,7 +375,8 @@ public class RescuePartyTest {
RescueParty.onSettingsProviderPublished(mMockContext);
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
+ /*configResetVerifiedTimesMap=*/ null);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
}
@@ -415,7 +488,8 @@ public class RescuePartyTest {
assertEquals(observer.onBootLoop(), PackageHealthObserverImpact.USER_IMPACT_HIGH);
}
- private void verifySettingsResets(int resetMode, String[] resetNamespaces) {
+ private void verifySettingsResets(int resetMode, String[] resetNamespaces,
+ HashMap<String, Integer> configResetVerifiedTimesMap) {
verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null,
resetMode, UserHandle.USER_SYSTEM));
verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(),
@@ -425,7 +499,16 @@ public class RescuePartyTest {
verify(() -> DeviceConfig.resetToDefaults(anyInt(), anyString()), never());
} else {
for (String namespace : resetNamespaces) {
- verify(() -> DeviceConfig.resetToDefaults(resetMode, namespace));
+ int verifiedTimes = 0;
+ if (configResetVerifiedTimesMap != null
+ && configResetVerifiedTimesMap.get(namespace) != null) {
+ verifiedTimes = configResetVerifiedTimesMap.get(namespace);
+ }
+ verify(() -> DeviceConfig.resetToDefaults(RescueParty.DEVICE_CONFIG_RESET_MODE,
+ namespace), times(verifiedTimes + 1));
+ if (configResetVerifiedTimesMap != null) {
+ configResetVerifiedTimesMap.put(namespace, verifiedTimes + 1);
+ }
}
}
}