คุณสามารถใช้รูปแบบไฟล์ APEX เพื่อแพ็กเกจและติดตั้งโมดูลระบบปฏิบัติการ Android ระดับล่าง ซึ่งช่วยให้สามารถบิลด์และติดตั้งคอมโพเนนต์ต่างๆ เช่น บริการและไลบรารีแบบเนทีฟ การใช้งาน HAL, เฟิร์มแวร์, ไฟล์การกําหนดค่า ฯลฯ ได้อย่างอิสระ
ระบบบิลด์จะติดตั้ง APEX ของผู้ให้บริการโดยอัตโนมัติใน /vendor
และเปิดใช้งานขณะรันไทม์โดย apexd
เช่นเดียวกับ APEX ใน
พาร์ติชัน
กรณีการใช้งาน
การแยกเป็นโมดูลสำหรับอิมเมจผู้ให้บริการ
APEX ช่วยให้การรวมกลุ่มและการจัดโมดูลการติดตั้งใช้งานฟีเจอร์ในรูปภาพผู้ให้บริการเป็นไปอย่างเป็นธรรมชาติ
เมื่อมีการสร้างอิมเมจผู้ให้บริการเป็นชุดค่าผสมของผู้ให้บริการที่สร้างแยกต่างหาก APEX ทำให้ผู้ผลิตอุปกรณ์สามารถเลือก ที่ผู้ให้บริการต้องการบนอุปกรณ์ของตน ผู้ผลิตยังสร้าง APEX ใหม่ของผู้ให้บริการได้หาก APEX ที่ระบุไว้ไม่ตรงกับความต้องการ หรือมีฮาร์ดแวร์ที่กำหนดเองใหม่
ตัวอย่างเช่น OEM อาจเลือกเขียนอุปกรณ์ด้วย Wi-Fi AOSP การใช้งาน APEX, การใช้บลูทูธ SoC, APEX และ OEM ที่กำหนดเอง การติดตั้งใช้งานโทรศัพท์อย่าง APEX
หากไม่มี APEX ของผู้ให้บริการ ก็การติดตั้งใช้งานที่มีทรัพยากร Dependency ต่างๆ ระหว่าง องค์ประกอบของผู้ให้บริการจำเป็นต้องมีการประสานงานและการติดตามอย่างรอบคอบ สรุปทั้งหมด คอมโพเนนต์ (รวมถึงไฟล์การกำหนดค่าและไลบรารีเพิ่มเติม) ใน APEXes ที่มี อินเทอร์เฟซที่กำหนดชัดเจน สำหรับการสื่อสารข้ามฟีเจอร์ คอมโพเนนต์ต่างๆ ก็สามารถใช้แทนกันได้
การทำซ้ำสำหรับนักพัฒนาซอฟต์แวร์
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 ทรัพยากร Dependency เหล่านี้ไม่รวมอยู่ใน
แพ็กเกจ และทรัพยากร Dependency จะได้รับการบันทึกไว้ในไฟล์ Manifest APEX linkerconfig
จะประมวลผลไฟล์ Manifest เพื่อให้การอ้างอิงภายนอกแบบเนทีฟพร้อมใช้งานเมื่อรันไทม์
ในข้อมูลโค้ดต่อไปนี้ APEX มีทั้งไบนารี (my_service
) และ
ทรัพยากร Dependency ที่ไม่เสถียร (*.so
ไฟล์)
apex {
..
vendor: true,
binaries: ["my_service"],
..
}
ในข้อมูลโค้ดต่อไปนี้ APEX มีไลบรารีที่ใช้ร่วมกัน
my_standalone_lib
และทรัพยากร Dependency ที่ไม่เสถียร (ตามที่อธิบายไว้ข้างต้น)
apex {
..
vendor: true,
native_shared_libs: ["my_standalone_lib"],
..
}
ทำให้ APEX เล็กลง
APEX อาจมีขนาดใหญ่ขึ้นเพราะรวมทรัพยากร Dependency ที่ไม่เสถียรเข้าด้วยกัน คำแนะนำจากเรา
โดยใช้การลิงก์แบบคงที่ ไลบรารีทั่วไป เช่น libc++.so
และ libbase.so
สามารถลิงก์แบบคงที่กับไบนารี HAL ได้ สร้างทรัพยากร Dependency เพื่อจัดเตรียมทรัพยากรที่เสถียร
อินเทอร์เฟซอาจเป็นอีกตัวเลือกหนึ่งได้ ระบบจะไม่รวมไฟล์แนบใน APEX
การติดตั้งใช้งาน HAL
หากต้องการกำหนดการปรับใช้ HAL ให้ระบุไบนารีและไลบรารีที่เกี่ยวข้อง ภายใน APEX ของผู้ให้บริการที่คล้ายกับตัวอย่างต่อไปนี้
เพื่อสรุปการติดตั้งใช้งาน HAL โดยสมบูรณ์ APEX ควรระบุ Fragment ของ VINTF และสคริปต์ Init ที่เกี่ยวข้อง
ส่วนย่อย 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 Passthrough
สคริปต์เริ่มต้น
APEX สามารถรวมสคริปต์ init ได้ 2 วิธี คือ (ก) ไฟล์ข้อความที่สร้างไว้ล่วงหน้าภายในแท็ก
เปย์โหลด APEX หรือ (B) สคริปต์ init ปกติใน /vendor/etc
คุณสามารถตั้ง
สำหรับ APEX เดียวกัน
เขียนสคริปต์เริ่มต้นใน APEX:
prebuilt_etc {
name: "myinit.rc",
src: "myinit.rc"
}
apex {
..
vendor: true,
prebuilts: ["myinit.rc"],
..
}
สคริปต์ Init ใน 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
เพื่อเริ่มดำเนินการโดยเร็วที่สุด
Bootstrap APEXes สามารถใช้ 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 ของผู้ให้บริการ ทำให้เอเพ็กซ์ "vendorBootstrap": true
ใน APEX
ไฟล์ Manifest เพื่อให้เปิดใช้งานได้ก่อนหน้านี้ โปรดทราบว่า APEX บูตสตราดอาจทำให้เกิด
เปิดใช้งานจากตำแหน่งที่สร้างไว้ล่วงหน้าอย่าง /vendor/apex
เท่านั้น ไม่ใช่จาก
/data/apex
พร็อพเพอร์ตี้ของระบบ
ต่อไปนี้คือพร็อพเพอร์ตี้ของระบบที่เฟรมเวิร์กระบุไว้เพื่อสนับสนุนผู้ให้บริการ APEXes:
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 ให้มองเห็นได้
ตั้งค่าพร็อพเพอร์ตี้ระบบในสคริปต์เริ่มต้นโดยใช้ setprop
คำสั่ง
ฟีเจอร์เพิ่มเติมสำหรับการพัฒนา
การเลือก APEX เมื่อเปิดเครื่อง
ตัวอย่าง
นักพัฒนาแอปยังสามารถติดตั้ง APEX ของผู้ให้บริการหลายเวอร์ชันที่ใช้
ชื่อและคีย์ APEX เดียวกัน แล้วเลือกเวอร์ชันที่จะเปิดใช้งานในแต่ละคีย์
เปิดเครื่องโดยใช้ sysprops ต่อเนื่อง สำหรับบาง Use Case ของนักพัฒนาแอป การดำเนินการนี้อาจง่ายกว่าการติดตั้งสําเนา APEX ใหม่โดยใช้ adb install
ตัวอย่างกรณีการใช้งาน
- ติดตั้ง APEX ของผู้ให้บริการ Wi-Fi HAL ทั้ง 3 เวอร์ชัน: ทีม QA สามารถดำเนินการด้วยตนเอง หรือการทดสอบอัตโนมัติโดยใช้เวอร์ชันหนึ่ง จากนั้นรีบูตเป็นเวอร์ชันอื่นและ ทำการทดสอบอีกครั้ง แล้วเปรียบเทียบผลลัพธ์สุดท้าย
- ติดตั้ง APEX ของผู้ให้บริการ HAL ของกล้อง 2 เวอร์ชัน คือปัจจุบัน และ ทดลอง: ผู้ร่วม Dogfood สามารถใช้เวอร์ชันทดลองได้โดยไม่ต้อง ดาวน์โหลดและติดตั้งไฟล์เพิ่มเติม เพื่อให้สลับกลับได้โดยง่าย
ในระหว่างการบูต 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";