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 <utility> 21 #include <optional> 22 23 #include "android-base/logging.h" 24 #include "android-base/parsebool.h" 25 #include "android-base/parseint.h" 26 #include "android-base/properties.h" 27 #include "utils/misc.h" 28 #include <utils/Log.h> 29 #include "jni.h" 30 #include "core_jni_helpers.h" 31 #include <nativehelper/JNIHelp.h> 32 #include <nativehelper/ScopedPrimitiveArray.h> 33 #include <nativehelper/ScopedUtfChars.h> 34 35 #if defined(__BIONIC__) 36 # include <sys/system_properties.h> 37 #else 38 struct prop_info; 39 #endif 40 41 namespace android { 42 namespace { 43 44 using android::base::ParseBoolResult; 45 46 template<typename Functor> 47 void ReadProperty(const prop_info* prop, Functor&& functor) 48 { 49 #if defined(__BIONIC__) 50 auto thunk = [](void* cookie, 51 const char* /*name*/, 52 const char* value, 53 uint32_t /*serial*/) { 54 std::forward<Functor>(*static_cast<Functor*>(cookie))(value); 55 }; 56 __system_property_read_callback(prop, thunk, &functor); 57 #else 58 LOG(FATAL) << "fast property access supported only on device"; 59 #endif 60 } 61 62 template<typename Functor> 63 void ReadProperty(JNIEnv* env, jstring keyJ, Functor&& functor) 64 { 65 ScopedUtfChars key(env, keyJ); 66 if (!key.c_str()) { 67 return; 68 } 69 #if defined(__BIONIC__) 70 const prop_info* prop = __system_property_find(key.c_str()); 71 if (!prop) { 72 return; 73 } 74 ReadProperty(prop, std::forward<Functor>(functor)); 75 #else 76 std::forward<Functor>(functor)( 77 android::base::GetProperty(key.c_str(), "").c_str()); 78 #endif 79 } 80 81 jstring SystemProperties_getSS(JNIEnv* env, jclass clazz, jstring keyJ, 82 jstring defJ) 83 { 84 jstring ret = defJ; 85 ReadProperty(env, keyJ, [&](const char* value) { 86 if (value[0]) { 87 ret = env->NewStringUTF(value); 88 } 89 }); 90 if (ret == nullptr && !env->ExceptionCheck()) { 91 ret = env->NewStringUTF(""); // Legacy behavior 92 } 93 return ret; 94 } 95 96 template <typename T> 97 T SystemProperties_get_integral(JNIEnv *env, jclass, jstring keyJ, 98 T defJ) 99 { 100 T ret = defJ; 101 ReadProperty(env, keyJ, [&](const char* value) { 102 android::base::ParseInt<T>(value, &ret); 103 }); 104 return ret; 105 } 106 107 static jboolean jbooleanFromParseBoolResult(ParseBoolResult parseResult, jboolean defJ) { 108 jboolean ret; 109 switch (parseResult) { 110 case ParseBoolResult::kError: 111 ret = defJ; 112 break; 113 case ParseBoolResult::kFalse: 114 ret = JNI_FALSE; 115 break; 116 case ParseBoolResult::kTrue: 117 ret = JNI_TRUE; 118 break; 119 } 120 return ret; 121 } 122 123 jboolean SystemProperties_get_boolean(JNIEnv *env, jclass, jstring keyJ, 124 jboolean defJ) 125 { 126 ParseBoolResult parseResult = ParseBoolResult::kError; 127 ReadProperty(env, keyJ, [&](const char* value) { 128 parseResult = android::base::ParseBool(value); 129 }); 130 return jbooleanFromParseBoolResult(parseResult, defJ); 131 } 132 133 jlong SystemProperties_find(JNIEnv* env, jclass, jstring keyJ) 134 { 135 #if defined(__BIONIC__) 136 ScopedUtfChars key(env, keyJ); 137 if (!key.c_str()) { 138 return 0; 139 } 140 const prop_info* prop = __system_property_find(key.c_str()); 141 return reinterpret_cast<jlong>(prop); 142 #else 143 LOG(FATAL) << "fast property access supported only on device"; 144 __builtin_unreachable(); // Silence warning 145 #endif 146 } 147 148 jstring SystemProperties_getH(JNIEnv* env, jclass clazz, jlong propJ) 149 { 150 jstring ret; 151 auto prop = reinterpret_cast<const prop_info*>(propJ); 152 ReadProperty(prop, [&](const char* value) { 153 ret = env->NewStringUTF(value); 154 }); 155 return ret; 156 } 157 158 template <typename T> 159 T SystemProperties_get_integralH(CRITICAL_JNI_PARAMS_COMMA jlong propJ, T defJ) 160 { 161 T ret = defJ; 162 auto prop = reinterpret_cast<const prop_info*>(propJ); 163 ReadProperty(prop, [&](const char* value) { 164 android::base::ParseInt<T>(value, &ret); 165 }); 166 return ret; 167 } 168 169 jboolean SystemProperties_get_booleanH(CRITICAL_JNI_PARAMS_COMMA jlong propJ, jboolean defJ) 170 { 171 ParseBoolResult parseResult = ParseBoolResult::kError; 172 auto prop = reinterpret_cast<const prop_info*>(propJ); 173 ReadProperty(prop, [&](const char* value) { 174 parseResult = android::base::ParseBool(value); 175 }); 176 return jbooleanFromParseBoolResult(parseResult, defJ); 177 } 178 179 void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ, 180 jstring valJ) 181 { 182 ScopedUtfChars key(env, keyJ); 183 if (!key.c_str()) { 184 return; 185 } 186 std::optional<ScopedUtfChars> value; 187 if (valJ != nullptr) { 188 value.emplace(env, valJ); 189 if (!value->c_str()) { 190 return; 191 } 192 } 193 bool success; 194 #if defined(__BIONIC__) 195 success = !__system_property_set(key.c_str(), value ? value->c_str() : ""); 196 #else 197 success = android::base::SetProperty(key.c_str(), value ? value->c_str() : ""); 198 #endif 199 if (!success) { 200 jniThrowException(env, "java/lang/RuntimeException", 201 "failed to set system property (check logcat for reason)"); 202 } 203 } 204 205 JavaVM* sVM = nullptr; 206 jclass sClazz = nullptr; 207 jmethodID sCallChangeCallbacks; 208 209 void do_report_sysprop_change() { 210 //ALOGI("Java SystemProperties: VM=%p, Clazz=%p", sVM, sClazz); 211 if (sVM != nullptr && sClazz != nullptr) { 212 JNIEnv* env; 213 if (sVM->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0) { 214 //ALOGI("Java SystemProperties: calling %p", sCallChangeCallbacks); 215 env->CallStaticVoidMethod(sClazz, sCallChangeCallbacks); 216 // There should not be any exceptions. But we must guarantee 217 // there are none on return. 218 if (env->ExceptionCheck()) { 219 env->ExceptionClear(); 220 LOG(ERROR) << "Exception pending after sysprop_change!"; 221 } 222 } 223 } 224 } 225 226 void SystemProperties_add_change_callback(JNIEnv *env, jobject clazz) 227 { 228 // This is called with the Java lock held. 229 if (sVM == nullptr) { 230 env->GetJavaVM(&sVM); 231 } 232 if (sClazz == nullptr) { 233 sClazz = (jclass) env->NewGlobalRef(clazz); 234 sCallChangeCallbacks = env->GetStaticMethodID(sClazz, "callChangeCallbacks", "()V"); 235 add_sysprop_change_callback(do_report_sysprop_change, -10000); 236 } 237 } 238 239 void SystemProperties_report_sysprop_change(JNIEnv /**env*/, jobject /*clazz*/) 240 { 241 report_sysprop_change(); 242 } 243 244 } // namespace 245 246 int register_android_os_SystemProperties(JNIEnv *env) 247 { 248 const JNINativeMethod method_table[] = { 249 { "native_get", 250 "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", 251 (void*) SystemProperties_getSS }, 252 { "native_get_int", "(Ljava/lang/String;I)I", 253 (void*) SystemProperties_get_integral<jint> }, 254 { "native_get_long", "(Ljava/lang/String;J)J", 255 (void*) SystemProperties_get_integral<jlong> }, 256 { "native_get_boolean", "(Ljava/lang/String;Z)Z", 257 (void*) SystemProperties_get_boolean }, 258 { "native_find", 259 "(Ljava/lang/String;)J", 260 (void*) SystemProperties_find }, 261 { "native_get", 262 "(J)Ljava/lang/String;", 263 (void*) SystemProperties_getH }, 264 { "native_get_int", "(JI)I", 265 (void*) SystemProperties_get_integralH<jint> }, 266 { "native_get_long", "(JJ)J", 267 (void*) SystemProperties_get_integralH<jlong> }, 268 { "native_get_boolean", "(JZ)Z", 269 (void*) SystemProperties_get_booleanH }, 270 { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V", 271 (void*) SystemProperties_set }, 272 { "native_add_change_callback", "()V", 273 (void*) SystemProperties_add_change_callback }, 274 { "native_report_sysprop_change", "()V", 275 (void*) SystemProperties_report_sysprop_change }, 276 }; 277 return RegisterMethodsOrDie(env, "android/os/SystemProperties", 278 method_table, NELEM(method_table)); 279 } 280 281 } // namespace android 282