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.
VNDK 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
is
true
.
For more details, see
Module definition
.
Configuring 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 with
vendor:true
, or
- a module with
vendor:true
depends on a
non-
llndk_library
module that has neither
vendor:true
nor
vendor_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/or
shared_libs
, must be either an
llndk_library
or a
module with
vendor_available
or
vndk.enabled
.
- If
vendor_available
is
true
, the vendor variant
is accessible to all vendor modules.
- If
vendor_available
is
false
, the vendor variant
is accessible only to other VNDK or VNDK-SP modules (i.e., modules with
vendor:true
cannot link
vendor_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
is
false
, the vendor variant
is installed into
/vendor/lib[64]
.
- If
vndk.enabled
is
true
, the vendor variant
is installed into VNDK APEX(
com.android.vndk.v${VER}
).
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.
|
false
|
false
|
false
|
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.
Defining 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
is
libvndk.so
instead of
libvndk_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
and
vendor_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,
}
Using 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.
Excluding 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.
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