รูปแบบคอนเทนเนอร์ Android Pony EXpress (APEX) เปิดตัวใน Android 10 และใช้ในขั้นตอนการติดตั้งสำหรับโมดูลระบบระดับล่าง รูปแบบนี้ช่วยให้อัปเดตคอมโพเนนต์ของระบบที่ไม่พอดี กับโมเดลแอปพลิเคชัน Android มาตรฐานได้ ตัวอย่างคอมโพเนนต์บางอย่าง ได้แก่ บริการและไลบรารีเนทีฟ เลเยอร์การแยกฮาร์ดแวร์ (HAL) รันไทม์ (ART) และไลบรารีคลาส
คำว่า "APEX" ยังหมายถึงไฟล์ APEX ได้ด้วย
ฉากหลัง
แม้ว่า Android จะรองรับการอัปเดตโมดูลที่อยู่ในรูปแบบแอปมาตรฐาน (เช่น บริการ กิจกรรม) ผ่านแอปโปรแกรมติดตั้งแพ็กเกจ (เช่น แอป Google Play Store) แต่การใช้รูปแบบที่คล้ายกันสำหรับคอมโพเนนต์ของระบบปฏิบัติการระดับล่างจะมีข้อเสียดังนี้
- ใช้โมดูลที่อิงตาม APK ในช่วงต้นของลำดับการบูตไม่ได้ Package Manager เป็นที่เก็บข้อมูลส่วนกลางเกี่ยวกับแอปและจะเริ่มได้จาก Activity Manager เท่านั้น ซึ่งจะพร้อมใช้งานในขั้นตอนต่อๆ ไปของ กระบวนการบูต
- รูปแบบ 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.*
- สงวนไว้สำหรับ AOSP APEX ไม่เฉพาะเจาะจงกับบริษัทหรืออุปกรณ์ใดๆ
com.<companyname>.*
- สงวนไว้สำหรับบริษัท อุปกรณ์หลายเครื่องจากบริษัทนั้นอาจใช้ข้อมูลนี้
com.<companyname>.<devicename>.*
- สงวนไว้สำหรับ APEX ที่ไม่ซ้ำกันสำหรับอุปกรณ์เฉพาะ (หรือกลุ่มย่อยของอุปกรณ์)
ผู้จัดการ APEX
ตัวจัดการ APEX (หรือ apexd
) เป็นกระบวนการเนทีฟแบบสแตนด์อโลนที่รับผิดชอบ
การยืนยัน การติดตั้ง และการถอนการติดตั้งไฟล์ APEX กระบวนการนี้จะเปิดตัวและ
พร้อมใช้งานตั้งแต่ช่วงต้นของลำดับการบูต โดยปกติแล้วไฟล์ APEX จะได้รับการติดตั้งล่วงหน้าในอุปกรณ์ภายใต้ /system/apex
โดยค่าเริ่มต้น ตัวจัดการ APEX จะใช้แพ็กเกจเหล่านี้
หากไม่มีการอัปเดต
ลำดับการอัปเดตของ APEX ใช้ คลาส PackageManager และมีดังนี้
- ระบบจะดาวน์โหลดไฟล์ APEX ผ่านแอปโปรแกรมติดตั้งแพ็กเกจ, ADB หรือแหล่งที่มาอื่นๆ
- ตัวจัดการแพ็กเกจจะเริ่มขั้นตอนการติดตั้ง เมื่อตรวจพบว่าไฟล์เป็น APEX ตัวจัดการแพ็กเกจจะโอนการควบคุมไปยังตัวจัดการ APEX
- APEX Manager จะยืนยันไฟล์ APEX
- หากยืนยันไฟล์ APEX แล้ว ระบบจะอัปเดตฐานข้อมูลภายในของผู้จัดการ APEX เพื่อให้แสดงว่าไฟล์ APEX จะเปิดใช้งานในการบูตครั้งถัดไป
- ผู้ขอติดตั้งจะได้รับการออกอากาศเมื่อยืนยันแพ็กเกจสำเร็จ
- หากต้องการติดตั้งต่อ คุณต้องรีบูตระบบ
เมื่อบูตครั้งถัดไป ตัวจัดการ APEX จะเริ่มต้น อ่านฐานข้อมูลภายใน และทำ สิ่งต่อไปนี้สำหรับไฟล์ APEX แต่ละไฟล์ที่แสดง
- ยืนยันไฟล์ APEX
- สร้างอุปกรณ์ Loopback จากไฟล์ APEX
- สร้างอุปกรณ์บล็อก Device Mapper ที่ด้านบนของอุปกรณ์ Loopback
- ติดตั้งอุปกรณ์บล็อก Device Mapper ไปยังเส้นทางที่ไม่ซ้ำกัน (เช่น
/apex/name@ver
)
เมื่อติดตั้งไฟล์ APEX ทั้งหมดที่แสดงในฐานข้อมูลภายในแล้ว ตัวจัดการ APEX จะให้บริการ Binder เพื่อให้คอมโพเนนต์อื่นๆ ของระบบค้นหา ข้อมูลเกี่ยวกับไฟล์ APEX ที่ติดตั้ง ตัวอย่างเช่น คอมโพเนนต์อื่นๆ ของระบบ สามารถค้นหารายการไฟล์ APEX ที่ติดตั้งในอุปกรณ์หรือค้นหา เส้นทางที่แน่นอนซึ่งมีการติดตั้ง APEX ที่เฉพาะเจาะจง เพื่อให้เข้าถึงไฟล์ได้
ไฟล์ APEX คือไฟล์ APK
ไฟล์ APEX เป็นไฟล์ APK ที่ถูกต้องเนื่องจากเป็นไฟล์ ZIP ที่ลงนามแล้ว (ใช้
APK Signature Scheme) ซึ่งมีไฟล์ 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 mainline ในอุปกรณ์ Android คุณจะต้องมีฟีเจอร์เคอร์เนล Linux ต่อไปนี้ ได้แก่ ไดรเวอร์ Loopback และ dm-verity ไดรเวอร์ Loopback จะติดตั้งอิมเมจระบบไฟล์ในโมดูล APEX และ dm-verity จะยืนยันโมดูล APEX
ประสิทธิภาพของไดรเวอร์ Loopback และ dm-verity เป็นสิ่งสำคัญในการทำให้ระบบมีประสิทธิภาพดีเมื่อใช้โมดูล APEX
เวอร์ชันเคอร์เนลที่รองรับ
โมดูล APEX mainline รองรับในอุปกรณ์ที่ใช้เคอร์เนลเวอร์ชัน 4.4 ขึ้นไป อุปกรณ์ใหม่ที่เปิดตัวพร้อม Android 10 ขึ้นไป ต้องใช้เคอร์เนลเวอร์ชัน 4.9 ขึ้นไปเพื่อรองรับโมดูล APEX
แพตช์เคอร์เนลที่จำเป็น
แพตช์เคอร์เนลที่จำเป็นสำหรับการรองรับโมดูล APEX จะรวมอยู่ใน Android Common Tree หากต้องการรับแพตช์เพื่อรองรับ 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)
- ต้นทาง: loop: Add LOOP_SET_BLOCK_SIZE in compat ioctl (4.4)
- ANDROID: mnt: Fix next_descendent (4.4)
- ANDROID: mnt: remount should propagate to slaves of slaves (4.4)
- ANDROID: mnt: Propagate remount correctly (4.4)
- Revert "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 สำหรับ
อาร์มที่แปลแล้วใน x86) |
ไฟล์สั่งการ | /bin |
ไลบรารี Java | /javalib |
สำเร็จรูป | /etc |
ทรัพยากร Dependency แบบทรานซิทีฟ
ไฟล์ APEX จะรวมการอ้างอิงแบบทรานซิทีฟของไลบรารีที่แชร์แบบเนทีฟ
หรือไฟล์ที่เรียกใช้งานได้โดยอัตโนมัติ ตัวอย่างเช่น หาก 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
: ตรงกับทั้ง 2 ABI โดยตัวเลือกนี้จะเป็นค่าเริ่มต้นสำหรับ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 ครั้ง ครั้งหนึ่งสำหรับ
ระบบไฟล์ขนาดเล็ก (ไฟล์ apex_payload.img
) และอีกครั้งสำหรับทั้งไฟล์
หากต้องการลงนาม APEX ที่ระดับไฟล์ ให้ตั้งค่าพร็อพเพอร์ตี้ certificate
ด้วยวิธีใดวิธีหนึ่งต่อไปนี้
- ไม่ได้ตั้งค่า: หากไม่ได้ตั้งค่า ระบบจะลงนาม APEX ด้วยใบรับรองที่อยู่ใน
PRODUCT_DEFAULT_DEV_CERTIFICATE
หากไม่ได้ตั้งค่าแฟล็กไว้ เส้นทางจะเป็นค่าเริ่มต้น เป็น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 ใหม่ได้โดยไม่ต้องรีบูตด้วยแฟล็ก --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
การบีบอัดไม่ได้เพิ่มประสิทธิภาพให้กับรายการต่อไปนี้
Bootstrap APEX ที่ต้องติดตั้งในช่วงต้นๆ ของลำดับการบูต
APEX ที่อัปเดตไม่ได้ การบีบอัดจะมีประโยชน์ก็ต่อเมื่อมีการติดตั้ง APEX เวอร์ชันที่อัปเดตแล้ว ในพาร์ติชัน
/data
ดูรายการ APEX ทั้งหมดที่อัปเดตได้ในหน้าคอมโพเนนต์ของระบบแบบแยกส่วนAPEX ของไลบรารีที่แชร์แบบไดนามิก เนื่องจาก
apexd
จะเปิดใช้งาน APEX ทั้ง 2 เวอร์ชันเสมอ (ติดตั้งไว้ล่วงหน้าและอัปเกรด) การบีบอัดจึงไม่ได้เพิ่มคุณค่า
รูปแบบไฟล์ APEX ที่บีบอัด
นี่คือรูปแบบของไฟล์ APEX ที่บีบอัด
รูปที่ 2 รูปแบบไฟล์ APEX ที่บีบอัด
ที่ระดับบนสุด ไฟล์ APEX ที่บีบอัดคือไฟล์ ZIP ที่มีไฟล์ APEX ต้นฉบับในรูปแบบที่บีบอัดด้วยระดับการบีบอัด 9 และมีไฟล์อื่นๆ ที่จัดเก็บโดยไม่มีการบีบอัด
ไฟล์ APEX ประกอบด้วยไฟล์ 4 ไฟล์ดังนี้
original_apex
: deflated with compression level of 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,
}
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 ที่บีบอัดซึ่งกำลัง
เปิดใช้งาน โดยมี versionCode 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 ซึ่งใช้เพื่อยืนยันว่าอุปกรณ์มีพื้นที่เพียงพอก่อนที่จะดาวน์โหลด OTA ได้reserveSpaceForCompressedApex
- จองพื้นที่ในดิสก์เพื่อใช้ในอนาคต โดย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 เพื่อให้ไฟล์มี
ระดับความปลอดภัยเดียวกัน หากไม่มี dm-verity APEX ในพาร์ติชัน /data
จะเสี่ยงต่อการแก้ไขโดยไม่ตั้งใจ
ซึ่งเกิดขึ้นหลังจากที่ได้รับการยืนยันและติดตั้งแล้ว
ในความเป็นจริงแล้ว /data
พาร์ติชันยังได้รับการปกป้องโดยเลเยอร์การเข้ารหัส เช่น
dm-crypt แม้ว่าการดำเนินการนี้จะช่วยป้องกันการดัดแปลงได้ในระดับหนึ่ง แต่
วัตถุประสงค์หลักคือความเป็นส่วนตัว ไม่ใช่ความสมบูรณ์ เมื่อผู้โจมตีได้รับสิทธิ์เข้าถึงพาร์ติชัน
/data
จะไม่มีการป้องกันเพิ่มเติม และนี่ก็เป็นอีกครั้งที่
การถดถอยเมื่อเทียบกับคอมโพเนนต์ของระบบทุกรายการที่อยู่ในพาร์ติชัน /system
Hash Tree ภายในไฟล์ 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 แบบคงที่ ซึ่งจะใช้ฟังก์ชันต่างๆ
ในกรณีดังกล่าว ระบบจะไม่เปลี่ยนเส้นทางแอปเหล่านั้น