รูปแบบไฟล์ APEX

รูปแบบคอนเทนเนอร์ Android Pony EXpress (APEX) ถูกนำมาใช้ใน Android 10 และใช้ในขั้นตอนการติดตั้งสำหรับโมดูลระบบระดับล่าง รูปแบบนี้อำนวยความสะดวกในการอัปเดตส่วนประกอบของระบบที่ไม่เข้ากับรูปแบบแอปพลิเคชัน Android มาตรฐาน คอมโพเนนต์ตัวอย่างบางส่วน ได้แก่ บริการเนทีฟและไลบรารี เลเยอร์นามธรรมของฮาร์ดแวร์ ( HALs ) รันไทม์ ( ART ) และไลบรารีคลาส

คำว่า "APEX" ยังสามารถอ้างถึงไฟล์ APEX

พื้นหลัง

แม้ว่า Android จะสนับสนุนการอัปเดตโมดูลที่พอดีกับรุ่นแอปมาตรฐาน (เช่น บริการ กิจกรรม) ผ่านแอปตัวติดตั้งแพ็กเกจ (เช่น แอป Google Play Store) การใช้รุ่นที่คล้ายกันสำหรับส่วนประกอบระบบปฏิบัติการระดับล่างก็มีข้อเสียดังต่อไปนี้:

  • ไม่สามารถใช้โมดูลที่ใช้ APK ในช่วงต้นของลำดับการบู๊ต ตัวจัดการแพ็คเกจเป็นที่เก็บส่วนกลางของข้อมูลเกี่ยวกับแอพและสามารถเริ่มต้นได้จากตัวจัดการกิจกรรมเท่านั้น ซึ่งจะพร้อมในขั้นตอนต่อมาของขั้นตอนการบู๊ต
  • รูปแบบ APK (โดยเฉพาะไฟล์ Manifest) ออกแบบมาสำหรับแอป Android และโมดูลระบบอาจไม่เหมาะสมเสมอไป

ออกแบบ

ส่วนนี้อธิบายการออกแบบระดับสูงของรูปแบบไฟล์ APEX และตัวจัดการ 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

เพื่อช่วยป้องกันความขัดแย้งในการตั้งชื่อระหว่าง APEX ใหม่เมื่อแพลตฟอร์มก้าวหน้า ให้ใช้แนวทางการตั้งชื่อต่อไปนี้:

  • com.android.*
    • สงวนไว้สำหรับ AOSP APEXes ไม่ซ้ำกับบริษัทหรืออุปกรณ์ใดๆ
  • com.<companyname>.*
    • สงวนไว้สำหรับบริษัท อาจถูกใช้โดยอุปกรณ์หลายเครื่องจากบริษัทนั้น
  • com.<companyname>.<devicename>.*
    • สงวนไว้สำหรับ APEX เฉพาะสำหรับอุปกรณ์เฉพาะ (หรือชุดย่อยของอุปกรณ์)

ผู้จัดการเอเพ็กซ์

ผู้จัดการ APEX (หรือ apexd ) เป็นกระบวนการดั้งเดิมแบบสแตนด์อโลนที่รับผิดชอบในการตรวจสอบ ติดตั้ง และถอนการติดตั้งไฟล์ APEX กระบวนการนี้เริ่มทำงานและพร้อมตั้งแต่เนิ่นๆ ในลำดับการบู๊ต ไฟล์ APEX จะถูกติดตั้งไว้ล่วงหน้าบนอุปกรณ์ภายใต้ /system/apex ผู้จัดการ APEX เริ่มต้นใช้แพ็คเกจเหล่านี้หากไม่มีการอัปเดต

ลำดับการอัปเดตของ APEX ใช้ คลาส PackageManager และเป็นดังนี้

  1. ไฟล์ APEX ถูกดาวน์โหลดผ่านแอพตัวติดตั้งแพคเกจ, ADB หรือแหล่งอื่นๆ
  2. ตัวจัดการแพ็คเกจเริ่มขั้นตอนการติดตั้ง เมื่อทราบว่าไฟล์นั้นเป็น APEX ตัวจัดการแพ็คเกจจะถ่ายโอนการควบคุมไปยังตัวจัดการ APEX
  3. ผู้จัดการ APEX ตรวจสอบไฟล์ APEX
  4. หากไฟล์ APEX ได้รับการตรวจสอบแล้ว ฐานข้อมูลภายในของผู้จัดการ APEX จะได้รับการอัปเดตเพื่อแสดงว่าไฟล์ APEX ได้รับการเปิดใช้งานเมื่อบูตครั้งถัดไป
  5. ผู้ร้องขอการติดตั้งจะได้รับการออกอากาศเมื่อการตรวจสอบแพ็คเกจสำเร็จ
  6. หากต้องการดำเนินการติดตั้งต่อ ต้องรีบูตระบบ
  7. ในการบูตครั้งถัดไป ตัวจัดการ APEX จะเริ่มทำงาน อ่านฐานข้อมูลภายใน และดำเนินการต่อไปนี้สำหรับแต่ละไฟล์ APEX ที่แสดงรายการ:

    1. ตรวจสอบไฟล์ APEX
    2. สร้างอุปกรณ์ย้อนกลับจากไฟล์ APEX
    3. สร้างอุปกรณ์ mapper บล็อกอุปกรณ์ที่ด้านบนของอุปกรณ์ย้อนกลับ
    4. ติดตั้งอุปกรณ์ mapper block device บนเส้นทางเฉพาะ (เช่น /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 มีการเซ็นชื่อในสองวิธี ขั้นแรก ไฟล์ apex_payload.img (โดยเฉพาะอย่างยิ่ง vbmeta descriptor ที่ต่อท้ายไฟล์ 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 ในการรับแพตช์ที่จำเป็น ขอแนะนำให้ใช้ down-merge จาก android-4.4 branch ต่อไปนี้เป็นรายการของแพตช์ที่จำเป็นสำหรับเคอร์เนลเวอร์ชัน 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: 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 ทั้งสอง lib จะรวมอยู่ด้วยเมื่อเฉพาะ 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 pair
openssl genrsa -out foo.pem 4096

# extract the public key from the key pair
avbtool extract_public_key --key foo.pem --output foo.avbpubkey

# in Android.bp
apex_key {
    name: "apex.test.key",
    public_key: "foo.avbpubkey",
    private_key: "foo.pem",
}

ในตัวอย่างข้างต้น ชื่อของคีย์สาธารณะ ( foo ) จะกลายเป็น ID ของคีย์ ID ของคีย์ที่ใช้ในการลงนาม APEX นั้นเขียนไว้ใน APEX ที่รันไทม์ apexd ตรวจสอบ APEX โดยใช้รหัสสาธารณะที่มี ID เดียวกันในอุปกรณ์

การลงนาม APEX

ลงชื่อ 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

หาก 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 เดียวกันได้หลายเวอร์ชันพร้อมกัน ในบรรดาเส้นทางเมานต์ เส้นทางที่สอดคล้องกับเวอร์ชันล่าสุดคือ bind-mounted ที่ /apex/<apex_name>

ไคลเอนต์สามารถใช้พาธผูกมัดเพื่ออ่านหรือเรียกใช้ไฟล์จาก APEX

โดยทั่วไปจะใช้ APEX ดังต่อไปนี้:

  1. OEM หรือ ODM โหลด APEX ไว้ล่วงหน้าภายใต้ /system/apex เมื่อจัดส่งอุปกรณ์
  2. ไฟล์ใน APEX สามารถเข้าถึงได้ผ่านเส้นทาง /apex/<apex_name>/
  3. เมื่อมีการติดตั้ง APEX เวอร์ชันอัปเดตใน /data/apex เส้นทางจะชี้ไปที่ APEX ใหม่หลังจากรีบูต

อัปเดตบริการด้วย APEX

ในการอัปเดตบริการโดยใช้ APEX:

  1. ทำเครื่องหมายบริการในพาร์ติชันระบบว่าอัปเดตได้ เพิ่มตัวเลือก updatable กับข้อกำหนดของบริการ

    /system/etc/init/myservice.rc:
    
    service myservice /system/bin/myservice
        class core
        user system
        ...
        updatable
    
  2. สร้างไฟล์ .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 ที่สร้างไว้ล่วงหน้าสำหรับโครงการต่างๆ เช่น Mainline APEX ที่ไม่ได้กำหนดไว้ล่วงหน้า (นั่นคือ สร้างจากแหล่งที่มา) ควรไม่แบนและลงนามด้วยคีย์ที่เหมาะสม อุปกรณ์ควรสืบทอดมาจาก updatable_apex.mk ตามที่อธิบายไว้ใน การอัปเดตบริการด้วย APEX

APEX ที่ถูกบีบอัด

Android 12 และใหม่กว่ามีการบีบอัด APEX เพื่อลดผลกระทบของพื้นที่เก็บข้อมูลของแพ็คเกจ APEX ที่อัปเดตได้ หลังจากติดตั้งการอัปเดตเป็น APEX แล้ว แม้ว่าเวอร์ชันที่ติดตั้งไว้ล่วงหน้าจะไม่ได้ใช้อีกต่อไป แต่ก็ยังใช้พื้นที่เท่าเดิม พื้นที่ว่างนั้นยังไม่สามารถใช้งานได้

การบีบอัด APEX ช่วยลดผลกระทบของพื้นที่จัดเก็บนี้โดยใช้ชุดไฟล์ APEX ที่มีการบีบอัดสูงบนพาร์ติชันแบบอ่านอย่างเดียว (เช่น พาร์ติ /system ) Android 12 และใหม่กว่าใช้อัลกอริทึมการบีบอัดซิป DEFLATE

การบีบอัดไม่มีการเพิ่มประสิทธิภาพสิ่งต่อไปนี้:

  • Bootstrap APEXes ที่จำเป็นต้องติดตั้งตั้งแต่เนิ่นๆ ในลำดับการบูต

  • APEX ที่ไม่สามารถอัปเดตได้ การบีบอัดจะมีประโยชน์ก็ต่อเมื่อมีการติดตั้ง APEX เวอร์ชันอัปเดตบนพาร์ติชัน /data รายการทั้งหมดของ APEX ที่อัปเดตได้มีอยู่ที่หน้า ส่วนประกอบระบบโมดูลาร์

  • APEX libs ที่แชร์แบบไดนามิก เนื่องจาก apexd จะเปิดใช้งาน APEX ดังกล่าวทั้งสองเวอร์ชันเสมอ (ติดตั้งล่วงหน้าและอัปเกรดแล้ว) การบีบอัดจึงไม่ได้เพิ่มมูลค่า

รูปแบบไฟล์ APEX ที่บีบอัด

นี่คือรูปแบบของไฟล์ APEX ที่บีบอัด

Diagram shows the format of a compressed APEX file

รูปที่ 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 รองรับเฉพาะการบีบอัดซิปแบบยุบตัวเท่านั้น

เปิดใช้งานไฟล์ APEX ที่บีบอัดระหว่างการบู๊ต

ก่อนที่จะสามารถเปิดใช้งาน APEX ที่บีบอัดได้ ไฟล์ original_apex ที่อยู่ภายในนั้นจะถูกขยายไปยังไดเร็กทอรี /data/apex/decompressed ไฟล์ APEX ที่คลายการบีบอัดที่เป็นผลลัพธ์จะถูกฮาร์ดลิงก์ไปยังไดเร็กทอรี /data/apex/active

พิจารณาตัวอย่างต่อไปนี้เป็นภาพประกอบของกระบวนการที่อธิบายไว้ข้างต้น

พิจารณา /system/apex/com.android.foo.capex เป็น APEX ที่บีบอัดที่กำลังเปิดใช้งาน โดยมีรหัสเวอร์ชัน 37

  1. ไฟล์ original_apex ภายใน /system/apex/com.android.foo.capex ถูกแตกเป็น /data/apex/decompressed/com.android.foo@37.apex
  2. restorecon /data/apex/decompressed/com.android.foo@37.apex เพื่อยืนยันว่ามีป้ายกำกับ SELinux ที่ถูกต้อง
  3. การตรวจสอบการยืนยันจะดำเนินการใน /data/apex/decompressed/com.android.foo@37.apex เพื่อให้แน่ใจว่าถูกต้อง: apexd ตรวจสอบพับลิกคีย์ที่รวมอยู่ใน /data/apex/decompressed/com.android.foo@37.apex ถึง ตรวจสอบว่ามันเท่ากับที่รวมอยู่ใน /system/apex/com.android.foo.capex
  4. ไฟล์ /data/apex/decompressed/com.android.foo@37.apex ฮาร์ดลิงก์ไปยังไดเรกทอรี /data/apex/active/com.android.foo@37.apex
  5. ตรรกะการเปิดใช้งานปกติสำหรับไฟล์ APEX ที่ไม่บีบอัดจะดำเนินการใน /data/apex/active/com.android.foo@37.apex

การโต้ตอบกับ OTA

ไฟล์ APEX ที่ถูกบีบอัดมีผลกระทบต่อการส่งและแอปพลิเคชัน OTA เนื่องจากการอัปเดต OTA อาจมีไฟล์ APEX ที่ถูกบีบอัดซึ่งมีระดับเวอร์ชันที่สูงกว่าที่ใช้งานอยู่ในอุปกรณ์ จึงต้องมีการสงวนพื้นที่ว่างจำนวนหนึ่งก่อนที่จะรีบูตอุปกรณ์เพื่อใช้การอัปเดต OTA

เพื่อรองรับระบบ OTA apexd จะเปิดเผย API ของ Binder ทั้งสองนี้:

  • 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 แบบคงที่ ซึ่งนำฟังก์ชันไปใช้ ในกรณีเช่นนี้ แอปเหล่านั้นจะไม่ถูกเปลี่ยนเส้นทาง