HIDL 패키지에 정의된 모든 인터페이스에는 패키지의 네임스페이스 내에 자체 생성된 C++ 클래스가 있습니다. 클라이언트와 서버는 인터페이스를 다양한 방식으로 처리합니다.
- 서버는 인터페이스를 구현합니다.
- 클라이언트는 인터페이스의 메서드를 호출합니다.
인터페이스는 서버에서 이름으로 등록하거나 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
를 사용하여 인터페이스 구현을 등록합니다(아래 세부정보 참조).
또는- 인터페이스 메서드의 인수로 인터페이스 구현을 전달합니다(자세한 내용은 비동기 콜백 참고).
인터페이스 구현을 등록할 때 hwservicemanager
프로세스는 기기에서 실행 중인 등록된 HIDL 인터페이스를 이름 및 버전으로 추적합니다. 서버는 이름으로 HIDL 인터페이스 구현을 등록할 수 있으며 클라이언트는 이름과 버전으로 서비스 구현을 요청할 수 있습니다. 이 프로세스는 HIDL 인터페이스 android.hidl.manager@1.0::IServiceManager
를 제공합니다.
자동 생성된 각 HIDL 인터페이스 헤더 파일(예: IFoo.h
)에는 hwservicemanager
로 인터페이스 구현을 등록하는 데 사용할 수 있는 registerAsService()
메서드가 있습니다. 클라이언트가 나중에 인터페이스 구현의 이름을 사용하여 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>
클라이언트는 다음 두 가지 방법으로 인터페이스를 가져올 수 있습니다.
hwservicemanager
를 경유하는I<InterfaceName>::getService
를 통해- 인터페이스 메서드를 통해
자동 생성된 각 인터페이스 헤더 파일에는 hwservicemanager
에서 서비스 인스턴스를 검색하는 데 사용할 수 있는 정적 getService
메서드가 있습니다.
// getService will return nullptr if the service can't be found sp<IFoo> myFoo = IFoo::getService(); sp<IFoo> myAlternateFoo = IFoo::getService("another_foo");
이제 클라이언트에는 IFoo
인터페이스가 있으며 마치 로컬 클래스 구현인 것처럼 인터페이스 메서드를 호출할 수 있습니다. 실제로 구현은 동일한 프로세스, 다른 프로세스 또는 다른 기기(HAL 원격 사용)에서도 실행할 수 있습니다. 클라이언트가 패키지의 1.0
버전에서 포함한 IFoo
객체의 getService
를 호출하였으므로 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); }
IFooCallback
매개변수를 가져오는 IFoo
의 새로운 메서드의 예는 다음과 같습니다.
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
인터페이스의 서버이며 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()
를 호출하여 서비스의 새 인스턴스를 요청하는 것입니다. 이 작업은 비정상 종료된 프로세스가 HAL 구현에 일반적으로 true인 servicemanager
로 서비스를 다시 시작 및 다시 등록한 경우에만 작동합니다.
이를 사후 대응적으로 처리하는 대신 인터페이스의 클라이언트가 death recipient를 등록하여 서비스가 종료될 때 알림을 받을 수도 있습니다.
검색된 IFoo
인터페이스에서 이러한 알림을 등록하려면 클라이언트는 다음을 실행할 수 있습니다.
foo->linkToDeath(recipient, 1481 /* cookie */);
recipient
매개변수는 HIDL에서 제공하는 android::hardware::hidl_death_recipient
인터페이스의 구현이어야 하며 인터페이스를 호스팅하는 프로세스가 종료될 때 RPC 스레드풀의 스레드에서 호출되는 단일 메서드 serviceDied()
가 포함됩니다.
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);