링커 네임스페이스

동적 링커는 트레블 VNDK 설계의 두 가지 문제점을 해결합니다.

  • VNDK-SP 라이브러리를 비롯한 SP-HAL 공유 라이브러리 및 종속 항목이 프레임워크 프로세스에 로드되며, 기호 충돌 방지를 위한 메커니즘이 있어야 합니다.
  • dlopen()android_dlopen_ext()는 빌드 시간에 표시되지 않고 정적 분석을 사용하여 감지하기 어려운 런타임 종속 항목을 도입할 수 있습니다.

이러한 두 가지 문제는 링커 네임스페이스 메커니즘으로 해결할 수 있습니다. 이 메커니즘은 동적 링커에서 제공합니다. 동적 링커는 라이브러리 이름은 같지만 기호는 다른 라이브러리가 충돌하지 않도록 여러 링커 네임스페이스의 공유 라이브러리를 격리할 수 있습니다.

반면 링커 네임스페이스 메커니즘은 유연하므로 링커 네임스페이스에서 일부 공유 라이브러리를 내보내고 다른 링커 네임스페이스에서 이러한 라이브러리를 사용할 수 있습니다. 내보낸 이러한 공유 라이브러리는 다른 프로그램에 공개되는 동시에 링커 네임스페이스 내에 구현 세부정보를 숨기는 애플리케이션 프로그래밍 인터페이스가 될 수 있습니다.

예를 들어 /system/lib[64]/libcutils.so/system/lib[64]/vndk-sp-${VER}/libcutils.so는 두 개의 공유 라이브러리입니다. 이 두 라이브러리의 기호는 서로 다를 수 있습니다. 이러한 라이브러리는 다른 링커 네임스페이스로 로드되므로 프레임워크 모듈이 /system/lib[64]/libcutils.so에, SP-HAL 공유 라이브러리가 /system/lib[64]/vndk-sp-${VER}/libcutils.so에 종속될 수 있습니다.

반면 /system/lib[64]/libc.so는 링커 네임스페이스에서 내보내고 여러 링커 네임스페이스로 가져오는 공개 라이브러리의 예입니다. libnetd_client.so와 같은 /system/lib[64]/libc.so의 종속 항목은 /system/lib[64]/libc.so가 상주하는 네임스페이스에 로드됩니다. 다른 네임스페이스는 이러한 종속 항목에 액세스할 수 없습니다. 이러한 메커니즘은 구현 세부정보를 캡슐화하는 동시에 공개 인터페이스를 제공합니다.

작동 원리

동적 링커는 DT_NEEDED 항목에 지정된 공유 라이브러리나 dlopen() 또는 android_dlopen_ext()의 인수에 의해 지정된 공유 라이브러리를 로드하는 역할을 합니다. 두 경우 모두 동적 링커는 호출자가 있는 링커 네임스페이스를 찾고 종속 항목을 동일한 링커 네임스페이스에 로드하려고 합니다. 동적 링커가 공유 라이브러리를 지정된 링커 네임스페이스에 로드할 수 없으면 연결된 링커 네임스페이스에 내보낸 공유 라이브러리를 요청합니다.

구성 파일 형식

구성 파일 형식은 INI 파일 형식에 기반하며 일반적인 구성 파일은 다음과 같습니다.

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}

구성 파일에는 다음이 포함됩니다.

  • 동적 링커가 효과적인 섹션을 선택하게 하는 초반의 여러 디렉터리 섹션 매핑 속성
  • 여러 링커 네임스페이스 구성 섹션:
    • 각 섹션에는 여러 네임스페이스(그래프 꼭짓점)와 네임스페이스 간 다양한 대체 링크(그래프 원호)가 포함되어 있습니다.
    • 각 네임스페이스에는 자체적인 격리, 검색 경로, 허용 경로, 공개 상태 설정이 포함됩니다.

아래 표에서는 각 속성의 의미에 관해 자세히 설명합니다.

디렉터리 섹션 매핑 속성

속성 설명

dir.name

[name] 섹션이 적용되는 디렉터리 경로입니다.

각 속성이 디렉터리 아래의 실행 프로그램을 링커 네임스페이스 구성 섹션에 매핑합니다. name은 같지만 다른 디렉터리를 가리키는 속성이 두 개 이상 있을 수 있습니다.

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

[system] 섹션에 지정된 구성이 /system/bin 또는 /system/xbin에서 로드된 실행 프로그램에 적용됨을 나타냅니다.

[vendor] 섹션에 지정된 구성이 /vendor/bin에서 로드된 실행 프로그램에 적용됩니다.

관계 속성

속성 설명
additional.namespaces

섹션의 추가 네임스페이스(default 네임스페이스 외)에 관한 쉼표로 구분된 목록입니다.

additional.namespaces = sphal,vndk

[system] 구성에 네임스페이스 세 개(default, sphal, vndk)가 있음을 나타냅니다.

namespace.name.links

쉼표로 구분된 대체 네임스페이스 목록입니다.

현재 네임스페이스에서 공유 라이브러리를 찾을 수 없다면 동적 링커는 대체 네임스페이스에서 공유 라이브러리를 로드하려고 합니다. 목록 초반에 지정된 네임스페이스의 우선순위가 더 높습니다.

namespace.sphal.links = default,vndk

공유 라이브러리나 실행 파일이 sphal 네임스페이스에 로드할 수 없는 공유 라이브러리를 요청하면 동적 링커는 default 네임스페이스에서 공유 라이브러리를 로드하려고 합니다.

그런 다음 default 네임스페이스에서도 공유 라이브러리를 로드할 수 없는 경우 동적 링커는 vndk 네임스페이스에서 공유 라이브러리를 로드하려고 합니다.

마지막으로 모든 시도에 실패하면 동적 링커가 오류를 반환합니다.

namespace.name.link.other.shared_libs

공유 라이브러리를 name 네임스페이스에서 찾을 수 없을 때 other 네임스페이스에서 검색할 수 있는 콜론으로 구분된 공유 라이브러리 목록입니다.

이 속성은 namespace.name.link.other.allow_all_shared_libs와 함께 사용할 수 없습니다.

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

대체 링크가 libc.so 또는 libm.so만 요청된 라이브러리 이름으로 허용함을 나타냅니다. 동적 링커는 요청된 라이브러리 이름이 libc.so 또는 libm.so가 아니면 default 네임스페이스 관련 sphal의 대체 링크를 무시합니다.

namespace.name.link.other.allow_all_shared_libs

공유 라이브러리를 name 네임스페이스에서 찾을 수 없을 때 모든 공유 라이브러리를 other 네임스페이스에서 검색할 수 있는지 나타내는 부울 값입니다.

이 속성은 namespace.name.link.other.shared_libs와 함께 사용할 수 없습니다.

namespace.vndk.link.sphal.allow_all_shared_libs = true

모든 라이브러리 이름이 vndk에서 sphal 네임스페이스까지의 대체 링크를 통과할 수 있음을 나타냅니다.

네임스페이스 속성

속성 설명
namespace.name.isolated

동적 링커가 공유 라이브러리 상주 위치를 확인해야 할지를 나타내는 부울 값입니다.

isolatedtrue이면 search.paths 디렉터리(하위 디렉터리 제외) 중 하나에 있거나 permitted.paths 디렉터리(하위 디렉터리 포함) 중 하나 아래에 위치한 공유 라이브러리만 로드할 수 있습니다.

isolatedfalse(기본값)면 동적 링커는 공유 라이브러리의 경로를 확인하지 않습니다.

namespace.sphal.isolated = true

search.pathspermitted.paths 아래의 공유 라이브러리만 sphal 네임스페이스에 로드될 수 있음을 나타냅니다.

namespace.name.search.paths

공유 라이브러리 검색을 위한 콜론으로 구분된 디렉터리 목록입니다.

search.paths에서 지정된 디렉터리는 dlopen() 또는 DT_NEEDED 항목의 함수 호출이 전체 경로를 지정하지 않는 경우 요청된 라이브러리 이름 앞에 추가됩니다. 목록 초반에 지정된 디렉터리의 우선순위가 더 높습니다.

isolatedtrue이면 search.paths 디렉터리(하위 디렉터리 제외) 중 하나에 있는 공유 라이브러리는 permitted.paths 속성과 관계없이 로드할 수 있습니다.

예를 들어 search.paths/system/${LIB}이고 permitted.paths가 비어 있으면 /system/${LIB}/libc.so를 로드할 수 있지만 /system/${LIB}/vndk/libutils.so는 로드할 수 없습니다.

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

동적 링커가 /system/${LIB}에서 공유 라이브러리를 검색함을 나타냅니다.

namespace.name.asan.search.paths

AddressSanitizer(ASan)가 사용 설정될 때 공유 라이브러리를 검색하기 위한 콜론으로 구분된 디렉터리 목록입니다.

ASan이 사용 설정되면 namespace.name.search.paths가 무시됩니다.

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

ASan이 사용 설정되면 동적 링커가 먼저 /data/asan/system/${LIB}를 검색하고 /system/${LIB}를 검색한다는 것을 나타냅니다.

namespace.name.permitted.paths

isolatedtrue일 때 동적 링커가 공유 라이브러리(search.paths 외에 추가로)를 로드할 수 있는 콜론으로 구분된 디렉터리 목록(하위 디렉터리 포함)입니다.

permitted.paths의 하위 디렉터리 아래에 위치한 공유 라이브러리도 로드할 수 있습니다. 예를 들어 permitted.paths/system/${LIB}이면 /system/${LIB}/libc.so/system/${LIB}/vndk/libutils.so를 둘 다 로드할 수 있습니다.

isolatedfalsepermitted.paths가 무시되고 경고가 표시됩니다.

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

/system/${LIB}/hw 아래의 공유 라이브러리는 격리된 default 네임스페이스에 로드될 수 있음을 나타냅니다.

예를 들어 permitted.paths가 없으면 libaudiohal.so/system/${LIB}/hw/audio.a2dp.default.sodefault 네임스페이스에 로드할 수 없습니다.

namespace.name.asan.permitted.paths

ASan이 사용 설정되었을 때 동적 링커가 공유 라이브러리를 로드할 수 있는 콜론으로 구분된 디렉터리 목록입니다.

ASan이 사용 설정되면 namespace.name.permitted.paths가 무시됩니다.

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

ASan이 사용 설정되면 /data/asan/system/${LIB}/hw 또는 /system/${LIB}/hw 아래의 공유 라이브러리를 격리된 default 네임스페이스에 로드할 수 있음을 나타냅니다.

namespace.name.visible

libc 외의 프로그램이 android_get_exported_namespace()로 링커 네임스페이스 핸들을 획득하고 핸들을 android_dlopen_ext()에 전달하여 링커 네임스페이스의 공유 라이브러리를 열 수 있는지를 나타내는 부울 값입니다.

visibletrueandroid_get_exported_namespace()는 네임스페이스가 존재하는 경우 항상 핸들을 반환합니다.

visiblefalse(기본값)면 android_get_exported_namespace()는 네임스페이스의 존재 여부와 상관없이 항상 NULL을 반환합니다. 공유 라이브러리는 (1) 이 네임스페이스에 관한 대체 링크를 보유한 다른 링커 네임스페이스에서 요청하거나 (2) 이 네임스페이스의 다른 공유 라이브러리 또는 실행 파일에서 요청하는 경우에만 이 네임스페이스에 로드할 수 있습니다.

namespace.sphal.visible = true

android_get_exported_namespace("sphal")가 유효한 링커 네임스페이스 핸들을 반환할 수 있음을 나타냅니다.

링커 네임스페이스 생성

Android 11에서 링커 구성은 ${android-src}/system/core/rootdir/etc의 일반 텍스트 파일을 사용하는 대신 런타임 시 /linkerconfig 아래에 생성됩니다. 구성은 런타임 환경에 기반하여 부팅 시간에 생성됩니다. 런타임 환경에는 다음 항목이 포함됩니다.

  • 기기에서 VNDK를 지원하는 경우
  • 공급업체 파티션의 타겟 VNDK 버전
  • 제품 파티션의 VNDK 버전
  • 설치된 APEX 모듈

링커 구성은 링커 네임스페이스 간 종속 항목을 결정하여 생성됩니다. 예를 들어 종속 항목 업데이트가 포함되어 있는 APEX 모듈에 업데이트가 있다면 이러한 변경사항을 반영하는 링커 구성이 생성됩니다. 링커 구성을 만드는 방법에 관한 자세한 내용은 ${android-src}/system/linkerconfig에서 확인할 수 있습니다.

링커 네임스페이스 격리

세 가지 구성 유형이 있습니다. BoardConfig.mkPRODUCT_TREBLE_LINKER_NAMESPACESBOARD_VNDK_VERSION 값에 따라 상응하는 구성이 부팅 시간에 생성됩니다.

PRODUCT_TREBLE_
LINKER_NAMESPACES
BOARD_VNDK_
VERSION
선택된 구성 VTS 요구사항
true current VNDK Android 9 이상으로 출시되는 기기의 경우 필수입니다.
비어 있음 VNDK Lite Android 8.x로 출시되는 기기의 경우 필수입니다.
false 비어 있음 Legacy 비 트레블 기기에 사용됩니다.

VNDK Lite 구성은 SP-HAL 및 VNDK-SP 공유 라이브러리를 격리합니다. Android 8.0에서는 PRODUCT_TREBLE_LINKER_NAMESPACEStrue면 동적 링커의 구성 파일이어야 합니다.

VNDK 구성은 SP-HAL 및 VNDK-SP 공유 라이브러리도 격리합니다. 또한 이 구성은 전체 동적 링커 격리 기능을 제공하며, 시스템 파티션의 모듈과 공급업체 파티션의 공유 라이브러리가 서로에 종속되지 않도록 합니다.

Android 8.1 이상에서는 VNDK가 기본 구성이므로 BOARD_VNDK_VERSIONcurrent로 설정하여 전체 동적 링커 격리를 사용 설정할 것을 적극 권장합니다.

VNDK 구성

VNDK 구성은 시스템 파티션과 공급업체 파티션 간 공유 라이브러리 종속 항목을 격리합니다. 이전 하위 섹션에서 언급한 구성과 비교할 때 차이점은 다음과 같습니다.

  • 프레임워크 프로세스

    • default, vndk, sphal, rs 네임스페이스가 생성됩니다.
    • 모든 네임스페이스가 격리됩니다.
    • 시스템 공유 라이브러리는 default 네임스페이스에 로드됩니다.
    • SP-HAL은 sphal 네임스페이스에 로드됩니다.
    • VNDK-SP 공유 라이브러리는 vndk 네임스페이스에 로드됩니다.
  • 공급업체 프로세스

    • default, vndk, system 네임스페이스가 생성됩니다.
    • default 네임스페이스가 격리됩니다.
    • 공급업체 공유 라이브러리는 default 네임스페이스에 로드됩니다.
    • VNDK 및 VNDK-SP 공유 라이브러리는 vndk 네임스페이스에 로드됩니다.
    • LL-NDK 및 종속 항목은 system 네임스페이스에 로드됩니다.

링커 네임스페이스 간의 관계는 아래에 나와 있습니다.

VNDK 구성에 설명된 링커 네임스페이스 그래프
그림 1. 링커 네임스페이스 격리(VNDK 구성)

위의 그래프에서 LL-NDKVNDK-SP는 다음과 같은 공유 라이브러리를 나타냅니다.

  • 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

기기의 /linkerconfig/ld.config.txt에서 자세한 내용을 확인할 수 있습니다.

VNDK Lite 구성

Android 8.0부터 동적 링커는 SP-HAL 및 VNDK-SP 공유 라이브러리를 격리하도록 구성되므로 다른 프레임워크 공유 라이브러리와 기호가 충돌하지 않습니다. 링커 네임스페이스 간의 관계는 아래에 나와 있습니다.

VNDK Lite 구성에 설명된 링커 네임스페이스 그래프
그림 2. 링커 네임스페이스 격리(VNDK Lite 구성)

LL-NDKVNDK-SP는 다음과 같은 공유 라이브러리를 나타냅니다.

  • LL-NDK
    • libEGL.so
    • libGLESv1_CM.so
    • libGLESv2.so
    • libc.so
    • libdl.so
    • liblog.so
    • libm.so
    • libnativewindow.so
    • libstdc++.so(구성에 없음)
    • libsync.so
    • libvndksupport.so
    • libz.so(구성의 VNDK-SP로 이동됨)
  • 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

아래 표에는 VNDK Lite 구성의 [system] 섹션에서 발췌한 프레임워크 프로세스의 네임스페이스 구성이 나열되어 있습니다.

네임스페이스 속성
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(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(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(컴파일된 RS 커널)
isolated true
visible true
links default,vndk
link.default.shared_libs LL-NDK
libmediandk.so
libft2.so
link.vndk.shared_libs VNDK-SP

아래 표에는 VNDK Lite 구성의 [vendor] 섹션에서 발췌한 공급업체 프로세스의 네임스페이스 구성이 표시되어 있습니다.

네임스페이스 속성
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}(지원 중단됨)
/product/${LIB}(지원 중단됨)
isolated false

자세한 내용은 기기의 /linkerconfig/ld.config.txt에서 확인할 수 있습니다.

문서 이력

Android 11 변경사항

  • Android 11에서는 정적 ld.config.*.txt 파일이 코드베이스에서 삭제되고 LinkerConfig가 대신 런타임에 이 파일을 생성합니다.

Android 9 변경사항

  • Android 9에서는 vndk 링커 네임스페이스가 공급업체 프로세스에 추가되고 VNDK 공유 라이브러리가 기본 링커 네임스페이스에서 격리됩니다.
  • PRODUCT_FULL_TREBLE을 좀 더 구체적인 PRODUCT_TREBLE_LINKER_NAMESPACES로 교체하세요.
  • Android 9에서는 다음과 같은 동적 링커 구성 파일의 이름이 변경됩니다.
    Android 8.x Android 9 설명
    ld.config.txt.in ld.config.txt 런타임 링커 네임스페이스 격리를 포함하는 기기
    ld.config.txt ld.config.vndk_lite.txt VNDK-SP 링커 네임스페이스 격리를 포함하는 기기
    ld.config.legacy.txt ld.config.legacy.txt Android 7.x 이하를 실행하는 기존 기기
  • android.hardware.graphics.allocator@2.0.so가 삭제됩니다.
  • productodm 파티션이 추가됩니다.