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

Commit 244d9b8f authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Use android::base::Result in libnativeloader"

parents d1160364 8f4afc82
Loading
Loading
Loading
Loading
+48 −39
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@
#include "public_libraries.h"
#include "utils.h"

using android::base::Error;

namespace android::nativeloader {

namespace {
@@ -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) {
@@ -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;
@@ -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);
}
@@ -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);

@@ -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.
@@ -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,
+7 −4
Original line number Diff line number Diff line
@@ -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
@@ -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_;
+18 −15
Original line number Diff line number Diff line
@@ -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);
@@ -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;
    }
  }

@@ -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.
+63 −33
Original line number Diff line number Diff line
@@ -28,6 +28,9 @@

#include "nativeloader/dlext_namespaces.h"

using android::base::Error;
using android::base::Errorf;

namespace android {

namespace {
@@ -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();
@@ -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) {
@@ -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
+13 −13
Original line number Diff line number Diff line
@@ -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);
@@ -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