当前位置: 代码网 > it编程>App开发>Android > Android VNDK使用及原理深入探究

Android VNDK使用及原理深入探究

2024年05月18日 Android 我要评论
为何要使用 vndk?vndk的全称是vendor native development kit,是android 8.0引入的一种新技术。它表现一系列库的合集,用于让供应商开发自己的hals。vnd

为何要使用 vndk?

vndk的全称是vendor native development kit,是android 8.0引入的一种新技术。它表现一系列库的合集,用于让供应商开发自己的hals。vndk 包含在 system.img 中,并在运行时与供应商代码动态关联。

官方文档的解释给我的感觉其目的就是收敛android的碎片化。不仅仅vndk,android 8.0引入许多的技术都是为了将system与vendor分割开来。这样可以保持android核心系统的纯净性,而将碎片化扔给供应商维护。渐渐的芯片供应商和设备厂商可以无需关心android系统的实现,仅仅使用vndk就可以完成产品开发。

vndk相关概念

供应商模块

供应商模块是特定于供应商的可执行文件或共享库,这些模块将安装到供应商分区中。

  • 在 android.bp 文件中,供应商模块必须将vendor或proprietary属性设置为 true
  • 在 android.mk 文件中,供应商模块必须将 local_vendor_module 或 local_proprietary_module 设置为 true

framework共享库

在理想的android 8.0及更高版本环境中,framework进程不加载供应商共享库,而供应商进程仅加载供应商共享库(和一部分framework共享库)。framework进程与供应商进程之间的通信由hidl和hardware binder控制。

供应商进程需要使用framework共享库可能随系统的更新而发生变化。为了保证供应商模块在多个android版本上皆可正常工作,根据framework共享库的特性不同,将其三个子类别:

  • ll-ndk库:已知稳定的framework共享库,它们的开发者致力于保持其 api/abi 稳定性。ll-ndk 包含以下库:libegl.solibglesv1_cm.solibglesv2.solibglesv3.solibandroid_net.solibc.solibdl.soliblog.solibm.solibnativewindow.solibneuralnetworks.solibsync.solibvndksupport.so 和 libvulkan.so
  • 合格的 vndk 库 (vndk):可以安全复制两次的framework共享库。framework模块和供应商模块可以与其各自的库副本相关联。framework共享库只有满足以下条件才能成为合格的 vndk 库:

    • 不向framework发送或从framework接收 ipc。
    • 与 art 虚拟机无关。
    • 不读写文件格式不稳定的文件/分区。
    • 没有需要法律审查的特殊软件许可。
    • 其代码所有者不反对供应商使用该库。
  • 框架专用库 (fwk-only) :不属于上述类别的framework共享库。此类库具有以下特点:

    • 被视为framework内部实现细节。
    • 不得由供应商模块访问。
    • 具有不稳定的 abi/api,无 api/abi 兼容性保证。
    • 不会被复制。

ll-ndk

ll-ndk 共享库是具有稳定 abi 的共享库。框架模块和供应商模块均具有相同的最新实现。对于每个 ll-ndk 共享库,android.bp 都包含一个 llndk_library 模块定义:

llndk_library {
    name: "libvndksupport",
    symbol_file: "libvndksupport.map.txt",
}

该模块定义指定了模块名称和符号文件,后者描述了对供应商模块可见的符号。例如:

libvndksupport {
  global:
    android_load_sphal_library; # vndk
    android_unload_sphal_library; # vndk
  local:
    *;
};

same-process hal (sp-hal)

same-process hal (sp-hal) 是预定义的的一组hal,作为供应商共享库进行实现,并被加载到framework进程中。sp-hal 必须仅依赖于 ll-ndk 和 vndk-sp。vndk-sp 是一部分预定义的符合条件的 vndk 库。vndk-sp 库会被仔细审查,以确保将 vndk-sp 库双重加载到framework进程中不会导致问题。sp-hal 和 vndk-sp 均由 google 定义,并通过链接器命名空间进行隔离。

以下库是经过批准的 sp-hal:

  • libglesv1_cm_${driver}.so
  • libglesv2_${driver}.so
  • libglesv3_${driver}.so
  • libegl_${driver}.so
  • vulkan.${driver}.so
  • android.hardware.renderscript@1.0-impl.so
  • android.hardware.graphics.mapper@2.0-impl.so

以下库是 sp-hal 可以访问的 vndk-sp 库:

  • android.hardware.graphics.common@1.0.so
  • android.hardware.graphics.mapper@2.0.so
  • android.hardware.renderscript@1.0.so (renderscript)
  • librs_internal.so (renderscript)
  • libbase.so
  • libc++.so
  • libcutils.so
  • libhardware.so
  • libhidlbase.so
  • libhidltransport.so
  • libhwbinder.so
  • libion.so
  • libutils.so
  • libz.so

以下 vndk-sp 依赖项 (vndk-sp-private) 对 sp-hal 来说是不可见的:

  • librscpuref.so (renderscript)
  • librsdriver.so (renderscript)
  • libbacktrace.so
  • libblas.so (renderscript)
  • libbcinfo.so (renderscript)
  • liblzma.so
  • libunwind.so

以下是具有 rs 例外的框架专用库 (fwk-only-rs):

  • libft2.so (renderscript)
  • libmediandk.so (renderscript)

vndk 库简介

vndk 定义了可与供应商代码相关联的库集:vndk-core、vndk-sp 和 ll-ndk,并阻止供应商使用不在 vndk 集内的库。

vndk-core 库安装在 /system/lib[64]/vndk-${ver} 中,仅适用于 api 级别为 ${ver} 的供应商进程。${ver} 可以通过/vendor/default.prop中的系统属性ro.vndk.version获取。系统进程不得使用这些库,而必须使用安装在 /system/lib[64] 中的库。由于每个进程都具有严格的命名空间限制,因此不会造成重复加载 vndk-core 库。要在 vndk-core 中添加库,请将以下内容添加到 android.bp 中:

vendor_available: true,
vndk: {
    enabled: true,
},

vndk-sp 库安装在 /system/lib[64]/vndk-sp-${ver} 中,可以被供应商进程和系统进程(通过安装在供应商分区中的 sp-hal 库)使用。vndk-sp 库可以重复加载。要在 vndk-sp 中添加库,请将以下内容添加到 android.bp 中:

vendor_available: true,
vndk: {
    enabled: true,
    support_system_process: true,
},

ll-ndk 库安装在 /system/lib[64] 中。供应商模块可以使用 ll-ndk stub访问 ll-ndk 库的预选符号。ll-ndk 库必须支持向后兼容,且具有 abi 稳定性,以便旧版供应商模块使用新版 ll-ndk 库。由于 ll-ndk 具有 abi 稳定特性,vndk 快照无需包含旧版供应商映像的 ll-ndk 库。

目录

vndk库可以大致划分为以下目录:

  • /system/lib[64] 包含所有framework共享库,具体包括 ll-ndk、vndk 和framework专用库(包括 ll-ndk-private 和一些与 vndk-sp 中的库同名的库)。
  • /system/lib[64]/vndk-sp 包含适用于 same-process hal 的 vndk-sp 库。
  • /vendor/lib[64] 包含供应商扩展的 vndk 库(dxua 库或 dxux vndk 库)、same-process hal 实现,以及其他供应商共享库。
  • /vendor/lib[64]/vndk-sp 可能包含供应商扩展的 vndk-sp 库。

供应商模块从 /system/lib[64] 中加载 vndk 库。

vndk 电子表格

google 会提供一个符合条件的 vndk 电子表格(例如 eligible-list.csv),该电子表格会标记可由供应商模块使用的框架共享库:

标记说明
ll-ndk可由框架模块和供应商模块使用的共享库(具有稳定的 abi/api)。
ll-ndk-privatell-ndk 库的私有依赖项。供应商模块不得直接访问此类库。
vndk-spsp-hal 框架共享库依赖项。
vndk-sp-private所有供应商模块都无法直接访问的 vndk-sp 依赖项。
vndk面向供应商模块(sp-hal 和 sp-hal-dep 除外)提供的框架共享库。
vndk-private所有供应商模块都无法直接访问的 vndk 依赖项。
fwk-only供应商模块不得(直接或间接)访问、仅限框架使用的共享库。
fwk-only-rs供应商模块不得访问(rs 用途除外)、仅限框架使用的共享库。

下表描述了适用于供应商共享库的标记:

标记说明
sp-halsame-process hal 实现共享库。
sp-hal-depsp-hal 供应商共享库依赖项(也称为 sp-hal 依赖项,不包括 ll-ndk 和 vndk-sp)。
vnd-only框架模块不可见且不得访问的共享库。所复制的扩展后 vndk 库也将被标记为 vnd-only。

标记之间的关系:

vndk 快照

vndk 快照就是一组预编译的库文件和配置文件的集合。因为vndk的实质就是要规范供应商的开发,如果保证vndk接口稳定的标准化,供应商就无需修改vndk库。系统只要提供所有vndk版本的二进制文件,就可以满足供应商的开发。这些需求的文件就是vndk快照需要提供的内容。

vndk 快照包含以下文件:

  • vndk-core 和 vndk-sp 共享库的供应商变体。

    • 无需 ll-ndk 共享库,因为这类库是向后兼容的。
    • 对于 64 位目标,target_arch 和 target_2nd_arch 库都将被编译并包含在内。
  • vndk-core、vndk-sp、ll-ndk 和 vndk-private 库的列表,文件为 [vndkcore|vndksp|llndk|vndkprivate].libraries.txt
  • 链接器配置文件为 ld.config.txt
  • 许可文件。
  • module_paths.txt。记录所有 vndk 库的模块路径;检查 gpl 项目是否已在指定 android 源代码树中发布源代码时,需要用到这种文件。

以下示例展示了 arm64 (target_arch=arm64) vndk 快照 zip 文件 (android-vndk-arm64.zip) 的目录结构。

供应商镜像会依赖于特定版本的vndk,所以系统镜像中应该提供供应商需求的vndk版本的镜像。即使系统镜像与供应商镜像使用不同版本的android进行编译,但是只要保证系统镜像能够提供正确的vndk就保证正常运行。下图展示了android p系统镜像使用android o供应商镜像的场景。

启用 vndk

编译选项

在 boardconfig.mk添加board_vndk_version=current可以在编译过程开启vndk。也可以在编译模块时传递该编译选项,例如: m -j board_vndk_version=current my-lib)。

当启用 board_vndk_version=current 后,编译系统会检查库的依赖性和头文件的合法性。

  • 确保vendor对象仅依赖于vndk库集:vndk-core、vndk-sp 和 ll-ndk。确保core组件不依赖与vendor组件。
  • 移除全局头文件的依赖项,以便编译器可以明确是否使用-d__android_vndk__来编译头文件。就是说全局头文件无法再使用传递方式包含在头文件内。

启用 board_vndk_version后,系统会移除多个默认的全局头文件搜索路径。模块使用这些路径下的头文件时,需要明确指定与 header_libsstatic_libs 和/或 shared_libs 的依赖关系。这些路径中包括:

  • frameworks/av/include
  • frameworks/native/include
  • frameworks/native/opengl/include
  • hardware/libhardware/include
  • hardware/libhardware_legacy/include
  • hardware/ril/include
  • libnativehelper/include
  • libnativehelper/include_deprecated
  • system/core/include
  • system/media/audio/include

供应商变体库

在 android.bp 文件中,cc_librarycc_library_staticcc_library_shared 和 cc_library_headers 模块定义支持三个与 vndk 相关的属性:vendor_availablevndk.enabled 和 vndk.support_system_process

如果 一个库标记为vendor_available 或 vndk.enabled 为 true,则可能被编译两次,生成两种变体:核心变体和供应商变体。

  • 核心变体被视为framework模块,将安装到 /system/lib[64] 中。
  • 而供应商变体应被视为供应商模块。系统根据模块依赖性来决定是否编译变体,并进行依赖性检查。供应商变体安装路径会根据 android.bp中的属性来决定。

下表总结了编译系统如何处理供应商变体,

vendor_availablevndk .enabledvndk. support_system_process供应商变体说明
truefalsefalse供应商变体为 vnd-only。共享库将安装到 /vendor/lib[64] 中。
truefalsetrue无效(编译错误)
truetruefalse供应商变体为 vndk。共享库将安装到 /system/lib[64]/vndk-${ver} 中。
truetruetrue供应商变体为 vndk-sp。共享库将安装到 /system/lib[64]/vndk-sp-${ver} 中。
falsefalsefalse没有供应商变体。此模块为 fwk-only。
falsefalsetrue无效(编译错误)
falsetruefalse供应商变体为 vndk-private。共享库将安装到 /system/lib[64]/vndk-${ver} 中。供应商模块不得直接使用这些变体。
falsetruetrue供应商变体为 vndk-sp-private。共享库将安装到 /system/lib[64]/vndk-sp-${ver} 中。供应商模块不得直接使用这些变体。

注意:供应商可以为其模块设置 vendor_available,但不得设置 vndk.enabled 和 vndk.support_system_process,因为供应商模块无法在通用系统映像 (gsi) 中找到它们。

条件编译

默认情况下,android 编译系统会为供应商变体和 vndk 扩展定义 __android_vndk__。您可以使用 c 预处理器防护程序保护代码:

void all() { }

#if !defined(__android_vndk__)
void framework_only() { }
#endif

#if defined(__android_vndk__)
void vndk_only() { }
#endif

除了 __android_vndk__,还可以在 android.bp 中指定不同的 cflags 或 cppflags。在 target.vendor 中指定的 cflags 或 cppflags 是专门针对供应商变体的。

例如,以下 android.bp 定义了 libexample 和 libexample_ext。它为libexample的供应商变体定义了"libexample_enable_vndk=1",为libexample的扩展库定义了 "libexample_enable_vndk=1" 和"libexample_enable_vndk_ext=1"。

cc_library {
    name: "libexample",
    srcs: ["src/example.c"],
    vendor_available: true,
    vndk: {
        enabled: true,
    },
    target: {
        vendor: {
            cflags: ["-dlibexample_enable_vndk=1"],
        },
    },
}

cc_library {
    name: "libexample_ext",
    srcs: ["src/example.c"],
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libexample",
    },
    cflags: [
        "-dlibexample_enable_vndk=1",
        "-dlibexample_enable_vndk_ext=1",
    ],
}

vndk 扩展

android还提供了vndk扩展的方法,就是使用自己修改的vndk共享库来替换原始的vndk共享库。因为供应商很可能根据自己的需求来更改aosp库的源码,可能是为了提高性能,或者添加新钩子、新 api 或新功能。vndk 扩展库会安装到 /vendor/lib[64]/vndk[-sp] 中,并在系统运行时会替换原始的 vndk 共享库。

在 android 9 及更高版本中,android.bp 本身支持 vndk 扩展。要编译 vndk 扩展,请定义另一个具有 vendor:true 和 extends 属性的模块:

cc_library {
    name: "libvndk",
    vendor_available: true,
    vndk: {
        enabled: true,
    },
}

cc_library {
    name: "libvndk_ext",
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libvndk",
    },
}

具有 vendor:truevndk.enabled:true 和 extends 属性的模块可定义 vndk 扩展:

  • extends 属性必须指定基础 vndk 共享库名称(或 vndk-sp 共享库名称)。
  • vndk 扩展(或 vndk-sp 扩展)以扩展时所基于的基础模块名称命名。例如,libvndk_ext 的输出二进制文件是 libvndk.so,而非 libvndk_ext.so
  • vndk 扩展将安装到 /vendor/lib[64]/vndk 中。
  • vndk-sp 扩展将安装到 /vendor/lib[64]/vndk-sp 中。
  • 基础共享库必须同时具有 vndk.enabled:true 和 vendor_available:true

vndk-sp 扩展必须从 vndk-sp 共享库进行扩展,就是说在定义时必须包含相同的vndk.support_system_process 。vndk 扩展(或 vndk-sp 扩展)也可以依赖于其他供应商共享库:

cc_library {
    name: "libvndk_sp",
    vendor_available: true,
    vndk: {
        enabled: true,
        support_system_process: true,
    },
}

cc_library {
    name: "libvndk_sp_ext",
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libvndk_sp",
        support_system_process: true,
    shared_libs: [
        "libvendor",
    ],
}

cc_library {
    name: "libvendor",
    vendor: true,
}

如果供应商模块依赖于由 vndk 扩展定义的其他 api,则该模块必须在其 shared_libs 属性中指定 vndk 扩展的名称:

// a vendor shared library example
cc_library {
    name: "libvendor",
    vendor: true,
    shared_libs: [
        "libvndk_ext",
    ],
}

// a vendor executable example
cc_binary {
    name: "vendor-example",
    vendor: true,
    shared_libs: [
        "libvndk_ext",
    ],
}

如果供应商模块依赖于 vndk 扩展,则这些 vndk 扩展将自动安装到 /vendor/lib[64]/vndk[-sp] 中。如果某个模块不再依赖于 vndk 扩展,请向 cleanspec.mk 添加一个清理步骤,以移除共享库。例如:

$(call add-clean-step, rm -rf $(target_out_vendor)/lib/libvndk.so)

规则和sepolicy

vndk 规则

完整的 vndk 规则列表如下。

  • 框架进程不得从供应商分区中加载非 sp-hal 共享库(此规则从 android 8.1 开始严格地强制实施)。
  • 供应商进程不得从系统分区中加载非 ll-ndk 库、非 vndk-sp 库和非 vndk 库(android o 中并未严格地强制实施此规则,但未来版本中会这么做)。
  • 注意:要想从未来版本(比 android 8.0 更高的版本)仅针对框架的 ota 中受益,就不得在搭载 android 8.0 出厂的设备中违反此规则。
  • 已安装的 vndk 库必须是由 google 定义的合格 vndk 库的子集。
  • sp-hal 和 sp-hal-dep 的外部依赖项必须仅限于 ll-ndk 库或由 google 定义的 vndk-sp 库。

    • sp-hal 共享库的依赖项必须仅限于 ll-ndk 库、由 google 定义的 vndk-sp 库、其他 sp-hal 库和/或可标记为 sp-hal-dep 库的其他供应商共享库。
    • 只有当供应商共享库不是 aosp 库,且其依赖项仅限于 ll-ndk 库、由 google 定义的 vndk-sp 库、sp-hal 库和/或其他 sp-hal-dep 库时,才可标记为 sp-hal-dep 库。
  • vndk-sp 必须保持独立。在 android 8.0 中,系统以一种特殊方式处理 librs_internal.so,但在未来版本中,其处理方式会被重新考虑。
  • 不得通过非 hidl 接口(包括但不限于 binder、套接字、共享内存、文件等)进行框架-供应商通信。
  • 系统分区必须足够大,以便容纳所有符合条件的 vndk 库的两个副本,以及不符合条件的框架共享库的一个副本。

sepolicy

本部分中介绍的框架进程对应于 sepolicy 中的 coredomain,而供应商进程对应于 non-coredomain。例如,/dev/binder 只能在 coredomain 中被访问,而 /dev/vndbinder 只能在非 coredomain 中被访问。

类似政策会限制对系统分区和供应商分区上的共享库的访问。下表列出了访问不同类别的共享库时所需的权限:

类别分区是否可从 coredomain 访问是否可从 非 coredomain 访问
ll-ndk系统
ll-ndk-private系统
vndk-sp/vndk-sp-private系统
vndk-sp-ext供应商
vndk系统
vndk-ext供应商
fwk-only系统
fwk-only-rs系统
sp-hal供应商
sp-hal-dep供应商
vnd-only供应商

ll-ndk-private 和 vndk-sp-private 必须从这两个域中都可访问,因为非 coredomain 会间接访问这些库。同样,sp-hal-dep 必须可从 coredomain 访问,因为 sp-hal 依赖该域。

same_process_hal_file 标签

供应商分区中包含下面几个库。确保这些库既可以从 coredomain 访问,又可以从非 coredomain 访问。

  • vndk-sp-ext,位于 /vendor/lib[64]/vndk-sp
  • sp-hal,位于 /vendor/lib[64] 或 /vendor/lib[64]/hw
  • sp-hal-dep,位于 /vendor/lib[64] 或 /vendor/lib[64]/hw

将这些文件明确标记为 same_process_hal_file。因为在默认情况下,从 coredomain 无法访问 vendor 分区中的任何内容。请向供应商特定的 file_contexts 文件中添加与以下命令行类似的命令行:

/vendor/lib(64)?/hw/libmysphal\.so        u:object_r:same_process_hal_file:s0
/vendor/lib(64)?/vndk-sp/libbase\.so      u:object_r:same_process_hal_file:s0
/vendor/lib(64)?/libbaseinternal\.so      u:object_r:same_process_hal_file:s0

参考文档:

android source: vndk

以上就是android vndk使用及原理深入探究的详细内容,更多关于android vndk使用原理的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com