In Android 8.1 and higher, the build system has built-in VNDK support. When VNDK support is enabled, the build system checks the dependencies between modules, builds a vendor-specific variant for vendor modules, and automatically installs those modules into designated directories.
VNDK build support example
In this example, the Android.bp
module definition defines a
library named libexample
. The vendor_available
property indicates framework modules and vendor modules may depend on
libexample
:
Figure 1. support enabled.
Both the framework executable /system/bin/foo
and the vendor
executable /vendor/bin/bar
depend on libexample
and
have libexample
in their shared_libs
properties.
If libexample
is used by both framework modules and vendor
modules, two variants of libexample
are built. The core variant
(named after libexample
) is used by framework modules and the
vendor variant (named after libexample.vendor
) is used by vendor
modules. The two variants are installed into different directories:
- The core variant is installed into
/system/lib[64]/libexample.so
. - The vendor variant is installed into VNDK APEX because
vndk.enabled
istrue
.
For more details, see Module definition.
Configure build support
To enable full build system support for a product device, add
BOARD_VNDK_VERSION
to BoardConfig.mk
:
BOARD_VNDK_VERSION := current
This setting has a global effect: When defined in
BoardConfig.mk
, all modules are checked. As there is no mechanism
to blacklist or whitelist an offending module, you should clean all
unnecessary dependencies before adding BOARD_VNDK_VERSION
. You
can test and compile a module by setting BOARD_VNDK_VERSION
in
your environment variables:
$ BOARD_VNDK_VERSION=current m module_name.vendor
When BOARD_VNDK_VERSION
is enabled, several default global
header search paths are removed. These include:
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
If a module depends on the headers from these directories, you must specify
(explicitly) the dependencies with header_libs
,
static_libs
, and/or shared_libs
.
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}
.
Figure 2. VNDK APEX.
Module definition
To build Android with BOARD_VNDK_VERSION
, you must revise the
module definition in either Android.mk
or
Android.bp
. This section describes different kinds of module
definitions, several VNDK-related module properties, and dependency checks
implemented in the build system.
Vendor modules
Vendor modules are vendor-specific executables or shared libraries that
must be installed into a vendor partition. In Android.bp
files,
vendor modules must set vendor or proprietary property to true
.
In Android.mk
files, vendor modules must set
LOCAL_VENDOR_MODULE
or LOCAL_PROPRIETARY_MODULE
to
true
.
If BOARD_VNDK_VERSION
is defined, the build system disallows
dependencies between vendor modules and framework modules and emits errors if:
- a module without
vendor:true
depends on a module withvendor:true
, or - a module with
vendor:true
depends on a non-llndk_library
module that has neithervendor:true
norvendor_available:true
.
The dependency check applies to header_libs
,
static_libs
, and shared_libs
in
Android.bp
, and to LOCAL_HEADER_LIBRARIES
,
LOCAL_STATIC_LIBRARIES
and LOCAL_SHARED_LIBRARIES
in
Android.mk
.
LL-NDK
LL-NDK shared libraries are shared libraries with stable ABIs. Both framework
and vendor modules share the same and the latest implementation. For each
LL-NDK shared library, the cc_library
contains a
llndk
property with a symbol file:
cc_library { name: "libvndksupport", llndk: { symbol_file: "libvndksupport.map.txt", }, }
The symbol file describes the symbols visible to vendor modules. For example:
LIBVNDKSUPPORT { global: android_load_sphal_library; # llndk android_unload_sphal_library; # llndk local: *; };
Based on the symbol file, the build system generates a stub shared library for
vendor modules, which link with these libraries when
BOARD_VNDK_VERSION
is enabled. A symbol is included in the stub
shared library only if it:
- Is not defined in the section end with
_PRIVATE
or_PLATFORM
, - Does not have
#platform-only
tag, and - Does not have
#introduce*
tags or the tag matches with the target.
VNDK
In Android.bp
files, cc_library
,
cc_library_static
, cc_library_shared
, and
cc_library_headers
module definitions support three VNDK-related
properties: vendor_available
, vndk.enabled
, and
vndk.support_system_process
.
If vendor_available
or vndk.enabled
is
true
, two variants (core and vendor) may be
built. The core variant should be treated as a framework module and the vendor
variant should be treated as a vendor module. 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. The build system enforces
the following dependency checks:
- The core variant is always framework-only and inaccessible to vendor modules.
- The vendor variant is always inaccessible to framework modules.
- All dependencies of the vendor variant, which are specified in
header_libs
,static_libs
, and/orshared_libs
, must be either anllndk_library
or a module withvendor_available
orvndk.enabled
. - If
vendor_available
istrue
, the vendor variant is accessible to all vendor modules. - If
vendor_available
isfalse
, the vendor variant is accessible only to other VNDK or VNDK-SP modules (i.e., modules withvendor:true
cannot linkvendor_available:false
modules).
The default installation path for cc_library
or
cc_library_shared
is determined by the following rules:
- The core variant is installed to
/system/lib[64]
. - The vendor variant installation path may vary:
- If
vndk.enabled
isfalse
, the vendor variant is installed into/vendor/lib[64]
. - If
vndk.enabled
istrue
, the vendor variant is installed into VNDK APEX(com.android.vndk.v${VER}
).
- If
The table below summarizes how the build system handles the vendor variants:
vendor_available | vndk enabled |
vndk support_same_process |
Vendor variant descriptions |
---|---|---|---|
true |
false |
false |
The vendor variants are VND-ONLY. Shared libraries are
installed into /vendor/lib[64] . |
true |
Invalid (Build error) | ||
true |
false |
The vendor variants are VNDK. Shared libraries are installed to VNDK APEX. | |
true |
The vendor variants are VNDK-SP. Shared libraries are installed to VNDK APEX. | ||
|
|
|
No vendor variants. This module is FWK-ONLY. |
true |
Invalid (Build error) | ||
true |
false |
The vendor variants are VNDK-Private. Shared libraries are installed to VNDK APEX. These must not be directly used by vendor modules. | |
true |
The vendor variants are VNDK-SP-Private. Shared libraries are installed to VNDK APEX. These must not be directly used by vendor modules. |
VNDK extensions
VNDK extensions are VNDK shared libraries with additional APIs. Extensions are
installed to /vendor/lib[64]/vndk[-sp]
(without version suffix)
and override the original VNDK shared libraries at runtime.
Define VNDK extensions
In Android 9 and higher, Android.bp
natively supports VNDK
extensions. To build a VNDK extension, define another module with a
vendor:true
and an extends
property:
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, }
A module with vendor:true
, vndk.enabled:true
, and
extends
properties defines the VNDK extension:
- The
extends
property must specify a base VNDK shared library name (or VNDK-SP shared library name). - VNDK extensions (or VNDK-SP extensions) are named after the base module
names from which they extend. For example, the output binary of
libvndk_ext
islibvndk.so
instead oflibvndk_ext.so
. - VNDK extensions are installed into
/vendor/lib[64]/vndk
. - VNDK-SP extensions are installed into
/vendor/lib[64]/vndk-sp
. - The base shared libraries must have both
vndk.enabled:true
andvendor_available:true
.
A VNDK-SP extension must extend from a VNDK-SP shared library
(vndk.support_system_process
must be equal):
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 extensions (or VNDK-SP extensions) may depend on other vendor shared libraries:
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, }
Use VNDK extensions
If a vendor module depends on additional APIs defined by VNDK extensions, the
module must specify the name of the VNDK extension in its
shared_libs
property:
// 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", ], }
If a vendor module depends on VNDK extensions, those VNDK extensions are
installed to /vendor/lib[64]/vndk[-sp]
automatically. If a module
no longer depends on a VNDK extension, add a clean step to
CleanSpec.mk
to remove the shared library. For example:
$(call add-clean-step, rm -rf $(TARGET_OUT_VENDOR)/lib/libvndk.so)
Conditional compilation
This section describes how to deal with the subtle differences (e.g. adding or removing a feature from one of the variants) between the following three VNDK shared libraries:
- Core variant (e.g.
/system/lib[64]/libexample.so
) - Vendor variant (e.g.
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) - VNDK extension (e.g.
/vendor/lib[64]/vndk[-sp]/libexample.so
)
Conditional compiler flags
The Android build system defines __ANDROID_VNDK__
for vendor
variants and VNDK extensions by default. You may guard the code
with the C preprocessor guards:
void all() { } #if !defined(__ANDROID_VNDK__) void framework_only() { } #endif #if defined(__ANDROID_VNDK__) void vndk_only() { } #endif
In addition to __ANDROID_VNDK__
, different cflags
or
cppflags
may be specified in Android.bp
. The
cflags
or cppflags
specified in
target.vendor
is specific to the vendor variant.
For example, the following Android.bp
defines
libexample
and libexample_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", ], }
And this is the code listing of 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
According to these two files, the build system generates shared libraries with following exported symbols:
Installation path | Exported symbols |
---|---|
/system/lib[64]/libexample.so |
all , framework_only |
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so |
all , vndk |
/vendor/lib[64]/vndk/libexample.so |
all , vndk , vndk_ext |
Requirements on the exported symbols
The VNDK ABI checker
compares the ABI of VNDK vendor variants and
VNDK extensions to the reference ABI dumps under
prebuilts/abi-dumps/vndk
.
- Symbols exported by VNDK vendor variants (e.g.
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) must be identical to (not the supersets of) the symbols defined in ABI dumps. - Symbols exported by VNDK extensions (e.g.
/vendor/lib[64]/vndk/libexample.so
) must be supersets of the symbols defined in ABI dumps.
If VNDK vendor variants or VNDK extensions fail to follow the requirements above, VNDK ABI checker emits build errors and stops the build.
Exclude source files or shared libraries from vendor variants
To exclude source files from the vendor variant, add them to the
exclude_srcs
property. Similarly, to ensure shared libraries are
not linked with the vendor variant, add those libraries to the
exclude_shared_libs
property. For example:
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"], }, }, }
In this example, the core variant of libexample_cond_exclude
includes the code from fwk.c
and both.c
and depends
on the shared libraries libfwk_only
and libboth
. The
vendor variant of libexample_cond_exclude
includes only the code
from both.c
because fwk.c
is excluded by the
exclude_srcs
property. Similarly, it depends on only the shared library
libboth
because libfwk_only
is excluded by the
exclude_shared_libs
property.
Export headers from VNDK extensions
A VNDK extension may add new classes or new functions to a VNDK shared library. It is suggested to keep those declarations in independent headers and avoid changing the existing headers.
For example, a new header file
include-ext/example/ext/feature_name.h
is created for the VNDK
extension libexample_ext
:
- Android.bp
- include-ext/example/ext/feature_name.h
- include/example/example.h
- src/example.c
- src/ext/feature_name.c
In the following Android.bp
, libexample
exports
only include
, whereas libexample_ext
exports both
include
and include-ext
. This ensures
feature_name.h
won't be incorrectly included by the users of
libexample
:
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", }, }
If separating extensions to independent header files is not feasible, an
alternative is to add #ifdef
guards. However, make sure that all
VNDK extension users add the define flags. You may define
cc_defaults
to add define flags to cflags
and link
shared libraries with shared_libs
.
For example, to add a new member function Example2::get_b()
to
the VNDK extension libexample2_ext
, you must modify the existing
header file and add a #ifdef
guard:
#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_
A cc_defaults
named libexample2_ext_defaults
is
defined for the users of libexample2_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", ], }
The users of libexample2_ext
may simply include
libexample2_ext_defaults
in their defaults
property:
cc_binary { name: "example2_user_executable", defaults: ["libexample2_ext_defaults"], vendor: true, }
Product packages
In the Android build system, the variable PRODUCT_PACKAGES
specifies the executables, shared libraries, or packages that should be
installed into the device. The transitive dependencies of the specified
modules are implicitly installed into the device as well.
If BOARD_VNDK_VERSION
is enabled, modules with
vendor_available
or vndk.enabled
get special
treatment. If a framework module depends on a module with
vendor_available
or vndk.enabled
, the core variant
is included in the transitive installation set. If a vendor module
depends on a module with vendor_available
, the vendor variant is
included in the transitive installation set. However, vendor variants of modules
with vndk.enabled
are installed whether or not they are used by vendor modules.
When the dependencies are invisible to the build system (e.g. shared libraries
that may be opened with dlopen()
in runtime), you should specify
the module names in PRODUCT_PACKAGES
to install those modules
explicitly.
If a module has vendor_available
or vndk.enabled
,
the module name stands for its core variant. To explicitly specify the
vendor variant in PRODUCT_PACKAGES
, append a .vendor
suffix to the module name. For example:
cc_library { name: "libexample", srcs: ["example.c"], vendor_available: true, }
In this example, libexample
stands for
/system/lib[64]/libexample.so
and libexample.vendor
stands for /vendor/lib[64]/libexample.so
. To install
/vendor/lib[64]/libexample.so
, add libexample.vendor
to PRODUCT_PACKAGES
:
PRODUCT_PACKAGES += libexample.vendor