HIDL

ภาษานิยามอินเทอร์เฟซ 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