รูปแบบคอนเทนเนอร์ Android Pony EXpress (APEX) ถูกนำมาใช้ใน Android 10 และใช้ในโฟลว์การติดตั้งสำหรับโมดูลระบบระดับล่าง รูปแบบนี้อำนวยความสะดวกในการอัปเดตส่วนประกอบของระบบที่ไม่เข้ากับรุ่นแอปพลิเคชัน Android มาตรฐาน ส่วนประกอบตัวอย่างบางส่วน ได้แก่ บริการและไลบรารีดั้งเดิม เลเยอร์ที่เป็นนามธรรมของฮาร์ดแวร์ ( HAL ) รันไทม์ ( ART ) และไลบรารีคลาส
คำว่า "APEX" ยังหมายถึงไฟล์ APEX
พื้นหลัง
แม้ว่า Android จะรองรับการอัปเดตโมดูลที่พอดีกับรุ่นแอปมาตรฐาน (เช่น บริการ กิจกรรม) ผ่านแอปตัวติดตั้งแพ็กเกจ (เช่น แอป Google Play Store) การใช้รุ่นที่คล้ายกันสำหรับส่วนประกอบ OS ระดับล่างจะมีข้อเสียดังต่อไปนี้:
- ใช้โมดูลที่ใช้ 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
ไฟล์ 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
เพื่อช่วยป้องกันความขัดแย้งในการตั้งชื่อระหว่าง 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 ตรวจสอบไฟล์ APEX
- หากไฟล์ APEX ได้รับการตรวจสอบแล้ว ฐานข้อมูลภายในของตัวจัดการ APEX จะได้รับการอัปเดตเพื่อแสดงว่าไฟล์ APEX ถูกเปิดใช้งานในการบูตครั้งถัดไป
- ผู้ขอติดตั้งจะได้รับการถ่ายทอดเมื่อทำการตรวจสอบแพ็คเกจสำเร็จ
- หากต้องการทำการติดตั้งต่อ ต้องรีบูตระบบ
ในการบู๊ตครั้งถัดไป ตัวจัดการ APEX จะเริ่มทำงาน อ่านฐานข้อมูลภายใน และทำสิ่งต่อไปนี้สำหรับไฟล์ APEX แต่ละไฟล์ที่แสดง:
- ตรวจสอบไฟล์ APEX
- สร้างอุปกรณ์วนรอบจากไฟล์ APEX
- สร้างอุปกรณ์บล็อกตัวแมปอุปกรณ์ที่ด้านบนของอุปกรณ์วนรอบ
- เมาต์อุปกรณ์ mapper block device บนพาธเฉพาะ (เช่น
/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 รองรับประเภทไฟล์เหล่านี้:
- Native libs ที่ใช้ร่วมกัน
- ไฟล์ปฏิบัติการดั้งเดิม
- ไฟล์ JAR
- ไฟล์ข้อมูล
- ไฟล์คอนฟิก
ไม่ได้หมายความว่า APEX สามารถอัปเดตไฟล์ประเภทนี้ได้ทั้งหมด การจะอัพเดตประเภทไฟล์ได้หรือไม่นั้นขึ้นอยู่กับแพลตฟอร์มและความเสถียรของคำจำกัดความของอินเทอร์เฟซสำหรับประเภทไฟล์
การลงนาม
ไฟล์ APEX มีการลงนามในสองวิธี ขั้นแรก ไฟล์ apex_payload.img
(โดยเฉพาะ vbmeta descriptor ต่อท้าย apex_payload.img
) ถูกเซ็นชื่อด้วยคีย์ จากนั้น APEX ทั้งหมดจะถูกลงนามโดยใช้ รูปแบบลายเซ็น APK v3 กระบวนการนี้ใช้คีย์ที่แตกต่างกันสองปุ่ม
ที่ด้านอุปกรณ์ มีการติดตั้งคีย์สาธารณะที่สอดคล้องกับคีย์ส่วนตัวที่ใช้ในการลงนาม vbmeta descriptor ตัวจัดการ APEX ใช้กุญแจสาธารณะเพื่อตรวจสอบ APEX ที่ได้รับการร้องขอให้ติดตั้ง APEX แต่ละรายการต้องลงนามด้วยคีย์ที่แตกต่างกัน และบังคับใช้ทั้งในเวลาบิลด์และรันไทม์
APEX ในพาร์ติชั่นในตัว
ไฟล์ APEX สามารถอยู่ในพาร์ติชั่นในตัวเช่น /system
. พาร์ติชั่นอยู่เหนือ dm-verity อยู่แล้ว ดังนั้นไฟล์ APEX จะถูกเมาต์โดยตรงบนอุปกรณ์ลูปแบ็ค
หากมี APEX อยู่ในพาร์ติชั่นในตัว APEX สามารถอัพเดตได้โดยการจัดเตรียมแพ็คเกจ APEX ที่มีชื่อแพ็คเกจเดียวกันและมากกว่าหรือเท่ากับโค้ดเวอร์ชัน APEX ใหม่ถูกจัดเก็บไว้ใน /data
และคล้ายกับ APK เวอร์ชันที่ติดตั้งใหม่จะแสดงเงาเวอร์ชันที่มีอยู่แล้วในพาร์ติชันในตัว แต่ต่างจาก APK APEX เวอร์ชันที่ติดตั้งใหม่จะเปิดใช้งานหลังจากรีบูตเท่านั้น
ข้อกำหนดเคอร์เนล
เพื่อรองรับโมดูล APEX mainline บนอุปกรณ์ 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: block/loop: set hw_sectors ( 4.4 )
- UPSTREAM: วนซ้ำ: เพิ่ม LOOP_SET_BLOCK_SIZE ใน ioctl ที่เข้ากันได้ ( 4.4 )
- ANDROID: mnt: แก้ไข next_descendent ( 4.4 )
- ANDROID: mnt: remount ควรเผยแพร่ไปยังทาสของทาส ( 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 ต่อไปนี้เป็นตัวอย่างของ 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 |
การพึ่งพาสกรรมกริยา
ไฟล์ APEX จะรวมการพึ่งพาสกรรมกริยาของ libs ที่แชร์หรือไฟล์เรียกทำงานแบบเนทีฟโดยอัตโนมัติ ตัวอย่างเช่น หาก libFoo
ขึ้นอยู่กับ libBar
ทั้งสอง libs จะถูกรวมไว้เมื่อมีเพียง 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 ทั้งสอง นี่เป็นค่าเริ่มต้นสำหรับ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 ของคีย์ รหัสของคีย์ที่ใช้ลงนามใน APEX เขียนไว้ใน APEX ที่รันไทม์ apexd
ตรวจสอบ APEX โดยใช้กุญแจสาธารณะที่มี ID เดียวกันในอุปกรณ์
เซ็นไปรษณีย์
ลงนาม APEX ในลักษณะเดียวกับที่คุณลงนาม APK ลงนาม APEX สองครั้ง; หนึ่งครั้งสำหรับระบบไฟล์ขนาดเล็ก (ไฟล์ 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
การใช้ 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
Flattened 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 ที่สร้างไว้ล่วงหน้า APEX ที่ลงนามล่วงหน้าสำหรับโครงการต่างๆ เช่น Mainline APEX ที่ไม่ได้กำหนดไว้ล่วงหน้า (ซึ่งก็คือ สร้างขึ้นจากแหล่งที่มา) ไม่ควรทำให้แบนราบและลงนามด้วยคีย์ที่เหมาะสม อุปกรณ์ควรสืบทอดจาก updatable_apex.mk
ตามที่อธิบายไว้ใน การอัปเดตบริการด้วย APEX
APEX ที่บีบอัด
Android 12 และใหม่กว่ามีการบีบอัด APEX เพื่อลดผลกระทบของการจัดเก็บข้อมูลของแพ็คเกจ APEX ที่อัปเดตได้ หลังจากติดตั้งการอัปเดต APEX แล้ว แม้ว่าเวอร์ชันที่ติดตั้งไว้ล่วงหน้าจะไม่ได้ใช้อีกต่อไป แต่ก็ยังใช้พื้นที่ในปริมาณเท่าเดิม พื้นที่ที่ถูกครอบครองนั้นยังคงใช้งานไม่ได้
การบีบอัด APEX ช่วยลดผลกระทบของการจัดเก็บนี้โดยใช้ชุดไฟล์ APEX ที่มีการบีบอัดสูงในพาร์ติชันแบบอ่านอย่างเดียว (เช่น /system
) Android 12 และใหม่กว่าใช้อัลกอริธึมการบีบอัด DEFLATE zip
การบีบอัดไม่ได้ให้การเพิ่มประสิทธิภาพต่อไปนี้:
Bootstrap APEX ที่จำเป็นต้องต่อเชื่อมตั้งแต่เนิ่นๆ ในลำดับการบู๊ต
APEX ที่ไม่สามารถอัปเดตได้ การบีบอัดจะมีประโยชน์ก็ต่อเมื่อติดตั้ง APEX เวอร์ชันที่อัปเดตบนพาร์ติชั่น
/data
รายการทั้งหมดของ APEX ที่อัปเดตได้มีอยู่ในหน้า ส่วนประกอบของระบบโมดูลา ร์libs APEX ที่แชร์แบบไดนามิก เนื่องจาก
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 รองรับเฉพาะการบีบอัด 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
เพื่อรองรับระบบ 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 จะถูกเก็บไว้ในอิมเมจระบบไฟล์ที่จับคู่กับ hash tree และ vbmeta descriptor หากไม่มี 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 แบบคงที่ ซึ่งใช้งานฟังก์ชั่นต่างๆ ในกรณีดังกล่าว แอปเหล่านั้นจะไม่ถูกเปลี่ยนเส้นทาง