ทุกอินเทอร์เฟซที่กำหนดไว้ในแพ็กเกจ HIDL มีคลาส C++ ที่สร้างขึ้นโดยอัตโนมัติของตนเอง ภายในเนมสเปซของแพ็กเกจ ไคลเอ็นต์และเซิร์ฟเวอร์จะจัดการกับอินเทอร์เฟซใน ได้หลายวิธีดังนี้
- เซิร์ฟเวอร์ใช้อินเทอร์เฟซต่างๆ
- วิธีการเรียกใช้ไคลเอ็นต์บนอินเทอร์เฟซ
อินเทอร์เฟซอาจลงทะเบียนด้วยชื่อโดยเซิร์ฟเวอร์ หรือส่งเป็น เป็นเมธอดที่กำหนดโดย HIDL ตัวอย่างเช่น โค้ดเฟรมเวิร์กอาจแสดง เพื่อรับข้อความแบบไม่พร้อมกันจาก HAL และส่งอินเทอร์เฟซนั้น ไปยัง HAL โดยตรงโดยไม่ต้องลงทะเบียน
การใช้งานเซิร์ฟเวอร์
เซิร์ฟเวอร์ที่ใช้อินเทอร์เฟซ IFoo
ต้องมีแอตทริบิวต์
ไฟล์ส่วนหัว IFoo
ที่สร้างขึ้นโดยอัตโนมัติ:
#include <android/hardware/samples/1.0/IFoo.h>
ส่วนหัวจะถูกส่งออกโดยอัตโนมัติโดยไลบรารีที่ใช้ร่วมกันของ
อินเทอร์เฟซของ IFoo
ที่จะลิงก์ด้วย ตัวอย่าง IFoo.hal
:
// IFoo.hal interface IFoo { someMethod() generates (vec<uint32_t>); ... }
โครงสร้างตัวอย่างสำหรับการติดตั้งใช้งานเซิร์ฟเวอร์ของอินเทอร์เฟซ IFoo
// From the IFoo.h header using android::hardware::samples::V1_0::IFoo; class FooImpl : public IFoo { Return<void> someMethod(foo my_foo, someMethod_cb _cb) { vec<uint32_t> return_data; // Compute return_data _cb(return_data); return Void(); } ... };
หากต้องการทำให้การใช้งานอินเทอร์เฟซเซิร์ฟเวอร์พร้อมใช้งานสำหรับไคลเอ็นต์ คุณต้อง ทำสิ่งต่อไปนี้ได้
- ลงทะเบียนการใช้งานอินเทอร์เฟซด้วย
hwservicemanager
(ดูรายละเอียดด้านล่าง)
หรือ
- ส่งการติดตั้งใช้งานอินเทอร์เฟซเป็นอาร์กิวเมนต์ของ เมธอดของอินเทอร์เฟซ (สำหรับการแยกส่วน โปรดดูอะซิงโครนัส Callback)
เมื่อลงทะเบียนการใช้งานอินเทอร์เฟซ
กระบวนการ hwservicemanager
จะติดตามอินเทอร์เฟซ HIDL ที่ลงทะเบียนไว้
ทำงานบนอุปกรณ์
ตามชื่อและเวอร์ชัน เซิร์ฟเวอร์สามารถลงทะเบียนอินเทอร์เฟซ HIDL ได้
การใช้งานตามชื่อ และลูกค้าจะขอการติดตั้งใช้งานบริการตามชื่อได้
และเวอร์ชัน กระบวนการนี้จะแสดงอินเทอร์เฟซ HIDL
android.hidl.manager@1.0::IServiceManager
ไฟล์ส่วนหัวของอินเทอร์เฟซ HIDL ที่สร้างขึ้นโดยอัตโนมัติแต่ละไฟล์ (เช่น IFoo.h
)
มีเมธอด registerAsService()
ซึ่งสามารถใช้เพื่อลงทะเบียน
อินเทอร์เฟซด้วย hwservicemanager
มีเพียง
อาร์กิวเมนต์ที่จำเป็นคือชื่อของการใช้งานอินเทอร์เฟซในฐานะไคลเอ็นต์
ใช้ชื่อนี้เพื่อเรียกอินเทอร์เฟซจาก hwservicemanager
ภายหลัง:
::android::sp<IFoo> myFoo = new FooImpl(); ::android::sp<IFoo> mySecondFoo = new FooAnotherImpl(); status_t status = myFoo->registerAsService(); status_t anotherStatus = mySecondFoo->registerAsService("another_foo");
hwservicemanager
จะถือว่าชุดค่าผสมของค่า
[package@version::interface, instance_name]
ไม่ซ้ำกันสำหรับการเปิดใช้
อินเทอร์เฟซที่แตกต่างกัน (หรืออินเทอร์เฟซเดียวกันแต่คนละเวอร์ชัน) ที่จะลงทะเบียน
ที่มีชื่ออินสแตนซ์เหมือนกันโดยไม่มีข้อขัดแย้ง หากคุณโทรหา
registerAsService()
ที่มีเวอร์ชันแพ็กเกจ อินเทอร์เฟซ และเวอร์ชันที่เหมือนกัน
และชื่ออินสแตนซ์ hwservicemanager
จะทิ้งการอ้างอิงไปยังฟังก์ชัน
ที่ลงทะเบียนไว้ก่อนหน้านี้และใช้บริการใหม่
การใช้งานไคลเอ็นต์
ไคลเอ็นต์ต้อง #include
ทุกอินเทอร์เฟซเช่นเดียวกับเซิร์ฟเวอร์
มันหมายถึง:
#include <android/hardware/samples/1.0/IFoo.h>
ลูกค้าสามารถรับอินเทอร์เฟซได้ 2 วิธี ดังนี้
- ถึงวันที่
I<InterfaceName>::getService
(ผ่านhwservicemanager
) - ผ่านวิธีอินเทอร์เฟซ
ไฟล์ส่วนหัวของอินเทอร์เฟซที่สร้างขึ้นโดยอัตโนมัติแต่ละไฟล์มี getService
แบบคงที่
ที่สามารถใช้เพื่อเรียกอินสแตนซ์บริการจาก
hwservicemanager
:
// getService returns nullptr if the service can't be found sp<IFoo> myFoo = IFoo::getService(); sp<IFoo> myAlternateFoo = IFoo::getService("another_foo");
ตอนนี้ไคลเอ็นต์มีอินเทอร์เฟซ IFoo
และสามารถเรียกใช้เมธอดเพื่อ
ราวกับว่าเป็นการนำไปใช้งานในชั้นเรียนในท้องถิ่น ในความเป็นจริง การติดตั้งโฆษณา
สามารถทำงานในกระบวนการเดียวกัน กระบวนการอื่น หรือแม้แต่บนอุปกรณ์อื่น
(โดยทำงานระยะไกล HAL) เนื่องจากลูกค้าโทรหา getService
บน
รวมออบเจ็กต์ IFoo
จากแพ็กเกจเวอร์ชัน 1.0
แล้ว
hwservicemanager
จะแสดงผลการใช้งานเซิร์ฟเวอร์เฉพาะในกรณีที่
การใช้งานเข้ากันได้กับไคลเอ็นต์ 1.0
ในทางปฏิบัติ
หมายถึงการใช้งานเซิร์ฟเวอร์กับเวอร์ชัน 1.n
(เวอร์ชัน
x.(y+1)
ของอินเทอร์เฟซต้องขยาย (รับค่าจาก)
x.y
)
นอกจากนี้ ยังมีวิธี castFrom
สำหรับการแคสต์ระหว่าง
อินเทอร์เฟซต่างๆ ได้ วิธีนี้ทำงานด้วยการเรียก IPC ไปยังรีโมต
เพื่อให้แน่ใจว่าประเภทที่สำคัญตรงกับประเภทที่แสดง
ที่ขอ หากไม่มีประเภทที่ขอ nullptr
จะเป็น
ส่งคืนแล้ว
sp<V1_0::IFoo> foo1_0 = V1_0::IFoo::getService(); sp<V1_1::IFoo> foo1_1 = V1_1::IFoo::castFrom(foo1_0);
Callback แบบอะซิงโครนัส
การใช้งาน HAL ที่มีอยู่แล้วจำนวนมากจะสื่อสารกับฮาร์ดแวร์แบบอะซิงโครนัส ซึ่งหมายความว่า ลูกค้าต้องการวิธีที่ไม่พร้อมกันในการแจ้งลูกค้าถึงเหตุการณ์ใหม่ เกิดขึ้น อินเทอร์เฟซ HIDL สามารถใช้เป็น Callback แบบไม่พร้อมกันเนื่องจาก HIDL ฟังก์ชันอินเทอร์เฟซสามารถใช้ออบเจ็กต์อินเทอร์เฟซ HIDL เป็นพารามิเตอร์ได้
ตัวอย่างไฟล์อินเทอร์เฟซ IFooCallback.hal
package android.hardware.samples@1.0; interface IFooCallback { sendEvent(uint32_t event_id); sendData(vec<uint8_t> data); }
ตัวอย่างเมธอดใหม่ใน IFoo
ที่ใช้
พารามิเตอร์ IFooCallback
:
package android.hardware.samples@1.0; interface IFoo { struct Foo { int64_t someValue; handle myHandle; }; someMethod(Foo foo) generates (int32_t ret); anotherMethod() generates (vec<uint32_t>); registerCallback(IFooCallback callback); };
ไคลเอ็นต์ที่ใช้อินเทอร์เฟซ IFoo
คือ
เซิร์ฟเวอร์ของอินเทอร์เฟซ IFooCallback
จะมี
การใช้งาน IFooCallback
:
class FooCallback : public IFooCallback { Return<void> sendEvent(uint32_t event_id) { // process the event from the HAL } Return<void> sendData(const hidl_vec<uint8_t>& data) { // process data from the HAL } };
และยังส่งผ่านอินสแตนซ์ที่มีอยู่ของ
อินเทอร์เฟซ IFoo
:
sp<IFooCallback> myFooCallback = new FooCallback(); myFoo.registerCallback(myFooCallback);
เซิร์ฟเวอร์ที่ใช้งาน IFoo
จะได้รับข้อมูลนี้เป็น
sp<IFooCallback>
ออบเจ็กต์ ช่วยจัดเก็บ Callback และ
กลับเข้าไปในไคลเอ็นต์ เมื่อใดก็ตามที่ต้องการใช้อินเทอร์เฟซนี้
ผู้รับเสียชีวิต
เนื่องจากการใช้บริการอาจทำงานในกระบวนการอื่น จึงอาจเกิดขึ้นได้
กระบวนการที่ใช้อินเทอร์เฟซจะหายไปขณะที่ไคลเอ็นต์ยังทำงานอยู่
การเรียกใช้ออบเจ็กต์อินเทอร์เฟซที่โฮสต์ในกระบวนการที่หยุดทำงานแล้วไม่สำเร็จ
มีข้อผิดพลาดการขนส่ง (isOK()
แสดงผล false
) วิธีเดียวในการ
กู้คืนจากความล้มเหลวดังกล่าว คือการขอบริการอินสแตนซ์ใหม่โดย
กำลังโทรหา I<InterfaceName>::getService()
วิธีนี้ใช้ได้ก็ต่อเมื่อ
กระบวนการที่ขัดข้องได้เริ่มต้นใหม่และลงทะเบียนบริการอีกครั้งด้วย
servicemanager
(ซึ่งโดยทั่วไปจะเป็นจริงสำหรับการติดตั้งใช้งาน HAL)
แทนที่จะต้องจัดการปัญหานี้ในเชิงรับ ลูกค้าที่ใช้อินเทอร์เฟซยังสามารถ
ลงทะเบียนผู้รับที่เสียชีวิตเพื่อรับการแจ้งเตือนเมื่อบริการสิ้นสุดลง
หากต้องการลงทะเบียนการแจ้งเตือนดังกล่าวในอินเทอร์เฟซ IFoo
ที่ดึงข้อมูลมา
ทำสิ่งต่อไปนี้ได้
foo->linkToDeath(recipient, 1481 /* cookie */);
พารามิเตอร์ recipient
ต้องเป็นการใช้งาน
android::hardware::hidl_death_recipient
มาจาก HIDL
ซึ่งมีเมธอด serviceDied()
เดียวที่เรียกว่า
จากเทรดใน Threadpool ของ RPC เมื่อกระบวนการที่โฮสต์อินเทอร์เฟซไม่ทำงาน
class MyDeathRecipient : public android::hardware::hidl_death_recipient { virtual void serviceDied(uint64_t cookie, const android::wp<::android::hidl::base::V1_0::IBase>& who) { // Deal with the fact that the service died } }
พารามิเตอร์ cookie
มีคุกกี้ที่ส่งผ่านด้วย
linkToDeath()
ในขณะที่พารามิเตอร์ who
มี
จุดอ่อนไปยังออบเจ็กต์ที่แสดงบริการในไคลเอ็นต์ ด้วยฟังก์ชัน
การโทรตัวอย่างที่ระบุไว้ข้างต้น cookie
เท่ากับ 1481 และ who
เท่ากับ foo
คุณยังยกเลิกการลงทะเบียนผู้รับที่เสียชีวิตหลังจากที่ลงทะเบียนไปแล้วได้ด้วย โดยทำดังนี้
foo->unlinkToDeath(recipient);