• 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.WRITE_ALLOWLISTED_DEVICE_CONFIG;
20 import static android.Manifest.permission.READ_DEVICE_CONFIG;
21 import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
22 import static android.Manifest.permission.READ_WRITE_SYNC_DISABLED_MODE_CONFIG;
23 import static android.Manifest.permission.DUMP;
24 
25 import android.Manifest;
26 import android.annotation.CallbackExecutor;
27 import android.annotation.FlaggedApi;
28 import android.annotation.IntDef;
29 import android.annotation.NonNull;
30 import android.annotation.Nullable;
31 import android.annotation.RequiresPermission;
32 import android.annotation.SuppressLint;
33 import android.annotation.SystemApi;
34 import android.content.ContentResolver;
35 import android.database.ContentObserver;
36 import android.net.Uri;
37 import android.os.Binder;
38 import android.os.IBinder;
39 import android.os.ParcelFileDescriptor;
40 import android.provider.DeviceConfigServiceManager;
41 import android.provider.DeviceConfigInitializer;
42 import android.provider.aidl.IDeviceConfigManager;
43 import android.provider.flags.Flags;
44 import android.ravenwood.annotation.RavenwoodKeepWholeClass;
45 import android.ravenwood.annotation.RavenwoodRedirect;
46 import android.ravenwood.annotation.RavenwoodRedirectionClass;
47 import android.ravenwood.annotation.RavenwoodThrow;
48 import android.util.ArrayMap;
49 import android.util.ArraySet;
50 import android.util.Log;
51 import android.util.Pair;
52 import android.util.Slog;
53 
54 import com.android.internal.annotations.GuardedBy;
55 import com.android.modules.utils.build.SdkLevel;
56 
57 import java.io.FileDescriptor;
58 import java.io.PrintWriter;
59 import java.lang.annotation.ElementType;
60 import java.lang.annotation.Retention;
61 import java.lang.annotation.RetentionPolicy;
62 import java.lang.annotation.Target;
63 
64 import java.util.Arrays;
65 import java.util.Collections;
66 import java.util.Comparator;
67 import java.util.HashMap;
68 import java.util.HashSet;
69 import java.util.List;
70 import java.util.Map;
71 import java.util.Objects;
72 import java.util.Set;
73 import java.util.TreeMap;
74 import java.util.TreeSet;
75 import java.util.concurrent.Executor;
76 
77 /**
78  * Device level configuration parameters which can be tuned by a separate configuration service.
79  * Namespaces that end in "_native" such as {@link #NAMESPACE_NETD_NATIVE} are intended to be used
80  * by native code and should be pushed to system properties to make them accessible.
81  *
82  * @hide
83  */
84 @SystemApi
85 @RavenwoodKeepWholeClass
86 @RavenwoodRedirectionClass("DeviceConfig_host")
87 public final class DeviceConfig {
88 
89     /**
90      * The name of the service that provides the logic to these APIs
91      *
92      * @hide
93      */
94     public static final String SERVICE_NAME = "device_config_updatable";
95 
96     /**
97      * Namespace for all accessibility related features.
98      *
99      * @hide
100      */
101     @SystemApi
102     public static final String NAMESPACE_ACCESSIBILITY = "accessibility";
103 
104     /**
105      * Namespace for activity manager related features. These features will be applied
106      * immediately upon change.
107      *
108      * @hide
109      */
110     @SystemApi
111     public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
112 
113     /**
114      * Namespace for activity manager, specific to the "component alias" feature. We needed a
115      * different namespace in order to avoid phonetype from resetting it.
116      * @hide
117      */
118     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
119     public static final String NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS = "activity_manager_ca";
120 
121     /**
122      * Namespace for features related to auto pin confirmation.
123      *
124      * @hide
125      */
126     @SystemApi
127     public static final String NAMESPACE_AUTO_PIN_CONFIRMATION = "auto_pin_confirmation";
128 
129     /**
130      * Namespace for all activity manager related features that are used at the native level.
131      * These features are applied at reboot.
132      *
133      * @hide
134      */
135     @SystemApi
136     public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT =
137             "activity_manager_native_boot";
138 
139     /**
140      * Namespace for AlarmManager configurations.
141      *
142      * @hide
143      */
144     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
145     public static final String NAMESPACE_ALARM_MANAGER = "alarm_manager";
146 
147     /**
148      * Namespace for all app compat related features.  These features will be applied
149      * immediately upon change.
150      *
151      * @hide
152      */
153     @SystemApi
154     public static final String NAMESPACE_APP_COMPAT = "app_compat";
155 
156     /**
157      * Namespace for all app hibernation related features.
158      * @hide
159      */
160     @SystemApi
161     public static final String NAMESPACE_APP_HIBERNATION = "app_hibernation";
162 
163     /**
164      * Namespace for all AppSearch related features.
165      * @hide
166      */
167     @SystemApi
168     public static final String NAMESPACE_APPSEARCH = "appsearch";
169 
170     /**
171      * Namespace for app standby configurations.
172      *
173      * @hide
174      */
175     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
176     public static final String NAMESPACE_APP_STANDBY = "app_standby";
177 
178     /**
179      * Namespace for all App Cloning related features.
180      * @hide
181      */
182     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
183     public static final String NAMESPACE_APP_CLONING = "app_cloning";
184 
185     /**
186      * Namespace for AttentionManagerService related features.
187      *
188      * @hide
189      */
190     @SystemApi
191     public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
192 
193     /**
194      * Namespace for autofill feature that provides suggestions across all apps when
195      * the user interacts with input fields.
196      *
197      * @hide
198      */
199     @SystemApi
200     public static final String NAMESPACE_AUTOFILL = "autofill";
201 
202     /**
203      * Namespace for battery saver feature.
204      *
205      * @hide
206      */
207     @SystemApi
208     public static final String NAMESPACE_BATTERY_SAVER = "battery_saver";
209 
210     /**
211      * Namespace for holding battery stats configuration.
212      *
213      * @hide
214      */
215     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
216     public static final String NAMESPACE_BATTERY_STATS = "battery_stats";
217 
218     /**
219      * Namespace for blobstore feature that allows apps to share data blobs.
220      *
221      * @hide
222      */
223     @SystemApi
224     public static final String NAMESPACE_BLOBSTORE = "blobstore";
225 
226     /**
227      * Namespace for all Bluetooth related features.
228      *
229      * @hide
230      */
231     @SystemApi
232     public static final String NAMESPACE_BLUETOOTH = "bluetooth";
233 
234     /**
235      * Namespace for features relating to android core experiments team internal usage.
236      *
237      * @hide
238      */
239     @SystemApi
240     public static final String NAMESPACE_CORE_EXPERIMENTS_TEAM_INTERNAL = "core_experiments_team_internal";
241 
242     /**
243      * Namespace for all camera-related features that are used at the native level.
244      *
245      * @hide
246      */
247     @SystemApi
248     public static final String NAMESPACE_CAMERA_NATIVE = "camera_native";
249 
250     /**
251      * Namespace for cellular security related features.
252      *
253      * @hide
254      */
255     @SystemApi
256     public static final String NAMESPACE_CELLULAR_SECURITY = "cellular_security";
257 
258     /**
259      * Namespace for features relating to clipboard.
260      *
261      * @hide
262      */
263     @SystemApi
264     public static final String NAMESPACE_CLIPBOARD = "clipboard";
265 
266     /**
267      * Namespace for all networking connectivity related features.
268      *
269      * @hide
270      */
271     @SystemApi
272     public static final String NAMESPACE_CONNECTIVITY = "connectivity";
273 
274     /**
275      * Namespace for CaptivePortalLogin module.
276      *
277      * @hide
278      */
279     @SystemApi
280     public static final String NAMESPACE_CAPTIVEPORTALLOGIN = "captive_portal_login";
281 
282     /**
283      * Namespace for all EdgeTpu related features.
284      *
285      * @hide
286      */
287     @SystemApi
288     public static final String NAMESPACE_EDGETPU_NATIVE = "edgetpu_native";
289 
290     /**
291      * Namespace for all HealthFitness related features.
292      *
293      * @hide
294      */
295     @SystemApi
296     public static final String NAMESPACE_HEALTH_FITNESS = "health_fitness";
297 
298     /**
299      * Namespace for Tethering module.
300      *
301      * @hide
302      */
303     @SystemApi
304     public static final String NAMESPACE_TETHERING = "tethering";
305 
306 
307     /**
308      * Namespace for Nearby module.
309      *
310      * @hide
311      */
312     @SystemApi
313     public static final String NAMESPACE_NEARBY = "nearby";
314 
315     /**
316      * Namespace for content capture feature used by on-device machine intelligence
317      * to provide suggestions in a privacy-safe manner.
318      *
319      * @hide
320      */
321     @SystemApi
322     public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
323 
324     /**
325      * Namespace for credential manager.
326      *
327      * @hide
328      */
329     @SystemApi
330     public static final String NAMESPACE_CREDENTIAL = "credential_manager";
331 
332     /**
333      * Namespace for device idle configurations.
334      *
335      * @hide
336      */
337     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
338     public static final String NAMESPACE_DEVICE_IDLE = "device_idle";
339 
340     /**
341      * Namespace for how dex runs. The feature requires a reboot to reach a clean state.
342      *
343      * @deprecated No longer used
344      * @hide
345      */
346     @Deprecated
347     @SystemApi
348     public static final String NAMESPACE_DEX_BOOT = "dex_boot";
349 
350     /**
351      * Namespace for display manager related features. The names to access the properties in this
352      * namespace should be defined in {@link android.hardware.display.DisplayManager}.
353      *
354      * @hide
355      */
356     @SystemApi
357     public static final String NAMESPACE_DISPLAY_MANAGER = "display_manager";
358 
359     /**
360      * Namespace for all Game Driver features.
361      *
362      * @hide
363      */
364     @SystemApi
365     public static final String NAMESPACE_GAME_DRIVER = "game_driver";
366 
367     /**
368      * Namespace for all HDMI Control features.
369      *
370      * @hide
371      */
372     @SystemApi
373     public static final String NAMESPACE_HDMI_CONTROL = "hdmi_control";
374 
375     /**
376      * Namespace for all input-related features that are used at the native level.
377      * These features are applied at reboot.
378      *
379      * @hide
380      */
381     @SystemApi
382     public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
383 
384     /**
385      * Namespace for attention-based features provided by on-device machine intelligence.
386      *
387      * @hide
388      */
389     @SystemApi
390     public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
391 
392     /**
393      * Definitions for properties related to Content Suggestions.
394      *
395      * @hide
396      */
397     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
398     public static final String NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS =
399             "intelligence_content_suggestions";
400 
401     /**
402      * Namespace for JobScheduler configurations.
403      * @hide
404      */
405     @SystemApi
406     public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler";
407 
408     /**
409      * Namespace for all lmkd related features.
410      *
411      * @hide
412      */
413     @SystemApi
414     public static final String NAMESPACE_LMKD_NATIVE = "lmkd_native";
415 
416     /**
417      * Namespace for all location related features.
418      *
419      * @hide
420      */
421     @SystemApi
422     public static final String NAMESPACE_LOCATION = "location";
423 
424     /**
425      * Namespace for all media related features.
426      *
427      * @hide
428      */
429     @SystemApi
430     public static final String NAMESPACE_MEDIA = "media";
431 
432     /**
433      * Namespace for all media native related features.
434      *
435      * @hide
436      */
437     @SystemApi
438     public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
439 
440     /**
441      * Namespace for all Kernel Multi-Gen LRU feature.
442      *
443      * @hide
444      */
445     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
446     public static final String NAMESPACE_MGLRU_NATIVE = "mglru_native";
447 
448     /**
449      * Namespace for all memory management related features.
450      *
451      * @hide
452      */
453     @SystemApi
454     @FlaggedApi(Flags.FLAG_MMD_DEVICE_CONFIG)
455     public static final String NAMESPACE_MM = "mm";
456 
457     /**
458      * Namespace for all mmd native related features.
459      *
460      * @hide
461      */
462     @SystemApi
463     @FlaggedApi(Flags.FLAG_MMD_DEVICE_CONFIG)
464     public static final String NAMESPACE_MMD_NATIVE = "mmd_native";
465 
466     /**
467      * Namespace for all netd related features.
468      *
469      * @hide
470      */
471     @SystemApi
472     public static final String NAMESPACE_NETD_NATIVE = "netd_native";
473 
474     /**
475      * Namespace for all Android NNAPI related features.
476      *
477      * @hide
478      */
479     @SystemApi
480     public static final String NAMESPACE_NNAPI_NATIVE = "nnapi_native";
481 
482     /**
483      * Namespace for all OnDevicePersonalization related feature.
484      * @hide
485      */
486     @SystemApi
487     public static final String NAMESPACE_ON_DEVICE_PERSONALIZATION = "on_device_personalization";
488 
489     /**
490      * Namespace for features related to the Package Manager Service.
491      *
492      * @hide
493      */
494     @SystemApi
495     public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service";
496 
497     /**
498      * Namespace for features related to the Profcollect native Service.
499      * These features are applied at reboot.
500      *
501      * @hide
502      */
503     @SystemApi
504     public static final String NAMESPACE_PROFCOLLECT_NATIVE_BOOT = "profcollect_native_boot";
505 
506     /**
507      * Namespace for features related to Reboot Readiness detection.
508      *
509      * @hide
510      */
511     @SystemApi
512     public static final String NAMESPACE_REBOOT_READINESS = "reboot_readiness";
513 
514     /**
515      * Namespace for Remote Key Provisioning related features.
516      *
517      * @hide
518      */
519     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
520     public static final String NAMESPACE_REMOTE_KEY_PROVISIONING_NATIVE =
521             "remote_key_provisioning_native";
522 
523     /**
524      * Namespace for Rollback flags that are applied immediately.
525      *
526      * @hide
527      */
528     @SystemApi
529     public static final String NAMESPACE_ROLLBACK = "rollback";
530 
531     /**
532      * Namespace for Rollback flags that are applied after a reboot.
533      *
534      * @hide
535      */
536     @SystemApi
537     public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
538 
539     /**
540      * Namespace for Rotation Resolver Manager Service.
541      *
542      * @hide
543      */
544     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
545     public static final String NAMESPACE_ROTATION_RESOLVER = "rotation_resolver";
546 
547     /**
548      * Namespace for all runtime related features that don't require a reboot to become active.
549      * There are no feature flags using NAMESPACE_RUNTIME.
550      *
551      * @hide
552      */
553     @SystemApi
554     public static final String NAMESPACE_RUNTIME = "runtime";
555 
556     /**
557      * Namespace for all runtime related features that require system properties for accessing
558      * the feature flags from C++ or Java language code. One example is the app image startup
559      * cache feature use_app_image_startup_cache.
560      *
561      * @hide
562      */
563     @SystemApi
564     public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native";
565 
566     /**
567      * Namespace for all runtime native boot related features. Boot in this case refers to the
568      * fact that the properties only take effect after rebooting the device.
569      *
570      * @hide
571      */
572     @SystemApi
573     public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
574 
575     /**
576      * Namespace for system scheduler related features. These features will be applied
577      * immediately upon change.
578      *
579      * @hide
580      */
581     @SystemApi
582     public static final String NAMESPACE_SCHEDULER = "scheduler";
583 
584     /**
585      * Namespace for all SdkSandbox related features.
586      * @hide
587      */
588     @SystemApi
589     public static final String NAMESPACE_SDK_SANDBOX = "sdk_sandbox";
590 
591     /**
592      * Namespace for settings statistics features.
593      *
594      * @hide
595      */
596     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
597     public static final String NAMESPACE_SETTINGS_STATS = "settings_stats";
598 
599     /**
600      * Namespace for all statsd java features that can be applied immediately.
601      *
602      * @hide
603      */
604     @SystemApi
605     public static final String NAMESPACE_STATSD_JAVA = "statsd_java";
606 
607     /**
608      * Namespace for all statsd java features that are applied on boot.
609      *
610      * @hide
611      */
612     @SystemApi
613     public static final String NAMESPACE_STATSD_JAVA_BOOT = "statsd_java_boot";
614 
615     /**
616      * Namespace for all statsd native features that can be applied immediately.
617      *
618      * @hide
619      */
620     @SystemApi
621     public static final String NAMESPACE_STATSD_NATIVE = "statsd_native";
622 
623     /**
624      * Namespace for all statsd native features that are applied on boot.
625      *
626      * @hide
627      */
628     @SystemApi
629     public static final String NAMESPACE_STATSD_NATIVE_BOOT = "statsd_native_boot";
630 
631     /**
632      * Namespace for storage-related features.
633      *
634      * @deprecated Replace storage namespace with storage_native_boot.
635      * @hide
636      */
637     @Deprecated
638     @SystemApi
639     public static final String NAMESPACE_STORAGE = "storage";
640 
641     /**
642      * Namespace for storage-related features, including native and boot.
643      *
644      * @hide
645      */
646     @SystemApi
647     public static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot";
648 
649     /**
650      * Namespace for all AdServices related features.
651      * @hide
652      */
653     @SystemApi
654     public static final String NAMESPACE_ADSERVICES = "adservices";
655 
656     /**
657      * Namespace for all SurfaceFlinger features that are used at the native level.
658      * These features are applied on boot or after reboot.
659      *
660      * @hide
661      */
662     @SystemApi
663     public static final String NAMESPACE_SURFACE_FLINGER_NATIVE_BOOT =
664             "surface_flinger_native_boot";
665 
666     /**
667      * Namespace for swcodec native related features.
668      *
669      * @hide
670      */
671     @SystemApi
672     public static final String NAMESPACE_SWCODEC_NATIVE = "swcodec_native";
673 
674 
675     /**
676      * Namespace for System UI related features.
677      *
678      * @hide
679      */
680     @SystemApi
681     public static final String NAMESPACE_SYSTEMUI = "systemui";
682 
683     /**
684      * Namespace for system time and time zone detection related features / behavior.
685      *
686      * @hide
687      */
688     @SystemApi
689     public static final String NAMESPACE_SYSTEM_TIME = "system_time";
690 
691     /**
692      * Namespace for TARE configurations.
693      *
694      * @hide
695      */
696     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
697     public static final String NAMESPACE_TARE = "tare";
698 
699     /**
700      * Telephony related properties.
701      *
702      * @hide
703      */
704     @SystemApi
705     public static final String NAMESPACE_TELEPHONY = "telephony";
706 
707     /**
708      * Namespace for TextClassifier related features.
709      *
710      * @hide
711      * @see android.provider.Settings.Global.TEXT_CLASSIFIER_CONSTANTS
712      */
713     @SystemApi
714     public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier";
715 
716     /**
717      * Namespace for contacts provider related features.
718      *
719      * @hide
720      */
721     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
722     public static final String NAMESPACE_CONTACTS_PROVIDER = "contacts_provider";
723 
724     /**
725      * Namespace for settings ui related features
726      *
727      * @hide
728      */
729     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
730     public static final String NAMESPACE_SETTINGS_UI = "settings_ui";
731 
732     /**
733      * Namespace for android related features, i.e. for flags that affect not just a single
734      * component, but the entire system.
735      *
736      * The keys for this namespace are defined in {@link AndroidDeviceConfig}.
737      *
738      * @hide
739      */
740     @SystemApi
741     public static final String NAMESPACE_ANDROID = "android";
742 
743     /**
744      * Namespace for window manager related features.
745      *
746      * @hide
747      */
748     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
749     public static final String NAMESPACE_WINDOW_MANAGER = "window_manager";
750 
751     /**
752      * Namespace for window manager features accessible by native code and
753      * loaded once per boot.
754      *
755      * @hide
756      */
757     @SystemApi
758     public static final String NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT = "window_manager_native_boot";
759 
760     /**
761      * Definitions for selection toolbar related functions.
762      *
763      * @hide
764      */
765     @SystemApi
766     public static final String NAMESPACE_SELECTION_TOOLBAR = "selection_toolbar";
767 
768     /**
769      * Definitions for voice interaction related functions.
770      *
771      * @hide
772      */
773     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
774     public static final String NAMESPACE_VOICE_INTERACTION = "voice_interaction";
775 
776     /**
777      * Namespace for DevicePolicyManager related features.
778      *
779      * @hide
780      */
781     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
782     public static final String NAMESPACE_DEVICE_POLICY_MANAGER =
783             "device_policy_manager";
784 
785     /**
786      * List of namespaces which can be read without READ_DEVICE_CONFIG permission
787      *
788      * @hide
789      */
790     @NonNull
791     private static final List<String> PUBLIC_NAMESPACES =
792             Arrays.asList(NAMESPACE_TEXTCLASSIFIER, NAMESPACE_RUNTIME, NAMESPACE_STATSD_JAVA,
793                     NAMESPACE_STATSD_JAVA_BOOT, NAMESPACE_SELECTION_TOOLBAR, NAMESPACE_AUTOFILL,
794                     NAMESPACE_DEVICE_POLICY_MANAGER, NAMESPACE_CONTENT_CAPTURE);
795     /**
796      * Privacy related properties definitions.
797      *
798      * @hide
799      */
800     @SystemApi
801     public static final String NAMESPACE_PRIVACY = "privacy";
802 
803     /**
804      * Namespace for biometrics related features
805      *
806      * @hide
807      */
808     @SystemApi
809     public static final String NAMESPACE_BIOMETRICS = "biometrics";
810 
811     /**
812      * Permission related properties definitions.
813      *
814      * @hide
815      */
816     @SystemApi
817     public static final String NAMESPACE_PERMISSIONS = "permissions";
818 
819     /**
820      * Namespace for ota related features.
821      *
822      * @hide
823      */
824     @SystemApi
825     public static final String NAMESPACE_OTA = "ota";
826 
827     /**
828      * Namespace for all widget related features.
829      *
830      * @hide
831      */
832     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
833     public static final String NAMESPACE_WIDGET = "widget";
834 
835     /**
836      * Namespace for connectivity thermal power manager features.
837      *
838      * @hide
839      */
840     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
841     public static final String NAMESPACE_CONNECTIVITY_THERMAL_POWER_MANAGER =
842             "connectivity_thermal_power_manager";
843 
844     /**
845      * Namespace for configuration related features.
846      *
847      * @hide
848      */
849     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
850     public static final String NAMESPACE_CONFIGURATION = "configuration";
851 
852     /**
853      * LatencyTracker properties definitions.
854      *
855      * @hide
856      */
857     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
858     public static final String NAMESPACE_LATENCY_TRACKER = "latency_tracker";
859 
860     /**
861      * InteractionJankMonitor properties definitions.
862      *
863      * @hide
864      */
865     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
866     @SuppressLint("IntentName")
867     public static final String NAMESPACE_INTERACTION_JANK_MONITOR = "interaction_jank_monitor";
868 
869     /**
870      * Namespace for game overlay related features.
871      *
872      * @hide
873      */
874     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
875     public static final String NAMESPACE_GAME_OVERLAY = "game_overlay";
876 
877     /**
878      * Namespace for Android Virtualization Framework related features accessible by native code.
879      *
880      * @hide
881      */
882     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
883     public static final String NAMESPACE_VIRTUALIZATION_FRAMEWORK_NATIVE =
884             "virtualization_framework_native";
885 
886     /**
887      * Namespace for Constrain Display APIs related features.
888      *
889      * @hide
890      */
891     @SystemApi
892     public static final String NAMESPACE_CONSTRAIN_DISPLAY_APIS = "constrain_display_apis";
893 
894     /**
895      * Namespace for App Compat Overrides related features.
896      *
897      * @hide
898      */
899     @SystemApi
900     public static final String NAMESPACE_APP_COMPAT_OVERRIDES = "app_compat_overrides";
901 
902     /**
903      * Namespace for all ultra wideband (uwb) related features.
904      *
905      * @hide
906      */
907     @SystemApi
908     public static final String NAMESPACE_UWB = "uwb";
909 
910     /**
911      * Namespace for AmbientContextEventManagerService related features.
912      *
913      * @hide
914      */
915     @SystemApi
916     public static final String NAMESPACE_AMBIENT_CONTEXT_MANAGER_SERVICE =
917             "ambient_context_manager_service";
918 
919     /**
920      * Namespace for WearableSensingManagerService related features.
921      *
922      * @hide
923      */
924     @SystemApi
925     public static final String NAMESPACE_WEARABLE_SENSING =
926             "wearable_sensing";
927 
928     /**
929      * Namespace for Vendor System Native related features.
930      *
931      * @hide
932      */
933     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
934     public static final String NAMESPACE_VENDOR_SYSTEM_NATIVE = "vendor_system_native";
935 
936     /**
937      * Namespace for Vendor System Native Boot related features.
938      *
939      * @hide
940      */
941     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
942     public static final String NAMESPACE_VENDOR_SYSTEM_NATIVE_BOOT = "vendor_system_native_boot";
943 
944     /**
945      * Namespace for memory safety related features (e.g. MTE) that need a reboot to be applied
946      *
947      * @hide
948      */
949     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
950     public static final String NAMESPACE_MEMORY_SAFETY_NATIVE_BOOT = "memory_safety_native_boot";
951 
952     /**
953      * Namespace for memory safety related features (e.g. MTE)
954      *
955      * @hide
956      */
957     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
958     public static final String NAMESPACE_MEMORY_SAFETY_NATIVE = "memory_safety_native";
959 
960     /**
961      * Namespace for wear OS platform features.
962      *
963      * @hide
964      */
965     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
966     public static final String NAMESPACE_WEAR = "wear";
967 
968     /**
969      * Namespace for the input method manager platform features.
970      *
971      * @hide
972      */
973     @SystemApi
974     public static final String NAMESPACE_INPUT_METHOD_MANAGER = "input_method_manager";
975 
976     /**
977      * Namespace for backup and restore service related features.
978      *
979      * @hide
980      */
981     @SystemApi
982     public static final String NAMESPACE_BACKUP_AND_RESTORE = "backup_and_restore";
983 
984     /**
985      * Namespace for ARC App Compat related features.
986      *
987      * @hide
988      */
989     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
990     public static final String NAMESPACE_ARC_APP_COMPAT = "arc_app_compat";
991 
992     /**
993      * Namespace for remote authentication features.
994      *
995      * @hide
996      */
997     @SystemApi
998     public static final String NAMESPACE_REMOTE_AUTH = "remote_auth";
999 
1000 
1001     /**
1002      * Namespace for tethering module native features.
1003      * Flags defined in this namespace are only usable on
1004      * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and newer.
1005      * On older Android releases, they will not be propagated to native code.
1006      *
1007      * @hide
1008      */
1009     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
1010     public static final String NAMESPACE_TETHERING_NATIVE =
1011             "tethering_u_or_later_native";
1012 
1013     /**
1014      * Namespace for all near field communication (nfc) related features.
1015      *
1016      * @hide
1017      */
1018     @SystemApi
1019     public static final String NAMESPACE_NFC = "nfc";
1020 
1021     /**
1022      * The modes that can be used when disabling syncs to the 'config' settings.
1023      * @hide
1024      */
1025     @IntDef(prefix = "SYNC_DISABLED_MODE_",
1026             value = { SYNC_DISABLED_MODE_NONE, SYNC_DISABLED_MODE_PERSISTENT,
1027                     SYNC_DISABLED_MODE_UNTIL_REBOOT })
1028     @Retention(RetentionPolicy.SOURCE)
1029     @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
1030     public @interface SyncDisabledMode {}
1031 
1032     /**
1033      * Sync is not disabled.
1034      *
1035      * @hide
1036      */
1037     @SystemApi
1038     public static final int SYNC_DISABLED_MODE_NONE = 0;
1039 
1040     /**
1041      * Disabling of Config bulk update / syncing is persistent, i.e. it survives a device
1042      * reboot.
1043      *
1044      * @hide
1045      */
1046     @SystemApi
1047     public static final int SYNC_DISABLED_MODE_PERSISTENT = 1;
1048 
1049     /**
1050      * Disabling of Config bulk update / syncing is not persistent, i.e. it will
1051      * not survive a device reboot.
1052      *
1053      * @hide
1054      */
1055     @SystemApi
1056     public static final int SYNC_DISABLED_MODE_UNTIL_REBOOT = 2;
1057 
1058 
1059     // NOTE: this API is only used by the framework code, but using MODULE_LIBRARIES causes a
1060     // build-time error on CtsDeviceConfigTestCases, so it's using PRIVILEGED_APPS.
1061     /**
1062      * Optional argument to {@link #dump(ParcelFileDescriptor, PrintWriter, String, String[])} to
1063      * indicate that the next argument is a namespace. How {@code dump()} will handle that
1064      * argument is documented there.
1065      *
1066      * @hide
1067      */
1068     @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
1069     @FlaggedApi(Flags.FLAG_DUMP_IMPROVEMENTS)
1070     public static final String DUMP_ARG_NAMESPACE = "--namespace";
1071 
1072     private static final Object sLock = new Object();
1073     @GuardedBy("sLock")
1074     private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
1075             new ArrayMap<>();
1076     @GuardedBy("sLock")
1077     private static Map<String, Pair<ContentObserver, Integer>> sNamespaces = new HashMap<>();
1078     private static final String TAG = "DeviceConfig";
1079     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
1080 
1081     private static final DeviceConfigDataStore sDataStore = newDataStore();
1082 
1083     @RavenwoodRedirect
newDataStore()1084     private static DeviceConfigDataStore newDataStore() {
1085         return new SettingsConfigDataStore();
1086     }
1087 
1088     private static final String DEVICE_CONFIG_OVERRIDES_NAMESPACE =
1089             "device_config_overrides";
1090 
1091     /**
1092      * Interface for monitoring callback functions.
1093      *
1094      * @hide
1095      */
1096     @SystemApi
1097     public interface MonitorCallback {
1098         /**
1099          * Callback for updating a namespace.
1100          * Reports that a config in the given namespace has changed.
1101          * Isn't called for {@link DeviceConfig#getPublicNamespaces() public namespaces}.
1102          *
1103          * @param updatedNamespace the namespace, within which at least one config has changed.
1104          * @hide
1105          */
1106         @SystemApi
onNamespaceUpdate(@onNull String updatedNamespace)1107         void onNamespaceUpdate(@NonNull String updatedNamespace);
1108 
1109         /**
1110          * Callback for accessing device config.
1111          * Reports an access to a the given namespace and the given calling package.
1112          * Isn't called for {@link DeviceConfig#getPublicNamespaces() public namespaces}.
1113          *
1114          * @param callingPackage the calling package id.
1115          * @param namespace the namespace, within which one of its config has been accessed.
1116          * @hide
1117          */
1118         @SystemApi
onDeviceConfigAccess(@onNull String callingPackage, @NonNull String namespace)1119         void onDeviceConfigAccess(@NonNull String callingPackage, @NonNull String namespace);
1120     }
1121 
1122     // Should never be invoked
DeviceConfig()1123     private DeviceConfig() {
1124     }
1125 
1126     /**
1127      * Look up the value of a property for a particular namespace.
1128      *
1129      * @param namespace The namespace containing the property to look up.
1130      * @param name      The name of the property to look up.
1131      * @return the corresponding value, or null if not present.
1132      * @hide
1133      */
1134     @SystemApi
1135     @Nullable
getProperty(@onNull String namespace, @NonNull String name)1136     public static String getProperty(@NonNull String namespace, @NonNull String name) {
1137         // Fetch all properties for the namespace at once and cache them in the local process, so we
1138         // incur the cost of the IPC less often. Lookups happen much more frequently than updates,
1139         // and we want to optimize the former.
1140         return getProperties(namespace, name).getString(name, null);
1141     }
1142 
1143     /**
1144      * Look up the values of multiple properties for a particular namespace. The lookup is atomic,
1145      * such that the values of these properties cannot change between the time when the first is
1146      * fetched and the time when the last is fetched.
1147      * <p>
1148      * Each call to {@link #setProperties(Properties)} is also atomic and ensures that either none
1149      * or all of the change is picked up here, but never only part of it.
1150      *
1151      * If there are any local overrides applied, they will take precedence over underlying values.
1152      *
1153      * @param namespace The namespace containing the properties to look up.
1154      * @param names     The names of properties to look up, or empty to fetch all properties for the
1155      *                  given namespace.
1156      * @return {@link Properties} object containing the requested properties. This reflects the
1157      *     state of these properties at the time of the lookup, and is not updated to reflect any
1158      *     future changes. The keyset of this Properties object will contain only the intersection
1159      *     of properties already set and properties requested via the names parameter. Properties
1160      *     that are already set but were not requested will not be contained here. Properties that
1161      *     are not set, but were requested will not be contained here either.
1162      * @hide
1163      */
1164     @SystemApi
1165     @NonNull
1166     @RequiresPermission(READ_DEVICE_CONFIG)
getProperties(@onNull String namespace, @NonNull String... names)1167     public static Properties getProperties(@NonNull String namespace, @NonNull String... names) {
1168         Properties properties = getPropertiesWithoutOverrides(namespace, names);
1169         if (SdkLevel.isAtLeastV()) {
1170             applyOverrides(properties);
1171         }
1172         return properties;
1173     }
1174 
1175     @NonNull
getPropertiesWithoutOverrides(@onNull String namespace, @NonNull String... names)1176     private static Properties getPropertiesWithoutOverrides(@NonNull String namespace,
1177         @NonNull String... names) {
1178         return sDataStore.getProperties(namespace, names);
1179     }
1180 
applyOverrides(@onNull Properties properties)1181     private static void applyOverrides(@NonNull Properties properties) {
1182         Properties overrides =
1183                 getPropertiesWithoutOverrides(DEVICE_CONFIG_OVERRIDES_NAMESPACE);
1184 
1185         final String prefix = properties.getNamespace() + ':';
1186         final int prefixLength = prefix.length();
1187 
1188         for (var override : overrides.getMap().entrySet()) {
1189             String fullKey = override.getKey();
1190             String value = override.getValue();
1191             if (value != null && fullKey.startsWith(prefix)) {
1192                 properties.setString(fullKey.substring(prefixLength), value);
1193             }
1194         }
1195     }
1196 
1197     /**
1198      * List all stored flags.
1199      *
1200      * The keys take the form {@code namespace/name}, and the values are the flag values.
1201      *
1202      * @hide
1203      */
1204     @SystemApi
1205     @NonNull
getAllProperties()1206     public static Set<Properties> getAllProperties() {
1207         Map<String, String> properties = sDataStore.getAllProperties();
1208         Map<String, Map<String, String>> propertyMaps = new HashMap<>();
1209         for (String flag : properties.keySet()) {
1210             String[] namespaceAndFlag = flag.split("/");
1211             String namespace = namespaceAndFlag[0];
1212             String flagName = namespaceAndFlag[1];
1213             String override =
1214                     getProperty(DEVICE_CONFIG_OVERRIDES_NAMESPACE, namespace + ":" + flagName);
1215 
1216             String value = override != null ? override : properties.get(flag);
1217 
1218             if (!propertyMaps.containsKey(namespace)) {
1219                 propertyMaps.put(namespace, new HashMap<>());
1220             }
1221             propertyMaps.get(namespace).put(flagName, value);
1222         }
1223 
1224         HashSet<Properties> result = new HashSet<>();
1225         for (Map.Entry<String, Map<String, String>> entry : propertyMaps.entrySet()) {
1226             result.add(new Properties(entry.getKey(), entry.getValue()));
1227         }
1228         return result;
1229     }
1230 
1231     /**
1232      * Look up the String value of a property for a particular namespace.
1233      *
1234      * @param namespace    The namespace containing the property to look up.
1235      * @param name         The name of the property to look up.
1236      * @param defaultValue The value to return if the property does not exist or has no non-null
1237      *                     value.
1238      * @return the corresponding value, or defaultValue if none exists.
1239      * @hide
1240      */
1241     @SystemApi
1242     @RequiresPermission(READ_DEVICE_CONFIG)
1243     @Nullable
getString(@onNull String namespace, @NonNull String name, @Nullable String defaultValue)1244     public static String getString(@NonNull String namespace, @NonNull String name,
1245             @Nullable String defaultValue) {
1246         String value = getProperty(namespace, name);
1247         return value != null ? value : defaultValue;
1248     }
1249 
1250     /**
1251      * Look up the boolean value of a property for a particular namespace.
1252      *
1253      * @param namespace The namespace containing the property to look up.
1254      * @param name      The name of the property to look up.
1255      * @param defaultValue The value to return if the property does not exist or has no non-null
1256      *                     value.
1257      * @return the corresponding value, or defaultValue if none exists.
1258      * @hide
1259      */
1260     @SystemApi
getBoolean(@onNull String namespace, @NonNull String name, boolean defaultValue)1261     public static boolean getBoolean(@NonNull String namespace, @NonNull String name,
1262             boolean defaultValue) {
1263         String value = getProperty(namespace, name);
1264         return value != null ? Boolean.parseBoolean(value) : defaultValue;
1265     }
1266 
1267     /**
1268      * Look up the int value of a property for a particular namespace.
1269      *
1270      * @param namespace The namespace containing the property to look up.
1271      * @param name      The name of the property to look up.
1272      * @param defaultValue The value to return if the property does not exist, has no non-null
1273      *                     value, or fails to parse into an int.
1274      * @return the corresponding value, or defaultValue if either none exists or it does not parse.
1275      * @hide
1276      */
1277     @SystemApi
1278     @RequiresPermission(READ_DEVICE_CONFIG)
getInt(@onNull String namespace, @NonNull String name, int defaultValue)1279     public static int getInt(@NonNull String namespace, @NonNull String name, int defaultValue) {
1280         String value = getProperty(namespace, name);
1281         if (value == null) {
1282             return defaultValue;
1283         }
1284         try {
1285             return Integer.parseInt(value);
1286         } catch (NumberFormatException e) {
1287             Slog.e(TAG, "Parsing integer failed for " + namespace + ":" + name);
1288             return defaultValue;
1289         }
1290     }
1291 
1292     /**
1293      * Look up the long value of a property for a particular namespace.
1294      *
1295      * @param namespace The namespace containing the property to look up.
1296      * @param name      The name of the property to look up.
1297      * @param defaultValue The value to return if the property does not exist, has no non-null
1298      *                     value, or fails to parse into a long.
1299      * @return the corresponding value, or defaultValue if either none exists or it does not parse.
1300      * @hide
1301      */
1302     @SystemApi
1303     @RequiresPermission(READ_DEVICE_CONFIG)
getLong(@onNull String namespace, @NonNull String name, long defaultValue)1304     public static long getLong(@NonNull String namespace, @NonNull String name, long defaultValue) {
1305         String value = getProperty(namespace, name);
1306         if (value == null) {
1307             return defaultValue;
1308         }
1309         try {
1310             return Long.parseLong(value);
1311         } catch (NumberFormatException e) {
1312             Slog.e(TAG, "Parsing long failed for " + namespace + ":" + name);
1313             return defaultValue;
1314         }
1315     }
1316 
1317     /**
1318      * Look up the float value of a property for a particular namespace.
1319      *
1320      * @param namespace The namespace containing the property to look up.
1321      * @param name      The name of the property to look up.
1322      * @param defaultValue The value to return if the property does not exist, has no non-null
1323      *                     value, or fails to parse into a float.
1324      * @return the corresponding value, or defaultValue if either none exists or it does not parse.
1325      * @hide
1326      */
1327     @SystemApi
1328     @RequiresPermission(READ_DEVICE_CONFIG)
getFloat(@onNull String namespace, @NonNull String name, float defaultValue)1329     public static float getFloat(@NonNull String namespace, @NonNull String name,
1330             float defaultValue) {
1331         String value = getProperty(namespace, name);
1332         if (value == null) {
1333             return defaultValue;
1334         }
1335         try {
1336             return Float.parseFloat(value);
1337         } catch (NumberFormatException e) {
1338             Slog.e(TAG, "Parsing float failed for " + namespace + ":" + name);
1339             return defaultValue;
1340         }
1341     }
1342 
1343     /**
1344      * Set flag {@code namespace/name} to {@code value}, and ignores server-updates for this flag.
1345      *
1346      * Can still be called even if there is no underlying value set.
1347      *
1348      * Returns {@code true} if successful, or {@code false} if the storage implementation throws
1349      * errors.
1350      *
1351      * @hide
1352      */
1353     @SystemApi
1354     @RequiresPermission(WRITE_DEVICE_CONFIG)
setLocalOverride(@onNull String namespace, @NonNull String name, @NonNull String value)1355     public static boolean setLocalOverride(@NonNull String namespace, @NonNull String name,
1356         @NonNull String value) {
1357         return setProperty(DEVICE_CONFIG_OVERRIDES_NAMESPACE, namespace + ":" + name, value, false);
1358     }
1359 
1360     /**
1361      * Clear all local sticky overrides.
1362      *
1363      * @hide
1364      */
1365     @SystemApi
1366     @RequiresPermission(WRITE_DEVICE_CONFIG)
clearAllLocalOverrides()1367     public static void clearAllLocalOverrides() {
1368         Properties overrides = getProperties(DEVICE_CONFIG_OVERRIDES_NAMESPACE);
1369         for (String overrideName : overrides.getKeyset()) {
1370             deleteProperty(DEVICE_CONFIG_OVERRIDES_NAMESPACE, overrideName);
1371         }
1372     }
1373 
1374     /**
1375      * Clear local sticky override for flag {@code namespace/name}.
1376      *
1377      * @hide
1378      */
1379     @SystemApi
1380     @RequiresPermission(WRITE_DEVICE_CONFIG)
clearLocalOverride(@onNull String namespace, @NonNull String name)1381     public static void clearLocalOverride(@NonNull String namespace,
1382         @NonNull String name) {
1383         deleteProperty(DEVICE_CONFIG_OVERRIDES_NAMESPACE, namespace + ":" + name);
1384     }
1385 
1386     /**
1387      * Return a map containing all flags that have been overridden.
1388      *
1389      * The keys of the outer map are namespaces. They keys of the inner maps are
1390      * flag names. The values of the inner maps are the underlying flag values
1391      * (not to be confused with their overridden values).
1392      *
1393      * @hide
1394      */
1395     @NonNull
1396     @SystemApi
getUnderlyingValuesForOverriddenFlags()1397     public static Map<String, Map<String, String>> getUnderlyingValuesForOverriddenFlags() {
1398         Properties overrides = getProperties(DEVICE_CONFIG_OVERRIDES_NAMESPACE);
1399         HashMap<String, Map<String, String>> result = new HashMap<>();
1400         for (Map.Entry<String, String> entry : overrides.getPropertyValues().entrySet()) {
1401             String[] namespaceAndFlag = entry.getKey().split(":");
1402             String namespace = namespaceAndFlag[0];
1403             String flag = namespaceAndFlag[1];
1404 
1405             String actualValue =
1406                     getPropertiesWithoutOverrides(namespace, flag)
1407                     .getString(flag, null);
1408             if (result.get(namespace) != null) {
1409                 result.get(namespace).put(flag, actualValue);
1410             } else {
1411                 HashMap<String, String> innerMap = new HashMap<>();
1412                 innerMap.put(flag, actualValue);
1413                 result.put(namespace, innerMap);
1414             }
1415         }
1416         return result;
1417     }
1418 
1419     /**
1420      * Create a new property with the provided name and value in the provided namespace, or
1421      * update the value of such a property if it already exists. The same name can exist in multiple
1422      * namespaces and might have different values in any or all namespaces.
1423      * <p>
1424      * The method takes an argument indicating whether to make the value the default for this
1425      * property.
1426      * <p>
1427      * All properties stored for a particular scope can be reverted to their default values
1428      * by passing the namespace to {@link #resetToDefaults(int, String)}.
1429      *
1430      * @param namespace   The namespace containing the property to create or update.
1431      * @param name        The name of the property to create or update.
1432      * @param value       The value to store for the property.
1433      * @param makeDefault Whether to make the new value the default one.
1434      * @return {@code true} if the value was set, {@code false} if the storage implementation throws
1435      * errors.
1436      * @hide
1437      * @see #resetToDefaults(int, String).
1438      */
1439     @SystemApi
1440     @RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG})
setProperty(@onNull String namespace, @NonNull String name, @Nullable String value, boolean makeDefault)1441     public static boolean setProperty(@NonNull String namespace, @NonNull String name,
1442             @Nullable String value, boolean makeDefault) {
1443         return sDataStore.setProperty(namespace, name, value, makeDefault);
1444     }
1445 
1446     /**
1447      * Set all of the properties for a specific namespace. Pre-existing properties will be updated
1448      * and new properties will be added if necessary. Any pre-existing properties for the specific
1449      * namespace which are not part of the provided {@link Properties} object will be deleted from
1450      * the namespace. These changes are all applied atomically, such that no calls to read or reset
1451      * these properties can happen in the middle of this update.
1452      * <p>
1453      * Each call to {@link #getProperties(String, String...)} is also atomic and ensures that either
1454      * none or all of this update is picked up, but never only part of it.
1455      *
1456      * @param properties the complete set of properties to set for a specific namespace.
1457      * @throws BadConfigException if the provided properties are banned by RescueParty.
1458      * @return {@code true} if the values were set, {@code false} otherwise.
1459      * @hide
1460      */
1461     @SystemApi
1462     @RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG})
setProperties(@onNull Properties properties)1463     public static boolean setProperties(@NonNull Properties properties) throws BadConfigException {
1464         return sDataStore.setProperties(properties);
1465     }
1466 
1467     /**
1468      * Delete a property with the provided name and value in the provided namespace
1469      *
1470      * @param namespace   The namespace containing the property to delete.
1471      * @param name        The name of the property to delete.
1472      * @return {@code true} if the property was deleted or it did not exist in the first place.
1473      * Return {@code false} if the storage implementation throws errors.
1474      * @hide
1475      */
1476     @SystemApi
1477     @RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG})
deleteProperty(@onNull String namespace, @NonNull String name)1478     public static boolean deleteProperty(@NonNull String namespace, @NonNull String name) {
1479         return sDataStore.deleteProperty(namespace, name);
1480     }
1481 
1482     /**
1483      * Reset properties to their default values by removing the underlying values.
1484      * <p>
1485      * The method accepts an optional namespace parameter. If provided, only properties set within
1486      * that namespace will be reset. Otherwise, all properties will be reset.
1487      * <p>
1488      * Note: This method should only be used by {@link com.android.server.RescueParty}. It was
1489      * designed to be used in the event of boot or crash loops caused by flag changes. It does not
1490      * revert flag values to defaults - instead it removes the property entirely which causes the
1491      * consumer of the flag to use hardcoded defaults upon retrieval.
1492      * <p>
1493      * To clear values for a namespace without removing the underlying properties, construct a
1494      * {@link Properties} object with the caller's namespace and either an empty flag map, or some
1495      * snapshot of flag values. Then use {@link #setProperties(Properties)} to remove all flags
1496      * under the namespace, or set them to the values in the snapshot.
1497      * <p>
1498      * To revert values for testing, one should mock DeviceConfig using
1499      * {@link com.android.server.testables.TestableDeviceConfig} where possible. Otherwise, fallback
1500      * to using {@link #setProperties(Properties)} as outlined above.
1501      *
1502      * @param resetMode The reset mode to use.
1503      * @param namespace Optionally, the specific namespace which resets will be limited to.
1504      * @hide
1505      * @see #setProperty(String, String, String, boolean)
1506      */
1507     @SystemApi
1508     @RavenwoodThrow
1509     @RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG})
resetToDefaults(int resetMode, @Nullable String namespace)1510     public static void resetToDefaults(int resetMode, @Nullable String namespace) {
1511         sDataStore.resetToDefaults(resetMode, namespace);
1512     }
1513 
1514     /**
1515      * Disables or re-enables bulk modifications ({@link #setProperties(Properties)}) to device
1516      * config values. This is intended for use during tests to prevent a sync operation clearing
1517      * config values which could influence the outcome of the tests, i.e. by changing behavior.
1518      *
1519      * @param syncDisabledMode the mode to use, see {@link Settings.Config#SYNC_DISABLED_MODE_NONE},
1520      *     {@link Settings.Config#SYNC_DISABLED_MODE_PERSISTENT} and {@link
1521      *     Settings.Config#SYNC_DISABLED_MODE_UNTIL_REBOOT}
1522      *
1523      * @see #getSyncDisabledMode()
1524      * @hide
1525      */
1526     @SystemApi
1527     @RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, READ_WRITE_SYNC_DISABLED_MODE_CONFIG})
setSyncDisabledMode(int syncDisabledMode)1528     public static void setSyncDisabledMode(int syncDisabledMode) {
1529         sDataStore.setSyncDisabledMode(syncDisabledMode);
1530     }
1531 
1532     /**
1533      * Returns the current mode of sync disabling.
1534      *
1535      * @see #setSyncDisabledMode(int)
1536      * @hide
1537      */
1538     @SystemApi
1539     @RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, READ_WRITE_SYNC_DISABLED_MODE_CONFIG})
getSyncDisabledMode()1540     public static int getSyncDisabledMode() {
1541         return sDataStore.getSyncDisabledMode();
1542     }
1543 
1544     /**
1545      * Add a listener for property changes.
1546      * <p>
1547      * This listener will be called whenever properties in the specified namespace change. Callbacks
1548      * will be made on the specified executor. Future calls to this method with the same listener
1549      * will replace the old namespace and executor. Remove the listener entirely by calling
1550      * {@link #removeOnPropertiesChangedListener(OnPropertiesChangedListener)}.
1551      *
1552      * @param namespace                   The namespace containing properties to monitor.
1553      * @param executor                    The executor which will be used to run callbacks.
1554      * @param onPropertiesChangedListener The listener to add.
1555      * @hide
1556      * @see #removeOnPropertiesChangedListener(OnPropertiesChangedListener)
1557      */
1558     @SystemApi
addOnPropertiesChangedListener( @onNull String namespace, @NonNull @CallbackExecutor Executor executor, @NonNull OnPropertiesChangedListener onPropertiesChangedListener)1559     public static void addOnPropertiesChangedListener(
1560             @NonNull String namespace,
1561             @NonNull @CallbackExecutor Executor executor,
1562             @NonNull OnPropertiesChangedListener onPropertiesChangedListener) {
1563         synchronized (sLock) {
1564             Pair<String, Executor> oldNamespace = sListeners.get(onPropertiesChangedListener);
1565             if (oldNamespace == null) {
1566                 // Brand new listener, add it to the list.
1567                 sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
1568                 incrementNamespace(namespace);
1569             } else if (namespace.equals(oldNamespace.first)) {
1570                 // Listener is already registered for this namespace, update executor just in case.
1571                 sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
1572             } else {
1573                 // Update this listener from an old namespace to the new one.
1574                 decrementNamespace(sListeners.get(onPropertiesChangedListener).first);
1575                 sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
1576                 incrementNamespace(namespace);
1577             }
1578         }
1579     }
1580 
1581     // NOTE: this API is only used by the framework code, but using MODULE_LIBRARIES causes a
1582     // build-time error on CtsDeviceConfigTestCases, so it's using PRIVILEGED_APPS.
1583     /**
1584      * Dumps internal state into the given {@code fd} or {@code printWriter}.
1585      *
1586      * <p><b>Note:</b> Currently the only supported argument is {@link #DUMP_ARG_NAMESPACE} which
1587      * will filter the output using a substring of the next argument. But other arguments might be
1588      * dynamically added in the future, without documentation - this method is meant only for
1589      * debugging purposes, and should not be used as a formal API.
1590      *
1591      * @param printWriter print writer that will output the dump state.
1592      * @param prefix prefix added to each line
1593      * @param args (optional) arguments passed by {@code dumpsys}.
1594      *
1595      * @hide
1596      */
1597     @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
1598     @FlaggedApi(Flags.FLAG_DUMP_IMPROVEMENTS)
dump(@onNull PrintWriter printWriter, @NonNull String dumpPrefix, @Nullable String[] args)1599     public static void dump(@NonNull PrintWriter printWriter, @NonNull String dumpPrefix,
1600             @Nullable String[] args) {
1601         if (DEBUG) {
1602             Slog.d(TAG, "dump(): args=" + Arrays.toString(args));
1603         }
1604         Objects.requireNonNull(printWriter, "printWriter cannot be null");
1605 
1606         Comparator<OnPropertiesChangedListener> comparator = (o1, o2) -> o1.toString()
1607                 .compareTo(o2.toString());
1608         TreeMap<String, Set<OnPropertiesChangedListener>> listenersByNamespace  =
1609                 new TreeMap<>();
1610         ArraySet<OnPropertiesChangedListener> uniqueListeners = new ArraySet<>();
1611         String filter = null;
1612         if (args.length > 0) {
1613             switch (args[0]) {
1614                 case DUMP_ARG_NAMESPACE:
1615                     if (args.length < 2) {
1616                         throw new IllegalArgumentException(
1617                                 "argument " + DUMP_ARG_NAMESPACE + " requires an extra argument");
1618                     }
1619                     filter = args[1];
1620                     if (DEBUG) {
1621                         Slog.d(TAG, "dump(): setting filter as " + filter);
1622                     }
1623                     break;
1624                 default:
1625                     Slog.w(TAG, "dump(): ignoring invalid arguments: " + Arrays.toString(args));
1626                     break;
1627             }
1628         }
1629         int listenersSize;
1630         synchronized (sLock) {
1631             listenersSize = sListeners.size();
1632             for (int i = 0; i < listenersSize; i++) {
1633                 var namespace = sListeners.valueAt(i).first;
1634                 if (filter != null && !namespace.contains(filter)) {
1635                     continue;
1636                 }
1637                 var listener = sListeners.keyAt(i);
1638                 var listeners = listenersByNamespace.get(namespace);
1639                 if (listeners == null) {
1640                     // Life would be so much easier if Android provided a MultiMap implementation...
1641                     listeners = new TreeSet<>(comparator);
1642                     listenersByNamespace.put(namespace, listeners);
1643                 }
1644                 listeners.add(listener);
1645                 uniqueListeners.add(listener);
1646             }
1647         }
1648         printWriter.printf("%s%d listeners for %d namespaces:\n", dumpPrefix, uniqueListeners.size(),
1649                 listenersByNamespace.size());
1650         for (var entry : listenersByNamespace.entrySet()) {
1651             var namespace = entry.getKey();
1652             var listeners = entry.getValue();
1653             printWriter.printf("%s%s: %d listeners\n", dumpPrefix, namespace, listeners.size());
1654             for (var listener : listeners) {
1655                 printWriter.printf("%s%s%s\n", dumpPrefix, dumpPrefix, listener);
1656             }
1657         }
1658     }
1659 
1660     /**
1661      * Remove a listener for property changes. The listener will receive no further notification of
1662      * property changes.
1663      *
1664      * @param onPropertiesChangedListener The listener to remove.
1665      * @hide
1666      * @see #addOnPropertiesChangedListener(String, Executor, OnPropertiesChangedListener)
1667      */
1668     @SystemApi
removeOnPropertiesChangedListener( @onNull OnPropertiesChangedListener onPropertiesChangedListener)1669     public static void removeOnPropertiesChangedListener(
1670             @NonNull OnPropertiesChangedListener onPropertiesChangedListener) {
1671         Objects.requireNonNull(onPropertiesChangedListener);
1672         synchronized (sLock) {
1673             if (sListeners.containsKey(onPropertiesChangedListener)) {
1674                 decrementNamespace(sListeners.get(onPropertiesChangedListener).first);
1675                 sListeners.remove(onPropertiesChangedListener);
1676             }
1677         }
1678     }
1679 
1680     /**
1681      * Setter callback for monitoring Config table.
1682      *
1683      * @param executor the {@link Executor} on which to invoke the callback
1684      * @param callback callback to set
1685      *
1686      * @hide
1687      */
1688     @SystemApi
1689     @RavenwoodThrow
1690     @RequiresPermission(Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS)
setMonitorCallback( @onNull ContentResolver resolver, @NonNull @CallbackExecutor Executor executor, @NonNull MonitorCallback callback)1691     public static void setMonitorCallback(
1692             @NonNull ContentResolver resolver,
1693             @NonNull @CallbackExecutor Executor executor,
1694             @NonNull MonitorCallback callback) {
1695         sDataStore.setMonitorCallback(resolver, executor, callback);
1696     }
1697 
1698     /**
1699      * Clear callback for monitoring Config table.
1700      * this may only be used to clear callback function registered by
1701      * {@link DeviceConfig#setMonitorCallback}
1702      * @hide
1703      */
1704     @SystemApi
1705     @RavenwoodThrow
1706     @RequiresPermission(Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS)
clearMonitorCallback(@onNull ContentResolver resolver)1707     public static void clearMonitorCallback(@NonNull ContentResolver resolver) {
1708         sDataStore.clearMonitorCallback(resolver);
1709     }
1710 
1711     /**
1712      * Increment the count used to represent the number of listeners subscribed to the given
1713      * namespace. If this is the first (i.e. incrementing from 0 to 1) for the given namespace, a
1714      * ContentObserver is registered.
1715      *
1716      * @param namespace The namespace to increment the count for.
1717      */
1718     @GuardedBy("sLock")
incrementNamespace(@onNull String namespace)1719     private static void incrementNamespace(@NonNull String namespace) {
1720         Objects.requireNonNull(namespace);
1721         Pair<ContentObserver, Integer> namespaceCount = sNamespaces.get(namespace);
1722         if (namespaceCount != null) {
1723             sNamespaces.put(namespace, new Pair<>(namespaceCount.first, namespaceCount.second + 1));
1724         } else {
1725             // This is a new namespace, register a ContentObserver for it.
1726             ContentObserver contentObserver = new ContentObserver(null) {
1727                 @Override
1728                 public void onChange(boolean selfChange, Uri uri) {
1729                     if (uri != null) {
1730                         handleChange(uri);
1731                     }
1732                 }
1733             };
1734             sDataStore
1735                     .registerContentObserver(namespace, true, contentObserver);
1736             sNamespaces.put(namespace, new Pair<>(contentObserver, 1));
1737         }
1738     }
1739 
1740     /**
1741      * Decrement the count used to represent the number of listeners subscribed to the given
1742      * namespace. If this is the final decrement call (i.e. decrementing from 1 to 0) for the given
1743      * namespace, the ContentObserver that had been tracking it will be removed.
1744      *
1745      * @param namespace The namespace to decrement the count for.
1746      */
1747     @GuardedBy("sLock")
decrementNamespace(@onNull String namespace)1748     private static void decrementNamespace(@NonNull String namespace) {
1749         Objects.requireNonNull(namespace);
1750         Pair<ContentObserver, Integer> namespaceCount = sNamespaces.get(namespace);
1751         if (namespaceCount == null) {
1752             // This namespace is not registered and does not need to be decremented
1753             return;
1754         } else if (namespaceCount.second > 1) {
1755             sNamespaces.put(namespace, new Pair<>(namespaceCount.first, namespaceCount.second - 1));
1756         } else {
1757             // Decrementing a namespace to zero means we no longer need its ContentObserver.
1758             sDataStore.unregisterContentObserver(namespaceCount.first);
1759             sNamespaces.remove(namespace);
1760         }
1761     }
1762 
handleChange(@onNull Uri uri)1763     private static void handleChange(@NonNull Uri uri) {
1764         Objects.requireNonNull(uri);
1765         List<String> pathSegments = uri.getPathSegments();
1766         // pathSegments(0) is "config"
1767         final String namespace = pathSegments.get(1);
1768         final Properties properties;
1769         if (pathSegments.size() > 2) {
1770             String[] keys = new String[pathSegments.size() - 2];
1771             for (int i = 2; i < pathSegments.size(); ++i) {
1772                 keys[i - 2] = pathSegments.get(i);
1773             }
1774 
1775             try {
1776                 properties = getProperties(namespace, keys);
1777             } catch (SecurityException e) {
1778                 // Silently failing to not crash binder or listener threads.
1779                 Slog.e(TAG, "OnPropertyChangedListener update failed: permission violation.");
1780                 return;
1781             }
1782 
1783             // Make sure all keys are present.
1784             for (String key : keys) {
1785                 properties.setString(key, properties.getString(key, null));
1786             }
1787         } else {
1788             properties = new Properties.Builder(namespace).build();
1789         }
1790 
1791         synchronized (sLock) {
1792             for (int i = 0; i < sListeners.size(); i++) {
1793                 if (namespace.equals(sListeners.valueAt(i).first)) {
1794                     final OnPropertiesChangedListener listener = sListeners.keyAt(i);
1795                     sListeners.valueAt(i).second.execute(() -> {
1796                         listener.onPropertiesChanged(properties);
1797                     });
1798                 }
1799             }
1800         }
1801     }
1802 
1803     /**
1804      * Returns list of namespaces that can be read without READ_DEVICE_CONFIG_PERMISSION;
1805      * @hide
1806      */
1807     @SystemApi
getPublicNamespaces()1808     public static @NonNull List<String> getPublicNamespaces() {
1809         return PUBLIC_NAMESPACES;
1810     }
1811 
1812     /**
1813      * Returns list of flags that can be written with adb as non-root.
1814      * @hide
1815      */
1816     @SystemApi
getAdbWritableFlags()1817     public static @NonNull Set<String> getAdbWritableFlags() {
1818         return WritableFlags.ALLOWLIST;
1819     }
1820 
1821     /**
1822      * Returns the list of namespaces in which all flags can be written with adb as non-root.
1823      * @hide
1824      */
1825     @SystemApi
1826     @FlaggedApi(Flags.FLAG_DEVICE_CONFIG_WRITABLE_NAMESPACES_API)
getAdbWritableNamespaces()1827     public static @NonNull Set<String> getAdbWritableNamespaces() {
1828         return WritableNamespaces.ALLOWLIST;
1829     }
1830 
1831     /**
1832      * Interface for monitoring changes to properties. Implementations will receive callbacks when
1833      * properties change, including a {@link Properties} object which contains a single namespace
1834      * and all of the properties which changed for that namespace. This includes properties which
1835      * were added, updated, or deleted. This is not necessarily a complete list of all properties
1836      * belonging to the namespace, as properties which don't change are omitted.
1837      * <p>
1838      * Override {@link #onPropertiesChanged(Properties)} to handle callbacks for changes.
1839      *
1840      * @hide
1841      */
1842     @SystemApi
1843     public interface OnPropertiesChangedListener {
1844         /**
1845          * Called when one or more properties have changed, providing a Properties object with all
1846          * of the changed properties. This object will contain only properties which have changed,
1847          * not the complete set of all properties belonging to the namespace.
1848          *
1849          * @param properties Contains the complete collection of properties which have changed for a
1850          *                   single namespace. This includes only those which were added, updated,
1851          *                   or deleted.
1852          */
onPropertiesChanged(@onNull Properties properties)1853         void onPropertiesChanged(@NonNull Properties properties);
1854     }
1855 
1856     /**
1857      * Thrown by {@link #setProperties(Properties)} when a configuration is rejected. This
1858      * happens if RescueParty has identified a bad configuration and reset the namespace.
1859      *
1860      * @hide
1861      */
1862     @SystemApi
1863     public static class BadConfigException extends Exception {}
1864 
1865     /**
1866      * A mapping of properties to values, as well as a single namespace which they all belong to.
1867      *
1868      * @hide
1869      */
1870     @SystemApi
1871     public static class Properties {
1872         private final String mNamespace;
1873         private final HashMap<String, String> mMap;
1874         private Set<String> mKeyset;
1875 
1876         /**
1877          * Create a mapping of properties to values and the namespace they belong to.
1878          *
1879          * @param namespace The namespace these properties belong to.
1880          * @param keyValueMap A map between property names and property values.
1881          * @hide
1882          */
1883         @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Properties(@onNull String namespace, @Nullable Map<String, String> keyValueMap)1884         public Properties(@NonNull String namespace, @Nullable Map<String, String> keyValueMap) {
1885             Objects.requireNonNull(namespace);
1886             mNamespace = namespace;
1887             mMap = new HashMap();
1888             if (keyValueMap != null) {
1889                 mMap.putAll(keyValueMap);
1890             }
1891         }
1892 
1893         /**
1894          * @return the namespace all properties within this instance belong to.
1895          */
1896         @NonNull
getNamespace()1897         public String getNamespace() {
1898             return mNamespace;
1899         }
1900 
1901         /**
1902          * @return the non-null set of property names.
1903          */
1904         @NonNull
getKeyset()1905         public Set<String> getKeyset() {
1906             if (mKeyset == null) {
1907                 mKeyset = Collections.unmodifiableSet(mMap.keySet());
1908             }
1909             return mKeyset;
1910         }
1911 
1912         /**
1913          * Look up the String value of a property.
1914          *
1915          * @param name         The name of the property to look up.
1916          * @param defaultValue The value to return if the property has not been defined.
1917          * @return the corresponding value, or defaultValue if none exists.
1918          */
1919         @Nullable
getString(@onNull String name, @Nullable String defaultValue)1920         public String getString(@NonNull String name, @Nullable String defaultValue) {
1921             Objects.requireNonNull(name);
1922             String value = mMap.get(name);
1923             return value != null ? value : defaultValue;
1924         }
1925 
1926         @Nullable
setString(@onNull String name, @Nullable String value)1927         private String setString(@NonNull String name, @Nullable String value) {
1928             Objects.requireNonNull(name);
1929             mKeyset = null;
1930             return mMap.put(name, value);
1931         }
1932 
1933         @NonNull
getMap()1934         private Map<String, String> getMap() {
1935             return mMap;
1936         }
1937 
1938         /**
1939          * Look up the boolean value of a property.
1940          *
1941          * @param name         The name of the property to look up.
1942          * @param defaultValue The value to return if the property has not been defined.
1943          * @return the corresponding value, or defaultValue if none exists.
1944          */
getBoolean(@onNull String name, boolean defaultValue)1945         public boolean getBoolean(@NonNull String name, boolean defaultValue) {
1946             Objects.requireNonNull(name);
1947             String value = mMap.get(name);
1948             return value != null ? Boolean.parseBoolean(value) : defaultValue;
1949         }
1950 
1951         /**
1952          * Look up the int value of a property.
1953          *
1954          * @param name         The name of the property to look up.
1955          * @param defaultValue The value to return if the property has not been defined or fails to
1956          *                     parse into an int.
1957          * @return the corresponding value, or defaultValue if no valid int is available.
1958          */
getInt(@onNull String name, int defaultValue)1959         public int getInt(@NonNull String name, int defaultValue) {
1960             Objects.requireNonNull(name);
1961             String value = mMap.get(name);
1962             if (value == null) {
1963                 return defaultValue;
1964             }
1965             try {
1966                 return Integer.parseInt(value);
1967             } catch (NumberFormatException e) {
1968                 Slog.e(TAG, "Parsing int failed for " + name);
1969                 return defaultValue;
1970             }
1971         }
1972 
1973         /**
1974          * Look up the long value of a property.
1975          *
1976          * @param name         The name of the property to look up.
1977          * @param defaultValue The value to return if the property has not been defined. or fails to
1978          *                     parse into a long.
1979          * @return the corresponding value, or defaultValue if no valid long is available.
1980          */
getLong(@onNull String name, long defaultValue)1981         public long getLong(@NonNull String name, long defaultValue) {
1982             Objects.requireNonNull(name);
1983             String value = mMap.get(name);
1984             if (value == null) {
1985                 return defaultValue;
1986             }
1987             try {
1988                 return Long.parseLong(value);
1989             } catch (NumberFormatException e) {
1990                 Slog.e(TAG, "Parsing long failed for " + name);
1991                 return defaultValue;
1992             }
1993         }
1994 
1995         /**
1996          * Look up the int value of a property.
1997          *
1998          * @param name         The name of the property to look up.
1999          * @param defaultValue The value to return if the property has not been defined. or fails to
2000          *                     parse into a float.
2001          * @return the corresponding value, or defaultValue if no valid float is available.
2002          */
getFloat(@onNull String name, float defaultValue)2003         public float getFloat(@NonNull String name, float defaultValue) {
2004             Objects.requireNonNull(name);
2005             String value = mMap.get(name);
2006             if (value == null) {
2007                 return defaultValue;
2008             }
2009             try {
2010                 return Float.parseFloat(value);
2011             } catch (NumberFormatException e) {
2012                 Slog.e(TAG, "Parsing float failed for " + name);
2013                 return defaultValue;
2014             }
2015         }
2016 
2017         /**
2018          * Returns a map with the underlying property values defined by this object
2019          *
2020          * @hide
2021          */
getPropertyValues()2022         public @NonNull Map<String, String> getPropertyValues() {
2023             return Collections.unmodifiableMap(mMap);
2024         }
2025 
2026         /**
2027          * Builder class for the construction of {@link Properties} objects.
2028          */
2029         public static final class Builder {
2030             @NonNull
2031             private final String mNamespace;
2032             @NonNull
2033             private final Map<String, String> mKeyValues = new HashMap<>();
2034 
2035             /**
2036              * Create a new Builders for the specified namespace.
2037              * @param namespace non null namespace.
2038              */
Builder(@onNull String namespace)2039             public Builder(@NonNull String namespace) {
2040                 mNamespace = namespace;
2041             }
2042 
2043             /**
2044              * Add a new property with the specified key and value.
2045              * @param name non null name of the property.
2046              * @param value nullable string value of the property.
2047              * @return this Builder object
2048              */
2049             @NonNull
setString(@onNull String name, @Nullable String value)2050             public Builder setString(@NonNull String name, @Nullable String value) {
2051                 mKeyValues.put(name, value);
2052                 return this;
2053             }
2054 
2055             /**
2056              * Add a new property with the specified key and value.
2057              * @param name non null name of the property.
2058              * @param value nullable string value of the property.
2059              * @return this Builder object
2060              */
2061             @NonNull
setBoolean(@onNull String name, boolean value)2062             public Builder setBoolean(@NonNull String name, boolean value) {
2063                 mKeyValues.put(name, Boolean.toString(value));
2064                 return this;
2065             }
2066 
2067             /**
2068              * Add a new property with the specified key and value.
2069              * @param name non null name of the property.
2070              * @param value int value of the property.
2071              * @return this Builder object
2072              */
2073             @NonNull
setInt(@onNull String name, int value)2074             public Builder setInt(@NonNull String name, int value) {
2075                 mKeyValues.put(name, Integer.toString(value));
2076                 return this;
2077             }
2078 
2079             /**
2080              * Add a new property with the specified key and value.
2081              * @param name non null name of the property.
2082              * @param value long value of the property.
2083              * @return this Builder object
2084              */
2085             @NonNull
setLong(@onNull String name, long value)2086             public Builder setLong(@NonNull String name, long value) {
2087                 mKeyValues.put(name, Long.toString(value));
2088                 return this;
2089             }
2090 
2091             /**
2092              * Add a new property with the specified key and value.
2093              * @param name non null name of the property.
2094              * @param value float value of the property.
2095              * @return this Builder object
2096              */
2097             @NonNull
setFloat(@onNull String name, float value)2098             public Builder setFloat(@NonNull String name, float value) {
2099                 mKeyValues.put(name, Float.toString(value));
2100                 return this;
2101             }
2102 
2103             /**
2104              * Create a new {@link Properties} object.
2105              * @return non null Properties.
2106              */
2107             @NonNull
build()2108             public Properties build() {
2109                 return new Properties(mNamespace, mKeyValues);
2110             }
2111         }
2112     }
2113 
2114 }
2115