介面

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();
    }
    ...
};

若要讓用戶端使用伺服器介面實作, 可以:

  1. 使用 hwservicemanager (詳情請參閱下方說明)



  2. 將介面實作傳遞為 介面方法 (如需詳細資料,請參閱 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);