Trong Android 8.0, hệ điều hành Android được thiết kế lại để xác định rõ giao diện giữa nền tảng Android độc lập với thiết bị và mã dành riêng cho thiết bị và nhà cung cấp. Android đã xác định nhiều giao diện như vậy ở dạng giao diện HAL, được xác định là tiêu đề C trong hardware/libhardware
. HIDL đã thay thế các giao diện HAL này bằng các giao diện có phiên bản ổn định. Các giao diện này có thể ở dạng Java (như mô tả bên dưới) hoặc là giao diện HIDL phía máy khách và phía máy chủ trong C++.
Giao diện HIDL chủ yếu được dùng từ mã gốc, do đó, 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 từ Java, vì một số hệ thống con Android (chẳng hạn như Điện thoại) có giao diện HIDL Java.
Các trang trong phần này mô tả giao diện người dùng Java cho giao diện HIDL, chi tiết cách tạo, đăng ký và sử dụng dịch vụ, đồng thời giải thích cách HAL và ứng dụng HAL được viết bằng Java tương tác với hệ thống RPC HIDL.
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ý dưới dạng 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 giả lập HIDL tương ứng nếu muốn sử dụng thư viện đó. 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 mình đang lấy các phần phụ thuộc trên các thư viện này, bạn cũng có thể sử dụng đường liên kết dùng chung:
// 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 cần cân nhắc khác khi thêm thư viện trong Android 10
Nếu có một ứng dụng hệ thống hoặc ứng dụng của nhà cung cấp nhắm đến Android 10 trở lên, bạn có thể đưa các thư viện này vào một cách tĩnh. Bạn cũng có thể (chỉ) sử dụng 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 sử dụng cơ chế uses-library
hiện có cho các ứng dụng hệ thống. Phương pháp sau 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 phần Triển khai Thư viện SDK Java. Đối với các ứng dụng cũ, hành vi cũ sẽ được giữ nguyên.
Kể từ Android 10, các phiên bản "shallow" (nhẹ) của các thư viện này cũng có sẵn. Các lớp này bao gồm lớp có liên quan nhưng không bao gồm bất kỳ lớp phụ thuộc nào. Ví dụ: android.hardware.foo-V1.0-java-shallow
bao gồm các lớp trong gói 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 đang tạo một thư viện đã có các lớp cơ sở của giao diện ưu tiên dưới dạng phần phụ thuộc, bạn có thể sử dụng các phần 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 có trên đường dẫn lớp khởi động cho ứng dụng (trước đây, các thư viện này đôi khi được dùng làm API ẩn, do trình tải lớp uỷ quyền trước của Android). Thay vào đó, các ứng dụng này đã được chuyển vào một không gian tên mới bằng jarjar
và các ứng dụng sử dụng các ứng dụng này (cần thiết là các ứng dụng riêng tư) 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 của các thư viện này có trong đường dẫn lớp khởi động.
Sửa đổi nguồn Java
Dịch vụ này chỉ có một phiên bản (@1.0
), vì vậy, mã này chỉ truy xuất phiên bản đó. Hãy xem phần tiện ích giao diện để biết cách xử lý nhiều phiên bản 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 giao diện để nhận lệnh gọi lại không đồng bộ từ HAL.
Đối với giao diện IFooCallback
trong phiên bản 1.0 của gói android.hardware.foo
, bạn có thể triển khai giao diện của mình trong Java bằng các bước sau:
- Xác định giao diện trong HIDL.
- Mở
/tmp/android/hardware/foo/IFooCallback.java
dưới dạng tài liệu tham khảo. - Tạo một mô-đun mới để triển khai Java.
- 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 lớp đó và triển khai các phương thức trừu tượng.
Xem 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
Các 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
, thao tác này sẽ tạo tệp /tmp/android/hardware/foo/1.0/IFooCallback.java
, đóng gói giao diện Java, mã proxy và mã giả lập (cả proxy và mã giả lập đều tuân thủ giao diện).
-Lmakefile
tạo các quy tắc chạy lệnh này tại thời điểm tạo bản dựng và cho phép bạn đưa android.hardware.foo-V1.0-java
vào và liên kết với các tệp thích hợp. Bạn có thể tìm thấy một tập lệnh tự động thực hiện việc này cho một dự án đầ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à một thư mục tạm thời trong cây mã để cho phép bạn phát triển HAL trước khi phát hành.
Chạy dịch vụ
HAL cung cấp giao diện IFoo
. Giao diện này phải thực hiện lệnh gọi lại không đồng bộ đến khung qua giao diện IFooCallback
. Giao diện IFooCallback
không được đăng ký theo tên dưới dạng dịch vụ có thể khám phá; 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
, hãy thêm android.hardware.foo-V1.0-java
vào Android.mk
. 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ả thiết bị, thì có thể trên một thiết bị cụ thể, dịch vụ đó có thể cung cấp các chức 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 giao diện mở rộng có thể sử dụng phương thức Java castFrom()
để truyền giao diện cơ sở đến giao diện mở rộng một cách an toàn:
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. }