Android 11 เปิดตัวความสามารถในการใช้ AIDL สำหรับ HAL ใน Android ซึ่งทำให้สามารถติดตั้งใช้งานบางส่วนของ Android โดยไม่ต้องใช้ HIDL ได้ เปลี่ยน HAL ให้ใช้ AIDL เพียงอย่างเดียวเมื่อเป็นไปได้ (เมื่อ HAL ต้นทางใช้ HIDL จะต้องใช้ HIDL)
HAL ที่ใช้ AIDL เพื่อสื่อสารระหว่างคอมโพเนนต์เฟรมเวิร์ก เช่น คอมโพเนนต์ใน system.img
กับคอมโพเนนต์ฮาร์ดแวร์ เช่น คอมโพเนนต์ใน vendor.img
ต้องใช้ AIDL ที่เสถียร อย่างไรก็ตาม หากต้องการสื่อสารภายในพาร์ติชัน เช่น จาก HAL หนึ่งไปยังอีก HAL หนึ่ง จะไม่มีข้อจำกัดเกี่ยวกับกลไก IPC ที่จะใช้ได้
แรงจูงใจ
AIDL ใช้งานได้นานกว่า HIDL และใช้ในหลายๆ ที่ เช่น ระหว่างคอมโพเนนต์เฟรมเวิร์ก Android หรือในแอป ตอนนี้ AIDL รองรับความเสถียรแล้ว คุณจึงใช้ทั้งสแต็กด้วยรันไทม์ IPC เดียวได้ นอกจากนี้ AIDL ยังมีระบบการจัดการเวอร์ชันที่ดีกว่า HIDL ด้วย ข้อดีของ AIDL มีดังนี้
- การใช้ภาษา IPC เดียวหมายความว่าคุณจะต้องเรียนรู้ แก้ไขข้อบกพร่อง เพิ่มประสิทธิภาพ และรักษาความปลอดภัยเพียงอย่างเดียว
- AIDL รองรับการกำหนดเวอร์ชันในตำแหน่งเดิมสำหรับผู้เป็นเจ้าของอินเทอร์เฟซ ดังนี้
- เจ้าของสามารถเพิ่มเมธอดไว้ที่ท้ายอินเทอร์เฟซ หรือเพิ่มช่องลงใน Parcelable ได้ ซึ่งหมายความว่าการกําหนดเวอร์ชันโค้ดในแต่ละปีจะง่ายขึ้น และค่าใช้จ่ายในแต่ละปีก็จะลดลงด้วย (สามารถแก้ไขประเภทในตำแหน่งเดิมได้และไม่จำเป็นต้องมีไลบรารีเพิ่มเติมสำหรับอินเทอร์เฟซแต่ละเวอร์ชัน)
- คุณสามารถแนบอินเทอร์เฟซส่วนขยายได้เมื่อรันไทม์แทนที่จะแนบในระบบประเภทต่างๆ จึงไม่จำเป็นต้องเปลี่ยนฐานส่วนขยายดาวน์สตรีมเป็นอินเทอร์เฟซเวอร์ชันใหม่
- คุณสามารถใช้อินเทอร์เฟซ AIDL ที่มีอยู่ได้โดยตรงเมื่อเจ้าของเลือกที่จะทำให้อินเทอร์เฟซนั้นเสถียร ก่อนหน้านี้ คุณต้องสร้างอินเทอร์เฟซทั้งชุดใน HIDL
บิลด์กับรันไทม์ AIDL
AIDL มีแบ็กเอนด์ 3 แบบ ได้แก่ Java, NDK และ CPP หากต้องการใช้ AIDL ที่เสถียร ให้ใช้สำเนาระบบของ libbinder
ที่ system/lib*/libbinder.so
เสมอ และพูดคุยใน /dev/binder
สําหรับโค้ดในภาพ vendor
หมายความว่าจะใช้ libbinder
(จาก VNDK) ไม่ได้ เนื่องจากไลบรารีนี้มี C++ API ที่ไม่เสถียรและอินเทอร์เนลที่ไม่เสถียร แทนที่จะใช้แบ็กเอนด์ NDK ของ AIDL, ลิงก์กับ libbinder_ndk
(ซึ่งระบบ libbinder.so
รองรับ) และลิงก์กับไลบรารี NDK ที่สร้างขึ้นโดยรายการ aidl_interface
ดูชื่อโมดูลที่แน่นอนได้ที่กฎการตั้งชื่อโมดูล
เขียนอินเทอร์เฟซ AIDL HAL
หากต้องการให้ระบบและผู้ให้บริการใช้อินเทอร์เฟซ AIDL ได้ อินเทอร์เฟซดังกล่าวต้องเปลี่ยนแปลง 2 อย่าง ดังนี้
- คำจำกัดความประเภททุกรายการต้องมีการกำกับเนื้อหาด้วย
@VintfStability
- ประกาศ
aidl_interface
ต้องมีstability: "vintf",
มีเพียงเจ้าของอินเทอร์เฟซเท่านั้นที่ทําการเปลี่ยนแปลงเหล่านี้ได้
เมื่อทําการเปลี่ยนแปลงเหล่านี้ อินเทอร์เฟซต้องอยู่ในไฟล์ Manifest ของ VINTF จึงจะทํางานได้ ทดสอบข้อกำหนดนี้ (และข้อกำหนดที่เกี่ยวข้อง เช่น ยืนยันว่าอินเทอร์เฟซที่เผยแพร่แล้วถูกหยุดไว้) โดยใช้การทดสอบ VTS vts_treble_vintf_vendor_test
คุณสามารถใช้อินเทอร์เฟซ @VintfStability
โดยไม่ต้องมีข้อกำหนดเหล่านี้ได้โดยเรียกใช้ AIBinder_forceDowngradeToLocalStability
ในแบ็กเอนด์ NDK, android::Stability::forceDowngradeToLocalStability
ในแบ็กเอนด์ C++, หรือ android.os.Binder#forceDowngradeToSystemStability
ในแบ็กเอนด์ Java บนออบเจ็กต์ Binder ก่อนที่จะส่งไปยังกระบวนการอื่น
นอกจากนี้ ให้ปิดใช้แบ็กเอนด์ CPP เพื่อให้โค้ดย้ายได้มากที่สุดและหลีกเลี่ยงปัญหาที่อาจเกิดขึ้น เช่น ไลบรารีเพิ่มเติมที่ไม่จำเป็น
โปรดทราบว่าการใช้ backends
ในตัวอย่างโค้ดต่อไปนี้ถูกต้อง เนื่องจากมีแบ็กเอนด์ 3 รายการ (Java, NDK และ CPP) โค้ดแสดงวิธีปิดใช้แบ็กเอนด์ CPP
aidl_interface: {
...
backends: {
cpp: {
enabled: false,
},
},
}
ค้นหาอินเทอร์เฟซ AIDL HAL
อินเทอร์เฟซ AIDL ที่เสถียรของ AOSP สำหรับ HAL จะอยู่ในโฟลเดอร์ aidl
ในไดเรกทอรีฐานเดียวกันกับอินเทอร์เฟซ HIDL
hardware/interfaces
สำหรับอินเทอร์เฟซที่ฮาร์ดแวร์มักจะให้frameworks/hardware/interfaces
สำหรับอินเทอร์เฟซระดับสูงที่ให้กับฮาร์ดแวร์system/hardware/interfaces
สำหรับอินเทอร์เฟซระดับต่ำที่ให้บริการแก่ฮาร์ดแวร์
ใส่อินเทอร์เฟซส่วนขยายในhardware/interfaces
ไดเรกทอรีย่อยอื่นๆ ใน vendor
หรือ hardware
อินเทอร์เฟซส่วนขยาย
Android มีชุดอินเทอร์เฟซ AOSP อย่างเป็นทางการสำหรับทุกรุ่น เมื่อพาร์ทเนอร์ Android ต้องการเพิ่มความสามารถให้กับอินเทอร์เฟซเหล่านี้ พาร์ทเนอร์ไม่ควรเปลี่ยนแปลงอินเทอร์เฟซเหล่านี้โดยตรง เนื่องจากจะทำให้รันไทม์ Android ของพาร์ทเนอร์ใช้งานร่วมกับรันไทม์ Android ของ AOSP ไม่ได้ หลีกเลี่ยงการเปลี่ยนแปลงอินเทอร์เฟซเหล่านี้เพื่อให้รูปภาพ GSI ทำงานต่อไปได้
คุณสามารถลงทะเบียนส่วนขยายได้ 2 วิธีดังนี้
- ขณะรันไทม์ โปรดดูอินเทอร์เฟซส่วนขยายที่แนบมา
- เป็นผลิตภัณฑ์เดี่ยวที่จดทะเบียนทั่วโลกและใน VINTF
ไม่ว่าจะลงทะเบียนส่วนขยายอย่างไร เมื่อคอมโพเนนต์เฉพาะของผู้ให้บริการ (ซึ่งไม่ได้เป็นส่วนหนึ่งของ AOSP ต้นทาง) ใช้อินเทอร์เฟซ ความขัดแย้งในการผสานจะไม่เกิดขึ้น อย่างไรก็ตาม เมื่อมีการแก้ไขคอมโพเนนต์ AOSP ต้นทางในดาวน์สตรีม ความขัดแย้งในการผสานอาจเกิดขึ้นได้ และเราขอแนะนำให้ใช้กลยุทธ์ต่อไปนี้
- ส่งต่อการเพิ่มอินเทอร์เฟซไปยัง AOSP ในรุ่นถัดไป
- การเพิ่มอินเทอร์เฟซสำหรับอัปสตรีมที่ช่วยเพิ่มความยืดหยุ่น (โดยไม่เกิดข้อขัดแย้งในการผสาน) ในรุ่นถัดไป
รายการที่แยกส่วนได้ของส่วนขยาย: ParcelableHolder
ParcelableHolder
คืออินสแตนซ์ของอินเทอร์เฟซ Parcelable
ที่อาจมีอินสแตนซ์อื่นของ Parcelable
กรณีการใช้งานหลักของ ParcelableHolder
คือทำให้ Parcelable
ขยายได้
เช่น รูปภาพที่ผู้ติดตั้งใช้งานอุปกรณ์คาดหวังว่าจะขยาย Parcelable
, AospDefinedParcelable
ที่ AOSP กำหนดให้มีฟีเจอร์ที่เพิ่มมูลค่า
ใช้อินเทอร์เฟซ ParcelableHolder
เพื่อขยาย Parcelable
ด้วยฟีเจอร์ที่เพิ่มมูลค่า อินเทอร์เฟซ ParcelableHolder
มีอินสแตนซ์ของ
Parcelable
หากคุณพยายามเพิ่มช่องใน Parcelable
โดยตรง ระบบจะแสดงข้อผิดพลาด
parcelable AospDefinedParcelable {
int a;
String b;
String x; // ERROR: added by a device implementer
int[] y; // added by a device implementer
}
ดังที่เห็นในโค้ดก่อนหน้า แนวทางปฏิบัตินี้ใช้ไม่ได้เนื่องจากช่องที่เพิ่มโดยผู้ติดตั้งใช้งานอุปกรณ์อาจขัดแย้งกันเมื่อมีการแก้ไข Parcelable
ใน Android เวอร์ชันถัดไป
การใช้ ParcelableHolder
ช่วยให้เจ้าของรายการที่แบ่งออกเป็นส่วนๆ สามารถกำหนดจุดขยายในอินสแตนซ์ของ Parcelable
ดังนี้
parcelable AospDefinedParcelable {
int a;
String b;
ParcelableHolder extension;
}
จากนั้นผู้ติดตั้งใช้งานอุปกรณ์จะกําหนดอินสแตนซ์ Parcelable
ของตนเองสําหรับส่วนขยายได้ ดังนี้
parcelable OemDefinedParcelable {
String x;
int[] y;
}
คุณสามารถแนบอินสแตนซ์ Parcelable
ใหม่ไปกับParcelable
เดิมได้โดยใช้ช่อง ParcelableHolder
ดังนี้
// Java
AospDefinedParcelable ap = ...;
OemDefinedParcelable op = new OemDefinedParcelable();
op.x = ...;
op.y = ...;
ap.extension.setParcelable(op);
...
OemDefinedParcelable op = ap.extension.getParcelable(OemDefinedParcelable.class);
// C++
AospDefinedParcelable ap;
OemDefinedParcelable op;
std::shared_ptr<OemDefinedParcelable> op_ptr = make_shared<OemDefinedParcelable>();
ap.extension.setParcelable(op);
ap.extension.setParcelable(op_ptr);
...
std::shared_ptr<OemDefinedParcelable> op_ptr;
ap.extension.getParcelable(&op_ptr);
// NDK
AospDefinedParcelable ap;
OemDefinedParcelable op;
ap.extension.setParcelable(op);
...
std::optional<OemDefinedParcelable> op;
ap.extension.getParcelable(&op);
// Rust
let mut ap = AospDefinedParcelable { .. };
let op = Rc::new(OemDefinedParcelable { .. });
ap.extension.set_parcelable(Rc::clone(&op));
...
let op = ap.extension.get_parcelable::<OemDefinedParcelable>();
ชื่ออินสแตนซ์เซิร์ฟเวอร์ AIDL HAL
ตามธรรมเนียมแล้ว บริการ AIDL HAL จะมีชื่ออินสแตนซ์ในรูปแบบ
$package.$type/$instance
เช่น อินสแตนซ์ของ HAL ของไวเบรเตอร์ได้รับการลงทะเบียนเป็น android.hardware.vibrator.IVibrator/default
เขียนเซิร์ฟเวอร์ AIDL HAL
@VintfStability
คุณต้องประกาศเซิร์ฟเวอร์ AIDL ในไฟล์ Manifest ของ VINTF ดังนี้
<hal format="aidl">
<name>android.hardware.vibrator</name>
<version>1</version>
<fqname>IVibrator/default</fqname>
</hal>
มิฉะนั้น ควรลงทะเบียนบริการ AIDL ตามปกติ เมื่อทำการทดสอบ VTS คาดว่า HAL ของ AIDL ที่ประกาศไว้ทั้งหมดจะพร้อมใช้งาน
เขียนไคลเอ็นต์ AIDL
ไคลเอ็นต์ AIDL ต้องประกาศตัวเองในตารางความเข้ากันได้ เช่น
<hal format="aidl" optional="true">
<name>android.hardware.vibrator</name>
<version>1-2</version>
<interface>
<name>IVibrator</name>
<instance>default</instance>
</interface>
</hal>
แปลง HAL ที่มีอยู่จาก HIDL เป็น AIDL
ใช้เครื่องมือ hidl2aidl
เพื่อแปลงอินเทอร์เฟซ HIDL เป็น AIDL
ฟีเจอร์ของ hidl2aidl
- สร้างไฟล์ AIDL (
.aidl
) ตามไฟล์ HAL (.hal
) สําหรับแพ็กเกจที่ระบุ - สร้างกฎการสร้างสำหรับแพ็กเกจ AIDL ที่สร้างขึ้นใหม่โดยเปิดใช้แบ็กเอนด์ทั้งหมด
- สร้างเมธอดการแปลในแบ็กเอนด์ Java, CPP และ NDK สำหรับการแปลจากประเภท HIDL เป็นประเภท AIDL
- สร้างกฎการสร้างสำหรับไลบรารีการแปลที่มีข้อกำหนดที่จำเป็น
- สร้างการยืนยันแบบคงที่เพื่อให้แน่ใจว่าตัวระบุรายการ HIDL และ AIDL มีค่าเดียวกันในแบ็กเอนด์ CPP และ NDK
ทําตามขั้นตอนต่อไปนี้เพื่อแปลงแพ็กเกจไฟล์ HAL เป็นไฟล์ AIDL
สร้างเครื่องมือที่อยู่ใน
system/tools/hidl/hidl2aidl
การสร้างเครื่องมือนี้จากแหล่งที่มาล่าสุดจะให้ประสบการณ์การใช้งานที่สมบูรณ์ที่สุด คุณสามารถใช้เวอร์ชันล่าสุดเพื่อแปลงอินเทอร์เฟซในสาขาเก่าจากรุ่นก่อนหน้าได้ ดังนี้
m hidl2aidl
เรียกใช้เครื่องมือด้วยไดเรกทอรีเอาต์พุตตามด้วยแพ็กเกจที่จะแปลง
(ไม่บังคับ) ใช้อาร์กิวเมนต์
-l
เพื่อเพิ่มเนื้อหาของไฟล์ใบอนุญาตใหม่ไว้ที่ด้านบนของไฟล์ที่สร้างขึ้นทั้งหมด ตรวจสอบว่าคุณใช้ใบอนุญาตและวันที่ที่ถูกต้องhidl2aidl -o <output directory> -l <file with license> <package>
เช่น
hidl2aidl -o . -l my_license.txt android.hardware.nfc@1.2
อ่านไฟล์ที่สร้างขึ้นและแก้ไขปัญหาเกี่ยวกับการแปลง
conversion.log
มีปัญหาที่ยังไม่ได้จัดการซึ่งต้องแก้ไขก่อน- ไฟล์ AIDL ที่สร้างขึ้นอาจมีคำเตือนและคำแนะนำที่จำเป็นต้องดำเนินการ ความคิดเห็นเหล่านี้ขึ้นต้นด้วย
//
- ล้างข้อมูลและปรับปรุงแพ็กเกจ
- ตรวจสอบคำอธิบายประกอบ
@JavaDerive
เพื่อดูฟีเจอร์ที่อาจต้องใช้ เช่นtoString
หรือequals
สร้างเฉพาะเป้าหมายที่ต้องการ
- ปิดใช้แบ็กเอนด์ที่จะไม่ใช้งาน ใช้แบ็กเอนด์ NDK แทนแบ็กเอนด์ CPP ดูการสร้างกับรันไทม์ AIDL
- นำไลบรารีการแปลหรือโค้ดที่สร้างขึ้นซึ่งจะไม่ได้ใช้ออก
ดูความแตกต่างที่สำคัญระหว่าง AIDL กับ HIDL
- โดยทั่วไปแล้ว การใช้
Status
และข้อยกเว้นในตัวของ AIDL จะปรับปรุงอินเทอร์เฟซและทำให้ไม่จำเป็นต้องมีสถานะประเภทอื่นสำหรับอินเทอร์เฟซ - อาร์กิวเมนต์อินเทอร์เฟซ AIDL ในเมธอดจะไม่เป็น
@nullable
โดยค่าเริ่มต้นเหมือนใน HIDL
- โดยทั่วไปแล้ว การใช้
SEPolicy สำหรับ AIDL HAL
ประเภทบริการ AIDL ที่แสดงต่อรหัสผู้ให้บริการต้องมีแอตทริบิวต์
hal_service_type
มิเช่นนั้น การกําหนดค่า sepolicy จะเหมือนกับบริการ AIDL อื่นๆ (แม้ว่าจะมีแอตทริบิวต์พิเศษสําหรับ HAL) ตัวอย่างคำจำกัดความของบริบทบริการ HAL มีดังนี้
type hal_foo_service, service_manager_type, hal_service_type;
สําหรับบริการส่วนใหญ่ที่แพลตฟอร์มกําหนดไว้ ระบบจะเพิ่มบริบทบริการที่มีประเภทที่ถูกต้องอยู่แล้ว (เช่น android.hardware.foo.IFoo/default
มีการทำเครื่องหมายเป็น hal_foo_service
อยู่แล้ว) อย่างไรก็ตาม หากไคลเอ็นต์เฟรมเวิร์กรองรับชื่ออินสแตนซ์หลายรายการ คุณต้องเพิ่มชื่ออินสแตนซ์เพิ่มเติมในไฟล์ service_contexts
สำหรับอุปกรณ์แต่ละเครื่อง ดังนี้
android.hardware.foo.IFoo/custom_instance u:object_r:hal_foo_service:s0
เมื่อสร้าง HAL ประเภทใหม่ คุณต้องเพิ่มแอตทริบิวต์ HAL แอตทริบิวต์ HAL ที่เฉพาะเจาะจงอาจเชื่อมโยงกับบริการหลายประเภท (แต่ละประเภทอาจมีอินสแตนซ์หลายรายการตามที่ได้กล่าวไปก่อนหน้านี้) สำหรับ HAL foo
จะมี
hal_attribute(foo)
มาโครนี้กําหนดแอตทริบิวต์ hal_foo_client
และ
hal_foo_server
สำหรับโดเมนหนึ่งๆ มาโคร hal_client_domain
และ hal_server_domain
จะเชื่อมโยงโดเมนกับแอตทริบิวต์ HAL ที่ระบุ ตัวอย่างเช่น เซิร์ฟเวอร์ระบบที่เป็นไคลเอ็นต์ของ HAL นี้สอดคล้องกับนโยบาย hal_client_domain(system_server, hal_foo)
เซิร์ฟเวอร์ HAL ก็มี hal_server_domain(my_hal_domain, hal_foo)
เช่นเดียวกัน
โดยทั่วไปแล้ว คุณควรสร้างโดเมน เช่น hal_foo_default
สำหรับแอตทริบิวต์ HAL หนึ่งๆ เพื่อใช้เป็นข้อมูลอ้างอิงหรือ HAL ตัวอย่าง อย่างไรก็ตาม อุปกรณ์บางเครื่องใช้โดเมนเหล่านี้สำหรับเซิร์ฟเวอร์ของตนเอง การแยกความแตกต่างระหว่างโดเมนสำหรับเซิร์ฟเวอร์หลายเครื่องจะมีผลก็ต่อเมื่อมีเซิร์ฟเวอร์หลายเครื่องที่ให้บริการอินเทอร์เฟซเดียวกันและจำเป็นต้องใช้ชุดสิทธิ์ที่แตกต่างกันในการติดตั้งใช้งาน
ในมาโครทั้งหมดเหล่านี้ hal_foo
ไม่ใช่ออบเจ็กต์ sepolicy แต่มาโครเหล่านี้จะใช้โทเค็นนี้เพื่ออ้างอิงกลุ่มแอตทริบิวต์ที่เชื่อมโยงกับคู่เซิร์ฟเวอร์ไคลเอ็นต์แทน
อย่างไรก็ตาม จนถึงตอนนี้ hal_foo_service
และ hal_foo
(คู่แอตทริบิวต์จาก hal_attribute(foo)
) ยังไม่ได้เชื่อมโยงกัน แอตทริบิวต์ HAL จะเชื่อมโยงกับบริการ AIDL HAL โดยใช้มาโคร hal_attribute_service
(HIDL HAL ใช้มาโคร hal_attribute_hwservice
) เช่น hal_attribute_service(hal_foo, hal_foo_service)
ซึ่งหมายความว่าhal_foo_client
กระบวนการจะเข้าถึง HAL ได้ และhal_foo_server
กระบวนการจะลงทะเบียน HAL ได้ ผู้จัดการบริบท (servicemanager
) จะเป็นผู้บังคับใช้กฎการจดทะเบียนเหล่านี้
ชื่อบริการอาจไม่ตรงกับแอตทริบิวต์ HAL เสมอไป เช่น
hal_attribute_service(hal_foo, hal_foo2_service)
โดยทั่วไปแล้ว คุณสามารถนำ hal_foo2_service
ออกและใช้ hal_foo_service
กับบริบทบริการทั้งหมดได้ เนื่องจากประโยคนี้บอกเป็นนัยว่าบริการดังกล่าวใช้ร่วมกันเสมอ เมื่อ HAL ตั้งค่าอินสแตนซ์ hal_attribute_service
หลายรายการ แสดงว่าชื่อแอตทริบิวต์ HAL เดิมไม่ทั่วไปพอและเปลี่ยนไม่ได้
เมื่อรวมทั้งหมดเข้าด้วยกัน ตัวอย่าง HAL จะมีลักษณะดังนี้
public/attributes:
// define hal_foo, hal_foo_client, hal_foo_server
hal_attribute(foo)
public/service.te
// define hal_foo_service
type hal_foo_service, hal_service_type, protected_service, service_manager_type
public/hal_foo.te:
// allow binder connection from client to server
binder_call(hal_foo_client, hal_foo_server)
// allow client to find the service, allow server to register the service
hal_attribute_service(hal_foo, hal_foo_service)
// allow binder communication from server to service_manager
binder_use(hal_foo_server)
private/service_contexts:
// bind an AIDL service name to the selinux type
android.hardware.foo.IFooXxxx/default u:object_r:hal_foo_service:s0
private/<some_domain>.te:
// let this domain use the hal service
binder_use(some_domain)
hal_client_domain(some_domain, hal_foo)
vendor/<some_hal_server_domain>.te
// let this domain serve the hal service
hal_server_domain(some_hal_server_domain, hal_foo)
อินเทอร์เฟซส่วนขยายที่แนบมา
ส่วนขยายจะแนบไปกับอินเทอร์เฟซ Binder ใดก็ได้ ไม่ว่าจะเป็นอินเทอร์เฟซระดับบนสุดที่ลงทะเบียนกับ Service Manager โดยตรงหรืออินเทอร์เฟซย่อย เมื่อได้รับส่วนขยาย คุณต้องยืนยันว่าประเภทส่วนขยายเป็นไปตามที่คาดไว้ คุณตั้งค่าส่วนขยายได้เฉพาะจากกระบวนการที่แสดง Binder เท่านั้น
ใช้ส่วนขยายที่แนบมาทุกครั้งที่ส่วนขยายแก้ไขฟังก์ชันการทำงานของ HAL ที่มีอยู่ เมื่อต้องการความสามารถใหม่ทั้งหมด คุณไม่จำเป็นต้องใช้กลไกนี้และสามารถลงทะเบียนอินเทอร์เฟซส่วนขยายกับตัวจัดการบริการได้โดยตรง อินเทอร์เฟซส่วนขยายที่แนบมาจะเหมาะสมที่สุดเมื่อแนบกับอินเทอร์เฟซย่อย เนื่องจากลําดับชั้นเหล่านี้อาจมีความลึกหรือมีหลายอินสแตนซ์ การใช้ส่วนขยายส่วนกลางเพื่อมิเรอร์ลําดับชั้นอินเทอร์เฟซ Binder ของบริการอื่นต้องใช้การบันทึกที่ครอบคลุมเพื่อให้ความสามารถเทียบเท่ากับส่วนขยายที่แนบโดยตรง
หากต้องการตั้งค่าส่วนขยายใน Binder ให้ใช้ API ต่อไปนี้
- แบ็กเอนด์ NDK:
AIBinder_setExtension
- แบ็กเอนด์ Java:
android.os.Binder.setExtension
- แบ็กเอนด์ CPP:
android::Binder::setExtension
- แบ็กเอนด์ Rust:
binder::Binder::set_extension
หากต้องการรับส่วนขยายใน Binder ให้ใช้ API ต่อไปนี้
- แบ็กเอนด์ NDK:
AIBinder_getExtension
- แบ็กเอนด์ Java:
android.os.IBinder.getExtension
- แบ็กเอนด์ CPP:
android::IBinder::getExtension
- แบ็กเอนด์ Rust:
binder::Binder::get_extension
ดูข้อมูลเพิ่มเติมสำหรับ API เหล่านี้ได้ในเอกสารประกอบของฟังก์ชัน getExtension
ในแบ็กเอนด์ที่เกี่ยวข้อง ตัวอย่างวิธีใช้ส่วนขยายมีอยู่ในhardware/interfaces/tests/extension/vibrator
ความแตกต่างที่สำคัญระหว่าง AIDL กับ HIDL
เมื่อใช้ AIDL HAL หรือใช้อินเทอร์เฟซ AIDL HAL โปรดทราบว่ามีความแตกต่างเมื่อเทียบกับการเขียน HIDL HAL
- ไวยากรณ์ของภาษา AIDL ใกล้เคียงกับ Java มากกว่า ไวยากรณ์ HIDL คล้ายกับ C++
- อินเทอร์เฟซ AIDL ทั้งหมดมีสถานะข้อผิดพลาดในตัว แทนที่จะสร้างประเภทสถานะที่กำหนดเอง ให้สร้าง int สถานะคงที่ในไฟล์อินเทอร์เฟซ และใช้
EX_SERVICE_SPECIFIC
ในแบ็กเอนด์ CPP และ NDK และServiceSpecificException
ในแบ็กเอนด์ Java ดูการจัดการข้อผิดพลาด - AIDL จะไม่เริ่มต้นพูลเธรดโดยอัตโนมัติเมื่อส่งออบเจ็กต์ Binder โดยคุณต้องเริ่มชุดข้อความด้วยตนเอง (ดูการจัดการชุดข้อความ)
- AIDL จะไม่หยุดทำงานเมื่อมีข้อผิดพลาดในการขนส่งที่ไม่ได้ตรวจสอบ (HIDL
Return
จะหยุดทำงานเมื่อมีข้อผิดพลาดที่ไม่ได้ตรวจสอบ) - AIDL ประกาศได้เพียง 1 ประเภทต่อไฟล์
- อาร์กิวเมนต์ AIDL สามารถระบุเป็น
in
,out
หรือinout
นอกเหนือจากพารามิเตอร์เอาต์พุต (ไม่มีการเรียกกลับแบบซิงค์) - AIDL ใช้
fd
เป็นประเภทพื้นฐานแทนhandle
- HIDL ใช้เวอร์ชันหลักสำหรับการเปลี่ยนแปลงที่เข้ากันไม่ได้และเวอร์ชันย่อยสำหรับการเปลี่ยนแปลงที่เข้ากันได้ ใน AIDL จะมีการเปลี่ยนแปลงที่เข้ากันได้แบบย้อนหลัง
AIDL ไม่มีแนวคิดที่ชัดเจนเกี่ยวกับเวอร์ชันหลัก แต่รวมไว้ในชื่อแพ็กเกจแทน เช่น AIDL อาจใช้ชื่อแพ็กเกจ
bluetooth2
- AIDL จะไม่รับค่าลำดับความสำคัญแบบเรียลไทม์โดยค่าเริ่มต้น ต้องใช้ฟังก์ชัน
setInheritRt
ต่อ Binder เพื่อเปิดใช้การสืบทอดลําดับความสําคัญแบบเรียลไทม์
การทดสอบชุดทดสอบของผู้ให้บริการ (VTS) สําหรับ HAL
Android อาศัยชุดทดสอบของผู้ให้บริการ (VTS) เพื่อยืนยันการติดตั้งใช้งาน HAL ที่คาดไว้ VTS ช่วยให้มั่นใจได้ว่า Android จะใช้งานร่วมกับการใช้งานเดิมของผู้ให้บริการได้ การติดตั้งใช้งานที่ไม่ผ่าน VTS มีปัญหาความเข้ากันได้ที่ทราบกันดี ซึ่งอาจทำให้ใช้งานกับระบบปฏิบัติการเวอร์ชันในอนาคตไม่ได้
VTS สำหรับ HAL ประกอบด้วย 2 ส่วนหลักๆ ดังนี้
1. ยืนยันว่า Android รู้จักและคาดหวัง HAL ในอุปกรณ์
ชุดการทดสอบนี้อยู่ใน test/vts-testcase/hal/treble/vintf
การทดสอบเหล่านี้มีหน้าที่รับผิดชอบในการยืนยันสิ่งต่อไปนี้
- อินเทอร์เฟซ
@VintfStability
ทั้งหมดที่ประกาศในไฟล์ Manifest ของ VINTF จะหยุดอยู่ที่เวอร์ชันที่เผยแพร่แล้วซึ่งทราบ วิธีนี้ช่วยให้มั่นใจว่าอินเทอร์เฟซทั้ง 2 ด้านจะยอมรับคำจำกัดความที่แน่นอนของอินเทอร์เฟซเวอร์ชันนั้น ซึ่งจำเป็นต่อการดำเนินการขั้นพื้นฐาน - HAL ทั้งหมดที่ประกาศในไฟล์ Manifest ของ VINTF จะพร้อมใช้งานในอุปกรณ์นั้น ไคลเอ็นต์ที่มีสิทธิ์เพียงพอในการใช้บริการ HAL ที่ประกาศไว้ต้องสามารถรับและใช้บริการเหล่านั้นได้ทุกเมื่อ
- HAL ทั้งหมดที่ประกาศในไฟล์ Manifest ของ VINTF จะแสดงอินเทอร์เฟซเวอร์ชันที่ประกาศไว้ในไฟล์ Manifest
- ไม่มี HAL ที่เลิกใช้งานแสดงในอุปกรณ์ Android จะหยุดรองรับอินเทอร์เฟซ HAL เวอร์ชันที่ต่ำกว่าตามที่อธิบายไว้ในวงจรชีวิตของ FCM
- มี HAL ที่จำเป็นในอุปกรณ์ HAL บางรายการจําเป็นต่อการทํางานของ Android
2. ยืนยันลักษณะการทำงานที่คาดไว้ของ HAL แต่ละรายการ
อินเทอร์เฟซ HAL แต่ละรายการมีการทดสอบ VTS เป็นของตัวเองเพื่อยืนยันลักษณะการทำงานที่คาดหวังจากไคลเอ็นต์ เทสเคสจะทํางานกับอินสแตนซ์ HAL ทั้งหมดที่ประกาศไว้และบังคับใช้ลักษณะการทํางานเฉพาะตามเวอร์ชันของอินเทอร์เฟซที่ติดตั้งใช้งาน
การทดสอบเหล่านี้พยายามครอบคลุมทุกแง่มุมของการใช้งาน HAL ที่เฟรมเวิร์ก Android ต้องใช้หรืออาจต้องใช้ในอนาคต
การทดสอบเหล่านี้รวมถึงการยืนยันการรองรับฟีเจอร์ การจัดการข้อผิดพลาด และลักษณะการทำงานอื่นๆ ที่ไคลเอ็นต์อาจคาดหวังจากบริการ
เหตุการณ์สำคัญ VTS สำหรับการพัฒนา HAL
คุณควรอัปเดตการทดสอบ VTS เมื่อสร้างหรือแก้ไขอินเทอร์เฟซ HAL ของ Android
การทดสอบ VTS ต้องเสร็จสิ้นและพร้อมที่จะยืนยันการติดตั้งใช้งานของผู้ให้บริการก่อนที่จะหยุดให้บริการสำหรับรุ่น Android Vendor API โดยต้องพร้อมใช้งานก่อนที่อินเทอร์เฟซจะหยุดทำงานเพื่อให้นักพัฒนาแอปสร้างการใช้งาน ยืนยัน และแสดงความคิดเห็นต่อนักพัฒนาอินเทอร์เฟซ HAL ได้
VTS ใน Cuttlefish
เมื่อไม่มีฮาร์ดแวร์ Android จะใช้ Cuttlefish เป็นแพลตฟอร์มการพัฒนาสำหรับอินเทอร์เฟซ HAL ซึ่งช่วยให้ VTS และทดสอบการผสานรวมของ Android ปรับขนาดได้
hal_implementation_test
ทดสอบว่า Cuttlefish มีการใช้งานอินเทอร์เฟซ HAL เวอร์ชันล่าสุดเพื่อให้แน่ใจว่า Android พร้อมจัดการอินเทอร์เฟซใหม่ และการทดสอบ VTS พร้อมทดสอบการใช้งานของผู้ให้บริการรายใหม่ทันทีที่มีฮาร์ดแวร์และอุปกรณ์ใหม่