• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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