Tạo phiên bản giao diện

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 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.
  • 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.imgsystem.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 Barandroid.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 Barandroid.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) qua import 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ại android.hardware.baz@1.0::types (các giao diện trong android.hardware.baz@1.0 không được nhập)
  • IQux.haltypes.hal từ android.hardware.qux@1.0
  • Quuz từ android.hardware.quuz@1.0 (giả sử Quuz được xác định trong types.hal, toàn bộ Tệp types.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).
HOẶC
Quy tắc B

Tất cả các đáp án sau đều đúng:

  1. "Phiên bản nhỏ trước đó là hợp lệ": package@major.(minor-1) phải được xác định và tuân theo cùng một quy tắc A (không có quy tắc nào trong số package@major.0 đến package@major.(minor-2) được xác định) hoặc quy tắc B (nếu đó là giá trị nâng cao từ @major.(minor-2));



  2. "Kế thừa ít nhất một giao diện có cùng tên": Tồn tại một giao diện giao diện package@major.minor::IFoo mở rộng package@major.(minor-1)::IFoo (nếu gói trước có giao diện);



  3. "Không có giao diện kế thừa có tên khác": Không được tồn tại package@major.minor::IBar mở rộng package@major.(minor-1)::IBaz, trong đó IBarIBaz là hai tên khác nhau. Nếu có một giao diện với phần tử cùng tên, package@major.minor::IBar phải mở rộng package@major.(minor-k)::IBar sao cho không có IBar nào tồn tại với k nhỏ hơn.

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ục hardware/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@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ả cá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 có thể 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 cấu trúc.

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:

  1. 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.
  2. 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).
  3. 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 tạo 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.