ภาษานิยามอินเทอร์เฟซ HAL หรือ HIDL เป็นภาษาคำอธิบายอินเทอร์เฟซ (IDL) เพื่อระบุอินเทอร์เฟซระหว่าง HAL กับผู้ใช้ HIDL อนุญาตให้ระบุประเภทและการเรียกใช้เมธอด ซึ่งรวบรวมไว้ในอินเทอร์เฟซและแพ็กเกจ กล่าวอย่างกว้างๆ ก็คือ HIDL เป็นระบบสำหรับการสื่อสารระหว่างโค้ดเบสที่อาจได้รับการคอมไพล์อย่างอิสระ
HIDL มีไว้เพื่อการสื่อสารระหว่างกระบวนการ (IPC) HAL ที่สร้างขึ้นด้วย HDL เรียกว่า Binderized HALs ที่สื่อสารกับเลเยอร์สถาปัตยกรรมอื่นๆ โดยใช้การเรียกใช้ Binder Inter-Process Communication (IPC) ได้ Binderized HAL จะทำงานในกระบวนการที่แยกต่างหากจากไคลเอ็นต์ที่ใช้ HAL สำหรับไลบรารีที่ต้องลิงก์กับกระบวนการจะมีโหมดส่งผ่านให้ใช้ด้วย (ไม่รองรับใน Java)
HIDL ระบุโครงสร้างข้อมูลและลายเซ็นเมธอด ซึ่งจัดระเบียบในอินเทอร์เฟซ (คล้ายกับคลาส) ซึ่งรวบรวมไว้ในแพ็กเกจ ไวยากรณ์ของ HIDL มีความคุ้นเคยสำหรับโปรแกรมเมอร์ C++ และ Java แต่ใช้ชุดคีย์เวิร์ดต่างกัน HIDL ยังใช้คำอธิบายประกอบแบบ Java ด้วย
คำศัพท์
ส่วนนี้ใช้คำที่เกี่ยวข้องกับ HIDL ต่อไปนี้
ถูกยึด | บ่งบอกว่ามีการใช้ HIDL สำหรับการเรียกใช้โพรซีเยอร์ระยะไกลระหว่างกระบวนการ ซึ่งนำไปใช้บนกลไกที่มีลักษณะเหมือน Binder ดูส่งผ่านด้วย |
---|---|
Callback, ไม่พร้อมกัน | อินเทอร์เฟซที่ให้บริการโดยผู้ใช้ HAL ส่งผ่านไปยัง HAL (โดยใช้วิธี HIDL) และการเรียกใช้โดย HAL เพื่อแสดงข้อมูลได้ทุกเมื่อ |
Callback, พร้อมกัน | ส่งคืนข้อมูลจากการใช้เมธอด HIDL ของเซิร์ฟเวอร์ไปยังไคลเอ็นต์ ไม่ใช้สำหรับวิธีการที่ส่งคืนค่าเป็นโมฆะหรือค่าพื้นฐานค่าเดียว |
ไคลเอ็นต์ | กระบวนการที่เรียกใช้เมธอดของอินเทอร์เฟซหนึ่งๆ กระบวนการของเฟรมเวิร์ก HAL หรือ Android อาจเป็นไคลเอ็นต์ของอินเทอร์เฟซหนึ่งและเซิร์ฟเวอร์ของอีกอินเทอร์เฟซหนึ่ง ดู Passthrough เพิ่มเติม |
ขยาย | บอกถึงอินเทอร์เฟซที่เพิ่มเมธอดและ/หรือประเภทให้กับอินเทอร์เฟซอื่น อินเทอร์เฟซหนึ่งสามารถขยายอินเทอร์เฟซอื่นได้เพียงรายการเดียวเท่านั้น สามารถใช้เพื่อเพิ่มเวอร์ชันย่อยในชื่อแพ็กเกจเดียวกัน หรือใช้สำหรับแพ็กเกจใหม่ (เช่น ส่วนขยายผู้ให้บริการ) เพื่อสร้างบนแพ็กเกจเก่า |
สร้าง | ระบุเมธอดอินเทอร์เฟซที่ส่งค่ากลับมาให้กับไคลเอ็นต์ หากต้องการแสดงผลค่าที่ไม่ใช่ค่าพื้นฐาน 1 ค่าหรือมากกว่า 1 ค่า ระบบจะสร้างฟังก์ชัน Callback แบบซิงโครนัส |
อินเทอร์เฟซ | การรวบรวมวิธีการและประเภท ได้รับการแปลเป็นคลาสใน C++ หรือ Java ระบบจะเรียกเมธอดทั้งหมดในอินเทอร์เฟซไปในทิศทางเดียวกัน กล่าวคือกระบวนการของไคลเอ็นต์จะเรียกใช้เมธอดที่ใช้โดยกระบวนการของเซิร์ฟเวอร์ |
เที่ยวเดียว | เมื่อใช้กับเมธอด HIDL จะบ่งบอกว่าเมธอดดังกล่าวไม่แสดงผลค่าใดๆ และไม่บล็อก |
พัสดุ | คอลเล็กชันอินเทอร์เฟซและประเภทข้อมูลที่แชร์เวอร์ชัน |
การปล่อยผ่านสัญญาณ | โหมด HIDL ซึ่งเซิร์ฟเวอร์เป็นไลบรารีที่ใช้ร่วมกัน ซึ่งไคลเอ็นต์dlopen กำหนด ในโหมดส่งผ่าน ไคลเอ็นต์และเซิร์ฟเวอร์เป็นกระบวนการเดียวกัน แต่โค้ดเบสแยกต่างหาก ใช้เพื่อนำฐานของโค้ดเดิมไปไว้ในโมเดล HIDL เท่านั้น
ดูการเชื่อมโยงเพิ่มเติม |
เซิร์ฟเวอร์ | กระบวนการที่ใช้วิธีการของอินเทอร์เฟซ ดู Passthrough เพิ่มเติม |
การขนส่ง | โครงสร้างพื้นฐาน HIDL ที่ย้ายข้อมูลระหว่างเซิร์ฟเวอร์และไคลเอ็นต์ |
เวอร์ชัน | เวอร์ชันของแพ็กเกจ ประกอบด้วยจำนวนเต็ม 2 ตัว ได้แก่ หลักและรอง การเพิ่มเวอร์ชันเล็กน้อยอาจเพิ่มประเภทและวิธีการ (แต่จะเปลี่ยนแปลงไม่ได้) |
รูปแบบ HIDL
เป้าหมายของ HIDL คือการแทนที่เฟรมเวิร์ก Android โดยไม่ต้องสร้าง HAL ใหม่ HAL จะสร้างขึ้นโดยผู้ให้บริการหรือผู้ผลิต SOC แล้วใส่พาร์ติชัน /vendor
ในอุปกรณ์ ทำให้เฟรมเวิร์ก Android อยู่ในพาร์ติชันของตนเองเปลี่ยนไปเป็น OTA โดยไม่ต้องคอมไพล์ HAL ใหม่
การออกแบบ HIDL ช่วยสร้างสมดุลให้กับข้อกังวลต่อไปนี้
- ความสามารถในการทำงานร่วมกัน สร้างอินเทอร์เฟซที่ทำงานร่วมกันได้อย่างเสถียรระหว่างกระบวนการต่างๆ ซึ่งอาจคอมไพล์ด้วยสถาปัตยกรรม เครื่องมือเชน และการกำหนดค่าบิลด์ที่หลากหลาย อินเทอร์เฟซ HIDL ได้รับการปรับเวอร์ชันและจะเปลี่ยนแปลงไม่ได้หลังจากเผยแพร่แล้ว
- ประสิทธิภาพ HIDL จะพยายามลดจำนวนการดำเนินการคัดลอก ระบบจะส่งข้อมูลที่ HIDL กำหนดไปยังโค้ด C++ ในโครงสร้างข้อมูลเลย์เอาต์มาตรฐาน C++ ที่ใช้ได้โดยไม่ต้องคลายการแพคข้อมูล HIDL ยังจัดเตรียมอินเทอร์เฟซหน่วยความจำที่ใช้ร่วมกัน และเนื่องจาก RPC ค่อนข้างช้าอยู่แล้ว HIDL จึงรองรับการโอนข้อมูล 2 วิธีโดยไม่ต้องใช้การเรียก RPC ได้แก่ หน่วยความจำที่ใช้ร่วมกันและคิวข้อความด่วน (FMQ)
- ใช้งานง่าย HIDL หลีกเลี่ยงปัญหาที่ยากลำบากในการเป็นเจ้าของหน่วยความจำด้วยการใช้พารามิเตอร์
in
สำหรับ RPC เท่านั้น (ดู Android Interface Definition Language (AIDL)) ค่าที่ไม่สามารถแสดงกลับอย่างมีประสิทธิภาพจากเมธอดได้จะถูกส่งคืนผ่านฟังก์ชัน Callback ไม่ว่าการส่งผ่านข้อมูล ไปยัง HIDL เพื่อการโอนหรือการรับข้อมูลจาก HIDL จะเปลี่ยนแปลงการเป็นเจ้าของข้อมูล การเป็นเจ้าของจะยังคงเดิมกับฟังก์ชันการเรียกใช้ ข้อมูลจะต้องคงอยู่เป็นระยะเวลาของฟังก์ชันที่เรียกใช้เท่านั้น และอาจถูกทำลายได้ทันทีหลังจากฟังก์ชันที่เรียกกลับมาทำงาน
ใช้โหมดส่งผ่าน
หากต้องการอัปเดตอุปกรณ์ที่ใช้ Android เวอร์ชันก่อนหน้าเป็น Android O คุณสามารถรวม HAL ทั้งแบบทั่วไป (และแบบเดิม) ในอินเทอร์เฟซ HIDL ใหม่ที่แสดง HAL ในโหมด BAL และแบบกระบวนการเดียวกัน (ส่งผ่าน) การรวมนี้มีความโปร่งใสสำหรับทั้ง HAL และเฟรมเวิร์ก Android
โหมดส่งผ่านใช้ได้เฉพาะกับไคลเอ็นต์และการใช้งาน C++ เท่านั้น อุปกรณ์ที่ใช้ Android เวอร์ชันก่อนหน้าไม่มี HAL ที่เขียนด้วย Java ดังนั้น Java HAL จะมีการเชื่อมโยงอย่างเป็นธรรมชาติ
ไฟล์ส่วนหัวแบบ Passthrough
เมื่อคอมไพล์ไฟล์ .hal
แล้ว hidl-gen
จะสร้างไฟล์ส่วนหัว Passthrough เพิ่มเติม BsFoo.h
นอกเหนือจากส่วนหัวที่ใช้สำหรับการสื่อสาร Binder ส่วนหัวนี้จะกำหนดฟังก์ชันที่จะ dlopen
เมื่อ HAL ส่งผ่านจะทำงานในกระบวนการเดียวกันที่มีการเรียกใช้ ในกรณีส่วนใหญ่เมธอด Passthrough จะเรียกใช้โดยการเรียกใช้ฟังก์ชันโดยตรง (เทรดเดียวกัน) เมธอด oneway
จะทำงานในชุดข้อความของตัวเองเนื่องจากไม่ได้ตั้งใจจะรอให้ HAL ประมวลผลเมธอดดังกล่าว (ซึ่งหมายความว่า HAL ที่ใช้เมธอด oneway
ในโหมดส่งผ่านต้องเป็นแบบปลอดภัยของชุดข้อความ)
โดยใช้ IFoo.hal
แล้ว BsFoo.h
จะรวมวิธีการที่ HIDL สร้างขึ้นเพื่อมอบฟีเจอร์เพิ่มเติม (เช่น การทำธุรกรรม oneway
ให้ทำงานในเทรดอื่น) ไฟล์นี้คล้ายกับ BpFoo.h
แต่แทนที่จะส่งต่อการเรียกใช้ IPC โดยใช้ Binder ระบบจะเรียกใช้ฟังก์ชันที่ต้องการโดยตรง การติดตั้งใช้งาน HAL ในอนาคตอาจให้การใช้งานหลายแบบ เช่น FooFast HAL และ FooAccurate HAL ในกรณีดังกล่าว ระบบจะสร้างไฟล์สำหรับการใช้งานเพิ่มเติมแต่ละรายการ (เช่น PTFooFast.cpp
และ PTFooAccurate.cpp
)
การเชื่อมโยง HAL ของ Passthrough
คุณสามารถรวมการติดตั้งใช้งาน HAL ที่รองรับโหมดส่งผ่าน เมื่อมีอินเทอร์เฟซ HAL a.b.c.d@M.N::IFoo
ระบบจะสร้างแพ็กเกจ 2 รายการดังนี้
a.b.c.d@M.N::IFoo-impl
มีการใช้งาน HAL และแสดงฟังก์ชันIFoo* HIDL_FETCH_IFoo(const char* name)
ในอุปกรณ์เดิม แพ็กเกจนี้dlopen
จะได้รับการdlopen
และมีการยืนยันการใช้งานโดยใช้HIDL_FETCH_IFoo
คุณสร้างโค้ดพื้นฐานได้โดยใช้hidl-gen
และ-Lc++-impl
และ-Landroidbp-impl
a.b.c.d@M.N::IFoo-service
เปิด Passthrough HAL และลงทะเบียนตัวเองเป็นบริการรวมตัวที่เชื่อมโยง ทำให้สามารถใช้งาน HAL เดียวกันเพื่อใช้เป็นทั้ง Passthrough และ Binderized
เนื่องจากเป็นประเภท IFoo
คุณสามารถเรียกใช้ sp<IFoo>
IFoo::getService(string name, bool getStub)
เพื่อเข้าถึงอินสแตนซ์ของ IFoo
ได้ หาก getStub
เป็นจริง getService
จะพยายามเปิด HAL ในโหมดส่งผ่านเท่านั้น หาก getStub
เป็น "เท็จ" getService
จะพยายามค้นหาบริการที่มีการผูกมัดหากไม่สำเร็จ ระบบจะพยายามค้นหาบริการส่งผ่าน คุณไม่ควรใช้พารามิเตอร์ getStub
ยกเว้นใน defaultPassthroughServiceImplementation
(อุปกรณ์ที่เปิดตัวด้วย
Android O เป็นอุปกรณ์ที่มีการผูกมัดอย่างสมบูรณ์ ดังนั้นจึงไม่อนุญาตให้เปิดบริการในโหมดส่งผ่าน)
ไวยากรณ์ HIDL
ภาษา HIDL ออกแบบมาให้คล้ายกับภาษา C (แต่ไม่ได้ใช้ตัวประมวลผลล่วงหน้า C) เครื่องหมายวรรคตอนทั้งหมดที่ไม่ได้อธิบายไว้ด้านล่าง (นอกเหนือจากการใช้ =
และ |
ที่เห็นได้ชัด) เป็นส่วนหนึ่งของไวยากรณ์
หมายเหตุ: ดูรายละเอียดเกี่ยวกับรูปแบบโค้ด HIDL ได้ที่ Code Style Guide
/** */
ระบุความคิดเห็นในเอกสาร ซึ่งใช้ได้เฉพาะกับการประกาศประเภท เมธอด ช่อง และค่า Enum/* */
หมายถึงความคิดเห็นหลายบรรทัด//
หมายถึงความคิดเห็นที่ท้ายบรรทัด นอกจาก//
แล้ว บรรทัดใหม่จะเหมือนกับช่องว่างอื่นๆ- ในไวยากรณ์ตัวอย่างด้านล่าง ข้อความจาก
//
ถึงท้ายบรรทัดไม่ได้เป็นส่วนหนึ่งของไวยากรณ์ แต่เป็นความคิดเห็นเกี่ยวกับไวยากรณ์แทน [empty]
หมายความว่าคํานั้นอาจว่างเปล่า?
ที่ตามหลังตัวลิเทอรัลหรือคำศัพท์หมายความว่าไม่บังคับให้...
ระบุลำดับที่มีรายการเป็นศูนย์ขึ้นไปพร้อมด้วยเครื่องหมายวรรคตอนตามที่ระบุ ไม่มีอาร์กิวเมนต์แปรผันใน HIDL- องค์ประกอบของลำดับที่คั่นด้วยคอมมา
- เครื่องหมายอัฒภาคจะสิ้นสุดแต่ละองค์ประกอบ รวมถึงองค์ประกอบสุดท้าย
- ตัวพิมพ์ใหญ่ไม่ใช่เทอร์มินัล
italics
เป็นกลุ่มโทเค็น เช่นinteger
หรือidentifier
(กฎการแยกวิเคราะห์ C มาตรฐาน)constexpr
เป็นนิพจน์คงที่ของรูปแบบ C (เช่น1 + 1
และ1L << 3
)import_name
คือชื่อแพ็กเกจหรือชื่ออินเทอร์เฟซซึ่งเป็นไปตามที่อธิบายไว้ใน การกำหนดเวอร์ชัน HIDLwords
ตัวพิมพ์เล็กเป็นโทเค็นแบบลิเทอรัล
ตัวอย่าง
ROOT = PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... } // not for types.hal | PACKAGE IMPORTS ITEM ITEM... // only for types.hal; no method definitions ITEM = ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?; | safe_union identifier { UFIELD; UFIELD; ...}; | struct identifier { SFIELD; SFIELD; ...}; // Note - no forward declarations | union identifier { UFIELD; UFIELD; ...}; | enum identifier: TYPE { ENUM_ENTRY, ENUM_ENTRY ... }; // TYPE = enum or scalar | typedef TYPE identifier; VERSION = integer.integer; PACKAGE = package android.hardware.identifier[.identifier[...]]@VERSION; PREAMBLE = interface identifier EXTENDS EXTENDS = <empty> | extends import_name // must be interface, not package GENERATES = generates (FIELD, FIELD ...) // allows the Binder interface to be used as a type // (similar to typedef'ing the final identifier) IMPORTS = [empty] | IMPORTS import import_name; TYPE = uint8_t | int8_t | uint16_t | int16_t | uint32_t | int32_t | uint64_t | int64_t | float | double | bool | string | identifier // must be defined as a typedef, struct, union, enum or import // including those defined later in the file | memory | pointer | vec<TYPE> | bitfield<TYPE> // TYPE is user-defined enum | fmq_sync<TYPE> | fmq_unsync<TYPE> | TYPE[SIZE] FIELD = TYPE identifier UFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...}; | struct identifier { FIELD; FIELD; ...}; | union identifier { FIELD; FIELD; ...}; | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SIZE = // Must be greater than zero constexpr ANNOTATIONS = [empty] | ANNOTATIONS ANNOTATION ANNOTATION = | @identifier | @identifier(VALUE) | @identifier(ANNO_ENTRY, ANNO_ENTRY ...) ANNO_ENTRY = identifier=VALUE VALUE = "any text including \" and other escapes" | constexpr | {VALUE, VALUE ...} // only in annotations ENUM_ENTRY = identifier | identifier = constexpr