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() may introduce some run-time dependencies that are not visible at build-time and can be difficult to detect using static analysis.

These two challenges can be resolved by the linker namespace mechanism. The linker namespace 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 may be exported by a linker namespace and used by another linker namespace. These exported shared libraries may become the 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 may have different symbols. They are 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 public libraries that is 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 try to load the dependencies into the same linker namespace. If the dynamic linker cannot 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:

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 vertices) 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 with 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 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 cannot 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 cannot 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 cannot 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 cannot be found in the name namespace.

This property cannot 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 only accepts 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 is not libc.so nor 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 cannot be found in the name namespace.

This property cannot be used with namespace.name.link.other.shared_libs.

namespace.vndk.link.sphal.allow_all_shared_libs = true

This indicates 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 sub-directories) or are under one of the permitted.paths directories (including sub-directories) 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 do not 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 sub-directories) can be loaded regardless 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 cannot 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 Address Sanitizer is enabled.

namespace.name.search.paths is ignored when Address Sanitizer is enabled.

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

This indicates that when Address Sanitizer 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 sub-directories) 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 sub-directories of permitted.paths can be loaded too. 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 won't be able to 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 Address Sanitizer is enabled.

namespace.name.permitted.paths is ignored when Address Sanitizer is enabled.

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

This indicates that when Address Sanitizer 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 the presence of the namespace. Shared libraries can only be loaded into this namespace if (1) they are requested by another linker namespace that has a fallback link to this namespace or (2) they are 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 isolation

There are three configuration files in ${android-src}/system/core/rootdir/etc. Depending on the value of PRODUCT_TREBLE_LINKER_NAMESPACES, BOARD_VNDK_VERSION, and BOARD_VNDK_RUNTIME_DISABLE in BoardConfig.mk, different configurations are selected:

PRODUCT_TREBLE_
LINKER_NAMESPACES
BOARD_VNDK_
VERSION
BOARD_VNDK_
RUNTIME_DISABLE
Selected configuration VTS Requirement
true current empty ld.config.txt Mandatory for devices launched with Android P.
true ld.config.vndk_lite.txt Mandatory for devices launched with Android 8.x.
empty any
false any any ld.config.legacy.txt For non-Treble devices

${android-src}/system/core/rootdir/etc/ld.config.vndk_lite.txt isolates SP-HAL and VNDK-SP shared libraries. In Android 8.0 and higher, this must be the configuration file for dynamic linker when PRODUCT_TREBLE_LINKER_NAMESPACES is true.

${android-src}/system/core/rootdir/etc/ld.config.txt isolates SP-HAL and VNDK-SP shared libraries as well. In addition, ld.config.txt also 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, ld.config.txt is the default configuration file and it is highly recommended to enable full dynamic linker isolation. However, if there are too many dependencies to be cleaned up in Android 8.1, you may add BOARD_VNDK_RUNTIME_DISABLE to BoardConfig.mk:

BOARD_VNDK_RUNTIME_DISABLE := true

If BOARD_VNDK_RUNTIME_DISABLE is true, ${android-src}/system/core/rootdir/etc/ld.config.vndk_lite.txt is installed.

ld.config.txt

ld.config.txt isolates the shared library dependencies between the system partition and vendor partitions. Compared to ld.config.txt mentioned in previous subsection, the differences are outlined as following items:

  • Framework Processes

    • Four namespaces (default, vndk, sphal, and rs) 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

    • Three namespaces (default, vndk, and system) 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 their dependencies are loaded into the system namespace.

The relationship between the linker namespaces is depicted in the figure below:

Linker namespace graph described in ld.config.txt
Figure 1. Linker namespace isolation (ld.config.txt)

In the graph 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

The table below presents the namespaces configuration for framework processes, which is excerpted from the [system] section in ld.config.txt:

Namespace Property Value
default search.paths /system/${LIB}
/product/${LIB}
permitted.paths /system/${LIB}/drm
/system/${LIB}/extractors
/system/${LIB}/hw
/product/${LIB}
/system/framework
/system/app
/system/priv-app
/vendor/app
/vendor/priv-app
/oem/app
/odm/priv-app
/oem/app
/product/framework
/product/app
/product/priv-app
/data
/mnt/expand
isolated true
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, sphal
link.default.shared_libs LL-NDK
link.default.allow_all_shared_libs true
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 ld.config.txt:

Namespace Property Value
default search.paths /odm/${LIB}
/vendor/${LIB}
permitted.paths /odm
/vendor
isolated true
visible true
links system, vndk
link.system.shared_libs LL-NDK
link.vndk.shared_libs VNDK, VNDK-SP (vendor available)
vndk search.paths /odm/${LIB}/vndk
/odm/${LIB}/vndk-sp
/vendor/${LIB}/vndk
/vendor/${LIB}/vndk-sp
/system/${LIB}/vndk-${VER}
/system/${LIB}/vndk-sp-${VER}
isolated true
links system, default
link.system.shared_libs LL-NDK
link.default.allow_all_shared_libs true
system search.paths /system/${LIB}
isolated false

More details can be found in ${android-src}/system/core/rootdir/etc/ld.config.txt.

ld.config.vndk_lite.txt

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

Linker namespace graph described in ld.config.vndk_lite.txt
Figure 2. Linker namespace isolation (ld.config.vndk_lite.txt)

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 ld.config.txt)
    • libsync.so
    • libvndksupport.so
    • libz.so (Moved to VNDK-SP in ld.config.txt)
  • 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 presents the namespaces configuration for framework processes, which is excerpted from the [system] section in ld.config.vndk_lite.txt:

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 ld.config.vndk_lite.txt:

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 ${android-src}/system/core/rootdir/etc/ld.config.vndk_lite.txt.

Document history

Android P changes

  • In Android P, 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 P changes the names of the following dynamic linker configuration files:

    Android 8.x Android P 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 and earlier
  • Remove android.hardware.graphics.allocator@2.0.so.

  • product and odm partitions are added.