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 31namespace android 32{ 33 34namespace { 35 36template <typename T, typename Handler> 37T 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 53jstring 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 73jstring SystemProperties_getS(JNIEnv *env, jclass clazz, jstring keyJ) 74{ 75 return SystemProperties_getSS(env, clazz, keyJ, nullptr); 76} 77 78template <typename T> 79T 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 88jboolean 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 98void 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 116JavaVM* sVM = nullptr; 117jclass sClazz = nullptr; 118jmethodID sCallChangeCallbacks; 119 120void 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 137void 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 150void SystemProperties_report_sysprop_change(JNIEnv /**env*/, jobject /*clazz*/) 151{ 152 report_sysprop_change(); 153} 154 155} // namespace 156 157int 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