Android system — 链接器命名空间共享库配置方法(Android 11后)

Android system --- 链接器命名空间共享库配置方法

  • [1. 应用进程](#1. 应用进程)
    • [1.1 应用进程类加载器的命名空间初始化](#1.1 应用进程类加载器的命名空间初始化)
      • [1.1.1 OpenNativeLibrary](#1.1.1 OpenNativeLibrary)
      • [1.1.2 LibraryNamespaces::Create](#1.1.2 LibraryNamespaces::Create)
    • [1.2 配置共享库位置](#1.2 配置共享库位置)
  • [2. native进程](#2. native进程)
    • [2.1 native 命名空间配置初始化](#2.1 native 命名空间配置初始化)
      • [2.1.1 android_namespace_t::is_accessible](#2.1.1 android_namespace_t::is_accessible)
      • [2.1.2 init_default_namespaces](#2.1.2 init_default_namespaces)
    • [2.2 配置共享库位置](#2.2 配置共享库位置)

1. 应用进程

1.1 应用进程类加载器的命名空间初始化

在应用程序对应的可执行文件app_process根据/linkerconfig/ld.config.txt配置文件初始化命名空间之后,每当应用程序创建一个类加载器classloader并调用System.loadLibrary加载so库时都会创建一个与此类加载器对应的命名空间。从源码角度分析一下这个过程,System.loadLibrary函数最后会调用OpenNativeLibrary函数。

1.1.1 OpenNativeLibrary

System.loadLibrary()-->nativeLoad()-->Runtime.c::Runtime_nativeLoad()-->JVM_NativeLoad()-->Openjdkjvm.cc::JVM_NativeLoad()-->java_vm_ext.cc::LoadNativeLibrary()-->native_loader.cpp::OpenNativeLibrary() 也就是java层的System.loadLibrary()最终会调用libnativeloader.so的OpenNativeLibrary函数。

  • OpenNativeLibrary先判断classloader类加载器是否为空,如果为空直接调用android_dlopen_ext加载库文件
  • 如果判断classloader类加载器不为空,并且classloader类加载器没有对应的命名空间(第一次调用System.loadLibrary)就调用LibraryNamespaces::Create创建新的命名空间。
cpp 复制代码
void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
                        jobject class_loader, const char* caller_location, jstring library_path,
                        bool* needs_native_bridge, char** error_msg) {
#if defined(ART_TARGET_ANDROID)
  UNUSED(target_sdk_version);

  if (class_loader == nullptr) { //如果类加载器为空直接调用android_dlopen_ext加载库文件
    *needs_native_bridge = false;
    if (caller_location != nullptr) {
      android_namespace_t* boot_namespace = FindExportedNamespace(caller_location);
      if (boot_namespace != nullptr) {
        const android_dlextinfo dlextinfo = {
            .flags = ANDROID_DLEXT_USE_NAMESPACE,
            .library_namespace = boot_namespace,
        };
        void* handle = android_dlopen_ext(path, RTLD_NOW, &dlextinfo);
        if (handle == nullptr) {
          *error_msg = strdup(dlerror());
        }
        return handle;
      }
    }

    // Check if the library is in NATIVELOADER_DEFAULT_NAMESPACE_LIBS and should
    // be loaded from the kNativeloaderExtraLibs namespace.
    {
      Result<void*> handle = TryLoadNativeloaderExtraLib(path);
      if (!handle.ok()) {
        *error_msg = strdup(handle.error().message().c_str());
        return nullptr;
      }
      if (handle.value() != nullptr) {
        return handle.value();
      }
    }

    // Fall back to the system namespace. This happens for preloaded JNI
    // libraries in the zygote.
    // TODO(b/185833744): Investigate if this should fall back to the app main
    // namespace (aka anonymous namespace) instead.
    void* handle = OpenSystemLibrary(path, RTLD_NOW);
    if (handle == nullptr) {
      *error_msg = strdup(dlerror());
    }
    return handle;
  }

  std::lock_guard<std::mutex> guard(g_namespaces_mutex);
  NativeLoaderNamespace* 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.
    Result<NativeLoaderNamespace*> isolated_ns =
        CreateClassLoaderNamespaceLocked(env,
                                         target_sdk_version,
                                         class_loader,
                                         /*is_shared=*/false,
                                         /*dex_path=*/nullptr,
                                         library_path,
                                         /*permitted_path=*/nullptr,
                                         /*uses_library_list=*/nullptr);
    if (!isolated_ns.ok()) {
      *error_msg = strdup(isolated_ns.error().message().c_str());
      return nullptr;
    } else {
      ns = *isolated_ns;
    }
  }

  return OpenNativeLibraryInNamespace(ns, path, needs_native_bridge, error_msg);

CreateClassLoaderNamespaceLocked中我们可以看到调用了LibraryNamespaces::Create创建新的命名空间

cpp 复制代码
Result<NativeLoaderNamespace*> CreateClassLoaderNamespaceLocked(JNIEnv* env,
                                                                int32_t target_sdk_version,
                                                                jobject class_loader,
                                                                bool is_shared,
                                                                jstring dex_path,
                                                                jstring library_path,
                                                                jstring permitted_path,
                                                                jstring uses_library_list)
    REQUIRES(g_namespaces_mutex) {
  Result<NativeLoaderNamespace*> ns = g_namespaces->Create(env,
                                                           target_sdk_version,
                                                           class_loader,
                                                           is_shared,
                                                           dex_path,
                                                           library_path,
                                                           permitted_path,
                                                           uses_library_list);
  if (!ns.ok()) {
    return ns;
  }
  Result<void> linked = CreateNativeloaderDefaultNamespaceLibsLink(*ns.value());
  if (!linked.ok()) {
    return linked.error();
  }
  return ns;
}

1.1.2 LibraryNamespaces::Create

  • 先调用android_create_namespace创建一个clns命名空间
  • 调用android_linker_namespace设置新创建的命名空间链接到system、APEX和vendor等命名空间
  • 设置链接到system、APEX等命名空间的共享库
cpp 复制代码
Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version,
                                                         jobject class_loader, bool is_shared,
                                                         jstring dex_path_j,
                                                         jstring java_library_path,
                                                         jstring java_permitted_path,
                                                         jstring uses_library_list) {
  std::string library_path;  // empty string by default.
  std::string dex_path;

  ......

  // Create the app namespace
  NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
  // 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.
  //创建命名空间,namespace_name为kClassloaderNamespaceName = "clns"
  auto app_ns = NativeLoaderNamespace::Create(
      namespace_name, library_path, permitted_path, parent_ns, is_shared,
      target_sdk_version < 24 /* is_exempt_list_enabled */, also_used_as_anonymous);
  if (!app_ns.ok()) {
    return app_ns.error();
  }
  // ... and link to other namespaces to allow access to some public libraries
  bool is_bridged = app_ns->IsBridged();

  auto system_ns = NativeLoaderNamespace::GetSystemNamespace(is_bridged);
  if (!system_ns.ok()) {
    return system_ns.error();
  }
  // 新创建的命名空间链接到system,共享库设置为system_exposed_libraries
  auto linked = app_ns->Link(&system_ns.value(), system_exposed_libraries);
  if (!linked.ok()) {
    return linked.error();
  }

  for (const auto&[apex_ns_name, public_libs] : apex_public_libraries()) {
    auto ns = NativeLoaderNamespace::GetExportedNamespace(apex_ns_name, is_bridged);
    // Even if APEX namespace is visible, it may not be available to bridged.
    if (ns.ok()) {
      // 新创建的命名空间链接到APEX,共享库设置为public_libs
      linked = app_ns->Link(&ns.value(), public_libs);
      if (!linked.ok()) {
        return linked.error();
      }
    }
  }

  // Give access to VNDK-SP libraries from the 'vndk' namespace for unbundled vendor apps.
  if (unbundled_app_origin == APK_ORIGIN_VENDOR && !vndksp_libraries_vendor().empty()) {
    auto vndk_ns = NativeLoaderNamespace::GetExportedNamespace(kVndkNamespaceName, is_bridged);
    if (vndk_ns.ok()) {
      // 新创建的命名空间链接到vndk,共享库设置为vndksp_libraries_vendor()
      linked = app_ns->Link(&vndk_ns.value(), vndksp_libraries_vendor());
      if (!linked.ok()) {
        return linked.error();
      }
    }
  }

  // Give access to VNDK-SP libraries from the 'vndk_product' namespace for unbundled product apps.
  if (unbundled_app_origin == APK_ORIGIN_PRODUCT && !vndksp_libraries_product().empty()) {
    auto vndk_ns = NativeLoaderNamespace::GetExportedNamespace(kVndkProductNamespaceName, is_bridged);
    if (vndk_ns.ok()) {
      linked = app_ns->Link(&vndk_ns.value(), vndksp_libraries_product());
      if (!linked.ok()) {
        return linked.error();
      }
    }
  }

  for (const std::string& each_jar_path : android::base::Split(dex_path, ":")) {
    auto apex_ns_name = FindApexNamespaceName(each_jar_path);
    if (apex_ns_name.ok()) {
      const auto& jni_libs = apex_jni_libraries(*apex_ns_name);
      if (jni_libs != "") {
        auto apex_ns = NativeLoaderNamespace::GetExportedNamespace(*apex_ns_name, is_bridged);
        if (apex_ns.ok()) {
          linked = app_ns->Link(&apex_ns.value(), jni_libs);
          if (!linked.ok()) {
            return linked.error();
          }
        }
      }
    }
  }

  auto vendor_libs = filter_public_libraries(target_sdk_version, uses_libraries,
                                             vendor_public_libraries());
  if (!vendor_libs.empty()) {
    auto vendor_ns = NativeLoaderNamespace::GetExportedNamespace(kVendorNamespaceName, is_bridged);
    // when vendor_ns is not configured, link to the system namespace
    auto target_ns = vendor_ns.ok() ? vendor_ns : system_ns;
    if (target_ns.ok()) {
      linked = app_ns->Link(&target_ns.value(), vendor_libs);
      if (!linked.ok()) {
        return linked.error();
      }
    }
  }

  auto product_libs = filter_public_libraries(target_sdk_version, uses_libraries,
                                              product_public_libraries());
  if (!product_libs.empty()) {
    auto target_ns = system_ns;
    if (is_product_vndk_version_defined()) {
      // If ro.product.vndk.version is defined, product namespace provides the product libraries.
      target_ns = NativeLoaderNamespace::GetExportedNamespace(kProductNamespaceName, is_bridged);
    }
    if (target_ns.ok()) {
      linked = app_ns->Link(&target_ns.value(), product_libs);
      if (!linked.ok()) {
        return linked.error();
      }
    } else {
      // The linkerconfig must have a problem on defining the product namespace in the system
      // section. Skip linking product namespace. This will not affect most of the apps. Only the
      // apps that requires the product public libraries will fail.
      ALOGW("Namespace for product libs not found: %s", target_ns.error().message().c_str());
    }
  }

  auto& emplaced = namespaces_.emplace_back(
      std::make_pair(env->NewWeakGlobalRef(class_loader), *app_ns));
  if (is_main_classloader) {
    app_main_namespace_ = &emplaced.second;
  }
  return &emplaced.second;
}

1.2 配置共享库位置

通过上面的代码跟踪我们会发现,其实在Android 11后,应用进程共享库的配置位置都在public_libraries.cpp

cpp 复制代码
// art/libnativeloader/public_libraries.cpp
namespace {

constexpr const char* kDefaultPublicLibrariesFile = "/etc/public.libraries.txt";
constexpr const char* kExtendedPublicLibrariesFilePrefix = "public.libraries-";
constexpr const char* kExtendedPublicLibrariesFileSuffix = ".txt";
constexpr const char* kApexLibrariesConfigFile = "/linkerconfig/apex.libraries.config.txt";
constexpr const char* kVendorPublicLibrariesFile = "/vendor/etc/public.libraries.txt";
constexpr const char* kLlndkLibrariesFile = "/apex/com.android.vndk.v{}/etc/llndk.libraries.{}.txt";
constexpr const char* kVndkLibrariesFile = "/apex/com.android.vndk.v{}/etc/vndksp.libraries.{}.txt";

只要在命名空间对应的配置文件中加上自己需要的共享库即可

2. native进程

2.1 native 命名空间配置初始化

native进程的so库是直接通过dlopen打开的,而其对应的命名空间也是直接通过linker进行判断的,并没有调用到libnativeloader.so,因此native进程的配置方式也与应用进程不同

2.1.1 android_namespace_t::is_accessible

前一篇Android system --- 链接器命名空间(linker namespace)源码分析 介绍了dlopen时会通过is_accessible进行权限判断

cpp 复制代码
// bionic/linker/linker_namespaces.cpp
// Given an absolute path, can this library be loaded into this namespace?
bool android_namespace_t::is_accessible(const std::string& file) {
  //判断命名空间的is_isolated_,即是否为严格隔离,如果不是则权限检查通过。
  if (!is_isolated_) {
    return true;
  }
  //判断是否在允许名单中
  if (!allowed_libs_.empty()) {
    const char *lib_name = basename(file.c_str());
    if (std::find(allowed_libs_.begin(), allowed_libs_.end(), lib_name) == allowed_libs_.end()) {
      return false;
    }
  }
  //判断是否在ld_library_paths中(LD_LIBRARY_PATH设置)
  for (const auto& dir : ld_library_paths_) {
    if (file_is_in_dir(file, dir)) {
      return true;
    }
  }
  //判断是否在default_library_paths中
  for (const auto& dir : default_library_paths_) {
    if (file_is_in_dir(file, dir)) {
      return true;
    }
  }
  //判断是否在特权路径permitted_paths中
  for (const auto& dir : permitted_paths_) {
    if (file_is_under_dir(file, dir)) {
      return true;
    }
  }

  return false;
}

我们可以看到这里有个allowed_libs_,我们跟踪代码可以发现linker_namespaces.h中有set_allowed_libs接口

cpp 复制代码
// bionic/linker/linker_namespaces.h 
  const std::vector<std::string>& get_allowed_libs() const { return allowed_libs_; }
  void set_allowed_libs(std::vector<std::string>&& allowed_libs) {
    allowed_libs_ = std::move(allowed_libs);
  }
  void set_allowed_libs(const std::vector<std::string>& allowed_libs) {
    allowed_libs_ = allowed_libs;
  }

2.1.2 init_default_namespaces

通过这个思路我们发现调用其实在init_default_namespaces

  • 初始化default命名空间
  • 初始化vndk等其他命名空间
  • 在命名空间之间建立链接
cpp 复制代码
std::vector<android_namespace_t*> init_default_namespaces(const char* executable_path) {
  g_default_namespace.set_name("(default)");

  soinfo* somain = solist_get_somain();

  const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
                                                       somain->load_bias);
  const char* bname = (interp != nullptr) ? basename(interp) : nullptr;

  g_is_asan = bname != nullptr &&
              (strcmp(bname, "linker_asan") == 0 ||
               strcmp(bname, "linker_asan64") == 0);

  const Config* config = nullptr;

  {
    std::string ld_config_file_path = get_ld_config_file_path(executable_path);
    INFO("[ Reading linker config \"%s\" ]", ld_config_file_path.c_str());
    ScopedTrace trace(("linker config " + ld_config_file_path).c_str());
    std::string error_msg;
    if (!Config::read_binary_config(ld_config_file_path.c_str(), executable_path, g_is_asan,
                                    &config, &error_msg)) {
      if (!error_msg.empty()) {
        DL_WARN("Warning: couldn't read '%s' for '%s' (using default configuration instead): %s",
                ld_config_file_path.c_str(), executable_path, error_msg.c_str());
      }
      config = nullptr;
    }
  }

  if (config == nullptr) {
    return init_default_namespace_no_config(g_is_asan);
  }

  const auto& namespace_configs = config->namespace_configs();
  std::unordered_map<std::string, android_namespace_t*> namespaces;

  // 1. Initialize default namespace
  const NamespaceConfig* default_ns_config = config->default_namespace_config();

  g_default_namespace.set_isolated(default_ns_config->isolated());
  g_default_namespace.set_default_library_paths(default_ns_config->search_paths());
  g_default_namespace.set_permitted_paths(default_ns_config->permitted_paths());

  namespaces[default_ns_config->name()] = &g_default_namespace;
  if (default_ns_config->visible()) {
    g_exported_namespaces[default_ns_config->name()] = &g_default_namespace;
  }

  // 2. Initialize other namespaces

  for (auto& ns_config : namespace_configs) {
    if (namespaces.find(ns_config->name()) != namespaces.end()) {
      continue;
    }

    android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
    ns->set_name(ns_config->name());
    ns->set_isolated(ns_config->isolated());
    ns->set_default_library_paths(ns_config->search_paths());
    ns->set_permitted_paths(ns_config->permitted_paths());
    ns->set_allowed_libs(ns_config->allowed_libs());

    namespaces[ns_config->name()] = ns;
    if (ns_config->visible()) {
      g_exported_namespaces[ns_config->name()] = ns;
    }
  }

  // 3. Establish links between namespaces
  for (auto& ns_config : namespace_configs) {
    auto it_from = namespaces.find(ns_config->name());
    CHECK(it_from != namespaces.end());
    android_namespace_t* namespace_from = it_from->second;
    for (const NamespaceLinkConfig& ns_link : ns_config->links()) {
      auto it_to = namespaces.find(ns_link.ns_name());
      CHECK(it_to != namespaces.end());
      android_namespace_t* namespace_to = it_to->second;
      if (ns_link.allow_all_shared_libs()) {
        link_namespaces_all_libs(namespace_from, namespace_to);
      } else {
        link_namespaces(namespace_from, namespace_to, ns_link.shared_libs().c_str());
      }
    }
  }
  // we can no longer rely on the fact that libdl.so is part of default namespace
  // this is why we want to add ld-android.so to all namespaces from ld.config.txt
  soinfo* ld_android_so = solist_get_head();

  // we also need vdso to be available for all namespaces (if present)
  soinfo* vdso = solist_get_vdso();
  for (auto it : namespaces) {
    if (it.second != &g_default_namespace) {
      it.second->add_soinfo(ld_android_so);
      if (vdso != nullptr) {
        it.second->add_soinfo(vdso);
      }
      // somain and ld_preloads are added to these namespaces after LD_PRELOAD libs are linked
    }
  }

  set_application_target_sdk_version(config->target_sdk_version());

  std::vector<android_namespace_t*> created_namespaces;
  created_namespaces.reserve(namespaces.size());
  for (const auto& kv : namespaces) {
    created_namespaces.push_back(kv.second);
  }
  return created_namespaces;
}
}

这里面我们发现配置文件是通过读取配置文件进行配置的,配置文件ld_config_file_path在Android 11后便改为/linkerconfig/ld.config.txt

cpp 复制代码
static const char* const kLdConfigArchFilePath = "/system/etc/ld.config." ABI_STRING ".txt";

static const char* const kLdConfigFilePath = "/system/etc/ld.config.txt";
static const char* const kLdConfigVndkLiteFilePath = "/system/etc/ld.config.vndk_lite.txt";

static const char* const kLdGeneratedConfigFilePath = "/linkerconfig/ld.config.txt";

static std::string get_ld_config_file_path(const char* executable_path) {
#ifdef USE_LD_CONFIG_FILE
  // This is a debugging/testing only feature. Must not be available on
  // production builds.
  const char* ld_config_file_env = getenv("LD_CONFIG_FILE");
  if (ld_config_file_env != nullptr && file_exists(ld_config_file_env)) {
    return ld_config_file_env;
  }
#endif

  std::string path = get_ld_config_file_apex_path(executable_path);
  if (!path.empty()) {
    if (file_exists(path.c_str())) {
      return path;
    }
    DL_WARN("Warning: couldn't read config file \"%s\" for \"%s\"",
            path.c_str(), executable_path);
  }

  path = kLdConfigArchFilePath;
  if (file_exists(path.c_str())) {
    return path;
  }

  if (file_exists(kLdGeneratedConfigFilePath)) {
    return kLdGeneratedConfigFilePath;
  }

  if (is_linker_config_expected(executable_path)) {
    DL_WARN("Warning: failed to find generated linker configuration from \"%s\"",
            kLdGeneratedConfigFilePath);
  }

  path = get_ld_config_file_vndk_path();
  if (file_exists(path.c_str())) {
    return path;
  }

  return kLdConfigFilePath;
}

2.2 配置共享库位置

上一章我们提到了配置文件位置为/linkerconfig/ld.config.txt,

在Android 11以前ld.config.txt是通过静态文件配置的,而Android 11是改为linkerconfig动态生成

我们以一个vendor/bin下的native 程序为例,要使用system/lib下的库

Android system --- Android链接器命名空间(Android 11后)中,我们提到了"目录-区段"映射属性dir.name,指向 [name] 区段所应用到的目录的路径,其实就是baseconfig.cc中定义的dirToSection

cpp 复制代码
// system/linkerconfig/contents/configuration/baseconfig.cc

android::linkerconfig::modules::Configuration CreateBaseConfiguration(
    Context& ctx) {
  std::vector<Section> sections;

  ctx.SetCurrentLinkerConfigType(LinkerConfigType::Default);

  // Don't change the order here. The first pattern that matches with the
  // absolute path of an executable is selected.
  std::vector<DirToSection> dirToSection = {
      {"/system/bin/", "system"},
      {"/system/xbin/", "system"},
      {Var("SYSTEM_EXT") + "/bin/", "system"},

      // Processes from the product partition will have a separate section if
      // PRODUCT_PRODUCT_VNDK_VERSION is defined. Otherwise, they are run from
      // the "system" section.
      {Var("PRODUCT") + "/bin/", "product"},

      {"/odm/bin/", "vendor"},
      {"/vendor/bin/", "vendor"},
      {"/data/nativetest/odm", "vendor"},
      {"/data/nativetest64/odm", "vendor"},
      {"/data/benchmarktest/odm", "vendor"},
      {"/data/benchmarktest64/odm", "vendor"},
      {"/data/nativetest/vendor", "vendor"},
      {"/data/nativetest64/vendor", "vendor"},
      {"/data/benchmarktest/vendor", "vendor"},
      {"/data/benchmarktest64/vendor", "vendor"},

      {"/data/nativetest/unrestricted", "unrestricted"},
      {"/data/nativetest64/unrestricted", "unrestricted"},

      // Create isolated namespace for development purpose.
      // This isolates binary from the system so binaries and libraries from
      // this location can be separated from system libraries.
      {"/data/local/tmp/isolated", "isolated"},

      // Create directories under shell-writable /data/local/tests for
      // each namespace in order to run tests.
      {"/data/local/tests/product", "product"},
      {"/data/local/tests/system", "system"},
      {"/data/local/tests/unrestricted", "unrestricted"},
      {"/data/local/tests/vendor", "vendor"},

      // TODO(b/123864775): Ensure tests are run from one of the subdirectories
      // above.  Then clean this up.
      {"/data/local/tmp", "unrestricted"},

      {"/postinstall", "postinstall"},
      // Fallback entry to provide APEX namespace lookups for binaries anywhere
      // else. This must be last.
      {"/data", "system"},
      // TODO(b/168556887): Remove this when we have a dedicated section for
      // binaries in APKs
      {Var("PRODUCT") + "/app/", "system"},
  };

  sections.emplace_back(BuildSystemSection(ctx));
  if (ctx.IsVndkAvailable()) {
    sections.emplace_back(BuildVendorSection(ctx));
    if (android::linkerconfig::modules::IsProductVndkVersionDefined()) {
      sections.emplace_back(BuildProductSection(ctx));
    } else {
      RedirectSection(dirToSection, "product", "system");
    }
  } else {
    RemoveSection(dirToSection, "product");
    RemoveSection(dirToSection, "vendor");
  }

  sections.emplace_back(BuildUnrestrictedSection(ctx));
  sections.emplace_back(BuildPostInstallSection(ctx));

  sections.emplace_back(BuildIsolatedSection(ctx));

  return android::linkerconfig::modules::Configuration(std::move(sections),
                                                       dirToSection);
}

因为我们是vendor/bin下面的程序,所以可以看出来我们是vendor section,因此我们看BuildVendorSection即可。

cpp 复制代码
// system/linkerconfig/contents/section/vendor.cc

Section BuildVendorSection(Context& ctx) {
  ctx.SetCurrentSection(SectionType::Vendor);
  std::vector<Namespace> namespaces;

  namespaces.emplace_back(BuildVendorDefaultNamespace(ctx));
  namespaces.emplace_back(BuildVndkNamespace(ctx, VndkUserPartition::Vendor));
  namespaces.emplace_back(BuildSystemNamespace(ctx));
  namespaces.emplace_back(BuildRsNamespace(ctx));

  if (android::linkerconfig::modules::IsVndkInSystemNamespace()) {
    namespaces.emplace_back(BuildVndkInSystemNamespace(ctx));
  }

  std::set<std::string> visible_apexes;

  // APEXes with public libs should be visible
  for (const auto& apex : ctx.GetApexModules()) {
    if (apex.public_libs.size() > 0) {
      visible_apexes.insert(apex.name);
    }
  }

  android::linkerconfig::modules::LibProviders libs_providers = {};
  if (ctx.IsVndkAvailable()) {
    libs_providers[":vndk"] = android::linkerconfig::modules::LibProvider{
        "vndk",
        std::bind(BuildVndkNamespace, ctx, VndkUserPartition::Vendor),
        {Var("VNDK_SAMEPROCESS_LIBRARIES_VENDOR"),
         Var("VNDK_CORE_LIBRARIES_VENDOR")},
    };
  }

  return BuildSection(
      ctx, "vendor", std::move(namespaces), visible_apexes, libs_providers);
}

我们可以看到最后调用了BuildSection,在其中调用了AddStandardSystemLinks 添加system的共享库

cpp 复制代码
// system/linkerconfig/contents/section/sectionbuilder.cc

Section BuildSection(const Context& ctx, const std::string& name,
                     std::vector<Namespace>&& namespaces,
                     const std::set<std::string>& visible_apexes,
                     const LibProviders& providers) {
  // add additional visible APEX namespaces
  for (const auto& apex : ctx.GetApexModules()) {
    if (visible_apexes.find(apex.name) == visible_apexes.end() &&
        !apex.visible) {
      continue;
    }
    if (auto it = std::find_if(
            namespaces.begin(),
            namespaces.end(),
            [&apex](auto& ns) { return ns.GetName() == apex.namespace_name; });
        it == namespaces.end()) {
      auto ns = ctx.BuildApexNamespace(apex, true);
      namespaces.push_back(std::move(ns));
    } else {
      // override "visible" when the apex is already created
      it->SetVisible(true);
    }
  }

  // resolve provide/require constraints
  Section section(std::move(name), std::move(namespaces));
  if (auto res = section.Resolve(ctx, providers); !res.ok()) {
    LOG(ERROR) << res.error();
  }

  AddStandardSystemLinks(ctx, &section); // 添加通用的system link共享库
  return section;
}

在kBionicLibs 加上我们需要的库即可

cpp 复制代码
 // system/linkerconfig/contents/common/system_links.cc

namespace {
const std::vector<std::string> kBionicLibs = {
    "libc.so",
    "libdl.so",
    "libdl_android.so",
    "libm.so",
};
}  // namespace

namespace android {
namespace linkerconfig {
namespace contents {

using android::linkerconfig::modules::Namespace;
using android::linkerconfig::modules::Section;

void AddStandardSystemLinks(const Context& ctx, Section* section) {
  const bool debuggable = android::base::GetBoolProperty("ro.debuggable", false);
  const std::string system_ns_name = ctx.GetSystemNamespaceName();
  const bool is_section_vndk_enabled = ctx.IsSectionVndkEnabled();
  section->ForEachNamespaces([&](Namespace& ns) {
    if (ns.GetName() != system_ns_name) {
      ns.GetLink(system_ns_name).AddSharedLib(kBionicLibs);
      if (!is_section_vndk_enabled || ns.GetName() != "default") {
        // TODO(b/185199923) remove the default value
        ns.GetLink(system_ns_name)
            .AddSharedLib(Var("SANITIZER_RUNTIME_LIBRARIES", ""));
      }
      if (debuggable) {
        // Library on the system image that can be dlopened for debugging purposes.
        ns.GetLink(system_ns_name).AddSharedLib("libfdtrack.so");
      }
    }
  });
}

}  // namespace contents
}  // namespace linkerconfig
}  // namespace android
相关推荐
Meteors.3 分钟前
Android约束布局(ConstraintLayout)常用属性
android
alexhilton39 分钟前
玩转Shader之学会如何变形画布
android·kotlin·android jetpack
whysqwhw5 小时前
安卓图片性能优化技巧
android
风往哪边走5 小时前
自定义底部筛选弹框
android
Yyyy4826 小时前
MyCAT基础概念
android
Android轮子哥6 小时前
尝试解决 Android 适配最后一公里
android
雨白7 小时前
OkHttp 源码解析:enqueue 非同步流程与 Dispatcher 调度
android
风往哪边走8 小时前
自定义仿日历组件弹框
android
没有了遇见8 小时前
Android 外接 U 盘开发实战:从权限到文件复制
android
Monkey-旭9 小时前
Android 文件存储机制全解析
android·文件存储·kolin