Mỗi giao diện được xác định trong một gói HIDL đều có lớp C++ được tạo tự động riêng bên trong không gian tên của gói. Máy khách và máy chủ giao dịch với giao diện theo các cách khác nhau:
- Máy chủ triển khai giao diện.
- Phương thức gọi ứng dụng trên giao diện.
Giao diện có thể được đăng ký theo tên bởi máy chủ hoặc được chuyển dưới dạng tham số vào phương thức do HIDL xác định. Ví dụ: mã khung có thể phân phát để nhận thông báo không đồng bộ từ HAL và chuyển giao diện đó trực tiếp với HAL mà không cần đăng ký.
Triển khai máy chủ
Một máy chủ triển khai giao diện IFoo
phải bao gồm
Tệp tiêu đề IFoo
được tạo tự động:
#include <android/hardware/samples/1.0/IFoo.h>
Tiêu đề được thư viện chia sẻ của thư viện chia sẻ tự động xuất
Giao diện IFoo
để liên kết. Ví dụ IFoo.hal
:
// IFoo.hal interface IFoo { someMethod() generates (vec<uint32_t>); ... }
Khung mẫu cho việc triển khai máy chủ giao diện IFoo:
// From the IFoo.h header using android::hardware::samples::V1_0::IFoo; class FooImpl : public IFoo { Return<void> someMethod(foo my_foo, someMethod_cb _cb) { vec<uint32_t> return_data; // Compute return_data _cb(return_data); return Void(); } ... };
Để triển khai giao diện máy chủ cho khách hàng, bạn có thể:
- Đăng ký triển khai giao diện bằng
hwservicemanager
(xem chi tiết bên dưới),
HOẶC
- Truyền phương thức triển khai giao diện dưới dạng đối số của phương thức giao diện (để biết chi tiết, hãy xem phần Không đồng bộ lệnh gọi lại).
Khi đăng ký triển khai giao diện,
Quy trình hwservicemanager
theo dõi các giao diện HIDL đã đăng ký
chạy trên thiết bị theo tên và phiên bản. Máy chủ có thể đăng ký giao diện HIDL
phương thức triển khai theo tên và ứng dụng khách có thể yêu cầu phương thức triển khai dịch vụ theo tên
và phiên bản. Quá trình này cung cấp giao diện HIDL
android.hidl.manager@1.0::IServiceManager
.
Mỗi tệp tiêu đề giao diện HIDL được tạo tự động (chẳng hạn như IFoo.h
)
có phương thức registerAsService()
có thể dùng để đăng ký
triển khai giao diện bằng hwservicemanager
. Chỉ
đối số bắt buộc là tên của việc triển khai giao diện làm ứng dụng
dùng tên này để truy xuất giao diện từ hwservicemanager
sau:
::android::sp<IFoo> myFoo = new FooImpl(); ::android::sp<IFoo> mySecondFoo = new FooAnotherImpl(); status_t status = myFoo->registerAsService(); status_t anotherStatus = mySecondFoo->registerAsService("another_foo");
hwservicemanager
xử lý kết hợp của
[package@version::interface, instance_name]
là duy nhất để bật
giao diện khác nhau (hoặc các phiên bản khác nhau của cùng một giao diện) để đăng ký
có tên thực thể giống hệt nhau mà không có xung đột. Nếu bạn gọi
registerAsService()
có cùng phiên bản gói, giao diện
và tên thực thể, hwservicemanager
sẽ bỏ tham chiếu đến
đã đăng ký trước đó và sử dụng dịch vụ mới.
Triển khai ứng dụng
Giống như máy chủ, ứng dụng phải #include
mọi giao diện
điều đó đề cập đến:
#include <android/hardware/samples/1.0/IFoo.h>
Ứng dụng có thể lấy giao diện theo hai cách:
- Thông qua
I<InterfaceName>::getService
(thông quahwservicemanager
) - Thông qua một phương thức giao diện
Mỗi tệp tiêu đề giao diện được tạo tự động có một getService
tĩnh
có thể dùng để truy xuất phiên bản dịch vụ từ
hwservicemanager
:
// getService returns nullptr if the service can't be found sp<IFoo> myFoo = IFoo::getService(); sp<IFoo> myAlternateFoo = IFoo::getService("another_foo");
Ứng dụng hiện đã có giao diện IFoo
và có thể gọi các phương thức đến
như thể là một hoạt động triển khai lớp cục bộ. Trong thực tế, việc triển khai
có thể chạy trong cùng một quy trình, một quy trình khác hoặc thậm chí trên thiết bị khác
(với HAL từ xa). Do ứng dụng khách đã gọi getService
trên một
đối tượng IFoo
được bao gồm từ phiên bản 1.0
của gói,
hwservicemanager
chỉ trả về triển khai máy chủ nếu
Triển khai này tương thích với ứng dụng 1.0
. Trong thực tế, đây là
có nghĩa là chỉ những cách triển khai máy chủ với phiên bản 1.n
(phiên bản
x.(y+1)
của một giao diện phải mở rộng (kế thừa từ)
x.y
).
Ngoài ra, phương thức castFrom
được cung cấp để truyền giữa
giao diện khác nhau. Phương thức này hoạt động bằng cách thực hiện lệnh gọi IPC đến điều khiển từ xa
để đảm bảo rằng loại cơ bản giống với loại đang được
đã yêu cầu. Nếu loại đã yêu cầu không có sẵn, thì nullptr
sẽ
bị trả lại.
sp<V1_0::IFoo> foo1_0 = V1_0::IFoo::getService(); sp<V1_1::IFoo> foo1_1 = V1_1::IFoo::castFrom(foo1_0);
Lệnh gọi lại không đồng bộ
Nhiều phương thức triển khai HAL (Lớp trừu tượng phần cứng) hiện có giao tiếp với phần cứng không đồng bộ, có nghĩa là họ cần một cách không đồng bộ để thông báo cho khách hàng về các sự kiện mới có đã xảy ra. Giao diện HIDL có thể được dùng làm lệnh gọi lại không đồng bộ vì HIDL hàm giao diện có thể lấy đối tượng giao diện HIDL làm tham số.
Tệp giao diện mẫu IFooCallback.hal
:
package android.hardware.samples@1.0; interface IFooCallback { sendEvent(uint32_t event_id); sendData(vec<uint8_t> data); }
Ví dụ về phương thức mới trong IFoo
sẽ lấy giá trị
Tham số IFooCallback
:
package android.hardware.samples@1.0; interface IFoo { struct Foo { int64_t someValue; handle myHandle; }; someMethod(Foo foo) generates (int32_t ret); anotherMethod() generates (vec<uint32_t>); registerCallback(IFooCallback callback); };
Ứng dụng sử dụng giao diện IFoo
là
server (máy chủ) của giao diện IFooCallback
; điều này mang đến
triển khai IFooCallback
:
class FooCallback : public IFooCallback { Return<void> sendEvent(uint32_t event_id) { // process the event from the HAL } Return<void> sendData(const hidl_vec<uint8_t>& data) { // process data from the HAL } };
Nó cũng có thể chỉ cần chuyển câu lệnh đó qua một thực thể hiện có của
Giao diện IFoo
:
sp<IFooCallback> myFooCallback = new FooCallback(); myFoo.registerCallback(myFooCallback);
Máy chủ triển khai IFoo
nhận dữ liệu này dưới dạng một
Đối tượng sp<IFooCallback>
. Mã này có thể lưu trữ lệnh gọi lại và gọi
trở lại máy khách bất cứ khi nào nó muốn sử dụng giao diện này.
Người nhận tử vong
Vì quá trình triển khai dịch vụ có thể chạy trong một quy trình khác, nên nó có thể xảy ra
rằng quy trình triển khai một giao diện sẽ bị vô hiệu hoá trong khi ứng dụng vẫn hoạt động.
Mọi lệnh gọi trên một đối tượng giao diện được lưu trữ trong một quy trình đã bị gián đoạn sẽ không thành công
có lỗi truyền tải (isOK()
trả về false
). Cách duy nhất để
khôi phục từ lỗi như vậy là yêu cầu bản sao mới của dịch vụ bằng
đang gọi I<InterfaceName>::getService()
. Cách này chỉ hiệu quả nếu
quy trình gặp sự cố đã khởi động lại và đăng ký lại dịch vụ của mình bằng
servicemanager
(thường đúng với trường hợp triển khai HAL).
Thay vì xử lý vấn đề này một cách thụ động, ứng dụng khách của một giao diện cũng có thể
đăng ký người nhận đã qua đời để nhận thông báo khi một dịch vụ không còn hoạt động.
Để đăng ký nhận các thông báo như vậy trên giao diện IFoo
đã truy xuất,
khách hàng có thể làm những việc sau:
foo->linkToDeath(recipient, 1481 /* cookie */);
Tham số recipient
phải là triển khai của
Giao diện android::hardware::hidl_death_recipient
do HIDL cung cấp,
chứa một phương thức duy nhất serviceDied()
được gọi là
từ một luồng trong nhóm luồng RPC khi quy trình lưu trữ giao diện bị gián đoạn:
class MyDeathRecipient : public android::hardware::hidl_death_recipient { virtual void serviceDied(uint64_t cookie, const android::wp<::android::hidl::base::V1_0::IBase>& who) { // Deal with the fact that the service died } }
Tham số cookie
chứa cookie đã được truyền bằng
linkToDeath()
, trong khi tham số who
chứa
con trỏ yếu đến đối tượng đại diện cho dịch vụ trong ứng dụng. Với
lệnh gọi mẫu nêu trên, cookie
bằng 1481 và who
bằng foo
.
Bạn cũng có thể huỷ đăng ký người nhận đã chết sau khi đăng ký:
foo->unlinkToDeath(recipient);