summaryrefslogtreecommitdiff
path: root/libnativeloader/native_loader.cpp
diff options
context:
space:
mode:
authorMartin Stjernholm <mast@google.com>2021-04-28 16:47:01 +0100
committerMartin Stjernholm <mast@google.com>2021-05-05 12:07:48 +0000
commit0d0f8df5070dc6c6e5a5809d8a57e0212a1a5164 (patch)
treefe0fc4815a3af6dfd5cd3e17a672362647c78af0 /libnativeloader/native_loader.cpp
parent2207b7e7db463dfa96d071654c49268e22e8745f (diff)
In run tests, do not rely on loading native libs in the ART namespace
with an allow_all_shared_libs fallback to system. The system and com_android_art namespaces need to be properly separated, but run tests have relied on loading test libraries through either LD_LIBRARY_PATH or java.library.path without a clear separation. That has worked through a combination of ANDROID_ADDITIONAL_PUBLIC_LIBRARIES and fallback dlopen() calls that used the ART namespace. This change introduces a new directory /data/nativetest(64)/com.android.art for test libraries that depend on internal ART libraries. It's added with LD_LIBRARY_PATH to the default namespace, which in the APEX linker config has full access to com_android_art. Normal JNI libraries that don't depend on ART internals stay in /data/nativetest(64)/art/<arch>. There should be no overlap between the two locations. A new environment variable NATIVELOADER_DEFAULT_NAMESPACE_LIBS is introduced to list the libraries added through LD_LIBRARY_PATH, so libnativeloader can link to them from classloader namespaces and in the fallback namespace when no classloader is specified. Like ANDROID_ADDITIONAL_PUBLIC_LIBRARIES, NATIVELOADER_DEFAULT_NAMESPACE_LIBS is only effective when ro.debuggable is true. A new cc_defaults "art_test_internal_library_defaults" is added to Android.bp, to be used in libraries that should be installed in the new com.android.art directory. Some run tests that are special and need more treatment are disabled for now, to be addressed in b/186654484. Test: art/test/testrunner/testrunner.py --target --64 --optimizing Test: art/test/testrunner/testrunner.py --target --32 --jit Test: art/test/testrunner/testrunner.py --host --64 --optimizing Bug: 130340935 Change-Id: Iec640d5e22b46af2c1a4d375ce3f06c57b1d224e
Diffstat (limited to 'libnativeloader/native_loader.cpp')
-rw-r--r--libnativeloader/native_loader.cpp175
1 files changed, 170 insertions, 5 deletions
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 64d60ea6cc..b34692ae16 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -29,7 +29,9 @@
#include <android-base/file.h>
#include <android-base/macros.h>
+#include <android-base/properties.h>
#include <android-base/strings.h>
+#include <android-base/thread_annotations.h>
#include <nativebridge/native_bridge.h>
#include <nativehelper/scoped_utf_chars.h>
@@ -42,11 +44,36 @@
namespace android {
namespace {
+
#if defined(ART_TARGET_ANDROID)
+
+// NATIVELOADER_DEFAULT_NAMESPACE_LIBS is an environment variable that can be
+// used when ro.debuggable is true to list extra libraries (separated by ":")
+// that libnativeloader will load from the default namespace. The libraries must
+// be listed without paths, and then LD_LIBRARY_PATH is typically set to the
+// directories to load them from. The libraries will be available in all
+// classloader namespaces, and also in the fallback namespace used when no
+// classloader is given.
+//
+// kNativeloaderExtraLibs is the name of that fallback namespace.
+//
+// NATIVELOADER_DEFAULT_NAMESPACE_LIBS is intended to be used for testing only,
+// and in particular in the ART run tests that are executed through dalvikvm in
+// the APEX. In that case the default namespace links to the ART namespace
+// (com_android_art) for all libraries, which means this can be used to load
+// test libraries that depend on ART internal libraries.
+constexpr const char* kNativeloaderExtraLibs = "nativeloader-extra-libs";
+
+bool Debuggable() {
+ static bool debuggable = android::base::GetBoolProperty("ro.debuggable", false);
+ return debuggable;
+}
+
using android::nativeloader::LibraryNamespaces;
std::mutex g_namespaces_mutex;
LibraryNamespaces* g_namespaces = new LibraryNamespaces;
+NativeLoaderNamespace* g_nativeloader_extra_libs_namespace = nullptr;
android_namespace_t* FindExportedNamespace(const char* caller_location) {
auto name = nativeloader::FindApexNamespaceName(caller_location);
@@ -58,7 +85,98 @@ android_namespace_t* FindExportedNamespace(const char* caller_location) {
}
return nullptr;
}
+
+Result<void> CreateNativeloaderDefaultNamespaceLibsLink(NativeLoaderNamespace& ns)
+ REQUIRES(g_namespaces_mutex) {
+ const char* links = getenv("NATIVELOADER_DEFAULT_NAMESPACE_LIBS");
+ if (links == nullptr || *links == 0) {
+ return {};
+ }
+ // Pass nullptr to Link() to create a link to the default namespace without
+ // requiring it to be visible.
+ return ns.Link(nullptr, links);
+}
+
+Result<NativeLoaderNamespace*> GetNativeloaderExtraLibsNamespace() REQUIRES(g_namespaces_mutex) {
+ if (g_nativeloader_extra_libs_namespace != nullptr) {
+ return g_nativeloader_extra_libs_namespace;
+ }
+
+ Result<NativeLoaderNamespace> ns =
+ NativeLoaderNamespace::Create(kNativeloaderExtraLibs,
+ /*search_paths=*/"",
+ /*permitted_paths=*/"",
+ /*parent=*/nullptr,
+ /*is_shared=*/false,
+ /*is_exempt_list_enabled=*/false,
+ /*also_used_as_anonymous=*/false);
+ if (!ns.ok()) {
+ return ns.error();
+ }
+ g_nativeloader_extra_libs_namespace = new NativeLoaderNamespace(std::move(ns.value()));
+ Result<void> linked =
+ CreateNativeloaderDefaultNamespaceLibsLink(*g_nativeloader_extra_libs_namespace);
+ if (!linked.ok()) {
+ return linked.error();
+ }
+ return g_nativeloader_extra_libs_namespace;
+}
+
+// If the given path matches a library in NATIVELOADER_DEFAULT_NAMESPACE_LIBS
+// then load it in the nativeloader-extra-libs namespace, otherwise return
+// nullptr without error. This is only enabled if the ro.debuggable is true.
+Result<void*> TryLoadNativeloaderExtraLib(const char* path) {
+ if (!Debuggable()) {
+ return nullptr;
+ }
+ const char* links = getenv("NATIVELOADER_DEFAULT_NAMESPACE_LIBS");
+ if (links == nullptr || *links == 0) {
+ return nullptr;
+ }
+ std::vector<std::string> lib_list = base::Split(links, ":");
+ if (std::find(lib_list.begin(), lib_list.end(), path) == lib_list.end()) {
+ return nullptr;
+ }
+
+ std::lock_guard<std::mutex> guard(g_namespaces_mutex);
+ Result<NativeLoaderNamespace*> ns = GetNativeloaderExtraLibsNamespace();
+ if (!ns.ok()) {
+ return ns.error();
+ }
+ return ns.value()->Load(path);
+}
+
+Result<NativeLoaderNamespace*> CreateClassLoaderNamespaceLocked(JNIEnv* env,
+ int32_t target_sdk_version,
+ jobject class_loader,
+ bool is_shared,
+ jstring dex_path,
+ jstring library_path,
+ jstring permitted_path,
+ jstring uses_library_list)
+ REQUIRES(g_namespaces_mutex) {
+ Result<NativeLoaderNamespace*> ns = g_namespaces->Create(env,
+ target_sdk_version,
+ class_loader,
+ is_shared,
+ dex_path,
+ library_path,
+ permitted_path,
+ uses_library_list);
+ if (!ns.ok()) {
+ return ns;
+ }
+ if (Debuggable()) {
+ Result<void> linked = CreateNativeloaderDefaultNamespaceLibsLink(*ns.value());
+ if (!linked.ok()) {
+ return linked.error();
+ }
+ }
+ return ns;
+}
+
#endif // #if defined(ART_TARGET_ANDROID)
+
} // namespace
void InitializeNativeLoader() {
@@ -72,6 +190,8 @@ void ResetNativeLoader() {
#if defined(ART_TARGET_ANDROID)
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
g_namespaces->Reset();
+ delete(g_nativeloader_extra_libs_namespace);
+ g_nativeloader_extra_libs_namespace = nullptr;
#endif
}
@@ -80,8 +200,14 @@ jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobj
jstring permitted_path, jstring uses_library_list) {
#if defined(ART_TARGET_ANDROID)
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- auto ns = g_namespaces->Create(env, target_sdk_version, class_loader, is_shared, dex_path,
- library_path, permitted_path, uses_library_list);
+ Result<NativeLoaderNamespace*> ns = CreateClassLoaderNamespaceLocked(env,
+ target_sdk_version,
+ class_loader,
+ is_shared,
+ dex_path,
+ library_path,
+ permitted_path,
+ uses_library_list);
if (!ns.ok()) {
return env->NewStringUTF(ns.error().message().c_str());
}
@@ -97,6 +223,7 @@ void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* pat
bool* needs_native_bridge, char** error_msg) {
#if defined(ART_TARGET_ANDROID)
UNUSED(target_sdk_version);
+
if (class_loader == nullptr) {
*needs_native_bridge = false;
if (caller_location != nullptr) {
@@ -113,6 +240,20 @@ void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* pat
return handle;
}
}
+
+ // Check if the library is in NATIVELOADER_DEFAULT_NAMESPACE_LIBS and should
+ // be loaded from the kNativeloaderExtraLibs namespace.
+ {
+ Result<void*> handle = TryLoadNativeloaderExtraLib(path);
+ if (!handle.ok()) {
+ *error_msg = strdup(handle.error().message().c_str());
+ return nullptr;
+ }
+ if (handle.value() != nullptr) {
+ return handle.value();
+ }
+ }
+
void* handle = dlopen(path, RTLD_NOW);
if (handle == nullptr) {
*error_msg = strdup(dlerror());
@@ -127,8 +268,14 @@ void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* pat
// This is the case where the classloader was not created by ApplicationLoaders
// In this case we create an isolated not-shared namespace for it.
Result<NativeLoaderNamespace*> isolated_ns =
- g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */, nullptr,
- library_path, nullptr, nullptr);
+ CreateClassLoaderNamespaceLocked(env,
+ target_sdk_version,
+ class_loader,
+ /*is_shared=*/false,
+ /*dex_path=*/nullptr,
+ library_path,
+ /*permitted_path=*/nullptr,
+ /*uses_library_list=*/nullptr);
if (!isolated_ns.ok()) {
*error_msg = strdup(isolated_ns.error().message().c_str());
return nullptr;
@@ -238,6 +385,24 @@ NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobje
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
}
-#endif
+
+void LinkNativeLoaderNamespaceToExportedNamespaceLibrary(struct NativeLoaderNamespace* ns,
+ const char* exported_ns_name,
+ const char* library_name,
+ char** error_msg) {
+ Result<NativeLoaderNamespace> exported_ns =
+ NativeLoaderNamespace::GetExportedNamespace(exported_ns_name, ns->IsBridged());
+ if (!exported_ns.ok()) {
+ *error_msg = strdup(exported_ns.error().message().c_str());
+ return;
+ }
+
+ Result<void> linked = ns->Link(&exported_ns.value(), std::string(library_name));
+ if (!linked.ok()) {
+ *error_msg = strdup(linked.error().message().c_str());
+ }
+}
+
+#endif // ART_TARGET_ANDROID
}; // namespace android