Google is committed to advancing racial equity for Black communities. See how.

Linker Namespace

The dynamic linker tackles two challenges in Treble VNDK design:

  • SP-HAL shared libraries and their dependencies, including VNDK-SP libraries, are loaded into framework processes. There should be some mechanisms to prevent symbol conflicts.
  • dlopen() and android_dlopen_ext() can introduce some runtime dependencies that aren't visible at build time and can be difficult to detect using static analysis.

These two challenges can be resolved by the linker namespace mechanism. This mechanism is provided by the dynamic linker. It can isolate the shared libraries in different linker namespaces so that libraries with same library name but with different symbols won't conflict.

On the other hand, the linker namespace mechanism provides the flexibility so that some shared libraries can be exported by a linker namespace and used by another linker namespace. These exported shared libraries can become application programming interfaces that are public to other programs while hiding their implementation details within their linker namespaces.

For example, /system/lib[64]/libcutils.so and /system/lib[64]/vndk-sp-${VER}/libcutils.so are two shared libraries. These two libraries can have different symbols. They're loaded into different linker namespaces so that framework modules can depend on /system/lib[64]/libcutils.so and SP-HAL shared libraries can depend on /system/lib[64]/vndk-sp-${VER}/libcutils.so.

On the other hand, /system/lib[64]/libc.so is an example of a public library that's exported by a linker namespace and imported into many linker namespaces. The dependencies of /system/lib[64]/libc.so, such as libnetd_client.so, are loaded into the namespace in which /system/lib[64]/libc.so resides. Other namespaces won't have accesses to those dependencies. This mechanism encapsulates the implementation details while providing the public interfaces.

How does it work?

The dynamic linker is responsible for loading the shared libraries specified in DT_NEEDED entries or the shared libraries specified by the argument of dlopen() or android_dlopen_ext(). In both cases, the dynamic linker finds the linker namespace where the caller resides and tries to load the dependencies into the same linker namespace. If the dynamic linker can't load the shared library into the specified linker namespace, it asks the linked linker namespace for exported shared libraries.

Configuration file format

The configuration file format is based on the INI file format. A typical configuration file looks like this:

dir.system = /system/bin
dir.system = /system/xbin
dir.vendor = /vendor/bin

[system]
additional.namespaces = sphal,vndk

namespace.default.isolated = true
namespace.default.search.paths = /system/${LIB}
namespace.default.permitted.paths = /system/${LIB}/hw
namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}
namespace.default.asan.permitted.paths = /data/asan/system/${LIB}/hw:/system/${LIB}/hw

namespace.sphal.isolated = true
namespace.sphal.visible = true
namespace.sphal.search.paths = /odm/${LIB}:/vendor/${LIB}
namespace.sphal.permitted.paths = /odm/${LIB}:/vendor/${LIB}
namespace.sphal.asan.search.paths  = /data/asan/odm/${LIB}:/odm/${LIB}
namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}:/vendor/${LIB}
namespace.sphal.asan.permitted.paths  = /data/asan/odm/${LIB}:/odm/${LIB}
namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}:/vendor/${LIB}
namespace.sphal.links = default,vndk
namespace.sphal.link.default.shared_libs = libc.so:libm.so
namespace.sphal.link.vndk.shared_libs = libbase.so:libcutils.so

namespace.vndk.isolated = true
namespace.vndk.search.paths = /system/${LIB}/vndk-sp-29
namespace.vndk.permitted.paths = /system/${LIB}/vndk-sp-29
namespace.vndk.links = default
namespace.vndk.link.default.shared_libs = libc.so:libm.so

[vendor]
namespace.default.isolated = false
namespace.default.search.paths = /vendor/${LIB}:/system/${LIB}

The configuration file includes:

  • Several directory-section mapping properties at the beginning for the dynamic linker to select the effective section.
  • Several linker namespaces configuration sections:
    • Each section contains several namespaces (graph vertexes) and several fallback links between namespaces (graph arcs).
    • Each namespace has its own isolation, search paths, permitted paths, and visibility settings.

The tables below describe the meaning of each property in detail.

Directory-section mapping property

Property Description Example

dir.name

A path to a directory that the [name] section applies to.

Each property maps the executables under the directory to a linker namespaces configuration section. There might be two (or more) properties that have the same name but point to different directories.

dir.system = /system/bin
dir.system = /system/xbin
dir.vendor = /vendor/bin

This indicates that the configuration specified in the [system] section applies to the executables that are loaded from either /system/bin or /system/xbin.

The configuration specified in the [vendor] section applies to the executables that are loaded from /vendor/bin.

Relation properties

Property Description Example
additional.namespaces

A comma-separated list of additional namespaces (in addition to the default namespace) for the section.

additional.namespaces = sphal,vndk

This indicates that there are three namespaces (default, sphal, and vndk) in the [system] configuration.

namespace.name.links

A comma-separated list of fallback namespaces.

If a shared library can't be found in the current namespace, the dynamic linker tries to load the shared library from the fallback namespaces. The namespace specified at the beginning of the list has higher priority.

namespace.sphal.links = default,vndk

If a shared library or an executable requests a shared library that can't be loaded into the sphal namespace, the dynamic linker tries to load the shared library from the default namespace.

And then, if the shared library can't be loaded from the default namespace either, the dynamic linker tries to load the shared library from the vndk namespace.

Finally, if all attempts fail, the dynamic linker returns an error.

namespace.name.link.other.shared_libs

A colon-separated list of shared libraries that can be searched in the other namespaces when those libraries can't be found in the name namespace.

This property can't be used with namespace.name.link.other.allow_all_shared_libs.

namespace.sphal.link.default.shared_libs = libc.so:libm.so

This indicates that the fallback link accepts only libc.so or libm.so as the requested library name. The dynamic linker ignores the fallback link from sphal to default namespace if the requested library name isn't libc.so or libm.so.

namespace.name.link.other.allow_all_shared_libs

A boolean value that indicates whether all shared libraries can be searched in the other namespace when those libraries can't be found in the name namespace.

This property can't be used with namespace.name.link.other.shared_libs.

namespace.vndk.link.sphal.allow_all_shared_libs = true

This indicates that all library names can walk through the fallback link from vndk to sphal namespace.

Namespace properties

Property Description Example
namespace.name.isolated

A boolean value that indicates whether the dynamic linker should check where the shared library resides.

If isolated is true, only the shared libraries that are in one of the search.paths directories (excluding subdirectories) or are under one of the permitted.paths directories (including subdirectories) can be loaded.

If isolated is false (default), the dynamic linker doesn't check the path of shared libraries.

namespace.sphal.isolated = true

This indicates that only the shared libraries in search.paths or under permitted.paths can be loaded into the sphal namespace.

namespace.name.search.paths

A colon-separated list of directories to search for shared libraries.

The directories specified in search.paths are prepended to the requested library name if function calls to dlopen() or DT_NEEDED entries don't specify the full path. The directory specified at the beginning of the list has higher priority.

When isolated is true, shared libraries that are in one of the search.paths directories (excluding subdirectories) can be loaded regardless of the permitted.paths property.

For example, if search.paths is /system/${LIB} and permitted.paths is empty, /system/${LIB}/libc.so can be loaded but /system/${LIB}/vndk/libutils.so can't be loaded.

namespace.default.search.paths = /system/${LIB}

This indicates that the dynamic linker searches /system/${LIB} for shared libraries.

namespace.name.asan.search.paths

A colon-separated list of directories to search for shared libraries when AddressSanitizer (ASan) is enabled.

namespace.name.search.paths is ignored when ASan is enabled.

namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}

This indicates that when ASan is enabled the dynamic linker searches /data/asan/system/${LIB} first and then searches /system/${LIB}.

namespace.name.permitted.paths

A colon-separated list of directories (including subdirectories) where the dynamic linker can load the shared libraries (in addition to search.paths) when isolated is true.

The shared libraries that are under the subdirectories of permitted.paths can also be loaded. For example, if permitted.paths is /system/${LIB}, both /system/${LIB}/libc.so and /system/${LIB}/vndk/libutils.so can be loaded.

If isolated is false, permitted.paths are ignored and a warning is emitted.

namespace.default.permitted.paths = /system/${LIB}/hw

This indicates that the shared libraries under /system/${LIB}/hw can be loaded into the isolated default namespace.

For example, without permitted.paths, libaudiohal.so can't load /system/${LIB}/hw/audio.a2dp.default.so into the default namespace.

namespace.name.asan.permitted.paths

A colon-separated list of directories where the dynamic linker can load the shared libraries when ASan is enabled.

namespace.name.permitted.paths is ignored when ASan is enabled.

namespace.default.asan.permitted.paths = /data/asan/system/${LIB}/hw:/system/${LIB}/hw

This indicates that when ASan is enabled shared libraries under /data/asan/system/${LIB}/hw or /system/${LIB}/hw can be loaded to the isolated default namespace.

namespace.name.visible

A boolean value that indicates whether the program (other than libc) can obtain a linker namespace handle with android_get_exported_namespace() and open a shared library in the linker namespace by passing the handle to android_dlopen_ext().

If visible is true, android_get_exported_namespace() always returns the handle if the namespace exists.

If visible is false (default), android_get_exported_namespace() always returns NULL regardless of the presence of the namespace. Shared libraries can be loaded into this namespace only if (1) they're requested by another linker namespace that has a fallback link to this namespace, or (2) they're requested by other shared libraries or executables in this namespace.

namespace.sphal.visible = true

This indicates that android_get_exported_namespace("sphal") can return a valid linker namespace handle.

Linker namespace creation

In Android 11, linker configuration is created at runtime under /linkerconfig instead of using plain text files in ${android-src}/system/core/rootdir/etc. The configuration is generated at boot time based on the runtime environment, which includes following items:

  • If device supports VNDK
  • Vendor partition's target VNDK version
  • Product partition's VNDK version
  • Installed APEX modules

Linker configuration is created by resolving dependencies between linker namespaces. For example, if there are any updates on the APEX modules that include dependency updates, linker configuration is generated reflecting these changes. More details to create linker configuration can be found in ${android-src}/system/linkerconfig.

Linker namespace isolation

There are three configuration types. Depending on the value of PRODUCT_TREBLE_LINKER_NAMESPACES and BOARD_VNDK_VERSION in BoardConfig.mk, the corresponding configuration is generated at boot time.

PRODUCT_TREBLE_
LINKER_NAMESPACES
BOARD_VNDK_
VERSION
Selected configuration VTS requirement
true current VNDK Mandatory for devices launched with Android 9 or higher
Empty VNDK Lite Mandatory for devices launched with Android 8.x
false Empty Legacy For non-Treble devices

VNDK Lite configuration isolates SP-HAL and VNDK-SP shared libraries. In Android 8.0, this must be the configuration file for dynamic linker when PRODUCT_TREBLE_LINKER_NAMESPACES is true.

VNDK configuration also isolates SP-HAL and VNDK-SP shared libraries. In addition, this configuration provides the full dynamic linker isolation. It makes sure that modules in the system partition won't depend on the shared libraries in the vendor partitions and vice versa.

In Android 8.1 or higher, VNDK configuration is the default configuration and it's highly recommended to enable full dynamic linker isolation by setting BOARD_VNDK_VERSION to current.

VNDK configuration

VNDK configuration isolates the shared library dependencies between the system partition and vendor partitions. Compared to configurations mentioned in previous subsection, the differences are outlined as follows:

  • Framework processes

    • default, vndk, sphal, and rs namespaces are created.
    • All namespaces are isolated.
    • System shared libraries are loaded into the default namespace.
    • SP-HALs are loaded into the sphal namespace.
    • VNDK-SP shared libraries loaded into the vndk namespace.
  • Vendor processes

    • default, vndk, and system namespaces are created.
    • The default namespace is isolated.
    • Vendor shared libraries are loaded into the default namespace.
    • VNDK and VNDK-SP shared libraries are loaded into the vndk namespace.
    • LL-NDK and its dependencies are loaded into the system namespace.

The relationship between the linker namespaces is illustrated below.

Linker namespace graph described in VNDK configuration
Figure 1. Linker namespace isolation (VNDK configuration)

In the image above, LL-NDK and VNDK-SP stand for following shared libraries:

  • LL-NDK
    • libEGL.so
    • libGLESv1_CM.so
    • libGLESv2.so
    • libGLESv3.so
    • libandroid_net.so
    • libc.so
    • libdl.so
    • liblog.so
    • libm.so
    • libnativewindow.so
    • libneuralnetworks.so
    • libsync.so
    • libvndksupport.so
    • libvulkan.so
  • VNDK-SP
    • android.hardware.graphics.common@1.0.so
    • android.hardware.graphics.mapper@2.0.so
    • android.hardware.renderscript@1.0.so
    • android.hidl.memory@1.0.so
    • libRSCpuRef.so
    • libRSDriver.so
    • libRS_internal.so
    • libbase.so
    • libbcinfo.so
    • libc++.so
    • libcutils.so
    • libhardware.so
    • libhidlbase.so
    • libhidlmemory.so
    • libhidltransport.so
    • libhwbinder.so
    • libion.so
    • libutils.so
    • libz.so

You can find more details in /linkerconfig/ld.config.txt from the device.

VNDK Lite configuration

As of Android 8.0, the dynamic linker is configured to isolate the SP-HAL and VNDK-SP shared libraries such that their symbols don't conflict with other framework shared libraries. The relationship between the linker namespaces is shown below.

Linker namespace graph described in VNDK Lite configuration
Figure 2. Linker namespace isolation (VNDK Lite configuration)

LL-NDK and VNDK-SP stand for following shared libraries:

  • LL-NDK
    • libEGL.so
    • libGLESv1_CM.so
    • libGLESv2.so
    • libc.so
    • libdl.so
    • liblog.so
    • libm.so
    • libnativewindow.so
    • libstdc++.so (not in the configuration)
    • libsync.so
    • libvndksupport.so
    • libz.so (moved to VNDK-SP in the configuration)
  • VNDK-SP
    • android.hardware.graphics.common@1.0.so
    • android.hardware.graphics.mapper@2.0.so
    • android.hardware.renderscript@1.0.so
    • android.hidl.memory@1.0.so
    • libbase.so
    • libc++.so
    • libcutils.so
    • libhardware.so
    • libhidlbase.so
    • libhidlmemory.so
    • libhidltransport.so
    • libhwbinder.so
    • libion.so
    • libutils.so

The table below lists the namespaces configuration for framework processes, which is excerpted from the [system] section in the VNDK Lite configuration.

Namespace Property Value
default search.paths /system/${LIB}
/odm/${LIB}
/vendor/${LIB}
/product/${LIB}
isolated false
sphal search.paths /odm/${LIB}
/vendor/${LIB}
permitted.paths /odm/${LIB}
/vendor/${LIB}
isolated true
visible true
links default,vndk,rs
link.default.shared_libs LL-NDK
link.vndk.shared_libs VNDK-SP
link.rs.shared_libs libRS_internal.so
vndk (for VNDK-SP) search.paths /odm/${LIB}/vndk-sp
/vendor/${LIB}/vndk-sp
/system/${LIB}/vndk-sp-${VER}
permitted.paths /odm/${LIB}/hw
/odm/${LIB}/egl
/vendor/${LIB}/hw
/vendor/${LIB}/egl
/system/${LIB}/vndk-sp-${VER}/hw
isolated true
visible true
links default
link.default.shared_libs LL-NDK
rs (for RenderScript) search.paths /odm/${LIB}/vndk-sp
/vendor/${LIB}/vndk-sp
/system/${LIB}/vndk-sp-${VER}
/odm/${LIB}
/vendor/${LIB}
permitted.paths /odm/${LIB}
/vendor/${LIB}
/data (for compiled RS kernel)
isolated true
visible true
links default,vndk
link.default.shared_libs LL-NDK
libmediandk.so
libft2.so
link.vndk.shared_libs VNDK-SP

The table below presents the namespaces configuration for vendor processes, which is excerpted from the [vendor] section in the VNDK Lite configuration.

Namespace Property Value
default search.paths /odm/${LIB}
/odm/${LIB}/vndk
/odm/${LIB}/vndk-sp
/vendor/${LIB}
/vendor/${LIB}/vndk
/vendor/${LIB}/vndk-sp
/system/${LIB}/vndk-${VER}
/system/${LIB}/vndk-sp-${VER}
/system/${LIB} (deprecated)
/product/${LIB} (deprecated)
isolated false

More details can be found in /linkerconfig/ld.config.txt from the device.

Document history

Android 11 Changes

  • In Android 11, the static ld.config.*.txt files are removed from the codebase and LinkerConfig generates them in runtime instead.

Android 9 changes

  • In Android 9, the vndk linker namespace is added to vendor processes and VNDK shared libraries are isolated from the default linker namespace.
  • Replace PRODUCT_FULL_TREBLE with more specific PRODUCT_TREBLE_LINKER_NAMESPACES.
  • Android 9 changes the names of the following dynamic linker configuration files.
    Android 8.x Android 9 Description
    ld.config.txt.in ld.config.txt For devices with runtime linker namespace isolation
    ld.config.txt ld.config.vndk_lite.txt For devices with VNDK-SP linker namespace isolation
    ld.config.legacy.txt ld.config.legacy.txt For legacy devices running Android 7.x or lower
  • Remove android.hardware.graphics.allocator@2.0.so.
  • product and odm partitions are added.