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