HIDL được xây dựng dựa trên các giao diện, một loại trừu tượng được dùng trong các ngôn ngữ hướng đối tượng để xác định hành vi. Mỗi giao diện là một phần của một gói.
Gói
Tên gói có thể có các cấp phụ như package.subpackage
. Thư mục gốc cho các gói HIDL đã xuất bản là hardware/interfaces
hoặc vendor/vendorName
(ví dụ: vendor/google
cho các thiết bị Pixel). Tên gói tạo thành một hoặc nhiều thư mục con trong thư mục gốc; tất cả các tệp xác định một gói đều nằm trong cùng một thư mục. Ví dụ: bạn có thể tìm thấy package android.hardware.example.extension.light@2.0
trong hardware/interfaces/example/extension/light/2.0
.
Bảng sau đây liệt kê các tiền tố và vị trí gói:
Tiền tố gói | Vị trí | Loại giao diện |
---|---|---|
android.hardware.* |
hardware/interfaces/* |
HAL |
android.frameworks.* |
frameworks/hardware/interfaces/* |
frameworks/ related |
android.system.* |
system/hardware/interfaces/* |
hệ thống/ có liên quan |
android.hidl.* |
system/libhidl/transport/* |
core |
Thư mục gói chứa các tệp có đuôi .hal
. Mọi tệp phải chứa một câu lệnh package
đặt tên cho gói và phiên bản mà tệp đó thuộc về. Tệp types.hal
(nếu có) không xác định giao diện mà xác định các loại dữ liệu mà mọi giao diện trong gói đều có thể truy cập.
Định nghĩa giao diện
Ngoài types.hal
, mọi tệp .hal
khác đều xác định một giao diện. Giao diện thường được xác định như sau:
interface IBar extends IFoo { // IFoo is another interface // embedded types struct MyStruct {/*...*/}; // interface methods create(int32_t id) generates (MyStruct s); close(); };
Một giao diện không có phần khai báo extends
rõ ràng sẽ mở rộng ngầm ẩn từ android.hidl.base@1.0::IBase
(tương tự như java.lang.Object
trong Java). Giao diện IBase, được nhập ngầm, khai báo một số phương thức được đặt trước mà không được và không thể khai báo lại trong các giao diện do người dùng xác định hoặc sử dụng theo cách khác. Các phương thức này bao gồm:
ping
interfaceChain
interfaceDescriptor
notifySyspropsChanged
linkToDeath
unlinkToDeath
setHALInstrumentation
getDebugInfo
debug
getHashChain
Quy trình nhập
Câu lệnh import
là cơ chế HIDL để truy cập vào các giao diện và loại gói trong một gói khác. Câu lệnh import
liên quan đến hai thực thể:
- Thực thể nhập, có thể là một gói hoặc một giao diện
- Thực thể nhập, có thể là một gói hoặc một giao diện
Thực thể nhập được xác định theo vị trí của câu lệnh import
. Khi câu lệnh nằm bên trong types.hal
của gói, toàn bộ gói sẽ thấy nội dung đang được nhập; đây là lệnh nhập cấp gói. Khi câu lệnh nằm bên trong tệp giao diện, thực thể nhập là chính giao diện đó; đây là một lệnh nhập cấp giao diện.
Thực thể được nhập được xác định bằng giá trị sau từ khoá import
. Giá trị này không cần phải là tên đủ điều kiện; nếu một thành phần bị bỏ qua, thành phần đó sẽ tự động được điền thông tin từ gói hiện tại.
Đối với các giá trị đủ điều kiện, các trường hợp nhập sau đây được hỗ trợ:
- Nhập toàn bộ gói. Nếu giá trị là tên gói và phiên bản (cú pháp được mô tả bên dưới), thì toàn bộ gói sẽ được nhập vào thực thể nhập.
- Nhập một phần. Nếu giá trị là:
- Một giao diện,
types.hal
của gói và giao diện đó được nhập vào thực thể nhập. - Một UDT được xác định trong
types.hal
, sau đó chỉ UDT đó được nhập vào thực thể nhập (các loại khác trongtypes.hal
sẽ không được nhập).
- Một giao diện,
- Chỉ nhập loại. Nếu giá trị sử dụng cú pháp của một lệnh nhập một phần được mô tả ở trên, nhưng với từ khoá
types
thay vì tên Giao diện, thì chỉ các UDT trongtypes.hal
của gói được chỉ định mới được nhập.
Thực thể nhập có quyền truy cập vào tổ hợp:
- Các UDT phổ biến của gói đã nhập được xác định trong
types.hal
; - Giao diện của gói đã nhập (đối với quá trình nhập toàn bộ gói) hoặc giao diện được chỉ định (đối với quá trình nhập một phần) cho mục đích gọi các giao diện đó, truyền tay cầm đến các giao diện đó và/hoặc kế thừa từ các giao diện đó.
Câu lệnh nhập sử dụng cú pháp tên-loại đủ điều kiện để cung cấp tên và phiên bản của gói hoặc giao diện đang được nhập:
import android.hardware.nfc@1.0; // import a whole package import android.hardware.example@1.0::IQuux; // import an interface and types.hal import android.hardware.example@1.0::types; // import just types.hal
Tính kế thừa giao diện
Giao diện có thể là phần mở rộng của giao diện đã xác định trước đó. Tiện ích có thể là một trong ba loại sau:
- Giao diện có thể thêm chức năng vào một giao diện khác, kết hợp API của giao diện đó mà không thay đổi.
- Gói có thể thêm chức năng vào một gói khác, tích hợp API của gói đó mà không thay đổi.
- Giao diện có thể nhập các loại từ một gói hoặc từ một giao diện cụ thể.
Một giao diện chỉ có thể mở rộng một giao diện khác (không có nhiều tính năng kế thừa).
Mỗi giao diện trong một gói có số phiên bản phụ khác 0 phải mở rộng một giao diện trong phiên bản trước của gói. Ví dụ: nếu giao diện IBar
trong phiên bản 4.0 của gói derivative
dựa trên (mở rộng) giao diện IFoo
trong phiên bản 1.2 của gói original
và phiên bản 1.3 của gói original
được tạo, thì IBar
phiên bản 4.1 không thể mở rộng phiên bản 1.3 của IFoo
. Thay vào đó, IBar
phiên bản 4.1 phải mở rộng IBar
phiên bản 4.0, được liên kết với IFoo
phiên bản 1.2.
IBar
phiên bản 5.0 có thể mở rộng IFoo
phiên bản 1.3, nếu bạn muốn.
Tiện ích giao diện không ngụ ý phần phụ thuộc thư viện hoặc đưa vào nhiều HAL trong mã được tạo – chúng chỉ nhập cấu trúc dữ liệu và định nghĩa phương thức ở cấp HIDL. Mọi phương thức trong HAL đều phải được triển khai trong HAL đó.
Tiện ích của nhà cung cấp
Trong một số trường hợp, tiện ích của nhà cung cấp được triển khai dưới dạng một lớp con của đối tượng cơ sở đại diện cho giao diện cốt lõi mà các tiện ích đó mở rộng. Cùng một đối tượng được đăng ký theo tên và phiên bản HAL cơ sở, cũng như theo tên và phiên bản HAL (nhà cung cấp) của tiện ích.
Lập phiên bản
Các gói được tạo phiên bản và giao diện có phiên bản của gói. Phiên bản được biểu thị bằng hai số nguyên, chính.phụ.
- Các phiên bản chính không có khả năng tương thích ngược. Việc tăng số phiên bản chính sẽ đặt lại số phiên bản phụ về 0.
- Các phiên bản nhỏ có khả năng tương thích ngược. Việc tăng số phiên bản phụ cho biết phiên bản mới hơn hoàn toàn tương thích ngược với phiên bản trước. Bạn có thể thêm các cấu trúc và phương thức dữ liệu mới, nhưng không được thay đổi cấu trúc dữ liệu hoặc chữ ký phương thức hiện có.
Nhiều phiên bản chính hoặc phụ của HAL có thể xuất hiện đồng thời trên một thiết bị. Tuy nhiên, bạn nên ưu tiên phiên bản nhỏ hơn phiên bản lớn vì mã ứng dụng hoạt động với giao diện phiên bản nhỏ trước đó cũng hoạt động với các phiên bản nhỏ sau này của cùng giao diện đó. Để biết thêm thông tin chi tiết về việc tạo phiên bản và tiện ích của nhà cung cấp, hãy xem phần Tạo phiên bản HIDL.
Tóm tắt bố cục giao diện
Phần này tóm tắt cách quản lý gói giao diện HIDL (chẳng hạn như hardware/interfaces
) và hợp nhất thông tin được trình bày trong toàn bộ phần HIDL. Trước khi đọc, hãy đảm bảo bạn đã nắm rõ các khái niệm về phiên bản HIDL, hàm băm bằng hidl-gen, thông tin chi tiết về cách làm việc chung với HIDL và các định nghĩa sau:
Thuật ngữ | Định nghĩa |
---|---|
Giao diện nhị phân của ứng dụng (ABI) | Giao diện lập trình ứng dụng cùng với mọi đường liên kết nhị phân bắt buộc. |
tên đủ điều kiện (fqName) | Tên để phân biệt loại hidl. Ví dụ: android.hardware.foo@1.0::IFoo . |
gói hàng | Gói chứa giao diện và các loại HIDL. Ví dụ: android.hardware.foo@1.0 . |
thư mục gốc của gói | Gói gốc chứa các giao diện HIDL. Ví dụ: giao diện HIDL android.hardware nằm trong thư mục gốc của gói android.hardware.foo@1.0 . |
đường dẫn gốc của gói | Vị trí trong cây nguồn Android mà thư mục gốc của gói ánh xạ đến. |
Để biết thêm định nghĩa, hãy xem Từ vựng HIDL.
Bạn có thể tìm thấy mọi tệp từ mối liên kết gốc của gói và tên đủ điều kiện của tệp
Gốc gói được chỉ định cho hidl-gen
dưới dạng đối số -r android.hardware:hardware/interfaces
. Ví dụ: nếu gói là vendor.awesome.foo@1.0::IFoo
và hidl-gen
được gửi -r vendor.awesome:some/device/independent/path/interfaces
, thì tệp giao diện phải nằm trong $ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal
.
Trong thực tế, nhà cung cấp hoặc OEM có tên awesome
nên đặt giao diện chuẩn của họ trong vendor.awesome
. Sau khi chọn đường dẫn gói, bạn không được thay đổi đường dẫn này vì đường dẫn này được đưa vào ABI của giao diện.
Bản đồ ánh xạ đường dẫn gói phải là duy nhất
Ví dụ: nếu bạn có -rsome.package:$PATH_A
và -rsome.package:$PATH_B
, thì $PATH_A
phải bằng $PATH_B
để có thư mục giao diện nhất quán (điều này cũng giúp phiên bản giao diện dễ dàng hơn nhiều).
Thư mục gốc của gói phải có tệp phiên bản
Nếu tạo đường dẫn gói như -r vendor.awesome:vendor/awesome/interfaces
, bạn cũng nên tạo tệp $ANDROID_BUILD_TOP/vendor/awesome/interfaces/current.txt
. Tệp này sẽ chứa hàm băm của các giao diện được tạo bằng tuỳ chọn -Lhash
trong hidl-gen
(vấn đề này được thảo luận rộng rãi trong phần Hàm băm bằng hidl-gen).
Giao diện nằm ở các vị trí độc lập với thiết bị
Trong thực tế, bạn nên chia sẻ giao diện giữa các nhánh. Điều này cho phép sử dụng lại mã tối đa và kiểm thử mã tối đa trên nhiều thiết bị và trường hợp sử dụng.