รูปแบบคอนเทนเนอร์ 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
ไฟล์สี่ไฟล์ในไฟล์ 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 รูปภาพถูกเมาท์ขณะรันไทม์ผ่านอุปกรณ์ย้อนกลับ โดยเฉพาะ แผนผังแฮชและบล็อกข้อมูลเมตาจะถูกสร้างขึ้นโดยใช้ไลบรารี libavb
เพย์โหลดของระบบไฟล์จะไม่ถูกแยกวิเคราะห์ (เนื่องจากรูปภาพควรสามารถติดตั้งได้) ไฟล์ปกติจะรวมอยู่ในไฟล์ apex_payload.img
apex_pubkey
เป็นกุญแจสาธารณะที่ใช้ในการลงนามอิมเมจระบบไฟล์ ณ รันไทม์ คีย์นี้ช่วยให้แน่ใจว่า APEX ที่ดาวน์โหลดนั้นได้รับการลงนามกับเอนทิตีเดียวกันกับที่ลงนาม APEX เดียวกันในพาร์ติชันในตัว
แนวทางการตั้งชื่อ APEX
เพื่อช่วยป้องกันความขัดแย้งในการตั้งชื่อระหว่าง APEXes ใหม่ในขณะที่แพลตฟอร์มก้าวหน้า ให้ใช้แนวทางการตั้งชื่อต่อไปนี้:
-
com.android.*
- สงวนไว้สำหรับ AOSP APEX ไม่ซ้ำกับบริษัทหรืออุปกรณ์ใดๆ
-
com.<companyname>.*
- สงวนไว้สำหรับบริษัท อาจถูกใช้งานโดยอุปกรณ์หลายเครื่องจากบริษัทนั้น
-
com.<companyname>.<devicename>.*
- สงวนไว้สำหรับ APEX เฉพาะสำหรับอุปกรณ์เฉพาะ (หรือชุดย่อยของอุปกรณ์)
ผู้จัดการเอเพ็กซ์
ตัวจัดการ APEX (หรือ apexd
) เป็นกระบวนการดั้งเดิมแบบสแตนด์อโลนที่รับผิดชอบในการตรวจสอบ ติดตั้ง และถอนการติดตั้งไฟล์ APEX กระบวนการนี้เปิดตัวและพร้อมตั้งแต่ช่วงเริ่มต้นของลำดับการบู๊ต โดยปกติไฟล์ APEX จะถูกติดตั้งไว้ล่วงหน้าบนอุปกรณ์ภายใต้ /system/apex
ตัวจัดการ APEX มีค่าเริ่มต้นให้ใช้แพ็คเกจเหล่านี้หากไม่มีการอัพเดต
ลำดับการอัปเดตของ APEX ใช้ คลาส PackageManager และเป็นดังนี้
- ไฟล์ APEX จะถูกดาวน์โหลดผ่านแอปติดตั้งแพ็คเกจ, ADB หรือแหล่งอื่นๆ
- ตัวจัดการแพ็คเกจเริ่มขั้นตอนการติดตั้ง เมื่อรับรู้ว่าไฟล์นั้นเป็น APEX ตัวจัดการแพ็คเกจจะถ่ายโอนการควบคุมไปยังตัวจัดการ APEX
- ผู้จัดการ APEX ตรวจสอบไฟล์ APEX
- หากไฟล์ APEX ได้รับการตรวจสอบแล้ว ฐานข้อมูลภายในของตัวจัดการ APEX จะได้รับการอัปเดตเพื่อแสดงว่าไฟล์ APEX ได้รับการเปิดใช้งานในการบูตครั้งถัดไป
- ผู้ร้องขอการติดตั้งจะได้รับการออกอากาศเมื่อการตรวจสอบแพ็คเกจสำเร็จ
- หากต้องการดำเนินการติดตั้งต่อ ต้องรีบูตระบบ
ในการบูตครั้งถัดไป ตัวจัดการ APEX จะเริ่มทำงาน อ่านฐานข้อมูลภายใน และดำเนินการต่อไปนี้สำหรับไฟล์ APEX แต่ละไฟล์ที่อยู่ในรายการ:
- ตรวจสอบไฟล์ APEX
- สร้างอุปกรณ์ย้อนกลับจากไฟล์ APEX
- สร้างอุปกรณ์ mapper block อุปกรณ์ที่ด้านบนของอุปกรณ์ loopback
- ติดตั้งอุปกรณ์บล็อกตัวทำแผนที่อุปกรณ์บนพาธเฉพาะ (เช่น
/apex/ name @ ver
)
เมื่อไฟล์ APEX ทั้งหมดที่อยู่ในฐานข้อมูลภายในถูกเมาท์แล้ว ตัวจัดการ APEX จะให้บริการเครื่องผูกสำหรับส่วนประกอบอื่นๆ ของระบบเพื่อสืบค้นข้อมูลเกี่ยวกับไฟล์ 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 มีการเซ็นชื่อได้สองวิธี ขั้นแรก ไฟล์ apex_payload.img
(โดยเฉพาะ ตัวอธิบาย vbmeta ต่อท้ายไฟล์ apex_payload.img
) จะถูกเซ็นชื่อด้วยคีย์ จากนั้น APEX ทั้งหมดจะถูกลงนามโดยใช้ APK Signature Scheme v3 มีการใช้คีย์ที่แตกต่างกันสองคีย์ในกระบวนการนี้
ที่ฝั่งอุปกรณ์ มีการติดตั้งคีย์สาธารณะที่สอดคล้องกับคีย์ส่วนตัวที่ใช้ในการลงนามตัวอธิบาย vbmeta ผู้จัดการ APEX ใช้กุญแจสาธารณะเพื่อตรวจสอบ APEX ที่ได้รับการร้องขอให้ติดตั้ง APEX แต่ละรายการจะต้องลงนามด้วยคีย์ที่แตกต่างกัน และบังคับใช้ทั้งในขณะสร้างและขณะรันไทม์
APEX ในพาร์ติชันในตัว
ไฟล์ APEX สามารถอยู่ในพาร์ติชันในตัว เช่น /system
พาร์ติชันอยู่เหนือ dm-verity แล้ว ดังนั้นไฟล์ APEX จึงถูกเมาท์โดยตรงบนอุปกรณ์ลูปแบ็ค
หากมี APEX อยู่ในพาร์ติชันในตัว คุณสามารถอัพเดต APEX ได้โดยจัดเตรียมแพ็คเกจ APEX ที่มีชื่อแพ็คเกจเดียวกันและมากกว่าหรือเท่ากับรหัสเวอร์ชัน APEX ใหม่จะถูกจัดเก็บไว้ใน /data
และเช่นเดียวกับ APK เวอร์ชันที่ติดตั้งใหม่จะซ่อนเวอร์ชันที่มีอยู่แล้วในพาร์ติชันในตัว แต่ต่างจาก APK ตรงที่ APEX เวอร์ชันที่ติดตั้งใหม่จะเปิดใช้งานหลังจากรีบูตเท่านั้น
ข้อกำหนดเคอร์เนล
เพื่อรองรับโมดูลเมนไลน์ APEX บนอุปกรณ์ Android จำเป็นต้องมีคุณสมบัติเคอร์เนล 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: วนซ้ำ: เพิ่ม ioctl สำหรับเปลี่ยนขนาดบล็อกลอจิคัล ( 4.4 )
- BACKPORT: บล็อก/วนซ้ำ: ตั้งค่า hw_sectors ( 4.4 )
- UPSTREAM: วนซ้ำ: เพิ่ม LOOP_SET_BLOCK_SIZE ใน compat ioctl ( 4.4 )
- Android: mnt: แก้ไข next_descendent ( 4.4 )
- Android: mnt: ติดตั้งใหม่ควรเผยแพร่ไปยังทาสของทาส ( 4.4 )
- ANDROID: mnt: เผยแพร่การติดตั้งใหม่อย่างถูกต้อง ( 4.4 )
- เปลี่ยนกลับ "ANDROID: dm verity: เพิ่มขนาดการดึงข้อมูลขั้นต่ำขั้นต่ำ" ( 4.4 )
- UPSTREAM: วนซ้ำ: วางแคชหากมีการเปลี่ยนแปลง offset หรือ block_size ( 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 build ต่อไปนี้เป็นตัวอย่างของ 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
ประเภทไฟล์ | ที่ตั้งในเอเพ็กซ์ |
---|---|
ห้องสมุดที่ใช้ร่วมกัน | /lib และ /lib64 ( /lib/arm สำหรับ arm ที่แปลใน x86) |
ปฏิบัติการได้ | /bin |
ไลบรารีจาวา | /javalib |
สร้างไว้ล่วงหน้า | /etc |
การพึ่งพาสกรรมกริยา
ไฟล์ APEX จะรวมการพึ่งพาสกรรมกริยาของ libs ที่ใช้ร่วมกันหรือไฟล์ปฏิบัติการโดยอัตโนมัติ ตัวอย่างเช่น หาก libFoo
ขึ้นอยู่กับ libBar
libs ทั้งสองจะถูกรวมไว้เมื่อมีเฉพาะ libFoo
ที่แสดงอยู่ในคุณสมบัติ native_shared_libs
จัดการ ABI หลายรายการ
ติดตั้งคุณสมบัติ native_shared_libs
สำหรับทั้ง Application Binary Interface (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 ทั้งสอง นี่เป็นค่าเริ่มต้นสำหรับnative_shared_libraries
คุณสมบัติ java
, libraries
และ prebuilts
เป็นแบบ ABI-agnostic
ตัวอย่างนี้ใช้กับอุปกรณ์ที่รองรับ 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
) จะกลายเป็น ID ของคีย์ ID ของคีย์ที่ใช้ในการลงนาม APEX นั้นเขียนไว้ใน APEX ขณะรันไทม์ apexd
จะตรวจสอบ APEX โดยใช้คีย์สาธารณะที่มี ID เดียวกันในอุปกรณ์
การลงนามเอเพ็กซ์
ลงนาม APEX ในลักษณะเดียวกับที่คุณลงนาม APK ลงชื่อ APEX สองครั้ง หนึ่งครั้งสำหรับระบบไฟล์ขนาดเล็ก (ไฟล์ apex_payload.img
) และหนึ่งครั้งสำหรับทั้งไฟล์
หากต้องการลงนาม APEX ที่ระดับไฟล์ ให้ตั้งค่าคุณสมบัติ certificate
ด้วยวิธีใดวิธีหนึ่งจาก 3 วิธีต่อไปนี้
- ไม่ได้ตั้งค่า: หากไม่มีการตั้งค่า 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_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
การบีบอัดไม่ได้เพิ่มประสิทธิภาพให้กับสิ่งต่อไปนี้:
Bootstrap APEXes ที่ต้องติดตั้งตั้งแต่เนิ่นๆ ในลำดับการบู๊ต
APEX ที่ไม่สามารถอัปเดตได้ การบีบอัดจะมีประโยชน์ก็ต่อเมื่อมีการติดตั้ง APEX เวอร์ชันอัปเดตบนพาร์ติชัน
/data
รายการ APEX ที่สามารถอัพเดตได้ทั้งหมดมีอยู่ในหน้า ส่วนประกอบระบบโมดูลาร์APEXes libs ที่ใช้ร่วมกันแบบไดนามิก เนื่องจาก
apexd
จะเปิดใช้งาน APEX ทั้งสองเวอร์ชันเสมอ (ติดตั้งไว้ล่วงหน้าและอัปเกรดแล้ว) การบีบอัดจึงไม่เพิ่มมูลค่า
รูปแบบไฟล์ APEX ที่ถูกบีบอัด
นี่คือรูปแบบของไฟล์ APEX ที่ถูกบีบอัด
รูปที่ 2 รูปแบบไฟล์ APEX ที่บีบอัด
ที่ระดับบนสุด ไฟล์ APEX ที่ถูกบีบอัดคือไฟล์ ZIP ที่บรรจุไฟล์ apex ดั้งเดิมในรูปแบบกิ่วโดยมีระดับการบีบอัด 9 และไฟล์อื่นๆ จะถูกเก็บไว้โดยไม่มีการบีบอัด
ไฟล์สี่ไฟล์ประกอบด้วยไฟล์ APEX:
-
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,
}
ธงผลิตภัณฑ์ PRODUCT_COMPRESSED_APEX
ควบคุมว่าอิมเมจระบบที่สร้างจากแหล่งที่มาต้องมีไฟล์ APEX ที่บีบอัดหรือไม่
สำหรับการทดลองในพื้นที่ คุณสามารถบังคับให้บิลด์บีบอัด APEX ได้โดยการตั้งค่า OVERRIDE_PRODUCT_COMPRESSED_APEX=
เป็น true
ไฟล์ APEX ที่ถูกบีบอัดที่สร้างโดยระบบบิลด์จะมีนามสกุล .capex
ส่วนขยายช่วยให้แยกความแตกต่างระหว่างไฟล์ APEX เวอร์ชันบีบอัดและไม่บีบอัดได้ง่ายขึ้น
อัลกอริธึมการบีบอัดที่รองรับ
Android 12 รองรับการบีบอัด 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
เพื่อรองรับระบบ OTA นั้น apexd
จะเปิดเผย Binder API ทั้งสองนี้:
-
calculateSizeForCompressedApex
- คำนวณขนาดที่จำเป็นในการขยายขนาดไฟล์ APEX ในแพ็คเกจ OTA ซึ่งสามารถใช้เพื่อตรวจสอบว่าอุปกรณ์มีพื้นที่เพียงพอก่อนที่จะดาวน์โหลด OTA -
reserveSpaceForCompressedApex
- สงวนพื้นที่บนดิสก์สำหรับการใช้งานในอนาคตโดยapexd
สำหรับการแตกไฟล์ APEX ที่บีบอัดภายในแพ็คเกจ OTA
ในกรณีของการอัปเดต A/B OTA apexd
จะพยายามคลายการบีบอัดในเบื้องหลังโดยเป็นส่วนหนึ่งของรูทีน OTA หลังการติดตั้ง หากการบีบอัดล้มเหลว apexd
จะดำเนินการคลายการบีบอัดระหว่างการบูตที่ใช้การอัปเดต OTA
ทางเลือกอื่นที่พิจารณาเมื่อพัฒนา APEX
ต่อไปนี้คือตัวเลือกบางส่วนที่ AOSP พิจารณาเมื่อออกแบบรูปแบบไฟล์ APEX และเหตุใดจึงรวมหรือแยกออก
ระบบการจัดการแพ็คเกจปกติ
ลีนุกซ์รุ่นต่างๆ มีระบบการจัดการแพ็คเกจ เช่น 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
แผนผังแฮชภายในไฟล์ 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 แบบคงที่ซึ่งใช้งานฟังก์ชันต่างๆ ในกรณีเช่นนี้ แอพเหล่านั้นจะไม่ถูกเปลี่ยนเส้นทาง