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 "cutils/properties.h"
21#include "utils/misc.h"
22#include <utils/Log.h>
23#include "jni.h"
24#include "core_jni_helpers.h"
25#include <nativehelper/JNIHelp.h>
26
27namespace android
28{
29
30static jstring SystemProperties_getSS(JNIEnv *env, jobject clazz,
31                                      jstring keyJ, jstring defJ)
32{
33    int len;
34    const char* key;
35    char buf[PROPERTY_VALUE_MAX];
36    jstring rvJ = NULL;
37
38    if (keyJ == NULL) {
39        jniThrowNullPointerException(env, "key must not be null.");
40        goto error;
41    }
42
43    key = env->GetStringUTFChars(keyJ, NULL);
44
45    len = property_get(key, buf, "");
46    if ((len <= 0) && (defJ != NULL)) {
47        rvJ = defJ;
48    } else if (len >= 0) {
49        rvJ = env->NewStringUTF(buf);
50    } else {
51        rvJ = env->NewStringUTF("");
52    }
53
54    env->ReleaseStringUTFChars(keyJ, key);
55
56error:
57    return rvJ;
58}
59
60static jstring SystemProperties_getS(JNIEnv *env, jobject clazz,
61                                      jstring keyJ)
62{
63    return SystemProperties_getSS(env, clazz, keyJ, NULL);
64}
65
66static jint SystemProperties_get_int(JNIEnv *env, jobject clazz,
67                                      jstring keyJ, jint defJ)
68{
69    int len;
70    const char* key;
71    char buf[PROPERTY_VALUE_MAX];
72    char* end;
73    jint result = defJ;
74
75    if (keyJ == NULL) {
76        jniThrowNullPointerException(env, "key must not be null.");
77        goto error;
78    }
79
80    key = env->GetStringUTFChars(keyJ, NULL);
81
82    len = property_get(key, buf, "");
83    if (len > 0) {
84        result = strtol(buf, &end, 0);
85        if (end == buf) {
86            result = defJ;
87        }
88    }
89
90    env->ReleaseStringUTFChars(keyJ, key);
91
92error:
93    return result;
94}
95
96static jlong SystemProperties_get_long(JNIEnv *env, jobject clazz,
97                                      jstring keyJ, jlong defJ)
98{
99    int len;
100    const char* key;
101    char buf[PROPERTY_VALUE_MAX];
102    char* end;
103    jlong result = defJ;
104
105    if (keyJ == NULL) {
106        jniThrowNullPointerException(env, "key must not be null.");
107        goto error;
108    }
109
110    key = env->GetStringUTFChars(keyJ, NULL);
111
112    len = property_get(key, buf, "");
113    if (len > 0) {
114        result = strtoll(buf, &end, 0);
115        if (end == buf) {
116            result = defJ;
117        }
118    }
119
120    env->ReleaseStringUTFChars(keyJ, key);
121
122error:
123    return result;
124}
125
126static jboolean SystemProperties_get_boolean(JNIEnv *env, jobject clazz,
127                                      jstring keyJ, jboolean defJ)
128{
129    int len;
130    const char* key;
131    char buf[PROPERTY_VALUE_MAX];
132    jboolean result = defJ;
133
134    if (keyJ == NULL) {
135        jniThrowNullPointerException(env, "key must not be null.");
136        goto error;
137    }
138
139    key = env->GetStringUTFChars(keyJ, NULL);
140
141    len = property_get(key, buf, "");
142    if (len == 1) {
143        char ch = buf[0];
144        if (ch == '0' || ch == 'n')
145            result = false;
146        else if (ch == '1' || ch == 'y')
147            result = true;
148    } else if (len > 1) {
149         if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
150            result = false;
151        } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
152            result = true;
153        }
154    }
155
156    env->ReleaseStringUTFChars(keyJ, key);
157
158error:
159    return result;
160}
161
162static void SystemProperties_set(JNIEnv *env, jobject clazz,
163                                      jstring keyJ, jstring valJ)
164{
165    int err;
166    const char* key;
167    const char* val;
168
169    if (keyJ == NULL) {
170        jniThrowNullPointerException(env, "key must not be null.");
171        return ;
172    }
173    key = env->GetStringUTFChars(keyJ, NULL);
174
175    if (valJ == NULL) {
176        val = "";       /* NULL pointer not allowed here */
177    } else {
178        val = env->GetStringUTFChars(valJ, NULL);
179    }
180
181    err = property_set(key, val);
182
183    env->ReleaseStringUTFChars(keyJ, key);
184
185    if (valJ != NULL) {
186        env->ReleaseStringUTFChars(valJ, val);
187    }
188
189    if (err < 0) {
190        jniThrowException(env, "java/lang/RuntimeException",
191                          "failed to set system property");
192    }
193}
194
195static JavaVM* sVM = NULL;
196static jclass sClazz = NULL;
197static jmethodID sCallChangeCallbacks;
198
199static void do_report_sysprop_change() {
200    //ALOGI("Java SystemProperties: VM=%p, Clazz=%p", sVM, sClazz);
201    if (sVM != NULL && sClazz != NULL) {
202        JNIEnv* env;
203        if (sVM->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0) {
204            //ALOGI("Java SystemProperties: calling %p", sCallChangeCallbacks);
205            env->CallStaticVoidMethod(sClazz, sCallChangeCallbacks);
206        }
207    }
208}
209
210static void SystemProperties_add_change_callback(JNIEnv *env, jobject clazz)
211{
212    // This is called with the Java lock held.
213    if (sVM == NULL) {
214        env->GetJavaVM(&sVM);
215    }
216    if (sClazz == NULL) {
217        sClazz = (jclass) env->NewGlobalRef(clazz);
218        sCallChangeCallbacks = env->GetStaticMethodID(sClazz, "callChangeCallbacks", "()V");
219        add_sysprop_change_callback(do_report_sysprop_change, -10000);
220    }
221}
222
223static const JNINativeMethod method_table[] = {
224    { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
225      (void*) SystemProperties_getS },
226    { "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
227      (void*) SystemProperties_getSS },
228    { "native_get_int", "(Ljava/lang/String;I)I",
229      (void*) SystemProperties_get_int },
230    { "native_get_long", "(Ljava/lang/String;J)J",
231      (void*) SystemProperties_get_long },
232    { "native_get_boolean", "(Ljava/lang/String;Z)Z",
233      (void*) SystemProperties_get_boolean },
234    { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
235      (void*) SystemProperties_set },
236    { "native_add_change_callback", "()V",
237      (void*) SystemProperties_add_change_callback },
238};
239
240int register_android_os_SystemProperties(JNIEnv *env)
241{
242    return RegisterMethodsOrDie(env, "android/os/SystemProperties", method_table,
243                                NELEM(method_table));
244}
245
246};
247