温馨提示:这篇文章已超过368天没有更新,请注意相关的内容是否还可用!
摘要:本文介绍了Android系统(Android 11及以后版本)中链接器命名空间共享库的配置方法。文章详细阐述了如何配置共享库,以便在应用程序中使用。通过优化配置,可以提高系统的运行效率和应用程序的性能。本文旨在为开发者提供关于Android系统链接器命名空间共享库配置的有效指南。
Android system — 链接器命名空间共享库配置方法
- 1. 应用进程
- 1.1 应用进程类加载器的命名空间初始化
- 1.1.1 OpenNativeLibrary
- 1.1.2 LibraryNamespaces::Create
- 1.2 配置共享库位置
- 2. native进程
- 2.1 native 命名空间配置初始化
- 2.1.1 android_namespace_t::is_accessible
- 2.1.2 init_default_namespaces
- 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创建新的命名空间。
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 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 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 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创建新的命名空间
(图片来源网络,侵删)Result 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 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 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等命名空间的共享库
Result 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 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中
// 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进行权限判断
// 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接口
// bionic/linker/linker_namespaces.h const std::vector& get_allowed_libs() const { return allowed_libs_; } void set_allowed_libs(std::vector&& allowed_libs) { allowed_libs_ = std::move(allowed_libs); } void set_allowed_libs(const std::vector& allowed_libs) { allowed_libs_ = allowed_libs; }
2.1.2 init_default_namespaces
通过这个思路我们发现调用其实在init_default_namespaces
- 初始化default命名空间
- 初始化vndk等其他命名空间
- 在命名空间之间建立链接
std::vector 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 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 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
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
// system/linkerconfig/contents/configuration/baseconfig.cc android::linkerconfig::modules::Configuration CreateBaseConfiguration( Context& ctx) { std::vector 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 = { {"/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即可。
// system/linkerconfig/contents/section/vendor.cc Section BuildVendorSection(Context& ctx) { ctx.SetCurrentSection(SectionType::Vendor); std::vector 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 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的共享库
// system/linkerconfig/contents/section/sectionbuilder.cc Section BuildSection(const Context& ctx, const std::string& name, std::vector&& namespaces, const std::set& 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) const std::vector "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
还没有评论,来说两句吧...