รูปแบบคอนเทนเนอร์ 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 นี่คือบัฟเฟอร์โปรโตคอล ApexManifest
ในรูปแบบ JSON
ไฟล์ 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 รองรับไฟล์ประเภทต่อไปนี้
- Libs ที่แชร์แบบเนทีฟ
- ไฟล์ปฏิบัติการที่มาพร้อมเครื่อง
- ไฟล์ 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 ที่ติดตั้งใหม่หลังจากรีบูตเท่านั้น
ข้อกำหนดของเคอร์เนล
หากต้องการรองรับโมดูลหลักของ APEX ในอุปกรณ์ Android คุณต้องมีฟีเจอร์เคอร์เนล Linux ต่อไปนี้ ไดรเวอร์ loopback และ dm-verity ไดรเวอร์ Loopback จะต่อเชื่อมอิมเมจระบบไฟล์ในโมดูล APEX และ dm-verity จะยืนยันโมดูล APEX
ประสิทธิภาพของไดรเวอร์ Loopback และ dm-verity สำคัญต่อการบรรลุประสิทธิภาพการทำงานของระบบที่ดีเมื่อใช้โมดูล APEX
เวอร์ชันเคอร์เนลที่รองรับ
อุปกรณ์ที่ใช้เคอร์เนลเวอร์ชัน 4.4 ขึ้นไปรองรับโมดูล APEX หลัก อุปกรณ์ใหม่ที่เปิดตัวด้วย Android 10 ขึ้นไป ต้องใช้เคอร์เนลเวอร์ชัน 4.9 ขึ้นไปเพื่อรองรับโมดูล APEX
แพตช์ของเคอร์เนลที่จำเป็น
แพตช์เคอร์เนลที่จำเป็นสำหรับการรองรับโมดูล APEX จะรวมอยู่ในแผนผังทั่วไปของ Android หากต้องการรับแพตช์ที่รองรับ APEX ให้ใช้เวอร์ชันล่าสุดของ Android Common Tree
Kernel เวอร์ชัน 4.4
เวอร์ชันนี้ใช้ได้กับอุปกรณ์ที่อัปเกรดจาก Android 9 เป็น Android 10 เท่านั้นและต้องการสนับสนุนโมดูล APEX หากต้องการรับแพตช์ที่จำเป็น ขอแนะนำให้ผสานลงจาก Branch android-4.4
ต่อไปนี้เป็นรายการแพตช์แต่ละรายการที่จำเป็นสำหรับเคอร์เนลเวอร์ชัน 4.4
- UPSTREAM: ลูป: เพิ่ม ioctl สำหรับการเปลี่ยนขนาดบล็อกเชิงตรรกะ (4.4)
- BACKPORT: บล็อก/ลูป: ตั้งค่า hw_sectors (4.4)
- UPSTREAM: loop: Add LOOP_SET_BLOCK_SIZE in compat ioctl (4.4)
- ANDROID: mnt: แก้ไข next_descendent (4.4)
- ANDROID: mnt: การต่อเชื่อมใหม่ควรเผยแพร่ไปยังทาสของทาส (4.4)
- ANDROID: mnt: Propagate remount correctly (4.4)
- เปลี่ยนกลับ "ANDROID: เวอร์ชัน dm เวอร์ชัน: เพิ่มขนาดการดึงข้อมูลล่วงหน้าขั้นต่ำ" (4.4)
- UPSTREAM: loop: drop caches if offset or block_size are changed (4.4)
Kernel เวอร์ชัน 4.9/4.14/4.19
หากต้องการรับแพตช์ที่จำเป็นสำหรับเคอร์เนลเวอร์ชัน 4.9/4.14/4.19 ให้ผสานลงจาก Branch ของ 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
ข้อกำหนดพารามิเตอร์บรรทัดคำสั่ง Kernel
หากต้องการรองรับ 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 จะรวมทรัพยากร Dependency แบบทรานซิทีฟของไลบรารีที่ใช้ร่วมกันหรือไฟล์ปฏิบัติการในเครื่องโดยอัตโนมัติ เช่น หาก libFoo
ขึ้นอยู่กับ libBar
ระบบจะรวม Lib ทั้ง 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
ด้วยวิธีใดวิธีหนึ่งใน 3 วิธีต่อไปนี้
- ไม่ได้ตั้งค่า: หากไม่ได้ตั้งค่าไว้ 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 ที่แยกเป็นหลายรายการจะไม่เกี่ยวข้องกับอุปกรณ์วนซ้ำ ไดเรกทอรี /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 ที่ใช้บูตซึ่งต้องได้รับการต่อเชื่อมในช่วงต้นของลำดับการบูต
APEXes ที่ไม่สามารถอัปเดตได้ การบีบอัดจะมีประโยชน์ก็ต่อเมื่อมีการติดตั้ง APEX เวอร์ชันที่อัปเดตแล้วในพาร์ติชัน
/data
ดูรายการ APEX ที่อัปเดตได้ทั้งหมดได้ในหน้าคอมโพเนนต์ของระบบแบบโมดูลAPEXes ไลบรารีที่ใช้ร่วมกันแบบไดนามิก เนื่องจาก
apexd
เปิดใช้งาน APEX ดังกล่าวทั้ง 2 เวอร์ชันเสมอ (ที่ติดตั้งไว้ล่วงหน้าและที่อัปเกรด) การบีบอัดจึงไม่มีประโยชน์
รูปแบบไฟล์ APEX ที่บีบอัด
นี่คือรูปแบบของไฟล์ APEX ที่บีบอัด
รูปที่ 2 รูปแบบไฟล์ APEX ที่บีบอัด
ที่ระดับบนสุด ไฟล์ APEX ที่บีบอัดจะเป็นไฟล์ ZIP ที่มีไฟล์ APEX ต้นฉบับในรูปแบบที่ไม่มีการบีบอัดโดยมีระดับการบีบอัด 9 และไฟล์อื่นๆ ที่เก็บไว้โดยไม่มีการบีบอัด
ไฟล์ APEX 1 ไฟล์ประกอบด้วยไฟล์ 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
ว่าพร็อพเพอร์ตี้ compressible
จะควบคุมไฟล์ APEX ที่บีบอัดได้หรือไม่
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 จะจัดเก็บอยู่ในอิมเมจระบบไฟล์ที่จับคู่กับแฮชทรีและข้อบ่งชี้ vbmeta หากไม่มี DMEX แล้ว 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 ในเชิงสถิติ ซึ่งจะใช้ฟังก์ชันต่างๆ
ในกรณีดังกล่าว แอปเหล่านั้นจะไม่ถูกเปลี่ยนเส้นทาง