VNDK 定义工具

VNDK 定义工具可帮助供应商将其源代码树迁移到 Android 8.0 环境。该工具会先扫描系统映像及供应商映像中的二进制文件,然后解析依赖项。若有模块依赖项图为依据,该工具还可检测出不符合 VNDK 概念的行为,以及为在分区之间移动模块提供分析数据/建议。如果指定了常规系统映像 (GSI),VNDK 定义工具便可将您的系统映像与 GSI 进行比较,从而确定扩展后的库。

本部分将介绍 VNDK 定义工具常用的 3 个命令:

  • vndk:为 Android 8.0 及更高版本中的编译系统临时解决方法计算 VNDK_SP_LIBRARIES、VNDK_SP_EXT_LIBRARIES 和 EXTRA_VENDOR_LIBRARIES。
  • check-dep:检查是否有违规模块依赖项(从供应商模块指向不符合条件的框架共享库)。
  • deps:显示共享库与可执行文件之间的依赖关系。

要详细了解高级命令用法,请参阅 VNDK 定义工具代码库中的 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.so 指向 libmediandk.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 Same-Process HAL 实现共享库。
SP-HAL-Dep SP-HAL 供应商共享库依赖项(也称为 SP-HAL 依赖项,不包括 LL-NDK 和 VNDK-SP)。
VND-ONLY 框架模块不可见且不得访问的共享库。所复制的扩展后 VNDK 库也将被标记为 VND-ONLY。

标记之间的关系:

图 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
        

此输出信息表明:libdl.so 使用了 ld-android.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 导出的 6 个函数。如果同时指定了 --symbol 选项和 --revert 选项,该子命令则会显示使用者所用的符号。