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>
ConvertKeyAndForward(JNIEnv * env,jstring keyJ,T defJ,Handler 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
SystemProperties_getSS(JNIEnv * env,jclass clazz,jstring keyJ,jstring defJ)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
SystemProperties_getS(JNIEnv * env,jclass clazz,jstring keyJ)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>
SystemProperties_get_integral(JNIEnv * env,jclass,jstring keyJ,T defJ)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
SystemProperties_get_boolean(JNIEnv * env,jclass,jstring keyJ,jboolean defJ)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
SystemProperties_set(JNIEnv * env,jobject clazz,jstring keyJ,jstring valJ)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
do_report_sysprop_change()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
SystemProperties_add_change_callback(JNIEnv * env,jobject clazz)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
SystemProperties_report_sysprop_change(JNIEnv,jobject)150 void SystemProperties_report_sysprop_change(JNIEnv /**env*/, jobject /*clazz*/)
151 {
152 report_sysprop_change();
153 }
154
155 } // namespace
156
register_android_os_SystemProperties(JNIEnv * env)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