diff options
author | Martin Stjernholm <mast@google.com> | 2021-04-28 16:47:01 +0100 |
---|---|---|
committer | Martin Stjernholm <mast@google.com> | 2021-05-05 12:07:48 +0000 |
commit | 0d0f8df5070dc6c6e5a5809d8a57e0212a1a5164 (patch) | |
tree | fe0fc4815a3af6dfd5cd3e17a672362647c78af0 /libnativeloader/native_loader.cpp | |
parent | 2207b7e7db463dfa96d071654c49268e22e8745f (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.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 |