From 3aecf323e3e9f253b5a5482c2b79c613ce8c9fcf Mon Sep 17 00:00:00 2001 From: Hongyi Zhang Date: Sun, 1 Mar 2020 18:46:51 -0800 Subject: [PATCH] RescueParty: Add a DeviceConfig killswitch 1. Add a killswitch DeviceConfig flag in case emergency rollback is needed (e.g. PackageWatchdog doesn't behave correctly). 2. Register the namespace for native flag sync mapper so that we can also use the flag to turn off native disaster recovery. Test: Atest RescueParty & verified on local device Bug: 149420506 Change-Id: I9a0b546c7229c8444947b522585dd2c5ed37a00b (cherry picked from commit 1c0993cf12d34e7611db258982c1854960985545) --- core/java/android/provider/DeviceConfig.java | 7 ++++++ .../java/com/android/server/RescueParty.java | 10 ++++++++ .../server/am/SettingsToPropertiesMapper.java | 1 + .../com/android/server/RescuePartyTest.java | 24 +++++++++++++++++++ 4 files changed, 42 insertions(+) diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index aa511cc46de98..fb81d675939cf 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -399,6 +399,13 @@ public final class DeviceConfig { public static final String NAMESPACE_CONNECTIVITY_THERMAL_POWER_MANAGER = "connectivity_thermal_power_manager"; + /** + * Namespace for configuration related features. + * + * @hide + */ + public static final String NAMESPACE_CONFIGURATION = "configuration"; + private static final Object sLock = new Object(); @GuardedBy("sLock") private static ArrayMap> sListeners = diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java index 80036bb4b4fa5..808d322020cb1 100644 --- a/services/core/java/com/android/server/RescueParty.java +++ b/services/core/java/com/android/server/RescueParty.java @@ -99,6 +99,8 @@ public class RescueParty { private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue"; private static final String PROP_VIRTUAL_DEVICE = "ro.hardware.virtual_device"; + private static final String DEVICE_CONFIG_DISABLE_FLAG = "disable_rescue_party"; + private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT | ApplicationInfo.FLAG_SYSTEM; @@ -114,6 +116,14 @@ public class RescueParty { return false; } + // We're disabled if the DeviceConfig disable flag is set to true. + // This is in case that an emergency rollback of the feature is needed. + if (DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_CONFIGURATION, DEVICE_CONFIG_DISABLE_FLAG, false)) { + Slog.v(TAG, "Disabled because of DeviceConfig flag"); + return true; + } + // We're disabled on all engineering devices if (Build.IS_ENG) { Slog.v(TAG, "Disabled because of eng build"); diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 0a8e70c7d772f..bac7565adfa57 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -80,6 +80,7 @@ public class SettingsToPropertiesMapper { @VisibleForTesting static final String[] sDeviceConfigScopes = new String[] { DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, + DeviceConfig.NAMESPACE_CONFIGURATION, DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT, DeviceConfig.NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS, DeviceConfig.NAMESPACE_MEDIA_NATIVE, diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java index c94bb879f4601..5c8220049d09d 100644 --- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java @@ -79,6 +79,7 @@ public class RescuePartyTest { private static final String CALLING_PACKAGE2 = "com.package.name2"; private static final String NAMESPACE1 = "namespace1"; private static final String NAMESPACE2 = "namespace2"; + private static final String DISABLE_RESCUE_PARTY_FLAG = "disable_rescue_party"; private MockitoSession mSession; private HashMap mSystemSettingsMap; @@ -316,6 +317,13 @@ public class RescuePartyTest { @Test public void testExplicitlyEnablingAndDisablingRescue() { + // mock the DeviceConfig get call to avoid hitting + // android.permission.READ_DEVICE_CONFIG when calling real DeviceConfig. + doReturn(true) + .when(() -> DeviceConfig.getBoolean( + eq(DeviceConfig.NAMESPACE_CONFIGURATION), + eq(DISABLE_RESCUE_PARTY_FLAG), + eq(false))); SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false)); SystemProperties.set(PROP_DISABLE_RESCUE, Boolean.toString(true)); assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage, @@ -326,6 +334,22 @@ public class RescuePartyTest { PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)); } + @Test + public void testDisablingRescueByDeviceConfigFlag() { + doReturn(true) + .when(() -> DeviceConfig.getBoolean( + eq(DeviceConfig.NAMESPACE_CONFIGURATION), + eq(DISABLE_RESCUE_PARTY_FLAG), + eq(false))); + SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false)); + + assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage, + PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING), false); + + // Restore the property value initalized in SetUp() + SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true)); + } + @Test public void testHealthCheckLevels() { RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);