• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 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.os;
18 
19 import android.util.Log;
20 import android.util.MutableInt;
21 
22 import com.android.internal.annotations.GuardedBy;
23 
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 
27 
28 /**
29  * Gives access to the system properties store.  The system properties
30  * store contains a list of string key-value pairs.
31  *
32  * {@hide}
33  */
34 public class SystemProperties {
35     private static final String TAG = "SystemProperties";
36     private static final boolean TRACK_KEY_ACCESS = false;
37 
38     /**
39      * Android O removed the property name length limit, but com.amazon.kindle 7.8.1.5
40      * uses reflection to read this whenever text is selected (http://b/36095274).
41      */
42     public static final int PROP_NAME_MAX = Integer.MAX_VALUE;
43 
44     public static final int PROP_VALUE_MAX = 91;
45 
46     private static final ArrayList<Runnable> sChangeCallbacks = new ArrayList<Runnable>();
47 
48     @GuardedBy("sRoReads")
49     private static final HashMap<String, MutableInt> sRoReads;
50     static {
51         if (TRACK_KEY_ACCESS) {
52             sRoReads = new HashMap<>();
53         } else {
54             sRoReads = null;
55         }
56     }
57 
onKeyAccess(String key)58     private static void onKeyAccess(String key) {
59         if (!TRACK_KEY_ACCESS) return;
60 
61         if (key != null && key.startsWith("ro.")) {
62             synchronized (sRoReads) {
63                 MutableInt numReads = sRoReads.getOrDefault(key, null);
64                 if (numReads == null) {
65                     numReads = new MutableInt(0);
66                     sRoReads.put(key, numReads);
67                 }
68                 numReads.value++;
69                 if (numReads.value > 3) {
70                     Log.d(TAG, "Repeated read (count=" + numReads.value
71                             + ") of a read-only system property '" + key + "'",
72                             new Exception());
73                 }
74             }
75         }
76     }
77 
native_get(String key)78     private static native String native_get(String key);
native_get(String key, String def)79     private static native String native_get(String key, String def);
native_get_int(String key, int def)80     private static native int native_get_int(String key, int def);
native_get_long(String key, long def)81     private static native long native_get_long(String key, long def);
native_get_boolean(String key, boolean def)82     private static native boolean native_get_boolean(String key, boolean def);
native_set(String key, String def)83     private static native void native_set(String key, String def);
native_add_change_callback()84     private static native void native_add_change_callback();
native_report_sysprop_change()85     private static native void native_report_sysprop_change();
86 
87     /**
88      * Get the value for the given key.
89      * @return an empty string if the key isn't found
90      */
get(String key)91     public static String get(String key) {
92         if (TRACK_KEY_ACCESS) onKeyAccess(key);
93         return native_get(key);
94     }
95 
96     /**
97      * Get the value for the given key.
98      * @return if the key isn't found, return def if it isn't null, or an empty string otherwise
99      */
get(String key, String def)100     public static String get(String key, String def) {
101         if (TRACK_KEY_ACCESS) onKeyAccess(key);
102         return native_get(key, def);
103     }
104 
105     /**
106      * Get the value for the given key, and return as an integer.
107      * @param key the key to lookup
108      * @param def a default value to return
109      * @return the key parsed as an integer, or def if the key isn't found or
110      *         cannot be parsed
111      */
getInt(String key, int def)112     public static int getInt(String key, int def) {
113         if (TRACK_KEY_ACCESS) onKeyAccess(key);
114         return native_get_int(key, def);
115     }
116 
117     /**
118      * Get the value for the given key, and return as a long.
119      * @param key the key to lookup
120      * @param def a default value to return
121      * @return the key parsed as a long, or def if the key isn't found or
122      *         cannot be parsed
123      */
getLong(String key, long def)124     public static long getLong(String key, long def) {
125         if (TRACK_KEY_ACCESS) onKeyAccess(key);
126         return native_get_long(key, def);
127     }
128 
129     /**
130      * Get the value for the given key, returned as a boolean.
131      * Values 'n', 'no', '0', 'false' or 'off' are considered false.
132      * Values 'y', 'yes', '1', 'true' or 'on' are considered true.
133      * (case sensitive).
134      * If the key does not exist, or has any other value, then the default
135      * result is returned.
136      * @param key the key to lookup
137      * @param def a default value to return
138      * @return the key parsed as a boolean, or def if the key isn't found or is
139      *         not able to be parsed as a boolean.
140      */
getBoolean(String key, boolean def)141     public static boolean getBoolean(String key, boolean def) {
142         if (TRACK_KEY_ACCESS) onKeyAccess(key);
143         return native_get_boolean(key, def);
144     }
145 
146     /**
147      * Set the value for the given key.
148      * @throws IllegalArgumentException if the value exceeds 92 characters
149      */
set(String key, String val)150     public static void set(String key, String val) {
151         if (val != null && val.length() > PROP_VALUE_MAX) {
152             throw newValueTooLargeException(key, val);
153         }
154         if (TRACK_KEY_ACCESS) onKeyAccess(key);
155         native_set(key, val);
156     }
157 
addChangeCallback(Runnable callback)158     public static void addChangeCallback(Runnable callback) {
159         synchronized (sChangeCallbacks) {
160             if (sChangeCallbacks.size() == 0) {
161                 native_add_change_callback();
162             }
163             sChangeCallbacks.add(callback);
164         }
165     }
166 
callChangeCallbacks()167     static void callChangeCallbacks() {
168         synchronized (sChangeCallbacks) {
169             //Log.i("foo", "Calling " + sChangeCallbacks.size() + " change callbacks!");
170             if (sChangeCallbacks.size() == 0) {
171                 return;
172             }
173             ArrayList<Runnable> callbacks = new ArrayList<Runnable>(sChangeCallbacks);
174             for (int i=0; i<callbacks.size(); i++) {
175                 callbacks.get(i).run();
176             }
177         }
178     }
179 
newValueTooLargeException(String key, String value)180     private static IllegalArgumentException newValueTooLargeException(String key, String value) {
181         return new IllegalArgumentException("value of system property '" + key + "' is longer than "
182                 + PROP_VALUE_MAX + " characters: " + value);
183     }
184 
185     /*
186      * Notifies listeners that a system property has changed
187      */
reportSyspropChanged()188     public static void reportSyspropChanged() {
189         native_report_sysprop_change();
190     }
191 }
192