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.cpp328
1 files changed, 248 insertions, 80 deletions
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 2deb5ef3d0..ea06b2041f 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -24,19 +24,24 @@
#include <algorithm>
#include <memory>
#include <mutex>
+#include <optional>
+#include <regex>
#include <string>
#include <vector>
-#include <android-base/file.h>
-#include <android-base/macros.h>
-#include <android-base/strings.h>
-#include <android-base/thread_annotations.h>
-#include <nativebridge/native_bridge.h>
-#include <nativehelper/scoped_utf_chars.h>
+#include "android-base/file.h"
+#include "android-base/macros.h"
+#include "android-base/strings.h"
+#include "android-base/thread_annotations.h"
+#include "base/macros.h"
+#include "nativebridge/native_bridge.h"
+#include "nativehelper/scoped_utf_chars.h"
+#include "public_libraries.h"
#ifdef ART_TARGET_ANDROID
-#include <log/log.h>
+#include "android-modules-utils/sdk_level.h"
#include "library_namespaces.h"
+#include "log/log.h"
#include "nativeloader/dlext_namespaces.h"
#endif
@@ -46,6 +51,12 @@ namespace {
#if defined(ART_TARGET_ANDROID)
+using ::android::base::Result;
+using ::android::nativeloader::LibraryNamespaces;
+
+const std::regex kPartitionNativeLibPathRegex(
+ "/(system(_ext)?|(system/)?(vendor|product))/lib(64)?/.*");
+
// NATIVELOADER_DEFAULT_NAMESPACE_LIBS is an environment variable that can be
// used to list extra libraries (separated by ":") that libnativeloader will
// load from the default namespace. The libraries must be listed without paths,
@@ -62,21 +73,41 @@ namespace {
// test libraries that depend on ART internal libraries.
constexpr const char* kNativeloaderExtraLibs = "nativeloader-extra-libs";
-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);
- if (name.ok()) {
- android_namespace_t* boot_namespace = android_get_exported_namespace(name->c_str());
- LOG_ALWAYS_FATAL_IF((boot_namespace == nullptr),
- "Error finding namespace of apex: no namespace called %s", name->c_str());
- return boot_namespace;
+LibraryNamespaces* g_namespaces GUARDED_BY(g_namespaces_mutex) = new LibraryNamespaces;
+NativeLoaderNamespace* g_nativeloader_extra_libs_namespace GUARDED_BY(g_namespaces_mutex) = nullptr;
+
+std::optional<NativeLoaderNamespace> FindApexNamespace(const char* caller_location) {
+ std::optional<std::string> name = nativeloader::FindApexNamespaceName(caller_location);
+ if (name.has_value()) {
+ // Native Bridge is never used for APEXes.
+ Result<NativeLoaderNamespace> ns =
+ NativeLoaderNamespace::GetExportedNamespace(name.value(), /*is_bridged=*/false);
+ LOG_ALWAYS_FATAL_IF(!ns.ok(),
+ "Error finding ns %s for APEX location %s: %s",
+ name.value().c_str(),
+ caller_location,
+ ns.error().message().c_str());
+ return ns.value();
+ }
+ return std::nullopt;
+}
+
+Result<NativeLoaderNamespace> GetNamespaceForApiDomain(nativeloader::ApiDomain api_domain,
+ bool is_bridged) {
+ switch (api_domain) {
+ case nativeloader::API_DOMAIN_VENDOR:
+ return NativeLoaderNamespace::GetExportedNamespace(nativeloader::kVendorNamespaceName,
+ is_bridged);
+ case nativeloader::API_DOMAIN_PRODUCT:
+ return NativeLoaderNamespace::GetExportedNamespace(nativeloader::kProductNamespaceName,
+ is_bridged);
+ case nativeloader::API_DOMAIN_SYSTEM:
+ return NativeLoaderNamespace::GetSystemNamespace(is_bridged);
+ default:
+ LOG_FATAL("Invalid API domain %d", api_domain);
+ UNREACHABLE();
}
- return nullptr;
}
Result<void> CreateNativeloaderDefaultNamespaceLibsLink(NativeLoaderNamespace& ns)
@@ -133,26 +164,34 @@ Result<void*> TryLoadNativeloaderExtraLib(const char* path) {
if (!ns.ok()) {
return ns.error();
}
- return ns.value()->Load(path);
+
+ Result<void*> res = ns.value()->Load(path);
+ ALOGD("Load %s using ns %s from NATIVELOADER_DEFAULT_NAMESPACE_LIBS match: %s",
+ path,
+ ns.value()->name().c_str(),
+ res.ok() ? "ok" : res.error().message().c_str());
+ return res;
}
Result<NativeLoaderNamespace*> CreateClassLoaderNamespaceLocked(JNIEnv* env,
int32_t target_sdk_version,
jobject class_loader,
+ nativeloader::ApiDomain api_domain,
bool is_shared,
- jstring dex_path,
- jstring library_path,
- jstring permitted_path,
- jstring uses_library_list)
+ const std::string& dex_path,
+ jstring library_path_j,
+ jstring permitted_path_j,
+ jstring uses_library_list_j)
REQUIRES(g_namespaces_mutex) {
Result<NativeLoaderNamespace*> ns = g_namespaces->Create(env,
target_sdk_version,
class_loader,
+ api_domain,
is_shared,
dex_path,
- library_path,
- permitted_path,
- uses_library_list);
+ library_path_j,
+ permitted_path_j,
+ uses_library_list_j);
if (!ns.ok()) {
return ns;
}
@@ -163,7 +202,7 @@ Result<NativeLoaderNamespace*> CreateClassLoaderNamespaceLocked(JNIEnv* env,
return ns;
}
-#endif // #if defined(ART_TARGET_ANDROID)
+#endif // ART_TARGET_ANDROID
} // namespace
@@ -183,47 +222,86 @@ void ResetNativeLoader() {
#endif
}
-jstring CreateClassLoaderNamespace(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) {
+// dex_path_j may be a ':'-separated list of paths, e.g. when creating a shared
+// library loader - cf. mCodePaths in android.content.pm.SharedLibraryInfo.
+jstring CreateClassLoaderNamespace(JNIEnv* env,
+ int32_t target_sdk_version,
+ jobject class_loader,
+ bool is_shared,
+ jstring dex_path_j,
+ jstring library_path_j,
+ jstring permitted_path_j,
+ jstring uses_library_list_j) {
#if defined(ART_TARGET_ANDROID)
+ std::string dex_path;
+ if (dex_path_j != nullptr) {
+ ScopedUtfChars dex_path_chars(env, dex_path_j);
+ dex_path = dex_path_chars.c_str();
+ }
+
+ Result<nativeloader::ApiDomain> api_domain = nativeloader::GetApiDomainFromPathList(dex_path);
+ if (!api_domain.ok()) {
+ return env->NewStringUTF(api_domain.error().message().c_str());
+ }
+
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
Result<NativeLoaderNamespace*> ns = CreateClassLoaderNamespaceLocked(env,
target_sdk_version,
class_loader,
+ api_domain.value(),
is_shared,
dex_path,
- library_path,
- permitted_path,
- uses_library_list);
+ library_path_j,
+ permitted_path_j,
+ uses_library_list_j);
if (!ns.ok()) {
return env->NewStringUTF(ns.error().message().c_str());
}
+
#else
- UNUSED(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path,
- uses_library_list);
+ UNUSED(env,
+ target_sdk_version,
+ class_loader,
+ is_shared,
+ dex_path_j,
+ library_path_j,
+ permitted_path_j,
+ uses_library_list_j);
#endif
+
return nullptr;
}
-void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
- jobject class_loader, const char* caller_location, jstring library_path,
- bool* needs_native_bridge, char** error_msg) {
+void* OpenNativeLibrary(JNIEnv* env,
+ int32_t target_sdk_version,
+ const char* path,
+ jobject class_loader,
+ const char* caller_location,
+ jstring library_path_j,
+ bool* needs_native_bridge,
+ char** error_msg) {
#if defined(ART_TARGET_ANDROID)
- UNUSED(target_sdk_version);
-
if (class_loader == nullptr) {
+ // class_loader is null only for the boot class loader (see
+ // IsBootClassLoader call in JavaVMExt::LoadNativeLibrary), i.e. the caller
+ // is in the boot classpath.
*needs_native_bridge = false;
if (caller_location != nullptr) {
- android_namespace_t* boot_namespace = FindExportedNamespace(caller_location);
- if (boot_namespace != nullptr) {
+ std::optional<NativeLoaderNamespace> ns = FindApexNamespace(caller_location);
+ if (ns.has_value()) {
const android_dlextinfo dlextinfo = {
.flags = ANDROID_DLEXT_USE_NAMESPACE,
- .library_namespace = boot_namespace,
+ .library_namespace = ns.value().ToRawAndroidNamespace(),
};
void* handle = android_dlopen_ext(path, RTLD_NOW, &dlextinfo);
- if (handle == nullptr) {
- *error_msg = strdup(dlerror());
+ char* dlerror_msg = handle == nullptr ? strdup(dlerror()) : nullptr;
+ ALOGD("Load %s using APEX ns %s for caller %s: %s",
+ path,
+ ns.value().name().c_str(),
+ caller_location,
+ dlerror_msg == nullptr ? "ok" : dlerror_msg);
+ if (dlerror_msg != nullptr) {
+ *error_msg = dlerror_msg;
}
return handle;
}
@@ -244,53 +322,141 @@ void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* pat
// Fall back to the system namespace. This happens for preloaded JNI
// libraries in the zygote.
- // TODO(b/185833744): Investigate if this should fall back to the app main
- // namespace (aka anonymous namespace) instead.
void* handle = OpenSystemLibrary(path, RTLD_NOW);
- if (handle == nullptr) {
- *error_msg = strdup(dlerror());
+ char* dlerror_msg = handle == nullptr ? strdup(dlerror()) : nullptr;
+ ALOGD("Load %s using system ns (caller=%s): %s",
+ path,
+ caller_location == nullptr ? "<unknown>" : caller_location,
+ dlerror_msg == nullptr ? "ok" : dlerror_msg);
+ if (dlerror_msg != nullptr) {
+ *error_msg = dlerror_msg;
}
return handle;
}
+ // If the caller is in any of the system image partitions and the library is
+ // in the same partition then load it without regards to public library
+ // restrictions. This is only done if the library is specified by an absolute
+ // path, so we don't affect the lookup process for libraries specified by name
+ // only.
+ if (caller_location != nullptr &&
+ // Check that the library is in the partition-wide native library
+ // location. Apps in the partition may have their own native libraries,
+ // and those should still be loaded with the app's classloader namespace.
+ std::regex_match(path, kPartitionNativeLibPathRegex) &&
+ // Don't do this if the system image is older than V, to avoid any compat
+ // issues with apps and shared libs in them.
+ android::modules::sdklevel::IsAtLeastV()) {
+ nativeloader::ApiDomain caller_api_domain = nativeloader::GetApiDomainFromPath(caller_location);
+ if (caller_api_domain != nativeloader::API_DOMAIN_DEFAULT) {
+ nativeloader::ApiDomain library_api_domain = nativeloader::GetApiDomainFromPath(path);
+
+ if (library_api_domain == caller_api_domain) {
+ bool is_bridged = false;
+ if (library_path_j != nullptr) {
+ ScopedUtfChars library_path_utf_chars(env, library_path_j);
+ if (library_path_utf_chars[0] != '\0') {
+ is_bridged = NativeBridgeIsPathSupported(library_path_utf_chars.c_str());
+ }
+ }
+
+ Result<NativeLoaderNamespace> ns = GetNamespaceForApiDomain(caller_api_domain, is_bridged);
+ if (!ns.ok()) {
+ ALOGD("Failed to find ns for caller %s in API domain %d to load %s (is_bridged=%b): %s",
+ caller_location,
+ caller_api_domain,
+ path,
+ is_bridged,
+ ns.error().message().c_str());
+ *error_msg = strdup(ns.error().message().c_str());
+ return nullptr;
+ }
+
+ *needs_native_bridge = ns.value().IsBridged();
+ Result<void*> handle = ns.value().Load(path);
+ ALOGD("Load %s using ns %s for caller %s in same partition (is_bridged=%b): %s",
+ path,
+ ns.value().name().c_str(),
+ caller_location,
+ is_bridged,
+ handle.ok() ? "ok" : handle.error().message().c_str());
+ if (!handle.ok()) {
+ *error_msg = strdup(handle.error().message().c_str());
+ return nullptr;
+ }
+ return handle.value();
+ }
+ }
+ }
+
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- NativeLoaderNamespace* ns;
-
- if ((ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader)) == nullptr) {
- // 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 =
- 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;
- } else {
- ns = *isolated_ns;
+
+ {
+ NativeLoaderNamespace* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+ if (ns != nullptr) {
+ *needs_native_bridge = ns->IsBridged();
+ Result<void*> handle = ns->Load(path);
+ ALOGD("Load %s using ns %s from class loader (caller=%s): %s",
+ path,
+ ns->name().c_str(),
+ caller_location == nullptr ? "<unknown>" : caller_location,
+ handle.ok() ? "ok" : handle.error().message().c_str());
+ if (!handle.ok()) {
+ *error_msg = strdup(handle.error().message().c_str());
+ return nullptr;
+ }
+ return handle.value();
}
}
- return OpenNativeLibraryInNamespace(ns, path, needs_native_bridge, error_msg);
-#else
+ // This is the case where the classloader was not created by ApplicationLoaders
+ // In this case we create an isolated not-shared namespace for it.
+ const std::string empty_dex_path;
+ Result<NativeLoaderNamespace*> isolated_ns =
+ CreateClassLoaderNamespaceLocked(env,
+ target_sdk_version,
+ class_loader,
+ nativeloader::API_DOMAIN_DEFAULT,
+ /*is_shared=*/false,
+ empty_dex_path,
+ library_path_j,
+ /*permitted_path=*/nullptr,
+ /*uses_library_list=*/nullptr);
+ if (!isolated_ns.ok()) {
+ ALOGD("Failed to create isolated ns for %s (caller=%s)",
+ path,
+ caller_location == nullptr ? "<unknown>" : caller_location);
+ *error_msg = strdup(isolated_ns.error().message().c_str());
+ return nullptr;
+ }
+
+ *needs_native_bridge = isolated_ns.value()->IsBridged();
+ Result<void*> handle = isolated_ns.value()->Load(path);
+ ALOGD("Load %s using isolated ns %s (caller=%s): %s",
+ path,
+ isolated_ns.value()->name().c_str(),
+ caller_location == nullptr ? "<unknown>" : caller_location,
+ handle.ok() ? "ok" : handle.error().message().c_str());
+ if (!handle.ok()) {
+ *error_msg = strdup(handle.error().message().c_str());
+ return nullptr;
+ }
+ return handle.value();
+
+#else // !ART_TARGET_ANDROID
UNUSED(env, target_sdk_version, class_loader, caller_location);
// Do some best effort to emulate library-path support. It will not
// work for dependencies.
//
// Note: null has a special meaning and must be preserved.
- std::string c_library_path; // Empty string by default.
- if (library_path != nullptr && path != nullptr && path[0] != '/') {
- ScopedUtfChars library_path_utf_chars(env, library_path);
- c_library_path = library_path_utf_chars.c_str();
+ std::string library_path; // Empty string by default.
+ if (library_path_j != nullptr && path != nullptr && path[0] != '/') {
+ ScopedUtfChars library_path_utf_chars(env, library_path_j);
+ library_path = library_path_utf_chars.c_str();
}
- std::vector<std::string> library_paths = base::Split(c_library_path, ":");
+ std::vector<std::string> library_paths = base::Split(library_path, ":");
for (const std::string& lib_path : library_paths) {
*needs_native_bridge = false;
@@ -323,7 +489,7 @@ void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* pat
}
}
return nullptr;
-#endif
+#endif // !ART_TARGET_ANDROID
}
bool CloseNativeLibrary(void* handle, const bool needs_native_bridge, char** error_msg) {
@@ -351,7 +517,7 @@ void NativeLoaderFreeErrorMessage(char* msg) {
#if defined(ART_TARGET_ANDROID)
void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path,
bool* needs_native_bridge, char** error_msg) {
- auto handle = ns->Load(path);
+ Result<void*> handle = ns->Load(path);
if (!handle.ok() && error_msg != nullptr) {
*error_msg = strdup(handle.error().message().c_str());
}
@@ -361,6 +527,8 @@ void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path,
return handle.ok() ? *handle : nullptr;
}
+bool IsNamespaceNativeBridged(const struct NativeLoaderNamespace* ns) { return ns->IsBridged(); }
+
// native_bridge_namespaces are not supported for callers of this function.
// This function will return nullptr in the case when application is running
// on native bridge.
@@ -397,4 +565,4 @@ void LinkNativeLoaderNamespaceToExportedNamespaceLibrary(struct NativeLoaderName
#endif // ART_TARGET_ANDROID
-}; // namespace android
+} // namespace android