HIDL 套件中定義的每個介面都有專屬的自動產生的 C++ 類別 該檔案的命名空間用戶端和伺服器處理 方法如下:
- 伺服器會實作介面。
- 介面上的 Clients 呼叫方法。
介面可依伺服器名稱註冊,或以 傳遞至 HIDL 定義方法的方法。舉例來說,架構程式碼可提供 從 HAL 接收非同步訊息並傳送該介面 直接提供給 HAL 而不註冊
伺服器實作
導入 IFoo
介面的伺服器必須包含
IFoo
自動產生的標頭檔案:
#include <android/hardware/samples/1.0/IFoo.h>
資源的共用資料庫會自動匯出標頭
要連結的 IFoo
介面。IFoo.hal
範例:
// IFoo.hal interface IFoo { someMethod() generates (vec<uint32_t>); ... }
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(); } ... };
若要讓用戶端使用伺服器介面實作, 可以:
- 使用
hwservicemanager
(詳情請參閱下方說明)
或
- 將介面實作傳遞為 介面方法 (如需詳細資料,請參閱 Asynchronous 回呼)。
在註冊介面實作時,
hwservicemanager
程序會追蹤已註冊的 HIDL 介面
的名稱和版本伺服器可註冊 HIDL 介面
名稱和用戶端可以根據名稱要求導入服務
和版本此程序會提供 HIDL 介面
android.hidl.manager@1.0::IServiceManager
。
每個自動產生的 HIDL 介面標頭檔案 (例如 IFoo.h
)
具備 registerAsService()
方法,可用於註冊
透過 hwservicemanager
實作介面。只有
必要引數是做為用戶端的介面實作名稱
使用這個名稱從 hwservicemanager
擷取介面
稍後:
::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
會將
[package@version::interface, instance_name]
為不重複值,以便啟用
不同的介面 (或同一介面的不同版本) 來註冊
都不會發生衝突如果你打電話
具有相同套件版本、介面的 registerAsService()
和執行個體名稱,hwservicemanager
會捨棄其對
並使用新的服務
用戶端實作
就像伺服器的做法一樣,用戶端必須為每個介面 #include
是指:
#include <android/hardware/samples/1.0/IFoo.h>
用戶端可以透過兩種方式取得介面:
- 透過
I<InterfaceName>::getService
(透過hwservicemanager
) - 透過介面方法
每個自動產生的介面標頭檔案都有靜態 getService
這個方法可用來從
hwservicemanager
:
// getService returns nullptr if the service can't be found sp<IFoo> myFoo = IFoo::getService(); sp<IFoo> myAlternateFoo = IFoo::getService("another_foo");
現在用戶端擁有 IFoo
介面,並可以呼叫方法來呼叫
就像是本機類別實作一樣實際上
可以在相同程序、不同程序,甚至是在其他裝置上執行
(具有 HAL 遠端功能)。由於用戶端呼叫了 getService
,
套件版本 1.0
中包含 IFoo
物件
只有在這樣的情況下,hwservicemanager
才會傳回伺服器實作。
實作項目與 1.0
用戶端相容。實務上
代表只有版本 1.n
(版本) 的伺服器實作
介面的 x.(y+1)
必須延伸 (繼承自)
x.y
)。
此外,系統也提供 castFrom
方法,可在
而且介面各有不同這個方法在向遠端發出 IPC 呼叫時
確保基礎類型與目標類型相同
。如果要求的類型無法使用,則 nullptr
。
sp<V1_0::IFoo> foo1_0 = V1_0::IFoo::getService(); sp<V1_1::IFoo> foo1_1 = V1_1::IFoo::castFrom(foo1_0);
非同步回呼
許多現有的 HAL 實作會與非同步硬體通訊 就需要以非同步的方式向用戶端通知 發生。HIDL 介面可用於非同步回呼,因為 HIDL 介面函式可將 HIDL 介面物件做為參數。
介面檔案 IFooCallback.hal
範例:
package android.hardware.samples@1.0; interface IFooCallback { sendEvent(uint32_t event_id); sendData(vec<uint8_t> data); }
IFoo
中的新方法範例,採用
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); };
使用 IFoo
介面的用戶端是
IFooCallback
介面的 server;也能享有
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 } };
它也能直接將標記傳遞到
IFoo
介面:
sp<IFooCallback> myFooCallback = new FooCallback(); myFoo.registerCallback(myFooCallback);
導入 IFoo
的伺服器將此方法接收為
sp<IFooCallback>
物件。可儲存回呼,並呼叫
並一律重新傳回用戶端。
死亡收件者
由於服務實作可以在不同的程序中執行,因此可能會
實作介面的程序會在用戶端保持運作時故障。
如果處理程序中託管的介面物件呼叫失敗,這些物件就會失敗
出現傳輸錯誤 (isOK()
傳回 false
)。如要
從這類失敗復原,是透過
正在撥打 I<InterfaceName>::getService()
。只有在下列情況中
當機程序。
servicemanager
(對 HAL 實作來說通常是 true)。
與其處理這種事,介面用戶端也可以
登記死亡收件者,以便在服務失敗時收到通知。
如要在擷取的 IFoo
介面上註冊此類通知,請
用戶端可進行下列操作:
foo->linkToDeath(recipient, 1481 /* cookie */);
recipient
參數必須是
android::hardware::hidl_death_recipient
介面,由 HIDL 提供。
當中包含系統呼叫的單一方法 serviceDied()
從 RPC 執行緒集區的執行緒執行緒故障時,則當代管介面的程序失敗時:
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 } }
cookie
參數包含先前透過
linkToDeath()
,who
參數則包含
較弱的指標指向在用戶端中代表服務的物件。使用
上述呼叫範例,cookie
等於 1481,而 who
等於 foo
。
你也可以在註冊死亡後取消註冊:
foo->unlinkToDeath(recipient);