summaryrefslogtreecommitdiffstats
path: root/libnativeloader
diff options
context:
space:
mode:
authorZhenhua WANG <zhenhua.wang@intel.com>2016-05-30 11:16:08 +0800
committerDimitry Ivanov <dimitry@google.com>2016-10-25 11:11:38 -0700
commitf2804e59854c2c7e7d3d5b58f987e5ec5cdc5b66 (patch)
tree536a348fda09a1b31edecd5ef12a58e47a588bf9 /libnativeloader
parent0ca2fe4c43e4d525979befd0a59d80fb0a9fa649 (diff)
downloadsystem_core-f2804e59854c2c7e7d3d5b58f987e5ec5cdc5b66.tar.gz
system_core-f2804e59854c2c7e7d3d5b58f987e5ec5cdc5b66.tar.bz2
system_core-f2804e59854c2c7e7d3d5b58f987e5ec5cdc5b66.zip
Upgrade native bridge to version 3 to support namespace
Native bridge implements namespace related interfaces in version 3. The namespace semantic here is same as Android dynamic linker's. Native loader wraps library loading functions of dynamic linker and native bridge. Thus, Android runtime is able to load native library of different ISA on one device by calling native loader directly. Bug: http://b/28242460 Test: mm && make test-art-host -j48 Change-Id: Idde2b9d99fb6ebe547407c716b5478a231f745a7 Signed-off-by: Zhenhua WANG <zhenhua.wang@intel.com>
Diffstat (limited to 'libnativeloader')
-rw-r--r--libnativeloader/Android.bp1
-rw-r--r--libnativeloader/include/nativeloader/native_loader.h7
-rw-r--r--libnativeloader/native_loader.cpp246
3 files changed, 200 insertions, 54 deletions
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index 30531bcbd..9d3389958 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -8,6 +8,7 @@ cc_library {
"libnativehelper",
"liblog",
"libcutils",
+ "libnativebridge",
],
static_libs: ["libbase"],
target: {
diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index 2a6aaec50..99ae3a759 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -19,6 +19,7 @@
#include "jni.h"
#include <stdint.h>
+#include <string>
#if defined(__ANDROID__)
#include <android/dlext.h>
#endif
@@ -41,10 +42,12 @@ 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);
__attribute__((visibility("default")))
-bool CloseNativeLibrary(void* handle);
+bool CloseNativeLibrary(void* handle, const bool needs_native_bridge);
#if defined(__ANDROID__)
// Look up linker namespace by class_loader. Returns nullptr if
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