首页 > 其他分享 >Android VNDK

Android VNDK

时间:2023-10-24 17:34:14浏览次数:32  
标签:vendor modules system vndk so Android VNDK

 

1.VNDK是什么

VNDK 的全称是 Vendor Native Development Kit,中文翻译过来叫“供应商原生开发套件”。本身实际上指的是 Google 提供给 Vendor 用来开发自己 HAL 的一套库。但实际上这个概念的引入有一个很大的背景,就是 Treble 项目。自 Android O(8.0)以来,Google 引入了 Treble 架构,希望对 vendor 和 system 分区进行解耦处理。期望实现的目标:

“In an ideal Android 8.0 and higher world, framework processes do not load vendor shared libraries, all vendor processes load only vendor shared libraries (and a portion of framework shared libraries), and communications between framework processes and vendor processes are governed by HIDL and hardware binder.”

注解:Google(AOSP)负责维护 system 分区里的内容和升级;vendor 负责维护 vendor 分区中的内容。为了解耦(所谓解耦,在官方文档上常用 dependency 指代,实际可以理解为动态库链接意义上的依赖),位于 system 分区的 framwork 进程不可以加载 vendor 分区中的共享库等资源,vendor 分区中的 vendor 进程(我理解这指的应该主要是提供 HAL 服务的后台进程)仅加载 vendor 分区中的共享库(vendor 编写的 HAL so)以及也可能会加载部分 system 分区中的共享库(具体是什么后面会总结),而 framework 进程和 vendor 进程之间按照 HIDL/AIDL 方式定义的接口,通过 IPC/hwbinder 的方式来实现通信。

这张图的红色虚线上面就是 system 分区,下面就是 vendor 分区。其中几个概念 LLNDK、VNDK、SP-HAL 的概念下面再聊。这里关键是要注意的红色禁止符号强调的内容,就是上面我们说的引入解耦后不允许出现的链接和加载情况。

注意该图中的 libcamera_metadata.so 被标注为 VNDK,这个就是我们关注的 VNDK。

那么 VNDK 到底是什么?官方的定义:

Eligible VNDK Libraries (VNDK) are Framework Shared Libraries that are safe to be copied twice. Framework Modules and Vendor Modules can link with their own copies. A framework shared library can become an eligible VNDK library only if it satisfies the following criteria:

  • It does not send/receive IPCs to/from the framework.
  • It is not related to ART virtual machine.
  • It does not read/write files/partitions with unstable file formats.
  • It does not have special software license which requires legal reviews.
  • Its code owner does not have objections to vendor usages.

我的理解是,之所以 framework 和 vendor 的 modules(注,这里的 modules 包括了 so 和 exe 等资源) 存在耦合,关键是因为它们都依赖于同一份公共的库,系统升级时一旦这些库的 ABI/API 发生变化,那么负责 framework modules 的 Google 和负责 vendor modules 的各个 Vendor 都要同步升级,这是一件很麻烦的事情。

所以改造的核心对象就是 framework modules 和 vendor modules 都依赖的那份公共的库。也就是下图中的那个 Dependencies。这些 Dependencies 其实就是在引入 Treble 设计之前原先 framework 维护的那组 framework modules。

经过深入的分析,Google 把这些 Dependencies 基于解耦的需要又再次分为两大类:

Dependencies 中的第一类库的 API/ABI 相对稳定的,不会因为 AOSP 的升级而轻易改变,我们把它们叫做 LL-NDK,即 Low Level NDK。这都是一些非常底层的基础库,具体包括:

libEGL.so, libGLESv1_CM.so, libGLESv2.so, libGLESv3.so, libandroid_net.so, libc.so, libdl.so, liblog.so, libm.so, libnativewindow.so, libneuralnetworks.so, libsync.so, libvndksupport.so, and libvulkan.so,

对于 LL-NDK,仍然保持一份就好,framework modules 和 vendor modules 共享同一套 LL-NDK 库。

除了 LL-NDK,Dependencies 中还有一些 framework modules 会被 vendor modules 访问。注意如果出现这种依赖情况我们对这些 framework modules 还是和原来一样只维护一份就不合适了。如下 【图 3】所示,假设 libcamera_metadata.so 这个库既会被 Framework 中的 modules 访问,又会被 vendor modules(图上是 [email protected])访问。那么这里的 libcamera_metadata.so 就是一个耦合点。Google 采用的解耦方法也很简单,就是对于 libcamera_metadata,我们在编译时会将其做成两份,一份给 Framework 的 modules 用,即图中的 libcamera_metadata.so (FWK-ONLY),一份给 vendor modules 用,即图中的 libcamera_metadata.so (VNDK)。而给 vendor modules 用的这份 so 就叫 VNDK。在 【参考 4】 中基于 build system 的上下文环境,libcamera_metadata.so (FWK-ONLY) 也叫做 "core variant",libcamera_metadata.so (VNDK) 也叫做 "vendor variant"。

分成两份后,即引入多出来的那份 VNDK 后对升级的影响见下图。假设我们在构建某个 AOSP 版本,譬如 Android 8 时,采用的 Framework 和 VNDK 版本都是 26,结合上图,libcamera_metadata.so (FWK-ONLY) 属于 Framework-26 部分,libcamera_metadata.so (VNDK) 属于 VNDK-26,[email protected] 属于 Vendor-26 部分。那么 vendor module 构建时都是基于 VNDK-26 的,工作正常。升级系统时,我们制作 system image 时,里面可以带上新的 Framework-27,其中 libcamera_metadata.so (FWK-ONLY) 升级到新的 27,而 VNDK 部分依然采用 VNDK-26。这样新系统启动后,Vendor-26 部分的 [email protected] 依然会链接 VNDK-26 版本中的停留在 26 版本的 libcamera_metadata.so (VNDK),framework 会链接 27 版本的 libcamera_metadata.so (FWK-ONLY)。也就是说,一式两份后,FWK-ONLY 和 VNDK 两部分可以单独升级,互不干扰,也就是解耦了。而且注意 FWK-ONLY 和 VNDK 这两部分还都在 Google 所掌控的 system image 中,Google 的控制权依然稳固。

值得注意的一点是,Dependencies 中的这第二类 framework modules 并不是都需要一式两份,这个实际 build 时也要看情况而定,具体的描述如下:

If some framework modules depend on this module, the core variant is built. If some vendor modules depend on this module, the vendor variant is built.

2.VNDK 在系统中存放的位置

VNDK APEX 章节有以下描述:

In Android 10 and lower, modules with vndk.enabled were installed in /system/lib[64]/vndk[-sp]-${VER}. In Android 11 and higher, VNDK libraries are packaged in an APEX format and the name of VNDK APEX is com.android.vndk.v${VER}. Depending on the device configuration, VNDK APEX is flattened or unflattened and is available from the canonical path /apex/com.android.vndk.v${VER}.

实验的系统是 aosp 12,所以我们可以去看一下 out/target/product/emulator_riscv64/system/apex, 下面的确存在一个 com.android.vndk.current.apex 文件。这个文件在系统启动阶段会被解压开后挂载在 /apex/com.android.vndk.v${VER} 下。

开模拟器登录会看到 /apex 下有个 com.android.vndk.v31 和 com.android.vndk.v31@1,具体解压开的是哪个我还没去仔细看,但这两个目录的文件都是一样的。以 /apex/com.android.vndk.v31@1/lib64/[email protected] 为例,我们会发现 /system/lib64/ 下也有一个同名的 [email protected]/system/lib64/[email protected] 就是 "core variant",而 /apex/com.android.vndk.v31@1/lib64/[email protected] 就是 "vendor variant"。

 

3.VNDK-SP

VNDK-SP 其本质也是一种 VNDK,唯一的例外是这些 so 专用于 SP-HAL。所以上面涉及 VNDK 的内容对 VNDK-SP 也是适用的。这里我们重点关心一下 VNDK-SP 和普通 VNDK 的区别。

SP-HAL 的定义有详细定义,摘录如下,更多的 SP-HAL 的介绍 :

Same-Process HAL (SP-HAL) is a set of predetermined HALs implemented as Vendor Shared Libraries and loaded into Framework Processes.

SP-HALs must depend only on LL-NDK and VNDK-SP.

VNDK-SP is a predefined subset of eligible VNDK libraries.

下面这幅图很好地给出了 SP-HAL 和 VNDK-SP 的例子

图中 libGLES_${chipset}.so 就是一个 SP-HAL。譬如 surfaceflinger 这个 framework 维护的system 进程要进行 GPU 合成的时候,需要访问位于 vendor 分区的 GPU 驱动(libvendor_gpu.so),此时需要通过 libGLES_${chipset}.so 这个 HAL 代理,和普通 HAL 通过 IPC 方式不同,SP-HAL 是将 该 so 直接 dlopen 加载到 surfaceflinger 进程。由于属于 framework module 的 surfaceflinger 和来自 vendor module 的 libGLES_${chipset}.so 都要依赖 libcutils.so,所以为了升级解耦的需要,我们同样要遵循 VNDK 的要求,将 libcutils.so 一式两份,其中我们称给 libGLES_${chipset}.so 链接的那份 so 为 VNDK-SP。

注意这里和普通 VNDK 有所不同的是,第三张图中 HAL service 和 client 之间采用 IPC,所以 libcamera_metadata.so (FWK-ONLY) 和 libcamera_metadata.so (FWK-VNDK) 实际加载在两个不同的进程中,不存在名字冲突的问题。但是在 上图 中 libcutils.so (FWK-ONLY) 和 libcutils.so (VNDK-SP) 两个 so 都会被加载到 surfaceflinger 这个进程中,为了解决加载冲突的问题,Google 又引入了 linker namespace 解决方案。这个专题也比较大,这里暂不展开。

 

4.VNDK的典型Issue

问题描述与分析

vndksupport:Could not load demo.so from default namespace:dlopen failed: library “libstdc++.so” not found.

demo.so位于vendor下面,找不到libstdc++.so,而libstdc++.so的库位于system/lib和system/lib64中。
这说明vendor下面的库引用libstdc++.so时,无法找到system/lib中的libstdc++.so。

Android O之后的变化,从 LL-NDK 库中移除 libstdc++.so,不再支持 libstdc++.so,改用 libc++.so。
这导致一些老的平台上依旧使用了 libstdc++.so,而产生了not found问题。

相关目录文件:
\system\core\rootdir\etc\

Solution 1

system/core/rootdir/etc/ld.config.txt文件中,[vendor]下,增加:

# Access to system libraries are allowed
namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
namespace.default.search.paths += /system/${LIB}
namespace.default.search.paths += /product/${LIB}

Solution 2

当google/wahoo/BoardConfig.mk中,打开如下编译选项时:
BOARD_VNDK_VERSION := current

根据build/make/core/Makefile中的判断:

# -----------------------------------------------------------------
# FINAL_VENDOR_DEFAULT_PROPERTIES will be installed in vendor/default.prop if
# property_overrides_split_enabled is true. Otherwise it will be installed in
# ROOT/default.prop.
ifdef BOARD_VNDK_VERSION
  ifeq ($(BOARD_VNDK_VERSION),current)
    FINAL_VENDOR_DEFAULT_PROPERTIES := ro.vndk.version=$(PLATFORM_VNDK_VERSION)
  else
    FINAL_VENDOR_DEFAULT_PROPERTIES := ro.vndk.version=$(BOARD_VNDK_VERSION)
  endif
  ifdef BOARD_VNDK_RUNTIME_DISABLE
    FINAL_VENDOR_DEFAULT_PROPERTIES += ro.vndk.lite=true
  endif
else
  FINAL_VENDOR_DEFAULT_PROPERTIES := ro.vndk.version=$(PLATFORM_VNDK_VERSION)
  FINAL_VENDOR_DEFAULT_PROPERTIES += ro.vndk.lite=true
endif

最终default.prop中会有ro.vndk.lite=true。当ro.vndk.lite=true时,动态链接器将加载 /system/etc/ld.config.vndk_lite.txt 中的链接器命名空间配置,这仅会隔离 SP-HAL 和 VNDK-SP。
即system/core/rootdir/etc/ld.config.vndk_lite.txt

而system/core/rootdir/etc/ld.config.vndk_lite.txt
中,已经包含了namespace.default.search.paths += /system/${LIB}。
因此,我们可以采取的操作为:

注释掉**/**/BoardConfig.mk中的编译选项:
#BOARD_VNDK_VERSION := current

Solution 3(不推荐)

找到libstdc++.so,将libstdc++.so文件拷贝到vendor/lib或者vendor/lib64中去。

 

 

参考链接

  • 学习笔记: VNDK 基本概念 https://gitee.com/aosp-riscv/working-group/blob/master/articles/20220923-vndk.md
  • Vendor Native Development Kit (VNDK) overview https://source.android.google.cn/docs/core/architecture/vndk
  • 关于Android 供应商原生开发套件(VNDK)引发的问题 https://blog.csdn.net/Sunxiaolin2016/article/details/103542190

 

标签:vendor,modules,system,vndk,so,Android,VNDK
From: https://www.cnblogs.com/ArsenalfanInECNU/p/17785351.html

相关文章

  • Android Kotlin 协程初探
    1它是什么(协程和Kotlin协程)1.1协程是什么维基百科:协程,英文Coroutine[kəru’tin](可入厅),是计算机程序的一类组件,推广了协作式多任务的子程序,允许执行被挂起与被恢复。作为Google钦定的Android开发首选语言Kotlin,协程并不是Kotlin提出来的新概念,目前有协程概念的编程语言......
  • uniapp h5低版本Android显示空白
    前言:uniapp写的H5访问一直空白,打包app就可以正常显示,排查说是箭头函数低版本不支持,一顿操作npm,还是一样空白。最后:需要发行打包h5才能正常访问,服了也没告诉我啊。注:打包出来访问报错UncaughtSyntaxError:Unexpectedtoken'<',访问空白问题,在manifest.json文件中添加如图所示......
  • android命令行开启应用
    获取应用包名pmlistpackages|grep[KeyName]获取应用清单信息dumpsyspackage[PackageName]可查找具体的activity及对应参数裸启动应用amstartcom.test/.MainActivity在应用清单中一般带有‘LAUNCHER’字样的activity即启动入口带参数启动应用-单......
  • Android中RadioGroup的使用
    在安卓中为了给在几个选项中选择其中某个选项,需要用到Radiogroup2、为了增加灵活行,想要在Java代码中动态加载Radio这就涉及到一个问题,Radio的样式应该怎样修改RadioGroup的代码<RadioGroupandroid:id="@+id/rbgAttrSelect"android:layout_width="match_parent"......
  • ADB修改Android手机的分辨率和屏幕密度
    前言之前用自动精灵操作手机的时候,需要修改手机的分辨率,后来发现用ADB工具可以免root修改ADB方式修改前置操作1、用adb工具连接手机,记得开启usb调试模式2、执行命令,进入shell模式adbshell分辨率设置命令wmsize[reset|WxH|WdpxHdp]returnoroverridedisplaysize.w......
  • MAC之Android安装APK
    一,打开paths文件1,打开Finder,前往/etc/(快捷键:Shfit+Option+G)如下图:2,右击“etc”文件夹->"显示源项目"3,右击“etc”文件夹->"显示简介"4,更改“etc”的权限为读写5,更改/etc/paths文件的权限为读写6,右键paths文件->打开文件方式-> 文本编辑二,编辑paths文件1,Finder,前往SDK,如......
  • Android etc1tool之png图片转换pkm 和 zipalign简介
    一、导读我们继续总结学习基础知识,温故知新。本文记录androidetc1工具的介绍及使用。本文记录androidzipalign命令的介绍及使用。二、etc1tooletc1tool是一种命令行实用程序,可用于将PNG图片编码为ETC1压缩标准格式(PKM),并将ETC1压缩图片解码回PNG。简单讲就是png跟pkm......
  • Android推送问题排查
    针对MobPush智能推送服务在使用过程中可能出现的问题,本文为各位开发者们带来了针对MobPush安卓端推送问题的解决办法。 TCP在线推送排查排查TCP在线收不到推送时,我们先通过客户端的RegistrationId接口获取设备的唯一标识示例:MobPush.getRegistrationId(newMobPushCallback<String......
  • MobPush如何在Android端自定义铃声
    随着移动应用竞争进入红海时代,如何在APP推送中别出心裁显得尤为重要。例如对自己的APP推送赋予独特的推送铃声,能够给用户更加理想的使用体验。1、个性化提醒铃声有助于当收到特定类型的消息时,用户能够立刻识别出来。2、不同的推送铃声可以用于区分消息的紧急程度,从而为用户是否查看......
  • android ebpf初体验实现文件重定位
    之前通过修改内核插桩并编写内核模块的方式hookdo_sys_open函数(这种方式有点像tracepoint,都属于静态探测),这种方式优点是可以hook内核中的任意函数,但是需要编译内核和驱动模块较为麻烦。eBPF相当于在内核中定义了一个虚拟机,能够加载eBPF字节码并依赖kprobe,uprobe,tracepoint实现......