blob: 7f3b32e1abed9a9db9d1a1c49b86abb42f7f410e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/* //device/libs/android_runtime/android_os_SystemProperties.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
Elliott Hughes69a017b2011-04-08 14:10:28 -07005** 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008**
Elliott Hughes69a017b2011-04-08 14:10:28 -07009** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010**
Elliott Hughes69a017b2011-04-08 14:10:28 -070011** 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080015** limitations under the License.
16*/
17
Dianne Hackborna53de062012-05-08 18:53:51 -070018#define LOG_TAG "SysPropJNI"
19
Daniel Colascione5e8ba5f2019-11-14 01:46:37 -080020#include <utility>
21#include <optional>
22
Andreas Gampea90534b2017-07-29 14:14:39 -070023#include "android-base/logging.h"
Daniel Colascione5e8ba5f2019-11-14 01:46:37 -080024#include "android-base/parsebool.h"
25#include "android-base/parseint.h"
Andreas Gampea90534b2017-07-29 14:14:39 -070026#include "android-base/properties.h"
Dianne Hackborna53de062012-05-08 18:53:51 -070027#include "utils/misc.h"
28#include <utils/Log.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029#include "jni.h"
Andreas Gampeed6b9df2014-11-20 22:02:20 -080030#include "core_jni_helpers.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031#include <nativehelper/JNIHelp.h>
Andreas Gampea90534b2017-07-29 14:14:39 -070032#include <nativehelper/ScopedPrimitiveArray.h>
33#include <nativehelper/ScopedUtfChars.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034
Daniel Colascione5e8ba5f2019-11-14 01:46:37 -080035#if defined(__BIONIC__)
36# include <sys/system_properties.h>
37#else
38struct prop_info;
39#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040
Daniel Colascione5e8ba5f2019-11-14 01:46:37 -080041namespace android {
Andreas Gampea90534b2017-07-29 14:14:39 -070042namespace {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043
Daniel Colascione6e2cff72019-11-14 13:22:31 -080044using android::base::ParseBoolResult;
45
Daniel Colascione5e8ba5f2019-11-14 01:46:37 -080046template<typename Functor>
47void 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
Mike Lockwoodd1945952009-08-12 17:15:51 -040060}
61
Daniel Colascione5e8ba5f2019-11-14 01:46:37 -080062template<typename Functor>
63void 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
81jstring SystemProperties_getSS(JNIEnv* env, jclass clazz, jstring keyJ,
Andreas Gampea90534b2017-07-29 14:14:39 -070082 jstring defJ)
Mike Lockwoodd1945952009-08-12 17:15:51 -040083{
Daniel Colascione5e8ba5f2019-11-14 01:46:37 -080084 jstring ret = defJ;
85 ReadProperty(env, keyJ, [&](const char* value) {
86 if (value[0]) {
87 ret = env->NewStringUTF(value);
Dianne Hackborn83e6eb12012-05-08 14:53:24 -070088 }
Daniel Colascione5e8ba5f2019-11-14 01:46:37 -080089 });
90 if (ret == nullptr && !env->ExceptionCheck()) {
91 ret = env->NewStringUTF(""); // Legacy behavior
92 }
93 return ret;
Andreas Gampea90534b2017-07-29 14:14:39 -070094}
Mike Lockwoodd1945952009-08-12 17:15:51 -040095
Andreas Gampea90534b2017-07-29 14:14:39 -070096template <typename T>
97T SystemProperties_get_integral(JNIEnv *env, jclass, jstring keyJ,
98 T defJ)
99{
Daniel Colascione5e8ba5f2019-11-14 01:46:37 -0800100 T ret = defJ;
101 ReadProperty(env, keyJ, [&](const char* value) {
102 android::base::ParseInt<T>(value, &ret);
103 });
104 return ret;
Andreas Gampea90534b2017-07-29 14:14:39 -0700105}
Mike Lockwoodd1945952009-08-12 17:15:51 -0400106
Daniel Colascione6e2cff72019-11-14 13:22:31 -0800107static jboolean jbooleanFromParseBoolResult(ParseBoolResult parseResult, jboolean defJ) {
Daniel Colascione5e8ba5f2019-11-14 01:46:37 -0800108 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;
Andreas Gampea90534b2017-07-29 14:14:39 -0700121}
Mike Lockwoodd1945952009-08-12 17:15:51 -0400122
Daniel Colascione6e2cff72019-11-14 13:22:31 -0800123jboolean SystemProperties_get_boolean(JNIEnv *env, jclass, jstring keyJ,
124 jboolean defJ)
125{
Greg Kaiser8d8c3b72019-11-22 13:38:14 -0800126 ParseBoolResult parseResult = ParseBoolResult::kError;
Daniel Colascione6e2cff72019-11-14 13:22:31 -0800127 ReadProperty(env, keyJ, [&](const char* value) {
128 parseResult = android::base::ParseBool(value);
129 });
130 return jbooleanFromParseBoolResult(parseResult, defJ);
131}
132
133jlong 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
148jstring 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
158template <typename T>
159T 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
169jboolean SystemProperties_get_booleanH(CRITICAL_JNI_PARAMS_COMMA jlong propJ, jboolean defJ)
170{
Greg Kaiser8d8c3b72019-11-22 13:38:14 -0800171 ParseBoolResult parseResult = ParseBoolResult::kError;
Daniel Colascione6e2cff72019-11-14 13:22:31 -0800172 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
Andreas Gampea90534b2017-07-29 14:14:39 -0700179void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ,
180 jstring valJ)
181{
Daniel Colascione5e8ba5f2019-11-14 01:46:37 -0800182 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;
Mike Lockwoodd1945952009-08-12 17:15:51 -0400191 }
Daniel Colascione5e8ba5f2019-11-14 01:46:37 -0800192 }
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) {
Brad Fitzpatrick06f36742011-03-10 16:04:59 -0800200 jniThrowException(env, "java/lang/RuntimeException",
Tom Cherry39373b22019-09-19 08:28:27 -0700201 "failed to set system property (check logcat for reason)");
Brad Fitzpatrick06f36742011-03-10 16:04:59 -0800202 }
203}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204
Andreas Gampea90534b2017-07-29 14:14:39 -0700205JavaVM* sVM = nullptr;
206jclass sClazz = nullptr;
207jmethodID sCallChangeCallbacks;
Dianne Hackborna53de062012-05-08 18:53:51 -0700208
Andreas Gampea90534b2017-07-29 14:14:39 -0700209void do_report_sysprop_change() {
Dianne Hackborna53de062012-05-08 18:53:51 -0700210 //ALOGI("Java SystemProperties: VM=%p, Clazz=%p", sVM, sClazz);
Andreas Gampea90534b2017-07-29 14:14:39 -0700211 if (sVM != nullptr && sClazz != nullptr) {
Dianne Hackborna53de062012-05-08 18:53:51 -0700212 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);
Andreas Gampe7074e6f2018-03-16 16:14:29 -0700216 // 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 }
Dianne Hackborna53de062012-05-08 18:53:51 -0700222 }
223 }
224}
225
Andreas Gampea90534b2017-07-29 14:14:39 -0700226void SystemProperties_add_change_callback(JNIEnv *env, jobject clazz)
Dianne Hackborna53de062012-05-08 18:53:51 -0700227{
228 // This is called with the Java lock held.
Andreas Gampea90534b2017-07-29 14:14:39 -0700229 if (sVM == nullptr) {
Dianne Hackborna53de062012-05-08 18:53:51 -0700230 env->GetJavaVM(&sVM);
231 }
Andreas Gampea90534b2017-07-29 14:14:39 -0700232 if (sClazz == nullptr) {
Dianne Hackborna53de062012-05-08 18:53:51 -0700233 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
Andreas Gampea90534b2017-07-29 14:14:39 -0700239void SystemProperties_report_sysprop_change(JNIEnv /**env*/, jobject /*clazz*/)
Martijn Coenen0754b272016-11-17 14:06:38 +0100240{
241 report_sysprop_change();
242}
243
Andreas Gampea90534b2017-07-29 14:14:39 -0700244} // namespace
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245
246int register_android_os_SystemProperties(JNIEnv *env)
247{
Andreas Gampea90534b2017-07-29 14:14:39 -0700248 const JNINativeMethod method_table[] = {
Andreas Gampea90534b2017-07-29 14:14:39 -0700249 { "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 },
Daniel Colascione6e2cff72019-11-14 13:22:31 -0800258 { "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 },
Andreas Gampea90534b2017-07-29 14:14:39 -0700270 { "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));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279}
280
Daniel Colascione5e8ba5f2019-11-14 01:46:37 -0800281} // namespace android