ภาษานิยามอินเทอร์เฟซ HAL หรือ HIDL เป็นภาษาคำอธิบายอินเทอร์เฟซ (IDL) เพื่อระบุอินเทอร์เฟซระหว่าง HAL และผู้ใช้ HIDL อนุญาตให้ระบุประเภทและการเรียกใช้เมธอด รวบรวมไว้ในอินเทอร์เฟซและแพ็คเกจ ในเชิงกว้างกว่านั้น HIDL เป็นระบบสำหรับการสื่อสารระหว่าง codebases ที่อาจถูกรวบรวมโดยอิสระ ตั้งแต่ Android 10 เป็นต้นมา HIDL เลิกใช้แล้ว และ Android กำลังโยกย้ายไปใช้ AIDL ทุกที่
HIDL มีวัตถุประสงค์เพื่อใช้สำหรับการสื่อสารระหว่างกระบวนการ (IPC) HAL ที่สร้างขึ้นด้วย HDL เรียกว่า Binderized HAL โดยสามารถสื่อสารกับเลเยอร์สถาปัตยกรรมอื่นๆ โดยใช้การเรียก Binder Inter-Process Communication (IPC) Binderized HAL ทำงานในกระบวนการแยกต่างหากจากไคลเอ็นต์ที่ใช้ สำหรับไลบรารีที่ต้องเชื่อมโยงกับโปรเซส โหมดพาส ทรูยังมีให้ใช้งาน (ไม่รองรับใน Java)
HIDL ระบุโครงสร้างข้อมูลและลายเซ็นเมธอด จัดระเบียบในส่วนต่อประสาน (คล้ายกับคลาส) ที่รวบรวมเป็นแพ็คเกจ ไวยากรณ์ของ HIDL ดูคุ้นเคยสำหรับโปรแกรมเมอร์ C++ และ Java แต่มีชุดคำหลักที่แตกต่างกัน HIDL ยังใช้คำอธิบายประกอบแบบ Java
คำศัพท์
ส่วนนี้ใช้คำศัพท์ที่เกี่ยวข้องกับ HIDL ต่อไปนี้:
ผูกมัด | บ่งชี้ว่า HIDL ถูกใช้สำหรับการเรียกโพรซีเดอร์ระยะไกลระหว่างโปรเซส ดำเนินการผ่านกลไกคล้าย Binder ดูทาง ผ่าน ด้วย |
---|---|
โทรกลับแบบอะซิงโครนัส | อินเทอร์เฟซที่ให้บริการโดยผู้ใช้ HAL ส่งผ่านไปยัง HAL (โดยใช้วิธี HIDL) และเรียกใช้โดย HAL เพื่อส่งคืนข้อมูลเมื่อใดก็ได้ |
โทรกลับ, ซิงโครนัส | ส่งคืนข้อมูลจากการใช้เมธอด HIDL ของเซิร์ฟเวอร์ไปยังไคลเอ็นต์ ไม่ใช้สำหรับเมธอดที่คืนค่าเป็นโมฆะหรือค่าดั้งเดิมค่าเดียว |
ลูกค้า | กระบวนการที่เรียกใช้เมธอดของอินเทอร์เฟซเฉพาะ กระบวนการเฟรมเวิร์ก HAL หรือ Android อาจเป็นไคลเอ็นต์ของอินเทอร์เฟซหนึ่งและเซิร์ฟเวอร์ของอีกอินเทอร์เฟซหนึ่ง ดูทาง ผ่าน ด้วย |
ขยาย | ระบุอินเทอร์เฟซที่เพิ่มเมธอดและ/หรือประเภทไปยังอินเทอร์เฟซอื่น อินเทอร์เฟซสามารถขยายอินเทอร์เฟซอื่นได้เพียงหนึ่งอินเทอร์เฟซเท่านั้น สามารถใช้สำหรับการเพิ่มเวอร์ชันรองในชื่อแพ็กเกจเดียวกันหรือสำหรับแพ็กเกจใหม่ (เช่น ส่วนขยายของผู้ขาย) เพื่อสร้างบนแพ็กเกจที่เก่ากว่า |
สร้าง | ระบุเมธอดอินเตอร์เฟสที่ส่งคืนค่าไปยังไคลเอ็นต์ หากต้องการส่งคืนค่าที่ไม่ใช่ค่าดั้งเดิมหนึ่งค่าหรือมากกว่าหนึ่งค่า ฟังก์ชันการโทรกลับแบบซิงโครนัสจะถูกสร้างขึ้น |
อินเตอร์เฟซ | การรวบรวมวิธีการและประเภท แปลเป็นคลาสใน C ++ หรือ Java เมธอดทั้งหมดในอินเทอร์เฟซถูกเรียกไปในทิศทางเดียวกัน: กระบวนการไคลเอ็นต์เรียกใช้เมธอดที่ดำเนินการโดยกระบวนการเซิร์ฟเวอร์ |
ทางเดียว | เมื่อนำไปใช้กับเมธอด HIDL แสดงว่าเมธอดไม่คืนค่าและไม่บล็อก |
บรรจุุภัณฑ์ | การรวบรวมอินเทอร์เฟซและประเภทข้อมูลที่ใช้เวอร์ชันร่วมกัน |
ทะลุผ่าน | โหมดของ HIDL ที่เซิร์ฟเวอร์เป็นไลบรารีที่ใช้ร่วมกัน dlopen ed โดยไคลเอ็นต์ ในโหมดพาสทรู ไคลเอนต์และเซิร์ฟเวอร์เป็นกระบวนการเดียวกัน แต่ฐานรหัสแยกกัน ใช้เพื่อนำ codebases ดั้งเดิมเข้าสู่โมเดล HIDL เท่านั้น ดูเพิ่มเติม ที่ Binderized |
เซิร์ฟเวอร์ | กระบวนการที่ใช้วิธีการของอินเทอร์เฟซ ดูทาง ผ่าน ด้วย |
ขนส่ง | โครงสร้างพื้นฐาน HIDL ที่ย้ายข้อมูลระหว่างเซิร์ฟเวอร์และไคลเอนต์ |
รุ่น | รุ่นของแพ็คเกจ ประกอบด้วยจำนวนเต็มสองจำนวนหลักและรอง การเพิ่มรุ่นย่อยอาจเพิ่ม (แต่ไม่เปลี่ยน) ประเภทและวิธีการ |
การออกแบบ HIDL
เป้าหมายของ HIDL คือสามารถเปลี่ยนเฟรมเวิร์ก Android ได้โดยไม่ต้องสร้าง HAL ใหม่ HAL จะถูกสร้างขึ้นโดยผู้ขายหรือผู้ผลิต SOC และใส่ในพาร์ติชั่น /vendor
บนอุปกรณ์ ทำให้สามารถแทนที่เฟรมเวิร์ก Android ในพาร์ติชันของตัวเองด้วย OTA โดยไม่ต้องคอมไพล์ HAL ใหม่
การออกแบบของ HIDL คำนึงถึงข้อกังวลต่อไปนี้:
- การทำงานร่วมกัน สร้างส่วนต่อประสานที่ทำงานร่วมกันได้อย่างน่าเชื่อถือระหว่างกระบวนการต่างๆ ซึ่งอาจถูกคอมไพล์ด้วยสถาปัตยกรรม ห่วงโซ่เครื่องมือ และการกำหนดค่าบิลด์ต่างๆ อินเทอร์เฟซ HIDL เป็นเวอร์ชันและไม่สามารถเปลี่ยนแปลงได้หลังจากเผยแพร่แล้ว
- ประสิทธิภาพ HIDL พยายามลดจำนวนการดำเนินการคัดลอก ข้อมูลที่กำหนดโดย HIDL จะถูกส่งไปยังโค้ด C++ ในโครงสร้างข้อมูลเค้าโครงมาตรฐานของ C++ ที่สามารถใช้ได้โดยไม่ต้องแตกไฟล์ HIDL ยังมีอินเทอร์เฟซหน่วยความจำที่ใช้ร่วมกัน และเนื่องจาก RPC นั้นค่อนข้างช้าอยู่แล้ว HIDL จึงสนับสนุนสองวิธีในการถ่ายโอนข้อมูลโดยไม่ใช้การเรียก RPC: หน่วยความจำที่ใช้ร่วมกันและ Fast Message Queue (FMQ)
- ใช้งานง่าย HIDL หลีกเลี่ยงปัญหายุ่งยากของการเป็นเจ้าของหน่วยความจำโดยใช้เฉพาะ
in
พารามิเตอร์สำหรับ RPC (ดูที่ Android Interface Definition Language (AIDL) ); ค่าที่ไม่สามารถส่งคืนได้อย่างมีประสิทธิภาพจากเมธอดจะถูกส่งกลับผ่านฟังก์ชันการเรียกกลับ การส่งข้อมูลไปยัง HIDL เพื่อถ่ายโอนหรือรับข้อมูลจาก HIDL จะไม่เปลี่ยนแปลงความเป็นเจ้าของข้อมูล ความเป็นเจ้าของจะยังคงอยู่กับฟังก์ชันการโทรเสมอ ข้อมูลจำเป็นต้องคงอยู่ในช่วงเวลาของฟังก์ชันที่เรียกเท่านั้น และอาจถูกทำลายทันทีหลังจากที่ฟังก์ชันที่เรียกกลับมา
โดยใช้โหมดการส่งผ่าน
หากต้องการอัปเดตอุปกรณ์ที่ใช้ Android เวอร์ชันก่อนหน้าเป็น Android O คุณสามารถรวม HAL แบบเดิม (และแบบเดิม) ไว้ในอินเทอร์เฟซ HIDL ใหม่ที่ให้บริการ HAL ในโหมด Binderized และโหมดกระบวนการเดียวกัน (ส่งผ่าน) การตัดคำนี้มีความโปร่งใสสำหรับทั้งเฟรมเวิร์ก HAL และ Android
โหมดพาสทรูใช้ได้เฉพาะกับไคลเอนต์ C++ และการใช้งานเท่านั้น อุปกรณ์ที่ใช้ Android เวอร์ชันก่อนหน้าไม่มี HAL ที่เขียนด้วย Java ดังนั้น Java HAL จึงถูกรวมเข้าด้วยกันโดยเนื้อแท้
ไฟล์ส่วนหัวแบบพาสทรู
เมื่อไฟล์ .hal ถูกคอมไพล์ .hal
hidl-gen
จะสร้างไฟล์ส่วนหัว passthrough BsFoo.h
เพิ่มเติมจากส่วนหัวที่ใช้สำหรับการสื่อสารของแฟ้ม ส่วนหัวนี้กำหนดฟังก์ชันที่จะ dlopen
ed เนื่องจาก HAL แบบพาสทรูทำงานในกระบวนการเดียวกับที่เรียกใช้ ในกรณีส่วนใหญ่เมธอดแบบพาสทรูจะถูกเรียกใช้โดยการเรียกฟังก์ชันโดยตรง (เธรดเดียวกัน) oneway
ทางเดียวทำงานในเธรดของตัวเองเนื่องจากไม่ได้ตั้งใจรอให้ HAL ประมวลผล (นั่นหมายความว่า HAL ใดๆ ที่ใช้วิธีทาง oneway
ในโหมดพาสทรูจะต้องปลอดภัยสำหรับเธรด)
กำหนด IFoo.hal
, BsFoo.h
รวมเมธอดที่สร้างโดย HIDL เพื่อให้คุณสมบัติเพิ่มเติม (เช่น การทำธุรกรรมทาง oneway
ทำงานในเธรดอื่น) ไฟล์นี้คล้ายกับ BpFoo.h
อย่างไรก็ตาม แทนที่จะส่งผ่านการเรียก IPC โดยใช้เครื่องผูก ฟังก์ชันที่ต้องการจะถูกเรียกใช้โดยตรง การใช้งาน HAL ในอนาคต อาจมี การใช้งานที่หลากหลาย เช่น FooFast HAL และ FooAccurate HAL ในกรณีดังกล่าว ไฟล์สำหรับการใช้งานเพิ่มเติมแต่ละรายการจะถูกสร้างขึ้น (เช่น PTFooFast.cpp
และ PTFooAccurate.cpp
)
Binderizing passthrough HALs
คุณสามารถเชื่อมโยงการใช้งาน HAL ที่รองรับโหมดการส่งผ่าน กำหนดอินเทอร์เฟซ HAL abcd@MN::IFoo
สองแพ็คเกจจะถูกสร้างขึ้น:
-
abcd@MN::IFoo-impl
ประกอบด้วยการใช้งาน HAL และเปิดเผยฟังก์ชันIFoo* HIDL_FETCH_IFoo(const char* name)
บนอุปกรณ์รุ่นเก่า แพ็คเกจนี้จะถูกdlopen
ed และการใช้งานจะถูกสร้างอินสแตนซ์โดยใช้HIDL_FETCH_IFoo
คุณสามารถสร้างรหัสฐานโดยใช้hidl-gen
และ-Lc++-impl
และ-Landroidbp-impl
-
abcd@MN::IFoo-service
เปิด HAL แบบพาสทรูและลงทะเบียนตัวเองเป็นบริการ Binderized ทำให้สามารถนำ HAL เดียวกันไปใช้ได้ทั้งแบบพาสทรูและ Binderized
กำหนดประเภท IFoo
คุณสามารถเรียก sp<IFoo> IFoo::getService(string name, bool getStub)
เพื่อเข้าถึงอินสแตนซ์ของ IFoo
หาก getStub
เป็นจริง getService
จะพยายามเปิด HAL ในโหมดพาสทรูเท่านั้น หาก getStub
เป็นเท็จ getService
จะพยายามค้นหาบริการที่ถูกผูกไว้ หากล้มเหลวก็จะพยายามค้นหาบริการพาสทรู ไม่ควรใช้พารามิเตอร์ getStub
ยกเว้นใน defaultPassthroughServiceImplementation
(อุปกรณ์ที่เปิดตัวด้วย Android O เป็นอุปกรณ์ที่มีการผูกมัดอย่างสมบูรณ์ ดังนั้นการเปิดบริการในโหมดพาสทรูจึงไม่ได้รับอนุญาต)
ไวยากรณ์ HIDL
โดยการออกแบบแล้ว ภาษา HIDL คล้ายกับภาษาซี (แต่ไม่ได้ใช้ตัวประมวลผลล่วงหน้าของภาษาซี) เครื่องหมายวรรคตอนทั้งหมดที่ไม่ได้อธิบายไว้ด้านล่าง (นอกเหนือจากการใช้ =
และ |
) เป็นส่วนหนึ่งของไวยากรณ์
หมายเหตุ: สำหรับรายละเอียดเกี่ยวกับรูปแบบรหัส HIDL โปรดดูคำ แนะนำรูปแบบรหัส
-
/** */
ระบุความคิดเห็นเอกสาร สิ่งเหล่านี้สามารถใช้ได้กับการประกาศประเภท วิธีการ ฟิลด์ และค่า enum เท่านั้น -
/* */
ระบุความคิดเห็นหลายบรรทัด -
//
ระบุความคิดเห็นที่ท้ายบรรทัด นอกเหนือจาก//
การขึ้นบรรทัดใหม่จะเหมือนกับช่องว่างอื่นๆ - ในตัวอย่างไวยากรณ์ด้านล่าง ข้อความจาก
//
ถึงท้ายบรรทัดไม่ได้เป็นส่วนหนึ่งของไวยากรณ์ แต่เป็นข้อคิดเห็นเกี่ยวกับไวยากรณ์แทน -
[empty]
แปลว่า คำนั้นอาจว่างเปล่า -
?
ตามตัวอักษรหรือคำศัพท์หมายความว่าเป็นทางเลือก -
...
ระบุลำดับที่มีรายการเป็นศูนย์หรือมากกว่าโดยมีเครื่องหมายวรรคตอนคั่นตามที่ระบุ ไม่มีอาร์กิวเมนต์ที่แตกต่างกันใน HIDL - องค์ประกอบลำดับที่คั่นด้วยเครื่องหมายจุลภาค
- เครื่องหมายอัฒภาคจะยุติแต่ละองค์ประกอบ รวมถึงองค์ประกอบสุดท้าย
- ตัวพิมพ์ใหญ่เป็น nonterminal
-
italics
เป็นตระกูลโทเค็น เช่นinteger
หรือidentifier
(กฎการแยกวิเคราะห์มาตรฐาน C) -
constexpr
เป็นนิพจน์คงที่สไตล์ C (เช่น1 + 1
และ1L << 3
) -
import_name
เป็นชื่อแพ็คเกจหรืออินเทอร์เฟซ มีคุณสมบัติตามที่อธิบายไว้ใน HIDL Versioning -
words
ตัวพิมพ์เล็กเป็นโทเค็นตัวอักษร
ตัวอย่าง:
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