คุณสามารถใช้รูปแบบไฟล์ APEX เพื่อแพ็กเกจและ ติดตั้งโมดูล Android OS ระดับล่างได้ ซึ่งช่วยให้สามารถสร้างและ ติดตั้งคอมโพเนนต์ต่างๆ เช่น บริการและไลบรารีแบบเนทีฟ การใช้งาน HAL เฟิร์มแวร์ ไฟล์กำหนดค่า ฯลฯ ได้อย่างอิสระ
ระบบบิลด์จะติดตั้ง APEX ของผู้ให้บริการโดยอัตโนมัติในพาร์ติชัน /vendor
และ apexd
จะเปิดใช้งานที่รันไทม์เช่นเดียวกับ 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 ได้ การสร้างการอ้างอิงเพื่อมอบอินเทอร์เฟซที่เสถียร
อาจเป็นอีกตัวเลือกหนึ่ง ระบบจะไม่รวมทรัพยากร Dependency ไว้ใน APEX
การใช้งาน HAL
หากต้องการกำหนดการใช้งาน HAL ให้ระบุไบนารีและไลบรารีที่เกี่ยวข้อง ภายใน APEX ของผู้ให้บริการในลักษณะที่คล้ายกับตัวอย่างต่อไปนี้
APEX ควรระบุ ส่วน VINTF และสคริปต์ init ที่เกี่ยวข้องด้วย เพื่อให้การติดตั้งใช้งาน HAL ครบถ้วนสมบูรณ์
VINTF fragments
ระบบจะแสดงผล VINTF Fragment จาก APEX ของผู้ให้บริการได้เมื่อ Fragment อยู่ใน
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 Fragment ลงใน 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 สามารถมีสคริปต์ init ได้ 2 วิธี ได้แก่ (ก) ไฟล์ข้อความที่สร้างไว้ล่วงหน้าภายใน
เพย์โหลด APEX หรือ (ข) สคริปต์ init ปกติใน /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
เพื่อทริกเกอร์การดำเนินการโดยเร็วที่สุด
Bootstrap APEX สามารถใช้ 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 ของฟีเจอร์เซ็นเซอร์เป็น Prebuilt ใน APEX ของผู้ให้บริการ HAL เซ็นเซอร์
- ไฟล์การกำหนดค่าอินพุต
- การกำหนดค่าหน้าจอสัมผัสเป็น prebuilts ใน APEX ของผู้ให้บริการที่กำหนดค่าเท่านั้น
APEX ของผู้ให้บริการ Bootstrap
บริการ HAL บางอย่าง เช่น keymint
ควรพร้อมใช้งานก่อนที่จะเปิดใช้งาน APEX
โดยปกติแล้ว HAL เหล่านั้นจะตั้งค่า early_hal
ในคำจำกัดความของบริการใน
สคริปต์ init อีกตัวอย่างหนึ่งคือanimation
class ซึ่งโดยปกติจะเริ่ม
ก่อนpost-fs-data
event เมื่อมีการแพ็กเกจบริการ HAL เวอร์ชันแรกดังกล่าวใน APEX ของผู้ให้บริการ ให้สร้าง APEX "vendorBootstrap": true
ใน APEX
Manifest เพื่อให้เปิดใช้งานได้เร็วขึ้น โปรดทราบว่าคุณจะเปิดใช้งาน APEX ที่บูตสแตรปได้จากตำแหน่งที่สร้างไว้ล่วงหน้า เช่น /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 ของผู้ให้บริการในระหว่างการบูตหรือไม่ก็ได้
หากคุณระบุชื่อไฟล์โดยใช้พร็อพเพอร์ตี้ของระบบ
ro.vendor.apex.<apex name>
ระบบจะเปิดใช้งานเฉพาะ APEX ที่ตรงกับชื่อไฟล์
สำหรับ <apex name>
ที่เฉพาะเจาะจง
ระบบจะไม่สนใจ (ไม่เปิดใช้งาน) APEX ที่มี <apex name>
หากตั้งค่าพร็อพเพอร์ตี้ของระบบนี้
เป็น none
คุณใช้ฟีเจอร์นี้เพื่อติดตั้ง APEX หลายสำเนาที่มีชื่อเดียวกันได้
หากมี APEX เดียวกันหลายเวอร์ชัน APEX เหล่านั้นควรใช้คีย์เดียวกัน
ตัวอย่างกรณีการใช้งาน
- ติดตั้ง HAL ของ Wi-Fi เวอร์ชัน 3 ของ APEX ของผู้ให้บริการ: ทีม QA สามารถเรียกใช้การทดสอบด้วยตนเอง หรือการทดสอบอัตโนมัติโดยใช้เวอร์ชันหนึ่ง จากนั้นรีบูตเป็นอีกเวอร์ชันหนึ่งและ เรียกใช้การทดสอบอีกครั้ง แล้วเปรียบเทียบผลลัพธ์สุดท้าย
- ติดตั้ง HAL ของกล้อง 2 เวอร์ชันจาก APEX ของผู้ให้บริการ current และ experimental: ผู้ใช้ที่ทดสอบผลิตภัณฑ์ภายในสามารถใช้เวอร์ชันทดลองได้โดยไม่ต้อง ดาวน์โหลดและติดตั้งไฟล์เพิ่มเติม จึงสลับกลับได้ง่าย
ในระหว่างการบูต apexd
จะค้นหา sysprop ที่มีรูปแบบเฉพาะเพื่อ
เปิดใช้งาน APEX เวอร์ชันที่ถูกต้อง
รูปแบบที่ควรจะเป็นสำหรับคีย์พร็อพเพอร์ตี้คือ
- Bootconfig
- ใช้เพื่อตั้งค่าเริ่มต้นใน
BoardConfig.mk
androidboot.vendor.apex.<apex name>
- ใช้เพื่อตั้งค่าเริ่มต้นใน
- Sysprop แบบถาวร
- ใช้เพื่อเปลี่ยนค่าเริ่มต้นที่ตั้งค่าไว้ในอุปกรณ์ที่บูตแล้ว
- ลบล้างค่า bootconfig หากมี
persist.vendor.apex.<apex name>
ค่าของพร็อพเพอร์ตี้ควรเป็นชื่อไฟล์ของ APEX ที่ควรเปิดใช้งาน หรือ none
เพื่อปิดใช้ 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";