summaryrefslogtreecommitdiff
path: root/libnativeloader/native_loader.cpp
diff options
context:
space:
mode:
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