Arayüzler

Bir HIDL paketinde tanımlanan her arabirim, paketin ad alanında kendi otomatik olarak oluşturulmuş C++ sınıfına sahiptir. İstemciler ve sunucular arayüzlerle farklı şekillerde ilgilenir:

  • Sunucular arayüzleri uygular.
  • İstemciler arayüzlerdeki yöntemleri çağırır.

Arayüzler sunucu tarafından isme göre kaydedilebilir veya HIDL tanımlı yöntemlere parametre olarak aktarılabilir. Örneğin, çerçeve kodu, HAL'den eşzamansız mesajları almak ve bu arayüzü kaydetmeden doğrudan HAL'ye geçirmek için bir arayüz görevi görebilir.

Sunucu uygulaması

IFoo arayüzünü uygulayan bir sunucu, otomatik olarak oluşturulan IFoo başlık dosyasını içermelidir:

#include <android/hardware/samples/1.0/IFoo.h>

Başlık, bağlantı kurulacak IFoo arayüzünün paylaşılan kitaplığı tarafından otomatik olarak dışa aktarılır. Örnek IFoo.hal :

// IFoo.hal
interface IFoo {
    someMethod() generates (vec<uint32_t>);
    ...
}

IFoo arayüzünün sunucu uygulaması için örnek iskelet:

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

Bir sunucu arayüzünün uygulanmasını istemcinin kullanımına sunmak için şunları yapabilirsiniz:

  1. Arayüz uygulamasını hwservicemanager kaydedin (aşağıdaki ayrıntılara bakın),

    VEYA

  2. Arayüz uygulamasını bir arayüz yönteminin argümanı olarak iletin (ayrıntılar için bkz. Eşzamansız geri aramalar ).

Arayüz uygulamasını kaydederken hwservicemanager işlemi, cihazda çalışan kayıtlı HIDL arayüzlerini ad ve sürüme göre takip eder. Sunucular bir HIDL arayüz uygulamasını ada göre kaydedebilir ve istemciler, hizmet uygulamalarını ada ve sürüme göre talep edebilir. Bu işlem android.hidl.manager@1.0::IServiceManager HIDL arayüzüne hizmet eder.

Otomatik olarak oluşturulan her HIDL arabirim başlık dosyası ( IFoo.h gibi), arabirim uygulamasını hwservicemanager kaydetmek için kullanılabilecek bir registerAsService() yöntemine sahiptir. İstemciler daha sonra hwservicemanager arayüzü almak için bu adı kullanacaklarından gerekli olan tek argüman arayüz uygulamalarının adıdır:

::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 farklı arayüzlerin (veya aynı arayüzün farklı sürümlerinin) çakışma olmadan aynı örnek adlarıyla kaydedilmesini sağlamak için [package@version::interface, instance_name] kombinasyonunu benzersiz olarak ele alır. registerAsService() ı tam olarak aynı paket sürümü, arayüz ve örnek adı ile çağırırsanız, hwservicemanager referansını önceden kayıtlı hizmete bırakır ve yenisini kullanır.

İstemci uygulaması

Tıpkı sunucunun yaptığı gibi, istemcinin de başvurduğu her arayüzü #include etmesi gerekir:

#include <android/hardware/samples/1.0/IFoo.h>

Bir istemci bir arayüzü iki şekilde elde edebilir:

  • I<InterfaceName>::getService aracılığıyla ( hwservicemanager aracılığıyla)
  • Bir arayüz yöntemi aracılığıyla

Otomatik oluşturulan her arayüz başlık dosyası, hwservicemanager bir hizmet örneğini almak için kullanılabilecek statik bir getService yöntemine sahiptir:

// getService will return nullptr if the service can't be found
sp<IFoo> myFoo = IFoo::getService();
sp<IFoo> myAlternateFoo = IFoo::getService("another_foo");

Artık istemcinin bir IFoo arayüzü var ve sanki yerel bir sınıf uygulamasıymış gibi ona yöntemleri çağırabiliyor. Gerçekte uygulama aynı süreçte, farklı bir süreçte veya hatta başka bir cihazda (HAL uzaktan kumandayla) çalışabilir. İstemci, paketin 1.0 sürümünde yer alan bir IFoo nesnesinde getService adını verdiğinden, hwservicemanager , yalnızca bu uygulamanın 1.0 istemcilerle uyumlu olması durumunda bir sunucu uygulamasını döndürür. Pratikte bu, yalnızca 1.n sürümüne (bir arayüzün x.(y+1) sürümü) sahip sunucu uygulamalarının xy genişletmesi (ve devralması) gerektiği anlamına gelir.

Ek olarak, farklı arayüzler arasında geçiş yapmak için castFrom yöntemi sağlanmıştır. Bu yöntem, temel türün istenen türle aynı olduğundan emin olmak için uzak arabirime bir IPC çağrısı yaparak çalışır. İstenilen tür mevcut değilse nullptr döndürülür.

sp<V1_0::IFoo> foo1_0 = V1_0::IFoo::getService();
sp<V1_1::IFoo> foo1_1 = V1_1::IFoo::castFrom(foo1_0);

Eşzamansız geri aramalar

Mevcut HAL uygulamalarının çoğu eşzamansız donanımla konuşur; bu da, istemcileri meydana gelen yeni olaylar hakkında bilgilendirmek için eşzamansız bir yola ihtiyaç duydukları anlamına gelir. HIDL arabirimi işlevleri, HIDL arabirimi nesnelerini parametre olarak alabildiğinden, HIDL arabirimi eşzamansız geri çağırma olarak kullanılabilir.

Örnek arayüz dosyası IFooCallback.hal :

package android.hardware.samples@1.0;
interface IFooCallback {
    sendEvent(uint32_t event_id);
    sendData(vec<uint8_t> data);
}

IFoo IFooCallback parametresini alan örnek yeni yöntem:

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 arayüzünü kullanan istemci , IFooCallback arayüzünün sunucusudur ; IFooCallback bir uygulamasını sağlar:

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
    }
};

Ayrıca bunu IFoo arayüzünün mevcut bir örneğinin üzerinden de aktarabilir:

sp<IFooCallback> myFooCallback = new FooCallback();
myFoo.registerCallback(myFooCallback);

IFoo uygulayan sunucu bunu bir sp<IFooCallback> nesnesi olarak alır. Geri aramayı saklayabilir ve bu arayüzü kullanmak istediğinde istemciye geri arama yapabilir.

Ölüm alıcıları

Hizmet uygulamaları farklı bir süreçte çalışabildiğinden, istemci hayatta kalırken arayüzü uygulayan sürecin ölmesi mümkündür. Ölen bir süreçte barındırılan bir arayüz nesnesine yapılan tüm çağrılar, bir aktarım hatasıyla başarısız olur ( isOK() işlevi false değerini döndürür). Böyle bir hatadan kurtulmanın tek yolu I<InterfaceName>::getService() öğesini çağırarak hizmetin yeni bir örneğini istemektir. Bu, yalnızca çöken işlem yeniden başlatıldığında ve hizmetlerini servicemanager yeniden kaydettirdiğinde işe yarar (bu genellikle HAL uygulamaları için geçerlidir).

Bununla reaktif olarak uğraşmak yerine, bir arayüzün istemcileri, bir hizmet sona erdiğinde bildirim almak için bir ölüm alıcısını da kaydedebilir. Alınan bir IFoo arayüzünde bu tür bildirimlere kaydolmak için istemci aşağıdakileri yapabilir:

foo->linkToDeath(recipient, 1481 /* cookie */);

recipient parametresi, HIDL tarafından sağlanan android::hardware::hidl_death_recipient arayüzünün bir uygulaması olmalıdır; bu arayüz, arayüzü barındıran işlem öldüğünde RPC iş parçacığı havuzundaki bir iş parçacığından çağrılacak tek bir serviceDied() yöntemini içerir:

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 parametresi linkToDeath() ile iletilen çerezi içerirken who parametresi istemcideki hizmeti temsil eden nesneye yönelik zayıf bir işaretçi içerir. Yukarıda verilen örnek çağrı ile cookie 1481'e, who ise foo eşittir.

Ölüm alıcısını kaydettikten sonra kaydını silmek de mümkündür:

foo->unlinkToDeath(recipient);