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. HIDL cho phép chỉ định loại và lệnh gọi phương thức, được thu thập thành 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.
HIDL được dùng cho hoạt động giao tiếp liên quy trình (IPC). HAL được tạo bằng HDL được gọi là HAL 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 liên kết lệnh gọi giao tiếp liên quy trình (IPC). HAL được liên kết chạy trong một quy trình riêng biệt với ứng dụng có sử dụng chúng. Cho các thư viện phải được liên kết với một quy trình, thông qua mode (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 sắp xếp thành 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 trông quen thuộc với C++ và là các lập trình viên Java, nhưng với một tập hợp từ khoá. HIDL cũng sử dụng các chú giải kiểu Java.
Thuật ngữ
Phần này sử dụng các thuật ngữ liên quan đến HIDL sau đây:
đã liên kết | Cho biết HIDL đang được dùng cho các lệnh gọi quy trình từ xa giữa các quy trình, được triển khai qua cơ chế giống Binder. Xem thêm phần hướng dẫn chi tiết. |
---|---|
gọi lại, không đồng bộ | Giao diện do người dùng HAL cung cấp, được truyền đến HAL (bằng phương pháp HIDL) và được HAL gọi để trả về dữ liệu bất kỳ lúc nào. |
lệnh gọi lại, đồng bộ | Trả về dữ liệu từ phương thức triển khai phương thức HIDL của máy chủ đến máy khách. Không dùng cho các phương thức trả về giá trị trống hoặc một giá trị gốc. |
ứng dụng | Quy trình gọi các phương thức của một giao diện cụ thể. HAL (Lớp trừu tượng phần cứng) hoặc khung Android có thể là ứng dụng khách của một giao diện và máy chủ của một giao diện khác. Xem thêm truyền qua. |
mở rộng | Cho biết một giao diện thêm 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ể dùng cho trẻ vị thành niên số phiên bản tăng dần trong cùng một tên gói hoặc cho một gói mới (ví dụ: một nhà cung cấp tiện ích) để xây dựng trên gói cũ hơn. |
tạo | Cho biết phương thức giao diện trả về các giá trị cho ứng dụng. Cần trả lại một giá trị không nguyên gốc hoặc nhiều giá trị, một hàm callback đồng bộ sẽ được tạo. |
giao diện | Tập hợp các phương thức và kiểu. Được dịch sang một lớp trong C++ hoặc Java. Tất cả các phương thức trong giao diện được gọi theo cùng một hướng: quy trình ứng dụng gọi các phương thức do quá trình máy chủ triển khai. |
một chiều | Khi được áp dụng cho phương thức HIDL, phương thức này không trả về giá trị nào và không chặn. |
gói hàng | Tập hợp giao diện và kiểu dữ liệu dùng chung một phiên bản. |
truyền qua | Chế độ HIDL trong đó máy chủ là một thư viện dùng chung, dlopen ed
yêu cầu. Ở chế độ truyền qua, máy khách và máy chủ là cùng một quy trình nhưng
các cơ sở mã riêng biệt. Chỉ dùng để đưa cơ sở mã cũ vào mô hình HIDL.
Hãy xem thêm phần Bị ràng buộc. |
máy chủ | Quy trình triển khai các phương thức của một giao diện. Xem thêm truyền qua. |
giao thông | Cơ sở hạ tầng HIDL di chuyển dữ liệu giữa máy chủ và ứng dụng. |
version | Phiên bản của một gói. Bao gồm 2 số nguyên là chính và nhỏ. Không đáng kể số phiên bả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à có thể thay thế khung Android mà không cần phải
xây dựng lại HAL. HAL do các nhà cung cấp hoặc nhà sản xuất SOC xây dựng và đặt trong một
Phân vùng /vendor
trên thiết bị, bật khung Android theo cách riêng
phân vùng, đượ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 vấn đề sau:
- Khả năng tương tác. Tạo giao diện có khả năng tương tác một cách đáng tin cậy giữa các quy trình có thể được biên dịch bằng nhiều cấu trúc, chuỗi công cụ, và cấu hình bản dựng. Giao diện HIDL đã được tạo phiên bản và không thể thay đổi sau khi xuất bản.
- Hiệu quả. HIDL cố gắng giảm thiểu số lượng bản sao các toán tử. Dữ liệu do HIDL xác định được phân phối sang mã C++ theo bố cục tiêu chuẩn C++ cấu trúc dữ liệu có thể sử dụng mà không cần giải nén. HIDL cũng cung cấp giao diện bộ nhớ và RPC vốn có hơi chậm nên HIDL hỗ trợ chuyể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 (FMQ).
- Trực quan. HIDL giúp tránh những vấn đề phức tạp về quyền sở hữu bộ nhớ bằng cách
chỉ sử dụng các tham số
in
cho RPC (xem Android Ngôn ngữ định nghĩa giao diện (AIDL)); các giá trị không thể mang lại hiệu quả trả về từ các phương thức được trả về qua hàm callback. Không truyền dữ liệu vào HIDL để chuyển hay nhận dữ liệu từ HIDL thay đổi quyền sở hữu của dữ liệu – quyền sở hữu luôn giữ nguyên với hàm gọi. Dữ liệu cần chỉ tồn tại trong khoảng thời gian của hàm được gọi và có thể bị huỷ ngay sau khi hàm được gọi trả về.
Sử dụng chế độ truyền qua
Để cập nhật thiết bị chạy các phiên bản Android cũ hơn lên Android O, bạn có thể bao 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à chế độ cùng quy trình (thông qua). Tự xuống dòng minh bạch với cả HAL và khung Android.
Chế độ truyền qua chỉ dành cho ứng dụng và hoạt động triển khai C++. Các thiết bị chạy những phiên bản Android trước đó không có HAL (Lớp trừu tượng phần cứng) được viết bằng Java, vì vậy HAL Java vốn đã được liên kết.
Tệp tiêu đề truyền qua
Khi tệp .hal
được biên dịch, hidl-gen
sẽ tạo ra một
tệp tiêu đề truyền qua bổ sung BsFoo.h
ngoài các tiêu đề
dùng để giao tiếp liên kết; mà tiêu đề này xác định các hàm
Đã phát hành dlopen
Khi HAL truyền qua chạy trong cùng một quy trình mà
chúng được gọi, trong hầu hết các trường hợp, các phương thức truyền qua được gọi bằng phương thức trực tiếp
lệnh gọi hàm (cùng một luồng). Các phương thức oneway
chạy trong luồng riê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
ở chế độ truyền qua phải an toàn cho luồng).
Với một IFoo.hal
, BsFoo.h
sẽ gói HIDL tạo
để cung cấp các tính năng bổ sung (chẳng hạn như tạo oneway
giao dịch chạy trong một chuỗi khác). Tệp này tương tự với
Tuy nhiên, BpFoo.h
, thay vì truyền các lệnh gọi IPC bằng liên kết,
các hàm mong muốn được gọi trực tiếp. Các triển khai HAL trong tương lai
có thể cung cấp nhiều cách triển khai, chẳng hạn như FooFast HAL (Lớp trừu tượng phần cứng) và
HAL (Lớp trừu tượng phần cứng) của FooMain. Trong những trường hợp như vậy, một tệp cho mỗi cách triển khai bổ sung sẽ
được tạo (ví dụ: PTFooFast.cpp
và
PTFooAccurate.cpp
).
Cải thiện lớp trừu tượng phần cứng (HAL)
Bạn có thể liên kết các phương thức triển khai HAL (Lớp trừu tượng phần cứng) có hỗ trợ chế độ truyền qua. Cho trước
Giao diện HAL a.b.c.d@M.N::IFoo
, có 2 gói được tạo:
a.b.c.d@M.N::IFoo-impl
. Chứa cách triển khai HAL và hiển thị hàmIFoo* HIDL_FETCH_IFoo(const char* name)
. Bật thiết bị cũ, gói này đã đượcdlopen
ed và cách triển khai là được tạo thực thể bằngHIDL_FETCH_IFoo
. Bạn có thể tạo mã cơ sở sử dụnghidl-gen
và-Lc++-impl
và-Landroidbp-impl
.a.b.c.d@M.N::IFoo-service
. Mở HAL truyền qua và tự đăng ký dưới dạng dịch vụ liên kết, cho phép triển khai HAL tương tự để sử dụng làm cả liên kết và truyền qua.
Với loại IFoo
, bạn có thể gọi sp<IFoo>
IFoo::getService(string name, bool getStub)
để nhận quyền truy cập vào một thực thể
trong tổng số IFoo
. Nếu getStub
là đúng, getService
cố gắng chỉ mở HAL ở chế độ thông qua. Nếu getStub
là
false, getService
cố gắng tìm một dịch vụ liên kết; nếu thế
không thành công, sau đó máy chủ đó sẽ cố gắng tìm dịch vụ truyền qua. getStub
không bao giờ được sử dụng thông số này ngoại trừ trong
defaultPassthroughServiceImplementation
(Thiết bị chạy với
Android O là các thiết bị liên kết hoàn toàn, vì vậy, việc mở một dịch vụ ở chế độ truyền qua
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 C
bộ tiền xử lý). Tất cả dấu câu không được mô tả bên dưới (ngoài cách sử dụng rõ ràng)
=
và |
) là một phần của ngữ pháp.
Lưu ý: Để biết thông tin 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 trong tài liệu. Bạn có thể áp dụng các đề xuất này chỉ để khai báo giá trị loại, phương thức, trường và giá trị enum./* */
biểu thị ghi chú nhiều dòng.//
biểu thị chú thích ở cuối dòng. Ngoài//
, các dòng mới sẽ giống như mọi khoảng trắng khác.- Trong ví dụ về ngữ pháp dưới đây, hãy nhập văn bản từ
//
đến cuối ký tự dòng không phải là một phần của ngữ pháp mà là một nhận xét về ngữ pháp. [empty]
có nghĩa là từ khoá đó có thể trống.?
đứng sau một giá trị cố định hoặc một thuật ngữ có nghĩa là giá trị này không bắt buộc....
biểu thị chuỗi không chứa hoặc nhiều mục có phân tách dấu câu như được chỉ định. Không có đối số biến thiên trong HIDL.- Dấu phẩy phân tách các phần tử trình tự.
- Dấu chấm phẩy chấm dứt từng phần tử, kể cả phần tử cuối cùng.
- CHỮ HOA không phải là chữ cái đầu cuối.
italics
là một nhóm mã thông báo, chẳng hạn nhưinteger
hoặcidentifier
(độ C tiêu chuẩn quy tắc phân tích cú pháp).constexpr
là một biểu thức hằng số kiểu C (chẳng hạn như1 + 1
và1L << 3
).import_name
là tên gói hoặc giao diện, đủ điều kiện như được mô tả trong HIDL Tạo phiên bản.words
viết thường là mã thông báo cố định.
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