diff options
Diffstat (limited to 'libnativeloader/native_loader.cpp')
-rw-r--r-- | libnativeloader/native_loader.cpp | 175 |
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 |