1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.provider;
18 
19 import static android.Manifest.permission.READ_DEVICE_CONFIG;
20 import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
21 
22 import android.annotation.CallbackExecutor;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.annotation.RequiresPermission;
26 import android.annotation.SystemApi;
27 import android.annotation.TestApi;
28 import android.app.ActivityThread;
29 import android.content.ContentResolver;
30 import android.content.Context;
31 import android.content.pm.PackageManager;
32 import android.database.ContentObserver;
33 import android.net.Uri;
34 import android.provider.Settings.Config.SyncDisabledMode;
35 import android.provider.Settings.ResetMode;
36 import android.util.ArrayMap;
37 import android.util.Log;
38 import android.util.Pair;
39 
40 import com.android.internal.annotations.GuardedBy;
41 import com.android.internal.util.Preconditions;
42 
43 import java.util.Arrays;
44 import java.util.Collections;
45 import java.util.HashMap;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Set;
49 import java.util.concurrent.Executor;
50 
51 /**
52  * Device level configuration parameters which can be tuned by a separate configuration service.
53  * Namespaces that end in "_native" such as {@link #NAMESPACE_NETD_NATIVE} are intended to be used
54  * by native code and should be pushed to system properties to make them accessible.
55  *
56  * @hide
57  */
58 @SystemApi
59 public final class DeviceConfig {
60     /**
61      * The content:// style URL for the config table.
62      *
63      * @hide
64      */
65     public static final Uri CONTENT_URI = Uri.parse("content://" + Settings.AUTHORITY + "/config");
66 
67     /**
68      * Namespace for activity manager related features. These features will be applied
69      * immediately upon change.
70      *
71      * @hide
72      */
73     @SystemApi
74     public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
75 
76     /**
77      * Namespace for all activity manager related features that are used at the native level.
78      * These features are applied at reboot.
79      *
80      * @hide
81      */
82     @SystemApi
83     public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT =
84             "activity_manager_native_boot";
85 
86     /**
87      * Namespace for AlarmManager configurations.
88      *
89      * @hide
90      */
91     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
92     @TestApi
93     public static final String NAMESPACE_ALARM_MANAGER = "alarm_manager";
94 
95     /**
96      * Namespace for all app compat related features.  These features will be applied
97      * immediately upon change.
98      *
99      * @hide
100      */
101     @SystemApi
102     public static final String NAMESPACE_APP_COMPAT = "app_compat";
103 
104     /**
105      * Namespace for all app hibernation related features.
106      * @hide
107      */
108     @SystemApi
109     public static final String NAMESPACE_APP_HIBERNATION = "app_hibernation";
110 
111     /**
112      * Namespace for all AppSearch related features.
113      * @hide
114      */
115     @SystemApi
116     public static final String NAMESPACE_APPSEARCH = "appsearch";
117 
118     /**
119      * Namespace for app standby configurations.
120      *
121      * @hide
122      */
123     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
124     public static final String NAMESPACE_APP_STANDBY = "app_standby";
125 
126     /**
127      * Namespace for AttentionManagerService related features.
128      *
129      * @hide
130      */
131     @SystemApi
132     public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
133 
134     /**
135      * Namespace for autofill feature that provides suggestions across all apps when
136      * the user interacts with input fields.
137      *
138      * @hide
139      */
140     @SystemApi
141     public static final String NAMESPACE_AUTOFILL = "autofill";
142 
143     /**
144      * Namespace for battery saver feature.
145      *
146      * @hide
147      */
148     @SystemApi
149     public static final String NAMESPACE_BATTERY_SAVER = "battery_saver";
150 
151     /**
152      * Namespace for blobstore feature that allows apps to share data blobs.
153      *
154      * @hide
155      */
156     @SystemApi
157     public static final String NAMESPACE_BLOBSTORE = "blobstore";
158 
159     /**
160      * Namespace for all Bluetooth related features.
161      *
162      * @hide
163      */
164     @SystemApi
165     public static final String NAMESPACE_BLUETOOTH = "bluetooth";
166 
167     /**
168      * Namespace for features relating to clipboard.
169      *
170      * @hide
171      */
172     @SystemApi
173     public static final String NAMESPACE_CLIPBOARD = "clipboard";
174 
175     /**
176      * Namespace for all networking connectivity related features.
177      *
178      * @hide
179      */
180     @SystemApi
181     public static final String NAMESPACE_CONNECTIVITY = "connectivity";
182 
183     /**
184      * Namespace for content capture feature used by on-device machine intelligence
185      * to provide suggestions in a privacy-safe manner.
186      *
187      * @hide
188      */
189     @SystemApi
190     public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
191 
192     /**
193      * Namespace for device idle configurations.
194      *
195      * @hide
196      */
197     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
198     @TestApi
199     public static final String NAMESPACE_DEVICE_IDLE = "device_idle";
200 
201     /**
202      * Namespace for how dex runs. The feature requires a reboot to reach a clean state.
203      *
204      * @deprecated No longer used
205      * @hide
206      */
207     @Deprecated
208     @SystemApi
209     public static final String NAMESPACE_DEX_BOOT = "dex_boot";
210 
211     /**
212      * Namespace for display manager related features. The names to access the properties in this
213      * namespace should be defined in {@link android.hardware.display.DisplayManager}.
214      *
215      * @hide
216      */
217     @SystemApi
218     public static final String NAMESPACE_DISPLAY_MANAGER = "display_manager";
219 
220     /**
221      * Namespace for all Game Driver features.
222      *
223      * @hide
224      */
225     @SystemApi
226     public static final String NAMESPACE_GAME_DRIVER = "game_driver";
227 
228     /**
229      * Namespace for all input-related features that are used at the native level.
230      * These features are applied at reboot.
231      *
232      * @hide
233      */
234     @SystemApi
235     public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
236 
237     /**
238      * Namespace for attention-based features provided by on-device machine intelligence.
239      *
240      * @hide
241      */
242     @SystemApi
243     public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
244 
245     /**
246      * Definitions for properties related to Content Suggestions.
247      *
248      * @hide
249      */
250     public static final String NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS =
251             "intelligence_content_suggestions";
252 
253     /**
254      * Namespace for JobScheduler configurations.
255      * @hide
256      */
257     @TestApi
258     public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler";
259 
260     /**
261      * Namespace for all lmkd related features.
262      *
263      * @hide
264      */
265     public static final String NAMESPACE_LMKD_NATIVE = "lmkd_native";
266 
267     /**
268      * Namespace for all location related features.
269      *
270      * @hide
271      */
272     @SystemApi
273     public static final String NAMESPACE_LOCATION = "location";
274 
275     /**
276      * Namespace for all media related features.
277      *
278      * @hide
279      */
280     @SystemApi
281     public static final String NAMESPACE_MEDIA = "media";
282 
283     /**
284      * Namespace for all media native related features.
285      *
286      * @hide
287      */
288     @SystemApi
289     public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
290 
291     /**
292      * Namespace for all netd related features.
293      *
294      * @hide
295      */
296     @SystemApi
297     public static final String NAMESPACE_NETD_NATIVE = "netd_native";
298 
299     /**
300      * Namespace for features related to the Package Manager Service.
301      *
302      * @hide
303      */
304     @SystemApi
305     public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service";
306 
307     /**
308      * Namespace for features related to the Profcollect native Service.
309      * These features are applied at reboot.
310      *
311      * @hide
312      */
313     @SystemApi
314     public static final String NAMESPACE_PROFCOLLECT_NATIVE_BOOT = "profcollect_native_boot";
315 
316     /**
317      * Namespace for features related to Reboot Readiness detection.
318      *
319      * @hide
320      */
321     @SystemApi
322     public static final String NAMESPACE_REBOOT_READINESS = "reboot_readiness";
323 
324     /**
325      * Namespace for Rollback flags that are applied immediately.
326      *
327      * @hide
328      */
329     @SystemApi
330     public static final String NAMESPACE_ROLLBACK = "rollback";
331 
332     /**
333      * Namespace for Rollback flags that are applied after a reboot.
334      *
335      * @hide
336      */
337     @SystemApi
338     public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
339 
340     /**
341      * Namespace for Rotation Resolver Manager Service.
342      *
343      * @hide
344      */
345     public static final String NAMESPACE_ROTATION_RESOLVER = "rotation_resolver";
346 
347     /**
348      * Namespace for all runtime related features that don't require a reboot to become active.
349      * There are no feature flags using NAMESPACE_RUNTIME.
350      *
351      * @hide
352      */
353     @SystemApi
354     public static final String NAMESPACE_RUNTIME = "runtime";
355 
356     /**
357      * Namespace for all runtime related features that require system properties for accessing
358      * the feature flags from C++ or Java language code. One example is the app image startup
359      * cache feature use_app_image_startup_cache.
360      *
361      * @hide
362      */
363     @SystemApi
364     public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native";
365 
366     /**
367      * Namespace for all runtime native boot related features. Boot in this case refers to the
368      * fact that the properties only take affect after rebooting the device.
369      *
370      * @hide
371      */
372     @SystemApi
373     public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
374 
375     /**
376      * Namespace for system scheduler related features. These features will be applied
377      * immediately upon change.
378      *
379      * @hide
380      */
381     @SystemApi
382     public static final String NAMESPACE_SCHEDULER = "scheduler";
383 
384     /**
385      * Namespace for settings statistics features.
386      *
387      * @hide
388      */
389     public static final String NAMESPACE_SETTINGS_STATS = "settings_stats";
390 
391     /**
392      * Namespace for all statsd java features that can be applied immediately.
393      *
394      * @hide
395      */
396     @SystemApi
397     public static final String NAMESPACE_STATSD_JAVA = "statsd_java";
398 
399     /**
400      * Namespace for all statsd java features that are applied on boot.
401      *
402      * @hide
403      */
404     @SystemApi
405     public static final String NAMESPACE_STATSD_JAVA_BOOT = "statsd_java_boot";
406 
407     /**
408      * Namespace for all statsd native features that can be applied immediately.
409      *
410      * @hide
411      */
412     @SystemApi
413     public static final String NAMESPACE_STATSD_NATIVE = "statsd_native";
414 
415     /**
416      * Namespace for all statsd native features that are applied on boot.
417      *
418      * @hide
419      */
420     @SystemApi
421     public static final String NAMESPACE_STATSD_NATIVE_BOOT = "statsd_native_boot";
422 
423     /**
424      * Namespace for storage-related features.
425      *
426      * @deprecated Replace storage namespace with storage_native_boot.
427      * @hide
428      */
429     @Deprecated
430     @SystemApi
431     public static final String NAMESPACE_STORAGE = "storage";
432 
433     /**
434      * Namespace for storage-related features, including native and boot.
435      *
436      * @hide
437      */
438     @SystemApi
439     public static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot";
440 
441     /**
442      * Namespace for System UI related features.
443      *
444      * @hide
445      */
446     @SystemApi
447     public static final String NAMESPACE_SYSTEMUI = "systemui";
448 
449     /**
450      * Namespace for system time and time zone detection related features / behavior.
451      *
452      * @hide
453      */
454     @SystemApi
455     public static final String NAMESPACE_SYSTEM_TIME = "system_time";
456 
457     /**
458      * Telephony related properties.
459      *
460      * @hide
461      */
462     @SystemApi
463     public static final String NAMESPACE_TELEPHONY = "telephony";
464 
465     /**
466      * Namespace for TextClassifier related features.
467      *
468      * @hide
469      * @see android.provider.Settings.Global.TEXT_CLASSIFIER_CONSTANTS
470      */
471     @SystemApi
472     public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier";
473 
474     /**
475      * Namespace for contacts provider related features.
476      *
477      * @hide
478      */
479     public static final String NAMESPACE_CONTACTS_PROVIDER = "contacts_provider";
480 
481     /**
482      * Namespace for settings ui related features
483      *
484      * @hide
485      */
486     public static final String NAMESPACE_SETTINGS_UI = "settings_ui";
487 
488     /**
489      * Namespace for android related features, i.e. for flags that affect not just a single
490      * component, but the entire system.
491      *
492      * The keys for this namespace are defined in {@link AndroidDeviceConfig}.
493      *
494      * @hide
495      */
496     @TestApi
497     public static final String NAMESPACE_ANDROID = "android";
498 
499     /**
500      * Namespace for window manager related features.
501      *
502      * @hide
503      */
504     public static final String NAMESPACE_WINDOW_MANAGER = "window_manager";
505 
506     /**
507      * Namespace for window manager features accessible by native code and
508      * loaded once per boot.
509      *
510      * @hide
511      */
512     @SystemApi
513     public static final String NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT = "window_manager_native_boot";
514 
515     /**
516      * List of namespaces which can be read without READ_DEVICE_CONFIG permission
517      *
518      * @hide
519      */
520     @NonNull
521     private static final List<String> PUBLIC_NAMESPACES =
522             Arrays.asList(NAMESPACE_TEXTCLASSIFIER, NAMESPACE_RUNTIME, NAMESPACE_STATSD_JAVA,
523                     NAMESPACE_STATSD_JAVA_BOOT);
524     /**
525      * Privacy related properties definitions.
526      *
527      * @hide
528      */
529     @SystemApi
530     public static final String NAMESPACE_PRIVACY = "privacy";
531 
532     /**
533      * Namespace for biometrics related features
534      *
535      * @hide
536      */
537     @SystemApi
538     public static final String NAMESPACE_BIOMETRICS = "biometrics";
539 
540     /**
541      * Permission related properties definitions.
542      *
543      * @hide
544      */
545     @SystemApi
546     public static final String NAMESPACE_PERMISSIONS = "permissions";
547 
548     /**
549      * Namespace for ota related features.
550      *
551      * @hide
552      */
553     @SystemApi
554     public static final String NAMESPACE_OTA = "ota";
555 
556     /**
557      * Namespace for all widget related features.
558      *
559      * @hide
560      */
561     public static final String NAMESPACE_WIDGET = "widget";
562 
563     /**
564      * Namespace for connectivity thermal power manager features.
565      *
566      * @hide
567      */
568     public static final String NAMESPACE_CONNECTIVITY_THERMAL_POWER_MANAGER =
569             "connectivity_thermal_power_manager";
570 
571     /**
572      * Namespace for configuration related features.
573      *
574      * @hide
575      */
576     public static final String NAMESPACE_CONFIGURATION = "configuration";
577 
578     /**
579      * LatencyTracker properties definitions.
580      *
581      * @hide
582      */
583     public static final String NAMESPACE_LATENCY_TRACKER = "latency_tracker";
584 
585     /**
586      * InteractionJankMonitor properties definitions.
587      *
588      * @hide
589      */
590     public static final String NAMESPACE_INTERACTION_JANK_MONITOR = "interaction_jank_monitor";
591 
592     /**
593      * Namespace for game overlay related features.
594      *
595      * @hide
596      */
597     public static final String NAMESPACE_GAME_OVERLAY = "game_overlay";
598 
599     /**
600      * Namespace for Constrain Display APIs related features.
601      *
602      * @hide
603      */
604     @TestApi
605     public static final String NAMESPACE_CONSTRAIN_DISPLAY_APIS = "constrain_display_apis";
606 
607     /**
608      * Namespace for App Compat Overrides related features.
609      *
610      * @hide
611      */
612     @TestApi
613     public static final String NAMESPACE_APP_COMPAT_OVERRIDES = "app_compat_overrides";
614 
615     private static final Object sLock = new Object();
616     @GuardedBy("sLock")
617     private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
618             new ArrayMap<>();
619     @GuardedBy("sLock")
620     private static Map<String, Pair<ContentObserver, Integer>> sNamespaces = new HashMap<>();
621     private static final String TAG = "DeviceConfig";
622 
623     // Should never be invoked
DeviceConfig()624     private DeviceConfig() {
625     }
626 
627     /**
628      * Look up the value of a property for a particular namespace.
629      *
630      * @param namespace The namespace containing the property to look up.
631      * @param name      The name of the property to look up.
632      * @return the corresponding value, or null if not present.
633      * @hide
634      */
635     @SystemApi
636     @RequiresPermission(READ_DEVICE_CONFIG)
getProperty(@onNull String namespace, @NonNull String name)637     public static String getProperty(@NonNull String namespace, @NonNull String name) {
638         // Fetch all properties for the namespace at once and cache them in the local process, so we
639         // incur the cost of the IPC less often. Lookups happen much more frequently than updates,
640         // and we want to optimize the former.
641         return getProperties(namespace, name).getString(name, null);
642     }
643 
644     /**
645      * Look up the values of multiple properties for a particular namespace. The lookup is atomic,
646      * such that the values of these properties cannot change between the time when the first is
647      * fetched and the time when the last is fetched.
648      * <p>
649      * Each call to {@link #setProperties(Properties)} is also atomic and ensures that either none
650      * or all of the change is picked up here, but never only part of it.
651      *
652      * @param namespace The namespace containing the properties to look up.
653      * @param names     The names of properties to look up, or empty to fetch all properties for the
654      *                  given namespace.
655      * @return {@link Properties} object containing the requested properties. This reflects the
656      *     state of these properties at the time of the lookup, and is not updated to reflect any
657      *     future changes. The keyset of this Properties object will contain only the intersection
658      *     of properties already set and properties requested via the names parameter. Properties
659      *     that are already set but were not requested will not be contained here. Properties that
660      *     are not set, but were requested will not be contained here either.
661      * @hide
662      */
663     @SystemApi
664     @NonNull
665     @RequiresPermission(READ_DEVICE_CONFIG)
getProperties(@onNull String namespace, @NonNull String ... names)666     public static Properties getProperties(@NonNull String namespace, @NonNull String ... names) {
667         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
668         return new Properties(namespace,
669                 Settings.Config.getStrings(contentResolver, namespace, Arrays.asList(names)));
670     }
671 
672     /**
673      * Look up the String value of a property for a particular namespace.
674      *
675      * @param namespace    The namespace containing the property to look up.
676      * @param name         The name of the property to look up.
677      * @param defaultValue The value to return if the property does not exist or has no non-null
678      *                     value.
679      * @return the corresponding value, or defaultValue if none exists.
680      * @hide
681      */
682     @SystemApi
683     @RequiresPermission(READ_DEVICE_CONFIG)
getString(@onNull String namespace, @NonNull String name, @Nullable String defaultValue)684     public static String getString(@NonNull String namespace, @NonNull String name,
685             @Nullable String defaultValue) {
686         String value = getProperty(namespace, name);
687         return value != null ? value : defaultValue;
688     }
689 
690     /**
691      * Look up the boolean value of a property for a particular namespace.
692      *
693      * @param namespace The namespace containing the property to look up.
694      * @param name      The name of the property to look up.
695      * @param defaultValue The value to return if the property does not exist or has no non-null
696      *                     value.
697      * @return the correspondfing value, or defaultValue if none exists.
698      * @hide
699      */
700     @SystemApi
701     @RequiresPermission(READ_DEVICE_CONFIG)
getBoolean(@onNull String namespace, @NonNull String name, boolean defaultValue)702     public static boolean getBoolean(@NonNull String namespace, @NonNull String name,
703             boolean defaultValue) {
704         String value = getProperty(namespace, name);
705         return value != null ? Boolean.parseBoolean(value) : defaultValue;
706     }
707 
708     /**
709      * Look up the int value of a property for a particular namespace.
710      *
711      * @param namespace The namespace containing the property to look up.
712      * @param name      The name of the property to look up.
713      * @param defaultValue The value to return if the property does not exist, has no non-null
714      *                     value, or fails to parse into an int.
715      * @return the corresponding value, or defaultValue if either none exists or it does not parse.
716      * @hide
717      */
718     @SystemApi
719     @RequiresPermission(READ_DEVICE_CONFIG)
getInt(@onNull String namespace, @NonNull String name, int defaultValue)720     public static int getInt(@NonNull String namespace, @NonNull String name, int defaultValue) {
721         String value = getProperty(namespace, name);
722         if (value == null) {
723             return defaultValue;
724         }
725         try {
726             return Integer.parseInt(value);
727         } catch (NumberFormatException e) {
728             Log.e(TAG, "Parsing integer failed for " + namespace + ":" + name);
729             return defaultValue;
730         }
731     }
732 
733     /**
734      * Look up the long value of a property for a particular namespace.
735      *
736      * @param namespace The namespace containing the property to look up.
737      * @param name      The name of the property to look up.
738      * @param defaultValue The value to return if the property does not exist, has no non-null
739      *                     value, or fails to parse into a long.
740      * @return the corresponding value, or defaultValue if either none exists or it does not parse.
741      * @hide
742      */
743     @SystemApi
744     @RequiresPermission(READ_DEVICE_CONFIG)
getLong(@onNull String namespace, @NonNull String name, long defaultValue)745     public static long getLong(@NonNull String namespace, @NonNull String name, long defaultValue) {
746         String value = getProperty(namespace, name);
747         if (value == null) {
748             return defaultValue;
749         }
750         try {
751             return Long.parseLong(value);
752         } catch (NumberFormatException e) {
753             Log.e(TAG, "Parsing long failed for " + namespace + ":" + name);
754             return defaultValue;
755         }
756     }
757 
758     /**
759      * Look up the float value of a property for a particular namespace.
760      *
761      * @param namespace The namespace containing the property to look up.
762      * @param name      The name of the property to look up.
763      * @param defaultValue The value to return if the property does not exist, has no non-null
764      *                     value, or fails to parse into a float.
765      * @return the corresponding value, or defaultValue if either none exists or it does not parse.
766      * @hide
767      */
768     @SystemApi
769     @RequiresPermission(READ_DEVICE_CONFIG)
getFloat(@onNull String namespace, @NonNull String name, float defaultValue)770     public static float getFloat(@NonNull String namespace, @NonNull String name,
771             float defaultValue) {
772         String value = getProperty(namespace, name);
773         if (value == null) {
774             return defaultValue;
775         }
776         try {
777             return Float.parseFloat(value);
778         } catch (NumberFormatException e) {
779             Log.e(TAG, "Parsing float failed for " + namespace + ":" + name);
780             return defaultValue;
781         }
782     }
783 
784     /**
785      * Create a new property with the the provided name and value in the provided namespace, or
786      * update the value of such a property if it already exists. The same name can exist in multiple
787      * namespaces and might have different values in any or all namespaces.
788      * <p>
789      * The method takes an argument indicating whether to make the value the default for this
790      * property.
791      * <p>
792      * All properties stored for a particular scope can be reverted to their default values
793      * by passing the namespace to {@link #resetToDefaults(int, String)}.
794      *
795      * @param namespace   The namespace containing the property to create or update.
796      * @param name        The name of the property to create or update.
797      * @param value       The value to store for the property.
798      * @param makeDefault Whether to make the new value the default one.
799      * @return True if the value was set, false if the storage implementation throws errors.
800      * @hide
801      * @see #resetToDefaults(int, String).
802      */
803     @SystemApi
804     @RequiresPermission(WRITE_DEVICE_CONFIG)
setProperty(@onNull String namespace, @NonNull String name, @Nullable String value, boolean makeDefault)805     public static boolean setProperty(@NonNull String namespace, @NonNull String name,
806             @Nullable String value, boolean makeDefault) {
807         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
808         return Settings.Config.putString(contentResolver, namespace, name, value, makeDefault);
809     }
810 
811     /**
812      * Set all of the properties for a specific namespace. Pre-existing properties will be updated
813      * and new properties will be added if necessary. Any pre-existing properties for the specific
814      * namespace which are not part of the provided {@link Properties} object will be deleted from
815      * the namespace. These changes are all applied atomically, such that no calls to read or reset
816      * these properties can happen in the middle of this update.
817      * <p>
818      * Each call to {@link #getProperties(String, String...)} is also atomic and ensures that either
819      * none or all of this update is picked up, but never only part of it.
820      *
821      * @param properties the complete set of properties to set for a specific namespace.
822      * @throws BadConfigException if the provided properties are banned by RescueParty.
823      * @return True if the values were set, false otherwise.
824      * @hide
825      */
826     @SystemApi
827     @RequiresPermission(WRITE_DEVICE_CONFIG)
setProperties(@onNull Properties properties)828     public static boolean setProperties(@NonNull Properties properties) throws BadConfigException {
829         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
830         return Settings.Config.setStrings(contentResolver, properties.getNamespace(),
831                 properties.mMap);
832     }
833 
834     /**
835      * Reset properties to their default values by removing the underlying values.
836      * <p>
837      * The method accepts an optional namespace parameter. If provided, only properties set within
838      * that namespace will be reset. Otherwise, all properties will be reset.
839      * <p>
840      * Note: This method should only be used by {@link com.android.server.RescueParty}. It was
841      * designed to be used in the event of boot or crash loops caused by flag changes. It does not
842      * revert flag values to defaults - instead it removes the property entirely which causes the
843      * consumer of the flag to use hardcoded defaults upon retrieval.
844      * <p>
845      * To clear values for a namespace without removing the underlying properties, construct a
846      * {@link Properties} object with the caller's namespace and either an empty flag map, or some
847      * snapshot of flag values. Then use {@link #setProperties(Properties)} to remove all flags
848      * under the namespace, or set them to the values in the snapshot.
849      * <p>
850      * To revert values for testing, one should mock DeviceConfig using
851      * {@link com.android.server.testables.TestableDeviceConfig} where possible. Otherwise, fallback
852      * to using {@link #setProperties(Properties)} as outlined above.
853      *
854      * @param resetMode The reset mode to use.
855      * @param namespace Optionally, the specific namespace which resets will be limited to.
856      * @hide
857      * @see #setProperty(String, String, String, boolean)
858      */
859     @SystemApi
860     @RequiresPermission(WRITE_DEVICE_CONFIG)
resetToDefaults(@esetMode int resetMode, @Nullable String namespace)861     public static void resetToDefaults(@ResetMode int resetMode, @Nullable String namespace) {
862         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
863         Settings.Config.resetToDefaults(contentResolver, resetMode, namespace);
864     }
865 
866     /**
867      * Disables or re-enables bulk modifications ({@link #setProperties(Properties)}) to device
868      * config values. This is intended for use during tests to prevent a sync operation clearing
869      * config values, which could influence the outcome of the tests, i.e. by changing behavior.
870      *
871      * @param syncDisabledMode the mode to use, see {@link Settings.Config#SYNC_DISABLED_MODE_NONE},
872      *     {@link Settings.Config#SYNC_DISABLED_MODE_PERSISTENT} and {@link
873      *     Settings.Config#SYNC_DISABLED_MODE_UNTIL_REBOOT}
874      *
875      * @see #isSyncDisabled()
876      * @hide
877      */
878     @RequiresPermission(WRITE_DEVICE_CONFIG)
setSyncDisabled(@yncDisabledMode int syncDisabledMode)879     public static void setSyncDisabled(@SyncDisabledMode int syncDisabledMode) {
880         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
881         Settings.Config.setSyncDisabled(contentResolver, syncDisabledMode);
882     }
883 
884     /**
885      * Returns the current state of sync disabling, {@code true} when disabled, {@code false}
886      * otherwise.
887      *
888      * @see #setSyncDisabled(int)
889      * @hide
890      */
891     @RequiresPermission(WRITE_DEVICE_CONFIG)
isSyncDisabled()892     public static boolean isSyncDisabled() {
893         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
894         return Settings.Config.isSyncDisabled(contentResolver);
895     }
896 
897     /**
898      * Add a listener for property changes.
899      * <p>
900      * This listener will be called whenever properties in the specified namespace change. Callbacks
901      * will be made on the specified executor. Future calls to this method with the same listener
902      * will replace the old namespace and executor. Remove the listener entirely by calling
903      * {@link #removeOnPropertiesChangedListener(OnPropertiesChangedListener)}.
904      *
905      * @param namespace                   The namespace containing properties to monitor.
906      * @param executor                    The executor which will be used to run callbacks.
907      * @param onPropertiesChangedListener The listener to add.
908      * @hide
909      * @see #removeOnPropertiesChangedListener(OnPropertiesChangedListener)
910      */
911     @SystemApi
912     @RequiresPermission(READ_DEVICE_CONFIG)
addOnPropertiesChangedListener( @onNull String namespace, @NonNull @CallbackExecutor Executor executor, @NonNull OnPropertiesChangedListener onPropertiesChangedListener)913     public static void addOnPropertiesChangedListener(
914             @NonNull String namespace,
915             @NonNull @CallbackExecutor Executor executor,
916             @NonNull OnPropertiesChangedListener onPropertiesChangedListener) {
917         enforceReadPermission(ActivityThread.currentApplication().getApplicationContext(),
918                 namespace);
919         synchronized (sLock) {
920             Pair<String, Executor> oldNamespace = sListeners.get(onPropertiesChangedListener);
921             if (oldNamespace == null) {
922                 // Brand new listener, add it to the list.
923                 sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
924                 incrementNamespace(namespace);
925             } else if (namespace.equals(oldNamespace.first)) {
926                 // Listener is already registered for this namespace, update executor just in case.
927                 sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
928             } else {
929                 // Update this listener from an old namespace to the new one.
930                 decrementNamespace(sListeners.get(onPropertiesChangedListener).first);
931                 sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
932                 incrementNamespace(namespace);
933             }
934         }
935     }
936 
937     /**
938      * Remove a listener for property changes. The listener will receive no further notification of
939      * property changes.
940      *
941      * @param onPropertiesChangedListener The listener to remove.
942      * @hide
943      * @see #addOnPropertiesChangedListener(String, Executor, OnPropertiesChangedListener)
944      */
945     @SystemApi
removeOnPropertiesChangedListener( @onNull OnPropertiesChangedListener onPropertiesChangedListener)946     public static void removeOnPropertiesChangedListener(
947             @NonNull OnPropertiesChangedListener onPropertiesChangedListener) {
948         Preconditions.checkNotNull(onPropertiesChangedListener);
949         synchronized (sLock) {
950             if (sListeners.containsKey(onPropertiesChangedListener)) {
951                 decrementNamespace(sListeners.get(onPropertiesChangedListener).first);
952                 sListeners.remove(onPropertiesChangedListener);
953             }
954         }
955     }
956 
createNamespaceUri(@onNull String namespace)957     private static Uri createNamespaceUri(@NonNull String namespace) {
958         Preconditions.checkNotNull(namespace);
959         return CONTENT_URI.buildUpon().appendPath(namespace).build();
960     }
961 
962     /**
963      * Increment the count used to represent the number of listeners subscribed to the given
964      * namespace. If this is the first (i.e. incrementing from 0 to 1) for the given namespace, a
965      * ContentObserver is registered.
966      *
967      * @param namespace The namespace to increment the count for.
968      */
969     @GuardedBy("sLock")
incrementNamespace(@onNull String namespace)970     private static void incrementNamespace(@NonNull String namespace) {
971         Preconditions.checkNotNull(namespace);
972         Pair<ContentObserver, Integer> namespaceCount = sNamespaces.get(namespace);
973         if (namespaceCount != null) {
974             sNamespaces.put(namespace, new Pair<>(namespaceCount.first, namespaceCount.second + 1));
975         } else {
976             // This is a new namespace, register a ContentObserver for it.
977             ContentObserver contentObserver = new ContentObserver(null) {
978                 @Override
979                 public void onChange(boolean selfChange, Uri uri) {
980                     if (uri != null) {
981                         handleChange(uri);
982                     }
983                 }
984             };
985             ActivityThread.currentApplication().getContentResolver()
986                     .registerContentObserver(createNamespaceUri(namespace), true, contentObserver);
987             sNamespaces.put(namespace, new Pair<>(contentObserver, 1));
988         }
989     }
990 
991     /**
992      * Decrement the count used to represent the number of listeners subscribed to the given
993      * namespace. If this is the final decrement call (i.e. decrementing from 1 to 0) for the given
994      * namespace, the ContentObserver that had been tracking it will be removed.
995      *
996      * @param namespace The namespace to decrement the count for.
997      */
998     @GuardedBy("sLock")
decrementNamespace(@onNull String namespace)999     private static void decrementNamespace(@NonNull String namespace) {
1000         Preconditions.checkNotNull(namespace);
1001         Pair<ContentObserver, Integer> namespaceCount = sNamespaces.get(namespace);
1002         if (namespaceCount == null) {
1003             // This namespace is not registered and does not need to be decremented
1004             return;
1005         } else if (namespaceCount.second > 1) {
1006             sNamespaces.put(namespace, new Pair<>(namespaceCount.first, namespaceCount.second - 1));
1007         } else {
1008             // Decrementing a namespace to zero means we no longer need its ContentObserver.
1009             ActivityThread.currentApplication().getContentResolver()
1010                     .unregisterContentObserver(namespaceCount.first);
1011             sNamespaces.remove(namespace);
1012         }
1013     }
1014 
handleChange(@onNull Uri uri)1015     private static void handleChange(@NonNull Uri uri) {
1016         Preconditions.checkNotNull(uri);
1017         List<String> pathSegments = uri.getPathSegments();
1018         // pathSegments(0) is "config"
1019         final String namespace = pathSegments.get(1);
1020         Properties.Builder propBuilder = new Properties.Builder(namespace);
1021         try {
1022             Properties allProperties = getProperties(namespace);
1023             for (int i = 2; i < pathSegments.size(); ++i) {
1024                 String key = pathSegments.get(i);
1025                 propBuilder.setString(key, allProperties.getString(key, null));
1026             }
1027         } catch (SecurityException e) {
1028             // Silently failing to not crash binder or listener threads.
1029             Log.e(TAG, "OnPropertyChangedListener update failed: permission violation.");
1030             return;
1031         }
1032         Properties properties = propBuilder.build();
1033 
1034         synchronized (sLock) {
1035             for (int i = 0; i < sListeners.size(); i++) {
1036                 if (namespace.equals(sListeners.valueAt(i).first)) {
1037                     final OnPropertiesChangedListener listener = sListeners.keyAt(i);
1038                     sListeners.valueAt(i).second.execute(() -> {
1039                         listener.onPropertiesChanged(properties);
1040                     });
1041                 }
1042             }
1043         }
1044     }
1045 
1046     /**
1047      * Enforces READ_DEVICE_CONFIG permission if namespace is not one of public namespaces.
1048      * @hide
1049      */
enforceReadPermission(Context context, String namespace)1050     public static void enforceReadPermission(Context context, String namespace) {
1051         if (context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG)
1052                 != PackageManager.PERMISSION_GRANTED) {
1053             if (!PUBLIC_NAMESPACES.contains(namespace)) {
1054                 throw new SecurityException("Permission denial: reading from settings requires:"
1055                         + READ_DEVICE_CONFIG);
1056             }
1057         }
1058     }
1059 
1060     /**
1061      * Returns list of namespaces that can be read without READ_DEVICE_CONFIG_PERMISSION;
1062      * @hide
1063      */
getPublicNamespaces()1064     public static @NonNull List<String> getPublicNamespaces() {
1065         return PUBLIC_NAMESPACES;
1066     }
1067 
1068     /**
1069      * Interface for monitoring changes to properties. Implementations will receive callbacks when
1070      * properties change, including a {@link Properties} object which contains a single namespace
1071      * and all of the properties which changed for that namespace. This includes properties which
1072      * were added, updated, or deleted. This is not necessarily a complete list of all properties
1073      * belonging to the namespace, as properties which don't change are omitted.
1074      * <p>
1075      * Override {@link #onPropertiesChanged(Properties)} to handle callbacks for changes.
1076      *
1077      * @hide
1078      */
1079     @SystemApi
1080     public interface OnPropertiesChangedListener {
1081         /**
1082          * Called when one or more properties have changed, providing a Properties object with all
1083          * of the changed properties. This object will contain only properties which have changed,
1084          * not the complete set of all properties belonging to the namespace.
1085          *
1086          * @param properties Contains the complete collection of properties which have changed for a
1087          *                   single namespace. This includes only those which were added, updated,
1088          *                   or deleted.
1089          */
onPropertiesChanged(@onNull Properties properties)1090         void onPropertiesChanged(@NonNull Properties properties);
1091     }
1092 
1093     /**
1094      * Thrown by {@link #setProperties(Properties)} when a configuration is rejected. This
1095      * happens if RescueParty has identified a bad configuration and reset the namespace.
1096      *
1097      * @hide
1098      */
1099     @SystemApi
1100     public static class BadConfigException extends Exception {}
1101 
1102     /**
1103      * A mapping of properties to values, as well as a single namespace which they all belong to.
1104      *
1105      * @hide
1106      */
1107     @SystemApi
1108     public static class Properties {
1109         private final String mNamespace;
1110         private final HashMap<String, String> mMap;
1111         private Set<String> mKeyset;
1112 
1113         /**
1114          * Create a mapping of properties to values and the namespace they belong to.
1115          *
1116          * @param namespace The namespace these properties belong to.
1117          * @param keyValueMap A map between property names and property values.
1118          * @hide
1119          */
Properties(@onNull String namespace, @Nullable Map<String, String> keyValueMap)1120         public Properties(@NonNull String namespace, @Nullable Map<String, String> keyValueMap) {
1121             Preconditions.checkNotNull(namespace);
1122             mNamespace = namespace;
1123             mMap = new HashMap();
1124             if (keyValueMap != null) {
1125                 mMap.putAll(keyValueMap);
1126             }
1127         }
1128 
1129         /**
1130          * @return the namespace all properties within this instance belong to.
1131          */
1132         @NonNull
getNamespace()1133         public String getNamespace() {
1134             return mNamespace;
1135         }
1136 
1137         /**
1138          * @return the non-null set of property names.
1139          */
1140         @NonNull
getKeyset()1141         public Set<String> getKeyset() {
1142             if (mKeyset == null) {
1143                 mKeyset = Collections.unmodifiableSet(mMap.keySet());
1144             }
1145             return mKeyset;
1146         }
1147 
1148         /**
1149          * Look up the String value of a property.
1150          *
1151          * @param name         The name of the property to look up.
1152          * @param defaultValue The value to return if the property has not been defined.
1153          * @return the corresponding value, or defaultValue if none exists.
1154          */
1155         @Nullable
getString(@onNull String name, @Nullable String defaultValue)1156         public String getString(@NonNull String name, @Nullable String defaultValue) {
1157             Preconditions.checkNotNull(name);
1158             String value = mMap.get(name);
1159             return value != null ? value : defaultValue;
1160         }
1161 
1162         /**
1163          * Look up the boolean value of a property.
1164          *
1165          * @param name         The name of the property to look up.
1166          * @param defaultValue The value to return if the property has not been defined.
1167          * @return the corresponding value, or defaultValue if none exists.
1168          */
getBoolean(@onNull String name, boolean defaultValue)1169         public boolean getBoolean(@NonNull String name, boolean defaultValue) {
1170             Preconditions.checkNotNull(name);
1171             String value = mMap.get(name);
1172             return value != null ? Boolean.parseBoolean(value) : defaultValue;
1173         }
1174 
1175         /**
1176          * Look up the int value of a property.
1177          *
1178          * @param name         The name of the property to look up.
1179          * @param defaultValue The value to return if the property has not been defined or fails to
1180          *                     parse into an int.
1181          * @return the corresponding value, or defaultValue if no valid int is available.
1182          */
getInt(@onNull String name, int defaultValue)1183         public int getInt(@NonNull String name, int defaultValue) {
1184             Preconditions.checkNotNull(name);
1185             String value = mMap.get(name);
1186             if (value == null) {
1187                 return defaultValue;
1188             }
1189             try {
1190                 return Integer.parseInt(value);
1191             } catch (NumberFormatException e) {
1192                 Log.e(TAG, "Parsing int failed for " + name);
1193                 return defaultValue;
1194             }
1195         }
1196 
1197         /**
1198          * Look up the long value of a property.
1199          *
1200          * @param name         The name of the property to look up.
1201          * @param defaultValue The value to return if the property has not been defined. or fails to
1202          *                     parse into a long.
1203          * @return the corresponding value, or defaultValue if no valid long is available.
1204          */
getLong(@onNull String name, long defaultValue)1205         public long getLong(@NonNull String name, long defaultValue) {
1206             Preconditions.checkNotNull(name);
1207             String value = mMap.get(name);
1208             if (value == null) {
1209                 return defaultValue;
1210             }
1211             try {
1212                 return Long.parseLong(value);
1213             } catch (NumberFormatException e) {
1214                 Log.e(TAG, "Parsing long failed for " + name);
1215                 return defaultValue;
1216             }
1217         }
1218 
1219         /**
1220          * Look up the int value of a property.
1221          *
1222          * @param name         The name of the property to look up.
1223          * @param defaultValue The value to return if the property has not been defined. or fails to
1224          *                     parse into a float.
1225          * @return the corresponding value, or defaultValue if no valid float is available.
1226          */
getFloat(@onNull String name, float defaultValue)1227         public float getFloat(@NonNull String name, float defaultValue) {
1228             Preconditions.checkNotNull(name);
1229             String value = mMap.get(name);
1230             if (value == null) {
1231                 return defaultValue;
1232             }
1233             try {
1234                 return Float.parseFloat(value);
1235             } catch (NumberFormatException e) {
1236                 Log.e(TAG, "Parsing float failed for " + name);
1237                 return defaultValue;
1238             }
1239         }
1240 
1241         /**
1242          * Builder class for the construction of {@link Properties} objects.
1243          */
1244         public static final class Builder {
1245             @NonNull
1246             private final String mNamespace;
1247             @NonNull
1248             private final Map<String, String> mKeyValues = new HashMap<>();
1249 
1250             /**
1251              * Create a new Builders for the specified namespace.
1252              * @param namespace non null namespace.
1253              */
Builder(@onNull String namespace)1254             public Builder(@NonNull String namespace) {
1255                 mNamespace = namespace;
1256             }
1257 
1258             /**
1259              * Add a new property with the specified key and value.
1260              * @param name non null name of the property.
1261              * @param value nullable string value of the property.
1262              * @return this Builder object
1263              */
1264             @NonNull
setString(@onNull String name, @Nullable String value)1265             public Builder setString(@NonNull String name, @Nullable String value) {
1266                 mKeyValues.put(name, value);
1267                 return this;
1268             }
1269 
1270             /**
1271              * Add a new property with the specified key and value.
1272              * @param name non null name of the property.
1273              * @param value nullable string value of the property.
1274              * @return this Builder object
1275              */
1276             @NonNull
setBoolean(@onNull String name, boolean value)1277             public Builder setBoolean(@NonNull String name, boolean value) {
1278                 mKeyValues.put(name, Boolean.toString(value));
1279                 return this;
1280             }
1281 
1282             /**
1283              * Add a new property with the specified key and value.
1284              * @param name non null name of the property.
1285              * @param value int value of the property.
1286              * @return this Builder object
1287              */
1288             @NonNull
setInt(@onNull String name, int value)1289             public Builder setInt(@NonNull String name, int value) {
1290                 mKeyValues.put(name, Integer.toString(value));
1291                 return this;
1292             }
1293 
1294             /**
1295              * Add a new property with the specified key and value.
1296              * @param name non null name of the property.
1297              * @param value long value of the property.
1298              * @return this Builder object
1299              */
1300             @NonNull
setLong(@onNull String name, long value)1301             public Builder setLong(@NonNull String name, long value) {
1302                 mKeyValues.put(name, Long.toString(value));
1303                 return this;
1304             }
1305 
1306             /**
1307              * Add a new property with the specified key and value.
1308              * @param name non null name of the property.
1309              * @param value float value of the property.
1310              * @return this Builder object
1311              */
1312             @NonNull
setFloat(@onNull String name, float value)1313             public Builder setFloat(@NonNull String name, float value) {
1314                 mKeyValues.put(name, Float.toString(value));
1315                 return this;
1316             }
1317 
1318             /**
1319              * Create a new {@link Properties} object.
1320              * @return non null Properties.
1321              */
1322             @NonNull
build()1323             public Properties build() {
1324                 return new Properties(mNamespace, mKeyValues);
1325             }
1326         }
1327     }
1328 
1329 }
1330