Home | History | Annotate | Download | only in jni
      1 /* //device/libs/android_runtime/android_os_SystemProperties.cpp
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #define LOG_TAG "SysPropJNI"
     19 
     20 #include "android-base/logging.h"
     21 #include "android-base/properties.h"
     22 #include "cutils/properties.h"
     23 #include "utils/misc.h"
     24 #include <utils/Log.h>
     25 #include "jni.h"
     26 #include "core_jni_helpers.h"
     27 #include <nativehelper/JNIHelp.h>
     28 #include <nativehelper/ScopedPrimitiveArray.h>
     29 #include <nativehelper/ScopedUtfChars.h>
     30 
     31 namespace android
     32 {
     33 
     34 namespace {
     35 
     36 template <typename T, typename Handler>
     37 T ConvertKeyAndForward(JNIEnv *env, jstring keyJ, T defJ, Handler handler) {
     38     std::string key;
     39     {
     40         // Scope the String access. If the handler can throw an exception,
     41         // releasing the string characters late would trigger an abort.
     42         ScopedUtfChars key_utf(env, keyJ);
     43         if (key_utf.c_str() == nullptr) {
     44             return defJ;
     45         }
     46         key = key_utf.c_str();  // This will make a copy, but we can't avoid
     47                                 // with the existing interface in
     48                                 // android::base.
     49     }
     50     return handler(key, defJ);
     51 }
     52 
     53 jstring SystemProperties_getSS(JNIEnv *env, jclass clazz, jstring keyJ,
     54                                jstring defJ)
     55 {
     56     // Using ConvertKeyAndForward is sub-optimal for copying the key string,
     57     // but improves reuse and reasoning over code.
     58     auto handler = [&](const std::string& key, jstring defJ) {
     59         std::string prop_val = android::base::GetProperty(key, "");
     60         if (!prop_val.empty()) {
     61             return env->NewStringUTF(prop_val.c_str());
     62         };
     63         if (defJ != nullptr) {
     64             return defJ;
     65         }
     66         // This function is specified to never return null (or have an
     67         // exception pending).
     68         return env->NewStringUTF("");
     69     };
     70     return ConvertKeyAndForward(env, keyJ, defJ, handler);
     71 }
     72 
     73 jstring SystemProperties_getS(JNIEnv *env, jclass clazz, jstring keyJ)
     74 {
     75     return SystemProperties_getSS(env, clazz, keyJ, nullptr);
     76 }
     77 
     78 template <typename T>
     79 T SystemProperties_get_integral(JNIEnv *env, jclass, jstring keyJ,
     80                                        T defJ)
     81 {
     82     auto handler = [](const std::string& key, T defV) {
     83         return android::base::GetIntProperty<T>(key, defV);
     84     };
     85     return ConvertKeyAndForward(env, keyJ, defJ, handler);
     86 }
     87 
     88 jboolean SystemProperties_get_boolean(JNIEnv *env, jclass, jstring keyJ,
     89                                       jboolean defJ)
     90 {
     91     auto handler = [](const std::string& key, jboolean defV) -> jboolean {
     92         bool result = android::base::GetBoolProperty(key, defV);
     93         return result ? JNI_TRUE : JNI_FALSE;
     94     };
     95     return ConvertKeyAndForward(env, keyJ, defJ, handler);
     96 }
     97 
     98 void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ,
     99                           jstring valJ)
    100 {
    101     auto handler = [&](const std::string& key, bool) {
    102         std::string val;
    103         if (valJ != nullptr) {
    104             ScopedUtfChars key_utf(env, valJ);
    105             val = key_utf.c_str();
    106         }
    107         return android::base::SetProperty(key, val);
    108     };
    109     if (!ConvertKeyAndForward(env, keyJ, true, handler)) {
    110         // Must have been a failure in SetProperty.
    111         jniThrowException(env, "java/lang/RuntimeException",
    112                           "failed to set system property");
    113     }
    114 }
    115 
    116 JavaVM* sVM = nullptr;
    117 jclass sClazz = nullptr;
    118 jmethodID sCallChangeCallbacks;
    119 
    120 void do_report_sysprop_change() {
    121     //ALOGI("Java SystemProperties: VM=%p, Clazz=%p", sVM, sClazz);
    122     if (sVM != nullptr && sClazz != nullptr) {
    123         JNIEnv* env;
    124         if (sVM->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0) {
    125             //ALOGI("Java SystemProperties: calling %p", sCallChangeCallbacks);
    126             env->CallStaticVoidMethod(sClazz, sCallChangeCallbacks);
    127             // There should not be any exceptions. But we must guarantee
    128             // there are none on return.
    129             if (env->ExceptionCheck()) {
    130                 env->ExceptionClear();
    131                 LOG(ERROR) << "Exception pending after sysprop_change!";
    132             }
    133         }
    134     }
    135 }
    136 
    137 void SystemProperties_add_change_callback(JNIEnv *env, jobject clazz)
    138 {
    139     // This is called with the Java lock held.
    140     if (sVM == nullptr) {
    141         env->GetJavaVM(&sVM);
    142     }
    143     if (sClazz == nullptr) {
    144         sClazz = (jclass) env->NewGlobalRef(clazz);
    145         sCallChangeCallbacks = env->GetStaticMethodID(sClazz, "callChangeCallbacks", "()V");
    146         add_sysprop_change_callback(do_report_sysprop_change, -10000);
    147     }
    148 }
    149 
    150 void SystemProperties_report_sysprop_change(JNIEnv /**env*/, jobject /*clazz*/)
    151 {
    152     report_sysprop_change();
    153 }
    154 
    155 }  // namespace
    156 
    157 int register_android_os_SystemProperties(JNIEnv *env)
    158 {
    159     const JNINativeMethod method_table[] = {
    160         { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
    161           (void*) SystemProperties_getS },
    162         { "native_get",
    163           "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
    164           (void*) SystemProperties_getSS },
    165         { "native_get_int", "(Ljava/lang/String;I)I",
    166           (void*) SystemProperties_get_integral<jint> },
    167         { "native_get_long", "(Ljava/lang/String;J)J",
    168           (void*) SystemProperties_get_integral<jlong> },
    169         { "native_get_boolean", "(Ljava/lang/String;Z)Z",
    170           (void*) SystemProperties_get_boolean },
    171         { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
    172           (void*) SystemProperties_set },
    173         { "native_add_change_callback", "()V",
    174           (void*) SystemProperties_add_change_callback },
    175         { "native_report_sysprop_change", "()V",
    176           (void*) SystemProperties_report_sysprop_change },
    177     };
    178     return RegisterMethodsOrDie(env, "android/os/SystemProperties",
    179                                 method_table, NELEM(method_table));
    180 }
    181 
    182 };
    183