รูปแบบไฟล์ APEX

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

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

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

    1. ตรวจสอบไฟล์ APEX
    2. สร้างอุปกรณ์วนรอบจากไฟล์ APEX
    3. สร้างอุปกรณ์บล็อกตัวแมปอุปกรณ์ที่ด้านบนของอุปกรณ์วนรอบ
    4. เมาต์อุปกรณ์ 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 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 ของคีย์ รหัสของคีย์ที่ใช้ลงนามใน 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 ดังต่อไปนี้:

  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 ที่สร้างไว้ล่วงหน้า 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 ที่บีบอัด

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 รองรับเฉพาะการบีบอัด deflate-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 จะถูกเก็บไว้ในอิมเมจระบบไฟล์ที่จับคู่กับ 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 แบบคงที่ ซึ่งใช้งานฟังก์ชั่นต่างๆ ในกรณีดังกล่าว แอปเหล่านั้นจะไม่ถูกเปลี่ยนเส้นทาง