هر رابط تعریف شده در بسته 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
) دارای یک متد 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
بر روی یک شی IFoo
موجود در نسخه 1.0
بسته، hwservicemanager
اجرای سرور را تنها در صورتی برمی گرداند که آن پیاده سازی با کلاینت های 1.0
سازگار باشد. در عمل، این بدان معنی است که فقط اجرای سرور با نسخه 1.n
(نسخه x.(y+1)
یک رابط باید گسترش یابد (از) xy
).
علاوه بر این، روش 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
است. پیاده سازی 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 صادق است).
بهجای برخورد واکنشی با این موضوع، مشتریان یک رابط میتوانند گیرنده مرگ را نیز ثبت کنند تا در صورت مرگ سرویس، اعلان دریافت کنند. برای ثبت نام برای چنین اعلانهایی در رابط بازیابی شده IFoo
، مشتری میتواند کارهای زیر را انجام دهد:
foo->linkToDeath(recipient, 1481 /* cookie */);
پارامتر recipient
باید پیادهسازی رابط android::hardware::hidl_death_recipient
باشد که توسط HIDL ارائه شده است، که حاوی یک متد serviceDied()
است که از یک رشته در Threadpool 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);