HIDL

Ngôn ngữ định nghĩa giao diện HAL hoặc HIDL là ngôn ngữ mô tả giao diện (IDL) để chỉ định giao diện giữa HAL và người dùng của nó. HIDL cho phép chỉ định các loại và lệnh gọi phương thức, được thu thập thành các giao diện và gói. Nói rộng hơn, HIDL là một hệ thống giao tiếp giữa các cơ sở mã có thể được biên dịch độc lập. Kể từ Android 10, HIDL không được dùng nữa và Android đang chuyển sang sử dụng AIDL ở mọi nơi.

HIDL được thiết kế để sử dụng cho giao tiếp giữa các quá trình (IPC). HAL được tạo bằng HDL được gọi là HAL được liên kết ở chỗ chúng có thể giao tiếp với các lớp kiến ​​trúc khác bằng cách sử dụng lệnh gọi liên lạc giữa các quá trình liên kết (IPC). HAL được liên kết chạy trong một quy trình riêng biệt với máy khách sử dụng chúng. Đối với các thư viện phải được liên kết với một quy trình, chế độ chuyển tiếp cũng có sẵn (không được hỗ trợ trong Java).

HIDL chỉ định cấu trúc dữ liệu và chữ ký phương thức, được tổ chức trong các giao diện (tương tự như một lớp) được thu thập thành các gói. Cú pháp của HIDL có vẻ quen thuộc với các lập trình viên C++ và Java, nhưng với một bộ từ khóa khác. HIDL cũng sử dụng các chú thích kiểu Java.

Thuật ngữ

Phần này sử dụng các thuật ngữ liên quan đến HIDL sau:

bị kết dính Cho biết HIDL đang được sử dụng cho các lệnh gọi thủ tục từ xa giữa các tiến trình, được triển khai qua cơ chế giống như Binder. Xem thêm thông qua .
gọi lại, không đồng bộ Giao diện được cung cấp bởi người dùng HAL, được chuyển đến HAL (sử dụng phương thức HIDL) và được HAL gọi để trả về dữ liệu bất kỳ lúc nào.
gọi lại, đồng bộ Trả về dữ liệu từ việc triển khai phương thức HIDL của máy chủ cho máy khách. Không được sử dụng cho các phương thức trả về void hoặc một giá trị nguyên thủy duy nhất.
khách hàng Quá trình gọi các phương thức của một giao diện cụ thể. Quá trình khung HAL hoặc Android có thể là máy khách của một giao diện và máy chủ của giao diện khác. Xem thêm thông qua .
mở rộng Chỉ ra một giao diện thêm các phương thức và/hoặc kiểu vào một giao diện khác. Một giao diện chỉ có thể mở rộng một giao diện khác. Có thể được sử dụng để tăng phiên bản nhỏ trong cùng tên gói hoặc cho gói mới (ví dụ: tiện ích mở rộng của nhà cung cấp) để xây dựng trên gói cũ hơn.
tạo ra Chỉ ra một phương thức giao diện trả về giá trị cho máy khách. Để trả về một giá trị không nguyên thủy hoặc nhiều giá trị, hàm gọi lại đồng bộ sẽ được tạo.
giao diện Bộ sưu tập các phương pháp và loại. Được dịch sang một lớp bằng C++ hoặc Java. Tất cả các phương thức trong một giao diện đều được gọi theo cùng một hướng: một tiến trình máy khách gọi các phương thức được thực hiện bởi một tiến trình máy chủ.
một chiều Khi được áp dụng cho phương thức HIDL, cho biết phương thức đó không trả về giá trị nào và không chặn.
bưu kiện Tập hợp các giao diện và kiểu dữ liệu chia sẻ một phiên bản.
sự đi qua Chế độ HIDL trong đó máy chủ là thư viện dùng chung, được khách hàng dlopen . Trong chế độ chuyển tiếp, máy khách và máy chủ là cùng một quy trình nhưng có cơ sở mã riêng biệt. Chỉ được sử dụng để đưa các cơ sở mã cũ vào mô hình HIDL. Xem thêm Chất kết dính .
máy chủ Quá trình thực hiện các phương thức của một giao diện. Xem thêm thông qua .
chuyên chở Cơ sở hạ tầng HIDL di chuyển dữ liệu giữa máy chủ và máy khách.
phiên bản Phiên bản của một gói. Gồm hai số nguyên lớn và nhỏ. Các phiên bản tăng dần có thể thêm (nhưng không thay đổi) loại và phương thức.

thiết kế HIDL

Mục tiêu của HIDL là khung Android có thể được thay thế mà không cần phải xây dựng lại HAL. HAL sẽ được các nhà cung cấp hoặc nhà sản xuất SOC xây dựng và đưa vào phân vùng /vendor trên thiết bị, cho phép khung Android, trong phân vùng riêng của nó, được thay thế bằng OTA mà không cần biên dịch lại HAL.

Thiết kế HIDL cân bằng các mối quan tâm sau:

  • Khả năng tương tác . Tạo các giao diện có khả năng tương tác đáng tin cậy giữa các quy trình có thể được biên dịch bằng nhiều kiến ​​trúc, chuỗi công cụ và cấu hình xây dựng khác nhau. Giao diện HIDL được phiên bản và không thể thay đổi sau khi chúng được xuất bản.
  • Hiệu quả . HIDL cố gắng giảm thiểu số lượng thao tác sao chép. Dữ liệu do HIDL xác định được phân phối tới mã C++ trong cấu trúc dữ liệu bố cục tiêu chuẩn C++ có thể được sử dụng mà không cần giải nén. HIDL cũng cung cấp giao diện bộ nhớ dùng chung và vì RPC vốn có phần chậm nên HIDL hỗ trợ hai cách để truyền dữ liệu mà không cần sử dụng lệnh gọi RPC: bộ nhớ dùng chung và Hàng đợi tin nhắn nhanh (FMQ).
  • Trực giác . HIDL tránh các vấn đề hóc búa về quyền sở hữu bộ nhớ bằng cách chỉ sử dụng in tham số cho RPC (xem Ngôn ngữ định nghĩa giao diện Android (AIDL) ); các giá trị không thể được trả về một cách hiệu quả từ các phương thức sẽ được trả về thông qua các hàm gọi lại. Việc truyền dữ liệu vào HIDL để truyền cũng như nhận dữ liệu từ HIDL đều không làm thay đổi quyền sở hữu dữ liệu—quyền sở hữu luôn thuộc về chức năng gọi. Dữ liệu chỉ cần tồn tại trong suốt thời gian của hàm được gọi và có thể bị hủy ngay sau khi hàm được gọi trả về.

Sử dụng chế độ chuyển tiếp

Để cập nhật các thiết bị chạy các phiên bản Android cũ hơn lên Android O, bạn có thể bọc cả HAL thông thường (và cũ) trong giao diện HIDL mới phục vụ HAL ở chế độ liên kết và cùng một quy trình (chuyển qua). Gói này minh bạch đối với cả khung HAL và Android.

Chế độ chuyển tiếp chỉ khả dụng cho các máy khách và triển khai C++. Các thiết bị chạy phiên bản Android cũ hơn không có HAL được viết bằng Java, do đó, HAL Java vốn đã được liên kết chặt chẽ.

Khi tệp .hal được biên dịch, hidl-gen tạo ra tệp tiêu đề chuyển tiếp bổ sung BsFoo.h ngoài các tiêu đề được sử dụng để liên lạc liên kết; tiêu đề này xác định các hàm được dlopen ed. Vì HAL chuyển tiếp chạy trong cùng một quy trình mà chúng được gọi, nên trong hầu hết các trường hợp, các phương thức chuyển tiếp được gọi bằng lệnh gọi hàm trực tiếp (cùng một luồng). Các phương thức oneway chạy trong luồng riêng của chúng vì chúng không có ý định đợi HAL xử lý chúng (điều này có nghĩa là bất kỳ HAL nào sử dụng các phương thức oneway trong chế độ chuyển qua đều phải an toàn theo luồng).

Với IFoo.hal , BsFoo.h bao bọc các phương thức do HIDL tạo để cung cấp các tính năng bổ sung (chẳng hạn như thực hiện các giao dịch oneway chạy trong một luồng khác). Tệp này tương tự như BpFoo.h , tuy nhiên thay vì chuyển các cuộc gọi IPC bằng chất kết dính, các hàm mong muốn sẽ được gọi trực tiếp. Việc triển khai HAL trong tương lai có thể cung cấp nhiều triển khai, chẳng hạn như FooFast HAL và FooAccurate HAL. Trong những trường hợp như vậy, một tệp cho mỗi lần triển khai bổ sung sẽ được tạo (ví dụ: PTFooFast.cppPTFooAccurate.cpp ).

HAL thông qua chất kết dính

Bạn có thể ràng buộc việc triển khai HAL hỗ trợ chế độ chuyển tiếp. Với giao diện HAL abcd@MN::IFoo , hai gói được tạo:

  • abcd@MN::IFoo-impl . Chứa việc triển khai HAL và hiển thị hàm IFoo* HIDL_FETCH_IFoo(const char* name) . Trên các thiết bị cũ, gói này được dlopen ed và việc triển khai được khởi tạo bằng cách sử dụng HIDL_FETCH_IFoo . Bạn có thể tạo mã cơ sở bằng cách sử dụng hidl-gen-Lc++-impl-Landroidbp-impl .
  • abcd@MN::IFoo-service . Mở HAL chuyển tiếp và tự đăng ký dưới dạng dịch vụ liên kết, cho phép sử dụng cùng một triển khai HAL như cả chuyển tiếp và liên kết.

Với loại IFoo , bạn có thể gọi sp<IFoo> IFoo::getService(string name, bool getStub) để có quyền truy cập vào một phiên bản của IFoo . Nếu getStub đúng, getService sẽ cố gắng mở HAL chỉ ở chế độ chuyển tiếp. Nếu getStub sai, getService sẽ cố gắng tìm một dịch vụ được liên kết; nếu thất bại, nó sẽ cố gắng tìm dịch vụ chuyển tiếp. Tham số getStub không bao giờ được sử dụng ngoại trừ trong defaultPassthroughServiceImplementation . (Các thiết bị khởi chạy bằng Android O là các thiết bị được liên kết hoàn toàn, do đó, việc mở dịch vụ ở chế độ chuyển tiếp là không được phép.)

ngữ pháp HIDL

Theo thiết kế, ngôn ngữ HIDL tương tự như C (nhưng không sử dụng bộ tiền xử lý C). Tất cả các dấu câu không được mô tả bên dưới (ngoài việc sử dụng rõ ràng =| ) đều là một phần của ngữ pháp.

Lưu ý: Để biết chi tiết về kiểu mã HIDL, hãy xem Hướng dẫn về kiểu mã .

  • /** */ biểu thị nhận xét tài liệu. Chúng chỉ có thể được áp dụng cho các khai báo kiểu, phương thức, trường và giá trị enum.
  • /* */ biểu thị chú thích nhiều dòng.
  • // biểu thị một chú thích ở cuối dòng. Ngoài // , các dòng mới cũng giống như mọi khoảng trắng khác.
  • Trong ví dụ ngữ pháp bên dưới, văn bản từ // đến cuối dòng không phải là một phần của ngữ pháp mà thay vào đó là một nhận xét về ngữ pháp.
  • [empty] có nghĩa là thuật ngữ có thể trống.
  • ? theo sau một nghĩa đen hoặc thuật ngữ có nghĩa là nó là tùy chọn.
  • ... biểu thị chuỗi chứa 0 hoặc nhiều mục có dấu phân cách như được chỉ định. Không có đối số đa dạng trong HIDL.
  • Các phần tử trình tự được phân tách bằng dấu phẩy.
  • Dấu chấm phẩy chấm dứt từng phần tử, kể cả phần tử cuối cùng.
  • UPPERCASE là một nonterminal.
  • italics là họ mã thông báo như integer hoặc identifier (quy tắc phân tích cú pháp C tiêu chuẩn).
  • constexpr là biểu thức hằng số kiểu C (chẳng hạn như 1 + 11L << 3 ).
  • import_name là tên gói hoặc giao diện, đủ điều kiện như được mô tả trong Phiên bản HIDL .
  • words viết thường là mã thông báo theo nghĩa đen.

Ví dụ:

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