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