รูปแบบไฟล์ APEX

รูปแบบคอนเทนเนอร์ 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

รูปแบบไฟล์ 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 และเป็นดังนี้

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

    1. ตรวจสอบไฟล์ APEX
    2. สร้างอุปกรณ์ย้อนกลับจากไฟล์ APEX
    3. สร้างอุปกรณ์ mapper block อุปกรณ์ที่ด้านบนของอุปกรณ์ loopback
    4. ติดตั้งอุปกรณ์บล็อกตัวทำแผนที่อุปกรณ์บนพาธเฉพาะ (เช่น /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 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 ในลักษณะเดียวกับที่คุณลงนาม 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 ดังต่อไปนี้:

  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

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 ที่ถูกบีบอัด

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 รองรับการบีบอัด zip แบบยุบเท่านั้น

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

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

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

พิจารณา /system/apex/com.android.foo.capex เป็น APEX ที่ถูกบีบอัดที่กำลังเปิดใช้งาน โดยมี versionCode 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 จะเปิดเผย 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 แบบคงที่ซึ่งใช้งานฟังก์ชันต่างๆ ในกรณีเช่นนี้ แอพเหล่านั้นจะไม่ถูกเปลี่ยนเส้นทาง