[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
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 0c2ce8d..66c8d0f 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -282,20 +282,12 @@
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 @@
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 b3987f4..172cec3 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 @@
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 @@
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 @@
// 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 89fb7c3..dbbc345 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 @@
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 a78aa8d..0000000
--- 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;
-}