คุณสามารถใช้รูปแบบไฟล์ APEX เพื่อแพ็กเกจและติดตั้งโมดูลระบบปฏิบัติการ Android ระดับล่าง ซึ่งช่วยให้สามารถบิลด์และติดตั้งคอมโพเนนต์ต่างๆ เช่น บริการและไลบรารีแบบเนทีฟ การใช้งาน HAL, เฟิร์มแวร์, ไฟล์การกําหนดค่า ฯลฯ ได้อย่างอิสระ
ระบบบิลด์จะติดตั้ง APEX ของผู้ให้บริการโดยอัตโนมัติในพาร์ติชัน /vendor
และ apexd
จะเปิดใช้งาน APEX ดังกล่าวเมื่อรันไทม์ เช่นเดียวกับ APEX ในพาร์ติชันอื่นๆ
กรณีการใช้งาน
การจัดโมดูลรูปภาพของผู้ขาย
APEX ช่วยให้การรวมกลุ่มและการจัดโมดูลการติดตั้งใช้งานฟีเจอร์ในรูปภาพผู้ให้บริการเป็นไปอย่างเป็นธรรมชาติ
เมื่อสร้างภาพผู้ให้บริการโดยรวม APEX ของผู้ให้บริการที่สร้างขึ้นอิสระ ผู้ผลิตอุปกรณ์จะเลือกและเลือกการใช้งานผู้ให้บริการที่ต้องการในอุปกรณ์ของตนได้อย่างง่ายดาย ผู้ผลิตยังสร้าง APEX ใหม่ของผู้ให้บริการได้หาก APEX ที่ระบุไว้ไม่ตรงกับความต้องการ หรือมีฮาร์ดแวร์ที่กำหนดเองใหม่
ตัวอย่างเช่น OEM อาจเลือกที่จะประกอบอุปกรณ์ด้วย APEX การติดตั้งใช้งาน Wi-Fi ของ AOSP, APEX การติดตั้งใช้งานบลูทูธของ SoC และ APEX การติดตั้งใช้งานโทรศัพท์ของ OEM ที่กําหนดเอง
หากไม่มี APEX ของผู้ให้บริการ การติดตั้งใช้งานที่ต้องใช้คอมโพเนนต์ของผู้ให้บริการจำนวนมากจะต้องมีการประสานงานและติดตามอย่างละเอียด การรวมคอมโพเนนต์ทั้งหมด (รวมถึงไฟล์การกําหนดค่าและไลบรารีเพิ่มเติม) ใน APEX ที่มีอินเทอร์เฟซที่กําหนดไว้อย่างชัดเจน ณ จุดใดก็ได้ของการสื่อสารข้ามฟีเจอร์ จะทำให้คอมโพเนนต์ต่างๆ ใช้แทนกันได้
การทำซ้ำสำหรับนักพัฒนาแอป
APEX ของผู้ให้บริการช่วยให้นักพัฒนาซอฟต์แวร์ปรับปรุงได้เร็วขึ้นขณะพัฒนาโมดูลของผู้ให้บริการด้วยการจัดกลุ่มการใช้งานฟีเจอร์ทั้งหมด เช่น HAL ของ Wi-Fi ไว้ใน APEX ของผู้ให้บริการ จากนั้นนักพัฒนาซอฟต์แวร์จะสร้างและพุช APEX ของผู้ให้บริการทีละรายการเพื่อทดสอบการเปลี่ยนแปลงได้ แทนที่จะต้องสร้างภาพผู้ให้บริการทั้งหมดขึ้นมาใหม่
วิธีนี้ช่วยให้นักพัฒนาแอปทำรอบการปรับปรุงได้ง่ายและรวดเร็วขึ้นสำหรับนักพัฒนาแอปที่ทำงานในพื้นที่ฟีเจอร์หนึ่งเป็นหลักและต้องการทำซ้ำในพื้นที่ฟีเจอร์นั้นๆ เท่านั้น
การรวมพื้นที่ฟีเจอร์เข้ากับ APEX อย่างเป็นธรรมชาติยังช่วยลดความซับซ้อนของการสร้าง การพุช และการทดสอบการเปลี่ยนแปลงสําหรับพื้นที่ฟีเจอร์นั้นด้วย ตัวอย่างเช่น การติดตั้ง APEX อีกครั้งจะอัปเดตไลบรารีหรือไฟล์การกําหนดค่าที่รวมอยู่ใน APEX โดยอัตโนมัติ
การรวมพื้นที่ฟีเจอร์ไว้ใน APEX ยังช่วยให้การแก้ไขข้อบกพร่องหรือการย้อนกลับง่ายขึ้นเมื่อพบลักษณะการทำงานที่ไม่ถูกต้องของอุปกรณ์ ตัวอย่างเช่น หากการโทรทำงานได้ไม่ดีในบิลด์ใหม่ นักพัฒนาแอปอาจลองติดตั้ง APEX การติดตั้งใช้งานการโทรเวอร์ชันเก่าในอุปกรณ์ (โดยไม่ต้องแฟลชบิลด์แบบสมบูรณ์) และดูว่าลักษณะการทำงานกลับมาเป็นปกติหรือไม่
ตัวอย่างเวิร์กโฟลว์
# Build the entire device and flash. OR, obtain an already-flashed device.
source build/envsetup.sh && lunch oem_device-userdebug
m
fastboot flashall -w
# Test the device.
... testing ...
# Check previous behavior using a vendor APEX from one week ago, downloaded from
# your continuous integration build.
... download command ...
adb install <path to downloaded APEX>
adb reboot
... testing ...
# Edit and rebuild just the APEX to change and test behavior.
... edit APEX source contents ...
m <apex module name>
adb install out/<path to built APEX>
adb reboot
... testing ...
ตัวอย่าง
ข้อมูลเบื้องต้น
ดูข้อมูลทั่วไปของ APEX ได้ที่หน้ารูปแบบไฟล์ APEX หลัก ซึ่งรวมถึงข้อกําหนดของอุปกรณ์ รายละเอียดรูปแบบไฟล์ และขั้นตอนการติดตั้ง
ใน Android.bp
การตั้งค่าพร็อพเพอร์ตี้ vendor: true
จะทำให้โมดูล APEX เป็น APEX ของผู้ให้บริการ
apex {
..
vendor: true,
..
}
ไฟล์ไบนารีและไลบรารีที่ใช้ร่วมกัน
APEX มีการพึ่งพาแบบทรานซิทีฟภายในเพย์โหลด APEX เว้นแต่จะมีอินเทอร์เฟซที่เสถียร
อินเทอร์เฟซแบบเนทีฟที่เสถียรสำหรับทรัพยากร Dependency ของ APEX ของผู้ให้บริการ ได้แก่ cc_library
with
stubs
และไลบรารี LLNDK ระบบจะไม่รวมไฟล์เหล่านี้ไว้ในแพ็กเกจ และระบบจะบันทึกไฟล์เหล่านี้ไว้ในไฟล์ Manifest ของ APEX linkerconfig
จะประมวลผลไฟล์ Manifest เพื่อให้การอ้างอิงภายนอกแบบเนทีฟพร้อมใช้งานเมื่อรันไทม์
ในข้อมูลโค้ดต่อไปนี้ APEX มีทั้งไฟล์ไบนารี (my_service
) และไฟล์ที่ต้องพึ่งพาซึ่งไม่เสถียร (*.so
)
apex {
..
vendor: true,
binaries: ["my_service"],
..
}
ในข้อมูลโค้ดต่อไปนี้ APEX มีไลบรารีที่แชร์
my_standalone_lib
และ Dependency ที่ไม่เสถียร (ตามที่อธิบายไว้ข้างต้น)
apex {
..
vendor: true,
native_shared_libs: ["my_standalone_lib"],
..
}
ทำให้ APEX เล็กลง
APEX อาจมีขนาดเพิ่มขึ้นเนื่องจากมีการรวมแพ็กเกจของไลบรารีที่ไม่เสถียร เราขอแนะนําให้ใช้การลิงก์แบบคงที่ ไลบรารีทั่วไป เช่น libc++.so
และ libbase.so
สามารถลิงก์แบบคงที่กับไบนารี HAL ได้ การสร้างการพึ่งพาเพื่อมอบอินเทอร์เฟซที่เสถียรอาจเป็นอีกทางเลือกหนึ่ง ระบบจะไม่รวมไฟล์แนบใน APEX
การใช้งาน HAL
หากต้องการกําหนดการใช้งาน HAL ให้ระบุไบนารีและไลบรารีที่เกี่ยวข้องภายใน APEX ของผู้ให้บริการซึ่งคล้ายกับตัวอย่างต่อไปนี้
APEX ควรระบุข้อมูลโค้ด VINTF ที่เกี่ยวข้องและสคริปต์เริ่มต้นด้วย เพื่อรวมการใช้งาน HAL อย่างสมบูรณ์
ข้อมูล VINTF บางส่วน
คุณสามารถแสดงข้อมูลโค้ด VINTF จาก APEX ของผู้ให้บริการได้เมื่อข้อมูลโค้ดอยู่ในetc/vintf
ของ APEX
ใช้พร็อพเพอร์ตี้ prebuilts
เพื่อฝังข้อมูลโค้ด VINTF ใน APEX
apex {
..
vendor: true,
prebuilts: ["fragment.xml"],
..
}
prebuilt_etc {
name: "fragment.xml",
src: "fragment.xml",
sub_dir: "vintf",
}
Query API
เมื่อเพิ่มข้อมูลโค้ด VINTF ลงใน APEX ให้ใช้ libbinder_ndk
API เพื่อรับการแมปอินเทอร์เฟซ HAL และชื่อ APEX
AServiceManager_isUpdatableViaApex("com.android.foo.IFoo/default")
:true
หากมีการกําหนดอินสแตนซ์ HAL ใน APEXAServiceManager_getUpdatableApexName("com.android.foo.IFoo/default", ...)
: รับชื่อ APEX ซึ่งกําหนดอินสแตนซ์ HALAServiceManager_openDeclaredPassthroughHal("mapper", "instance", ...)
: ใช้เพื่อเปิด HAL แบบส่งผ่าน
สคริปต์เริ่มต้น
APEX สามารถใส่สคริปต์เริ่มต้นได้ 2 วิธี ได้แก่ (ก) ไฟล์ข้อความที่สร้างไว้ล่วงหน้าภายในเพย์โหลด APEX หรือ (ข) สคริปต์เริ่มต้นปกติใน /vendor/etc
คุณตั้งค่าทั้ง 2 รายการสําหรับ APEX เดียวกันได้
สคริปต์เริ่มต้นใน APEX
prebuilt_etc {
name: "myinit.rc",
src: "myinit.rc"
}
apex {
..
vendor: true,
prebuilts: ["myinit.rc"],
..
}
สคริปต์เริ่มต้นใน APEX ของผู้ให้บริการอาจมีservice
คําจํากัดความและ
on <property or event>
คําสั่ง
ตรวจสอบว่าคําจํากัดความ service
ชี้ไปยังไบนารีใน APEX เดียวกัน
เช่น com.android.foo
APEX อาจกำหนดบริการชื่อ foo-service
on foo-service /apex/com.android.foo/bin/foo
...
โปรดระมัดระวังเมื่อใช้คำสั่ง on
เนื่องจากสคริปต์ init ใน APEX จะได้รับการแยกวิเคราะห์และดำเนินการหลังจากเปิดใช้งาน APEX คุณจึงใช้เหตุการณ์หรือพร็อพเพอร์ตี้บางอย่างไม่ได้ ใช้ apex.all.ready=true
เพื่อเริ่มการดำเนินการโดยเร็วที่สุด
APEX ที่ใช้ Bootstrap สามารถใช้ on init
ได้ แต่ไม่สามารถใช้ on early-init
เฟิร์มแวร์
ตัวอย่าง
ฝังเฟิร์มแวร์ใน APEX ของผู้ให้บริการที่มีประเภทโมดูล prebuilt_firmware
ดังนี้
prebuilt_firmware {
name: "my.bin",
src: "path_to_prebuilt_firmware",
vendor: true,
}
apex {
..
vendor: true,
prebuilts: ["my.bin"], // installed inside APEX as /etc/firmware/my.bin
..
}
ติดตั้งโมดูล prebuilt_firmware
ในไดเรกทอรี <apex name>/etc/firmware
ของ APEX ueventd
จะสแกนไดเรกทอรี /apex/*/etc/firmware
เพื่อค้นหาโมดูลเฟิร์มแวร์
file_contexts
ของ APEX ควรติดป้ายกำกับรายการเพย์โหลดของเฟิร์มแวร์อย่างถูกต้องเพื่อให้ ueventd
เข้าถึงไฟล์เหล่านี้ได้เมื่อรันไทม์ โดยปกติแล้วป้ายกำกับ vendor_file
ก็เพียงพอแล้ว เช่น
(/.*)? u:object_r:vendor_file:s0
โมดูลเคอร์เนล
ฝังโมดูลเคอร์เนลใน APEX ของผู้ให้บริการเป็นโมดูลที่สร้างไว้ล่วงหน้า ดังนี้
prebuilt_etc {
name: "my.ko",
src: "my.ko",
vendor: true,
sub_dir: "modules"
}
apex {
..
vendor: true,
prebuilts: ["my.ko"], // installed inside APEX as /etc/modules/my.ko
..
}
file_contexts
ของ APEX ควรติดป้ายกำกับรายการเพย์โหลดของโมดูลเคอร์เนลอย่างถูกต้อง เช่น
/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0
ต้องติดตั้งโมดูลเคอร์เนลอย่างชัดเจน ตัวอย่างสคริปต์ init ต่อไปนี้ในพาร์ติชันของผู้ให้บริการแสดงการติดตั้งผ่าน insmod
my_init.rc
:
on early-boot
insmod /apex/myapex/etc/modules/my.ko
..
การซ้อนทับทรัพยากรรันไทม์
ตัวอย่าง
ฝังการวางซ้อนทรัพยากรรันไทม์ใน APEX ของผู้ให้บริการโดยใช้พร็อพเพอร์ตี้ rros
runtime_resource_overlay {
name: "my_rro",
soc_specific: true,
}
apex {
..
vendor: true,
rros: ["my_rro"], // installed inside APEX as /overlay/my_rro.apk
..
}
ไฟล์การกําหนดค่าอื่นๆ
APEX ของผู้ให้บริการรองรับไฟล์การกําหนดค่าอื่นๆ อีกหลายรายการที่มักพบในพาร์ติชันของผู้ให้บริการในรูปแบบที่สร้างไว้ล่วงหน้าภายใน APEX ของผู้ให้บริการ และเรากําลังเพิ่มรายการอื่นๆ อยู่
ตัวอย่าง
- XML การประกาศฟีเจอร์
- เซ็นเซอร์มี XML ในรูปแบบที่สร้างไว้ล่วงหน้าใน APEX ของผู้ให้บริการ HAL ของเซ็นเซอร์
- ป้อนไฟล์การกําหนดค่า
- การกำหนดค่าหน้าจอสัมผัสเป็นค่าที่กำหนดไว้ล่วงหน้าใน APEX ของผู้ให้บริการสำหรับการกำหนดค่าเท่านั้น
APEX ของผู้ให้บริการ Bootstrap
บริการ HAL บางอย่างเช่น keymint
ควรพร้อมใช้งานก่อนที่จะเปิดใช้งาน APEX โดยปกติแล้ว HAL เหล่านั้นจะตั้งค่า early_hal
ในคําจํากัดความของบริการในสคริปต์ init อีกตัวอย่างหนึ่งคือคลาส animation
ซึ่งโดยปกติแล้วจะเริ่มขึ้นก่อนเหตุการณ์ post-fs-data
เมื่อแพ็กเกจบริการ HAL ระยะแรกดังกล่าวใน APEX ของผู้ให้บริการ ให้สร้าง apex "vendorBootstrap": true
ใน APEX Manifest เพื่อให้เปิดใช้งานได้เร็วขึ้น โปรดทราบว่าคุณจะเปิดใช้งาน APEX แบบบูตสแtrap ได้เฉพาะจากตำแหน่งที่สร้างไว้ล่วงหน้า เช่น /vendor/apex
เท่านั้น แต่จะเปิดใช้งานจาก /data/apex
ไม่ได้
พร็อพเพอร์ตี้ของระบบ
พร็อพเพอร์ตี้ของระบบที่เฟรมเวิร์กอ่านเพื่อรองรับ APEX ของผู้ให้บริการมีดังนี้
input_device.config_file.apex=<apex name>
- เมื่อตั้งค่า ระบบจะค้นหาไฟล์การกำหนดค่าอินพุต (*.idc
,*.kl
และ*.kcm
) จากไดเรกทอรี/etc/usr
ของ APEXro.vulkan.apex=<apex name>
- เมื่อตั้งค่า ระบบจะโหลดไดรเวอร์ Vulkan จาก APEX เนื่องจาก HAL เวอร์ชันแรกใช้ไดรเวอร์ Vulkan ให้ทำให้ APEX Bootstrap APEX และกำหนดค่าเนมสเปซ linker ให้มองเห็นได้
ตั้งค่าพร็อพเพอร์ตี้ของระบบในสคริปต์ init โดยใช้คำสั่ง setprop
ฟีเจอร์เพิ่มเติมสำหรับการพัฒนา
การเลือก APEX เมื่อเปิดเครื่อง
ตัวอย่าง
นอกจากนี้ นักพัฒนาซอฟต์แวร์ยังติดตั้ง APEX ของผู้ให้บริการหลายเวอร์ชันที่ใช้ชื่อและคีย์ APEX เดียวกันได้ด้วย จากนั้นเลือกเวอร์ชันที่จะเปิดใช้งานระหว่างการบูตแต่ละครั้งโดยใช้ sysprop แบบถาวร สำหรับบาง Use Case ของนักพัฒนาแอป การดำเนินการนี้อาจง่ายกว่าการติดตั้ง APEX สำเนาใหม่โดยใช้ adb install
ตัวอย่างกรณีการใช้งาน
- ติดตั้ง APEX ของผู้ให้บริการ HAL ของ Wi-Fi 3 เวอร์ชัน: ทีม QA สามารถทำการทดสอบด้วยตนเองหรือแบบอัตโนมัติโดยใช้เวอร์ชันหนึ่ง จากนั้นรีบูตเป็นเวอร์ชันอื่นและทำการทดสอบอีกครั้ง แล้วเปรียบเทียบผลลัพธ์สุดท้าย
- ติดตั้ง APEX ของผู้ให้บริการ HAL ของกล้อง 2 เวอร์ชัน ได้แก่ เวอร์ชันปัจจุบันและเวอร์ชันทดลอง: ผู้ทดสอบเวอร์ชันทดลองสามารถใช้เวอร์ชันทดลองได้โดยไม่ต้องดาวน์โหลดและติดตั้งไฟล์เพิ่มเติม จึงสลับกลับไปใช้เวอร์ชันปัจจุบันได้ง่ายๆ
ในระหว่างการบูต apexd
จะค้นหา sysprops ตามรูปแบบที่เฉพาะเจาะจงเพื่อเปิดใช้งาน APEX เวอร์ชันที่ถูกต้อง
รูปแบบที่ควรจะเป็นสำหรับคีย์พร็อพเพอร์ตี้มีดังนี้
- Bootconfig
- ใช้เพื่อตั้งค่าเริ่มต้นในสกุลเงิน
BoardConfig.mk
androidboot.vendor.apex.<apex name>
- ใช้เพื่อตั้งค่าเริ่มต้นในสกุลเงิน
- sysprop แบบถาวร
- ใช้เพื่อเปลี่ยนค่าเริ่มต้นที่ตั้งค่าไว้ในอุปกรณ์ที่บูตแล้ว
- ลบล้างค่า bootconfig หากมี
persist.vendor.apex.<apex name>
ค่าของพร็อพเพอร์ตี้ควรเป็นชื่อไฟล์ของ APEX ที่ควรเปิดใช้งาน
// Default version.
apex {
name: "com.oem.camera.hal.my_apex_default",
vendor: true,
..
}
// Non-default version.
apex {
name: "com.oem.camera.hal.my_apex_experimental",
vendor: true,
..
}
นอกจากนี้ คุณควรกำหนดค่าเวอร์ชันเริ่มต้นโดยใช้ bootconfig ใน BoardConfig.mk
ด้วย
# Example for APEX "com.oem.camera.hal" with the default above:
BOARD_BOOTCONFIG += \
androidboot.vendor.apex.com.oem.camera.hal=com.oem.camera.hal.my_apex_default
หลังจากบูตอุปกรณ์แล้ว ให้เปลี่ยนเวอร์ชันที่เปิดใช้งานโดยการตั้งค่า sysprop แบบถาวร ดังนี้
$ adb root;
$ adb shell setprop \
persist.vendor.apex.com.oem.camera.hal \
com.oem.camera.hal.my_apex_experimental;
$ adb reboot;
หากอุปกรณ์รองรับการอัปเดต bootconfig หลังจากการแฟลช (เช่น ผ่านคำสั่ง fastboot
oem
) การเปลี่ยนแปลงพร็อพเพอร์ตี้ bootconfig สำหรับ APEX ที่ติดตั้งหลายรายการจะเปลี่ยนเวอร์ชันที่เปิดใช้งานเมื่อบูตด้วย
สําหรับอุปกรณ์อ้างอิงเสมือนที่อิงตาม Cuttlefish คุณสามารถใช้คําสั่ง --extra_bootconfig_args
เพื่อตั้งค่าพร็อพเพอร์ตี้ bootconfig ได้โดยตรงขณะเปิดใช้งาน เช่น
launch_cvd --noresume \
--extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";