Expose set/clear monitor callback

Exposing set/clear monitor callback as part of moving rescue party calls to use device config apis instead
of depending on settings.config.

To follow API guildlines: add executor parameter, clear monitor
callback, pass monitorCallback interface instead of passing generic
remote callback function

Test: atest CtsProviderTestCases:android.provider.cts.settings.Settings_ConfigTest#testRegisterMonitorCallback, atest CtsDeviceConfigTestCases:android.deviceconfig.cts.DeviceConfigApiTests#testRegisterMonitorCallback
Bug: 261723248
Change-Id: I40e567a9eb6a4fe3e1d167b1ece909a859f6c2df
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 314fd03..5a8a86a 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -430,6 +430,7 @@
   }
 
   public static final class Settings.Config extends android.provider.Settings.NameValueTable {
+    method @RequiresPermission(android.Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS) public static void clearMonitorCallback(@NonNull android.content.ContentResolver);
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean deleteString(@NonNull String, @NonNull String);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getString(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static java.util.Map<java.lang.String,java.lang.String> getStrings(@NonNull String, @NonNull java.util.List<java.lang.String>);
@@ -437,6 +438,7 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean putString(@NonNull String, @NonNull String, @Nullable String, boolean);
     method public static void registerContentObserver(@Nullable String, boolean, @NonNull android.database.ContentObserver);
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String);
+    method @RequiresPermission(android.Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS) public static void setMonitorCallback(@NonNull android.content.ContentResolver, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.MonitorCallback);
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setStrings(@NonNull String, @NonNull java.util.Map<java.lang.String,java.lang.String>) throws android.provider.DeviceConfig.BadConfigException;
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void setSyncDisabledMode(int);
     method public static void unregisterContentObserver(@NonNull android.database.ContentObserver);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 46f51c7..9d96e63 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -212,6 +212,7 @@
     field public static final String MODIFY_PARENTAL_CONTROLS = "android.permission.MODIFY_PARENTAL_CONTROLS";
     field public static final String MODIFY_QUIET_MODE = "android.permission.MODIFY_QUIET_MODE";
     field public static final String MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE = "android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE";
+    field public static final String MONITOR_DEVICE_CONFIG_ACCESS = "android.permission.MONITOR_DEVICE_CONFIG_ACCESS";
     field public static final String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
     field public static final String NETWORK_AIRPLANE_MODE = "android.permission.NETWORK_AIRPLANE_MODE";
     field public static final String NETWORK_CARRIER_PROVISIONING = "android.permission.NETWORK_CARRIER_PROVISIONING";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d01c33d..efe8238 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -17,6 +17,7 @@
 package android.provider;
 
 import android.Manifest;
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -87,6 +88,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.MemoryIntArray;
+import android.util.Slog;
 import android.view.Display;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
@@ -112,6 +114,8 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.Executor;
+
 /**
  * The Settings provider contains global system-level device preferences.
  */
@@ -2719,6 +2723,10 @@
     public static final String CALL_METHOD_REGISTER_MONITOR_CALLBACK_CONFIG =
             "REGISTER_MONITOR_CALLBACK_config";
 
+    /** @hide - Private call() method to unregister monitor callback for 'configuration' table */
+    public static final String CALL_METHOD_UNREGISTER_MONITOR_CALLBACK_CONFIG =
+            "UNREGISTER_MONITOR_CALLBACK_config";
+
     /** @hide - String argument extra to the config monitor callback */
     public static final String EXTRA_MONITOR_CALLBACK_TYPE = "monitor_callback_type";
 
@@ -18370,16 +18378,41 @@
         }
 
         /**
-         * Register callback for monitoring Config table.
+         * Setter callback for monitoring Config table.
          *
-         * @param callback callback to register
+         * @param executor the {@link Executor} on which to invoke the callback
+         * @param callback callback to set
          *
          * @hide
          */
+        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
         @RequiresPermission(Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS)
-        public static void registerMonitorCallback(@NonNull ContentResolver resolver,
-                @NonNull RemoteCallback callback) {
-            registerMonitorCallbackAsUser(resolver, resolver.getUserId(), callback);
+        public static void setMonitorCallback(
+                @NonNull ContentResolver resolver,
+                @NonNull @CallbackExecutor Executor executor,
+                @NonNull DeviceConfig.MonitorCallback callback) {
+            setMonitorCallbackAsUser(executor, resolver, resolver.getUserId(), callback);
+        }
+
+        /**
+         * Clear callback for monitoring Config table.
+         * this may only be used to clear callback function registered by
+         * {@link Config#setMonitorCallback}
+         * @hide
+         */
+        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+        @RequiresPermission(Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS)
+        public static void clearMonitorCallback(@NonNull ContentResolver resolver) {
+            try {
+                Bundle arg = new Bundle();
+                arg.putInt(CALL_METHOD_USER_KEY, resolver.getUserId());
+                IContentProvider cp = sProviderHolder.getProvider(resolver);
+                cp.call(resolver.getAttributionSource(),
+                        sProviderHolder.mUri.getAuthority(),
+                        CALL_METHOD_UNREGISTER_MONITOR_CALLBACK_CONFIG, null, arg);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Can't clear config monitor callback", e);
+            }
         }
 
 
@@ -18446,19 +18479,23 @@
             }
         }
 
-        private static void registerMonitorCallbackAsUser(
+        private static void setMonitorCallbackAsUser(
+                @NonNull @CallbackExecutor Executor executor,
                 @NonNull ContentResolver resolver, @UserIdInt int userHandle,
-                @NonNull RemoteCallback callback) {
+                @NonNull DeviceConfig.MonitorCallback callback) {
             try {
                 Bundle arg = new Bundle();
                 arg.putInt(CALL_METHOD_USER_KEY, userHandle);
-                arg.putParcelable(CALL_METHOD_MONITOR_CALLBACK_KEY, callback);
+                arg.putParcelable(CALL_METHOD_MONITOR_CALLBACK_KEY,
+                        new RemoteCallback(result -> {
+                            handleMonitorCallback(result, executor, callback);
+                        }));
                 IContentProvider cp = sProviderHolder.getProvider(resolver);
                 cp.call(resolver.getAttributionSource(),
                         sProviderHolder.mUri.getAuthority(),
                         CALL_METHOD_REGISTER_MONITOR_CALLBACK_CONFIG, null, arg);
             } catch (RemoteException e) {
-                Log.w(TAG, "Can't register config monitor callback", e);
+                Log.w(TAG, "Can't set config monitor callback", e);
             }
         }
 
@@ -18468,6 +18505,32 @@
             sNameValueCache.clearGenerationTrackerForTest();
         }
 
+        private static void handleMonitorCallback(
+                Bundle result,
+                @NonNull @CallbackExecutor Executor executor,
+                DeviceConfig.MonitorCallback monitorCallback) {
+            String callbackType = result.getString(EXTRA_MONITOR_CALLBACK_TYPE, "");
+            switch (callbackType) {
+                case EXTRA_NAMESPACE_UPDATED_CALLBACK:
+                    String updatedNamespace = result.getString(EXTRA_NAMESPACE);
+                    if (updatedNamespace != null) {
+                        executor.execute(() -> monitorCallback.onNamespaceUpdate(updatedNamespace));
+                    }
+                    break;
+                case EXTRA_ACCESS_CALLBACK:
+                    String callingPackage = result.getString(EXTRA_CALLING_PACKAGE, null);
+                    String namespace = result.getString(EXTRA_NAMESPACE, null);
+                    if (namespace != null && callingPackage != null) {
+                        executor.execute(() ->
+                                monitorCallback.onDeviceConfigAccess(callingPackage, namespace));
+                    }
+                    break;
+                default:
+                    Slog.w(TAG, "Unrecognized DeviceConfig callback");
+                    break;
+            }
+        }
+
         private static String createCompositeName(@NonNull String namespace, @NonNull String name) {
             Preconditions.checkNotNull(namespace);
             Preconditions.checkNotNull(name);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 78a6a66..89d5c81 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3632,7 +3632,7 @@
     <permission android:name="android.permission.SET_APP_SPECIFIC_LOCALECONFIG"
         android:protectionLevel="signature" />
 
-    <!-- @hide Allows an application to monitor {@link android.provider.Settings.Config} access.
+    <!-- @SystemApi @hide Allows an application to monitor {@link android.provider.Settings.Config} access.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"
         android:protectionLevel="signature"/>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index ed8a457..ed1a0f3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -564,6 +564,11 @@
                 break;
             }
 
+            case Settings.CALL_METHOD_UNREGISTER_MONITOR_CALLBACK_CONFIG: {
+                clearMonitorCallback();
+                break;
+            }
+
             case Settings.CALL_METHOD_LIST_GLOBAL: {
                 Bundle result = new Bundle();
                 result.putStringArrayList(RESULT_SETTINGS_LIST,
@@ -2352,6 +2357,16 @@
         }
     }
 
+    private void clearMonitorCallback() {
+        getContext().enforceCallingOrSelfPermission(
+                Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS,
+                "Permission denial: registering for config access requires: "
+                        + Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS);
+        synchronized (mLock) {
+            mConfigMonitorCallback = null;
+        }
+    }
+
     private void reportDeviceConfigAccess(@Nullable String prefix) {
         if (prefix == null) {
             return;
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b8ac384..af4d7d4 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -145,6 +145,7 @@
     <uses-permission android:name="android.permission.LOCATION_BYPASS" />
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
+    <uses-permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS" />
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
     <uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY" />
     <!-- Development tool permissions granted to the shell. -->
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index b4ab254..d1e0f16 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -28,12 +28,10 @@
 import android.content.pm.PackageManager;
 import android.content.pm.VersionedPackage;
 import android.os.Build;
-import android.os.Bundle;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.PowerManager;
 import android.os.RecoverySystem;
-import android.os.RemoteCallback;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -63,6 +61,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -188,9 +187,10 @@
     public static void onSettingsProviderPublished(Context context) {
         handleNativeRescuePartyResets();
         ContentResolver contentResolver = context.getContentResolver();
-        Settings.Config.registerMonitorCallback(contentResolver, new RemoteCallback(result -> {
-            handleMonitorCallback(context, result);
-        }));
+        DeviceConfig.setMonitorCallback(
+                contentResolver,
+                Executors.newSingleThreadExecutor(),
+                new RescuePartyMonitorCallback(context));
     }
 
 
@@ -278,27 +278,22 @@
         return SystemClock.elapsedRealtime();
     }
 
-    private static void handleMonitorCallback(Context context, Bundle result) {
-        String callbackType = result.getString(Settings.EXTRA_MONITOR_CALLBACK_TYPE, "");
-        switch (callbackType) {
-            case Settings.EXTRA_NAMESPACE_UPDATED_CALLBACK:
-                String updatedNamespace = result.getString(Settings.EXTRA_NAMESPACE);
-                if (updatedNamespace != null) {
-                    startObservingPackages(context, updatedNamespace);
-                }
-                break;
-            case Settings.EXTRA_ACCESS_CALLBACK:
-                String callingPackage = result.getString(Settings.EXTRA_CALLING_PACKAGE, null);
-                String namespace = result.getString(Settings.EXTRA_NAMESPACE, null);
-                if (namespace != null && callingPackage != null) {
-                    RescuePartyObserver.getInstance(context).recordDeviceConfigAccess(
+    private static class RescuePartyMonitorCallback implements DeviceConfig.MonitorCallback {
+        Context mContext;
+
+        RescuePartyMonitorCallback(Context context) {
+            this.mContext = context;
+        }
+
+        public void onNamespaceUpdate(@NonNull String updatedNamespace) {
+            startObservingPackages(mContext, updatedNamespace);
+        }
+
+        public void onDeviceConfigAccess(@NonNull String callingPackage,
+                @NonNull String namespace) {
+            RescuePartyObserver.getInstance(mContext).recordDeviceConfigAccess(
                             callingPackage,
                             namespace);
-                }
-                break;
-            default:
-                Slog.w(TAG, "Unrecognized DeviceConfig callback");
-                break;
         }
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index e7c384b..83441bf 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -40,9 +40,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.VersionedPackage;
-import android.os.Bundle;
 import android.os.RecoverySystem;
-import android.os.RemoteCallback;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
@@ -69,6 +67,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
  * Test RescueParty.
@@ -111,7 +110,7 @@
     private PackageManager mPackageManager;
 
     @Captor
-    private ArgumentCaptor<RemoteCallback> mMonitorCallbackCaptor;
+    private ArgumentCaptor<DeviceConfig.MonitorCallback> mMonitorCallbackCaptor;
     @Captor
     private ArgumentCaptor<List<String>> mPackageListCaptor;
 
@@ -125,7 +124,6 @@
                         .spyStatic(SystemProperties.class)
                         .spyStatic(Settings.Global.class)
                         .spyStatic(Settings.Secure.class)
-                        .spyStatic(Settings.Config.class)
                         .spyStatic(SettingsToPropertiesMapper.class)
                         .spyStatic(RecoverySystem.class)
                         .spyStatic(RescueParty.class)
@@ -222,7 +220,8 @@
     @Test
     public void testBootLoopDetectionWithExecutionForAllRescueLevels() {
         RescueParty.onSettingsProviderPublished(mMockContext);
-        verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+        verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
+                any(Executor.class),
                 mMonitorCallbackCaptor.capture()));
         HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
 
@@ -233,9 +232,9 @@
 
         // Record DeviceConfig accesses
         RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
-        RemoteCallback monitorCallback = mMonitorCallbackCaptor.getValue();
-        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE1));
-        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE2));
+        DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE2);
 
         final String[] expectedAllResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
 
@@ -309,25 +308,27 @@
     @Test
     public void testNonPersistentAppCrashDetectionWithScopedResets() {
         RescueParty.onSettingsProviderPublished(mMockContext);
-        verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+        verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
+                any(Executor.class),
                 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));
+        DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE2);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE2);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE3);
+
         // Fake DeviceConfig value changes
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE1));
+        monitorCallback.onNamespaceUpdate(NAMESPACE1);
         verify(mMockPackageWatchdog).startObservingHealth(observer,
                 Arrays.asList(CALLING_PACKAGE1), RescueParty.DEFAULT_OBSERVING_DURATION_MS);
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE2));
+        monitorCallback.onNamespaceUpdate(NAMESPACE2);
         verify(mMockPackageWatchdog, times(2)).startObservingHealth(eq(observer),
                 mPackageListCaptor.capture(),
                 eq(RescueParty.DEFAULT_OBSERVING_DURATION_MS));
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE3));
+        monitorCallback.onNamespaceUpdate(NAMESPACE3);
         verify(mMockPackageWatchdog).startObservingHealth(observer,
                 Arrays.asList(CALLING_PACKAGE2), RescueParty.DEFAULT_OBSERVING_DURATION_MS);
         assertTrue(mPackageListCaptor.getValue().containsAll(
@@ -364,20 +365,21 @@
     @Test
     public void testNonDeviceConfigSettingsOnlyResetOncePerLevel() {
         RescueParty.onSettingsProviderPublished(mMockContext);
-        verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+        verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
+                any(Executor.class),
                 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));
+        DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE2);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE2);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE3);
         // Fake DeviceConfig value changes
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE1));
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE2));
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE3));
+        monitorCallback.onNamespaceUpdate(NAMESPACE1);
+        monitorCallback.onNamespaceUpdate(NAMESPACE2);
+        monitorCallback.onNamespaceUpdate(NAMESPACE3);
         // Perform and verify scoped resets
         final String[] expectedPackage1ResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
         final String[] expectedPackage2ResetNamespaces = new String[]{NAMESPACE2, NAMESPACE3};
@@ -549,20 +551,21 @@
     @Test
     public void testResetDeviceConfigForPackagesOnlyRuntimeMap() {
         RescueParty.onSettingsProviderPublished(mMockContext);
-        verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+        verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
+                any(Executor.class),
                 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));
+        DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE2);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE2);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE3);
         // Fake DeviceConfig value changes
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE1));
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE2));
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE3));
+        monitorCallback.onNamespaceUpdate(NAMESPACE1);
+        monitorCallback.onNamespaceUpdate(NAMESPACE2);
+        monitorCallback.onNamespaceUpdate(NAMESPACE3);
 
         doReturn("").when(() -> DeviceConfig.getString(
                 eq(RescueParty.NAMESPACE_CONFIGURATION),
@@ -578,7 +581,8 @@
     @Test
     public void testResetDeviceConfigForPackagesOnlyPresetMap() {
         RescueParty.onSettingsProviderPublished(mMockContext);
-        verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+        verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
+                any(Executor.class),
                 mMonitorCallbackCaptor.capture()));
 
         String presetMapping = NAMESPACE1 + ":" + CALLING_PACKAGE1 + ","
@@ -598,22 +602,23 @@
     @Test
     public void testResetDeviceConfigForPackagesBothMaps() {
         RescueParty.onSettingsProviderPublished(mMockContext);
-        verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+        verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
+                any(Executor.class),
                 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));
-        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE3, NAMESPACE4));
+        DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE2);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE2);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE3);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE3, NAMESPACE4);
         // Fake DeviceConfig value changes
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE1));
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE2));
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE3));
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE4));
+        monitorCallback.onNamespaceUpdate(NAMESPACE1);
+        monitorCallback.onNamespaceUpdate(NAMESPACE2);
+        monitorCallback.onNamespaceUpdate(NAMESPACE3);
+        monitorCallback.onNamespaceUpdate(NAMESPACE4);
 
         String presetMapping = NAMESPACE1 + ":" + CALLING_PACKAGE1 + ","
                 + NAMESPACE2 + ":" + CALLING_PACKAGE2 + ","
@@ -633,20 +638,21 @@
     @Test
     public void testResetDeviceConfigNoExceptionWhenFlagMalformed() {
         RescueParty.onSettingsProviderPublished(mMockContext);
-        verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+        verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
+                any(Executor.class),
                 mMonitorCallbackCaptor.capture()));
 
         // Record DeviceConfig accesses
         RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
-        RemoteCallback monitorCallback = mMonitorCallbackCaptor.getValue();
-        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE1));
-        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE3));
-        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE3, NAMESPACE4));
+        DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE3);
+        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE3, NAMESPACE4);
         // Fake DeviceConfig value changes
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE1));
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE2));
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE3));
-        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE4));
+        monitorCallback.onNamespaceUpdate(NAMESPACE1);
+        monitorCallback.onNamespaceUpdate(NAMESPACE2);
+        monitorCallback.onNamespaceUpdate(NAMESPACE3);
+        monitorCallback.onNamespaceUpdate(NAMESPACE4);
 
         String invalidPresetMapping = NAMESPACE2 + ":" + CALLING_PACKAGE2 + ","
                 + NAMESPACE1 + "." + CALLING_PACKAGE2;
@@ -696,20 +702,4 @@
         RescuePartyObserver.getInstance(mMockContext).execute(new VersionedPackage(
                 packageName, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, mitigationCount);
     }
-
-    private Bundle getConfigAccessBundle(String callingPackage, String namespace) {
-        Bundle result = new Bundle();
-        result.putString(Settings.EXTRA_MONITOR_CALLBACK_TYPE, Settings.EXTRA_ACCESS_CALLBACK);
-        result.putString(Settings.EXTRA_CALLING_PACKAGE, callingPackage);
-        result.putString(Settings.EXTRA_NAMESPACE, namespace);
-        return result;
-    }
-
-    private Bundle getConfigNamespaceUpdateBundle(String updatedNamespace) {
-        Bundle result = new Bundle();
-        result.putString(Settings.EXTRA_MONITOR_CALLBACK_TYPE,
-                Settings.EXTRA_NAMESPACE_UPDATED_CALLBACK);
-        result.putString(Settings.EXTRA_NAMESPACE, updatedNamespace);
-        return result;
-    }
 }