รูปแบบคอนเทนเนอร์ Android Pony EXpress (APEX) เปิดตัวใน Android 10 และใช้ในขั้นตอนการติดตั้งสำหรับข้อบังคับของระบบในระดับล่าง รูปแบบนี้ช่วยให้อัปเดตคอมโพเนนต์ของระบบที่ไม่เข้ากับรูปแบบแอปพลิเคชัน Android มาตรฐานได้ ตัวอย่างคอมโพเนนต์ ได้แก่ บริการและไลบรารีแบบเนทีฟ, เลเยอร์การแยกแยะฮาร์ดแวร์ (HAL), รันไทม์ (ART) และไลบรารีคลาส
คําว่า "APEX" อาจหมายถึงไฟล์ APEX ด้วย
ฉากหลัง
แม้ว่า Android จะรองรับการอัปเดตโมดูลที่เหมาะกับรูปแบบแอปมาตรฐาน (เช่น บริการ กิจกรรม) ผ่านแอปโปรแกรมติดตั้งแพ็กเกจ (เช่น แอป Google Play Store) แต่การใช้รูปแบบที่คล้ายกันสำหรับคอมโพเนนต์ระบบปฏิบัติการในระดับล่างมีข้อเสียดังนี้
- โมดูลที่อิงตาม APK จะใช้ในช่วงต้นของลําดับการบูตไม่ได้ เครื่องมือจัดการแพ็กเกจเป็นที่เก็บข้อมูลกลางเกี่ยวกับแอป และสามารถเริ่มต้นได้จากเครื่องมือจัดการกิจกรรมเท่านั้น ซึ่งจะพร้อมใช้งานในขั้นตอนถัดไปของกระบวนการบูต
- รูปแบบ APK (โดยเฉพาะไฟล์ Manifest) ออกแบบมาสำหรับแอป Android และอาจไม่เหมาะกับโมดูลระบบเสมอไป
การออกแบบ
ส่วนนี้อธิบายการออกแบบระดับสูงของรูปแบบไฟล์ APEX และเครื่องมือจัดการ APEX ซึ่งเป็นบริการที่จัดการไฟล์ APEX
ดูข้อมูลเพิ่มเติมเกี่ยวกับเหตุผลที่เลือกการออกแบบนี้สําหรับ APEX ได้ที่หัวข้อทางเลือกที่พิจารณาเมื่อพัฒนา APEX
รูปแบบ APEX
นี่คือรูปแบบของไฟล์ APEX
รูปที่ 1 รูปแบบไฟล์ APEX
ที่ระดับบนสุด ไฟล์ APEX คือไฟล์ ZIP ที่ระบบจัดเก็บไฟล์แบบไม่บีบอัดและอยู่ตรงขอบเขต 4 KB
ไฟล์ 4 ไฟล์ในไฟล์ APEX มีดังนี้
apex_manifest.json
AndroidManifest.xml
apex_payload.img
apex_pubkey
ไฟล์ apex_manifest.json
มีชื่อและเวอร์ชันของแพ็กเกจ ซึ่งจะระบุไฟล์ APEX ไฟล์นี้เป็นบัฟเฟอร์โปรโตคอลรูปแบบ JSON ของ ApexManifest
ไฟล์ AndroidManifest.xml
ช่วยให้ไฟล์ APEX ใช้เครื่องมือและโครงสร้างพื้นฐานที่เกี่ยวข้องกับ APK ได้ เช่น ADB, PackageManager และแอปตัวติดตั้งแพ็กเกจ (เช่น Play Store) เช่น ไฟล์ APEX สามารถใช้เครื่องมือที่มีอยู่ เช่น aapt
เพื่อตรวจสอบข้อมูลเมตาพื้นฐานจากไฟล์ ไฟล์จะมีชื่อแพ็กเกจและข้อมูลเวอร์ชัน โดยทั่วไปแล้วข้อมูลนี้ยังอยู่ใน apex_manifest.json
ด้วย
ขอแนะนําให้ใช้ apex_manifest.json
แทน AndroidManifest.xml
สําหรับโค้ดและระบบใหม่ที่ใช้ APEX AndroidManifest.xml
อาจมีข้อมูลเพิ่มเติมเกี่ยวกับการกำหนดเป้าหมายที่เครื่องมือเผยแพร่แอปที่มีอยู่สามารถใช้ได้
apex_payload.img
คืออิมเมจระบบไฟล์ ext4 ที่สำรองข้อมูลโดย dm-verity ระบบจะเมานต์อิมเมจเมื่อรันไทม์ผ่านอุปกรณ์ Loopback กล่าวโดยละเอียดคือ ระบบจะสร้าง Hash Tree และบล็อกข้อมูลเมตาโดยใช้ไลบรารี libavb
ระบบไม่แยกวิเคราะห์เพย์โหลดของระบบไฟล์ (เนื่องจากควรที่จะต่อเชื่อมรูปภาพได้) ไฟล์ปกติจะรวมอยู่ในไฟล์ apex_payload.img
apex_pubkey
คือคีย์สาธารณะที่ใช้ลงนามในภาพระบบไฟล์ ขณะรันไทม์
คีย์นี้ช่วยให้มั่นใจได้ว่า APEX ที่ดาวน์โหลดมาได้รับการลงนามโดยเอนทิตีเดียวกันกับที่ลงนาม APEX เดียวกันในพาร์ติชันในตัว
หลักเกณฑ์การตั้งชื่อ APEX
โปรดใช้หลักเกณฑ์การตั้งชื่อต่อไปนี้เพื่อช่วยป้องกันความขัดแย้งในการตั้งชื่อระหว่าง APEX ใหม่เมื่อแพลตฟอร์มพัฒนาขึ้น
com.android.*
- สงวนไว้สำหรับ APEX ของ AOSP ไม่ใช่รหัสเฉพาะของบริษัทหรืออุปกรณ์ใดๆ
com.<companyname>.*
- สงวนไว้สำหรับบริษัท มีแนวโน้มว่าอุปกรณ์หลายเครื่องจากบริษัทดังกล่าวจะใช้
com.<companyname>.<devicename>.*
- สงวนไว้สำหรับ APEX ที่ไม่ซ้ำกันสำหรับอุปกรณ์หนึ่งๆ (หรือกลุ่มย่อยของอุปกรณ์)
เครื่องมือจัดการ APEX
เครื่องมือจัดการ APEX (หรือ apexd
) เป็นกระบวนการแบบสแตนด์อโลนซึ่งมีหน้าที่ตรวจสอบ ติดตั้ง และถอนการติดตั้งไฟล์ APEX กระบวนการนี้จะเริ่มต้นและพร้อมใช้งานในช่วงต้นของลำดับการบูต โดยปกติแล้วระบบจะติดตั้งไฟล์ APEX ไว้ล่วงหน้าในอุปกรณ์ในส่วน /system/apex
โดยค่าเริ่มต้น เครื่องมือจัดการ APEX จะใช้แพ็กเกจเหล่านี้หากไม่มีการอัปเดต
ลำดับการอัปเดตของ APEX ใช้คลาส PackageManager ดังนี้
- ระบบจะดาวน์โหลดไฟล์ APEX ผ่านแอปตัวติดตั้งแพ็กเกจ, ADB หรือแหล่งที่มาอื่นๆ
- ตัวจัดการแพ็กเกจจะเริ่มขั้นตอนการติดตั้ง เมื่อทราบว่าไฟล์เป็น APEX เครื่องมือจัดการแพ็กเกจจะโอนการควบคุมไปยังเครื่องมือจัดการ APEX
- ผู้จัดการ APEX จะยืนยันไฟล์ APEX
- หากไฟล์ APEX ได้รับการยืนยัน ระบบจะอัปเดตฐานข้อมูลภายในของเครื่องมือจัดการ APEX เพื่อระบุว่าไฟล์ APEX จะเปิดใช้งานเมื่อบูตครั้งถัดไป
- ผู้ขอติดตั้งจะได้รับการแจ้งเตือนเมื่อยืนยันแพ็กเกจเรียบร้อยแล้ว
- คุณต้องรีบูตระบบเพื่อติดตั้งต่อ
เมื่อบูตครั้งถัดไป เครื่องมือจัดการ APEX จะเริ่มต้น อ่านฐานข้อมูลภายใน และทำสิ่งต่อไปนี้กับไฟล์ APEX แต่ละไฟล์ที่แสดง
- ยืนยันไฟล์ APEX
- สร้างอุปกรณ์ Loopback จากไฟล์ APEX
- สร้างอุปกรณ์บล็อกโปรแกรมแมปอุปกรณ์บนอุปกรณ์การวนกลับ
- ติดตั้งอุปกรณ์บล็อกโปรแกรมแมปอุปกรณ์ลงในเส้นทางที่ไม่ซ้ำกัน (เช่น
/apex/name@ver
)
เมื่อระบบเมานต์ไฟล์ APEX ทั้งหมดที่แสดงในฐานข้อมูลภายในแล้ว เครื่องมือจัดการ APEX จะให้บริการ Binder สำหรับคอมโพเนนต์อื่นๆ ของระบบเพื่อค้นหาข้อมูลเกี่ยวกับไฟล์ APEX ที่ติดตั้ง ตัวอย่างเช่น ส่วนประกอบอื่นๆ ของระบบสามารถค้นหารายการไฟล์ APEX ที่ติดตั้งในอุปกรณ์ หรือค้นหาเส้นทางที่แน่นอนซึ่งมีการต่อเชื่อม APEX หนึ่งๆ เพื่อให้เข้าถึงไฟล์ได้
ไฟล์ APEX คือไฟล์ APK
ไฟล์ APEX เป็นไฟล์ APK ที่ถูกต้องเนื่องจากเป็นไฟล์ ZIP ที่มีการรับรอง (โดยใช้รูปแบบลายเซ็น APK) ซึ่งมีไฟล์ AndroidManifest.xml
ซึ่งจะช่วยให้ไฟล์ APEX ใช้โครงสร้างพื้นฐานสำหรับไฟล์ APK ได้ เช่น แอปตัวติดตั้งแพ็กเกจ ยูทิลิตีการลงนาม และเครื่องมือจัดการแพ็กเกจ
ไฟล์ AndroidManifest.xml
ในไฟล์ APEX มีข้อมูลขั้นต่ำ ซึ่งประกอบด้วยแพ็กเกจ name
, versionCode
และ targetSdkVersion
(ไม่บังคับ), minSdkVersion
และ maxSdkVersion
สำหรับการกําหนดเป้าหมายแบบละเอียด ข้อมูลนี้ช่วยให้ส่งไฟล์ APEX ผ่านช่องทางที่มีอยู่ได้ เช่น แอปโปรแกรมติดตั้งแพ็กเกจและ ADB
ประเภทไฟล์ที่รองรับ
รูปแบบ APEX รองรับไฟล์ประเภทต่อไปนี้
- ไลบรารีที่แชร์แบบเนทีฟ
- ไฟล์ปฏิบัติการแบบเนทีฟ
- ไฟล์ JAR
- ไฟล์ข้อมูล
- ไฟล์การกําหนดค่า
แต่ไม่ได้หมายความว่า APEX จะอัปเดตไฟล์ทุกประเภทเหล่านี้ได้ ความสามารถในการอัปเดตประเภทไฟล์จะขึ้นอยู่กับแพลตฟอร์มและการกำหนดอินเทอร์เฟซสำหรับประเภทไฟล์ที่มีความเสถียรเพียงใด
ตัวเลือกการลงนาม
ไฟล์ APEX มีการเซ็นชื่อได้ 2 วิธี ก่อนอื่น ไฟล์ apex_payload.img
(โดยเฉพาะข้อบ่งชี้ vbmeta ที่ต่อท้าย apex_payload.img
) ได้รับการรับรองด้วยคีย์
จากนั้น APEX ทั้งหมดจะได้รับการรับรองโดยใช้APK Signature Scheme v3 กระบวนการนี้ใช้คีย์ 2 รายการที่แตกต่างกัน
ทางฝั่งอุปกรณ์จะมีการติดตั้งคีย์สาธารณะที่สอดคล้องกับคีย์ส่วนตัวที่ใช้ลงนามในข้อบ่งชี้ vbmeta เครื่องมือจัดการ APEX ใช้คีย์สาธารณะเพื่อยืนยัน APEX ที่ขอติดตั้ง APEX แต่ละรายการต้องลงนามด้วยคีย์ที่แตกต่างกันและบังคับใช้ทั้งในช่วงที่สร้างและรันไทม์
APEX ในพาร์ติชันในตัว
ไฟล์ APEX จะอยู่ในพาร์ติชันในตัว เช่น /system
พาร์ติชันอยู่เหนือ dm-verity อยู่แล้ว ระบบจึงจะต่อเชื่อมไฟล์ APEX โดยตรงผ่านอุปกรณ์ loopback
หากมี APEX ในพาร์ติชันในตัว คุณจะอัปเดต APEX ได้โดยการระบุแพ็กเกจ APEX ที่มีชื่อแพ็กเกจเดียวกันและรหัสเวอร์ชันที่มากกว่าหรือเท่ากับรหัสเวอร์ชันปัจจุบัน APEX ใหม่จะจัดเก็บไว้ใน /data
และเช่นเดียวกับ APK เวอร์ชันที่ติดตั้งใหม่จะแทนที่เวอร์ชันที่มีอยู่แล้วในพาร์ติชันในตัว แต่ APEX เวอร์ชันที่ติดตั้งใหม่จะเปิดใช้งานหลังจากรีบูตเท่านั้น ซึ่งต่างจาก APK
ข้อกำหนดเกี่ยวกับเคอร์เนล
หากต้องการรองรับโมดูลหลักของ APEX ในอุปกรณ์ Android คุณต้องมีฟีเจอร์เคอร์เนล Linux ต่อไปนี้ ไดรเวอร์ loopback และ dm-verity โปรแกรมควบคุมการวนซ้ำจะต่อเชื่อมอิมเมจระบบไฟล์ในโมดูล APEX และ dm-verity จะยืนยันโมดูล APEX
ประสิทธิภาพของไดรเวอร์ loopback และ dm-verity มีความสำคัญต่อประสิทธิภาพของระบบที่ดีเมื่อใช้โมดูล APEX
เวอร์ชันเคอร์เนลที่รองรับ
อุปกรณ์ที่ใช้เคอร์เนลเวอร์ชัน 4.4 ขึ้นไปรองรับโมดูล APEX หลัก อุปกรณ์ใหม่ที่ใช้ Android 10 ขึ้นไปต้องใช้เคอร์เนลเวอร์ชัน 4.9 ขึ้นไปเพื่อรองรับโมดูล APEX
การแก้ไขเคอร์เนลที่จำเป็น
การแก้ไขเคอร์เนลที่จำเป็นสำหรับการรองรับโมดูล APEX จะรวมอยู่ในต้นไม้ทั่วไปของ Android หากต้องการรับแพตช์ที่รองรับ APEX ให้ใช้เวอร์ชันล่าสุดของ Android Common Tree
เวอร์ชันเคอร์เนล 4.4
เวอร์ชันนี้ใช้ได้กับอุปกรณ์ที่อัปเกรดจาก Android 9 เป็น Android 10 เท่านั้นและต้องการสนับสนุนโมดูล APEX เราขอแนะนําอย่างยิ่งให้ผสานจากสาขา android-4.4
ลงเพื่อรับแพตช์ที่จําเป็น ต่อไปนี้คือรายการแพตช์แต่ละรายการที่จำเป็นสำหรับเคอร์เนลเวอร์ชัน 4.4
- UPSTREAM: loop: add ioctl for changing logical block size (4.4)
- BACKPORT: block/loop: set hw_sectors (4.4)
- UPSTREAM: loop: Add LOOP_SET_BLOCK_SIZE in compat ioctl (4.4)
- ANDROID: mnt: แก้ไข next_descendent (4.4)
- ANDROID: mnt: remount should propagate to slaves of slaves (4.4)
- ANDROID: mnt: Propagate remount correctly (4.4)
- เปลี่ยนกลับ "ANDROID: dm verity: add minimum prefetch size" (4.4)
- UPSTREAM: loop: drop caches if offset or block_size are changed (4.4)
เวอร์ชันเคอร์เนล 4.9/4.14/4.19
หากต้องการรับแพตช์ที่จำเป็นสำหรับเคอร์เนลเวอร์ชัน 4.9/4.14/4.19 ให้ผสานจากสาขา android-common
ตัวเลือกการกำหนดค่าเคอร์เนลที่จำเป็น
รายการต่อไปนี้แสดงข้อกำหนดการกำหนดค่าพื้นฐานสำหรับการรองรับโมดูล APEX ที่เปิดตัวใน Android 10 รายการที่มีเครื่องหมายดอกจัน (*) เป็นข้อกําหนดที่มีอยู่จาก 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
ส่วนนี้จะอธิบายวิธีสร้าง APEX โดยใช้ระบบการสร้างของ Android
ต่อไปนี้คือตัวอย่าง Android.bp
สำหรับ APEX ชื่อ apex.test
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 (/lib/arm สำหรับ ARM ที่แปลแล้วใน x86) |
ไฟล์สั่งการ | /bin |
ไลบรารี Java | /javalib |
รายการที่สร้างไว้ล่วงหน้า | /etc |
Dependency แบบทรานซิทีฟ
ไฟล์ APEX จะรวมการพึ่งพาแบบทรานซิทีฟของไลบรารีที่แชร์หรือไฟล์ปฏิบัติการแบบเนทีฟโดยอัตโนมัติ เช่น หาก libFoo
ขึ้นอยู่กับ libBar
ระบบจะรวมทั้ง 2 ไลบรารีเมื่อมีเพียง libFoo
แสดงอยู่ในพร็อพเพอร์ตี้ native_shared_libs
จัดการ ABI หลายรายการ
ติดตั้งพร็อพเพอร์ตี้ native_shared_libs
สําหรับทั้งอินเทอร์เฟซแบบไบนารีของแอปพลิเคชัน (ABI) หลักและรองของอุปกรณ์ หาก APEX กำหนดเป้าหมายเป็นอุปกรณ์ที่มี ABI เดียว (เช่น 32 บิตเท่านั้นหรือ 64 บิตเท่านั้น) ระบบจะติดตั้งเฉพาะไลบรารีที่มี ABI ที่เกี่ยวข้องเท่านั้น
ติดตั้งพร็อพเพอร์ตี้ binaries
สำหรับ ABI หลักของอุปกรณ์เท่านั้นตามที่อธิบายไว้ด้านล่าง
- หากอุปกรณ์เป็น 32 บิตเท่านั้น ระบบจะติดตั้งเฉพาะตัวแปร 32 บิตของไบนารี
- หากอุปกรณ์เป็น 64 บิตเท่านั้น ระบบจะติดตั้งเฉพาะตัวแปร 64 บิตของไบนารี
หากต้องการเพิ่มการควบคุม ABI ของไลบรารีและไบนารีแบบละเอียด ให้ใช้พร็อพเพอร์ตี้ multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries]
first
: ตรงกับ ABI หลักของอุปกรณ์ ซึ่งเป็นค่าเริ่มต้นสำหรับไฟล์ปฏิบัติการlib32
: ตรงกับ ABI 32 บิตของอุปกรณ์ หากรองรับlib64
: ตรงกับ ABI 64 บิตของอุปกรณ์ที่รองรับprefer32
: ตรงกับ ABI 32 บิตของอุปกรณ์ หากรองรับ หากระบบไม่รองรับ ABI 32 บิต ให้จับคู่กับ ABI 64 บิตboth
: ตรงกับ ABI ทั้ง 2 รายการ ซึ่งเป็นค่าเริ่มต้นสำหรับnative_shared_libraries
พร็อพเพอร์ตี้ java
, libraries
และ prebuilts
จะไม่สนใจ 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 โดยใช้คีย์ ระบบจะรวมคีย์สาธารณะไว้ใน APEX โดยอัตโนมัติโดยใช้ชื่อ avb_pubkey
# create an rsa key pairopenssl genrsa -out foo.pem 4096
# extract the public key from the key pairavbtool extract_public_key --key foo.pem --output foo.avbpubkey
# in Android.bpapex_key { name: "apex.test.key", public_key: "foo.avbpubkey", private_key: "foo.pem", }
ในตัวอย่างข้างต้น ชื่อของคีย์สาธารณะ (foo
) จะกลายเป็นรหัสของคีย์ รหัสของคีย์ที่ใช้ลงนามใน APEX จะเขียนอยู่ใน APEX ขณะรันไทม์ apexd
จะยืนยัน APEX โดยใช้คีย์สาธารณะที่มีรหัสเดียวกันในอุปกรณ์
การลงนาม APEX
ลงชื่อ APEX ในลักษณะเดียวกับการลงชื่อ APK ลงนาม APEX 2 ครั้ง โดยลงนาม 1 ครั้งสำหรับระบบไฟล์ขนาดเล็ก (ไฟล์ apex_payload.img
) และลงนาม 1 ครั้งสำหรับทั้งไฟล์
หากต้องการลงนามใน APEX ที่ระดับไฟล์ ให้ตั้งค่าพร็อพเพอร์ตี้ certificate
ด้วยวิธีใดวิธีหนึ่งต่อไปนี้
- ไม่ได้ตั้งค่า: หากไม่ได้ตั้งค่า ระบบจะเซ็นชื่อ APEX ด้วยใบรับรองที่อยู่ใน
PRODUCT_DEFAULT_DEV_CERTIFICATE
หากไม่ได้ตั้งค่า Flag ระบบจะใช้เส้นทางเป็นbuild/target/product/security/testkey
โดยค่าเริ่มต้น <name>
: APEX ลงนามด้วยใบรับรอง<name>
ในไดเรกทอรีเดียวกับPRODUCT_DEFAULT_DEV_CERTIFICATE
:<name>
: APEX ลงนามด้วยใบรับรองที่กำหนดโดยข้อบังคับ Soong ที่ชื่อ<name>
โมดูลใบรับรองสามารถกําหนดได้ดังนี้
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
หากตั้งค่า supportsRebootlessUpdate
เป็น true
ใน apex_manifest.json
และ APEX ที่ติดตั้งอยู่ในปัจจุบันไม่ได้ใช้งาน (เช่น บริการทั้งหมดใน APEX หยุดทำงานแล้ว) คุณจะติดตั้ง APEX ใหม่ได้โดยไม่ต้องรีบูตด้วย Flag --force-non-staged
adb install --force-non-staged apex_file_name
ใช้ APEX
หลังจากรีบูต ระบบจะต่อเชื่อม APEX ที่ไดเรกทอรี /apex/<apex_name>@<version>
คุณสามารถเมานต์ APEX เดียวกันหลายเวอร์ชันพร้อมกันได้
ในบรรดาเส้นทางการต่อเชื่อม เส้นทางที่สอดคล้องกับเวอร์ชันล่าสุดจะได้รับการต่อเชื่อมแบบ "การเชื่อมโยง" ที่ /apex/<apex_name>
ไคลเอ็นต์สามารถใช้เส้นทางที่ผูกไว้เพื่ออ่านหรือเรียกใช้ไฟล์จาก APEX
โดยทั่วไป APEX จะใช้ในกรณีต่อไปนี้
- OEM หรือ ODM จะโหลด APEX ไว้ล่วงหน้าในส่วน
/system/apex
เมื่อจัดส่งอุปกรณ์ - ไฟล์ใน APEX จะเข้าถึงได้ผ่านเส้นทาง
/apex/<apex_name>/
- เมื่อติดตั้ง APEX เวอร์ชันอัปเดตใน
/data/apex
แล้ว เส้นทางจะชี้ไปยัง APEX เวอร์ชันใหม่หลังจากรีบูต
อัปเดตบริการด้วย APEX
วิธีอัปเดตบริการโดยใช้ APEX
ทำเครื่องหมายบริการในพาร์ติชันระบบว่าอัปเดตได้ เพิ่มตัวเลือก
updatable
ลงในคำจำกัดความของบริการ/system/etc/init/myservice.rc: service myservice /system/bin/myservice class core user system ... updatable
สร้างไฟล์
.rc
ใหม่สำหรับบริการที่อัปเดต ใช้ตัวเลือกoverride
เพื่อกำหนดบริการที่มีอยู่ใหม่/apex/my.apex/etc/init.rc: service myservice /apex/my.apex/bin/myservice class core user system ... override
คุณจะกำหนดคำจำกัดความของบริการได้ในไฟล์ .rc
ของ APEX เท่านั้น 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 อย่างเต็มรูปแบบอาจไม่สามารถทำได้หรือดำเนินการไม่ได้ เช่น อาจมีการสร้างเคอร์เนลโดยไม่มี CONFIG_BLK_DEV_LOOP=Y
ซึ่งจำเป็นสำหรับการต่อเชื่อมอิมเมจระบบไฟล์ภายใน APEX
APEX แบบแบนคือ APEX ที่สร้างขึ้นเป็นพิเศษซึ่งเปิดใช้งานในอุปกรณ์ที่มีเคอร์เนลเดิมได้ ระบบจะติดตั้งไฟล์ใน APEX ที่ผสานรวมแล้วลงในไดเรกทอรีโดยตรงภายใต้พาร์ติชันในตัว เช่น lib/libFoo.so
ใน APEX ที่แปลงเป็นตาราง my.apex
ติดตั้งใน /system/apex/my.apex/lib/libFoo.so
การเปิดใช้งาน APEX ที่ยุบไม่ได้เกี่ยวข้องกับอุปกรณ์ Loop ไดเรกทอรี /system/apex/my.apex
ทั้งหมดจะได้รับการเชื่อมโยงโดยตรงกับ /apex/name@ver
คุณไม่สามารถอัปเดต APEX ที่ผสานแล้วโดยการดาวน์โหลด APEX เวอร์ชันอัปเดตจากเครือข่าย เนื่องจาก APEX ที่ดาวน์โหลดมาไม่สามารถผสานได้ APEX ที่ผสานรวมจะอัปเดตได้ผ่าน OTA ปกติเท่านั้น
APEX แบบแบนเป็นการกำหนดค่าเริ่มต้น ซึ่งหมายความว่า APEX ทั้งหมดจะได้รับการแปลงเป็นไฟล์เดียวโดยค่าเริ่มต้น เว้นแต่คุณจะกําหนดค่าอุปกรณ์อย่างชัดเจนเพื่อสร้าง APEX ที่ไม่ได้แปลงเป็นไฟล์เดียวเพื่อรองรับการอัปเดต APEX (ตามที่อธิบายไว้ข้างต้น)
ระบบไม่รองรับการผสม APEX แบบแบนและแบบไม่แบนในอุปกรณ์ APEX ในอุปกรณ์ต้องไม่ได้รับการแฟล็ททั้งหมดหรือได้รับการแฟล็ททั้งหมด
ซึ่งสำคัญอย่างยิ่งเมื่อจัดส่ง APEX ที่คอมไพล์ไว้ล่วงหน้าซึ่งลงชื่อไว้ล่วงหน้าสำหรับโปรเจ็กต์ เช่น Mainline APEX ที่ไม่ได้ลงนามล่วงหน้า (นั่นคือสร้างขึ้นจากแหล่งที่มา) ไม่ควรมีการยุบ และควรลงนามด้วยคีย์ที่เหมาะสม อุปกรณ์ควรรับค่าจาก updatable_apex.mk
ตามที่อธิบายไว้ในการอัปเดตบริการด้วย APEX
APEX ที่บีบอัด
Android 12 ขึ้นไปมีฟีเจอร์การบีบอัด APEX เพื่อลดผลกระทบต่อพื้นที่เก็บข้อมูลของแพ็กเกจ APEX ที่อัปเดตได้ หลังจากอัปเดต APEX แล้ว แม้ว่าจะไม่มีการใช้เวอร์ชันที่ติดตั้งไว้ล่วงหน้าอีกต่อไป แต่เวอร์ชันดังกล่าวจะยังคงใช้พื้นที่เท่าเดิม พื้นที่ที่ใช้งานอยู่จะยังคงไม่พร้อมใช้งาน
การบีบอัด APEX จะลดผลกระทบต่อพื้นที่เก็บข้อมูลนี้โดยใช้ชุดไฟล์ APEX ที่บีบอัดสูงในพาร์ติชันที่อ่านอย่างเดียว (เช่น พาร์ติชัน /system
) Android 12 ขึ้นไปใช้อัลกอริทึมการบีบอัด ZIP แบบ DEFLATE
การบีบอัดจะไม่เพิ่มประสิทธิภาพให้กับรายการต่อไปนี้
APEX ที่ใช้บูตซึ่งต้องได้รับการต่อเชื่อมในช่วงต้นของลำดับการบูต
APEX ที่อัปเดตไม่ได้ การบีบอัดจะมีประโยชน์ก็ต่อเมื่อมีการติดตั้ง APEX เวอร์ชันที่อัปเดตแล้วในพาร์ติชัน
/data
ดูรายการ APEX ที่อัปเดตได้ทั้งหมดได้ในหน้าคอมโพเนนต์ของระบบแบบโมดูลAPEX ของไลบรารีที่แชร์แบบไดนามิก เนื่องจาก
apexd
จะเปิดใช้งาน APEX ดังกล่าวทั้ง 2 เวอร์ชัน (ที่ติดตั้งไว้ล่วงหน้าและที่อัปเกรด) เสมอ การบีบอัดจึงไม่มีประโยชน์
รูปแบบไฟล์ APEX ที่บีบอัด
นี่คือรูปแบบของไฟล์ APEX ที่บีบอัด
รูปที่ 2 รูปแบบไฟล์ APEX ที่บีบอัด
ที่ระดับบนสุด ไฟล์ APEX ที่บีบอัดจะเป็นไฟล์ ZIP ที่มีไฟล์ APEX ต้นฉบับในรูปแบบที่ไม่มีการบีบอัดโดยมีระดับการบีบอัด 9 และไฟล์อื่นๆ ที่เก็บไว้โดยไม่มีการบีบอัด
ไฟล์ APEX ประกอบด้วยไฟล์ 4 ไฟล์ ได้แก่
original_apex
: มีการขยายไฟล์ด้วยระดับการบีบอัด 9 นี่คือไฟล์ APEX ต้นฉบับที่ไม่มีการบีบอัดapex_manifest.pb
: จัดเก็บเท่านั้นAndroidManifest.xml
: จัดเก็บเท่านั้นapex_pubkey
: จัดเก็บเท่านั้น
ไฟล์ apex_manifest.pb
, AndroidManifest.xml
และ apex_pubkey
เป็นสำเนาของไฟล์ที่เกี่ยวข้องใน original_apex
สร้าง APEX ที่บีบอัด
คุณสร้าง APEX ที่บีบอัดได้โดยใช้เครื่องมือ apex_compression_tool.py
ที่หัวข้อ
system/apex/tools
พารามิเตอร์หลายรายการที่เกี่ยวข้องกับการบีบอัด APEX มีอยู่ในระบบการสร้าง
ใน Android.bp
ความสามารถในการบีบอัดไฟล์ APEX จะควบคุมโดยพร็อพเพอร์ตี้ compressible
ดังนี้
apex {
name: "apex.test",
manifest: "apex_manifest.json",
file_contexts: "file_contexts",
compressible: true,
}
Flag ผลิตภัณฑ์ PRODUCT_COMPRESSED_APEX
จะควบคุมว่าอิมเมจระบบที่สร้างจากแหล่งที่มาต้องมีไฟล์ APEX ที่บีบอัดหรือไม่
สําหรับการทดสอบในเครื่อง คุณสามารถบังคับให้บิลด์บีบอัด APEX ได้โดยตั้งค่า OVERRIDE_PRODUCT_COMPRESSED_APEX=
เป็น true
ไฟล์ APEX ที่บีบอัดซึ่งระบบบิลด์สร้างขึ้นจะมีนามสกุล .capex
ส่วนขยายนี้ช่วยให้คุณแยกความแตกต่างระหว่างไฟล์ APEX เวอร์ชันที่บีบอัดและไม่บีบอัดได้ง่ายขึ้น
อัลกอริทึมการบีบอัดที่รองรับ
Android 12 รองรับเฉพาะการบีบอัด deflate-zip
เปิดใช้งานไฟล์ APEX ที่บีบอัดระหว่างการบูต
ก่อนที่จะเปิดใช้งาน APEX ที่บีบอัด ระบบจะแตกไฟล์ original_apex
ในไฟล์นั้นลงในไดเรกทอรี /data/apex/decompressed
ไฟล์ APEX ที่บีบอัดแล้วซึ่งได้จะลิงก์อย่างถาวรกับไดเรกทอรี /data/apex/active
ตัวอย่างต่อไปนี้เป็นภาพประกอบของกระบวนการที่อธิบายไว้ข้างต้น
ให้ถือว่า /system/apex/com.android.foo.capex
เป็น APEX ที่บีบอัดซึ่งเปิดใช้งานอยู่ โดยมีรหัสเวอร์ชัน 37
- ไฟล์
original_apex
ใน/system/apex/com.android.foo.capex
ได้รับการขยายไฟล์เป็น/data/apex/decompressed/com.android.foo@37.apex
restorecon /data/apex/decompressed/com.android.foo@37.apex
เพื่อตรวจสอบว่ามีป้ายกำกับ SELinux ที่ถูกต้อง- ระบบจะดำเนินการตรวจสอบการยืนยันใน
/data/apex/decompressed/com.android.foo@37.apex
เพื่อให้แน่ใจว่าถูกต้อง โดยapexd
จะตรวจสอบคีย์สาธารณะที่รวมอยู่ใน/data/apex/decompressed/com.android.foo@37.apex
เพื่อยืนยันว่าคีย์นั้นเท่ากับคีย์ที่รวมอยู่ใน/system/apex/com.android.foo.capex
- ไฟล์
/data/apex/decompressed/com.android.foo@37.apex
ลิงก์กับไดเรกทอรี/data/apex/active/com.android.foo@37.apex
แบบฮาร์ดลิงก์ - ตรรกะการเปิดใช้งานปกติสำหรับไฟล์ APEX ที่ไม่ได้บีบอัดจะดำเนินการใน
/data/apex/active/com.android.foo@37.apex
การโต้ตอบกับ OTA
ไฟล์ APEX ที่บีบอัดจะมีผลกับการนําส่ง OTA และแอปพลิเคชัน เนื่องจากอัปเดต OTA อาจประกอบด้วยไฟล์ APEX ที่บีบอัดซึ่งมีระดับเวอร์ชันสูงกว่าเวอร์ชันที่ใช้งานอยู่ในอุปกรณ์ คุณจึงต้องจองพื้นที่ว่างไว้ก่อนรีบูตอุปกรณ์เพื่อใช้การอัปเดต OTA
apexd
แสดง Binder API 2 รายการต่อไปนี้เพื่อรองรับระบบ OTA
calculateSizeForCompressedApex
- คํานวณขนาดที่จําเป็นสําหรับการขยายไฟล์ APEX ในแพ็กเกจ OTA ซึ่งสามารถใช้เพื่อยืนยันว่าอุปกรณ์มีพื้นที่เพียงพอก่อนที่จะดาวน์โหลด OTAreserveSpaceForCompressedApex
- สำรองพื้นที่ในดิสก์ไว้ใช้ในอนาคตโดยapexd
สำหรับการขยายไฟล์ APEX ที่บีบอัดภายในแพ็กเกจ OTA
ในกรณีของการอัปเดต OTA แบบ A/B apexd
จะพยายามทำการขยายไฟล์ในเบื้องหลังโดยเป็นส่วนหนึ่งของกิจวัตร OTA หลังการติดตั้ง หากการขยายไฟล์ไม่สำเร็จ apexd
จะทำการขยายไฟล์ระหว่างการบูตที่ใช้การอัปเดต OTA
ทางเลือกที่พิจารณาเมื่อพัฒนา APEX
ต่อไปนี้คือตัวเลือกบางส่วนที่ AOSP พิจารณาเมื่อออกแบบรูปแบบไฟล์ APEX และเหตุผลที่รวมหรือยกเว้นตัวเลือกเหล่านั้น
ระบบการจัดการแพ็กเกจทั่วไป
ดิสทริบิวชัน Linux มีระบบการจัดการแพ็กเกจอย่าง dpkg
และ rpm
ซึ่งมีประสิทธิภาพ สมบูรณ์แบบ และมีประสิทธิภาพ แต่ไม่ได้นำมาใช้ใน APEX เนื่องจากไม่สามารถปกป้องแพ็กเกจหลังจากการติดตั้ง ระบบจะดำเนินการยืนยันเมื่อติดตั้งแพ็กเกจเท่านั้น
ผู้โจมตีสามารถทำลายความสมบูรณ์ของแพ็กเกจที่ติดตั้งได้โดยที่ผู้ใช้ไม่รู้ตัว นี่เป็นกรณีถดถอยสำหรับ Android ที่คอมโพเนนต์ของระบบทั้งหมดจัดเก็บไว้ในระบบไฟล์แบบอ่านอย่างเดียวซึ่งความสมบูรณ์ได้รับการปกป้องโดย dm-verity สำหรับ I/O ทั้งหมด ต้องห้ามไม่ให้มีการเปลี่ยนแปลงใดๆ ในคอมโพเนนต์ของระบบ หรือต้องตรวจจับการเปลี่ยนแปลงได้เพื่อให้อุปกรณ์ปฏิเสธการบูตหากถูกบุกรุก
dm-crypt เพื่อความสมบูรณ์
ไฟล์ในคอนเทนเนอร์ APEX มาจากพาร์ติชันในตัว (เช่น พาร์ติชัน /system
) ที่ปกป้องโดย dm-verity ซึ่งไม่อนุญาตให้แก้ไขไฟล์แม้หลังจากมีการต่อเชื่อมพาร์ติชันแล้วก็ตาม ไฟล์ทั้งหมดใน APEX จะจัดเก็บไว้ในไฟล์ภาพระบบที่จับคู่กับ Hash Tree และตัวระบุ vbmeta เพื่อให้ไฟล์มีการรักษาความปลอดภัยในระดับเดียวกัน หากไม่มี DM-Verity นั้น APEX ในพาร์ติชัน /data
จะเสี่ยงต่อการแก้ไขโดยไม่ตั้งใจซึ่งเกิดขึ้นหลังจากได้รับการยืนยันและติดตั้งแล้ว
อันที่จริงแล้ว พาร์ติชัน /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
แต่ทีม Android ตัดสินใจที่จะไม่วางซ้อนไฟล์ในพาร์ติชัน /system
เนื่องจากอาจส่งผลต่อประสิทธิภาพเมื่อจำนวนไฟล์ที่วางซ้อน (หรืออาจซ้อนกันทีละไฟล์) เพิ่มขึ้น
อีกทางเลือกหนึ่งคือการลักลอบใช้ฟังก์ชันการเข้าถึงไฟล์ เช่น open
, stat
และ readlink
เพื่อให้ระบบเปลี่ยนเส้นทางเส้นทางที่ขึ้นต้นด้วย /system
ไปยังเส้นทางที่เกี่ยวข้องภายใต้ /apex
ทีม Android ทิ้งตัวเลือกนี้เนื่องจากไม่สามารถเปลี่ยนฟังก์ชันทั้งหมดที่ยอมรับเส้นทางได้
ตัวอย่างเช่น แอปบางแอปลิงก์ Bionic แบบคงที่ ซึ่งใช้ฟังก์ชันดังกล่าว
ในกรณีเช่นนี้ แอปเหล่านั้นจะไม่ได้รับการเปลี่ยนเส้นทาง