บริการและการโอนข้อมูล

หน้านี้จะอธิบายวิธีลงทะเบียนและสำรวจบริการและวิธีส่ง ข้อมูลไปยังบริการโดยวิธีการเรียกใช้ที่กำหนดไว้ในอินเทอร์เฟซใน .hal

ลงทะเบียนบริการ

ลงทะเบียนเซิร์ฟเวอร์อินเทอร์เฟซ HIDL (ออบเจ็กต์ที่ใช้อินเทอร์เฟซ) ได้ ว่าเป็นบริการที่มีชื่อ ชื่อที่จดทะเบียนไม่จำเป็นต้องเกี่ยวข้องกับอินเทอร์เฟซหรือ ชื่อแพ็กเกจ หากไม่ได้ระบุชื่อไว้ จะมีชื่อว่า "ค่าเริ่มต้น" ควร ใช้สำหรับ HAL ที่ไม่จำเป็นต้องลงทะเบียนเป็นการใช้งาน 2 แบบ ของ Google ตัวอย่างเช่น การเรียก C++ สำหรับการลงทะเบียนบริการที่กำหนดไว้ในแต่ละ คือ

status_t status = myFoo->registerAsService();
status_t anotherStatus = anotherFoo->registerAsService("another_foo_service");  // if needed

เวอร์ชันของอินเทอร์เฟซ HIDL จะรวมอยู่ในตัวอินเทอร์เฟซเอง ใช่เลย เชื่อมโยงโดยอัตโนมัติกับการลงทะเบียนบริการ และสามารถดึงข้อมูลผ่าน การเรียกเมธอด (android::hardware::IInterface::getInterfaceVersion()) ในทุกอินเทอร์เฟซ HIDL ออบเจ็กต์เซิร์ฟเวอร์ไม่จำเป็นต้องลงทะเบียนและสามารถส่งได้ ผ่านพารามิเตอร์เมธอด HIDL ไปยังกระบวนการอื่นที่ทำให้เรียกใช้เมธอด HIDL ไว้ในเซิร์ฟเวอร์

สำรวจบริการ

คำขอตามโค้ดของไคลเอ็นต์สร้างขึ้นสำหรับอินเทอร์เฟซที่กำหนด ตามชื่อและ โดยเรียก getService ในคลาส HAL ที่ต้องการ:

// C++
sp<V1_1::IFooService> service = V1_1::IFooService::getService();
sp<V1_1::IFooService> alternateService = V1_1::IFooService::getService("another_foo_service");
// Java
V1_1.IFooService service = V1_1.IFooService.getService(true /* retry */);
V1_1.IFooService alternateService = V1_1.IFooService.getService("another", true /* retry */);

อินเทอร์เฟซ HIDL แต่ละเวอร์ชันถือเป็นอินเทอร์เฟซที่แยกจากกัน ดังนั้น IFooService เวอร์ชัน 1.1 และ IFooService เวอร์ชัน 2.2 สามารถลงทะเบียนเป็น "foo_service" ทั้งคู่ และ getService("foo_service") ในอินเทอร์เฟซใดอินเทอร์เฟซหนึ่งจะได้รับการลงทะเบียน สำหรับอินเทอร์เฟซนั้น ดังนั้นในกรณีส่วนใหญ่จึงไม่จำเป็นต้องมีพารามิเตอร์ชื่อ ได้รับเพื่อการลงทะเบียนหรือการค้นพบ (หมายถึงชื่อ "ค่าเริ่มต้น")

นอกจากนี้ ออบเจ็กต์อินเทอร์เฟซผู้ให้บริการยังมีส่วนในวิธีการขนส่งของ อินเทอร์เฟซที่แสดงกลับมา สำหรับอินเทอร์เฟซ IFoo ในแพ็กเกจ android.hardware.foo@1.0 แสดงอินเทอร์เฟซโดย IFoo::getService จะใช้วิธีการรับส่งข้อมูลที่ประกาศไว้เสมอสำหรับ android.hardware.foo ในไฟล์ Manifest ของอุปกรณ์หากมีรายการนั้น และหากวิธี Transport ไม่พร้อมใช้งาน ระบบจะแสดงผล nullptr

ในบางกรณี คุณอาจจำเป็นต้องดำเนินการต่อทันทีแม้จะไม่มี กำลังรับบริการ กรณีนี้อาจเกิดขึ้นได้ (ตัวอย่างเช่น) เมื่อลูกค้าต้องการ จัดการการแจ้งเตือนบริการด้วยตนเอง หรือในโปรแกรมการวินิจฉัย (เช่น atrace) ซึ่งต้องได้รับ Hwservices ทั้งหมดและเรียกดู ใน ในกรณีนี้ มีการระบุ API เพิ่มเติม เช่น tryGetService ใน C++ หรือ getService("instance-name", false) ใน Java API เดิม ต้องใช้ getService ที่ให้ไว้ใน Java กับบริการ การแจ้งเตือน การใช้ API นี้ไม่ได้หลีกเลี่ยงเงื่อนไขการแข่งขันที่เซิร์ฟเวอร์ ลงทะเบียนตัวเองหลังจากที่ไคลเอ็นต์ส่งคำขอโดยใช้ API ที่ไม่ทดลองซ้ำรายการใดรายการหนึ่งเหล่านี้

การแจ้งเตือนการเสียชีวิตของบริการ

ลูกค้าที่ต้องการรับการแจ้งเตือนเมื่อบริการเสียชีวิตอาจได้รับการเสียชีวิต ที่ส่งมาตามเฟรมเวิร์ก หากต้องการรับการแจ้งเตือน ลูกค้า ต้อง

  1. คลาสย่อยของคลาส/อินเทอร์เฟซ HIDL hidl_death_recipient (ใน C++ ไม่ใช่ใน HIDL)
  2. ลบล้างเมธอด serviceDied() ของเมธอด
  3. สร้างอินสแตนซ์ออบเจ็กต์ของคลาสย่อย hidl_death_recipient
  4. เรียกใช้เมธอด linkToDeath() ในบริการเพื่อตรวจสอบ ส่งในออบเจ็กต์อินเทอร์เฟซของ IDeathRecipient โปรดทราบว่า วิธีการนี้ไม่ถือครองกรรมสิทธิ์ของผู้รับที่เสียชีวิตหรือผู้รับมอบอำนาจที่ผู้รับมอบสิทธิ์นั้น จะถูกเรียก

ตัวอย่าง Pseudocode (C++ และ Java มีความคล้ายคลึงกัน)

class IMyDeathReceiver : hidl_death_recipient {
  virtual void serviceDied(uint64_t cookie,
                           wp<IBase>& service) override {
    log("RIP service %d!", cookie);  // Cookie should be 42
  }
};
....
IMyDeathReceiver deathReceiver = new IMyDeathReceiver();
m_importantService->linkToDeath(deathReceiver, 42);

ผู้รับเสียชีวิตรายเดียวกันสามารถลงทะเบียนในหลายบริการได้

การโอนข้อมูล

สามารถส่งข้อมูลไปยังบริการได้โดยวิธีการเรียกใช้ที่กำหนดไว้ในอินเทอร์เฟซใน .hal ไฟล์ โดยมีวิธีการ 2 ประเภทดังนี้

  • การบล็อกจะรอจนกว่าเซิร์ฟเวอร์จะสร้าง ผลลัพธ์
  • วิธีการแบบทางเดียวจะส่งข้อมูลในทิศทางเดียวเท่านั้น และไม่ส่งข้อมูล บล็อก หากปริมาณข้อมูลที่กำลังทำงานอยู่ในการเรียกใช้ RPC เกินการใช้งาน ขีดจำกัด การเรียกอาจบล็อกหรือส่งคืนสัญญาณระบุข้อผิดพลาด (ลักษณะการทำงานคือ ยังไม่ได้ระบุ)

เมธอดที่ไม่แสดงผลค่าแต่ไม่ได้ประกาศว่าเป็น oneway ยังบล็อกอยู่

เมธอดทั้งหมดที่ประกาศในอินเทอร์เฟซ HIDL จะเรียกในทิศทางเดียว จาก HAL หรือ HAL ก็ได้ อินเทอร์เฟซไม่ได้ระบุว่า ทิศทางที่เรียกใช้ สถาปัตยกรรมที่ต้องมีการเรียกเพื่อเริ่มต้น HAL ควรมีอินเทอร์เฟซ 2 แบบ (หรือมากกว่า) ในแพ็กเกจ HAL และแสดง ที่เหมาะสมจากแต่ละกระบวนการ คำว่า client และ server จะใช้ตามทิศทางการเรียกของอินเทอร์เฟซ (กล่าวคือ HAL อาจเป็นเซิร์ฟเวอร์ของอินเทอร์เฟซหนึ่งและไคลเอ็นต์ของอีกอินเทอร์เฟซหนึ่ง อินเทอร์เฟซ)

Callback

คำว่า callback หมายถึงแนวคิด 2 แบบที่แตกต่างกัน โดยแยกตาม synchronous Callback และ asynchronous Callback

การติดต่อกลับแบบซิงโครนัสใช้ในเมธอด HIDL บางอย่างที่ให้ผลลัพธ์ เมธอด HIDL ที่แสดงค่ามากกว่า 1 ค่า (หรือแสดง 1 ค่าของ ไม่ใช่ประเภทพื้นฐาน) จะแสดงผลลัพธ์ผ่านฟังก์ชัน Callback หากมีเพียงรายการเดียว แสดงผลและเป็นประเภทพื้นฐาน จะไม่มีการใช้ Callback และ จะแสดงผลจากเมธอด เซิร์ฟเวอร์จะนำวิธีการ HIDL ไปใช้และ ไคลเอ็นต์จะใช้ Callback

การติดต่อกลับแบบไม่พร้อมกันทำให้เซิร์ฟเวอร์ของอินเทอร์เฟซ HIDL ดำเนินการต่อไปนี้ได้ ทำให้เกิดการโทร ซึ่งทำได้โดยการส่งผ่านอินสแตนซ์ของอินเทอร์เฟซที่ 2 ผ่านอินเทอร์เฟซแรก ไคลเอ็นต์ของอินเทอร์เฟซแรกต้องทำหน้าที่เป็น ของคนที่ 2 เซิร์ฟเวอร์ของอินเทอร์เฟซแรกสามารถเรียกใช้เมธอดใน ออบเจ็กต์อินเทอร์เฟซที่ 2 ตัวอย่างเช่น การใช้งาน HAL สามารถส่งข้อมูล แบบไม่พร้อมกันกลับไปยังกระบวนการที่กำลังใช้งานอยู่ด้วยการเรียกใช้เมธอดใน ที่สร้างและแสดงโดยกระบวนการนั้น วิธีการในอินเทอร์เฟซที่ใช้ สำหรับการติดต่อกลับแบบไม่พร้อมกันอาจบล็อก (และอาจส่งคืนค่าไปยังผู้โทร) หรือ oneway ตัวอย่างเช่น โปรดดู "การติดต่อกลับแบบไม่พร้อมกัน" ใน HIDL C++

เพื่อให้การเป็นเจ้าของหน่วยความจำง่ายขึ้น การเรียกเมธอดและ Callback จะใช้เพียง มีพารามิเตอร์ in รายการและไม่รองรับ out หรือ inout พารามิเตอร์

ขีดจำกัดต่อธุรกรรม

ระบบไม่ได้กำหนดขีดจำกัดต่อธุรกรรมให้กับจำนวนข้อมูลที่ส่งใน HIDL เมธอดและ Callback อย่างไรก็ตาม การโทรที่เกิน 4KB ต่อธุรกรรม ถือว่าเกินความจำเป็น หากคุณเห็นข้อความนี้ ให้ลองปรับอินเทอร์เฟซ HIDL ใหม่อีกครั้ง แนะนำ ข้อจำกัดอีกประการหนึ่งคือทรัพยากรที่มีให้สำหรับ HIDL เพื่อรองรับการทำธุรกรรมหลายรายการพร้อมกัน หลายสกุลเงิน ธุรกรรมอาจอยู่ระหว่างดำเนินการพร้อมกันเนื่องจากมีชุดข้อความหลายรายการ หรือ กระบวนการส่งการโทรไปยังกระบวนการหรือการเรียก oneway หลายครั้งที่ ไม่ได้รับการจัดการอย่างรวดเร็วจากกระบวนการรับ พื้นที่รวมสูงสุด ใช้ได้กับการทำธุรกรรมพร้อมกันทั้งหมดคือ 1MB โดยค่าเริ่มต้น

ในอินเทอร์เฟซที่ออกแบบมาอย่างดี การใช้เกินขีดจำกัดทรัพยากรเหล่านี้ เกิดขึ้น หากเกิน การโทรที่เกินเกณฑ์อาจบล็อกจนกว่า ทรัพยากรพร้อมใช้งานหรือเป็นสัญญาณแสดงข้อผิดพลาดในการขนส่ง การแสดงแต่ละครั้งของ เกินขีดจำกัดต่อธุรกรรม หรือมีทรัพยากรการใช้งาน HIDL ล้นโดย ข้อมูลรวมของธุรกรรมในการบินจะได้รับการบันทึกเพื่ออำนวยความสะดวกในการแก้ไขข้อบกพร่อง

การติดตั้งใช้งานเมธอด

HIDL สร้างไฟล์ส่วนหัวซึ่งระบุประเภท เมธอด และ Callback ในภาษาเป้าหมาย (C++ หรือ Java) ต้นแบบของ HIDL เมธอดและ Callback จะเหมือนกันสำหรับทั้งโค้ดของไคลเอ็นต์และเซิร์ฟเวอร์ HIDL ระบบให้บริการพร็อกซีสำหรับเมธอดใน ฝั่งผู้โทรที่จัดการข้อมูลสำหรับการส่ง IPC และ stub ในฝั่งผู้โทรซึ่งส่งผ่านข้อมูลไปยังการติดตั้งใช้งาน วิธีการ

ผู้โทรของฟังก์ชัน (เมธอด HIDL หรือ Callback) เป็นเจ้าของข้อมูล ที่ส่งผ่านไปยังฟังก์ชัน และยังคงเป็นเจ้าของหลังการโทร ใน ทุกกรณีที่ผู้โทรไม่จำเป็นต้องเพิ่มพื้นที่ว่างหรือปล่อยพื้นที่เก็บข้อมูล

  • ใน C++ ข้อมูลอาจเป็นแบบอ่านอย่างเดียว (การพยายามเขียนข้อมูลอาจทำให้เกิด ความผิดพลาดของการแบ่งกลุ่มลูกค้า) และสามารถใช้ได้ตลอดระยะเวลาการโทร ลูกค้าสามารถ คัดลอกข้อมูลให้แพร่หลายไปมากกว่าการโทร
  • ใน Java โค้ดจะได้รับสำเนาข้อมูลในเครื่อง (ออบเจ็กต์ Java ปกติ) ซึ่งอาจเก็บและแก้ไข หรืออนุญาตให้เก็บขยะได้

การโอนข้อมูลที่ไม่ใช่ RPC

HIDL มี 2 วิธีในการโอนข้อมูลโดยไม่ต้องใช้การเรียก RPC ได้แก่แบบที่แชร์ หน่วยความจำและคิวข้อความด่วน (FMQ) ทั้ง 2 อย่างนี้รองรับเฉพาะใน C++ เท่านั้น

  • ความทรงจำที่แชร์ ประเภท HIDL ในตัวคือ memory ใช้เพื่อส่งผ่านออบเจ็กต์ที่แสดงถึงหน่วยความจำที่ใช้ร่วมกันซึ่งได้รับการจัดสรรแล้ว ใช้ในกระบวนการรับข้อมูลเพื่อแมปหน่วยความจำที่แชร์ได้
  • Fast Message Queue (FMQ) HIDL จะแสดงข้อความที่ใช้เทมเพลต ประเภทคิวที่ใช้การส่งผ่านข้อความโดยไม่ต้องรอ ไม่ได้ใช้เคอร์เนล หรือเครื่องจัดตารางเวลาในโหมดส่งผ่านหรือโหมด Binderized (การสื่อสารระหว่างอุปกรณ์ไม่ มีคุณสมบัติเหล่านี้) ตามปกติ HAL จะเป็นผู้ตั้งค่าช่วงท้ายของคิว การสร้างออบเจ็กต์ที่สามารถส่งผ่าน RPC ผ่านพารามิเตอร์ในตัว HIDL ประเภท MQDescriptorSync หรือ MQDescriptorUnsync ช่วงเวลานี้ กระบวนการรับของออบเจ็กต์สามารถใช้เพื่อตั้งค่าปลายอีกด้านของคิวได้
    • ไม่อนุญาตให้เพิ่มคิวการซิงค์ และมีคิวได้เพียงรายการเดียวเท่านั้น ผู้อ่าน
    • คิวยกเลิกการซิงค์จะได้รับอนุญาตให้ล้นเกิน และสามารถมีโปรแกรมอ่านได้หลายคน ข้อมูลแต่ละประเภทจะต้องอ่านข้อมูลทันเวลาหรือสูญหาย
    ไม่มีประเภทใดที่ได้รับอนุญาตให้แสดงผลน้อยกว่าที่ระบุ (การอ่านจากคิวที่ว่างเปล่าล้มเหลว) และ แต่ละประเภทจะมีผู้เขียนได้เพียงคนเดียว

ดูรายละเอียดเพิ่มเติมเกี่ยวกับ FMQ ได้ที่ Fast Message Queue (FMQ)