HIDL yêu cầu mọi giao diện được viết bằng HIDL đều được tạo phiên bản. Sau HAL giao diện đã được xuất bản thì giao diện bị treo và phải thực hiện bất kỳ thay đổi nào khác đối với phiên bản mới của giao diện đó. Mặc dù giao diện đã xuất bản nhất định không thể sửa đổi, nó có thể được mở rộng bằng một giao diện khác.
Cấu trúc mã HIDL
Mã HIDL được sắp xếp theo giá trị do người dùng xác định loại, giao diện và gói:
- Loại do người dùng xác định (UDT). HIDL cung cấp quyền truy cập vào một tập hợp có thể dùng để kết hợp các loại dữ liệu phức tạp hơn bằng cấu trúc, tập hợp và giá trị enum. UDT được truyền đến các phương pháp các giao diện và có thể được xác định ở cấp của một gói (phổ biến cho tất cả giao diện) hoặc cục bộ trên một giao diện.
- Giao diện. Là một thành phần cơ bản của HIDL, một giao diện bao gồm UDT và phần khai báo phương thức. Giao diện cũng có thể kế thừa từ một giao diện khác.
- Packages (Gói). Sắp xếp các giao diện HIDL liên quan và dữ liệu
mà chúng hoạt động. Một gói được xác định theo tên, phiên bản và
bao gồm:
- Tệp định nghĩa kiểu dữ liệu có tên là
types.hal
. - Không có hoặc có nhiều giao diện, mỗi giao diện trong tệp
.hal
riêng.
- Tệp định nghĩa kiểu dữ liệu có tên là
Tệp định nghĩa kiểu dữ liệu types.hal
chỉ chứa các UDT (tất cả
UDT ở cấp gói được lưu giữ trong một tệp duy nhất). Đại diện trong mục tiêu
có sẵn cho tất cả giao diện trong gói.
Triết lý tạo phiên bản
Một gói HIDL (chẳng hạn như android.hardware.nfc
), sau khi được
được xuất bản cho một phiên bản nhất định (chẳng hạn như 1.0
), là không thể thay đổi; nó
Không thể thay đổi. Sửa đổi giao diện trong gói hoặc bất kỳ
các thay đổi đối với UDT của lớp đó chỉ có thể diễn ra trong một gói khác.
Trong HIDL, việc lập phiên bản áp dụng ở cấp gói chứ không phải ở cấp giao diện, và tất cả các giao diện cũng như UDT trong một gói sẽ có cùng một phiên bản. Gói hàng các phiên bản tuân theo ngữ nghĩa tạo phiên bản mà không có thành phần cấp bản vá và thành phần siêu dữ liệu bản dựng. Trong một gói đã cung cấp, dấu tăng phiên bản nhỏ ngụ ý phiên bản mới của gói này có khả năng tương thích ngược với gói cũ và một chính version (phiên bản) tăng thì ngụ ý rằng phiên bản mới của gói không tương thích ngược với gói cũ.
Về mặt lý thuyết, một gói có thể liên quan đến một gói khác theo một trong số cách sau:
- Hoàn toàn không.
- Khả năng mở rộng tương thích ngược ở cấp gói. Chiến dịch này
xảy ra đối với các lượt đảo ngược phiên bản nhỏ mới (bản sửa đổi tăng dần tiếp theo) của một gói;
gói mới có cùng tên và phiên bản chính với gói cũ, nhưng
phiên bản nhỏ cao hơn. Về mặt chức năng, gói mới là tập mẹ của gói cũ
gói, có nghĩa là:
- Giao diện cấp cao nhất của gói mẹ có trong gói mới,
mặc dù các giao diện có thể có các phương pháp mới, UDT trên giao diện cục bộ mới (
tiện ích cấp giao diện được mô tả bên dưới) và UDT mới trong
types.hal
. - Bạn cũng có thể thêm giao diện mới vào gói mới.
- Tất cả các loại dữ liệu của gói mẹ đều có trong gói mới và có thể được xử lý bằng các phương thức (có thể triển khai lại) từ gói cũ.
- Các loại dữ liệu mới cũng có thể được thêm vào để sử dụng bằng một trong các phương pháp mới để nâng cấp giao diện hiện có hoặc giao diện mới.
- Giao diện cấp cao nhất của gói mẹ có trong gói mới,
mặc dù các giao diện có thể có các phương pháp mới, UDT trên giao diện cục bộ mới (
tiện ích cấp giao diện được mô tả bên dưới) và UDT mới trong
- Khả năng mở rộng có khả năng tương thích ngược ở cấp độ giao diện. Gói thuê bao mới
gói cũng có thể mở rộng gói ban đầu bằng cách bao gồm các thành phần phân tách theo logic
những giao diện chỉ cung cấp chức năng bổ sung chứ không phải chức năng cốt lõi.
Vì mục đích này, bạn nên:
- Các giao diện trong gói mới cần phụ thuộc vào loại dữ liệu của gói cũ .
- Giao diện trong gói mới có thể mở rộng giao diện của một hoặc nhiều giao diện cũ .
- Mở rộng khả năng không tương thích ngược ban đầu. Đây là một lớn-phiên bản nâng cấp của gói và không cần có bất kỳ mối tương quan nào giữa cả hai. Trong phạm vi có thể, nó có thể được biểu thị bằng sự kết hợp của loại từ phiên bản cũ hơn của gói và kế thừa một tập hợp con giao diện gói cũ.
Cấu trúc giao diện
Để có một giao diện có cấu trúc hợp lý, việc thêm các loại chức năng mới không thuộc thiết kế ban đầu nên cần được sửa đổi đối với HIDL . Ngược lại, nếu bạn có thể hoặc muốn thực hiện thay đổi ở cả hai phía của giao diện giới thiệu chức năng mới mà không thay đổi giao diện thì giao diện sẽ không có cấu trúc.
Treble hỗ trợ các thành phần hệ thống và nhà cung cấp được biên dịch riêng biệt, trong đó
vendor.img
trên một thiết bị và system.img
có thể là
được biên dịch riêng biệt. Tất cả hoạt động tương tác giữa vendor.img
và
system.img
phải được xác định rõ ràng và kỹ lưỡng để có thể
sẽ tiếp tục hoạt động hiệu quả trong nhiều năm tới. Điều này bao gồm nhiều nền tảng API, nhưng
bề mặt là cơ chế IPC mà HIDL sử dụng để giao tiếp liên quy trình trên
Ranh giới system.img
/vendor.img
.
Yêu cầu
Bạn phải xác định rõ ràng tất cả dữ liệu được truyền qua HIDL. Để đảm bảo quá trình triển khai và ứng dụng có thể tiếp tục làm việc cùng nhau ngay cả khi riêng biệt hoặc được phát triển độc lập, dữ liệu phải tuân thủ những các yêu cầu:
- Có thể mô tả trực tiếp trong HIDL (sử dụng cấu trúc enum, v.v.) bằng tên và ý nghĩa ngữ nghĩa.
- Có thể được mô tả theo tiêu chuẩn công khai như ISO/IEC 7816.
- Có thể được mô tả bằng tiêu chuẩn phần cứng hoặc bố cục vật lý của phần cứng.
- Có thể là dữ liệu mờ (chẳng hạn như khoá công khai, mã nhận dạng, v.v.) nếu cần.
Nếu sử dụng dữ liệu mờ, dữ liệu đó chỉ được đọc bằng một bên của HIDL
. Ví dụ: nếu mã vendor.img
cung cấp một thành phần trên
system.img
một thông điệp chuỗi hoặc vec<uint8_t>
thì dữ liệu đó không thể được chính system.img
phân tích cú pháp; thiết bị có thể
chỉ được trả về cho vendor.img
để diễn giải. Thời điểm
chuyển một giá trị từ vendor.img
sang mã nhà cung cấp
system.img
hoặc sang một thiết bị khác, định dạng và cách thức dữ liệu xuất hiện
cần phải được mô tả chính xác và vẫn là một phần của
.
Nguyên tắc
Bạn phải có thể viết chương trình triển khai hoặc ứng dụng khách của HAL mà chỉ sử dụng các tệp .hal (tức là bạn không cần xem nguồn Android hoặc công khai chuẩn). Bạn nên chỉ định chính xác hành vi bắt buộc. Những tuyên bố như là "việc triển khai có thể thực hiện A hoặc B" khuyến khích các triển khai trở thành kết hợp với các khách hàng cùng phát triển.
Bố cục mã HIDL
HIDL bao gồm các gói chính và gói nhà cung cấp.
Giao diện HIDL chính là những giao diện do Google chỉ định. Các gói có trong kho
bắt đầu bằng android.hardware.
và do hệ thống con đặt tên,
có thể có các cấp độ đặt tên lồng nhau. Ví dụ: gói NFC được đặt tên
android.hardware.nfc
và gói máy ảnh là
android.hardware.camera
Nói chung, gói cốt lõi sẽ có tên là
android.hardware.
[name1
].[name2
]....
Các gói HIDL có một phiên bản ngoài tên. Ví dụ: gói
android.hardware.camera
có thể đang ở phiên bản 3.4
; đây là
rất quan trọng, vì phiên bản của một gói sẽ ảnh hưởng đến vị trí của nó trong cây nguồn.
Tất cả các gói chính đều được đặt tại hardware/interfaces/
trong phần tử
hệ thống xây dựng. Gói hàng
android.hardware.
[name1
].[name2
]...
phiên bản $m.$n
đang thấp hơn
hardware/interfaces/name1/name2/
.../$m.$n/
; gói hàng
android.hardware.camera
phiên bản 3.4
có trong thư mục
hardware/interfaces/camera/3.4/.
Đã tồn tại một mối liên kết được cố định giá trị trong mã
giữa tiền tố gói android.hardware.
và đường dẫn
hardware/interfaces/
.
Gói không phải lõi (nhà cung cấp) là những gói do nhà cung cấp SoC hoặc ODM tạo ra. Chiến lược phát hành đĩa đơn
tiền tố cho các gói không phải chính là vendor.$(VENDOR).hardware.
, trong đó
$(VENDOR)
là nhà cung cấp hệ thống SoC (SoC) hoặc OEM/ODM. Bản đồ này ánh xạ đến đường dẫn
vendor/$(VENDOR)/interfaces
trong cây (việc ánh xạ này cũng
được cố định giá trị trong mã).
Tên loại do người dùng xác định đủ điều kiện
Trong HIDL, mỗi UDT đều có tên đủ điều kiện bao gồm tên UDT,
tên gói nơi UDT được định nghĩa và phiên bản gói. Chiến lược phát hành đĩa đơn
tên đủ điều kiện chỉ được sử dụng khi các phiên bản của loại này được khai báo và
không phải nơi loại đó được xác định. Ví dụ: giả sử gói
android.hardware.nfc,
phiên bản 1.0
xác định một cấu trúc
có tên là NfcData
. Tại trang web khai báo (cho dù trong
types.hal
hoặc trong phần khai báo của một giao diện), phần khai báo
chỉ khẳng định:
struct NfcData { vec<uint8_t> data; };
Khi khai báo một thực thể thuộc loại này (cho dù trong một cấu trúc dữ liệu hay làm thông số phương thức), hãy sử dụng tên loại đủ điều kiện:
android.hardware.nfc@1.0::NfcData
Cú pháp chung là
PACKAGE@VERSION::UDT
, trong đó:
PACKAGE
là tên được phân tách bằng dấu chấm của một gói HIDL (ví dụ:android.hardware.nfc
).VERSION
là phiên bản lớn.minor được phân tách bằng dấu chấm định dạng của gói (ví dụ:1.0
).UDT
là tên được phân tách bằng dấu chấm của HIDL UDT. Do HIDL hỗ trợ các giao diện UDT lồng nhau và giao diện HIDL có thể chứa UDT (một loại khai báo lồng nhau), dấu chấm được dùng để truy cập tên.
Ví dụ: nếu nội dung khai báo lồng nhau sau đây được xác định trong thuộc tính chung
tệp type trong gói phiên bản android.hardware.example
1.0
:
// types.hal package android.hardware.example@1.0; struct Foo { struct Bar { // … }; Bar cheers; };
Tên đủ điều kiện cho Bar
là
android.hardware.example@1.0::Foo.Bar
Nếu, ngoài việc ở trong
gói ở trên, phần khai báo lồng nhau nằm trong giao diện được gọi là
IQuux
:
// IQuux.hal package android.hardware.example@1.0; interface IQuux { struct Foo { struct Bar { // … }; Bar cheers; }; doSomething(Foo f) generates (Foo.Bar fb); };
Tên đủ điều kiện cho Bar
là
android.hardware.example@1.0::IQuux.Foo.Bar
Trong cả hai trường hợp, Bar
chỉ có thể được gọi là Bar
trong phạm vi khai báo Foo
. Trong gói hàng hoặc
cấp giao diện, bạn phải tham chiếu đến Bar
thông qua Foo
:
Foo.Bar
, như trong phần khai báo phương thức doSomething
ở trên. Ngoài ra, bạn có thể khai báo phương thức này chi tiết hơn như sau:
// IQuux.hal doSomething(android.hardware.example@1.0::IQuux.Foo f) generates (android.hardware.example@1.0::IQuux.Foo.Bar fb);
Giá trị liệt kê đủ điều kiện
Nếu UDT là một loại enum, thì mỗi giá trị của loại enum
tên đủ điều kiện bắt đầu bằng tên đủ điều kiện của loại enum,
theo sau là dấu hai chấm rồi đến tên của giá trị enum. Ví dụ:
giả định gói android.hardware.nfc,
phiên bản 1.0
xác định một loại enum NfcStatus
:
enum NfcStatus { STATUS_OK, STATUS_FAILED };
Khi tham chiếu đến STATUS_OK
, tên đủ điều kiện là:
android.hardware.nfc@1.0::NfcStatus:STATUS_OK
Cú pháp chung là
PACKAGE@VERSION::UDT:VALUE
,
trong đó:
PACKAGE@VERSION::UDT
là cùng một tên đủ điều kiện cho loại enum.VALUE
là tên của giá trị.
Quy tắc tự động suy luận
Bạn không cần chỉ định tên UDT đủ điều kiện. Tên UDT có thể an toàn, bỏ qua các bước sau:
- Ví dụ: gói
@1.0::IFoo.Type
- Cả gói và phiên bản, ví dụ:
IFoo.Type
HIDL cố gắng điền tên bằng cách sử dụng các quy tắc tự động nhiễu (quy tắc thấp hơn) số có nghĩa là mức độ ưu tiên cao hơn).
Quy tắc 1
Nếu không có gói và phiên bản nào được cung cấp, thì hệ thống sẽ thử tra cứu tên cục bộ. Ví dụ:
interface Nfc { typedef string NfcErrorMessage; send(NfcData d) generates (@1.0::NfcStatus s, NfcErrorMessage m); };
NfcErrorMessage
được tra cứu trên thiết bị và typedef
phía trên nó được tìm thấy. NfcData
cũng được tra cứu ở địa phương, nhưng vì đúng như vậy
chưa được xác định cục bộ, quy tắc 2 và 3 được sử dụng. @1.0::NfcStatus
cung cấp phiên bản nên quy tắc 1 không được áp dụng.
Quy tắc 2
Nếu quy tắc 1 không thành công và thiếu một thành phần của tên đủ điều kiện
(gói, phiên bản hoặc gói và phiên bản), thành phần được tự động điền bằng
khỏi gói hiện tại. Sau đó, trình biên dịch HIDL xem xét
tệp hiện tại (và tất cả dữ liệu nhập) để tìm tên đủ điều kiện được tự động điền.
Trong ví dụ trên, hãy giả định khai báo ExtendedNfcData
được thực hiện trong cùng một gói (android.hardware.nfc
) ở cùng một gói
phiên bản (1.0
) dưới dạng NfcData
, như sau:
struct ExtendedNfcData { NfcData base; // … additional members };
Trình biên dịch HIDL điền tên gói và tên phiên bản từ
gói hiện tại để tạo tên UDT đủ điều kiện
android.hardware.nfc@1.0::NfcData
. Như tên tồn tại trong
gói hiện tại (giả sử gói được nhập đúng cách), gói này được sử dụng cho
khai báo.
Tên trong gói hiện tại chỉ được nhập nếu một trong các tên sau là đúng:
- Tệp này được nhập một cách rõ ràng bằng câu lệnh
import
. - Giá trị này được xác định trong
types.hal
của gói hiện tại
Quy trình tương tự cũng được thực hiện nếu NfcData
chỉ đủ điều kiện bởi
số phiên bản:
struct ExtendedNfcData { // autofill the current package name (android.hardware.nfc) @1.0::NfcData base; // … additional members };
Quy tắc 3
Nếu quy tắc 2 không tạo ra được kết quả trùng khớp (UDT không được xác định trong quy tắc hiện tại
gói), trình biên dịch HIDL sẽ quét tìm một kết quả trùng khớp trong tất cả các gói đã nhập.
Sử dụng ví dụ trên, giả sử ExtendedNfcData
được khai báo trong
phiên bản 1.1
của gói android.hardware.nfc
,
1.1
sẽ nhập 1.0
như bình thường (xem
Tiện ích cấp gói) và định nghĩa
chỉ xác định tên UDT:
struct ExtendedNfcData { NfcData base; // … additional members };
Trình biên dịch tìm kiếm UDT bất kỳ có tên NfcData
và tìm thấy một UDT trong
android.hardware.nfc
ở phiên bản 1.0
, dẫn đến một
UDT đủ điều kiện là android.hardware.nfc@1.0::NfcData
. Nếu có
tìm thấy một kết quả trùng khớp cho một UDT đủ điều kiện một phần, trình biên dịch HIDL
gửi lỗi.
Ví dụ
Sử dụng quy tắc 2, một kiểu đã nhập được xác định trong gói hiện tại sẽ được ưu tiên kiểu được nhập từ một gói khác:
// hardware/interfaces/foo/1.0/types.hal package android.hardware.foo@1.0; struct S {}; // hardware/interfaces/foo/1.0/IFooCallback.hal package android.hardware.foo@1.0; interface IFooCallback {}; // hardware/interfaces/bar/1.0/types.hal package android.hardware.bar@1.0; typedef string S; // hardware/interfaces/bar/1.0/IFooCallback.hal package android.hardware.bar@1.0; interface IFooCallback {}; // hardware/interfaces/bar/1.0/IBar.hal package android.hardware.bar@1.0; import android.hardware.foo@1.0; interface IBar { baz1(S s); // android.hardware.bar@1.0::S baz2(IFooCallback s); // android.hardware.foo@1.0::IFooCallback };
S
được nội suy làandroid.hardware.bar@1.0::S
và được tìm thấy ởbar/1.0/types.hal
(vìtypes.hal
được tự động áp dụng đã nhập).IFooCallback
được nội suy làandroid.hardware.bar@1.0::IFooCallback
đang sử dụng quy tắc 2, nhưng Không thể tìm thấy vìbar/1.0/IFooCallback.hal
chưa được nhập tự động (nhưtypes.hal
). Do đó, quy tắc 3 giải quyết vấn đề thành Thay vào đó,android.hardware.foo@1.0::IFooCallback
(được nhập) quaimport android.hardware.foo@1.0;
).
type.hal
Mỗi gói HIDL chứa một tệp types.hal
chứa UDT
được dùng chung giữa tất cả giao diện tham gia trong gói đó. Loại HIDL
luôn công khai; bất kể UDT có được khai báo trong
types.hal
hoặc trong khai báo giao diện, các loại này là
có thể truy cập bên ngoài phạm vi mà chúng được xác định. types.hal
không nhằm mô tả API công khai của một gói mà là để lưu trữ UDT
được sử dụng bởi tất cả giao diện trong gói. Do bản chất của HIDL, tất cả UDT
đều là một phần của giao diện.
types.hal
bao gồm các câu lệnh UDT và import
.
Vì types.hal
được cung cấp cho mọi giao diện của
gói (đây là một lệnh nhập ngầm định), những câu lệnh import
này là
cấp gói theo định nghĩa. UDT trong types.hal
cũng có thể kết hợp
Do đó, UDT và giao diện được nhập vào.
Ví dụ: đối với IFoo.hal
:
package android.hardware.foo@1.0; // whole package import import android.hardware.bar@1.0; // types only import import android.hardware.baz@1.0::types; // partial imports import android.hardware.qux@1.0::IQux.Quux; // partial imports import android.hardware.quuz@1.0::Quuz;
Các mục sau đây sẽ được nhập:
android.hidl.base@1.0::IBase
(ngầm ẩn)android.hardware.foo@1.0::types
(ngầm ẩn)- Mọi nội dung trong
android.hardware.bar@1.0
(bao gồm tất cả các giao diện vàtypes.hal
của nó) types.hal
tạiandroid.hardware.baz@1.0::types
(các giao diện trongandroid.hardware.baz@1.0
không được nhập)IQux.hal
vàtypes.hal
từandroid.hardware.qux@1.0
Quuz
từandroid.hardware.quuz@1.0
(giả sửQuuz
được xác định trongtypes.hal
, toàn bộ Tệptypes.hal
được phân tích cú pháp, nhưng các loại không phải làQuuz
không được nhập).
Tạo phiên bản ở cấp giao diện
Mỗi giao diện bên trong một gói nằm trong tệp riêng của nó. Đóng gói
thuộc về nào được khai báo ở đầu giao diện bằng cách sử dụng các tham số
Câu lệnh package
. Sau khi khai báo gói, có từ 0 trở lên
các mục nhập ở cấp giao diện (một phần hoặc toàn bộ gói) có thể được liệt kê. Ví dụ:
package android.hardware.nfc@1.0;
Trong HIDL, các giao diện có thể kế thừa từ các giao diện khác bằng cách sử dụng phương thức
Từ khoá extends
. Để một giao diện mở rộng một giao diện khác,
phải có quyền truy cập vào câu lệnh đó thông qua câu lệnh import
. Tên của
giao diện được mở rộng (giao diện cơ sở) sẽ tuân theo các quy tắc về tên loại
trình độ chuyên môn được giải thích ở trên. Một giao diện chỉ có thể kế thừa từ một giao diện;
HIDL không hỗ trợ nhiều tính năng kế thừa.
Các ví dụ về cách tạo phiên bản nâng cấp dưới đây sử dụng gói sau:
// types.hal package android.hardware.example@1.0 struct Foo { struct Bar { vec<uint32_t> val; }; }; // IQuux.hal package android.hardware.example@1.0 interface IQuux { fromFooToBar(Foo f) generates (Foo.Bar b); }
Quy tắc tăng
Để xác định một gói package@major.minor
, A hoặc tất cả B
phải đúng:
Quy tắc A | "Là phiên bản nhỏ bắt đầu": Tất cả phiên bản nhỏ trước đó,
package@major.0 , package@major.1 , ...,
Không được xác định package@major.(minor-1) .
|
---|
Quy tắc B | Tất cả các đáp án sau đều đúng:
|
---|
Theo quy tắc A:
- Gói có thể bắt đầu bằng bất kỳ số phiên bản phụ nào (ví dụ:
android.hardware.biometrics.fingerprint
bắt đầu lúc@2.1
.) - Yêu cầu "
android.hardware.foo@1.0
không được xác định" nghĩa là thư mụchardware/interfaces/foo/1.0
thậm chí không được tồn tại.
Tuy nhiên, quy tắc A không ảnh hưởng đến một gói có cùng tên gói, nhưng
phiên bản chính khác (ví dụ:
android.hardware.camera.device
có cả @1.0
và
@3.2
được xác định; @3.2
không cần tương tác với
@1.0
.) Do đó, @3.2::IExtFoo
có thể mở rộng
@1.0::IFoo
.
Miễn là tên gói khác nhau,
package@major.minor::IBar
có thể mở rộng từ một giao diện có
tên khác (ví dụ: android.hardware.bar@1.0::IBar
có thể
mở rộng android.hardware.baz@2.2::IBaz
). Nếu một giao diện không
khai báo rõ ràng loại siêu dữ liệu bằng từ khoá extend
mở rộng android.hidl.base@1.0::IBase
(ngoại trừ IBase
).
B.2 và B.3 phải được tuân theo cùng một lúc. Ví dụ: ngay cả khi
android.hardware.foo@1.1::IFoo
mở rộng
android.hardware.foo@1.0::IFoo
để chuyển quy tắc B.2, nếu
android.hardware.foo@1.1::IExtBar
mở rộng
android.hardware.foo@1.0::IBar
, đây vẫn không phải là giá trị vòng quay hợp lệ.
Giao diện UpRev
Để nâng cấp android.hardware.example@1.0
(đã xác định ở trên) lên
@1.1
:
// types.hal package android.hardware.example@1.1; import android.hardware.example@1.0; // IQuux.hal package android.hardware.example@1.1 interface IQuux extends @1.0::IQuux { fromBarToFoo(Foo.Bar b) generates (Foo f); }
Đây là import
cấp gói của phiên bản 1.0
của
android.hardware.example
trong types.hal
. Mặc dù không có
UDT được thêm vào phiên bản 1.1
của gói, tham chiếu đến UDT trong
vẫn cần phiên bản 1.0
, do đó cần nhập phiên bản cấp gói
trong types.hal
. (Hiệu quả tương tự có thể đã đạt được với
nhập cấp giao diện trong IQuux.hal
.)
Trong extends @1.0::IQuux
trong phần khai báo về
IQuux
, chúng tôi đã chỉ định phiên bản IQuux
đang được
kế thừa (cần phân định vì IQuux
được dùng để
khai báo giao diện và kế thừa từ giao diện). Vì nội dung khai báo
chỉ đơn giản là tên kế thừa tất cả thuộc tính gói và phiên bản tại trang web của
phần khai báo, phần phân định phải nằm trong tên của giao diện cơ sở; chúng tôi
cũng có thể sử dụng UDT đủ điều kiện, nhưng
dư thừa.
Giao diện mới IQuux
không khai báo lại phương thức
fromFooToBar()
kế thừa từ @1.0::IQuux
; đơn giản là
liệt kê phương thức mới mà phương thức này thêm fromBarToFoo()
. Trong HIDL, được kế thừa
Bạn không thể khai báo lại các phương thức trong giao diện con, vì vậy
giao diện IQuux
không thể khai báo fromFooToBar()
một cách rõ ràng.
Quy ước tăng
Đôi khi, tên giao diện phải đổi tên giao diện mở rộng. Bạn nên rằng các tiện ích, cấu trúc và tập hợp enum đều có cùng tên với những gì chúng mở rộng trừ khi chúng đủ khác biệt để đảm bảo một tên mới. Ví dụ:
// in parent hal file enum Brightness : uint32_t { NONE, WHITE }; // in child hal file extending the existing set with additional similar values enum Brightness : @1.0::Brightness { AUTOMATIC }; // extending the existing set with values that require a new, more descriptive name: enum Color : @1.0::Brightness { HW_GREEN, RAINBOW };
Nếu một phương thức có thể có tên ngữ nghĩa mới (ví dụ:
fooWithLocation
) thì đối tượng đó sẽ được ưu tiên. Nếu không, mã phải là
được đặt tên tương tự như tên mở rộng. Ví dụ: phương thức
foo_1_1
trong @1.1::IFoo
có thể thay thế chức năng này
của phương thức foo
trong @1.0::IFoo
nếu không có phương thức nào tốt hơn
tên thay thế.
Tạo phiên bản cấp gói
Phiên bản HIDL xảy ra ở cấp gói; sau khi xuất bản một gói, ứng dụng là bất biến (bộ giao diện và UDT của lớp này không thể thay đổi được). Gói có thể có liên quan với nhau theo nhiều cách, tất cả đều có thể biểu thị được thông qua sự kết hợp giữa tính kế thừa ở cấp giao diện và việc tạo UDT theo thành phần kết hợp.
Tuy nhiên, có một loại quan hệ được định nghĩa chặt chẽ và phải được thực thi: Tính kế thừa có khả năng tương thích ngược ở cấp gói. Trong trường hợp này, gói parent là gói được kế thừa từ đó và gói child là gói mở rộng mẹ. Cấp gói Sau đây là các quy tắc kế thừa có khả năng tương thích ngược:
- Tất cả giao diện cấp cao nhất của gói mẹ đều được các giao diện trong gói mẹ kế thừa gói con.
- Bạn cũng có thể thêm giao diện mới vào gói mới (không có hạn chế về với các giao diện khác trong các gói khác).
- Các loại dữ liệu mới cũng có thể được thêm vào để sử dụng bằng một trong các phương pháp mới để nâng cấp giao diện hiện có hoặc giao diện mới.
Những quy tắc này có thể được triển khai bằng tính năng kế thừa và UDT ở cấp giao diện HIDL cấu trúc, nhưng đòi hỏi kiến thức ở mức siêu cấp để biết những mối quan hệ này cấu thành tiện ích gói có khả năng tương thích ngược. Kiến thức này được suy luận như sau:
Nếu gói đáp ứng yêu cầu này, hidl-gen
sẽ thực thi
các quy tắc về khả năng tương thích ngược.