• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     private static final Object sLock = new Object();
608     @GuardedBy("sLock")
609     private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
610             new ArrayMap<>();
611     @GuardedBy("sLock")
612     private static Map<String, Pair<ContentObserver, Integer>> sNamespaces = new HashMap<>();
613     private static final String TAG = "DeviceConfig";
614 
615     // Should never be invoked
DeviceConfig()616     private DeviceConfig() {
617     }
618 
619     /**
620      * Look up the value of a property for a particular namespace.
621      *
622      * @param namespace The namespace containing the property to look up.
623      * @param name      The name of the property to look up.
624      * @return the corresponding value, or null if not present.
625      * @hide
626      */
627     @SystemApi
628     @RequiresPermission(READ_DEVICE_CONFIG)
getProperty(@onNull String namespace, @NonNull String name)629     public static String getProperty(@NonNull String namespace, @NonNull String name) {
630         // Fetch all properties for the namespace at once and cache them in the local process, so we
631         // incur the cost of the IPC less often. Lookups happen much more frequently than updates,
632         // and we want to optimize the former.
633         return getProperties(namespace, name).getString(name, null);
634     }
635 
636     /**
637      * Look up the values of multiple properties for a particular namespace. The lookup is atomic,
638      * such that the values of these properties cannot change between the time when the first is
639      * fetched and the time when the last is fetched.
640      * <p>
641      * Each call to {@link #setProperties(Properties)} is also atomic and ensures that either none
642      * or all of the change is picked up here, but never only part of it.
643      *
644      * @param namespace The namespace containing the properties to look up.
645      * @param names     The names of properties to look up, or empty to fetch all properties for the
646      *                  given namespace.
647      * @return {@link Properties} object containing the requested properties. This reflects the
648      *     state of these properties at the time of the lookup, and is not updated to reflect any
649      *     future changes. The keyset of this Properties object will contain only the intersection
650      *     of properties already set and properties requested via the names parameter. Properties
651      *     that are already set but were not requested will not be contained here. Properties that
652      *     are not set, but were requested will not be contained here either.
653      * @hide
654      */
655     @SystemApi
656     @NonNull
657     @RequiresPermission(READ_DEVICE_CONFIG)
getProperties(@onNull String namespace, @NonNull String ... names)658     public static Properties getProperties(@NonNull String namespace, @NonNull String ... names) {
659         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
660         return new Properties(namespace,
661                 Settings.Config.getStrings(contentResolver, namespace, Arrays.asList(names)));
662     }
663 
664     /**
665      * Look up the String value of a property for a particular namespace.
666      *
667      * @param namespace    The namespace containing the property to look up.
668      * @param name         The name of the property to look up.
669      * @param defaultValue The value to return if the property does not exist or has no non-null
670      *                     value.
671      * @return the corresponding value, or defaultValue if none exists.
672      * @hide
673      */
674     @SystemApi
675     @RequiresPermission(READ_DEVICE_CONFIG)
getString(@onNull String namespace, @NonNull String name, @Nullable String defaultValue)676     public static String getString(@NonNull String namespace, @NonNull String name,
677             @Nullable String defaultValue) {
678         String value = getProperty(namespace, name);
679         return value != null ? value : defaultValue;
680     }
681 
682     /**
683      * Look up the boolean value of a property for a particular namespace.
684      *
685      * @param namespace The namespace containing the property to look up.
686      * @param name      The name of the property to look up.
687      * @param defaultValue The value to return if the property does not exist or has no non-null
688      *                     value.
689      * @return the correspondfing value, or defaultValue if none exists.
690      * @hide
691      */
692     @SystemApi
693     @RequiresPermission(READ_DEVICE_CONFIG)
getBoolean(@onNull String namespace, @NonNull String name, boolean defaultValue)694     public static boolean getBoolean(@NonNull String namespace, @NonNull String name,
695             boolean defaultValue) {
696         String value = getProperty(namespace, name);
697         return value != null ? Boolean.parseBoolean(value) : defaultValue;
698     }
699 
700     /**
701      * Look up the int value of a property for a particular namespace.
702      *
703      * @param namespace The namespace containing the property to look up.
704      * @param name      The name of the property to look up.
705      * @param defaultValue The value to return if the property does not exist, has no non-null
706      *                     value, or fails to parse into an int.
707      * @return the corresponding value, or defaultValue if either none exists or it does not parse.
708      * @hide
709      */
710     @SystemApi
711     @RequiresPermission(READ_DEVICE_CONFIG)
getInt(@onNull String namespace, @NonNull String name, int defaultValue)712     public static int getInt(@NonNull String namespace, @NonNull String name, int defaultValue) {
713         String value = getProperty(namespace, name);
714         if (value == null) {
715             return defaultValue;
716         }
717         try {
718             return Integer.parseInt(value);
719         } catch (NumberFormatException e) {
720             Log.e(TAG, "Parsing integer failed for " + namespace + ":" + name);
721             return defaultValue;
722         }
723     }
724 
725     /**
726      * Look up the long value of a property for a particular namespace.
727      *
728      * @param namespace The namespace containing the property to look up.
729      * @param name      The name of the property to look up.
730      * @param defaultValue The value to return if the property does not exist, has no non-null
731      *                     value, or fails to parse into a long.
732      * @return the corresponding value, or defaultValue if either none exists or it does not parse.
733      * @hide
734      */
735     @SystemApi
736     @RequiresPermission(READ_DEVICE_CONFIG)
getLong(@onNull String namespace, @NonNull String name, long defaultValue)737     public static long getLong(@NonNull String namespace, @NonNull String name, long defaultValue) {
738         String value = getProperty(namespace, name);
739         if (value == null) {
740             return defaultValue;
741         }
742         try {
743             return Long.parseLong(value);
744         } catch (NumberFormatException e) {
745             Log.e(TAG, "Parsing long failed for " + namespace + ":" + name);
746             return defaultValue;
747         }
748     }
749 
750     /**
751      * Look up the float value of a property for a particular namespace.
752      *
753      * @param namespace The namespace containing the property to look up.
754      * @param name      The name of the property to look up.
755      * @param defaultValue The value to return if the property does not exist, has no non-null
756      *                     value, or fails to parse into a float.
757      * @return the corresponding value, or defaultValue if either none exists or it does not parse.
758      * @hide
759      */
760     @SystemApi
761     @RequiresPermission(READ_DEVICE_CONFIG)
getFloat(@onNull String namespace, @NonNull String name, float defaultValue)762     public static float getFloat(@NonNull String namespace, @NonNull String name,
763             float defaultValue) {
764         String value = getProperty(namespace, name);
765         if (value == null) {
766             return defaultValue;
767         }
768         try {
769             return Float.parseFloat(value);
770         } catch (NumberFormatException e) {
771             Log.e(TAG, "Parsing float failed for " + namespace + ":" + name);
772             return defaultValue;
773         }
774     }
775 
776     /**
777      * Create a new property with the the provided name and value in the provided namespace, or
778      * update the value of such a property if it already exists. The same name can exist in multiple
779      * namespaces and might have different values in any or all namespaces.
780      * <p>
781      * The method takes an argument indicating whether to make the value the default for this
782      * property.
783      * <p>
784      * All properties stored for a particular scope can be reverted to their default values
785      * by passing the namespace to {@link #resetToDefaults(int, String)}.
786      *
787      * @param namespace   The namespace containing the property to create or update.
788      * @param name        The name of the property to create or update.
789      * @param value       The value to store for the property.
790      * @param makeDefault Whether to make the new value the default one.
791      * @return True if the value was set, false if the storage implementation throws errors.
792      * @hide
793      * @see #resetToDefaults(int, String).
794      */
795     @SystemApi
796     @RequiresPermission(WRITE_DEVICE_CONFIG)
setProperty(@onNull String namespace, @NonNull String name, @Nullable String value, boolean makeDefault)797     public static boolean setProperty(@NonNull String namespace, @NonNull String name,
798             @Nullable String value, boolean makeDefault) {
799         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
800         return Settings.Config.putString(contentResolver, namespace, name, value, makeDefault);
801     }
802 
803     /**
804      * Set all of the properties for a specific namespace. Pre-existing properties will be updated
805      * and new properties will be added if necessary. Any pre-existing properties for the specific
806      * namespace which are not part of the provided {@link Properties} object will be deleted from
807      * the namespace. These changes are all applied atomically, such that no calls to read or reset
808      * these properties can happen in the middle of this update.
809      * <p>
810      * Each call to {@link #getProperties(String, String...)} is also atomic and ensures that either
811      * none or all of this update is picked up, but never only part of it.
812      *
813      * @param properties the complete set of properties to set for a specific namespace.
814      * @throws BadConfigException if the provided properties are banned by RescueParty.
815      * @return True if the values were set, false otherwise.
816      * @hide
817      */
818     @SystemApi
819     @RequiresPermission(WRITE_DEVICE_CONFIG)
setProperties(@onNull Properties properties)820     public static boolean setProperties(@NonNull Properties properties) throws BadConfigException {
821         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
822         return Settings.Config.setStrings(contentResolver, properties.getNamespace(),
823                 properties.mMap);
824     }
825 
826     /**
827      * Reset properties to their default values by removing the underlying values.
828      * <p>
829      * The method accepts an optional namespace parameter. If provided, only properties set within
830      * that namespace will be reset. Otherwise, all properties will be reset.
831      * <p>
832      * Note: This method should only be used by {@link com.android.server.RescueParty}. It was
833      * designed to be used in the event of boot or crash loops caused by flag changes. It does not
834      * revert flag values to defaults - instead it removes the property entirely which causes the
835      * consumer of the flag to use hardcoded defaults upon retrieval.
836      * <p>
837      * To clear values for a namespace without removing the underlying properties, construct a
838      * {@link Properties} object with the caller's namespace and either an empty flag map, or some
839      * snapshot of flag values. Then use {@link #setProperties(Properties)} to remove all flags
840      * under the namespace, or set them to the values in the snapshot.
841      * <p>
842      * To revert values for testing, one should mock DeviceConfig using
843      * {@link com.android.server.testables.TestableDeviceConfig} where possible. Otherwise, fallback
844      * to using {@link #setProperties(Properties)} as outlined above.
845      *
846      * @param resetMode The reset mode to use.
847      * @param namespace Optionally, the specific namespace which resets will be limited to.
848      * @hide
849      * @see #setProperty(String, String, String, boolean)
850      */
851     @SystemApi
852     @RequiresPermission(WRITE_DEVICE_CONFIG)
resetToDefaults(@esetMode int resetMode, @Nullable String namespace)853     public static void resetToDefaults(@ResetMode int resetMode, @Nullable String namespace) {
854         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
855         Settings.Config.resetToDefaults(contentResolver, resetMode, namespace);
856     }
857 
858     /**
859      * Disables or re-enables bulk modifications ({@link #setProperties(Properties)}) to device
860      * config values. This is intended for use during tests to prevent a sync operation clearing
861      * config values, which could influence the outcome of the tests, i.e. by changing behavior.
862      *
863      * @param syncDisabledMode the mode to use, see {@link Settings.Config#SYNC_DISABLED_MODE_NONE},
864      *     {@link Settings.Config#SYNC_DISABLED_MODE_PERSISTENT} and {@link
865      *     Settings.Config#SYNC_DISABLED_MODE_UNTIL_REBOOT}
866      *
867      * @see #isSyncDisabled()
868      * @hide
869      */
870     @RequiresPermission(WRITE_DEVICE_CONFIG)
setSyncDisabled(@yncDisabledMode int syncDisabledMode)871     public static void setSyncDisabled(@SyncDisabledMode int syncDisabledMode) {
872         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
873         Settings.Config.setSyncDisabled(contentResolver, syncDisabledMode);
874     }
875 
876     /**
877      * Returns the current state of sync disabling, {@code true} when disabled, {@code false}
878      * otherwise.
879      *
880      * @see #setSyncDisabled(int)
881      * @hide
882      */
883     @RequiresPermission(WRITE_DEVICE_CONFIG)
isSyncDisabled()884     public static boolean isSyncDisabled() {
885         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
886         return Settings.Config.isSyncDisabled(contentResolver);
887     }
888 
889     /**
890      * Add a listener for property changes.
891      * <p>
892      * This listener will be called whenever properties in the specified namespace change. Callbacks
893      * will be made on the specified executor. Future calls to this method with the same listener
894      * will replace the old namespace and executor. Remove the listener entirely by calling
895      * {@link #removeOnPropertiesChangedListener(OnPropertiesChangedListener)}.
896      *
897      * @param namespace                   The namespace containing properties to monitor.
898      * @param executor                    The executor which will be used to run callbacks.
899      * @param onPropertiesChangedListener The listener to add.
900      * @hide
901      * @see #removeOnPropertiesChangedListener(OnPropertiesChangedListener)
902      */
903     @SystemApi
904     @RequiresPermission(READ_DEVICE_CONFIG)
addOnPropertiesChangedListener( @onNull String namespace, @NonNull @CallbackExecutor Executor executor, @NonNull OnPropertiesChangedListener onPropertiesChangedListener)905     public static void addOnPropertiesChangedListener(
906             @NonNull String namespace,
907             @NonNull @CallbackExecutor Executor executor,
908             @NonNull OnPropertiesChangedListener onPropertiesChangedListener) {
909         enforceReadPermission(ActivityThread.currentApplication().getApplicationContext(),
910                 namespace);
911         synchronized (sLock) {
912             Pair<String, Executor> oldNamespace = sListeners.get(onPropertiesChangedListener);
913             if (oldNamespace == null) {
914                 // Brand new listener, add it to the list.
915                 sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
916                 incrementNamespace(namespace);
917             } else if (namespace.equals(oldNamespace.first)) {
918                 // Listener is already registered for this namespace, update executor just in case.
919                 sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
920             } else {
921                 // Update this listener from an old namespace to the new one.
922                 decrementNamespace(sListeners.get(onPropertiesChangedListener).first);
923                 sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
924                 incrementNamespace(namespace);
925             }
926         }
927     }
928 
929     /**
930      * Remove a listener for property changes. The listener will receive no further notification of
931      * property changes.
932      *
933      * @param onPropertiesChangedListener The listener to remove.
934      * @hide
935      * @see #addOnPropertiesChangedListener(String, Executor, OnPropertiesChangedListener)
936      */
937     @SystemApi
removeOnPropertiesChangedListener( @onNull OnPropertiesChangedListener onPropertiesChangedListener)938     public static void removeOnPropertiesChangedListener(
939             @NonNull OnPropertiesChangedListener onPropertiesChangedListener) {
940         Preconditions.checkNotNull(onPropertiesChangedListener);
941         synchronized (sLock) {
942             if (sListeners.containsKey(onPropertiesChangedListener)) {
943                 decrementNamespace(sListeners.get(onPropertiesChangedListener).first);
944                 sListeners.remove(onPropertiesChangedListener);
945             }
946         }
947     }
948 
createNamespaceUri(@onNull String namespace)949     private static Uri createNamespaceUri(@NonNull String namespace) {
950         Preconditions.checkNotNull(namespace);
951         return CONTENT_URI.buildUpon().appendPath(namespace).build();
952     }
953 
954     /**
955      * Increment the count used to represent the number of listeners subscribed to the given
956      * namespace. If this is the first (i.e. incrementing from 0 to 1) for the given namespace, a
957      * ContentObserver is registered.
958      *
959      * @param namespace The namespace to increment the count for.
960      */
961     @GuardedBy("sLock")
incrementNamespace(@onNull String namespace)962     private static void incrementNamespace(@NonNull String namespace) {
963         Preconditions.checkNotNull(namespace);
964         Pair<ContentObserver, Integer> namespaceCount = sNamespaces.get(namespace);
965         if (namespaceCount != null) {
966             sNamespaces.put(namespace, new Pair<>(namespaceCount.first, namespaceCount.second + 1));
967         } else {
968             // This is a new namespace, register a ContentObserver for it.
969             ContentObserver contentObserver = new ContentObserver(null) {
970                 @Override
971                 public void onChange(boolean selfChange, Uri uri) {
972                     if (uri != null) {
973                         handleChange(uri);
974                     }
975                 }
976             };
977             ActivityThread.currentApplication().getContentResolver()
978                     .registerContentObserver(createNamespaceUri(namespace), true, contentObserver);
979             sNamespaces.put(namespace, new Pair<>(contentObserver, 1));
980         }
981     }
982 
983     /**
984      * Decrement the count used to represent the number of listeners subscribed to the given
985      * namespace. If this is the final decrement call (i.e. decrementing from 1 to 0) for the given
986      * namespace, the ContentObserver that had been tracking it will be removed.
987      *
988      * @param namespace The namespace to decrement the count for.
989      */
990     @GuardedBy("sLock")
decrementNamespace(@onNull String namespace)991     private static void decrementNamespace(@NonNull String namespace) {
992         Preconditions.checkNotNull(namespace);
993         Pair<ContentObserver, Integer> namespaceCount = sNamespaces.get(namespace);
994         if (namespaceCount == null) {
995             // This namespace is not registered and does not need to be decremented
996             return;
997         } else if (namespaceCount.second > 1) {
998             sNamespaces.put(namespace, new Pair<>(namespaceCount.first, namespaceCount.second - 1));
999         } else {
1000             // Decrementing a namespace to zero means we no longer need its ContentObserver.
1001             ActivityThread.currentApplication().getContentResolver()
1002                     .unregisterContentObserver(namespaceCount.first);
1003             sNamespaces.remove(namespace);
1004         }
1005     }
1006 
handleChange(@onNull Uri uri)1007     private static void handleChange(@NonNull Uri uri) {
1008         Preconditions.checkNotNull(uri);
1009         List<String> pathSegments = uri.getPathSegments();
1010         // pathSegments(0) is "config"
1011         final String namespace = pathSegments.get(1);
1012         Properties.Builder propBuilder = new Properties.Builder(namespace);
1013         try {
1014             Properties allProperties = getProperties(namespace);
1015             for (int i = 2; i < pathSegments.size(); ++i) {
1016                 String key = pathSegments.get(i);
1017                 propBuilder.setString(key, allProperties.getString(key, null));
1018             }
1019         } catch (SecurityException e) {
1020             // Silently failing to not crash binder or listener threads.
1021             Log.e(TAG, "OnPropertyChangedListener update failed: permission violation.");
1022             return;
1023         }
1024         Properties properties = propBuilder.build();
1025 
1026         synchronized (sLock) {
1027             for (int i = 0; i < sListeners.size(); i++) {
1028                 if (namespace.equals(sListeners.valueAt(i).first)) {
1029                     final OnPropertiesChangedListener listener = sListeners.keyAt(i);
1030                     sListeners.valueAt(i).second.execute(() -> {
1031                         listener.onPropertiesChanged(properties);
1032                     });
1033                 }
1034             }
1035         }
1036     }
1037 
1038     /**
1039      * Enforces READ_DEVICE_CONFIG permission if namespace is not one of public namespaces.
1040      * @hide
1041      */
enforceReadPermission(Context context, String namespace)1042     public static void enforceReadPermission(Context context, String namespace) {
1043         if (context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG)
1044                 != PackageManager.PERMISSION_GRANTED) {
1045             if (!PUBLIC_NAMESPACES.contains(namespace)) {
1046                 throw new SecurityException("Permission denial: reading from settings requires:"
1047                         + READ_DEVICE_CONFIG);
1048             }
1049         }
1050     }
1051 
1052     /**
1053      * Returns list of namespaces that can be read without READ_DEVICE_CONFIG_PERMISSION;
1054      * @hide
1055      */
getPublicNamespaces()1056     public static @NonNull List<String> getPublicNamespaces() {
1057         return PUBLIC_NAMESPACES;
1058     }
1059 
1060     /**
1061      * Interface for monitoring changes to properties. Implementations will receive callbacks when
1062      * properties change, including a {@link Properties} object which contains a single namespace
1063      * and all of the properties which changed for that namespace. This includes properties which
1064      * were added, updated, or deleted. This is not necessarily a complete list of all properties
1065      * belonging to the namespace, as properties which don't change are omitted.
1066      * <p>
1067      * Override {@link #onPropertiesChanged(Properties)} to handle callbacks for changes.
1068      *
1069      * @hide
1070      */
1071     @SystemApi
1072     public interface OnPropertiesChangedListener {
1073         /**
1074          * Called when one or more properties have changed, providing a Properties object with all
1075          * of the changed properties. This object will contain only properties which have changed,
1076          * not the complete set of all properties belonging to the namespace.
1077          *
1078          * @param properties Contains the complete collection of properties which have changed for a
1079          *                   single namespace. This includes only those which were added, updated,
1080          *                   or deleted.
1081          */
onPropertiesChanged(@onNull Properties properties)1082         void onPropertiesChanged(@NonNull Properties properties);
1083     }
1084 
1085     /**
1086      * Thrown by {@link #setProperties(Properties)} when a configuration is rejected. This
1087      * happens if RescueParty has identified a bad configuration and reset the namespace.
1088      *
1089      * @hide
1090      */
1091     @SystemApi
1092     public static class BadConfigException extends Exception {}
1093 
1094     /**
1095      * A mapping of properties to values, as well as a single namespace which they all belong to.
1096      *
1097      * @hide
1098      */
1099     @SystemApi
1100     public static class Properties {
1101         private final String mNamespace;
1102         private final HashMap<String, String> mMap;
1103         private Set<String> mKeyset;
1104 
1105         /**
1106          * Create a mapping of properties to values and the namespace they belong to.
1107          *
1108          * @param namespace The namespace these properties belong to.
1109          * @param keyValueMap A map between property names and property values.
1110          * @hide
1111          */
Properties(@onNull String namespace, @Nullable Map<String, String> keyValueMap)1112         public Properties(@NonNull String namespace, @Nullable Map<String, String> keyValueMap) {
1113             Preconditions.checkNotNull(namespace);
1114             mNamespace = namespace;
1115             mMap = new HashMap();
1116             if (keyValueMap != null) {
1117                 mMap.putAll(keyValueMap);
1118             }
1119         }
1120 
1121         /**
1122          * @return the namespace all properties within this instance belong to.
1123          */
1124         @NonNull
getNamespace()1125         public String getNamespace() {
1126             return mNamespace;
1127         }
1128 
1129         /**
1130          * @return the non-null set of property names.
1131          */
1132         @NonNull
getKeyset()1133         public Set<String> getKeyset() {
1134             if (mKeyset == null) {
1135                 mKeyset = Collections.unmodifiableSet(mMap.keySet());
1136             }
1137             return mKeyset;
1138         }
1139 
1140         /**
1141          * Look up the String value of a property.
1142          *
1143          * @param name         The name of the property to look up.
1144          * @param defaultValue The value to return if the property has not been defined.
1145          * @return the corresponding value, or defaultValue if none exists.
1146          */
1147         @Nullable
getString(@onNull String name, @Nullable String defaultValue)1148         public String getString(@NonNull String name, @Nullable String defaultValue) {
1149             Preconditions.checkNotNull(name);
1150             String value = mMap.get(name);
1151             return value != null ? value : defaultValue;
1152         }
1153 
1154         /**
1155          * Look up the boolean value of a property.
1156          *
1157          * @param name         The name of the property to look up.
1158          * @param defaultValue The value to return if the property has not been defined.
1159          * @return the corresponding value, or defaultValue if none exists.
1160          */
getBoolean(@onNull String name, boolean defaultValue)1161         public boolean getBoolean(@NonNull String name, boolean defaultValue) {
1162             Preconditions.checkNotNull(name);
1163             String value = mMap.get(name);
1164             return value != null ? Boolean.parseBoolean(value) : defaultValue;
1165         }
1166 
1167         /**
1168          * Look up the int value of a property.
1169          *
1170          * @param name         The name of the property to look up.
1171          * @param defaultValue The value to return if the property has not been defined or fails to
1172          *                     parse into an int.
1173          * @return the corresponding value, or defaultValue if no valid int is available.
1174          */
getInt(@onNull String name, int defaultValue)1175         public int getInt(@NonNull String name, int defaultValue) {
1176             Preconditions.checkNotNull(name);
1177             String value = mMap.get(name);
1178             if (value == null) {
1179                 return defaultValue;
1180             }
1181             try {
1182                 return Integer.parseInt(value);
1183             } catch (NumberFormatException e) {
1184                 Log.e(TAG, "Parsing int failed for " + name);
1185                 return defaultValue;
1186             }
1187         }
1188 
1189         /**
1190          * Look up the long value of a property.
1191          *
1192          * @param name         The name of the property to look up.
1193          * @param defaultValue The value to return if the property has not been defined. or fails to
1194          *                     parse into a long.
1195          * @return the corresponding value, or defaultValue if no valid long is available.
1196          */
getLong(@onNull String name, long defaultValue)1197         public long getLong(@NonNull String name, long defaultValue) {
1198             Preconditions.checkNotNull(name);
1199             String value = mMap.get(name);
1200             if (value == null) {
1201                 return defaultValue;
1202             }
1203             try {
1204                 return Long.parseLong(value);
1205             } catch (NumberFormatException e) {
1206                 Log.e(TAG, "Parsing long failed for " + name);
1207                 return defaultValue;
1208             }
1209         }
1210 
1211         /**
1212          * Look up the int value of a property.
1213          *
1214          * @param name         The name of the property to look up.
1215          * @param defaultValue The value to return if the property has not been defined. or fails to
1216          *                     parse into a float.
1217          * @return the corresponding value, or defaultValue if no valid float is available.
1218          */
getFloat(@onNull String name, float defaultValue)1219         public float getFloat(@NonNull String name, float defaultValue) {
1220             Preconditions.checkNotNull(name);
1221             String value = mMap.get(name);
1222             if (value == null) {
1223                 return defaultValue;
1224             }
1225             try {
1226                 return Float.parseFloat(value);
1227             } catch (NumberFormatException e) {
1228                 Log.e(TAG, "Parsing float failed for " + name);
1229                 return defaultValue;
1230             }
1231         }
1232 
1233         /**
1234          * Builder class for the construction of {@link Properties} objects.
1235          */
1236         public static final class Builder {
1237             @NonNull
1238             private final String mNamespace;
1239             @NonNull
1240             private final Map<String, String> mKeyValues = new HashMap<>();
1241 
1242             /**
1243              * Create a new Builders for the specified namespace.
1244              * @param namespace non null namespace.
1245              */
Builder(@onNull String namespace)1246             public Builder(@NonNull String namespace) {
1247                 mNamespace = namespace;
1248             }
1249 
1250             /**
1251              * Add a new property with the specified key and value.
1252              * @param name non null name of the property.
1253              * @param value nullable string value of the property.
1254              * @return this Builder object
1255              */
1256             @NonNull
setString(@onNull String name, @Nullable String value)1257             public Builder setString(@NonNull String name, @Nullable String value) {
1258                 mKeyValues.put(name, value);
1259                 return this;
1260             }
1261 
1262             /**
1263              * Add a new property with the specified key and value.
1264              * @param name non null name of the property.
1265              * @param value nullable string value of the property.
1266              * @return this Builder object
1267              */
1268             @NonNull
setBoolean(@onNull String name, boolean value)1269             public Builder setBoolean(@NonNull String name, boolean value) {
1270                 mKeyValues.put(name, Boolean.toString(value));
1271                 return this;
1272             }
1273 
1274             /**
1275              * Add a new property with the specified key and value.
1276              * @param name non null name of the property.
1277              * @param value int value of the property.
1278              * @return this Builder object
1279              */
1280             @NonNull
setInt(@onNull String name, int value)1281             public Builder setInt(@NonNull String name, int value) {
1282                 mKeyValues.put(name, Integer.toString(value));
1283                 return this;
1284             }
1285 
1286             /**
1287              * Add a new property with the specified key and value.
1288              * @param name non null name of the property.
1289              * @param value long value of the property.
1290              * @return this Builder object
1291              */
1292             @NonNull
setLong(@onNull String name, long value)1293             public Builder setLong(@NonNull String name, long value) {
1294                 mKeyValues.put(name, Long.toString(value));
1295                 return this;
1296             }
1297 
1298             /**
1299              * Add a new property with the specified key and value.
1300              * @param name non null name of the property.
1301              * @param value float value of the property.
1302              * @return this Builder object
1303              */
1304             @NonNull
setFloat(@onNull String name, float value)1305             public Builder setFloat(@NonNull String name, float value) {
1306                 mKeyValues.put(name, Float.toString(value));
1307                 return this;
1308             }
1309 
1310             /**
1311              * Create a new {@link Properties} object.
1312              * @return non null Properties.
1313              */
1314             @NonNull
build()1315             public Properties build() {
1316                 return new Properties(mNamespace, mKeyValues);
1317             }
1318         }
1319     }
1320 
1321 }
1322