HIDL

ภาษานิยามอินเทอร์เฟซ HAL หรือ HIDL (ออกเสียงว่า "hide-l") เป็นภาษาคำอธิบายอินเทอร์เฟซ (IDL) เพื่อระบุอินเทอร์เฟซระหว่าง HAL และผู้ใช้ อนุญาตให้ระบุประเภทและการเรียกใช้เมธอด รวบรวมไว้ในอินเทอร์เฟซและแพ็กเกจ กว้างกว่านั้น HIDL เป็นระบบสำหรับการสื่อสารระหว่าง codebases ที่อาจรวบรวมอย่างอิสระ สำหรับ Android 10 นั้น HIDL เลิกใช้แล้ว และ Android กำลังโยกย้ายไปใช้ AIDL ทุกที่

HIDL มีวัตถุประสงค์เพื่อใช้สำหรับการสื่อสารระหว่างกระบวนการ (IPC) การสื่อสารระหว่างกระบวนการจะเรียกว่าเป็น Binderized สำหรับห้องสมุดที่จะต้องเชื่อมโยงกับกระบวนการที่เป็น โหมด passthrough ยังมีอยู่ (ไม่ได้รับการสนับสนุนใน Java)

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

การออกแบบ HIDL

เป้าหมายของ HIDL คือสามารถเปลี่ยนเฟรมเวิร์กได้โดยไม่ต้องสร้าง HAL ใหม่ HAL ที่จะถูกสร้างขึ้นโดยผู้ขายหรือผู้ผลิต SOC และใส่ใน /vendor พาร์ทิชันบนอุปกรณ์ที่ช่วยให้กรอบในพาร์ทิชันของตัวเองที่จะถูกแทนที่ด้วย OTA โดยไม่ต้อง recompiling HALs

การออกแบบ HIDL สร้างสมดุลให้กับข้อกังวลต่อไปนี้:

  • การทำงานร่วมกัน สร้างอินเทอร์เฟซที่ทำงานร่วมกันได้อย่างน่าเชื่อถือระหว่างกระบวนการ ซึ่งอาจคอมไพล์ด้วยสถาปัตยกรรม เครื่องมือโซ่ และการกำหนดค่าบิลด์ต่างๆ อินเทอร์เฟซ HIDL เป็นเวอร์ชันและไม่สามารถเปลี่ยนแปลงได้หลังจากเผยแพร่แล้ว
  • อย่างมีประสิทธิภาพ HIDL พยายามลดจำนวนการดำเนินการคัดลอกให้เหลือน้อยที่สุด ข้อมูลที่กำหนดโดย HIDL จะถูกส่งไปยังโค้ด C++ ในโครงสร้างข้อมูลโครงร่างมาตรฐาน C++ ที่สามารถใช้งานได้โดยไม่ต้องเปิดออก HIDL ยังมีอินเทอร์เฟซหน่วยความจำที่ใช้ร่วมกันและเนื่องจาก RPC ค่อนข้างช้าโดยเนื้อแท้ HIDL จึงสนับสนุนสองวิธีในการถ่ายโอนข้อมูลโดยไม่ต้องใช้การโทร RPC: หน่วยความจำที่ใช้ร่วมกันและ Fast Message Queue (FMQ)
  • ที่ใช้งานง่าย HIDL หลีกเลี่ยงหนามปัญหาของความเป็นเจ้าของหน่วยความจำโดยใช้เพียง in พารามิเตอร์สำหรับการ RPC (ดู Android อินเตอร์เฟซภาษานิยาม (AIDL) ); ค่าที่ไม่สามารถส่งคืนได้อย่างมีประสิทธิภาพจากเมธอดจะถูกส่งกลับผ่านฟังก์ชันเรียกกลับ การส่งข้อมูลไปยัง HIDL เพื่อการถ่ายโอนหรือการรับข้อมูลจาก HIDL จะไม่เปลี่ยนแปลงความเป็นเจ้าของข้อมูล ความเป็นเจ้าของจะคงอยู่กับฟังก์ชันการโทรเสมอ ข้อมูลจำเป็นต้องคงอยู่ในช่วงเวลาของฟังก์ชันที่เรียกเท่านั้น และอาจถูกทำลายทันทีหลังจากที่ฟังก์ชันที่เรียกกลับมา

การใช้โหมดส่งผ่าน

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

โหมด Passthrough ใช้ได้เฉพาะกับไคลเอนต์ C++ และการนำไปใช้งาน อุปกรณ์ที่ใช้ Android เวอร์ชันก่อนหน้าไม่มี HAL ที่เขียนในภาษา Java ดังนั้น Java HAL จะถูกผูกมัดโดยเนื้อแท้

เมื่อ .hal ไฟล์จะรวบรวม hidl-gen ผลิตพิเศษส่งผ่านไฟล์ส่วนหัว BsFoo.h นอกเหนือไปจากส่วนหัวใช้สำหรับการสื่อสารเครื่องผูก; ฟังก์ชั่นนี้ส่วนหัวกำหนดให้เป็น dlopen เอ็ด เนื่องจาก HAL ที่ส่งผ่านทำงานในกระบวนการเดียวกับที่มีการเรียกใช้ ในกรณีส่วนใหญ่ วิธีการส่งผ่านจะถูกเรียกใช้โดยการเรียกใช้ฟังก์ชันโดยตรง (เธรดเดียวกัน) oneway วิธีการทำงานในกระทู้ของตัวเองขณะที่พวกเขาไม่ได้มีเจตนาที่จะรอให้ฮาลในการประมวลผลพวกเขา (ที่นี้หมายถึง HAL ใด ๆ ที่ใช้ oneway วิธีการในโหมด passthrough ต้องด้ายปลอดภัย)

รับ IFoo.hal , BsFoo.h wraps วิธี HIDL สร้างขึ้นเพื่อให้คุณลักษณะเพิ่มเติม (เช่นการ oneway การทำธุรกรรมการทำงานในหัวข้ออื่น) ไฟล์นี้จะคล้ายกับ BpFoo.h แต่แทนการส่งผ่านในการโทร IPC ใช้เครื่องผูก, ฟังก์ชั่นที่ต้องการจะเรียกโดยตรง การใช้งานในอนาคตของ HALs อาจจัดให้มีการใช้งานหลายอย่างเช่น FooFast HAL และ FooAccurate HAL ในกรณีเช่นไฟล์สำหรับแต่ละการดำเนินงานเพิ่มเติมจะถูกสร้างขึ้น (เช่น PTFooFast.cpp และ PTFooAccurate.cpp )

ประสานผ่าน HALs

คุณสามารถรวมการใช้งาน HAL ที่สนับสนุนโหมดส่งผ่าน กำหนด HAL อินเตอร์เฟซ abcd@MN::IFoo สองแพคเกจที่ถูกสร้างขึ้น

  • abcd@MN::IFoo-impl มีการดำเนินงานของฮาลและ exposes ทำงาน IFoo* HIDL_FETCH_IFoo(const char* name) บนอุปกรณ์เดิมแพคเกจนี้เป็น dlopen เอ็ดและการดำเนินงานที่มีการใช้อินสแตนซ์ HIDL_FETCH_IFoo คุณสามารถสร้างรหัสฐานใช้ hidl-gen และ -Lc++-impl และ -Landroidbp-impl
  • abcd@MN::IFoo-service เปิด HAL ที่ส่งผ่านและลงทะเบียนตัวเองเป็นบริการที่ผูกมัด ทำให้การนำ HAL ไปใช้งานแบบเดียวกันนั้นสามารถใช้เป็นทั้งแบบส่งผ่านและแบบผูก

ที่กำหนดประเภท IFoo คุณสามารถเรียก sp<IFoo> IFoo::getService(string name, bool getStub) ได้รับการเข้าถึงตัวอย่างของ IFoo หาก getStub เป็นความจริง getService ความพยายามที่จะเปิด HAL เฉพาะในโหมด passthrough หาก getStub เป็นเท็จ getService ความพยายามที่จะหาบริการ binderized; หากล้มเหลวก็จะพยายามค้นหาบริการส่งผ่าน getStub พารามิเตอร์ไม่ควรใช้ยกเว้นใน defaultPassthroughServiceImplementation (อุปกรณ์ที่เปิดตัวด้วย Android O เป็นอุปกรณ์ที่ผูกมัดอย่างสมบูรณ์ ดังนั้นจึงไม่อนุญาตการเปิดบริการในโหมดส่งผ่าน)

ไวยากรณ์ HIDL

โดยการออกแบบ ภาษา HIDL จะคล้ายกับ C (แต่ไม่ได้ใช้ตัวประมวลผลล่วงหน้า C) เครื่องหมายวรรคตอนทั้งหมดที่ไม่ได้ระบุไว้ด้านล่าง (นอกเหนือจากการใช้งานที่ชัดเจนของ = และ | ) เป็นส่วนหนึ่งของไวยากรณ์

หมายเหตุ: สำหรับรายละเอียดเกี่ยวกับรูปแบบรหัส HIDL ดูที่ คู่มือสไตล์รหัส

  • /** */ แสดงให้เห็นความคิดเห็นเอกสาร สิ่งเหล่านี้สามารถใช้ได้เฉพาะกับการประกาศประเภท วิธี ฟิลด์ และค่า enum
  • /* */ แสดงให้เห็นความคิดเห็นหลาย
  • // บ่งชี้ความคิดเห็นที่ปลายสาย นอกเหนือจาก // , การขึ้นบรรทัดใหม่เป็นเช่นเดียวกับช่องว่างอื่น ๆ
  • ในตัวอย่างไวยากรณ์ด้านล่างข้อความจาก // ไปยังจุดสิ้นสุดของเส้นที่ไม่ได้เป็นส่วนหนึ่งของไวยากรณ์ แต่แทนที่จะเป็นความคิดเห็นเกี่ยวกับไวยากรณ์
  • [empty] หมายถึงว่าคำว่าอาจจะว่างเปล่า
  • ? ตามตัวอักษรหรือคำหมายความว่าเป็นทางเลือก
  • ... แสดงให้เห็นลำดับที่มีศูนย์หรือมากกว่ารายการที่มีการแยกวรรคตอนตามที่ระบุไว้ ไม่มีอาร์กิวเมนต์ที่หลากหลายใน HIDL
  • เครื่องหมายจุลภาคแยกองค์ประกอบลำดับ
  • อัฒภาคยุติแต่ละองค์ประกอบ รวมถึงองค์ประกอบสุดท้าย
  • ตัวพิมพ์ใหญ่ไม่ใช่เทอร์มินัล
  • italics เป็นครอบครัวโทเค็นเช่น integer หรือ identifier (กฎมาตรฐาน C แยก)
  • constexpr คือการแสดงออกสไตล์ C คงที่ (เช่น 1 + 1 และ 1L << 3 )
  • import_name เป็นแพคเกจหรืออินเตอร์เฟซชื่อที่มีคุณสมบัติตามที่อธิบายใน HIDL รุ่น
  • ตัวพิมพ์เล็ก 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

คำศัพท์

ส่วนนี้ใช้คำศัพท์ที่เกี่ยวข้องกับ HIDL ต่อไปนี้:

ผูกมัด บ่งชี้ว่ากำลังใช้ HIDL สำหรับการเรียกโพรซีเดอร์ระยะไกลระหว่างกระบวนการ ใช้งานผ่านกลไกคล้าย Binder ดูเพิ่มเติม passthrough
โทรกลับแบบอะซิงโครนัส อินเทอร์เฟซที่ให้บริการโดยผู้ใช้ HAL ส่งผ่านไปยัง HAL (ผ่านวิธี HIDL) และเรียกโดย HAL เพื่อส่งคืนข้อมูลเมื่อใดก็ได้
โทรกลับ, ซิงโครนัส ส่งกลับข้อมูลจากการใช้วิธีการ HIDL ของเซิร์ฟเวอร์ไปยังไคลเอนต์ ไม่ได้ใช้สำหรับวิธีการที่คืนค่าเป็นโมฆะหรือค่าดั้งเดิมเพียงค่าเดียว
ลูกค้า กระบวนการที่เรียกใช้เมธอดของอินเทอร์เฟซเฉพาะ กระบวนการ HAL หรือเฟรมเวิร์กอาจเป็นไคลเอ็นต์ของอินเทอร์เฟซหนึ่งและเซิร์ฟเวอร์ของอีกเซิร์ฟเวอร์หนึ่ง ดูเพิ่มเติม passthrough
ยืดออก ระบุอินเทอร์เฟซที่เพิ่มวิธีการและ/หรือประเภทไปยังอินเทอร์เฟซอื่น อินเทอร์เฟซสามารถขยายอินเทอร์เฟซอื่นได้เพียงหนึ่งอินเทอร์เฟซ สามารถใช้สำหรับรุ่นรองที่เพิ่มขึ้นในชื่อแพ็คเกจเดียวกันหรือสำหรับแพ็คเกจใหม่ (เช่น ส่วนขยายของผู้ขาย) เพื่อสร้างบนแพ็คเกจที่เก่ากว่า
สร้าง ระบุเมธอดของอินเตอร์เฟสที่คืนค่าไปยังไคลเอนต์ ในการส่งคืนค่าที่ไม่ใช่ค่าพื้นฐาน หรือมากกว่า 1 ค่า ฟังก์ชันการเรียกกลับแบบซิงโครนัสจะถูกสร้างขึ้น
อินเตอร์เฟซ การรวบรวมวิธีการและประเภท แปลเป็นคลาสในภาษา C++ หรือ Java เมธอดทั้งหมดในอินเทอร์เฟซถูกเรียกไปในทิศทางเดียวกัน: กระบวนการไคลเอนต์เรียกวิธีการที่ดำเนินการโดยกระบวนการเซิร์ฟเวอร์
ทางเดียว เมื่อนำไปใช้กับวิธีการ HIDL แสดงว่าวิธีการนั้นไม่มีค่าและไม่บล็อก
บรรจุุภัณฑ์ การรวบรวมอินเทอร์เฟซและประเภทข้อมูลที่ใช้เวอร์ชันร่วมกัน
ทะลุผ่าน โหมดของการ HIDL ที่เซิร์ฟเวอร์เป็นห้องสมุดที่ใช้ร่วมกัน dlopen เอ็ดโดยลูกค้า ในโหมดส่งผ่าน ไคลเอนต์และเซิร์ฟเวอร์เป็นกระบวนการเดียวกันแต่แยกฐานรหัส ใช้เพื่อนำ codebase ดั้งเดิมมาสู่โมเดล HIDL เท่านั้น ดูเพิ่มเติม Binderized
เซิร์ฟเวอร์ กระบวนการที่ใช้วิธีการของอินเทอร์เฟซ ดูเพิ่มเติม passthrough
ขนส่ง โครงสร้างพื้นฐาน HIDL ที่ย้ายข้อมูลระหว่างเซิร์ฟเวอร์และไคลเอนต์
รุ่น เวอร์ชันของแพ็คเกจ ประกอบด้วยจำนวนเต็มสองจำนวนหลักและรอง เวอร์ชันรองที่เพิ่มขึ้นอาจเพิ่ม (แต่ไม่เปลี่ยนแปลง) ประเภทและวิธีการ