Google은 흑인 공동체를 위한 인종 간 평등을 진전시키기 위해 노력하고 있습니다. Google에서 어떤 노력을 하고 있는지 확인하세요.

APEX 파일 형식

Android Pony EXpress(APEX)는 Android 10에 도입된 컨테이너 형식입니다. APEX는 하위 수준 시스템 모듈의 설치 흐름에 사용됩니다. 이 형식은 표준 Android 애플리케이션 모델에 맞지 않는 시스템 구성요소의 업데이트를 용이하게 합니다. 구성요소의 예로는 네이티브 서비스 및 라이브러리, 하드웨어 추상화 계층(HAL), 런타임(ART) 및 클래스 라이브러리 등이 있습니다.

'APEX'란 용어는 APEX 파일을 지칭할 수도 있습니다.

배경

Android는 Google Play 스토어 앱과 같은 패키지 설치 앱을 통해 서비스, 액티비티와 같은 표준 앱 모델 내에 적합한 모듈의 업데이트를 지원하지만, 하위 수준 OS 구성요소에 유사한 모델을 사용할 경우 아래와 같은 단점이 있습니다.

  • APK 기반 모듈은 부팅 시퀀스 초반에 사용할 수 없습니다. 패키지 관리자는 앱에 대한 정보로 구성된 중앙 저장소이며, 액티비티 관리자에서만 시작할 수 있습니다. 액티비티 관리자는 부팅 절차의 후반 단계에서 준비됩니다.
  • APK 형식(특히 매니페스트)은 경우에 따라 적합하지 않을 수 있는 Android 앱과 시스템 모듈을 위해 설계되었습니다.

설계

이 섹션에서는 APEX 파일 형식의 높은 설계 수준, 그리고 APEX 파일 관리 서비스인 APEX 관리자에 대해 설명합니다.

왜 이 설계가 APEX에 대해 선택되었는지에 대한 자세한 내용은 APEX 개발 시에 고려된 대안을 참조하세요.

APEX 형식

이는 APEX 파일의 형식입니다.

APEX 파일 형식

그림 1. APEX 파일 형식

상위 수준에서의 APEX 파일은 파일이 압축되지 않은 상태로 4KB 경계에 저장되는 zip 파일입니다.

APEX 파일에 포함되는 4개의 파일은 다음과 같습니다.

  • apex_manifest.json
  • AndroidManifest.xml
  • apex_payload.img
  • apex_pubkey

apex_manifest.json 파일에는 APEX 파일을 나타내는 패키지 이름과 버전이 포함됩니다.

AndroidManifest.xml 파일은 APEX 파일이 APK 관련 도구, ADB, PackageManager 등의 인프라와 패키지 설치 앱(Play 스토어 등)을 사용할 수 있게 해줍니다. 예를 들어 APEX 파일은 aapt 등의 기존 도구를 사용하여 파일에서 기본 메타데이터를 검사할 수 있습니다. 파일에는 패키지 이름과 버전 정보가 포함됩니다. 이 정보는 보통 apex_manifest.json에서도 제공됩니다.

apex_manifest.json은 APEX를 새 코드의 AndroidManifest.xml과 APEX를 다루는 시스템에 사용하면 좋습니다. AndroidManifest.xml에는 기존 앱 게시 도구에서 사용할 수 있는 추가적인 타겟팅 정보가 포함될 수 있습니다.

apex_payload.img는 dm-verity가 지원하는 ext4 파일 시스템 이미지입니다.. 이미지는 런타임 시 루프백 기기를 통해 마운트됩니다. 구체적으로는 해시 트리와 메타데이터 블록이 libavb를 사용하여 생성됩니다. 이미지를 제자리에 마운트할 수 있어야 하므로 파일 시스템 페이로드는 파싱되지 않습니다. 일반 파일은 apex_payload.img 파일 내에 포함됩니다.

apex_pubkey는 파일 시스템 이미지를 서명하는 데 사용되는 공개 키입니다. 런타임 시 이 키는 다운로드된 APEX가 기본 파티션의 동일한 APEX를 서명하는 동일한 항목에 의해 서명되는지 확인합니다.

APEX 관리자

APEX 관리자(apexd)는 APEX 파일의 인증, 설치 및 설치 제거를 담당하는 독립형 네이티브 프로세스입니다. 이 프로세스는 부팅 시퀀스 초반에 실행 및 준비됩니다. APEX 파일은 보통 /system/apex 아래의 기기에 사전 설치됩니다. APEX 관리자는 업데이트가 없을 경우 이러한 패키지를 기본으로 사용합니다.

APEX 업데이트 시퀀스는 PackageManager 클래스를 사용하며, 이는 다음과 같습니다.

  1. APEX 파일이 설치 앱, ADB 또는 다른 소스를 통해 다운로드됩니다.
  2. 패키지 관리자가 설치 절차를 시작합니다. APEX 파일을 인지한 패키지 관리자는 APEX 관리자에게 컨트롤을 이전합니다.
  3. APEX 관리자가 APEX 파일을 인증합니다.
  4. APEX 파일이 인증되면 APEX 파일이 다음 부팅에 활성화된다는 내용을 반영하도록 APEX 관리자의 내부 데이터베이스가 업데이트됩니다.
  5. 설치 요청자는 패키지 인증 성공 시 브로드캐스트를 수신합니다.
  6. 설치를 계속하기 위해 시스템은 자동으로 기기를 재부팅합니다.
  7. 부팅 시 APEX 관리자가 시작되고 내부 데이터베이스를 읽고 나열된 각 APEX 파일에 대해 다음을 수행합니다.

    1. APEX 파일을 인증합니다.
    2. APEX 파일에서 루프백 기기를 생성합니다.
    3. 루프백 기기 외에 긱 매퍼 블록 기기를 생성합니다.
    4. 기기 매퍼 블록 기기를 고유 경로(예: /apex/name@ver)에 마운트합니다.

내부 데이터베이스에 나열된 모든 APEX 파일이 마운트되면 APEX 관리자는 다른 시스템 구성요소가 설치된 APEX 파일에 대한 정보를 쿼리할 수 있도록 바인더 서비스를 제공합니다. 예를 들어 다른 시스템 구성요소는 파일이 액세스될 수 있도록 기기에 설치된 APEX 파일 목록을 쿼리하거나 특정 APEX가 마운트된 정확한 경로를 쿼리할 수 있습니다.

APEX 파일은 APK 파일임

APEX 파일은 AndroidManifest.xml 파일을 포함하는 서명(APK 서명 체계 사용)된 zip 아카이브이므로 유효한 APK 파일입니다. 따라서 APEX 파일은 패키지 설치 앱, 서명 유틸리티 및 패키지 관리자와 같은 APK 파일의 인프라를 사용할 수 있습니다.

APEX 파일 내의 AndroidManifest.xml 파일은 패키지 name, versionCode, 그리고 세부 타겟팅을 위한 선택적 targetSdkVersion, minSdkVersion, maxSdkVersion으로 구성된 최소 파일입니다. 이 정보는 패키지 설치 앱과 ADB 등의 기존 채널을 통해 APEX 파일을 전달할 수 있게 해줍니다.

지원되는 파일 유형

APEX 형식은 다음과 같은 파일 유형을 지원합니다.

  • 네이티브 공유 libs
  • 네이티브 실행 파일
  • JAR 파일
  • 데이터 파일
  • Config 파일

그렇다고 해서 APEX가 이러한 모든 파일 유형을 업데이트할 수 있는 것은 아닙니다. 파일 유형의 업데이트 가능 여부는 플랫폼, 그리고 파일 유형의 인터페이스가 얼마나 안정적으로 정의되는지에 따라 다릅니다.

서명

APEX 파일은 두 가지 방식으로 서명됩니다. 우선 apex_payload.img(구체적으로는 apex_payload.img에 추가되는 vbmeta 설명자) 파일은 키로 서명됩니다. 이어서 전체 APEX가 APK 서명 체계 v3을 사용하여 서명됩니다. 이 과정에서 2개의 상이한 키가 사용됩니다.

기기 측에서는 vbmeta 설명자를 서명하는 데 사용된 비공개 키에 해당하는 공개 키가 설치됩니다. APEX 관리자는 공개 키를 사용하여 설치가 요청된 APEX를 인증합니다. 각 APEX는 다른 키로 서명되어야 하며 빌드 시간과 런타임에 적용됩니다.

내장 파티션의 APEX

APEX 파일은 /system과 같은 내장 파티션에 위치할 수 있습니다. 파티션이 이미 dm-verity 위에 있는 경우 APEX 파일이 루프백 기기 바로 위에 마운트됩니다.

APEX가 내장 파티션에 존재하는 경우 같은 패키지 이름과 더 높은 버전 코드가 포함된 APEX 패키지를 제공하여 APEX를 업데이트할 수 있습니다. 새 APEX는 /data에 저장되며, APK와 마찬가지로 최신 버전이 내장 파티션에 이미 존재하는 버전을 덮습니다. 하지만 APK와 달리 APEX의 최신 버전은 재부팅 이후에만 활성화됩니다.

커널 요구사항

ndroid 기기에서 APEX 메인라인 모듈을 지원하려면 Linux 커널 기능(루프백 드라이버 및 dm-verity)이 필요합니다. 루프백 드라이버는 APEX 모듈에 파일 시스템 이미지를 마운트하고 dm-verity는 APEx 모듈을 인증합니다.

루프백 드라이버와 dm-verity의 성능은 APEX 모듈 사용 시의 우수한 시스템 성능을 달성하는 데 있어 매우 중요합니다.

지원되는 커널 버전

APEX 메인라인 모듈은 커널 버전 4.4 이상을 사용하는 기기에서 지원됩니다. Android 10 이상으로 출시되는 새 기기는 커널 버전 4.9 이상을 사용해야 APEX 모듈을 지원할 수 있습니다.

필수 커널 패치

APEX 모듈 지원을 위한 필수 커널 패치는 Android 일반 트리에 포함됩니다. APEX 지원을 위한 패치를 가져오려면 최신 버전의 Android 일반 트리를 사용하세요.

커널 버전 4.4

이 버전은 Android 9 및 Android 10으로 업그레이드될 예정이고 APEX 모듈을 지원할 의향이 있는 기기에 대해서만 지원됩니다. 필수 패치를 가져올 때는 android-4.4 브랜치에서 아래로 병합하는 것이 좋습니다. 다음은 커널 버전 4.4의 필수 개별 패치 목록입니다.

  • UPSTREAM: loop: 논리 블록 크기 변경을 위한 ioctl을 추가(4.4)
  • BACKPORT: block/loop: hw_sectors를 설정(4.4)
  • UPSTREAM: loop: LOOP_SET_BLOCK_SIZE를 compat ioctl에 추가(4.4)
  • ANDROID: mnt: next_descendent를 고정(4.4)
  • ANDROID: mnt: 재마운트 시 slave의 slave로 전파되어야 함(4.4)
  • ANDROID: mnt: 재마운트를 올바르게 전파(4.4)
  • Revert "ANDROID: dm verity: 최소 미리 가져오기 크기를 추가(4.4)
  • UPSTREAM: loop: 오프셋 또는 block_size가 변경되면 캐시를 드롭(4.4)

커널 버전 4.9/4.14/4.19

커널 버전 4.9/4.14/4.19의 필수 패치를 가져오려면 android-common 브랜치에서 아래로 병합합니다.

필수 커널 구성 옵션

다음 목록은 Android 10에 도입되었던 APEX 모듈 지원을 위한 기본 구성 요구사항을 보여줍니다. 별표(*)가 표시된 항목은 Android 9 이하의 기존 요구사항입니다.

(*) CONFIG_AIO=Y # AIO support (for direct I/O on loop devices)
    CONFIG_BLK_DEV_LOOP=Y # for loop device support
    CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 # pre-create 16 loop devices
    (*) CONFIG_CRYPTO_SHA1=Y # SHA1 hash for DM-verity
    (*) CONFIG_CRYPTO_SHA256=Y # SHA256 hash for DM-verity
    CONFIG_DM_VERITY=Y # DM-verity support
    

커널 명령줄 매개변수 요구사항

APEX를 지원하려면 커널 명령줄 매개변수가 다음과 같은 요구사항을 충족하는지 확인해야 합니다.

  • loop.max_loop를 설정하면 안 됨
  • loop.max_part가 <= 8이어야 함

APEX 빌드

이 섹션에서는 Android 빌드 시스템을 사용하여 APEX를 빌드하는 방법을 설명합니다. 다음은 apex.test라는 APEX의 Android.bp 예시입니다.

apex {
        name: "apex.test",
        manifest: "apex_manifest.json",
        file_contexts: "file_contexts",
        // libc.so and libcutils.so are included in the apex
        native_shared_libs: ["libc", "libcutils"],
        binaries: ["vold"],
        java_libs: ["core-all"],
        prebuilts: ["my_prebuilt"],
        compile_multilib: "both",
        key: "apex.test.key",
        certificate: "platform",
    }
    

apex_manifest.json 예시:

{
      "name": "com.android.example.apex",
      "version": 1
    }
    

file_contexts 예시:

(/.*)?           u:object_r:system_file:s0
    /sub(/.*)?       u:object_r:sub_file:s0
    /sub/file3       u:object_r:file3_file:s0
    

APEX의 파일 형식 및 위치

파일 형식 APEX 내 위치
공유 라이브러리 /lib/lib64(x86에서 해석된 arm의 /lib/arm)
실행 파일 /bin
자바 라이브러리 /javalib
사전 빌드 /etc

전이 종속성

APEX 파일은 네이티브 공유 libs 또는 실행 파일의 전이 종속성을 자동으로 포함합니다. 예를 들어 libFoolibBar에 종속되는 경우에는 libFoonative_shared_libs 속성에 나열되는 경우에만 2개의 libs가 포함됩니다.

여러 ABI 처리

기기의 기본 및 보조 애플리케이션 바이너리 인터페이스((ABI) 둘 다의 native_shared_libs 속성을 설치합니다. APEX가 단일 ABI(32비트 또는 64비트로만)로 기기를 타겟팅하면 해당하는 ABI가 포함된 라이브러리만 설치됩니다.

아래의 설명처럼 기본 ABI의 binaries 속성만 설치합니다.

  • 기기가 32비트 전용인 경우 바이너리의 32비트 변형만 설치됩니다.
  • 기기가 32/64 ABI를 둘 다 지원하지만 TARGET_PREFER_32_BIT_EXECUTABLES=true를 포함하는 경우에는 바이너리의 32비트 변형만 설치됩니다.
  • 기기가 64비트 전용인 경우 바이너리의 64비트 변형만 설치됩니다.
  • 기기가 32/64 ABI를 둘 다 지원하지만 TARGET_PREFER_32_BIT_EXECUTABLES=true를 포함하지 않는 경우에는 바이너리의 64비트 변형만 설치됩니다.

네이티브 라이브러리 및 바이너리의 ABI에 대한 세부 제어를 추가하려면 multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries] 속성을 사용하세요.

  • first: 기기의 기본 ABI를 매칭합니다. 이는 바이너리의 기본값입니다.
  • lib32: 지원되는 경우 기기의 32비트 ABI를 매칭합니다.
  • lib64: 지원되는 경우 기기의 64비트 ABI를 매칭합니다.
  • prefer32: 지원되는 경우 기기의 32비트 ABI를 매칭합니다. 32비트 ABI가 지원되지 않는 경우 64비트 ABI를 매칭합니다.
  • both: 두 ABI를 모두 매칭합니다. 이는 native_shared_libraries의 기본값입니다.

java, librariesprebuilts 속성은 ABI에 구속받지 않습니다.

이 예시는 32/64를 지원하지만 32를 선호하지 않는 기기와 관련이 있습니다.

apex {
        // other properties are omitted
        native_shared_libs: ["libFoo"], // installed for 32 and 64
        binaries: ["exec1"], // installed for 64, but not for 32
        multilib: {
            first: {
                native_shared_libs: ["libBar"], // installed for 64, but not for 32
                binaries: ["exec2"], // same as binaries without multilib.first
            },
            both: {
                native_shared_libs: ["libBaz"], // same as native_shared_libs without multilib
                binaries: ["exec3"], // installed for 32 and 64
            },
            prefer32: {
                native_shared_libs: ["libX"], // installed for 32, but not for 64
            },
            lib64: {
                native_shared_libs: ["libY"], // installed for 64, but not for 32
            },
        },
    }
    

vbmeta 서명

각 APEX를 다른 키로 서명합니다. 새 키가 필요한 경우 공개-비공개 키 쌍을 생성하고 apex_key 모듈을 만듭니다. key 속성을 사용하여 키로 APEX를 서명합니다. 공개 키가 이름이 avb_pubkey인 APEX에 자동으로 포함됩니다.

    # create an rsa key pair
    openssl genrsa -out foo.pem 4096

    # extract the public key from the key pair
    avbtool extract_public_key --key foo.pem --output foo.avbpubkey

    # in Android.bp
    apex_key {
        name: "apex.test.key",
        public_key: "foo.avbpubkey",
        private_key: "foo.pem",
    }
    

위의 예시에서는 공개 키의 이름(foo)이 키의 ID가 됩니다. APEX를 서명하는 데 사용된 키의 ID는 APEX에서 작성됩니다. 런타임 시 apexd는 기기의 동일한 ID를 가진 공개 키를 사용하여 APEX를 인증합니다.

ZIP 서명

APK와 동일한 방식으로 APEX를 서명합니다. APEX가 미니 파일 시스템(apex_payload.img 파일)에 한 번, 전체 파일에 한 번, 이렇게 두 번 서명됩니다.

파일 수준에서 APEX를 서명하려면 아래와 같은 세 방식 중 하나를 사용하여 certificate 속성을 설정합니다.

  • 설정되지 않음: 설정된 값이 않으면 APEX가 PRODUCT_DEFAULT_DEV_CERTIFICATE에 위치한 인증서로 서명됩니다. 설정된 플래그가 없으면 경로가 기본값인 build/target/product/security/testkey로 설정됩니다.
  • <name>: APEX가 PRODUCT_DEFAULT_DEV_CERTIFICATE과 같은 디렉터리에 있는 <name> 인증서로 서명됩니다.
  • :<name>: APEX가 이름이 <name>인 Soong 모듈에 의해 정의된 인증서로 서명됩니다. 인증서 모듈은 다음과 같이 정의할 수 있습니다.
android_app_certificate {
        name: "my_key_name",
        certificate: "dir/cert",
        // this will use dir/cert.x509.pem (the cert) and dir/cert.pk8 (the private key)
    }
    

APEX 설치

APEX를 설치하려면 ADB를 사용합니다.

    adb install apex_file_name
    adb reboot
    

APEX 사용

재부팅 후에는 APEX가 /apex/<apex_name>@<version> 디렉터리에 마운트됩니다. 동일한 APEX의 여러 버전을 동시에 마운트할 수 있습니다. 마운트 경로 중에서 최신 버전에 해당하는 경로가 /apex/<apex_name>에서 제위치에 마운트됩니다.

클라이언트는 제자리에 마운트된 경로를 사용하여 APEX에서 파일을 읽고 실행할 수 있습니다.

APEX는 일반적으로 다음과 같이 사용됩니다.

  1. 기기가 배송되면 OEM 또는 ODM이 /system/apex 아래에 APEX를 미리 로드합니다.
  2. APEX의 파일은 /apex/<apex_name>/ 경로를 통해 액세스됩니다.
  3. APEX의 업데이트된 버전이 /data/apex에 설치되면 경로가 재부팅 후에 새 APEX를 가리킵니다.

APEX로 서비스 업데이트

APEX를 사용하여 서비스를 업데이트하는 방법:

  1. 시스템 파티션의 서비스를 업데이트 가능으로 표시합니다. 옵션 updatable을 서비스 정의에 추가합니다.

    /system/etc/init/myservice.rc:
    
        service myservice /system/bin/myservice
            class core
            user system
            ...
            updatable
        
  2. 업데이트된 서비스의 새 .rc 파일을 생성합니다. override 옵션을 사용하여 기존 서비스를 재정의합니다.

    /apex/my.apex@1/etc/init.rc:
    
        service myservice /apex/my.apex@1/bin/myservice
            class core
            user system
            ...
            override
        

서비스 정의는 APEX의 .rc 파일에서만 정의할 수 있습니다. 작업 트리거는 APEX에서 지원되지 않습니다.

업데이트 가능으로 표시된 서비스가 APEX 활성화 이전에 시작되면 APEX 활성화가 완료될 때까지 시작이 지연됩니다.

APEX 업데이트를 지원하도록 시스템 구성

다음 시스템 속성을 true로 설정하여 APEX 파일 업데이트를 지원합니다.

<device.mk>:

    PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=true

    BoardConfig.mk:
    TARGET_FLATTEN_APEX := false
    

아니면 그냥 다음을 실행합니다.

<device.mk>:

    $(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)
    

평면화된 APEX

레거시 기기의 경우 간혹 기존 커널을 업데이트하여 APEX를 온전히 지원하기가 불가능할 수 있습니다. 예를 들어 커널은 파일 시스템 이미지를 APEX 내에 마운트하는 데 있어 중요한 CONFIG_BLK_DEV_LOOP=Y 없이 빌드되었을 수 있습니다.

평면화된 APEX는 레거시 커널을 포함하는 기기에 활성화할 수 있는 특수 빌드된 APEX입니다. 평면화된 APEX의 파일은 내장 파티션 아래의 디렉터리에 직접적으로 설치됩니다. 예를 들어 평면화된 APEX my.apexlib/libFoo.so/system/apex/my.apex/lib/libFoo.so에 설치됩니다.

평면화된 APEX를 활성화할 때는 루프 기기가 사용되지 않으며, 전체 디렉터리 /system/apex/my.apex가 바로 /apex/name@ver의 제자리에 마운트됩니다.

평면화된 APEX는 네트워크에서 APEX의 업데이트된 버전을 다운로드하여 업데이트할 수 없습니다. 이는 다운로드된 APEX가 평면화될 수 없기 때문입니다. 평면화된 APEX는 일반 OTA를 통해서만 업데이트 가능합니다.

평면화된 APEX는 기본 구성입니다. 즉, 위에서 설명한 것처럼 기기가 평면화되지 않은 APEX를 빌드하여 APEX 업데이트를 지원하도록 명시적으로 구성하지 않는 이상 모든 APEX가 기본으로 평면화됩니다.

평면화되었거나 평면화되지 않은 APEX를 기기에서 함께 사용하는 기능은 지원되지 않습니다. 기기의 APEX는 모두 평면화되었거나 평면화되지 않은 APEX여야 합니다. 이는 Mainline과 같은 프로젝트의 미리 서명된 APEX 사전 빌드를 배송하는 경우에 특히 중요합니다. 사전 서명되지 않은(즉, 소스에서 빌드된) APEX도 평면화되지 않아야 하며 올바른 키로 서명되어야 합니다. 기기는 APEX로 서비스 업데이트에 설명된 것처럼 updatable_apex.mk에서 상속해야 합니다.

APEX 개발 시 고려해야 하는 대안

다음은 APEX 파일 형식을 설계할 때 고려해야 하는 몇 가지 옵션, 그리고 이러한 옵션을 포함하거나 제외해야 하는 이유입니다.

일반 패키지 관리 시스템

Linux 배포판에는 강력하고 성숙하고 안정적인 dpkgrpm 등의 패키지 관리 시스템이 포함되어 있습니다. 하지만 이러한 관리 시스템이 APEX에 채택되지 않은 이유는 설치 이후에 패키지를 보호할 수 없기 때문입니다. 인증은 패키지가 설치되고 있는 동안에만 이루어집니다. 공격자는 설치된 패키지의 무결성을 몰래 아무도 모르게 훼손할 수 있습니다. 이는 모든 I/O의 dm-verity에 의해 무결성이 보호되는 읽기 전용 파일 시스템에 모든 시스템 구성요소가 저장되는 Android에서는 퇴행으로 볼 수 있습니다. 시스템 구성요소에 대한 모든 조작은 금지되어야 하거나 위험할 경우 기기에서 부팅을 거부할 수 있도록 감지 가능해야 합니다.

무결성을 위한 dm-crypt

APEX 컨테이너의 파일은 dm-verity에 의해 보호되는 내장 파티션(예: /system 파티션)에서 비롯됩니다. 여기서는 파티션이 마운트된 후에도 파일에 대한 수정이 금지됩니다. 파일에 대한 동일한 수준의 보안을 제공하기 위해 APEX의 모든 파일은 해시 트리 및 vbmeta 설명자로 페어링된 파일 시스템 이미지에 저장됩니다. dm-verity가 없으면 /data 파티션의 APEX는 인증 및 설치 후에 이루어진 의도되지 않은 수정에 취약해집니다.

실제로 /data 파티션은 dm-crypt와 같은 암호화 계층에 의해서도 보호됩니다. 이는 조작에 대한 어느 정도의 보호 효과를 제공하지만 기본적인 목적은 무결성이 아닌 개인정보 보호입니다. 공격자가 /data 파티션에 액세스하면 추가적인 보호 기능이 존재할 수 없으며, 마찬가지로 이는 /system 파티션에 있는 모든 시스템 구성요소에 비교하면 퇴행으로 볼 수 있습니다. APEX 파일 내의 해시 트리와 dm-verity는 동일한 수준의 콘텐츠 보호 효과를 제공합니다.

경로를 /system에서 /apex로 리디렉션

APEX에 패키징된 시스템 구성요소 파일은 /apex/<name>/lib/libfoo.so와 같은 새로운 경로를 통해 액세스 가능합니다. 파일이 /system의 일부였을 때는 /system/lib/libfoo.so 등의 경로를 통해 액세스 가능했습니다. APEX 파일의 클라이언트(다른 APEX 파일 또는 플랫폼)는 새 경로를 사용해야 합니다. 이러한 경로의 변경에는 기존 코드에 대한 업데이트가 필요할 수 있습니다.

경로 변경을 피할 수 있는 한 가지 방법은 APEX 파일의 파일 콘텐츠를 /system에 오버레이하는 것입니다. 하지만 Google이 /system 파티션에 파일을 오버레이하지 않기로 결정하는 이유는 오버레이되거나 심지어는 계속해서 중첩되는 파일의 수가 늘어나면서 성능에 부정적인 영향을 미칠 수 있다고 판단했기 때문입니다.

또 다른 방법은 /system으로 시작하는 경로가 /apex 아래의 해당하는 경로로 리디렉션되도록 open, statreadlink 등의 파일 액세스 함수를 도용하는 것입니다. 하지만 해당 경로를 허용하는 모든 함수를 변경하기가 현실적으로 불가능하므로 Google은 이 방법을 폐기했습니다. 예를 들어 일부 앱은 함수를 구현하는 Bionic을 정적으로 연결하며, 이 경우 리디렉션이 해당 앱에 대해 발생하지 않습니다.