Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 09738138 authored by Victor Khimenko's avatar Victor Khimenko Committed by Gerrit Code Review
Browse files

Merge "Separate namespace acquisition from library loading"

parents df398f2b 1443ec49
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -53,8 +53,21 @@ bool CloseNativeLibrary(void* handle, const bool needs_native_bridge);
#if defined(__ANDROID__)
// Look up linker namespace by class_loader. Returns nullptr if
// there is no namespace associated with the class_loader.
// TODO(b/79940628): move users to FindNativeLoaderNamespaceByClassLoader and remove this function.
__attribute__((visibility("default")))
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
// That version works with native bridge namespaces, but requires use of OpenNativeLibrary.
class NativeLoaderNamespace;
__attribute__((visibility("default")))
NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(
    JNIEnv* env, jobject class_loader);
// Load library.  Unlinke OpenNativeLibrary above couldn't create namespace on demand, but does
// not require access to JNIEnv either.
__attribute__((visibility("default")))
void* OpenNativeLibrary(NativeLoaderNamespace* ns,
                        const char* path,
                        bool* needs_native_bridge,
                        std::string* error_msg);
#endif

__attribute__((visibility("default")))
+79 −77
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include "nativebridge/native_bridge.h"

#include <algorithm>
#include <list>
#include <memory>
#include <mutex>
#include <string>
@@ -150,14 +151,13 @@ class LibraryNamespaces {
 public:
  LibraryNamespaces() : initialized_(false) { }

  bool Create(JNIEnv* env,
  NativeLoaderNamespace* Create(JNIEnv* env,
                                uint32_t target_sdk_version,
                                jobject class_loader,
                                bool is_shared,
                                bool is_for_vendor,
                                jstring java_library_path,
                                jstring java_permitted_path,
              NativeLoaderNamespace* ns,
                                std::string* error_msg) {
    std::string library_path; // empty string by default.

@@ -182,10 +182,10 @@ class LibraryNamespaces {
    }

    if (!initialized_ && !InitPublicNamespace(library_path.c_str(), error_msg)) {
      return false;
      return nullptr;
    }

    bool found = FindNamespaceByClassLoader(env, class_loader, nullptr);
    bool found = FindNamespaceByClassLoader(env, class_loader);

    LOG_ALWAYS_FATAL_IF(found,
                        "There is already a namespace associated with this classloader");
@@ -199,13 +199,12 @@ class LibraryNamespaces {
      namespace_type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED;
    }

    NativeLoaderNamespace parent_ns;
    bool found_parent_namespace = FindParentNamespaceByClassLoader(env, class_loader, &parent_ns);
    NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);

    bool is_native_bridge = false;

    if (found_parent_namespace) {
      is_native_bridge = !parent_ns.is_android_namespace();
    if (parent_ns != nullptr) {
      is_native_bridge = !parent_ns->is_android_namespace();
    } else if (!library_path.empty()) {
      is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
    }
@@ -251,15 +250,17 @@ class LibraryNamespaces {

    NativeLoaderNamespace native_loader_ns;
    if (!is_native_bridge) {
      android_namespace_t* android_parent_ns =
          parent_ns == nullptr ? nullptr : parent_ns->get_android_ns();
      android_namespace_t* ns = android_create_namespace(namespace_name,
                                                         nullptr,
                                                         library_path.c_str(),
                                                         namespace_type,
                                                         permitted_path.c_str(),
                                                         parent_ns.get_android_ns());
                                                         android_parent_ns);
      if (ns == nullptr) {
        *error_msg = dlerror();
        return false;
        return nullptr;
      }

      // Note that when vendor_ns is not configured this function will return nullptr
@@ -269,49 +270,50 @@ class LibraryNamespaces {

      if (!android_link_namespaces(ns, nullptr, system_exposed_libraries.c_str())) {
        *error_msg = dlerror();
        return false;
        return nullptr;
      }

      if (vndk_ns != nullptr && !system_vndksp_libraries_.empty()) {
        // vendor apks are allowed to use VNDK-SP libraries.
        if (!android_link_namespaces(ns, vndk_ns, system_vndksp_libraries_.c_str())) {
          *error_msg = dlerror();
          return false;
          return nullptr;
        }
      }

      if (!vendor_public_libraries_.empty()) {
        if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
          *error_msg = dlerror();
          return false;
          return nullptr;
        }
      }

      native_loader_ns = NativeLoaderNamespace(ns);
    } else {
      native_bridge_namespace_t* native_bridge_parent_namespace =
          parent_ns == nullptr ? nullptr : parent_ns->get_native_bridge_ns();
      native_bridge_namespace_t* ns = NativeBridgeCreateNamespace(namespace_name,
                                                                  nullptr,
                                                                  library_path.c_str(),
                                                                  namespace_type,
                                                                  permitted_path.c_str(),
                                                                  parent_ns.get_native_bridge_ns());

                                                                  native_bridge_parent_namespace);
      if (ns == nullptr) {
        *error_msg = NativeBridgeGetError();
        return false;
        return nullptr;
      }

      native_bridge_namespace_t* vendor_ns = NativeBridgeGetVendorNamespace();

      if (!NativeBridgeLinkNamespaces(ns, nullptr, system_exposed_libraries.c_str())) {
        *error_msg = NativeBridgeGetError();
        return false;
        return nullptr;
      }

      if (!vendor_public_libraries_.empty()) {
        if (!NativeBridgeLinkNamespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
          *error_msg = NativeBridgeGetError();
          return false;
          return nullptr;
        }
      }

@@ -320,24 +322,19 @@ class LibraryNamespaces {

    namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns));

    *ns = native_loader_ns;
    return true;
    return &(namespaces_.back().second);
  }

  bool FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader, NativeLoaderNamespace* ns) {
  NativeLoaderNamespace* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
    auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
                [&](const std::pair<jweak, NativeLoaderNamespace>& value) {
                  return env->IsSameObject(value.first, class_loader);
                });
    if (it != namespaces_.end()) {
      if (ns != nullptr) {
        *ns = it->second;
      }

      return true;
      return &it->second;
    }

    return false;
    return nullptr;
  }

  void Initialize() {
@@ -557,24 +554,23 @@ class LibraryNamespaces {
    return env->CallObjectMethod(class_loader, get_parent);
  }

  bool FindParentNamespaceByClassLoader(JNIEnv* env,
                                        jobject class_loader,
                                        NativeLoaderNamespace* ns) {
  NativeLoaderNamespace* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
    jobject parent_class_loader = GetParentClassLoader(env, class_loader);

    while (parent_class_loader != nullptr) {
      if (FindNamespaceByClassLoader(env, parent_class_loader, ns)) {
        return true;
      NativeLoaderNamespace* ns;
      if ((ns = FindNamespaceByClassLoader(env, parent_class_loader)) != nullptr) {
        return ns;
      }

      parent_class_loader = GetParentClassLoader(env, parent_class_loader);
    }

    return false;
    return nullptr;
  }

  bool initialized_;
  std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
  std::list<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
  std::string system_public_libraries_;
  std::string vendor_public_libraries_;
  std::string oem_public_libraries_;
@@ -614,7 +610,6 @@ jstring CreateClassLoaderNamespace(JNIEnv* env,
  std::lock_guard<std::mutex> guard(g_namespaces_mutex);

  std::string error_msg;
  NativeLoaderNamespace ns;
  bool success = g_namespaces->Create(env,
                                      target_sdk_version,
                                      class_loader,
@@ -622,8 +617,7 @@ jstring CreateClassLoaderNamespace(JNIEnv* env,
                                      is_for_vendor,
                                      library_path,
                                      permitted_path,
                                      &ns,
                                      &error_msg);
                                      &error_msg) != nullptr;
  if (!success) {
    return env->NewStringUTF(error_msg.c_str());
  }
@@ -649,43 +643,24 @@ void* OpenNativeLibrary(JNIEnv* env,
  }

  std::lock_guard<std::mutex> guard(g_namespaces_mutex);
  NativeLoaderNamespace ns;
  NativeLoaderNamespace* ns;

  if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &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.
    if (!g_namespaces->Create(env,
    if ((ns = g_namespaces->Create(env,
                                   target_sdk_version,
                                   class_loader,
                                   false /* is_shared */,
                                   false /* is_for_vendor */,
                                   library_path,
                                   nullptr,
                              &ns,
                              error_msg)) {
                                   error_msg)) == nullptr) {
      return nullptr;
    }
  }

  if (ns.is_android_namespace()) {
    android_dlextinfo extinfo;
    extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
    extinfo.library_namespace = ns.get_android_ns();

    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;
  }
  return OpenNativeLibrary(ns, path, needs_native_bridge, error_msg);
#else
  UNUSED(env, target_sdk_version, class_loader);

@@ -741,18 +716,45 @@ bool CloseNativeLibrary(void* handle, const bool needs_native_bridge) {
}

#if defined(__ANDROID__)
void* OpenNativeLibrary(NativeLoaderNamespace* ns, const char* path, bool* needs_native_bridge,
                        std::string* error_msg) {
  if (ns->is_android_namespace()) {
    android_dlextinfo extinfo;
    extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
    extinfo.library_namespace = ns->get_android_ns();

    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;
  }
}

// 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.
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
  std::lock_guard<std::mutex> guard(g_namespaces_mutex);
  NativeLoaderNamespace ns;
  if (g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
    return ns.is_android_namespace() ? ns.get_android_ns() : nullptr;
  NativeLoaderNamespace* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
  if (ns != nullptr) {
    return ns->is_android_namespace() ? ns->get_android_ns() : nullptr;
  }

  return nullptr;
}
NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
  std::lock_guard<std::mutex> guard(g_namespaces_mutex);
  return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
}
#endif

}; //  android namespace