diff options
author | 2024-11-26 01:48:37 +0000 | |
---|---|---|
committer | 2024-11-26 01:48:37 +0000 | |
commit | 75068d5340e840f59ce83cace4d9c2da38beb5ba (patch) | |
tree | 2f7340b8723685623bc7a0c2c0de4f55c9d406e8 | |
parent | de6bd0574e1ce67f2893416fd4edfc1827b8414a (diff) |
[Ravenwood] Merge libinit and libsysprop
Flag: EXEMPT host test change only
Bug: 292141694
Test: $ANDROID_BUILD_TOP/frameworks/base/ravenwood/scripts/run-ravenwood-tests.sh
Change-Id: Ie475a13f979ee8aaceb19adf8525e16654f6da20
-rw-r--r-- | ravenwood/Android.bp | 13 | ||||
-rw-r--r-- | ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java | 14 | ||||
-rw-r--r-- | ravenwood/runtime-jni/ravenwood_initializer.cpp | 189 | ||||
-rw-r--r-- | ravenwood/runtime-jni/ravenwood_sysprop.cpp | 200 |
4 files changed, 192 insertions, 224 deletions
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp index 0c2ce8dcb698..66c8d0fa32f9 100644 --- a/ravenwood/Android.bp +++ b/ravenwood/Android.bp @@ -282,20 +282,12 @@ cc_defaults { visibility: ["//visibility:private"], } -cc_library_host_shared { - name: "libravenwood_initializer", - defaults: ["ravenwood_jni_defaults"], - srcs: [ - "runtime-jni/ravenwood_initializer.cpp", - ], -} - // We need this as a separate library because we need to overload the // sysprop symbols before libbase is loaded into the process cc_library_host_shared { - name: "libravenwood_sysprop", + name: "libravenwood_initializer", defaults: ["ravenwood_jni_defaults"], - srcs: ["runtime-jni/ravenwood_sysprop.cpp"], + srcs: ["runtime-jni/ravenwood_initializer.cpp"], } cc_library_host_shared { @@ -669,7 +661,6 @@ android_ravenwood_libgroup { jni_libs: [ // Libraries has to be loaded in the following order "libravenwood_initializer", - "libravenwood_sysprop", "libravenwood_runtime", "libandroid_runtime", ], diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java index b3987f4987df..172cec3b8e13 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java @@ -103,7 +103,6 @@ public class RavenwoodRuntimeEnvironmentController { private static final String MAIN_THREAD_NAME = "RavenwoodMain"; private static final String LIBRAVENWOOD_INITIALIZER_NAME = "ravenwood_initializer"; - private static final String RAVENWOOD_NATIVE_SYSPROP_NAME = "ravenwood_sysprop"; private static final String RAVENWOOD_NATIVE_RUNTIME_NAME = "ravenwood_runtime"; /** @@ -215,8 +214,12 @@ public class RavenwoodRuntimeEnvironmentController { Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler); } - // Some process-wide initialization. (maybe redirect stdout/stderr) - RavenwoodCommonUtils.loadJniLibrary(LIBRAVENWOOD_INITIALIZER_NAME); + // Some process-wide initialization: + // - maybe redirect stdout/stderr + // - override native system property functions + var lib = RavenwoodCommonUtils.getJniLibraryPath(LIBRAVENWOOD_INITIALIZER_NAME); + System.load(lib); + RavenwoodRuntimeNative.reloadNativeLibrary(lib); // Redirect stdout/stdin to the Log API. RuntimeInit.redirectLogStreams(); @@ -226,11 +229,6 @@ public class RavenwoodRuntimeEnvironmentController { // We haven't initialized liblog yet, so directly write to System.out here. RavenwoodCommonUtils.log(TAG, "globalInitInner()"); - // Load libravenwood_sysprop before other libraries that may use SystemProperties. - var libProp = RavenwoodCommonUtils.getJniLibraryPath(RAVENWOOD_NATIVE_SYSPROP_NAME); - System.load(libProp); - RavenwoodRuntimeNative.reloadNativeLibrary(libProp); - // Make sure libravenwood_runtime is loaded. System.load(RavenwoodCommonUtils.getJniLibraryPath(RAVENWOOD_NATIVE_RUNTIME_NAME)); diff --git a/ravenwood/runtime-jni/ravenwood_initializer.cpp b/ravenwood/runtime-jni/ravenwood_initializer.cpp index 89fb7c3c3510..dbbc3453b2f1 100644 --- a/ravenwood/runtime-jni/ravenwood_initializer.cpp +++ b/ravenwood/runtime-jni/ravenwood_initializer.cpp @@ -14,16 +14,174 @@ * limitations under the License. */ - /* - * This file is compiled into a single SO file, which we load at the very first. - * We can do process-wide initialization here. - */ +/* + * This file is compiled into a single SO file, which we load at the very first. + * We can do process-wide initialization here. + * Please be aware that all symbols defined in this SO file will be reloaded + * as `RTLD_GLOBAL`, so make sure all functions are static except those we EXPLICITLY + * want to expose and override globally. + */ +#include <dlfcn.h> #include <fcntl.h> -#include <unistd.h> + +#include <set> #include "jni_helper.h" +// Implement a rudimentary system properties data store + +#define PROP_VALUE_MAX 92 + +namespace { + +struct prop_info { + std::string key; + mutable std::string value; + mutable uint32_t serial; + + prop_info(const char* key, const char* value) : key(key), value(value), serial(0) {} +}; + +struct prop_info_cmp { + using is_transparent = void; + bool operator()(const prop_info& lhs, const prop_info& rhs) { + return lhs.key < rhs.key; + } + bool operator()(std::string_view lhs, const prop_info& rhs) { + return lhs < rhs.key; + } + bool operator()(const prop_info& lhs, std::string_view rhs) { + return lhs.key < rhs; + } +}; + +} // namespace + +static auto& g_properties_lock = *new std::mutex; +static auto& g_properties = *new std::set<prop_info, prop_info_cmp>; + +static bool property_set(const char* key, const char* value) { + if (key == nullptr || *key == '\0') return false; + if (value == nullptr) value = ""; + bool read_only = !strncmp(key, "ro.", 3); + if (!read_only && strlen(value) >= PROP_VALUE_MAX) return false; + + std::lock_guard lock(g_properties_lock); + auto [it, success] = g_properties.emplace(key, value); + if (read_only) return success; + if (!success) { + it->value = value; + ++it->serial; + } + return true; +} + +template <typename Func> +static void property_get(const char* key, Func callback) { + std::lock_guard lock(g_properties_lock); + auto it = g_properties.find(key); + if (it != g_properties.end()) { + callback(*it); + } +} + +// Redefine the __system_property_XXX functions here so we can perform +// logging and access checks for all sysprops in native code. + +static void check_system_property_access(const char* key, bool write); + +extern "C" { + +int __system_property_set(const char* key, const char* value) { + check_system_property_access(key, true); + return property_set(key, value) ? 0 : -1; +} + +int __system_property_get(const char* key, char* value) { + check_system_property_access(key, false); + *value = '\0'; + property_get(key, [&](const prop_info& info) { + snprintf(value, PROP_VALUE_MAX, "%s", info.value.c_str()); + }); + return strlen(value); +} + +const prop_info* __system_property_find(const char* key) { + check_system_property_access(key, false); + const prop_info* pi = nullptr; + property_get(key, [&](const prop_info& info) { pi = &info; }); + return pi; +} + +void __system_property_read_callback(const prop_info* pi, + void (*callback)(void*, const char*, const char*, uint32_t), + void* cookie) { + std::lock_guard lock(g_properties_lock); + callback(cookie, pi->key.c_str(), pi->value.c_str(), pi->serial); +} + +} // extern "C" + +// ---- JNI ---- + +static JavaVM* gVM = nullptr; +static jclass gRunnerState = nullptr; +static jmethodID gCheckSystemPropertyAccess; + +static void reloadNativeLibrary(JNIEnv* env, jclass, jstring javaPath) { + ScopedUtfChars path(env, javaPath); + // Force reload ourselves as global + dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL | RTLD_NOLOAD); +} + +// Call back into Java code to check property access +static void check_system_property_access(const char* key, bool write) { + if (gVM != nullptr && gRunnerState != nullptr) { + JNIEnv* env; + if (gVM->GetEnv((void**)&env, JNI_VERSION_1_4) >= 0) { + ALOGI("%s access to system property '%s'", write ? "Write" : "Read", key); + env->CallStaticVoidMethod(gRunnerState, gCheckSystemPropertyAccess, + env->NewStringUTF(key), write ? JNI_TRUE : JNI_FALSE); + return; + } + } + // Not on JVM thread, abort + LOG_ALWAYS_FATAL("Access to system property '%s' on non-JVM threads is not allowed.", key); +} + +static jstring getSystemProperty(JNIEnv* env, jclass, jstring javaKey) { + ScopedUtfChars key(env, javaKey); + jstring value = nullptr; + property_get(key.c_str(), + [&](const prop_info& info) { value = env->NewStringUTF(info.value.c_str()); }); + return value; +} + +static jboolean setSystemProperty(JNIEnv* env, jclass, jstring javaKey, jstring javaValue) { + ScopedUtfChars key(env, javaKey); + ScopedUtfChars value(env, javaValue); + return property_set(key.c_str(), value.c_str()) ? JNI_TRUE : JNI_FALSE; +} + +static jboolean removeSystemProperty(JNIEnv* env, jclass, jstring javaKey) { + std::lock_guard lock(g_properties_lock); + + if (javaKey == nullptr) { + g_properties.clear(); + return JNI_TRUE; + } else { + ScopedUtfChars key(env, javaKey); + auto it = g_properties.find(key); + if (it != g_properties.end()) { + g_properties.erase(it); + return JNI_TRUE; + } else { + return JNI_FALSE; + } + } +} + static void maybeRedirectLog() { auto ravenwoodLogOut = getenv("RAVENWOOD_LOG_OUT"); if (ravenwoodLogOut == NULL) { @@ -42,9 +200,30 @@ static void maybeRedirectLog() { dup2(ttyFd, 2); } +static const JNINativeMethod sMethods[] = { + {"reloadNativeLibrary", "(Ljava/lang/String;)V", (void*)reloadNativeLibrary}, + {"getSystemProperty", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getSystemProperty}, + {"setSystemProperty", "(Ljava/lang/String;Ljava/lang/String;)Z", (void*)setSystemProperty}, + {"removeSystemProperty", "(Ljava/lang/String;)Z", (void*)removeSystemProperty}, +}; + extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { ALOGI("%s: JNI_OnLoad", __FILE__); maybeRedirectLog(); + + JNIEnv* env = GetJNIEnvOrDie(vm); + gVM = vm; + + // Fetch several references for future use + gRunnerState = FindGlobalClassOrDie(env, kRunnerState); + gCheckSystemPropertyAccess = + GetStaticMethodIDOrDie(env, gRunnerState, "checkSystemPropertyAccess", + "(Ljava/lang/String;Z)V"); + + // Expose raw property methods as JNI methods + jint res = jniRegisterNativeMethods(env, kRuntimeNative, sMethods, NELEM(sMethods)); + if (res < 0) return -1; + return JNI_VERSION_1_4; } diff --git a/ravenwood/runtime-jni/ravenwood_sysprop.cpp b/ravenwood/runtime-jni/ravenwood_sysprop.cpp deleted file mode 100644 index a78aa8da9052..000000000000 --- a/ravenwood/runtime-jni/ravenwood_sysprop.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <dlfcn.h> - -#include <set> - -#include "jni_helper.h" - -// Implement a rudimentary system properties data store - -#define PROP_VALUE_MAX 92 - -namespace { - -struct prop_info { - std::string key; - mutable std::string value; - mutable uint32_t serial; - - prop_info(const char* key, const char* value) : key(key), value(value), serial(0) {} -}; - -struct prop_info_cmp { - using is_transparent = void; - bool operator()(const prop_info& lhs, const prop_info& rhs) { - return lhs.key < rhs.key; - } - bool operator()(std::string_view lhs, const prop_info& rhs) { - return lhs < rhs.key; - } - bool operator()(const prop_info& lhs, std::string_view rhs) { - return lhs.key < rhs; - } -}; - -} // namespace - -static auto& g_properties_lock = *new std::mutex; -static auto& g_properties = *new std::set<prop_info, prop_info_cmp>; - -static bool property_set(const char* key, const char* value) { - if (key == nullptr || *key == '\0') return false; - if (value == nullptr) value = ""; - bool read_only = !strncmp(key, "ro.", 3); - if (!read_only && strlen(value) >= PROP_VALUE_MAX) return false; - - std::lock_guard lock(g_properties_lock); - auto [it, success] = g_properties.emplace(key, value); - if (read_only) return success; - if (!success) { - it->value = value; - ++it->serial; - } - return true; -} - -template <typename Func> -static void property_get(const char* key, Func callback) { - std::lock_guard lock(g_properties_lock); - auto it = g_properties.find(key); - if (it != g_properties.end()) { - callback(*it); - } -} - -// Redefine the __system_property_XXX functions here so we can perform -// logging and access checks for all sysprops in native code. - -static void check_system_property_access(const char* key, bool write); - -extern "C" { - -int __system_property_set(const char* key, const char* value) { - check_system_property_access(key, true); - return property_set(key, value) ? 0 : -1; -} - -int __system_property_get(const char* key, char* value) { - check_system_property_access(key, false); - *value = '\0'; - property_get(key, [&](const prop_info& info) { - snprintf(value, PROP_VALUE_MAX, "%s", info.value.c_str()); - }); - return strlen(value); -} - -const prop_info* __system_property_find(const char* key) { - check_system_property_access(key, false); - const prop_info* pi = nullptr; - property_get(key, [&](const prop_info& info) { pi = &info; }); - return pi; -} - -void __system_property_read_callback(const prop_info* pi, - void (*callback)(void*, const char*, const char*, uint32_t), - void* cookie) { - std::lock_guard lock(g_properties_lock); - callback(cookie, pi->key.c_str(), pi->value.c_str(), pi->serial); -} - -} // extern "C" - -// ---- JNI ---- - -static JavaVM* gVM = nullptr; -static jclass gRunnerState = nullptr; -static jmethodID gCheckSystemPropertyAccess; - -static void reloadNativeLibrary(JNIEnv* env, jclass, jstring javaPath) { - ScopedUtfChars path(env, javaPath); - // Force reload ourselves as global - dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL | RTLD_NOLOAD); -} - -// Call back into Java code to check property access -static void check_system_property_access(const char* key, bool write) { - if (gVM != nullptr && gRunnerState != nullptr) { - JNIEnv* env; - if (gVM->GetEnv((void**)&env, JNI_VERSION_1_4) >= 0) { - ALOGI("%s access to system property '%s'", write ? "Write" : "Read", key); - env->CallStaticVoidMethod(gRunnerState, gCheckSystemPropertyAccess, - env->NewStringUTF(key), write ? JNI_TRUE : JNI_FALSE); - return; - } - } - // Not on JVM thread, abort - LOG_ALWAYS_FATAL("Access to system property '%s' on non-JVM threads is not allowed.", key); -} - -static jstring getSystemProperty(JNIEnv* env, jclass, jstring javaKey) { - ScopedUtfChars key(env, javaKey); - jstring value = nullptr; - property_get(key.c_str(), - [&](const prop_info& info) { value = env->NewStringUTF(info.value.c_str()); }); - return value; -} - -static jboolean setSystemProperty(JNIEnv* env, jclass, jstring javaKey, jstring javaValue) { - ScopedUtfChars key(env, javaKey); - ScopedUtfChars value(env, javaValue); - return property_set(key.c_str(), value.c_str()) ? JNI_TRUE : JNI_FALSE; -} - -static jboolean removeSystemProperty(JNIEnv* env, jclass, jstring javaKey) { - std::lock_guard lock(g_properties_lock); - - if (javaKey == nullptr) { - g_properties.clear(); - return JNI_TRUE; - } else { - ScopedUtfChars key(env, javaKey); - auto it = g_properties.find(key); - if (it != g_properties.end()) { - g_properties.erase(it); - return JNI_TRUE; - } else { - return JNI_FALSE; - } - } -} - -static const JNINativeMethod sMethods[] = { - {"reloadNativeLibrary", "(Ljava/lang/String;)V", (void*)reloadNativeLibrary}, - {"getSystemProperty", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getSystemProperty}, - {"setSystemProperty", "(Ljava/lang/String;Ljava/lang/String;)Z", (void*)setSystemProperty}, - {"removeSystemProperty", "(Ljava/lang/String;)Z", (void*)removeSystemProperty}, -}; - -extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { - ALOGI("%s: JNI_OnLoad", __FILE__); - - JNIEnv* env = GetJNIEnvOrDie(vm); - gVM = vm; - - // Fetch several references for future use - gRunnerState = FindGlobalClassOrDie(env, kRunnerState); - gCheckSystemPropertyAccess = - GetStaticMethodIDOrDie(env, gRunnerState, "checkSystemPropertyAccess", - "(Ljava/lang/String;Z)V"); - - // Expose raw property methods as JNI methods - jint res = jniRegisterNativeMethods(env, kRuntimeNative, sMethods, NELEM(sMethods)); - if (res < 0) return -1; - - return JNI_VERSION_1_4; -} |