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.enabledistrue.
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:truedepends on a module withvendor:true, or
- a module with vendor:truedepends on a non-llndk_librarymodule that has neithervendor:truenorvendor_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 _PRIVATEor_PLATFORM,
- Does not have #platform-onlytag, 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_libraryor a module withvendor_availableorvndk.enabled.
- If vendor_availableistrue, the vendor variant is accessible to all vendor modules.
- If vendor_availableisfalse, the vendor variant is accessible only to other VNDK or VNDK-SP modules (i.e., modules withvendor:truecannot linkvendor_available:falsemodules).
  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.enabledisfalse, the vendor variant is installed into/vendor/lib[64].
- If vndk.enabledistrue, 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_system_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 extendsproperty 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_extislibvndk.soinstead 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:trueandvendor_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() { }
#endifAccording 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
