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

Commit b37c4818 authored by Jiyong Park's avatar Jiyong Park
Browse files

Don't create anonymous namespace

Don't create anonymous namespace separately, use the first namespace
that is created for app classloader as the anonymous namespace.

Note that the anonymous namespace is set via the new
ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS. I didn't creat a new
function like android_set_anonymous_namespace as it requires uprev of
the libnativebridge interface and makes it harder to delete the old
android_init_anonymous_namespace as we have to keep it until all
proprietary bridged loaders are updated.

Bug: 130388701
Test: CtsBionicTestCases
Test: run games on http://www.monogame.net/showcase/?Android
Change-Id: I0fdd614365eaa56c4ab47538bf3772d94bd9ae55
parent e2adc148
Loading
Loading
Loading
Loading
+12 −14
Original line number Diff line number Diff line
@@ -22,18 +22,6 @@

__BEGIN_DECLS

/*
 * Initializes anonymous namespaces. The shared_libs_sonames is the list of sonames
 * to be shared by default namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
 *
 * The library_search_path is the search path for anonymous namespace. The anonymous namespace
 * is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
 * for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
 */
extern bool android_init_anonymous_namespace(const char* shared_libs_sonames,
                                             const char* library_search_path);


enum {
  /* A regular namespace is the namespace with a custom search path that does
   * not impose any restrictions on the location of native libraries.
@@ -62,8 +50,18 @@ enum {
   */
  ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED = 0x08000000,

  ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED = ANDROID_NAMESPACE_TYPE_SHARED |
                                           ANDROID_NAMESPACE_TYPE_ISOLATED,
  /* This flag instructs linker to use this namespace as the anonymous
   * namespace. The anonymous namespace is used in the case when linker cannot
   * identify the caller of dlopen/dlsym. This happens for the code not loaded
   * by dynamic linker; for example calls from the mono-compiled code. There can
   * be only one anonymous namespace in a process. If there already is an
   * anonymous namespace in the process, using this flag when creating a new
   * namespace causes an error.
   */
  ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS = 0x10000000,

  ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED =
      ANDROID_NAMESPACE_TYPE_SHARED | ANDROID_NAMESPACE_TYPE_ISOLATED,
};

/*
+16 −37
Original line number Diff line number Diff line
@@ -159,13 +159,6 @@ Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t t
    }
  }

  // Initialize the anonymous namespace with the first non-empty library path.
  Result<void> ret;
  if (!library_path.empty() && !initialized_ &&
      !(ret = InitPublicNamespace(library_path.c_str()))) {
    return ret.error();
  }

  LOG_ALWAYS_FATAL_IF(FindNamespaceByClassLoader(env, class_loader) != nullptr,
                      "There is already a namespace associated with this classloader");

@@ -215,13 +208,22 @@ Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t t

  // Create the app namespace
  NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
  auto app_ns =
      NativeLoaderNamespace::Create(namespace_name, library_path, permitted_path, parent_ns,
                                    is_shared, target_sdk_version < 24 /* is_greylist_enabled */);
  // Heuristic: the first classloader with non-empty library_path is assumed to
  // be the main classloader for app
  // TODO(b/139178525) remove this heuristic by determining this in LoadedApk (or its
  // friends) and then passing it down to here.
  bool is_main_classloader = app_main_namespace_ == nullptr && !library_path.empty();
  // Policy: the namespace for the main classloader is also used as the
  // anonymous namespace.
  bool also_used_as_anonymous = is_main_classloader;
  // Note: this function is executed with g_namespaces_mutex held, thus no
  // racing here.
  auto app_ns = NativeLoaderNamespace::Create(
      namespace_name, library_path, permitted_path, parent_ns, is_shared,
      target_sdk_version < 24 /* is_greylist_enabled */, also_used_as_anonymous);
  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();

@@ -278,6 +280,9 @@ Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t t
  }

  namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), *app_ns));
  if (is_main_classloader) {
    app_main_namespace_ = &(*app_ns);
  }

  return &(namespaces_.back().second);
}
@@ -295,32 +300,6 @@ NativeLoaderNamespace* LibraryNamespaces::FindNamespaceByClassLoader(JNIEnv* env
  return nullptr;
}

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

  // (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_anonymous_namespace(default_public_libraries().c_str(),
                                                  is_native_bridge ? nullptr : library_path);
  if (!initialized_) {
    return Error() << dlerror();
  }

  // and now initialize native bridge namespaces if necessary.
  if (NativeBridgeInitialized()) {
    initialized_ = NativeBridgeInitAnonymousNamespace(default_public_libraries().c_str(),
                                                      is_native_bridge ? library_path : nullptr);
    if (!initialized_) {
      return Error() << NativeBridgeGetError();
    }
  }

  return {};
}

NativeLoaderNamespace* LibraryNamespaces::FindParentNamespaceByClassLoader(JNIEnv* env,
                                                                           jobject class_loader) {
  jobject parent_class_loader = GetParentClassLoader(env, class_loader);
+2 −0
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ class LibraryNamespaces {
  void Reset() {
    namespaces_.clear();
    initialized_ = false;
    app_main_namespace_ = nullptr;
  }
  Result<NativeLoaderNamespace*> Create(JNIEnv* env, uint32_t target_sdk_version,
                                        jobject class_loader, bool is_shared, jstring dex_path,
@@ -59,6 +60,7 @@ class LibraryNamespaces {
  NativeLoaderNamespace* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader);

  bool initialized_;
  NativeLoaderNamespace* app_main_namespace_;
  std::list<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
};

+12 −1
Original line number Diff line number Diff line
@@ -85,7 +85,8 @@ Result<NativeLoaderNamespace> NativeLoaderNamespace::GetPlatformNamespace(bool i

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) {
    const NativeLoaderNamespace* parent, bool is_shared, bool is_greylist_enabled,
    bool also_used_as_anonymous) {
  bool is_bridged = false;
  if (parent != nullptr) {
    is_bridged = parent->IsBridged();
@@ -100,7 +101,17 @@ Result<NativeLoaderNamespace> NativeLoaderNamespace::Create(
  }
  const NativeLoaderNamespace& effective_parent = parent != nullptr ? *parent : *platform_ns;

  // All namespaces for apps are isolated
  uint64_t type = ANDROID_NAMESPACE_TYPE_ISOLATED;

  // The namespace is also used as the anonymous namespace
  // which is used when the linker fails to determine the caller address
  if (also_used_as_anonymous) {
    type |= ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS;
  }

  // Bundled apps have access to all system libraries that are currently loaded
  // in the default namespace
  if (is_shared) {
    type |= ANDROID_NAMESPACE_TYPE_SHARED;
  }
+2 −1
Original line number Diff line number Diff line
@@ -39,7 +39,8 @@ struct NativeLoaderNamespace {
                                              const std::string& search_paths,
                                              const std::string& permitted_paths,
                                              const NativeLoaderNamespace* parent, bool is_shared,
                                              bool is_greylist_enabled);
                                              bool is_greylist_enabled,
                                              bool also_used_as_anonymous);

  NativeLoaderNamespace(NativeLoaderNamespace&&) = default;
  NativeLoaderNamespace(const NativeLoaderNamespace&) = default;
Loading