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