Java HIDL

Trong Android 8.0, hệ điều hành Android được cấu trúc lại để xác định các giao diện rõ ràng giữa nền tảng Android độc lập với thiết bị và theo từng thiết bị và nhà cung cấp . Android đã xác định nhiều giao diện như vậy dưới dạng HAL các giao diện, được xác định là tiêu đề C trong hardware/libhardware. Phóng điện cường độ cao thay thế các giao diện HAL này bằng giao diện ổn định, được lập phiên bản, nằm trong Java (như mô tả bên dưới) hoặc là HIDL phía máy khách và phía máy chủ trong C++.

Giao diện HIDL được thiết kế để sử dụng chủ yếu từ mã gốc và như một kết quả HIDL tập trung vào việc tự động tạo mã hiệu quả trong C++. Tuy nhiên, Giao diện HIDL cũng phải có sẵn để sử dụng trực tiếp qua Java, vì một số Android các hệ thống con (chẳng hạn như Hệ thống điện thoại) có giao diện Java HIDL.

Các trang trong phần này mô tả giao diện người dùng Java cho giao diện HIDL, trình bày chi tiết cách tạo, đăng ký và sử dụng các dịch vụ, cũng như giải thích cách thức HAL và HAL các ứng dụng được viết bằng Java tương tác với hệ thống HIDL RPC.

Ví dụ về ứng dụng

Đây là ví dụ về ứng dụng cho giao diện IFoo trong gói android.hardware.foo@1.0 đã được đăng ký làm tên dịch vụ default và một dịch vụ bổ sung có tên dịch vụ tuỳ chỉnh second_impl.

Thêm thư viện

Bạn cần thêm các phần phụ thuộc trên thư viện mã giả lập HIDL tương ứng nếu mà bạn muốn sử dụng. Thông thường, đây là một thư viện tĩnh:

// in Android.bp
static_libs: [ "android.hardware.foo-V1.0-java", ],
// in Android.mk
LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java

Nếu biết rằng bạn đã đưa các phần phụ thuộc vào các thư viện này, bạn cũng có thể sử dụng đường liên kết được chia sẻ:

// in Android.bp
libs: [ "android.hardware.foo-V1.0-java", ],
// in Android.mk
LOCAL_JAVA_LIBRARIES += android.hardware.foo-V1.0-java

Những điểm khác cần cân nhắc khi thêm thư viện trong Android 10

Nếu bạn có một ứng dụng của nhà cung cấp hoặc hệ thống nhắm đến Android 10 trở lên, bạn có thể đưa tĩnh các thư viện này vào. Bạn cũng có thể sử dụng (chỉ) các lớp HIDL từ các tệp JAR tuỳ chỉnh được cài đặt trên thiết bị có API Java ổn định được cung cấp bằng cơ chế uses-library hiện có cho các ứng dụng hệ thống. Chiến lược phát hành đĩa đơn phương pháp thứ hai giúp tiết kiệm dung lượng trên thiết bị. Để biết thêm thông tin chi tiết, hãy xem bài viết Triển khai thư viện SDK Java. Cho ứng dụng cũ hơn thì hành vi cũ sẽ được giữ nguyên.

Kể từ Android 10, "nông" phiên bản của các thư viện này tại đây cũng có sẵn. Các thuộc tính này bao gồm lớp được đề cập nhưng không bao gồm bất kỳ của các lớp phụ thuộc. Ví dụ: android.hardware.foo-V1.0-java-shallow bao gồm các lớp trong foo nhưng không bao gồm các lớp trong android.hidl.base-V1.0-java, chứa lớp cơ sở của tất cả Giao diện HIDL. Nếu bạn đang tạo một thư viện đã có thư viện ưu tiên các lớp cơ sở của giao diện có sẵn dưới dạng phần phụ thuộc, bạn có thể sử dụng các lớp sau:

// in Android.bp
static_libs: [ "android.hardware.foo-V1.0-java-shallow", ],
// in Android.mk
LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java-shallow

Thư viện cơ sở và thư viện trình quản lý HIDL cũng không còn hoạt động khi khởi động classpath cho ứng dụng (trước đây, đôi khi chúng được dùng làm API ẩn, do Trình tải lớp uỷ quyền trước tiên của Android). Thay vào đó, chúng được chuyển đến một không gian tên với jarjar và các ứng dụng sử dụng các không gian tên này (nếu cần ứng dụng) phải có bản sao riêng. Các mô-đun trên đường dẫn lớp khởi động sử dụng HIDL phải sử dụng các biến thể nông của các thư viện Java này và để thêm jarjar_rules: ":framework-jarjar-rules" vào Android.bp để sử dụng phiên bản hiện có của các thư viện này trong đường dẫn lớp khởi động.

Sửa đổi nguồn Java

Chỉ có một phiên bản (@1.0) của dịch vụ này, vì vậy, mã này chỉ truy xuất phiên bản đó. Xem tiện ích giao diện về cách xử lý nhiều phiên bản khác nhau của dịch vụ.

import android.hardware.foo.V1_0.IFoo;
...
// retry to wait until the service starts up if it is in the manifest
IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
IFoo anotherServer = IFoo.getService("second_impl", true /* retry */);
server.doSomething(…);

Cung cấp dịch vụ

Mã khung trong Java có thể cần phân phát các giao diện để nhận được các giao diện không đồng bộ các lệnh gọi lại từ HAL (Lớp trừu tượng phần cứng).

Đối với giao diện IFooCallback trong phiên bản 1.0 của android.hardware.foo, bạn có thể triển khai giao diện của mình trong Java bằng cách sử dụng các bước sau:

  1. Xác định giao diện của bạn trong HIDL.
  2. Mở /tmp/android/hardware/foo/IFooCallback.java dưới dạng tham chiếu.
  3. Tạo một mô-đun mới để triển khai Java.
  4. Kiểm tra lớp trừu tượng android.hardware.foo.V1_0.IFooCallback.Stub, sau đó viết một lớp mới để mở rộng và triển khai các phương thức trừu tượng.

Xem các tệp được tạo tự động

Để xem các tệp được tạo tự động, hãy chạy:

hidl-gen -o /tmp -Ljava \
  -randroid.hardware:hardware/interfaces \
  -randroid.hidl:system/libhidl/transport android.hardware.foo@1.0

Những lệnh này tạo thư mục /tmp/android/hardware/foo/1.0. Đối với tệp hardware/interfaces/foo/1.0/IFooCallback.hal, điều này sẽ tạo ra tệp /tmp/android/hardware/foo/1.0/IFooCallback.java đóng gói giao diện Java, mã proxy và các mã giả lập (cả proxy và các mã giả lập phù hợp với giao diện).

-Lmakefile tạo các quy tắc chạy lệnh này trong bản dựng và cho phép bạn bao gồm android.hardware.foo-V1.0-java và liên kết với tệp phù hợp. Một tập lệnh tự động thực hiện việc này cho một dự án có bạn có thể tìm thấy giao diện tại hardware/interfaces/update-makefiles.sh. Các đường dẫn trong ví dụ này là tương đối; phần cứng/giao diện có thể là trong cây mã để cho phép bạn phát triển HAL trước khi xuất bản ứng dụng đó.

Chạy một dịch vụ

HAL cung cấp giao diện IFoo, giao diện này phải làm cho không đồng bộ các lệnh gọi lại cho khung này qua giao diện IFooCallback. Chiến lược phát hành đĩa đơn Giao diện IFooCallback không được đăng ký theo tên dưới dạng giao diện có thể phát hiện dịch vụ; thay vào đó, IFoo phải chứa một phương thức như setFooCallback(IFooCallback x).

Để thiết lập IFooCallback từ phiên bản 1.0 của Gói android.hardware.foo, thêm android.hardware.foo-V1.0-java đến Android.mk. Đoạn mã để chạy dịch vụ là:

import android.hardware.foo.V1_0.IFoo;
import android.hardware.foo.V1_0.IFooCallback.Stub;
....
class FooCallback extends IFooCallback.Stub {
    // implement methods
}
....
// Get the service from which you will be receiving callbacks.
// This also starts the threadpool for your callback service.
IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
....
// This must be a persistent instance variable, not local,
//   to avoid premature garbage collection.
FooCallback mFooCallback = new FooCallback();
....
// Do this once to create the callback service and tell the "foo-bar" service
server.setFooCallback(mFooCallback);

Tiện ích giao diện

Giả sử một dịch vụ nhất định triển khai giao diện IFoo trên tất cả trên một thiết bị cụ thể, dịch vụ có thể cung cấp các khả năng bổ sung được triển khai trong tiện ích giao diện IBetterFoo, như sau:

interface IFoo {
   ...
};

interface IBetterFoo extends IFoo {
   ...
};

Mã gọi nhận biết được giao diện mở rộng có thể sử dụng Phương thức Java castFrom() để truyền giao diện cơ sở một cách an toàn đến giao diện mở rộng:

IFoo baseService = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
IBetterFoo extendedService = IBetterFoo.castFrom(baseService);
if (extendedService != null) {
  // The service implements the extended interface.
} else {
  // The service implements only the base interface.
}