Loading services/core/java/com/android/server/RescueParty.java +10 −0 Original line number Original line Diff line number Diff line Loading @@ -38,9 +38,11 @@ import android.util.StatsLog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils; import com.android.server.am.SettingsToPropertiesMapper; import com.android.server.utils.FlagNamespaceUtils; import com.android.server.utils.FlagNamespaceUtils; import java.io.File; import java.io.File; import java.util.Arrays; /** /** * Utilities to help rescue the system from crash loops. Callers are expected to * Utilities to help rescue the system from crash loops. Callers are expected to Loading Loading @@ -158,6 +160,7 @@ public class RescueParty { * opportunity to reset any settings depending on our rescue level. * opportunity to reset any settings depending on our rescue level. */ */ public static void onSettingsProviderPublished(Context context) { public static void onSettingsProviderPublished(Context context) { handleNativeRescuePartyResets(); executeRescueLevel(context); executeRescueLevel(context); } } Loading @@ -176,6 +179,13 @@ public class RescueParty { return SystemClock.elapsedRealtime(); return SystemClock.elapsedRealtime(); } } private static void handleNativeRescuePartyResets() { if (SettingsToPropertiesMapper.isNativeFlagsResetPerformed()) { FlagNamespaceUtils.resetDeviceConfig(Settings.RESET_MODE_TRUSTED_DEFAULTS, Arrays.asList(SettingsToPropertiesMapper.getResetNativeCategories())); } } /** /** * Escalate to the next rescue level. After incrementing the level you'll * Escalate to the next rescue level. After incrementing the level you'll * probably want to call {@link #executeRescueLevel(Context)}. * probably want to call {@link #executeRescueLevel(Context)}. Loading services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.am; package com.android.server.am; import android.annotation.NonNull; import android.content.ContentResolver; import android.content.ContentResolver; import android.database.ContentObserver; import android.database.ContentObserver; import android.net.Uri; import android.net.Uri; Loading Loading @@ -167,7 +168,7 @@ public class SettingsToPropertiesMapper { * booting. * booting. * @return * @return */ */ public static String[] getResetNativeCategories() { public static @NonNull String[] getResetNativeCategories() { if (!isNativeFlagsResetPerformed()) { if (!isNativeFlagsResetPerformed()) { return new String[0]; return new String[0]; } } Loading services/core/java/com/android/server/utils/FlagNamespaceUtils.java +24 −6 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.utils; import android.annotation.Nullable; import android.annotation.Nullable; import android.provider.DeviceConfig; import android.provider.DeviceConfig; import com.android.internal.annotations.VisibleForTesting; import com.android.server.RescueParty; import com.android.server.RescueParty; import java.util.ArrayList; import java.util.ArrayList; Loading @@ -41,20 +42,23 @@ public final class FlagNamespaceUtils { /** /** * Name of the special namespace in DeviceConfig table used for communicating resets. * Name of the special namespace in DeviceConfig table used for communicating resets. */ */ private static final String NAMESPACE_RESCUE_PARTY = "rescue_party_namespace"; @VisibleForTesting public static final String NAMESPACE_RESCUE_PARTY = "rescue_party_namespace"; /** /** * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY}, holding all known {@link * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY}, holding all known {@link * DeviceConfig} namespaces, as a {@link #DELIMITER} separated String. It's updated after the * DeviceConfig} namespaces, as a {@link #DELIMITER} separated String. It's updated after the * first time flags are written to the new namespace in the {@link DeviceConfig}. * first time flags are written to the new namespace in the {@link DeviceConfig}. */ */ private static final String ALL_KNOWN_NAMESPACES_FLAG = "all_known_namespaces"; @VisibleForTesting public static final String ALL_KNOWN_NAMESPACES_FLAG = "all_known_namespaces"; /** /** * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY} with integer counter * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY} with integer counter * suffix added to it, holding {@link DeviceConfig} namespace value whose flags were recently * suffix added to it, holding {@link DeviceConfig} namespace value whose flags were recently * reset by the {@link RescueParty}. It's updated by {@link RescueParty} every time given * reset by the {@link RescueParty}. It's updated by {@link RescueParty} every time given * namespace flags are reset. * namespace flags are reset. */ */ private static final String RESET_PLATFORM_PACKAGE_FLAG = "reset_platform_package"; @VisibleForTesting public static final String RESET_PLATFORM_PACKAGE_FLAG = "reset_platform_package"; private static final String DELIMITER = ":"; private static final String DELIMITER = ":"; /** /** * Maximum value of the counter used in combination with {@link #RESET_PLATFORM_PACKAGE_FLAG} * Maximum value of the counter used in combination with {@link #RESET_PLATFORM_PACKAGE_FLAG} Loading Loading @@ -97,11 +101,25 @@ public final class FlagNamespaceUtils { * Reset all namespaces in DeviceConfig with consumed resetMode. * Reset all namespaces in DeviceConfig with consumed resetMode. */ */ public static void resetDeviceConfig(int resetMode) { public static void resetDeviceConfig(int resetMode) { List<String> allKnownNamespaces = getAllKnownDeviceConfigNamespacesList(); resetDeviceConfig(resetMode, getAllKnownDeviceConfigNamespacesList()); for (String namespace : allKnownNamespaces) { } /** * Reset all consumed namespaces in DeviceConfig with consumed resetMode. */ public static void resetDeviceConfig(int resetMode, List<String> namespacesList) { for (String namespace : namespacesList) { DeviceConfig.resetToDefaults(resetMode, namespace); DeviceConfig.resetToDefaults(resetMode, namespace); } } addToKnownResetNamespaces(allKnownNamespaces); addToKnownResetNamespaces(namespacesList); } /** * Resets known reset namespaces flag counter for tests only. */ @VisibleForTesting public static void resetKnownResetNamespacesFlagCounterForTest() { sKnownResetNamespacesFlagCounter = -1; } } /** /** Loading services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java +42 −2 Original line number Original line Diff line number Diff line Loading @@ -35,9 +35,12 @@ import android.content.Context; import android.os.RecoverySystem; import android.os.RecoverySystem; import android.os.SystemProperties; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserHandle; import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings; import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.server.am.SettingsToPropertiesMapper; import com.android.server.utils.FlagNamespaceUtils; import org.junit.After; import org.junit.After; import org.junit.Before; import org.junit.Before; Loading @@ -56,6 +59,10 @@ import java.util.HashMap; public class RescuePartyTest { public class RescuePartyTest { private static final int PERSISTENT_APP_UID = 12; private static final int PERSISTENT_APP_UID = 12; private static final long CURRENT_NETWORK_TIME_MILLIS = 0L; private static final long CURRENT_NETWORK_TIME_MILLIS = 0L; private static final String FAKE_NATIVE_NAMESPACE1 = "native1"; private static final String FAKE_NATIVE_NAMESPACE2 = "native2"; private static final String[] FAKE_RESET_NATIVE_NAMESPACES = {FAKE_NATIVE_NAMESPACE1, FAKE_NATIVE_NAMESPACE2}; private MockitoSession mSession; private MockitoSession mSession; Loading @@ -73,9 +80,11 @@ public class RescuePartyTest { ExtendedMockito.mockitoSession().initMocks( ExtendedMockito.mockitoSession().initMocks( this) this) .strictness(Strictness.LENIENT) .strictness(Strictness.LENIENT) .spyStatic(DeviceConfig.class) .spyStatic(SystemProperties.class) .spyStatic(SystemProperties.class) .spyStatic(Settings.Global.class) .spyStatic(Settings.Global.class) .spyStatic(Settings.Secure.class) .spyStatic(Settings.Secure.class) .spyStatic(SettingsToPropertiesMapper.class) .spyStatic(RecoverySystem.class) .spyStatic(RecoverySystem.class) .spyStatic(RescueParty.class) .spyStatic(RescueParty.class) .startMocking(); .startMocking(); Loading Loading @@ -121,8 +130,17 @@ public class RescuePartyTest { } } ).when(() -> SystemProperties.getLong(anyString(), anyLong())); ).when(() -> SystemProperties.getLong(anyString(), anyLong())); // Mock DeviceConfig doAnswer((Answer<Boolean>) invocationOnMock -> true) .when(() -> DeviceConfig.setProperty(anyString(), anyString(), anyString(), anyBoolean())); doAnswer((Answer<Void>) invocationOnMock -> null) .when(() -> DeviceConfig.resetToDefaults(anyInt(), anyString())); doReturn(CURRENT_NETWORK_TIME_MILLIS).when(() -> RescueParty.getElapsedRealtime()); doReturn(CURRENT_NETWORK_TIME_MILLIS).when(() -> RescueParty.getElapsedRealtime()); RescueParty.resetAllThresholds(); RescueParty.resetAllThresholds(); FlagNamespaceUtils.resetKnownResetNamespacesFlagCounterForTest(); SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(RescueParty.LEVEL_NONE)); Integer.toString(RescueParty.LEVEL_NONE)); Loading Loading @@ -278,10 +296,32 @@ public class RescuePartyTest { SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE)); SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE)); } } @Test public void testNativeRescuePartyResets() { doReturn(true).when(() -> SettingsToPropertiesMapper.isNativeFlagsResetPerformed()); doReturn(FAKE_RESET_NATIVE_NAMESPACES).when( () -> SettingsToPropertiesMapper.getResetNativeCategories()); RescueParty.onSettingsProviderPublished(mMockContext); verify(() -> DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS, FAKE_NATIVE_NAMESPACE1)); verify(() -> DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS, FAKE_NATIVE_NAMESPACE2)); ExtendedMockito.verify( () -> DeviceConfig.setProperty(FlagNamespaceUtils.NAMESPACE_RESCUE_PARTY, FlagNamespaceUtils.RESET_PLATFORM_PACKAGE_FLAG + 0, FAKE_NATIVE_NAMESPACE1, /*makeDefault=*/true)); ExtendedMockito.verify( () -> DeviceConfig.setProperty(FlagNamespaceUtils.NAMESPACE_RESCUE_PARTY, FlagNamespaceUtils.RESET_PLATFORM_PACKAGE_FLAG + 1, FAKE_NATIVE_NAMESPACE2, /*makeDefault=*/true)); } private void verifySettingsResets(int resetMode) { private void verifySettingsResets(int resetMode) { verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null, verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null, resetMode, resetMode, UserHandle.USER_SYSTEM)); UserHandle.USER_SYSTEM)); verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(), verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(), eq(resetMode), anyInt())); eq(resetMode), anyInt())); } } Loading Loading
services/core/java/com/android/server/RescueParty.java +10 −0 Original line number Original line Diff line number Diff line Loading @@ -38,9 +38,11 @@ import android.util.StatsLog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils; import com.android.server.am.SettingsToPropertiesMapper; import com.android.server.utils.FlagNamespaceUtils; import com.android.server.utils.FlagNamespaceUtils; import java.io.File; import java.io.File; import java.util.Arrays; /** /** * Utilities to help rescue the system from crash loops. Callers are expected to * Utilities to help rescue the system from crash loops. Callers are expected to Loading Loading @@ -158,6 +160,7 @@ public class RescueParty { * opportunity to reset any settings depending on our rescue level. * opportunity to reset any settings depending on our rescue level. */ */ public static void onSettingsProviderPublished(Context context) { public static void onSettingsProviderPublished(Context context) { handleNativeRescuePartyResets(); executeRescueLevel(context); executeRescueLevel(context); } } Loading @@ -176,6 +179,13 @@ public class RescueParty { return SystemClock.elapsedRealtime(); return SystemClock.elapsedRealtime(); } } private static void handleNativeRescuePartyResets() { if (SettingsToPropertiesMapper.isNativeFlagsResetPerformed()) { FlagNamespaceUtils.resetDeviceConfig(Settings.RESET_MODE_TRUSTED_DEFAULTS, Arrays.asList(SettingsToPropertiesMapper.getResetNativeCategories())); } } /** /** * Escalate to the next rescue level. After incrementing the level you'll * Escalate to the next rescue level. After incrementing the level you'll * probably want to call {@link #executeRescueLevel(Context)}. * probably want to call {@link #executeRescueLevel(Context)}. Loading
services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.am; package com.android.server.am; import android.annotation.NonNull; import android.content.ContentResolver; import android.content.ContentResolver; import android.database.ContentObserver; import android.database.ContentObserver; import android.net.Uri; import android.net.Uri; Loading Loading @@ -167,7 +168,7 @@ public class SettingsToPropertiesMapper { * booting. * booting. * @return * @return */ */ public static String[] getResetNativeCategories() { public static @NonNull String[] getResetNativeCategories() { if (!isNativeFlagsResetPerformed()) { if (!isNativeFlagsResetPerformed()) { return new String[0]; return new String[0]; } } Loading
services/core/java/com/android/server/utils/FlagNamespaceUtils.java +24 −6 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.utils; import android.annotation.Nullable; import android.annotation.Nullable; import android.provider.DeviceConfig; import android.provider.DeviceConfig; import com.android.internal.annotations.VisibleForTesting; import com.android.server.RescueParty; import com.android.server.RescueParty; import java.util.ArrayList; import java.util.ArrayList; Loading @@ -41,20 +42,23 @@ public final class FlagNamespaceUtils { /** /** * Name of the special namespace in DeviceConfig table used for communicating resets. * Name of the special namespace in DeviceConfig table used for communicating resets. */ */ private static final String NAMESPACE_RESCUE_PARTY = "rescue_party_namespace"; @VisibleForTesting public static final String NAMESPACE_RESCUE_PARTY = "rescue_party_namespace"; /** /** * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY}, holding all known {@link * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY}, holding all known {@link * DeviceConfig} namespaces, as a {@link #DELIMITER} separated String. It's updated after the * DeviceConfig} namespaces, as a {@link #DELIMITER} separated String. It's updated after the * first time flags are written to the new namespace in the {@link DeviceConfig}. * first time flags are written to the new namespace in the {@link DeviceConfig}. */ */ private static final String ALL_KNOWN_NAMESPACES_FLAG = "all_known_namespaces"; @VisibleForTesting public static final String ALL_KNOWN_NAMESPACES_FLAG = "all_known_namespaces"; /** /** * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY} with integer counter * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY} with integer counter * suffix added to it, holding {@link DeviceConfig} namespace value whose flags were recently * suffix added to it, holding {@link DeviceConfig} namespace value whose flags were recently * reset by the {@link RescueParty}. It's updated by {@link RescueParty} every time given * reset by the {@link RescueParty}. It's updated by {@link RescueParty} every time given * namespace flags are reset. * namespace flags are reset. */ */ private static final String RESET_PLATFORM_PACKAGE_FLAG = "reset_platform_package"; @VisibleForTesting public static final String RESET_PLATFORM_PACKAGE_FLAG = "reset_platform_package"; private static final String DELIMITER = ":"; private static final String DELIMITER = ":"; /** /** * Maximum value of the counter used in combination with {@link #RESET_PLATFORM_PACKAGE_FLAG} * Maximum value of the counter used in combination with {@link #RESET_PLATFORM_PACKAGE_FLAG} Loading Loading @@ -97,11 +101,25 @@ public final class FlagNamespaceUtils { * Reset all namespaces in DeviceConfig with consumed resetMode. * Reset all namespaces in DeviceConfig with consumed resetMode. */ */ public static void resetDeviceConfig(int resetMode) { public static void resetDeviceConfig(int resetMode) { List<String> allKnownNamespaces = getAllKnownDeviceConfigNamespacesList(); resetDeviceConfig(resetMode, getAllKnownDeviceConfigNamespacesList()); for (String namespace : allKnownNamespaces) { } /** * Reset all consumed namespaces in DeviceConfig with consumed resetMode. */ public static void resetDeviceConfig(int resetMode, List<String> namespacesList) { for (String namespace : namespacesList) { DeviceConfig.resetToDefaults(resetMode, namespace); DeviceConfig.resetToDefaults(resetMode, namespace); } } addToKnownResetNamespaces(allKnownNamespaces); addToKnownResetNamespaces(namespacesList); } /** * Resets known reset namespaces flag counter for tests only. */ @VisibleForTesting public static void resetKnownResetNamespacesFlagCounterForTest() { sKnownResetNamespacesFlagCounter = -1; } } /** /** Loading
services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java +42 −2 Original line number Original line Diff line number Diff line Loading @@ -35,9 +35,12 @@ import android.content.Context; import android.os.RecoverySystem; import android.os.RecoverySystem; import android.os.SystemProperties; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserHandle; import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings; import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.server.am.SettingsToPropertiesMapper; import com.android.server.utils.FlagNamespaceUtils; import org.junit.After; import org.junit.After; import org.junit.Before; import org.junit.Before; Loading @@ -56,6 +59,10 @@ import java.util.HashMap; public class RescuePartyTest { public class RescuePartyTest { private static final int PERSISTENT_APP_UID = 12; private static final int PERSISTENT_APP_UID = 12; private static final long CURRENT_NETWORK_TIME_MILLIS = 0L; private static final long CURRENT_NETWORK_TIME_MILLIS = 0L; private static final String FAKE_NATIVE_NAMESPACE1 = "native1"; private static final String FAKE_NATIVE_NAMESPACE2 = "native2"; private static final String[] FAKE_RESET_NATIVE_NAMESPACES = {FAKE_NATIVE_NAMESPACE1, FAKE_NATIVE_NAMESPACE2}; private MockitoSession mSession; private MockitoSession mSession; Loading @@ -73,9 +80,11 @@ public class RescuePartyTest { ExtendedMockito.mockitoSession().initMocks( ExtendedMockito.mockitoSession().initMocks( this) this) .strictness(Strictness.LENIENT) .strictness(Strictness.LENIENT) .spyStatic(DeviceConfig.class) .spyStatic(SystemProperties.class) .spyStatic(SystemProperties.class) .spyStatic(Settings.Global.class) .spyStatic(Settings.Global.class) .spyStatic(Settings.Secure.class) .spyStatic(Settings.Secure.class) .spyStatic(SettingsToPropertiesMapper.class) .spyStatic(RecoverySystem.class) .spyStatic(RecoverySystem.class) .spyStatic(RescueParty.class) .spyStatic(RescueParty.class) .startMocking(); .startMocking(); Loading Loading @@ -121,8 +130,17 @@ public class RescuePartyTest { } } ).when(() -> SystemProperties.getLong(anyString(), anyLong())); ).when(() -> SystemProperties.getLong(anyString(), anyLong())); // Mock DeviceConfig doAnswer((Answer<Boolean>) invocationOnMock -> true) .when(() -> DeviceConfig.setProperty(anyString(), anyString(), anyString(), anyBoolean())); doAnswer((Answer<Void>) invocationOnMock -> null) .when(() -> DeviceConfig.resetToDefaults(anyInt(), anyString())); doReturn(CURRENT_NETWORK_TIME_MILLIS).when(() -> RescueParty.getElapsedRealtime()); doReturn(CURRENT_NETWORK_TIME_MILLIS).when(() -> RescueParty.getElapsedRealtime()); RescueParty.resetAllThresholds(); RescueParty.resetAllThresholds(); FlagNamespaceUtils.resetKnownResetNamespacesFlagCounterForTest(); SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(RescueParty.LEVEL_NONE)); Integer.toString(RescueParty.LEVEL_NONE)); Loading Loading @@ -278,10 +296,32 @@ public class RescuePartyTest { SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE)); SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE)); } } @Test public void testNativeRescuePartyResets() { doReturn(true).when(() -> SettingsToPropertiesMapper.isNativeFlagsResetPerformed()); doReturn(FAKE_RESET_NATIVE_NAMESPACES).when( () -> SettingsToPropertiesMapper.getResetNativeCategories()); RescueParty.onSettingsProviderPublished(mMockContext); verify(() -> DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS, FAKE_NATIVE_NAMESPACE1)); verify(() -> DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS, FAKE_NATIVE_NAMESPACE2)); ExtendedMockito.verify( () -> DeviceConfig.setProperty(FlagNamespaceUtils.NAMESPACE_RESCUE_PARTY, FlagNamespaceUtils.RESET_PLATFORM_PACKAGE_FLAG + 0, FAKE_NATIVE_NAMESPACE1, /*makeDefault=*/true)); ExtendedMockito.verify( () -> DeviceConfig.setProperty(FlagNamespaceUtils.NAMESPACE_RESCUE_PARTY, FlagNamespaceUtils.RESET_PLATFORM_PACKAGE_FLAG + 1, FAKE_NATIVE_NAMESPACE2, /*makeDefault=*/true)); } private void verifySettingsResets(int resetMode) { private void verifySettingsResets(int resetMode) { verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null, verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null, resetMode, resetMode, UserHandle.USER_SYSTEM)); UserHandle.USER_SYSTEM)); verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(), verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(), eq(resetMode), anyInt())); eq(resetMode), anyInt())); } } Loading