Loading libnativeloader/library_namespaces.cpp +48 −39 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ #include "public_libraries.h" #include "utils.h" using android::base::Error; namespace android::nativeloader { namespace { Loading Loading @@ -128,11 +130,11 @@ void LibraryNamespaces::Initialize() { } } NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version, Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader, bool is_shared, jstring dex_path, jstring java_library_path, jstring java_permitted_path, std::string* error_msg) { jstring dex_path, jstring java_library_path, jstring java_permitted_path) { std::string library_path; // empty string by default. if (java_library_path != nullptr) { Loading @@ -158,14 +160,14 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd } // Initialize the anonymous namespace with the first non-empty library path. Result<void> ret; if (!library_path.empty() && !initialized_ && !InitPublicNamespace(library_path.c_str(), error_msg)) { return nullptr; !(ret = InitPublicNamespace(library_path.c_str()))) { return ret.error(); } bool found = FindNamespaceByClassLoader(env, class_loader); LOG_ALWAYS_FATAL_IF(found, "There is already a namespace associated with this classloader"); LOG_ALWAYS_FATAL_IF(FindNamespaceByClassLoader(env, class_loader) != nullptr, "There is already a namespace associated with this classloader"); std::string system_exposed_libraries = default_public_libraries(); const char* namespace_name = kClassloaderNamespaceName; Loading Loading @@ -216,58 +218,66 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd auto app_ns = NativeLoaderNamespace::Create(namespace_name, library_path, permitted_path, parent_ns, is_shared, target_sdk_version < 24 /* is_greylist_enabled */); if (app_ns.IsNil()) { *error_msg = app_ns.GetError(); return nullptr; if (!app_ns) { return app_ns.error(); } // ... and link to other namespaces to allow access to some public libraries bool is_bridged = app_ns.IsBridged(); bool is_bridged = app_ns->IsBridged(); auto platform_ns = NativeLoaderNamespace::GetPlatformNamespace(is_bridged); if (!app_ns.Link(platform_ns, system_exposed_libraries)) { *error_msg = app_ns.GetError(); return nullptr; if (!platform_ns) { return platform_ns.error(); } auto linked = app_ns->Link(*platform_ns, system_exposed_libraries); if (!linked) { return linked.error(); } auto runtime_ns = NativeLoaderNamespace::GetExportedNamespace(kRuntimeNamespaceName, is_bridged); // Runtime apex does not exist in host, and under certain build conditions. if (!runtime_ns.IsNil()) { if (!app_ns.Link(runtime_ns, runtime_public_libraries())) { *error_msg = app_ns.GetError(); return nullptr; if (runtime_ns) { linked = app_ns->Link(*runtime_ns, runtime_public_libraries()); if (!linked) { return linked.error(); } } // Give access to NNAPI libraries (apex-updated LLNDK library). auto nnapi_ns = NativeLoaderNamespace::GetExportedNamespace(kNeuralNetworksNamespaceName, is_bridged); if (!app_ns.Link(nnapi_ns, neuralnetworks_public_libraries())) { *error_msg = app_ns.GetError(); return nullptr; if (nnapi_ns) { linked = app_ns->Link(*nnapi_ns, neuralnetworks_public_libraries()); if (!linked) { return linked.error(); } } // Give access to VNDK-SP libraries from the 'vndk' namespace. if (unbundled_vendor_or_product_app && !vndksp_libraries().empty()) { auto vndk_ns = NativeLoaderNamespace::GetExportedNamespace(kVndkNamespaceName, is_bridged); if (!vndk_ns.IsNil() && !app_ns.Link(vndk_ns, vndksp_libraries())) { *error_msg = app_ns.GetError(); return nullptr; if (vndk_ns) { linked = app_ns->Link(*vndk_ns, vndksp_libraries()); if (!linked) { return linked.error(); } } } // Note that when vendor_ns is not configured, vendor_ns.IsNil() will be true // and it will result in linking to the default namespace which is expected // behavior in this case. if (!vendor_public_libraries().empty()) { auto vendor_ns = NativeLoaderNamespace::GetExportedNamespace(kVendorNamespaceName, is_bridged); if (!app_ns.Link(vendor_ns, vendor_public_libraries())) { *error_msg = dlerror(); return nullptr; // when vendor_ns is not configured, link to the platform namespace auto target_ns = vendor_ns ? vendor_ns : platform_ns; if (target_ns) { linked = app_ns->Link(*target_ns, vendor_public_libraries()); if (!linked) { return linked.error(); } } } namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), app_ns)); namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), *app_ns)); return &(namespaces_.back().second); } Loading @@ -285,7 +295,7 @@ NativeLoaderNamespace* LibraryNamespaces::FindNamespaceByClassLoader(JNIEnv* env return nullptr; } bool LibraryNamespaces::InitPublicNamespace(const char* library_path, std::string* error_msg) { Result<void> LibraryNamespaces::InitPublicNamespace(const char* library_path) { // Ask native bride if this apps library path should be handled by it bool is_native_bridge = NativeBridgeIsPathSupported(library_path); Loading @@ -296,8 +306,7 @@ bool LibraryNamespaces::InitPublicNamespace(const char* library_path, std::strin initialized_ = android_init_anonymous_namespace(default_public_libraries().c_str(), is_native_bridge ? nullptr : library_path); if (!initialized_) { *error_msg = dlerror(); return false; return Error() << dlerror(); } // and now initialize native bridge namespaces if necessary. Loading @@ -305,11 +314,11 @@ bool LibraryNamespaces::InitPublicNamespace(const char* library_path, std::strin initialized_ = NativeBridgeInitAnonymousNamespace(default_public_libraries().c_str(), is_native_bridge ? library_path : nullptr); if (!initialized_) { *error_msg = NativeBridgeGetError(); return Error() << NativeBridgeGetError(); } } return initialized_; return {}; } NativeLoaderNamespace* LibraryNamespaces::FindParentNamespaceByClassLoader(JNIEnv* env, Loading libnativeloader/library_namespaces.h +7 −4 Original line number Diff line number Diff line Loading @@ -25,10 +25,13 @@ #include <list> #include <string> #include <android-base/result.h> #include <jni.h> namespace android::nativeloader { using android::base::Result; // LibraryNamespaces is a singleton object that manages NativeLoaderNamespace // objects for an app process. Its main job is to create (and configure) a new // NativeLoaderNamespace object for a Java ClassLoader, and to find an existing Loading @@ -46,13 +49,13 @@ class LibraryNamespaces { namespaces_.clear(); initialized_ = false; } NativeLoaderNamespace* Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader, bool is_shared, jstring dex_path, jstring java_library_path, jstring java_permitted_path, std::string* error_msg); Result<NativeLoaderNamespace*> Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader, bool is_shared, jstring dex_path, jstring java_library_path, jstring java_permitted_path); NativeLoaderNamespace* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader); private: bool InitPublicNamespace(const char* library_path, std::string* error_msg); Result<void> InitPublicNamespace(const char* library_path); NativeLoaderNamespace* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader); bool initialized_; Loading libnativeloader/native_loader.cpp +18 −15 Original line number Diff line number Diff line Loading @@ -92,12 +92,10 @@ jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobj jstring permitted_path) { #if defined(__ANDROID__) std::lock_guard<std::mutex> guard(g_namespaces_mutex); std::string error_msg; bool success = g_namespaces->Create(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path, &error_msg) != nullptr; if (!success) { return env->NewStringUTF(error_msg.c_str()); auto ns = g_namespaces->Create(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path); if (!ns) { return env->NewStringUTF(ns.error().message().c_str()); } #else UNUSED(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path); Loading Loading @@ -139,11 +137,14 @@ void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* pat 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. std::string create_error_msg; if ((ns = g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */, nullptr, library_path, nullptr, &create_error_msg)) == nullptr) { *error_msg = strdup(create_error_msg.c_str()); Result<NativeLoaderNamespace*> isolated_ns = g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */, nullptr, library_path, nullptr); if (!isolated_ns) { *error_msg = strdup(isolated_ns.error().message().c_str()); return nullptr; } else { ns = *isolated_ns; } } Loading Loading @@ -222,12 +223,14 @@ void NativeLoaderFreeErrorMessage(char* msg) { #if defined(__ANDROID__) void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path, bool* needs_native_bridge, char** error_msg) { void* handle = ns->Load(path); if (handle == nullptr) { *error_msg = ns->GetError(); auto handle = ns->Load(path); if (!handle && error_msg != nullptr) { *error_msg = strdup(handle.error().message().c_str()); } if (needs_native_bridge != nullptr) { *needs_native_bridge = ns->IsBridged(); return handle; } return handle ? *handle : nullptr; } // native_bridge_namespaces are not supported for callers of this function. Loading libnativeloader/native_loader_namespace.cpp +63 −33 Original line number Diff line number Diff line Loading @@ -28,6 +28,9 @@ #include "nativeloader/dlext_namespaces.h" using android::base::Error; using android::base::Errorf; namespace android { namespace { Loading @@ -35,41 +38,46 @@ namespace { constexpr const char* kDefaultNamespaceName = "default"; constexpr const char* kPlatformNamespaceName = "platform"; std::string GetLinkerError(bool is_bridged) { const char* msg = is_bridged ? NativeBridgeGetError() : dlerror(); if (msg == nullptr) { return "no error"; } return std::string(msg); } } // namespace NativeLoaderNamespace NativeLoaderNamespace::GetExportedNamespace(const std::string& name, Result<NativeLoaderNamespace> NativeLoaderNamespace::GetExportedNamespace(const std::string& name, bool is_bridged) { if (!is_bridged) { return NativeLoaderNamespace(name, android_get_exported_namespace(name.c_str())); } else { return NativeLoaderNamespace(name, NativeBridgeGetExportedNamespace(name.c_str())); } auto raw = android_get_exported_namespace(name.c_str()); if (raw != nullptr) { return NativeLoaderNamespace(name, raw); } char* NativeLoaderNamespace::GetError() const { if (!IsBridged()) { return strdup(dlerror()); } else { return strdup(NativeBridgeGetError()); auto raw = NativeBridgeGetExportedNamespace(name.c_str()); if (raw != nullptr) { return NativeLoaderNamespace(name, raw); } } return Errorf("namespace {} does not exist or exported", name); } // The platform namespace is called "default" for binaries in /system and // "platform" for those in the Runtime APEX. Try "platform" first since // "default" always exists. NativeLoaderNamespace NativeLoaderNamespace::GetPlatformNamespace(bool is_bridged) { NativeLoaderNamespace ns = GetExportedNamespace(kPlatformNamespaceName, is_bridged); if (ns.IsNil()) { Result<NativeLoaderNamespace> NativeLoaderNamespace::GetPlatformNamespace(bool is_bridged) { auto ns = GetExportedNamespace(kPlatformNamespaceName, is_bridged); if (!ns) { ns = GetExportedNamespace(kDefaultNamespaceName, is_bridged); } return ns; } NativeLoaderNamespace NativeLoaderNamespace::Create(const std::string& name, const std::string& search_paths, const std::string& permitted_paths, const NativeLoaderNamespace* parent, bool is_shared, bool is_greylist_enabled) { Result<NativeLoaderNamespace> NativeLoaderNamespace::Create( const std::string& name, const std::string& search_paths, const std::string& permitted_paths, const NativeLoaderNamespace* parent, bool is_shared, bool is_greylist_enabled) { bool is_bridged = false; if (parent != nullptr) { is_bridged = parent->IsBridged(); Loading @@ -78,8 +86,11 @@ NativeLoaderNamespace NativeLoaderNamespace::Create(const std::string& name, } // Fall back to the platform namespace if no parent is set. const NativeLoaderNamespace& effective_parent = parent != nullptr ? *parent : GetPlatformNamespace(is_bridged); auto platform_ns = GetPlatformNamespace(is_bridged); if (!platform_ns) { return platform_ns.error(); } const NativeLoaderNamespace& effective_parent = parent != nullptr ? *parent : *platform_ns; uint64_t type = ANDROID_NAMESPACE_TYPE_ISOLATED; if (is_shared) { Loading @@ -93,37 +104,56 @@ NativeLoaderNamespace NativeLoaderNamespace::Create(const std::string& name, android_namespace_t* raw = android_create_namespace(name.c_str(), nullptr, search_paths.c_str(), type, permitted_paths.c_str(), effective_parent.ToRawAndroidNamespace()); if (raw != nullptr) { return NativeLoaderNamespace(name, raw); } } else { native_bridge_namespace_t* raw = NativeBridgeCreateNamespace( name.c_str(), nullptr, search_paths.c_str(), type, permitted_paths.c_str(), effective_parent.ToRawNativeBridgeNamespace()); if (raw != nullptr) { return NativeLoaderNamespace(name, raw); } } return Errorf("failed to create {} namespace name:{}, search_paths:{}, permitted_paths:{}", is_bridged ? "bridged" : "native", name, search_paths, permitted_paths); } bool NativeLoaderNamespace::Link(const NativeLoaderNamespace& target, Result<void> NativeLoaderNamespace::Link(const NativeLoaderNamespace& target, const std::string& shared_libs) const { LOG_ALWAYS_FATAL_IF(shared_libs.empty(), "empty share lib when linking %s to %s", this->name().c_str(), target.name().c_str()); if (!IsBridged()) { return android_link_namespaces(this->ToRawAndroidNamespace(), target.ToRawAndroidNamespace(), shared_libs.c_str()); if (android_link_namespaces(this->ToRawAndroidNamespace(), target.ToRawAndroidNamespace(), shared_libs.c_str())) { return {}; } } else { return NativeBridgeLinkNamespaces(this->ToRawNativeBridgeNamespace(), target.ToRawNativeBridgeNamespace(), shared_libs.c_str()); if (NativeBridgeLinkNamespaces(this->ToRawNativeBridgeNamespace(), target.ToRawNativeBridgeNamespace(), shared_libs.c_str())) { return {}; } } return Error() << GetLinkerError(IsBridged()); } void* NativeLoaderNamespace::Load(const char* lib_name) const { Result<void*> NativeLoaderNamespace::Load(const char* lib_name) const { if (!IsBridged()) { android_dlextinfo extinfo; extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; extinfo.library_namespace = this->ToRawAndroidNamespace(); return android_dlopen_ext(lib_name, RTLD_NOW, &extinfo); void* handle = android_dlopen_ext(lib_name, RTLD_NOW, &extinfo); if (handle != nullptr) { return handle; } } else { return NativeBridgeLoadLibraryExt(lib_name, RTLD_NOW, this->ToRawNativeBridgeNamespace()); void* handle = NativeBridgeLoadLibraryExt(lib_name, RTLD_NOW, this->ToRawNativeBridgeNamespace()); if (handle != nullptr) { return handle; } } return Error() << GetLinkerError(IsBridged()); } } // namespace android libnativeloader/native_loader_namespace.h +13 −13 Original line number Diff line number Diff line Loading @@ -21,19 +21,22 @@ #include <vector> #include <android-base/logging.h> #include <android-base/result.h> #include <android/dlext.h> #include <log/log.h> #include <nativebridge/native_bridge.h> namespace android { using android::base::Result; // NativeLoaderNamespace abstracts a linker namespace for the native // architecture (ex: arm on arm) or the translated architecture (ex: arm on // x86). Instances of this class are managed by LibraryNamespaces object. struct NativeLoaderNamespace { public: // TODO(return with errors) static NativeLoaderNamespace Create(const std::string& name, const std::string& search_paths, static Result<NativeLoaderNamespace> Create(const std::string& name, const std::string& search_paths, const std::string& permitted_paths, const NativeLoaderNamespace* parent, bool is_shared, bool is_greylist_enabled); Loading @@ -47,16 +50,13 @@ struct NativeLoaderNamespace { std::string name() const { return name_; } bool IsBridged() const { return raw_.index() == 1; } bool IsNil() const { return IsBridged() ? std::get<1>(raw_) == nullptr : std::get<0>(raw_) == nullptr; } bool Link(const NativeLoaderNamespace& target, const std::string& shared_libs) const; void* Load(const char* lib_name) const; char* GetError() const; Result<void> Link(const NativeLoaderNamespace& target, const std::string& shared_libs) const; Result<void*> Load(const char* lib_name) const; static NativeLoaderNamespace GetExportedNamespace(const std::string& name, bool is_bridged); static NativeLoaderNamespace GetPlatformNamespace(bool is_bridged); static Result<NativeLoaderNamespace> GetExportedNamespace(const std::string& name, bool is_bridged); static Result<NativeLoaderNamespace> GetPlatformNamespace(bool is_bridged); private: explicit NativeLoaderNamespace(const std::string& name, android_namespace_t* ns) Loading Loading
libnativeloader/library_namespaces.cpp +48 −39 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ #include "public_libraries.h" #include "utils.h" using android::base::Error; namespace android::nativeloader { namespace { Loading Loading @@ -128,11 +130,11 @@ void LibraryNamespaces::Initialize() { } } NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version, Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader, bool is_shared, jstring dex_path, jstring java_library_path, jstring java_permitted_path, std::string* error_msg) { jstring dex_path, jstring java_library_path, jstring java_permitted_path) { std::string library_path; // empty string by default. if (java_library_path != nullptr) { Loading @@ -158,14 +160,14 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd } // Initialize the anonymous namespace with the first non-empty library path. Result<void> ret; if (!library_path.empty() && !initialized_ && !InitPublicNamespace(library_path.c_str(), error_msg)) { return nullptr; !(ret = InitPublicNamespace(library_path.c_str()))) { return ret.error(); } bool found = FindNamespaceByClassLoader(env, class_loader); LOG_ALWAYS_FATAL_IF(found, "There is already a namespace associated with this classloader"); LOG_ALWAYS_FATAL_IF(FindNamespaceByClassLoader(env, class_loader) != nullptr, "There is already a namespace associated with this classloader"); std::string system_exposed_libraries = default_public_libraries(); const char* namespace_name = kClassloaderNamespaceName; Loading Loading @@ -216,58 +218,66 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd auto app_ns = NativeLoaderNamespace::Create(namespace_name, library_path, permitted_path, parent_ns, is_shared, target_sdk_version < 24 /* is_greylist_enabled */); if (app_ns.IsNil()) { *error_msg = app_ns.GetError(); return nullptr; if (!app_ns) { return app_ns.error(); } // ... and link to other namespaces to allow access to some public libraries bool is_bridged = app_ns.IsBridged(); bool is_bridged = app_ns->IsBridged(); auto platform_ns = NativeLoaderNamespace::GetPlatformNamespace(is_bridged); if (!app_ns.Link(platform_ns, system_exposed_libraries)) { *error_msg = app_ns.GetError(); return nullptr; if (!platform_ns) { return platform_ns.error(); } auto linked = app_ns->Link(*platform_ns, system_exposed_libraries); if (!linked) { return linked.error(); } auto runtime_ns = NativeLoaderNamespace::GetExportedNamespace(kRuntimeNamespaceName, is_bridged); // Runtime apex does not exist in host, and under certain build conditions. if (!runtime_ns.IsNil()) { if (!app_ns.Link(runtime_ns, runtime_public_libraries())) { *error_msg = app_ns.GetError(); return nullptr; if (runtime_ns) { linked = app_ns->Link(*runtime_ns, runtime_public_libraries()); if (!linked) { return linked.error(); } } // Give access to NNAPI libraries (apex-updated LLNDK library). auto nnapi_ns = NativeLoaderNamespace::GetExportedNamespace(kNeuralNetworksNamespaceName, is_bridged); if (!app_ns.Link(nnapi_ns, neuralnetworks_public_libraries())) { *error_msg = app_ns.GetError(); return nullptr; if (nnapi_ns) { linked = app_ns->Link(*nnapi_ns, neuralnetworks_public_libraries()); if (!linked) { return linked.error(); } } // Give access to VNDK-SP libraries from the 'vndk' namespace. if (unbundled_vendor_or_product_app && !vndksp_libraries().empty()) { auto vndk_ns = NativeLoaderNamespace::GetExportedNamespace(kVndkNamespaceName, is_bridged); if (!vndk_ns.IsNil() && !app_ns.Link(vndk_ns, vndksp_libraries())) { *error_msg = app_ns.GetError(); return nullptr; if (vndk_ns) { linked = app_ns->Link(*vndk_ns, vndksp_libraries()); if (!linked) { return linked.error(); } } } // Note that when vendor_ns is not configured, vendor_ns.IsNil() will be true // and it will result in linking to the default namespace which is expected // behavior in this case. if (!vendor_public_libraries().empty()) { auto vendor_ns = NativeLoaderNamespace::GetExportedNamespace(kVendorNamespaceName, is_bridged); if (!app_ns.Link(vendor_ns, vendor_public_libraries())) { *error_msg = dlerror(); return nullptr; // when vendor_ns is not configured, link to the platform namespace auto target_ns = vendor_ns ? vendor_ns : platform_ns; if (target_ns) { linked = app_ns->Link(*target_ns, vendor_public_libraries()); if (!linked) { return linked.error(); } } } namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), app_ns)); namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), *app_ns)); return &(namespaces_.back().second); } Loading @@ -285,7 +295,7 @@ NativeLoaderNamespace* LibraryNamespaces::FindNamespaceByClassLoader(JNIEnv* env return nullptr; } bool LibraryNamespaces::InitPublicNamespace(const char* library_path, std::string* error_msg) { Result<void> LibraryNamespaces::InitPublicNamespace(const char* library_path) { // Ask native bride if this apps library path should be handled by it bool is_native_bridge = NativeBridgeIsPathSupported(library_path); Loading @@ -296,8 +306,7 @@ bool LibraryNamespaces::InitPublicNamespace(const char* library_path, std::strin initialized_ = android_init_anonymous_namespace(default_public_libraries().c_str(), is_native_bridge ? nullptr : library_path); if (!initialized_) { *error_msg = dlerror(); return false; return Error() << dlerror(); } // and now initialize native bridge namespaces if necessary. Loading @@ -305,11 +314,11 @@ bool LibraryNamespaces::InitPublicNamespace(const char* library_path, std::strin initialized_ = NativeBridgeInitAnonymousNamespace(default_public_libraries().c_str(), is_native_bridge ? library_path : nullptr); if (!initialized_) { *error_msg = NativeBridgeGetError(); return Error() << NativeBridgeGetError(); } } return initialized_; return {}; } NativeLoaderNamespace* LibraryNamespaces::FindParentNamespaceByClassLoader(JNIEnv* env, Loading
libnativeloader/library_namespaces.h +7 −4 Original line number Diff line number Diff line Loading @@ -25,10 +25,13 @@ #include <list> #include <string> #include <android-base/result.h> #include <jni.h> namespace android::nativeloader { using android::base::Result; // LibraryNamespaces is a singleton object that manages NativeLoaderNamespace // objects for an app process. Its main job is to create (and configure) a new // NativeLoaderNamespace object for a Java ClassLoader, and to find an existing Loading @@ -46,13 +49,13 @@ class LibraryNamespaces { namespaces_.clear(); initialized_ = false; } NativeLoaderNamespace* Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader, bool is_shared, jstring dex_path, jstring java_library_path, jstring java_permitted_path, std::string* error_msg); Result<NativeLoaderNamespace*> Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader, bool is_shared, jstring dex_path, jstring java_library_path, jstring java_permitted_path); NativeLoaderNamespace* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader); private: bool InitPublicNamespace(const char* library_path, std::string* error_msg); Result<void> InitPublicNamespace(const char* library_path); NativeLoaderNamespace* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader); bool initialized_; Loading
libnativeloader/native_loader.cpp +18 −15 Original line number Diff line number Diff line Loading @@ -92,12 +92,10 @@ jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobj jstring permitted_path) { #if defined(__ANDROID__) std::lock_guard<std::mutex> guard(g_namespaces_mutex); std::string error_msg; bool success = g_namespaces->Create(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path, &error_msg) != nullptr; if (!success) { return env->NewStringUTF(error_msg.c_str()); auto ns = g_namespaces->Create(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path); if (!ns) { return env->NewStringUTF(ns.error().message().c_str()); } #else UNUSED(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path); Loading Loading @@ -139,11 +137,14 @@ void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* pat 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. std::string create_error_msg; if ((ns = g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */, nullptr, library_path, nullptr, &create_error_msg)) == nullptr) { *error_msg = strdup(create_error_msg.c_str()); Result<NativeLoaderNamespace*> isolated_ns = g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */, nullptr, library_path, nullptr); if (!isolated_ns) { *error_msg = strdup(isolated_ns.error().message().c_str()); return nullptr; } else { ns = *isolated_ns; } } Loading Loading @@ -222,12 +223,14 @@ void NativeLoaderFreeErrorMessage(char* msg) { #if defined(__ANDROID__) void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path, bool* needs_native_bridge, char** error_msg) { void* handle = ns->Load(path); if (handle == nullptr) { *error_msg = ns->GetError(); auto handle = ns->Load(path); if (!handle && error_msg != nullptr) { *error_msg = strdup(handle.error().message().c_str()); } if (needs_native_bridge != nullptr) { *needs_native_bridge = ns->IsBridged(); return handle; } return handle ? *handle : nullptr; } // native_bridge_namespaces are not supported for callers of this function. Loading
libnativeloader/native_loader_namespace.cpp +63 −33 Original line number Diff line number Diff line Loading @@ -28,6 +28,9 @@ #include "nativeloader/dlext_namespaces.h" using android::base::Error; using android::base::Errorf; namespace android { namespace { Loading @@ -35,41 +38,46 @@ namespace { constexpr const char* kDefaultNamespaceName = "default"; constexpr const char* kPlatformNamespaceName = "platform"; std::string GetLinkerError(bool is_bridged) { const char* msg = is_bridged ? NativeBridgeGetError() : dlerror(); if (msg == nullptr) { return "no error"; } return std::string(msg); } } // namespace NativeLoaderNamespace NativeLoaderNamespace::GetExportedNamespace(const std::string& name, Result<NativeLoaderNamespace> NativeLoaderNamespace::GetExportedNamespace(const std::string& name, bool is_bridged) { if (!is_bridged) { return NativeLoaderNamespace(name, android_get_exported_namespace(name.c_str())); } else { return NativeLoaderNamespace(name, NativeBridgeGetExportedNamespace(name.c_str())); } auto raw = android_get_exported_namespace(name.c_str()); if (raw != nullptr) { return NativeLoaderNamespace(name, raw); } char* NativeLoaderNamespace::GetError() const { if (!IsBridged()) { return strdup(dlerror()); } else { return strdup(NativeBridgeGetError()); auto raw = NativeBridgeGetExportedNamespace(name.c_str()); if (raw != nullptr) { return NativeLoaderNamespace(name, raw); } } return Errorf("namespace {} does not exist or exported", name); } // The platform namespace is called "default" for binaries in /system and // "platform" for those in the Runtime APEX. Try "platform" first since // "default" always exists. NativeLoaderNamespace NativeLoaderNamespace::GetPlatformNamespace(bool is_bridged) { NativeLoaderNamespace ns = GetExportedNamespace(kPlatformNamespaceName, is_bridged); if (ns.IsNil()) { Result<NativeLoaderNamespace> NativeLoaderNamespace::GetPlatformNamespace(bool is_bridged) { auto ns = GetExportedNamespace(kPlatformNamespaceName, is_bridged); if (!ns) { ns = GetExportedNamespace(kDefaultNamespaceName, is_bridged); } return ns; } NativeLoaderNamespace NativeLoaderNamespace::Create(const std::string& name, const std::string& search_paths, const std::string& permitted_paths, const NativeLoaderNamespace* parent, bool is_shared, bool is_greylist_enabled) { Result<NativeLoaderNamespace> NativeLoaderNamespace::Create( const std::string& name, const std::string& search_paths, const std::string& permitted_paths, const NativeLoaderNamespace* parent, bool is_shared, bool is_greylist_enabled) { bool is_bridged = false; if (parent != nullptr) { is_bridged = parent->IsBridged(); Loading @@ -78,8 +86,11 @@ NativeLoaderNamespace NativeLoaderNamespace::Create(const std::string& name, } // Fall back to the platform namespace if no parent is set. const NativeLoaderNamespace& effective_parent = parent != nullptr ? *parent : GetPlatformNamespace(is_bridged); auto platform_ns = GetPlatformNamespace(is_bridged); if (!platform_ns) { return platform_ns.error(); } const NativeLoaderNamespace& effective_parent = parent != nullptr ? *parent : *platform_ns; uint64_t type = ANDROID_NAMESPACE_TYPE_ISOLATED; if (is_shared) { Loading @@ -93,37 +104,56 @@ NativeLoaderNamespace NativeLoaderNamespace::Create(const std::string& name, android_namespace_t* raw = android_create_namespace(name.c_str(), nullptr, search_paths.c_str(), type, permitted_paths.c_str(), effective_parent.ToRawAndroidNamespace()); if (raw != nullptr) { return NativeLoaderNamespace(name, raw); } } else { native_bridge_namespace_t* raw = NativeBridgeCreateNamespace( name.c_str(), nullptr, search_paths.c_str(), type, permitted_paths.c_str(), effective_parent.ToRawNativeBridgeNamespace()); if (raw != nullptr) { return NativeLoaderNamespace(name, raw); } } return Errorf("failed to create {} namespace name:{}, search_paths:{}, permitted_paths:{}", is_bridged ? "bridged" : "native", name, search_paths, permitted_paths); } bool NativeLoaderNamespace::Link(const NativeLoaderNamespace& target, Result<void> NativeLoaderNamespace::Link(const NativeLoaderNamespace& target, const std::string& shared_libs) const { LOG_ALWAYS_FATAL_IF(shared_libs.empty(), "empty share lib when linking %s to %s", this->name().c_str(), target.name().c_str()); if (!IsBridged()) { return android_link_namespaces(this->ToRawAndroidNamespace(), target.ToRawAndroidNamespace(), shared_libs.c_str()); if (android_link_namespaces(this->ToRawAndroidNamespace(), target.ToRawAndroidNamespace(), shared_libs.c_str())) { return {}; } } else { return NativeBridgeLinkNamespaces(this->ToRawNativeBridgeNamespace(), target.ToRawNativeBridgeNamespace(), shared_libs.c_str()); if (NativeBridgeLinkNamespaces(this->ToRawNativeBridgeNamespace(), target.ToRawNativeBridgeNamespace(), shared_libs.c_str())) { return {}; } } return Error() << GetLinkerError(IsBridged()); } void* NativeLoaderNamespace::Load(const char* lib_name) const { Result<void*> NativeLoaderNamespace::Load(const char* lib_name) const { if (!IsBridged()) { android_dlextinfo extinfo; extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; extinfo.library_namespace = this->ToRawAndroidNamespace(); return android_dlopen_ext(lib_name, RTLD_NOW, &extinfo); void* handle = android_dlopen_ext(lib_name, RTLD_NOW, &extinfo); if (handle != nullptr) { return handle; } } else { return NativeBridgeLoadLibraryExt(lib_name, RTLD_NOW, this->ToRawNativeBridgeNamespace()); void* handle = NativeBridgeLoadLibraryExt(lib_name, RTLD_NOW, this->ToRawNativeBridgeNamespace()); if (handle != nullptr) { return handle; } } return Error() << GetLinkerError(IsBridged()); } } // namespace android
libnativeloader/native_loader_namespace.h +13 −13 Original line number Diff line number Diff line Loading @@ -21,19 +21,22 @@ #include <vector> #include <android-base/logging.h> #include <android-base/result.h> #include <android/dlext.h> #include <log/log.h> #include <nativebridge/native_bridge.h> namespace android { using android::base::Result; // NativeLoaderNamespace abstracts a linker namespace for the native // architecture (ex: arm on arm) or the translated architecture (ex: arm on // x86). Instances of this class are managed by LibraryNamespaces object. struct NativeLoaderNamespace { public: // TODO(return with errors) static NativeLoaderNamespace Create(const std::string& name, const std::string& search_paths, static Result<NativeLoaderNamespace> Create(const std::string& name, const std::string& search_paths, const std::string& permitted_paths, const NativeLoaderNamespace* parent, bool is_shared, bool is_greylist_enabled); Loading @@ -47,16 +50,13 @@ struct NativeLoaderNamespace { std::string name() const { return name_; } bool IsBridged() const { return raw_.index() == 1; } bool IsNil() const { return IsBridged() ? std::get<1>(raw_) == nullptr : std::get<0>(raw_) == nullptr; } bool Link(const NativeLoaderNamespace& target, const std::string& shared_libs) const; void* Load(const char* lib_name) const; char* GetError() const; Result<void> Link(const NativeLoaderNamespace& target, const std::string& shared_libs) const; Result<void*> Load(const char* lib_name) const; static NativeLoaderNamespace GetExportedNamespace(const std::string& name, bool is_bridged); static NativeLoaderNamespace GetPlatformNamespace(bool is_bridged); static Result<NativeLoaderNamespace> GetExportedNamespace(const std::string& name, bool is_bridged); static Result<NativeLoaderNamespace> GetPlatformNamespace(bool is_bridged); private: explicit NativeLoaderNamespace(const std::string& name, android_namespace_t* ns) Loading