แบบ HIDL

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

HIDL มีไว้เพื่อการสื่อสารระหว่างกระบวนการ (IPC) HAL ที่สร้างด้วย HDL ที่เรียกว่า Binderized HALs ที่สื่อสารกับเลเยอร์สถาปัตยกรรมอื่นๆ โดยใช้ไฟล์ Binder การสื่อสารระหว่างกระบวนการ (IPC) HAL ที่มีการเชื่อมโยงจะทำงานในกระบวนการที่แยกจากไคลเอ็นต์ ที่ใช้โค้ดเหล่านั้น สำหรับ ไลบรารีที่ต้องลิงก์กับกระบวนการ การส่งผ่าน มีโหมด ให้ใช้งานด้วย (ไม่ได้รับการสนับสนุนใน Java)

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

คำศัพท์

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

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

รูปแบบ HIDL

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

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

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

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

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

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

เมื่อคอมไพล์ไฟล์ .hal แล้ว hidl-gen จะสร้างเอลิเมนต์ ไฟล์ส่วนหัวส่งผ่าน (Pass Through) เพิ่มเติม BsFoo.h นอกเหนือจากส่วนหัว ใช้สำหรับการสื่อสารแฟ้ม ส่วนหัวนี้จะกำหนดฟังก์ชัน dlopen แล้ว เมื่อ HAL Passthrough จะทํางานในกระบวนการเดียวกับที่ โดยปกติจะเรียกเมธอด 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 และการติดตั้งใช้งาน สร้างอินสแตนซ์โดยใช้ HIDL_FETCH_IFoo คุณสามารถสร้างโค้ดพื้นฐาน โดยใช้ hidl-gen และ -Lc++-impl และ -Landroidbp-impl
  • a.b.c.d@M.N::IFoo-service. เปิด HAL Passthrough และ จดทะเบียนตัวเองเป็นบริการที่มีการเชื่อมโยง ซึ่งช่วยให้ใช้งาน HAL ได้เหมือนกัน เพื่อใช้เป็นทั้ง Passthrough และ Binderized

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

ไวยากรณ์ HIDL

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

หมายเหตุ: ดูรายละเอียดเกี่ยวกับรูปแบบรหัส HIDL ได้ที่ Code Style Guide

  • /** */ ระบุความคิดเห็นในเอกสาร คุณใช้วิธีเหล่านี้ได้ เพื่อประกาศค่า Method ฟิลด์ และ enum เท่านั้น
  • /* */ หมายถึงความคิดเห็นหลายบรรทัด
  • // หมายถึงความคิดเห็นที่ท้ายบรรทัด นอกจาก // บรรทัดใหม่จะเหมือนกับช่องว่างอื่นๆ
  • ในไวยากรณ์ตัวอย่างด้านล่าง ข้อความจาก // ถึงส่วนท้าย ไม่ได้เป็นส่วนหนึ่งของไวยากรณ์ แต่เป็นความคิดเห็นเกี่ยวกับไวยากรณ์
  • [empty] หมายความว่าคํานั้นอาจว่างเปล่า
  • ? ที่ตามหลังตัวลิเทอรัลหรือคำศัพท์หมายความว่าไม่บังคับให้
  • ... หมายถึงลำดับที่มีรายการตั้งแต่ 0 รายการขึ้นไป การแยกเครื่องหมายวรรคตอนตามที่ระบุ ไม่มีอาร์กิวเมนต์แปรผันใน 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