summaryrefslogtreecommitdiffstats
path: root/libnativeloader/native_loader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libnativeloader/native_loader.cpp')
-rw-r--r--libnativeloader/native_loader.cpp246
1 files changed, 194 insertions, 52 deletions
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 3a6e54d82..fb95cb63d 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -24,6 +24,7 @@
#include "android/log.h"
#include "cutils/properties.h"
#endif
+#include "nativebridge/native_bridge.h"
#include <algorithm>
#include <vector>
@@ -34,11 +35,53 @@
#include <android-base/macros.h>
#include <android-base/strings.h>
+#define CHECK(predicate) LOG_ALWAYS_FATAL_IF(!(predicate),\
+ "%s:%d: %s CHECK '" #predicate "' failed.",\
+ __FILE__, __LINE__, __FUNCTION__)
+
namespace android {
#if defined(__ANDROID__)
-static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt";
-static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt";
+class NativeLoaderNamespace {
+ public:
+ NativeLoaderNamespace()
+ : android_ns_(nullptr), native_bridge_ns_(nullptr) { }
+
+ explicit NativeLoaderNamespace(android_namespace_t* ns)
+ : android_ns_(ns), native_bridge_ns_(nullptr) { }
+
+ explicit NativeLoaderNamespace(native_bridge_namespace_t* ns)
+ : android_ns_(nullptr), native_bridge_ns_(ns) { }
+
+ NativeLoaderNamespace(NativeLoaderNamespace&& that) = default;
+ NativeLoaderNamespace(const NativeLoaderNamespace& that) = default;
+
+ NativeLoaderNamespace& operator=(const NativeLoaderNamespace& that) = default;
+
+ android_namespace_t* get_android_ns() const {
+ CHECK(native_bridge_ns_ == nullptr);
+ return android_ns_;
+ }
+
+ native_bridge_namespace_t* get_native_bridge_ns() const {
+ CHECK(android_ns_ == nullptr);
+ return native_bridge_ns_;
+ }
+
+ bool is_android_namespace() const {
+ return native_bridge_ns_ == nullptr;
+ }
+
+ private:
+ // Only one of them can be not null
+ android_namespace_t* android_ns_;
+ native_bridge_namespace_t* native_bridge_ns_;
+};
+
+static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot =
+ "/etc/public.libraries.txt";
+static constexpr const char* kPublicNativeLibrariesVendorConfig =
+ "/vendor/etc/public.libraries.txt";
// (http://b/27588281) This is a workaround for apps using custom classloaders and calling
// System.load() with an absolute path which is outside of the classloader library search path.
@@ -55,11 +98,13 @@ class LibraryNamespaces {
public:
LibraryNamespaces() : initialized_(false) { }
- android_namespace_t* Create(JNIEnv* env,
- jobject class_loader,
- bool is_shared,
- jstring java_library_path,
- jstring java_permitted_path) {
+ bool Create(JNIEnv* env,
+ jobject class_loader,
+ bool is_shared,
+ jstring java_library_path,
+ jstring java_permitted_path,
+ NativeLoaderNamespace* ns,
+ std::string* error_msg) {
std::string library_path; // empty string by default.
if (java_library_path != nullptr) {
@@ -82,13 +127,13 @@ class LibraryNamespaces {
}
}
- if (!initialized_ && !InitPublicNamespace(library_path.c_str())) {
- return nullptr;
+ if (!initialized_ && !InitPublicNamespace(library_path.c_str(), error_msg)) {
+ return false;
}
- android_namespace_t* ns = FindNamespaceByClassLoader(env, class_loader);
+ bool found = FindNamespaceByClassLoader(env, class_loader, nullptr);
- LOG_ALWAYS_FATAL_IF(ns != nullptr,
+ LOG_ALWAYS_FATAL_IF(found,
"There is already a namespace associated with this classloader");
uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED;
@@ -96,28 +141,66 @@ class LibraryNamespaces {
namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
}
- android_namespace_t* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
+ NativeLoaderNamespace parent_ns;
+ bool found_parent_namespace = FindParentNamespaceByClassLoader(env, class_loader, &parent_ns);
- ns = android_create_namespace("classloader-namespace",
- nullptr,
- library_path.c_str(),
- namespace_type,
- permitted_path.c_str(),
- parent_ns);
+ bool is_native_bridge = false;
+
+ if (found_parent_namespace) {
+ is_native_bridge = !parent_ns.is_android_namespace();
+ } else if (!library_path.empty()) {
+ is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
+ }
+
+ NativeLoaderNamespace native_loader_ns;
+ if (!is_native_bridge) {
+ android_namespace_t* ns = android_create_namespace("classloader-namespace",
+ nullptr,
+ library_path.c_str(),
+ namespace_type,
+ permitted_path.c_str(),
+ parent_ns.get_android_ns());
+ if (ns == nullptr) {
+ *error_msg = dlerror();
+ return false;
+ }
+
+ native_loader_ns = NativeLoaderNamespace(ns);
+ } else {
+ native_bridge_namespace_t* ns = NativeBridgeCreateNamespace("classloader-namespace",
+ nullptr,
+ library_path.c_str(),
+ namespace_type,
+ permitted_path.c_str(),
+ parent_ns.get_native_bridge_ns());
+ if (ns == nullptr) {
+ *error_msg = NativeBridgeGetError();
+ return false;
+ }
- if (ns != nullptr) {
- namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
+ native_loader_ns = NativeLoaderNamespace(ns);
}
- return ns;
+ namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns));
+
+ *ns = native_loader_ns;
+ return true;
}
- android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+ bool FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader, NativeLoaderNamespace* ns) {
auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
- [&](const std::pair<jweak, android_namespace_t*>& value) {
+ [&](const std::pair<jweak, NativeLoaderNamespace>& value) {
return env->IsSameObject(value.first, class_loader);
});
- return it != namespaces_.end() ? it->second : nullptr;
+ if (it != namespaces_.end()) {
+ if (ns != nullptr) {
+ *ns = it->second;
+ }
+
+ return true;
+ }
+
+ return false;
}
void Initialize() {
@@ -217,12 +300,25 @@ class LibraryNamespaces {
return true;
}
- bool InitPublicNamespace(const char* library_path) {
+ bool InitPublicNamespace(const char* library_path, std::string* error_msg) {
+ // Ask native bride if this apps library path should be handled by it
+ bool is_native_bridge = NativeBridgeIsPathSupported(library_path);
+
// (http://b/25844435) - Some apps call dlopen from generated code (mono jited
// code is one example) unknown to linker in which case linker uses anonymous
// namespace. The second argument specifies the search path for the anonymous
// namespace which is the library_path of the classloader.
- initialized_ = android_init_namespaces(public_libraries_.c_str(), library_path);
+ if (!is_native_bridge) {
+ initialized_ = android_init_namespaces(public_libraries_.c_str(), library_path);
+ if (!initialized_) {
+ *error_msg = dlerror();
+ }
+ } else {
+ initialized_ = NativeBridgeInitNamespace(public_libraries_.c_str(), library_path);
+ if (!initialized_) {
+ *error_msg = NativeBridgeGetError();
+ }
+ }
return initialized_;
}
@@ -236,22 +332,24 @@ class LibraryNamespaces {
return env->CallObjectMethod(class_loader, get_parent);
}
- android_namespace_t* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+ bool FindParentNamespaceByClassLoader(JNIEnv* env,
+ jobject class_loader,
+ NativeLoaderNamespace* ns) {
jobject parent_class_loader = GetParentClassLoader(env, class_loader);
while (parent_class_loader != nullptr) {
- android_namespace_t* ns = FindNamespaceByClassLoader(env, parent_class_loader);
- if (ns != nullptr) {
- return ns;
+ if (FindNamespaceByClassLoader(env, parent_class_loader, ns)) {
+ return true;
}
parent_class_loader = GetParentClassLoader(env, parent_class_loader);
}
- return nullptr;
+
+ return false;
}
bool initialized_;
- std::vector<std::pair<jweak, android_namespace_t*>> namespaces_;
+ std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
std::string public_libraries_;
@@ -285,13 +383,18 @@ jstring CreateClassLoaderNamespace(JNIEnv* env,
#if defined(__ANDROID__)
UNUSED(target_sdk_version);
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- android_namespace_t* ns = g_namespaces->Create(env,
- class_loader,
- is_shared,
- library_path,
- permitted_path);
- if (ns == nullptr) {
- return env->NewStringUTF(dlerror());
+
+ std::string error_msg;
+ NativeLoaderNamespace ns;
+ bool success = g_namespaces->Create(env,
+ class_loader,
+ is_shared,
+ library_path,
+ permitted_path,
+ &ns,
+ &error_msg);
+ if (!success) {
+ return env->NewStringUTF(error_msg.c_str());
}
#else
UNUSED(env, target_sdk_version, class_loader, is_shared,
@@ -304,44 +407,83 @@ void* OpenNativeLibrary(JNIEnv* env,
int32_t target_sdk_version,
const char* path,
jobject class_loader,
- jstring library_path) {
+ jstring library_path,
+ bool* needs_native_bridge,
+ std::string* error_msg) {
#if defined(__ANDROID__)
UNUSED(target_sdk_version);
if (class_loader == nullptr) {
+ *needs_native_bridge = false;
return dlopen(path, RTLD_NOW);
}
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- android_namespace_t* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+ NativeLoaderNamespace ns;
- if (ns == nullptr) {
+ if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
// This is the case where the classloader was not created by ApplicationLoaders
// In this case we create an isolated not-shared namespace for it.
- ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr);
- if (ns == nullptr) {
+ if (!g_namespaces->Create(env, class_loader, false, library_path, nullptr, &ns, error_msg)) {
return nullptr;
}
}
- android_dlextinfo extinfo;
- extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
- extinfo.library_namespace = ns;
+ if (ns.is_android_namespace()) {
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns.get_android_ns();
- return android_dlopen_ext(path, RTLD_NOW, &extinfo);
+ void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
+ if (handle == nullptr) {
+ *error_msg = dlerror();
+ }
+ *needs_native_bridge = false;
+ return handle;
+ } else {
+ void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());
+ if (handle == nullptr) {
+ *error_msg = NativeBridgeGetError();
+ }
+ *needs_native_bridge = true;
+ return handle;
+ }
#else
UNUSED(env, target_sdk_version, class_loader, library_path);
- return dlopen(path, RTLD_NOW);
+ *needs_native_bridge = false;
+ void* handle = dlopen(path, RTLD_NOW);
+ if (handle == nullptr) {
+ if (NativeBridgeIsSupported(path)) {
+ *needs_native_bridge = true;
+ handle = NativeBridgeLoadLibrary(path, RTLD_NOW);
+ if (handle == nullptr) {
+ *error_msg = NativeBridgeGetError();
+ }
+ } else {
+ *needs_native_bridge = false;
+ *error_msg = dlerror();
+ }
+ }
+ return handle;
#endif
}
-bool CloseNativeLibrary(void* handle) {
- return dlclose(handle) == 0;
+bool CloseNativeLibrary(void* handle, const bool needs_native_bridge) {
+ return needs_native_bridge ? NativeBridgeUnloadLibrary(handle) :
+ dlclose(handle);
}
#if defined(__ANDROID__)
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+ // native_bridge_namespaces are not supported for callers of this function.
+ // At the moment this is libwebviewchromium_loader and vulkan.
+ NativeLoaderNamespace ns;
+ if (g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
+ CHECK(ns.is_android_namespace());
+ return ns.get_android_ns();
+ }
+
+ return nullptr;
}
#endif