VNDK 定义工具

VNDK 定义工具可帮助供应商将其源代码树迁移到 Android 8.0 环境。此工具会扫描系统和供应商映像中的二进制文件,然后解析依赖项。根据模块依赖关系图,此工具还可以检测到违反 VNDK 概念的行为,并为在分区之间移动模块提供见解/建议。如果指定了通用系统映像 (GSI),VNDK 定义工具可以将您的系统映像与 GSI 进行比较,并确定扩展库。

本节介绍 VNDK 定义工具常用的三个命令

  • vndk。计算 Android 8.0 及更高版本中构建系统变通方法的 VNDK_SP_LIBRARIES、VNDK_SP_EXT_LIBRARIES 和 EXTRA_VENDOR_LIBRARIES。
  • check-dep。检查从供应商模块到不符合条件的框架共享库的违规模块依赖关系。
  • deps。打印共享库和可执行文件之间的依赖关系。

如需详细了解高级命令用法,请参阅 VNDK Definition Tool 代码库中的 README.md 文件。

vndk

vndk 子命令从系统分区和供应商分区加载共享库和可执行文件,然后解析模块依赖关系,以确定必须复制到 /system/lib[64]/vndk-sp-${VER}/vendor/lib[64] 的库。vndk 子命令的选项包括:

选项 说明
--system 指向包含系统分区中文件的目录。
--vendor 指向包含供应商分区中文件的目录。
--aosp-system 指向包含通用系统映像 (GSI) 中文件的目录。
--load-extra-deps 指向描述隐式依赖关系(例如 dlopen())的文件。

例如,要计算 VNDK 库集,请运行以下 vndk 子命令:

./vndk_definition_tool.py vndk \
    --system ${ANDROID_PRODUCT_OUT}/system \
    --vendor ${ANDROID_PRODUCT_OUT}/vendor \
    --aosp-system ${ANDROID_PRODUCT_OUT}/../generic_arm64_ab/system\
    --load-extra-deps dlopen.dep

使用简单的文件格式指定额外的依赖项。每行表示一个关系,冒号前面的文件依赖于冒号后面的文件。例如:

/system/lib/libart.so: /system/lib/libart-compiler.so

此行让 VNDK 定义工具知道 libart.so 依赖于 libart-compiler.so

安装目标位置

VNDK 定义工具列出了以下类别的库和相应的安装目录:

类别 目录
vndk_sp 必须安装到 /system/lib[64]/vndk-sp-${VER}
vndk_sp_ext 必须安装到 /vendor/lib[64]/vndk-sp
extra_vendor_libs 必须安装到 /vendor/lib[64]

构建系统模板

从 VNDK 定义工具收集输出后,供应商可以创建一个 Android.mk 文件,并在其中填写 VNDK_SP_LIBRARIESVNDK_SP_EXT_LIBRARIESEXTRA_VENDOR_LIBRARIES,以自动执行将库复制到指定安装目标位置的过程。

ifneq ($(filter $(YOUR_DEVICE_NAME),$(TARGET_DEVICE)),)
VNDK_SP_LIBRARIES := ##_VNDK_SP_##
VNDK_SP_EXT_LIBRARIES := ##_VNDK_SP_EXT_##
EXTRA_VENDOR_LIBRARIES := ##_EXTRA_VENDOR_LIBS_##

#-------------------------------------------------------------------------------
# VNDK Modules
#-------------------------------------------------------------------------------
LOCAL_PATH := $(call my-dir)

define define-vndk-lib
include $$(CLEAR_VARS)
LOCAL_MODULE := $1.$2
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_PREBUILT_MODULE_FILE := $$(TARGET_OUT_INTERMEDIATE_LIBRARIES)/$1.so
LOCAL_STRIP_MODULE := false
LOCAL_MULTILIB := first
LOCAL_MODULE_TAGS := optional
LOCAL_INSTALLED_MODULE_STEM := $1.so
LOCAL_MODULE_SUFFIX := .so
LOCAL_MODULE_RELATIVE_PATH := $3
LOCAL_VENDOR_MODULE := $4
include $$(BUILD_PREBUILT)

ifneq ($$(TARGET_2ND_ARCH),)
ifneq ($$(TARGET_TRANSLATE_2ND_ARCH),true)
include $$(CLEAR_VARS)
LOCAL_MODULE := $1.$2
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_PREBUILT_MODULE_FILE := $$($$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_INTERMEDIATE_LIBRARIES)/$1.so
LOCAL_STRIP_MODULE := false
LOCAL_MULTILIB := 32
LOCAL_MODULE_TAGS := optional
LOCAL_INSTALLED_MODULE_STEM := $1.so
LOCAL_MODULE_SUFFIX := .so
LOCAL_MODULE_RELATIVE_PATH := $3
LOCAL_VENDOR_MODULE := $4
include $$(BUILD_PREBUILT)
endif  # TARGET_TRANSLATE_2ND_ARCH is not true
endif  # TARGET_2ND_ARCH is not empty
endef

$(foreach lib,$(VNDK_SP_LIBRARIES),\
    $(eval $(call define-vndk-lib,$(lib),vndk-sp-gen,vndk-sp,)))
$(foreach lib,$(VNDK_SP_EXT_LIBRARIES),\
    $(eval $(call define-vndk-lib,$(lib),vndk-sp-ext-gen,vndk-sp,true)))
$(foreach lib,$(EXTRA_VENDOR_LIBRARIES),\
    $(eval $(call define-vndk-lib,$(lib),vndk-ext-gen,,true)))


#-------------------------------------------------------------------------------
# Phony Package
#-------------------------------------------------------------------------------

include $(CLEAR_VARS)
LOCAL_MODULE := $(YOUR_DEVICE_NAME)-vndk
LOCAL_MODULE_TAGS := optional
LOCAL_REQUIRED_MODULES := \
    $(addsuffix .vndk-sp-gen,$(VNDK_SP_LIBRARIES)) \
    $(addsuffix .vndk-sp-ext-gen,$(VNDK_SP_EXT_LIBRARIES)) \
    $(addsuffix .vndk-ext-gen,$(EXTRA_VENDOR_LIBRARIES))
include $(BUILD_PHONY_PACKAGE)

endif  # ifneq ($(filter $(YOUR_DEVICE_NAME),$(TARGET_DEVICE)),)

check-dep

check-dep 子命令扫描供应商模块并检查其依赖关系。如果检测到违规行为,它会打印违规的依赖库和符号用法。

./vndk_definition_tool.py check-dep \
    --system ${ANDROID_PRODUCT_OUT}/system \
    --vendor ${ANDROID_PRODUCT_OUT}/vendor \
    --tag-file eligible-list.csv \
    --module-info ${ANDROID_PRODUCT_OUT}/module-info.json \
    1> check_dep.txt \
    2> check_dep_err.txt

例如,以下示例输出显示了从 libRS_internal.solibmediandk.so 的违规依赖关系:

/system/lib/libRS_internal.so
        MODULE_PATH: frameworks/rs
        /system/lib/libmediandk.so
                AImageReader_acquireNextImage
                AImageReader_delete
                AImageReader_getWindow
                AImageReader_new
                AImageReader_setImageListener

check-dep 子命令的选项包括:

选项 说明
--tag-file 必须引用符合条件的库标记文件(如下所述),这是一个 Google 提供的电子表格,其中描述了框架共享库的类别。
--module-info 指向 Android 构建系统生成的 module-info.json 文件。它帮助 VNDK 定义工具将二进制模块与源代码关联起来。

符合条件的库标记文件

Google 提供了一个符合条件的 VNDK 电子表格(例如 eligible-list.csv),用于标记可供供应商模块使用的框架共享库。

标记 说明
LL-NDK 具有稳定 ABI/API 的共享库,可供框架模块和供应商模块使用。
LL-NDK-Private LL-NDK 库的私有依赖项。供应商模块不得直接访问这些库。
VNDK-SP SP-HAL 框架共享库依赖项。
VNDK-SP-Private 并非所有供应商模块都可直接访问的 VNDK-SP 依赖项。
VNDK 可供供应商模块使用的框架共享库(SP-HAL 和 SP-HAL-Dep 除外)。
VNDK-Private 并非所有供应商模块都可直接访问的 VNDK 依赖项。
FWK-ONLY 框架专用共享库,供应商模块不得访问(无论是直接还是间接访问)。
FWK-ONLY-RS 框架专用共享库,供应商模块不得访问(RS 用法除外)。

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

标记 说明
SP-HAL 同进程 HAL 实现共享库。
SP-HAL-Dep SP-HAL 供应商共享库依赖项(也称为 SP-HAL 依赖项,不包括 LL-NDK 和 VNDK-SP)。
VND-ONLY 框架不可见的共享库,框架模块不得访问。复制的扩展 VNDK 库也标记为 VND-ONLY。

标记之间的关系

Relationships between tags.

图 1. 标记之间的关系。

deps

为了调试库依赖关系,deps 子命令会打印模块依赖关系。

./vndk_definition_tool.py deps \
    --system ${ANDROID_PRODUCT_OUT}/system \
    --vendor ${ANDROID_PRODUCT_OUT}/vendor

输出由多行组成。没有制表符的行表示新节的开始。带有制表符的行依赖于上一节。例如:

/system/lib/ld-android.so
/system/lib/libc.so
        /system/lib/libdl.so

此输出表明 ld-android.so 没有依赖项,而 libc.so 依赖于 libdl.so

当指定 --revert 选项时,deps 子命令会打印库的用法(反向依赖关系)。

./vndk_definition_tool.py deps \
    --revert \
    --system ${ANDROID_PRODUCT_OUT}/system \
    --vendor ${ANDROID_PRODUCT_OUT}/vendor

例如:

/system/lib/ld-android.so
        /system/lib/libdl.so
        

此输出表明 ld-android.solibdl.so 使用,或者换句话说,libdl.so 依赖于 ld-android.so。此外,此输出表明 libdl.sold-android.so 的唯一用户。

当指定 --symbol 选项时,deps 子命令会打印正在使用的符号。

./vndk_definition_tool.py deps \
    --symbol \
    --system ${ANDROID_PRODUCT_OUT}/system \
    --vendor ${ANDROID_PRODUCT_OUT}/vendor
    

例如:

/system/lib/libc.so
        /system/lib/libdl.so
                android_get_application_target_sdk_version
                dl_unwind_find_exidx
                dlclose
                dlerror
                dlopen
                dlsym

此输出表明 libc.so 依赖于从 libdl.so 导出的六个函数。如果同时指定 --symbol 选项和 --revert 选项,则会打印用户使用的符号。