VNDK 构建系统支持

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

在 Android 8.1 及更高版本中,构建系统具有内置的 VNDK 支持。启用 VNDK 支持后,构建系统会检查模块之间的依赖关系,为供应商模块构建特定于供应商的变体,并自动将这些模块安装到指定目录中。

VNDK 构建支持示例

在此示例中, Android.bp模块定义定义了一个名为libexample的库。 vendor_available属性表示框架模块和供应商模块可能依赖于libexample

libexample vendor_available:true 和 vndk.enabled:true

图 1.启用 VNDK 支持

框架可执行文件/system/bin/foo和供应商可执行文件/vendor/bin/bar都依赖于libexample ,并在其shared_libs属性中包含libexample

如果框架模块和供应商模块都使用libexample ,则会构建libexample的两个变体。核心变体(以libexample命名)由框架模块使用,供应商变体(以libexample.vendor命名)由供应商模块使用。这两个变体安装到不同的目录中:

  • 核心变体安装在/system/lib[64]/libexample.so中。
  • 供应商变体安装到 VNDK APEX 中,因为vndk.enabledtrue

有关更多详细信息,请参阅模块定义

配置构建支持

要为产品设备启用完整的构建系统支持,请将BOARD_VNDK_VERSION添加到BoardConfig.mk

BOARD_VNDK_VERSION := current

此设置具有全局效果:在BoardConfig.mk中定义时,会检查所有模块。由于没有将违规模块列入黑名单或白名单的机制,因此您应该在添加BOARD_VNDK_VERSION之前清除所有不必要的依赖项。您可以通过在环境变量中设置BOARD_VNDK_VERSION来测试和编译模块:

$ BOARD_VNDK_VERSION=current m module_name.vendor

启用BOARD_VNDK_VERSION时,会删除几个默认的全局标头搜索路径。这些包括:

  • 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

如果一个模块依赖于这些目录中的头文件,您必须(明确地)使用header_libsstatic_libs和/或shared_libs指定依赖关系。

VNDK 顶点

在 Android 10 及更低版本中,启用了vndk.enabled的模块安装在/system/lib[64]/vndk[-sp]-${VER}中。在 Android 11 及更高版本中,VNDK 库以 APEX 格式打包,VNDK APEX 的名称为com.android.vndk.v${VER} 。根据设备配置, VNDK APEX 是扁平化或非扁平化的,可从规范路径/apex/com.android.vndk.v${VER}

VNDK 顶点

图 2. VNDK APEX

模块定义

要使用BOARD_VNDK_VERSION构建 Android,您必须修改Android.mkAndroid.bp中的模块定义。本节介绍不同类型的模块定义、几个与 VNDK 相关的模块属性,以及在构建系统中实现的依赖项检查。

供应商模块

供应商模块是供应商特定的可执行文件或共享库,必须安装到供应商分区中。在Android.bp文件中,供应商模块必须将供应商或专有属性设置为true 。在Android.mk文件中,供应商模块必须将LOCAL_VENDOR_MODULELOCAL_PROPRIETARY_MODULE设置为true

如果定义了BOARD_VNDK_VERSION ,则构建系统不允许供应商模块和框架模块之间的依赖关系,并在以下情况下发出错误:

  • 没有vendor:true的模块依赖于带有vendor:true的模块,或者
  • 具有vendor:true的模块依赖于既没有vendor:true也没有vendor_available:true的非llndk_library模块。

依赖项检查适用于Android.mk中的header_libsstatic_libsshared_libs ,以及Android.bp中的LOCAL_HEADER_LIBRARIESLOCAL_STATIC_LIBRARIESLOCAL_SHARED_LIBRARIES

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; # llndk
    android_unload_sphal_library; # llndk
  local:
    *;
};

基于符号文件,构建系统为供应商模块生成一个存根共享库,当BOARD_VNDK_VERSION启用时,这些库与这些库链接。仅当满足以下条件时,符号才会包含在存根共享库中:

  • 未在以_PRIVATE_PLATFORM结尾的部分中定义,
  • 没有#platform-only标签,并且
  • 没有#introduce*标签或标签与目标匹配。

越南盾

Android.bp文件中, cc_librarycc_library_staticcc_library_sharedcc_library_headers模块定义支持三个与 VNDK 相关的属性: vendor_availablevndk.enabledvndk.support_system_process

如果vendor_availablevndk.enabledtrue ,则可能会构建两个变体( corevendor )。核心变体应视为框架模块,供应商变体应视为供应商模块。如果某些框架模块依赖于该模块,则构建核心变体。如果某些供应商模块依赖于此模块,则会构建供应商变体。构建系统强制执行以下依赖项检查:

  • 核心变体始终是仅限框架的,供应商模块无法访问。
  • 供应商变体始终无法访问框架模块。
  • header_libsstatic_libs和/或shared_libs中指定的供应商变体的所有依赖项必须是llndk_library或具有vendor_availablevndk.enabled的模块。
  • 如果vendor_availabletrue ,则所有供应商模块都可以访问供应商变体。
  • 如果vendor_availablefalse ,则只能由其他 VNDK 或 VNDK-SP 模块访问 vendor 变体(即,带有vendor:true的模块无法链接vendor_available:false模块)。

cc_librarycc_library_shared的默认安装路径由以下规则确定:

  • 核心变体安装到/system/lib[64]
  • 供应商变体安装路径可能会有所不同:
    • 如果vndk.enabledfalse ,则供应商变体安装到/vendor/lib[64]中。
    • 如果vndk.enabledtrue ,供应商变体将安装到 VNDK APEX( com.android.vndk.v${VER} ) 中。

下表总结了构建系统如何处理供应商变体:

vendor_available vndk
启用
vndk
support_same_process
供应商变体描述
true false false供应商变体是VND-ONLY 。共享库安装在/vendor/lib[64]中。
true无效(构建错误)
true false供应商变体是VNDK 。共享库安装到 VNDK APEX。
true供应商变体是VNDK-SP 。共享库安装到 VNDK APEX。

false

false

false

没有供应商变体。这个模块是FWK-ONLY 的

true无效(构建错误)
true false供应商变体是VNDK-Private 。共享库安装到 VNDK APEX。供应商模块不得直接使用这些。
true供应商变体是VNDK-SP-Private 。共享库安装到 VNDK APEX。供应商模块不得直接使用这些。

VNDK 扩展

VNDK 扩展是带有附加 API 的 VNDK 共享库。扩展安装到/vendor/lib[64]/vndk[-sp] (没有版本后缀)并在运行时覆盖原始 VNDK 共享库。

定义 VNDK 扩展

在 Android 9 及更高版本中, Android.bp原生支持 VNDK 扩展。要构建 VNDK 扩展,请使用vendor:trueextends属性定义另一个模块:

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:trueextends属性的模块定义了 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:truevendor_available:true

VNDK-SP 扩展必须从 VNDK-SP 共享库扩展( vndk.support_system_process必须相等):

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,
    },
}

VNDK 扩展(或 VNDK-SP 扩展)可能依赖于其他供应商共享库:

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

cc_library {
    name: "libvndk_ext",
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libvndk",
    },
    shared_libs: [
        "libvendor",
    ],
}

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

使用 VNDK 扩展

如果供应商模块依赖于 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)

条件编译

本节介绍如何处理以下三个 VNDK 共享库之间的细微差异(例如,从其中一个变体中添加或删除功能):

  • 核心变体(例如/system/lib[64]/libexample.so
  • 供应商变体(例如/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
  • VNDK 扩展(例如/vendor/lib[64]/vndk[-sp]/libexample.so

条件编译器标志

默认情况下,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中指定不同的cflagscppflagstarget.vendor中指定的cflagscppflags特定于供应商变体。

例如,以下Android.bp定义了libexamplelibexample_ext

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",
    ],
}

这是src/example.c的代码清单:

void all() { }

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

#if defined(LIBEXAMPLE_ENABLE_VNDK)
void vndk() { }
#endif

#if defined(LIBEXAMPLE_ENABLE_VNDK_EXT)
void vndk_ext() { }
#endif

根据这两个文件,构建系统生成具有以下导出符号的共享库:

安装路径导出的符号
/system/lib[64]/libexample.so allframework_only
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so allvndk
/vendor/lib[64]/vndk/libexample.so allvndkvndk_ext

对导出符号的要求

VNDK ABI 检查器VNDK 供应商变体VNDK 扩展的 ABI 与prebuilts/abi-dumps/vndk下的参考 ABI 转储进行比较。

  • VNDK 供应商变体(例如/apex/com.android.vndk.v${VER}/lib[64]/libexample.so )导出的符号必须与 ABI 转储中定义的符号相同(而不是其超集)。
  • VNDK 扩展导出的符号(例如/vendor/lib[64]/vndk/libexample.so )必须是 ABI 转储中定义的符号的超集。

如果VNDK 供应商变体VNDK 扩展未能遵循上述要求,VNDK ABI 检查器会发出构建错误并停止构建。

从供应商变体中排除源文件或共享库

要从供应商变体中排除源文件,请将它们添加到exclude_srcs属性。同样,要确保共享库不与供应商变体链接,请将这些库添加到exclude_shared_libs属性。例如:

cc_library {
    name: "libexample_cond_exclude",
    srcs: ["fwk.c", "both.c"],
    shared_libs: ["libfwk_only", "libboth"],
    vendor_available: true,
    target: {
        vendor: {
            exclude_srcs: ["fwk.c"],
            exclude_shared_libs: ["libfwk_only"],
        },
    },
}

在此示例中, libexample_cond_exclude的核心变体包括来自fwk.cboth.c的代码,并且依赖于共享库libfwk_onlylibbothlibexample_cond_exclude的供应商变体仅包含来自both.c的代码,因为fwk.cexclude_srcs属性排除。同样,它仅依赖于共享库libboth ,因为libfwk_onlyexclude_shared_libs属性排除。

从 VNDK 扩展导出标头

VNDK 扩展可以向 VNDK 共享库添加新类或新函数。建议将这些声明保留在独立的标头中,并避免更改现有标头。

例如,为 VNDK 扩展libexample_ext创建了一个新的头文件include-ext/example/ext/feature_name.h

  • 安卓.bp
  • 包含-ext/example/ext/feature_name.h
  • 包括/example/example.h
  • src/example.c
  • src/ext/feature_name.c

在以下Android.bp中, libexample仅导出include ,而libexample_ext导出includeinclude-ext 。这确保了libexample的用户不会错误地包含feature_name.h

cc_library {
    name: "libexample",
    srcs: ["src/example.c"],
    export_include_dirs: ["include"],
    vendor_available: true,
    vndk: {
        enabled: true,
    },
}

cc_library {
    name: "libexample_ext",
    srcs: [
        "src/example.c",
        "src/ext/feature_name.c",
    ],
    export_include_dirs: [
        "include",
        "include-ext",
    ],
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libexample",
    },
}

如果分离独立头文件的扩展是不可行的,另一种方法是添加#ifdef保护。但是,请确保所有 VNDK 扩展用户都添加定义标志。您可以定义cc_defaults以将定义标志添加到cflags并将共享库与shared_libs链接。

例如,要将新成员函数Example2::get_b()添加到 VNDK 扩展libexample2_ext ,您必须修改现有头文件并添加#ifdef保护:

#ifndef LIBEXAMPLE2_EXAMPLE_H_
#define LIBEXAMPLE2_EXAMPLE_H_

class Example2 {
 public:
  Example2();

  void get_a();

#ifdef LIBEXAMPLE2_ENABLE_VNDK_EXT
  void get_b();
#endif

 private:
  void *impl_;
};

#endif  // LIBEXAMPLE2_EXAMPLE_H_

cc_defaults的用户定义了一个名为libexample2_ext_defaultslibexample2_ext

cc_library {
    name: "libexample2",
    srcs: ["src/example2.cpp"],
    export_include_dirs: ["include"],
    vendor_available: true,
    vndk: {
        enabled: true,
    },
}

cc_library {
    name: "libexample2_ext",
    srcs: ["src/example2.cpp"],
    export_include_dirs: ["include"],
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libexample2",
    },
    cflags: [
        "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1",
    ],
}

cc_defaults {
    name: "libexample2_ext_defaults",
    shared_libs: [
        "libexample2_ext",
    ],
    cflags: [
        "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1",
    ],
}

libexample2_ext的用户可以简单地将libexample2_ext_defaults包含在他们的defaults属性中:

cc_binary {
    name: "example2_user_executable",
    defaults: ["libexample2_ext_defaults"],
    vendor: true,
}

产品包

在 Android 构建系统中,变量PRODUCT_PACKAGES指定应安装到设备中的可执行文件、共享库或包。指定模块的传递依赖关系也隐式安装到设备中。

如果启用了BOARD_VNDK_VERSION ,则带有vendor_availablevndk.enabled的模块会得到特殊处理。如果框架模块依赖于具有vendor_availablevndk.enabled的模块,则核心变体包含在传递安装集中。如果供应商模块依赖于具有vendor_available的模块,则供应商变体包含在传递安装集中。但是,无论供应商模块是否使用它们,都会安装带有vndk.enabled的模块的供应商变体。

当依赖项对构建系统不可见时(例如,可以在运行时使用dlopen()打开的共享库),您应该在PRODUCT_PACKAGES中指定模块名称以显式安装这些模块。

如果模块具有vendor_availablevndk.enabled ,则模块名称代表其核心变体。要在PRODUCT_PACKAGES中明确指定供应商变体,请将.vendor后缀附加到模块名称。例如:

cc_library {
    name: "libexample",
    srcs: ["example.c"],
    vendor_available: true,
}

在此示例中, libexample代表/system/lib[64]/libexample.solibexample.vendor代表/vendor/lib[64]/libexample.so 。要安装/vendor/lib[64]/libexample.so ,请将libexample.vendor添加到PRODUCT_PACKAGES

PRODUCT_PACKAGES += libexample.vendor