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 ด้วย
- การใช้ภาษา IPC เดียวหมายความว่าคุณจะต้องเรียนรู้ แก้ไขข้อบกพร่อง เพิ่มประสิทธิภาพ และรักษาความปลอดภัยเพียงอย่างเดียว
- AIDL รองรับการกำหนดเวอร์ชันในตำแหน่งเดิมสำหรับผู้เป็นเจ้าของอินเทอร์เฟซ ดังนี้
- เจ้าของสามารถเพิ่มเมธอดไว้ที่ท้ายอินเทอร์เฟซ หรือเพิ่มช่องลงใน Parcelable ได้ ซึ่งหมายความว่าการทําเวอร์ชันโค้ดในแต่ละปีจะง่ายขึ้น และค่าใช้จ่ายในแต่ละปีก็จะลดลงด้วย (สามารถแก้ไขประเภทในตำแหน่งเดิมได้และไม่จำเป็นต้องมีไลบรารีเพิ่มเติมสําหรับอินเทอร์เฟซแต่ละเวอร์ชัน)
- อินเทอร์เฟซส่วนขยายจะแนบได้เมื่อรันไทม์แทนที่จะเป็นในระบบประเภท ดังนั้นจึงไม่จำเป็นต้องเปลี่ยนฐานส่วนขยายดาวน์สตรีมเป็นอินเทอร์เฟซเวอร์ชันใหม่
- คุณสามารถใช้อินเทอร์เฟซ AIDL ที่มีอยู่ได้โดยตรงเมื่อเจ้าของเลือกที่จะทำให้อินเทอร์เฟซนั้นเสถียร ก่อนหน้านี้ คุณต้องสร้างอินเทอร์เฟซทั้งชุดใน HIDL
บิลด์กับรันไทม์ AIDL
AIDL มีแบ็กเอนด์ 3 แบบ ได้แก่ Java, NDK และ CPP หากต้องการใช้ AIDL แบบเสถียร คุณต้องใช้สำเนา libbinder ของระบบที่ system/lib*/libbinder.so
เสมอและพูดคุยใน /dev/binder
สำหรับโค้ดในอิมเมจของผู้ให้บริการ หมายความว่าจะใช้ 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 ก่อนที่จะส่งไปยังกระบวนการอื่น Java ไม่รองรับการดาวน์เกรดบริการเพื่อเพิ่มความเสถียรของผู้ให้บริการ เนื่องจากแอปทั้งหมดทำงานในบริบทของระบบ
นอกจากนี้ ให้ปิดใช้แบ็กเอนด์ CPP เพื่อให้โค้ดย้ายได้มากที่สุดและหลีกเลี่ยงปัญหาที่อาจเกิดขึ้น เช่น ไลบรารีเพิ่มเติมที่ไม่จำเป็น
โปรดทราบว่าการใช้ backends
ในตัวอย่างโค้ดด้านล่างนั้นถูกต้อง เนื่องจากมีแบ็กเอนด์ 3 รายการ (Java, NDK และ CPP) โค้ดด้านล่างจะบอกวิธีเลือกแบ็กเอนด์ CPP โดยเฉพาะเพื่อปิดใช้
aidl_interface: {
...
backends: {
cpp: {
enabled: false,
},
},
}
ค้นหาอินเทอร์เฟซ AIDL HAL
อินเทอร์เฟซ AIDL ของ AOSP เวอร์ชันเสถียรสำหรับ HAL อยู่ในไดเรกทอรีฐานเดียวกันกับอินเทอร์เฟซ HIDL ในโฟลเดอร์ aidl
- hardware/interfaces: สำหรับอินเทอร์เฟซที่ฮาร์ดแวร์มักให้ไว้
- frameworks/hardware/interfaces: สำหรับอินเทอร์เฟซระดับสูงที่ให้บริการแก่ฮาร์ดแวร์
- system/hardware/interfaces: สำหรับอินเทอร์เฟซระดับต่ำที่ระบุให้กับฮาร์ดแวร์
คุณควรใส่อินเทอร์เฟซส่วนขยายไว้ในhardware/interfaces
ไดเรกทอรีย่อยอื่นๆ ใน vendor
หรือ hardware
อินเทอร์เฟซส่วนขยาย
Android มีชุดอินเทอร์เฟซ AOSP อย่างเป็นทางการสำหรับทุกรุ่น เมื่อพาร์ทเนอร์ Android ต้องการเพิ่มฟังก์ชันการทำงานลงในอินเทอร์เฟซเหล่านี้ พาร์ทเนอร์ไม่ควรเปลี่ยนแปลงอินเทอร์เฟซเหล่านี้โดยตรง เนื่องจากจะทำให้รันไทม์ Android ใช้งานร่วมกับรันไทม์ Android ของ AOSP ไม่ได้ สำหรับอุปกรณ์ GMS การหลีกเลี่ยงการเปลี่ยนแปลงอินเทอร์เฟซเหล่านี้ยังช่วยให้มั่นใจได้ว่ารูปภาพ GSI จะยังคงใช้งานได้ต่อไป
ส่วนขยายจะลงทะเบียนได้ 2 วิธีดังนี้
- ขณะรันไทม์ ให้ดูส่วนขยายที่แนบมา
- แบบสแตนด์อโลนที่จดทะเบียนทั่วโลกและใน VINTF
ไม่ว่าจะลงทะเบียนส่วนขยายอย่างไร เมื่อคอมโพเนนต์เฉพาะผู้ให้บริการ (ไม่ได้เป็นส่วนหนึ่งของ AOSP ต้นทาง) ใช้อินเทอร์เฟซ ก็ไม่มีความเป็นไปได้ที่จะเกิดข้อขัดแย้งในการผสาน อย่างไรก็ตาม เมื่อมีการแก้ไขคอมโพเนนต์ AOSP ดาวน์สตรีมในอัปสตรีม อาจทำให้เกิดข้อขัดแย้งในการผสาน และเราขอแนะนำให้ใช้กลยุทธ์ต่อไปนี้
- การเพิ่มอินเทอร์เฟซสามารถส่งไปยัง AOSP ในรุ่นถัดไปได้
- การเพิ่มอินเทอร์เฟซที่เพิ่มความยืดหยุ่นมากขึ้นโดยไม่เกิดข้อขัดแย้งในการผสาน สามารถส่งไปยังเวอร์ชันหลักได้ในรุ่นถัดไป
รายการที่แยกส่วนได้ของส่วนขยาย: ParcelableHolder
ParcelableHolder
คือ Parcelable
ที่มี Parcelable
อื่นอยู่ภายใน
กรณีการใช้งานหลักของ ParcelableHolder
คือทำให้ Parcelable
ขยายได้
เช่น รูปภาพที่ผู้ติดตั้งใช้งานอุปกรณ์คาดหวังว่าจะขยาย Parcelable
, AospDefinedParcelable
ที่ AOSP กำหนดให้รวมฟีเจอร์ที่มีคุณค่าเพิ่ม
ก่อนหน้านี้ หากไม่มี ParcelableHolder
ผู้ติดตั้งใช้งานอุปกรณ์จะแก้ไขอินเทอร์เฟซ AIDL ที่เสถียรซึ่ง AOSP กำหนดไว้ไม่ได้ เนื่องจากการเพิ่มช่องเพิ่มเติมจะเป็นข้อผิดพลาด
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
โดยอิงตามไฟล์.hal
สำหรับแพ็กเกจที่ระบุ - สร้างกฎการสร้างสำหรับแพ็กเกจ AIDL ที่สร้างขึ้นใหม่โดยเปิดใช้แบ็กเอนด์ทั้งหมด
- สร้างเมธอดการแปลในแบ็กเอนด์ Java, CPP และ NDK สำหรับการแปลจากประเภท HIDL เป็นประเภท AIDL
- สร้างกฎการสร้างสำหรับไลบรารีการแปลที่มีทรัพยากร Dependency ที่จำเป็น
- สร้างการยืนยันแบบคงที่เพื่อให้แน่ใจว่าตัวระบุรายการ 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/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 จะไม่เริ่มต้น Thread Pool โดยอัตโนมัติเมื่อส่งออบเจ็กต์ Binder โดยต้องเริ่มต้นด้วยตนเอง (ดูการจัดการเธรด)
- AIDL จะไม่หยุดทำงานเมื่อมีข้อผิดพลาดในการขนส่งที่ไม่ได้ตรวจสอบ (HIDL
Return
จะหยุดทำงานเมื่อมีข้อผิดพลาดที่ไม่ได้ตรวจสอบ) - AIDL ประกาศได้เพียง 1 ประเภทต่อไฟล์
- อาร์กิวเมนต์ AIDL สามารถระบุเป็น in/out/inout นอกเหนือจากพารามิเตอร์เอาต์พุต (ไม่มี "การเรียกกลับแบบซิงค์")
- AIDL ใช้ fd เป็นประเภทพื้นฐานแทนตัวแฮนเดิล
- 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 พร้อมทดสอบการใช้งานของผู้ให้บริการรายใหม่ทันทีที่มีฮาร์ดแวร์และอุปกรณ์ใหม่