AIDL cho HAL

Android 11 giới thiệu khả năng sử dụng AIDL cho HAL trong Android. Điều này cho phép triển khai các phần của Android mà không cần HIDL. Chuyển đổi HAL để sử dụng AIDL exclusively khi có thể (khi HAL thượng nguồn sử dụng HIDL, bạn phải sử dụng HIDL).

Các HAL sử dụng AIDL để giao tiếp giữa các thành phần khung, chẳng hạn như các thành phần trong system.img và các thành phần phần cứng, chẳng hạn như các thành phần trong vendor.img, phải sử dụng AIDL ổn định. Tuy nhiên, để giao tiếp trong một phân vùng, chẳng hạn như từ một HAL đến một HAL khác, không có quy định hạn chế nào về cơ chế IPC để sử dụng.

Động lực

AIDL đã xuất hiện lâu hơn HIDL và được sử dụng ở nhiều nơi khác, chẳng hạn như giữa các thành phần khung Android hoặc trong ứng dụng. Giờ đây, AIDL có hỗ trợ độ ổn định, bạn có thể triển khai toàn bộ ngăn xếp bằng một thời gian chạy IPC duy nhất. AIDL cũng có hệ thống tạo phiên bản tốt hơn so với HIDL.

  • Việc sử dụng một ngôn ngữ IPC duy nhất có nghĩa là bạn chỉ cần học, gỡ lỗi, tối ưu hoá và bảo mật một ngôn ngữ.
  • AIDL hỗ trợ tạo phiên bản tại chỗ cho chủ sở hữu giao diện:
    • Chủ sở hữu có thể thêm phương thức vào cuối giao diện hoặc trường vào các đối tượng có thể phân phối. Điều này có nghĩa là bạn có thể dễ dàng tạo phiên bản mã hơn theo năm, đồng thời chi phí theo năm sẽ nhỏ hơn (các loại có thể được sửa đổi tại chỗ và không cần thêm thư viện cho mỗi phiên bản giao diện).
    • Bạn có thể đính kèm giao diện tiện ích trong thời gian chạy thay vì trong hệ thống loại, vì vậy, bạn không cần phải đặt lại cơ sở các tiện ích hạ nguồn trên các phiên bản giao diện mới hơn.
  • Bạn có thể sử dụng trực tiếp giao diện AIDL hiện có khi chủ sở hữu chọn ổn định giao diện đó. Trước đây, bạn phải tạo toàn bộ bản sao của giao diện trong HIDL.

Xây dựng dựa trên môi trường thời gian chạy AIDL

AIDL có ba phần phụ trợ khác nhau: Java, NDK, CPP. Để sử dụng AIDL ổn định, bạn phải luôn sử dụng bản sao hệ thống của libbinder tại system/lib*/libbinder.so và giao tiếp trên /dev/binder. Đối với mã trên hình ảnh của nhà cung cấp, điều này có nghĩa là bạn không thể sử dụng libbinder (từ VNDK): thư viện này có API C++ không ổn định và nội bộ không ổn định. Thay vào đó, mã gốc của nhà cung cấp phải sử dụng phần phụ trợ NDK của AIDL, liên kết với libbinder_ndk (được hệ thống libbinder.so hỗ trợ) và liên kết với các thư viện NDK do các mục aidl_interface tạo. Để biết tên mô-đun chính xác, hãy xem quy tắc đặt tên mô-đun.

Viết giao diện AIDL HAL

Để giao diện AIDL được sử dụng giữa hệ thống và nhà cung cấp, giao diện này cần có hai thay đổi:

  • Mọi định nghĩa loại phải được chú thích bằng @VintfStability.
  • Nội dung khai báo aidl_interface cần bao gồm stability: "vintf",.

Chỉ chủ sở hữu của giao diện mới có thể thực hiện những thay đổi này.

Khi bạn thực hiện những thay đổi này, giao diện phải nằm trong tệp kê khai VINTF để hoạt động. Kiểm thử yêu cầu này (và các yêu cầu liên quan, chẳng hạn như xác minh rằng các giao diện đã phát hành bị đóng băng) bằng kiểm thử VTS vts_treble_vintf_vendor_test. Bạn có thể sử dụng giao diện @VintfStability mà không cần các yêu cầu này bằng cách gọi AIBinder_forceDowngradeToLocalStability trong phần phụ trợ NDK, android::Stability::forceDowngradeToLocalStability trong phần phụ trợ C++, hoặc android.os.Binder#forceDowngradeToSystemStability trong phần phụ trợ Java trên một đối tượng liên kết trước khi đối tượng đó được gửi đến một quy trình khác. Java không hỗ trợ việc hạ cấp dịch vụ xuống mức độ ổn định của nhà cung cấp vì tất cả ứng dụng đều chạy trong ngữ cảnh hệ thống.

Ngoài ra, để có khả năng di chuyển mã tối đa và tránh các vấn đề tiềm ẩn như thư viện bổ sung không cần thiết, hãy tắt phần phụ trợ CPP.

Xin lưu ý rằng việc sử dụng backends trong ví dụ mã bên dưới là chính xác, vì có ba phần phụ trợ (Java, NDK và CPP). Mã dưới đây cho biết cách chọn cụ thể phần phụ trợ CPP để tắt phần phụ trợ đó.

    aidl_interface: {
        ...
        backends: {
            cpp: {
                enabled: false,
            },
        },
    }

Tìm giao diện HAL AIDL

Giao diện AIDL ổn định của AOSP cho HAL nằm trong cùng thư mục cơ sở với giao diện HIDL, trong thư mục aidl.

  • hardware/interfaces: dành cho các giao diện thường do phần cứng cung cấp
  • frameworks/hardware/interfaces: dành cho các giao diện cấp cao được cung cấp cho phần cứng
  • system/hardware/interfaces: dành cho các giao diện cấp thấp được cung cấp cho phần cứng

Bạn nên đặt giao diện tiện ích vào các thư mục con hardware/interfaces khác trong vendor hoặc hardware.

Giao diện tiện ích

Android có một bộ giao diện AOSP chính thức với mỗi bản phát hành. Khi các đối tác Android muốn thêm chức năng vào các giao diện này, họ không nên thay đổi trực tiếp các giao diện này vì điều này có nghĩa là môi trường thời gian chạy Android của họ không tương thích với môi trường thời gian chạy Android AOSP. Đối với các thiết bị GMS, việc tránh thay đổi các giao diện này cũng là yếu tố đảm bảo hình ảnh GSI có thể tiếp tục hoạt động.

Tiện ích có thể đăng ký theo hai cách:

Tuy nhiên, khi một tiện ích được đăng ký, khi các thành phần dành riêng cho nhà cung cấp (nghĩa là không phải là một phần của AOSP thượng nguồn) sử dụng giao diện, thì không có khả năng xảy ra xung đột hợp nhất. Tuy nhiên, khi các sửa đổi hạ nguồn đối với các thành phần AOSP thượng nguồn được thực hiện, các xung đột hợp nhất có thể xảy ra và bạn nên sử dụng các chiến lược sau:

  • các phần bổ sung giao diện có thể được chuyển lên AOSP trong bản phát hành tiếp theo
  • các phần bổ sung giao diện cho phép linh hoạt hơn mà không có xung đột hợp nhất, có thể được chuyển lên trong bản phát hành tiếp theo

Tiện ích có thể phân phối: ParcelableHolder

ParcelableHolder là một Parcelable có thể chứa một Parcelable khác. Trường hợp sử dụng chính của ParcelableHolder là để mở rộng Parcelable. Ví dụ: hình ảnh mà người triển khai thiết bị muốn có thể mở rộng Parcelable, AospDefinedParcelable do AOSP xác định để bao gồm các tính năng gia tăng giá trị của họ.

Trước đây, khi không có ParcelableHolder, các trình triển khai thiết bị không thể sửa đổi giao diện AIDL ổn định do AOSP xác định vì sẽ xảy ra lỗi khi thêm các trường khác:

parcelable AospDefinedParcelable {
  int a;
  String b;
  String x; // ERROR: added by a device implementer
  int[] y; // added by a device implementer
}

Như đã thấy trong mã trước, phương pháp này không hoạt động vì các trường do trình triển khai thiết bị thêm vào có thể xung đột khi Parcelable được sửa đổi trong các bản phát hành Android tiếp theo.

Bằng cách sử dụng ParcelableHolder, chủ sở hữu của một đối tượng có thể phân phối có thể xác định một điểm mở rộng trong Parcelable.

parcelable AospDefinedParcelable {
  int a;
  String b;
  ParcelableHolder extension;
}

Sau đó, trình triển khai thiết bị có thể xác định Parcelable của riêng mình cho tiện ích.

parcelable OemDefinedParcelable {
  String x;
  int[] y;
}

Cuối cùng, bạn có thể đính kèm Parcelable mới vào Parcelable ban đầu bằng trường ParcelableHolder.


// Java
AospDefinedParcelable ap = ...;
OemDefinedParcelable op = new OemDefinedParcelable();
op.x = ...;
op.y = ...;

ap.extension.setParcelable(op);

...

OemDefinedParcelable op = ap.extension.getParcelable(OemDefinedParcelable.class);

// C++
AospDefinedParcelable ap;
OemDefinedParcelable op;
std::shared_ptr<OemDefinedParcelable> op_ptr = make_shared<OemDefinedParcelable>();

ap.extension.setParcelable(op);
ap.extension.setParcelable(op_ptr);

...

std::shared_ptr<OemDefinedParcelable> op_ptr;

ap.extension.getParcelable(&op_ptr);

// NDK
AospDefinedParcelable ap;
OemDefinedParcelable op;
ap.extension.setParcelable(op);

...

std::optional<OemDefinedParcelable> op;
ap.extension.getParcelable(&op);

// Rust
let mut ap = AospDefinedParcelable { .. };
let op = Rc::new(OemDefinedParcelable { .. });

ap.extension.set_parcelable(Rc::clone(&op));

...

let op = ap.extension.get_parcelable::<OemDefinedParcelable>();

Tên thực thể máy chủ HAL AIDL

Theo quy ước, các dịch vụ AIDL HAL có tên thực thể ở định dạng $package.$type/$instance. Ví dụ: một thực thể của HAL của bộ rung được đăng ký là android.hardware.vibrator.IVibrator/default.

Viết máy chủ HAL AIDL

Bạn phải khai báo máy chủ AIDL @VintfStability trong tệp kê khai VINTF, ví dụ như sau:

    <hal format="aidl">
        <name>android.hardware.vibrator</name>
        <version>1</version>
        <fqname>IVibrator/default</fqname>
    </hal>

Nếu không, các ứng dụng này sẽ đăng ký dịch vụ AIDL như bình thường. Khi chạy kiểm thử VTS, dự kiến tất cả HAL AIDL đã khai báo đều có sẵn.

Viết ứng dụng AIDL

Ứng dụng AIDL phải tự khai báo trong ma trận tương thích, ví dụ như:

    <hal format="aidl" optional="true">
        <name>android.hardware.vibrator</name>
        <version>1-2</version>
        <interface>
            <name>IVibrator</name>
            <instance>default</instance>
        </interface>
    </hal>

Chuyển đổi HAL hiện có từ HIDL sang AIDL

Sử dụng công cụ hidl2aidl để chuyển đổi giao diện HIDL thành AIDL.

Tính năng hidl2aidl:

  • Tạo tệp .aidl dựa trên tệp .hal cho gói đã cho
  • Tạo quy tắc bản dựng cho gói AIDL mới tạo với tất cả các phần phụ trợ được bật
  • Tạo các phương thức dịch trong phần phụ trợ Java, CPP và NDK để dịch từ các loại HIDL sang các loại AIDL
  • Tạo quy tắc bản dựng cho thư viện dịch có các phần phụ thuộc bắt buộc
  • Tạo các câu nhận định tĩnh để đảm bảo rằng trình liệt kê HIDL và AIDL có cùng giá trị trong phần phụ trợ CPP và NDK

Hãy làm theo các bước sau để chuyển đổi gói tệp .hal thành tệp .aidl:

  1. Tạo công cụ nằm trong system/tools/hidl/hidl2aidl.

    Việc tạo công cụ này từ nguồn mới nhất sẽ mang lại trải nghiệm hoàn chỉnh nhất. Bạn có thể sử dụng phiên bản mới nhất để chuyển đổi giao diện trên các nhánh cũ từ các bản phát hành trước.

    m hidl2aidl
  2. Thực thi công cụ bằng một thư mục đầu ra, theo sau là gói cần chuyển đổi.

    Bạn có thể sử dụng đối số -l để thêm nội dung của tệp giấy phép mới vào đầu tất cả tệp được tạo. Hãy nhớ sử dụng đúng giấy phép và ngày.

    hidl2aidl -o <output directory> -l <file with license> <package>

    Ví dụ:

    hidl2aidl -o . -l my_license.txt android.hardware.nfc@1.2
  3. Đọc kỹ các tệp đã tạo và khắc phục mọi vấn đề về lượt chuyển đổi.

    • conversion.log chứa mọi vấn đề chưa được xử lý cần khắc phục trước tiên.
    • Các tệp .aidl được tạo có thể có cảnh báo và đề xuất cần được xử lý. Các nhận xét này bắt đầu bằng //.
    • Hãy tận dụng cơ hội này để dọn dẹp và cải thiện gói.
    • Kiểm tra chú thích @JavaDerive cho các tính năng có thể cần thiết, chẳng hạn như toString hoặc equals.
  4. Chỉ tạo những mục tiêu mà bạn cần.

    • Tắt các phần phụ trợ sẽ không được sử dụng. Ưu tiên phần phụ trợ NDK hơn phần phụ trợ CPP, hãy xem phần chọn thời gian chạy.
    • Xoá thư viện dịch hoặc bất kỳ mã nào được tạo không được sử dụng.
  5. Xem Các điểm khác biệt chính giữa AIDL/HIDL.

    • Việc sử dụng Status tích hợp sẵn và các trường hợp ngoại lệ của AIDL thường cải thiện giao diện và không cần đến loại trạng thái dành riêng cho giao diện khác.
    • Theo mặc định, các đối số giao diện AIDL trong phương thức không phải là @nullable như trong HIDL.

SEPolicy cho HAL AIDL

Loại dịch vụ AIDL hiển thị với mã của nhà cung cấp phải có thuộc tính hal_service_type. Nếu không, cấu hình sepolicy sẽ giống như mọi dịch vụ AIDL khác (mặc dù có các thuộc tính đặc biệt cho HAL). Dưới đây là ví dụ về định nghĩa ngữ cảnh dịch vụ HAL:

    type hal_foo_service, service_manager_type, hal_service_type;

Đối với hầu hết các dịch vụ do nền tảng xác định, ngữ cảnh dịch vụ có loại chính xác đã được thêm (ví dụ: android.hardware.foo.IFoo/default đã được đánh dấu là hal_foo_service). Tuy nhiên, nếu ứng dụng khung hỗ trợ nhiều tên thực thể, thì bạn phải thêm các tên thực thể bổ sung trong tệp service_contexts dành riêng cho thiết bị.

    android.hardware.foo.IFoo/custom_instance u:object_r:hal_foo_service:s0

Bạn phải thêm các thuộc tính HAL khi tạo một loại HAL mới. Một thuộc tính HAL cụ thể có thể được liên kết với nhiều loại dịch vụ (mỗi loại có thể có nhiều thực thể như chúng ta vừa thảo luận). Đối với HAL, foo, chúng ta có hal_attribute(foo). Macro này xác định các thuộc tính hal_foo_clienthal_foo_server. Đối với một miền cụ thể, các macro hal_client_domainhal_server_domain liên kết một miền với một thuộc tính HAL nhất định. Ví dụ: máy chủ hệ thống là ứng dụng của HAL này tương ứng với chính sách hal_client_domain(system_server, hal_foo). Tương tự, máy chủ HAL cũng bao gồm hal_server_domain(my_hal_domain, hal_foo). Thông thường, đối với một thuộc tính HAL nhất định, chúng ta cũng tạo một miền như hal_foo_default để tham khảo hoặc ví dụ về HAL. Tuy nhiên, một số thiết bị sử dụng các miền này cho máy chủ của riêng mình. Việc phân biệt giữa các miền cho nhiều máy chủ chỉ quan trọng nếu chúng ta có nhiều máy chủ phân phát cùng một giao diện và cần một nhóm quyền khác nhau trong quá trình triển khai. Trong tất cả các macro này, hal_foo không thực sự là một đối tượng sepolicy. Thay vào đó, các macro này sử dụng mã thông báo này để tham chiếu đến nhóm thuộc tính liên kết với một cặp máy chủ ứng dụng.

Tuy nhiên, cho đến nay, chúng ta chưa liên kết hal_foo_servicehal_foo (cặp thuộc tính từ hal_attribute(foo)). Một thuộc tính HAL được liên kết với các dịch vụ HAL AIDL bằng cách sử dụng macro hal_attribute_service (HAL HIDL sử dụng macro hal_attribute_hwservice). Ví dụ: hal_attribute_service(hal_foo, hal_foo_service). Điều này có nghĩa là các quy trình hal_foo_client có thể nắm bắt HAL và các quy trình hal_foo_server có thể đăng ký HAL. Trình quản lý ngữ cảnh (servicemanager) sẽ thực thi các quy tắc đăng ký này. Xin lưu ý rằng tên dịch vụ không phải lúc nào cũng tương ứng với các thuộc tính HAL. Ví dụ: chúng ta có thể thấy hal_attribute_service(hal_foo, hal_foo2_service). Tuy nhiên, nói chung, vì điều này ngụ ý rằng các dịch vụ luôn được sử dụng cùng nhau, nên chúng ta có thể cân nhắc việc xoá hal_foo2_service và sử dụng hal_foo_service cho tất cả ngữ cảnh dịch vụ của mình. Hầu hết các HAL đặt nhiều hal_attribute_service là do tên thuộc tính HAL ban đầu không đủ chung và không thể thay đổi.

Khi kết hợp tất cả những điều này, một HAL mẫu sẽ có dạng như sau:

    public/attributes:
    // define hal_foo, hal_foo_client, hal_foo_server
    hal_attribute(foo)

    public/service.te
    // define hal_foo_service
    type hal_foo_service, hal_service_type, protected_service, service_manager_type

    public/hal_foo.te:
    // allow binder connection from client to server
    binder_call(hal_foo_client, hal_foo_server)
    // allow client to find the service, allow server to register the service
    hal_attribute_service(hal_foo, hal_foo_service)
    // allow binder communication from server to service_manager
    binder_use(hal_foo_server)

    private/service_contexts:
    // bind an AIDL service name to the selinux type
    android.hardware.foo.IFooXxxx/default u:object_r:hal_foo_service:s0

    private/<some_domain>.te:
    // let this domain use the hal service
    binder_use(some_domain)
    hal_client_domain(some_domain, hal_foo)

    vendor/<some_hal_server_domain>.te
    // let this domain serve the hal service
    hal_server_domain(some_hal_server_domain, hal_foo)

Giao diện tiện ích đính kèm

Bạn có thể đính kèm một tiện ích vào bất kỳ giao diện liên kết nào, cho dù đó là giao diện cấp cao nhất được đăng ký trực tiếp với trình quản lý dịch vụ hay là giao diện phụ. Khi nhận được một tiện ích, bạn phải xác nhận loại tiện ích đó như dự kiến. Bạn chỉ có thể đặt tiện ích từ quy trình phân phát liên kết.

Bạn nên sử dụng các tiện ích đính kèm bất cứ khi nào một tiện ích sửa đổi chức năng của một HAL hiện có. Khi cần chức năng hoàn toàn mới, bạn không cần sử dụng cơ chế này và có thể đăng ký trực tiếp giao diện tiện ích với trình quản lý dịch vụ. Giao diện tiện ích đính kèm sẽ phù hợp nhất khi được đính kèm vào giao diện phụ, vì các hệ phân cấp này có thể sâu hoặc nhiều phiên bản. Việc sử dụng một tiện ích toàn cục để phản ánh hệ phân cấp giao diện liên kết của một dịch vụ khác sẽ yêu cầu ghi chép rộng rãi để cung cấp chức năng tương đương cho các tiện ích được đính kèm trực tiếp.

Để đặt một tiện ích trên liên kết, hãy sử dụng các API sau:

  • Trong phần phụ trợ NDK: AIBinder_setExtension
  • Trong phần phụ trợ Java: android.os.Binder.setExtension
  • Trong phần phụ trợ CPP: android::Binder::setExtension
  • Trong phần phụ trợ Rust: binder::Binder::set_extension

Để lấy một phần mở rộng trên một liên kết, hãy sử dụng các API sau:

  • Trong phần phụ trợ NDK: AIBinder_getExtension
  • Trong phần phụ trợ Java: android.os.IBinder.getExtension
  • Trong phần phụ trợ CPP: android::IBinder::getExtension
  • Trong phần phụ trợ Rust: binder::Binder::get_extension

Bạn có thể tìm thêm thông tin về các API này trong tài liệu về hàm getExtension trong phần phụ trợ tương ứng. Bạn có thể xem ví dụ về cách sử dụng các tiện ích trong hardware/interfaces/tests/extension/vibrator.

Sự khác biệt chính giữa AIDL và HIDL

Khi sử dụng HAL AIDL hoặc sử dụng giao diện HAL AIDL, hãy lưu ý đến sự khác biệt so với việc viết HAL HIDL.

  • Cú pháp của ngôn ngữ AIDL gần giống với Java. Cú pháp HIDL tương tự như C++.
  • Tất cả giao diện AIDL đều có trạng thái lỗi tích hợp. Thay vì tạo các loại trạng thái tuỳ chỉnh, hãy tạo các số nguyên trạng thái không đổi trong tệp giao diện và sử dụng EX_SERVICE_SPECIFIC trong phần phụ trợ CPP/NDK và ServiceSpecificException trong phần phụ trợ Java. Xem phần Xử lý lỗi.
  • AIDL không tự động bắt đầu các nhóm luồng khi gửi đối tượng liên kết. Bạn phải bắt đầu các luồng này theo cách thủ công (xem phần quản lý luồng).
  • AIDL không huỷ khi gặp lỗi truyền tải chưa được kiểm tra (Return HIDL huỷ khi gặp lỗi chưa được kiểm tra).
  • AIDL chỉ có thể khai báo một loại trên mỗi tệp.
  • Bạn có thể chỉ định các đối số AIDL là in/out/inout ngoài tham số đầu ra (không có "lệnh gọi lại đồng bộ").
  • AIDL sử dụng fd làm loại gốc thay vì handle.
  • HIDL sử dụng các phiên bản chính cho các thay đổi không tương thích và các phiên bản phụ cho các thay đổi tương thích. Trong AIDL, các thay đổi tương thích ngược được thực hiện tại chỗ. AIDL không có khái niệm rõ ràng về các phiên bản chính; thay vào đó, khái niệm này được đưa vào tên gói. Ví dụ: AIDL có thể sử dụng tên gói bluetooth2.
  • AIDL không kế thừa mức độ ưu tiên theo thời gian thực theo mặc định. Bạn phải sử dụng hàm setInheritRt cho mỗi trình liên kết để bật tính năng kế thừa mức độ ưu tiên theo thời gian thực.

Kiểm thử Bộ kiểm thử của nhà cung cấp (VTS) cho HAL

Android dựa vào Bộ kiểm thử nhà cung cấp (VTS) để xác minh việc triển khai HAL dự kiến. VTS giúp đảm bảo Android có thể tương thích ngược với các phương thức triển khai cũ của nhà cung cấp. Các phương thức triển khai không thành công với VTS có các vấn đề về khả năng tương thích đã biết có thể khiến chúng không hoạt động được với các phiên bản hệ điều hành trong tương lai.

Có hai phần chính của VTS cho HAL.

1. Xác minh rằng Android đã biết và dự kiến các HAL trên thiết bị.

Bạn có thể tìm thấy bộ kiểm thử này trong test/vts-testcase/hal/treble/vintf. Họ chịu trách nhiệm xác minh:

  • Mọi giao diện @VintfStability được khai báo trong tệp kê khai VINTF sẽ bị khoá ở một phiên bản đã phát hành đã biết. Điều này đảm bảo cả hai bên của giao diện đều đồng ý về định nghĩa chính xác của phiên bản giao diện đó. Đây là điều cần thiết để hoạt động cơ bản.
  • Tất cả HAL được khai báo trong tệp kê khai VINTF đều có trên thiết bị đó. Mọi ứng dụng có đủ quyền để sử dụng một dịch vụ HAL đã khai báo phải có thể nhận và sử dụng các dịch vụ đó bất cứ lúc nào.
  • Tất cả HAL được khai báo trong tệp kê khai VINTF đều phân phát phiên bản giao diện mà chúng khai báo trong tệp kê khai.
  • Không có HAL nào không dùng nữa được phân phát trên thiết bị. Android ngừng hỗ trợ các phiên bản giao diện HAL thấp hơn như mô tả trong Vòng đời FCM.
  • Các HAL bắt buộc có trên thiết bị. Một số HAL là bắt buộc để Android hoạt động đúng cách.

2. Xác minh hành vi dự kiến của từng HAL

Mỗi giao diện HAL đều có các bài kiểm thử VTS riêng để xác minh hành vi dự kiến của các ứng dụng khách. Các trường hợp kiểm thử chạy trên mọi thực thể của giao diện HAL đã khai báo và thực thi hành vi cụ thể dựa trên phiên bản giao diện được triển khai.

Các chương trình kiểm thử này cố gắng bao gồm mọi khía cạnh của việc triển khai HAL mà khung Android dựa vào hoặc có thể dựa vào trong tương lai.

Các kiểm thử này bao gồm việc xác minh khả năng hỗ trợ các tính năng, xử lý lỗi và mọi hành vi khác mà ứng dụng khách có thể mong đợi từ dịch vụ.

Các mốc VTS cho việc phát triển HAL

Các bài kiểm thử VTS dự kiến sẽ được cập nhật khi tạo hoặc sửa đổi giao diện HAL của Android.

Bạn phải hoàn tất các thử nghiệm VTS và sẵn sàng xác minh việc triển khai của nhà cung cấp trước khi các thử nghiệm này bị đóng băng cho các bản phát hành API của nhà cung cấp Android. Các lớp này phải sẵn sàng trước khi giao diện bị đóng băng để nhà phát triển có thể tạo các phương thức triển khai, xác minh các phương thức đó và đưa ra ý kiến phản hồi cho nhà phát triển giao diện HAL.

VTS trên Cuttlefish

Khi không có phần cứng, Android sẽ sử dụng Cuttlefish làm công cụ phát triển cho giao diện HAL. Điều này cho phép kiểm thử tích hợp và VTS có thể mở rộng của Android. hal_implementation_test kiểm thử để đảm bảo Cuttlefish triển khai các phiên bản giao diện HAL mới nhất nhằm đảm bảo Android đã sẵn sàng xử lý các giao diện mới và các kiểm thử VTS đã sẵn sàng kiểm thử các hoạt động triển khai mới của nhà cung cấp ngay khi có phần cứng và thiết bị mới.