Hizmetler ve Hizmetler Veri aktarımı

Bu bölümde hizmetlerin nasıl kaydedilip keşfedileceği ve .hal dosyalarındaki arabirimlerde tanımlanan yöntemlerin çağrılması yoluyla bir hizmete nasıl veri gönderileceği açıklanmaktadır.

Hizmetlerin kaydedilmesi

HIDL arayüz sunucuları (arayüz uygulayan nesneler), adlandırılmış hizmetler olarak kaydedilebilir. Kayıtlı adın arayüz veya paket adıyla ilişkili olması gerekmez. Herhangi bir ad belirtilmezse "varsayılan" adı kullanılır; bu, aynı arayüzün iki uygulamasını kaydetmesi gerekmeyen HAL'ler için kullanılmalıdır. Örneğin, her arayüzde tanımlanan hizmet kaydına yönelik C++ çağrısı şöyledir:

status_t status = myFoo->registerAsService();
status_t anotherStatus = anotherFoo->registerAsService("another_foo_service");  // if needed

HIDL arayüzünün sürümü arayüzün kendisinde bulunur. Otomatik olarak hizmet kaydıyla ilişkilendirilir ve her HIDL arabiriminde bir yöntem çağrısı ( android::hardware::IInterface::getInterfaceVersion() ) aracılığıyla alınabilir. Sunucu nesnelerinin kaydedilmesine gerek yoktur ve HIDL yöntemi parametreleri aracılığıyla, sunucuya HIDL yöntemi çağrıları yapacak başka bir işleme aktarılabilir.

Hizmetleri keşfetme

İstemci koduna göre istekler, belirli bir arayüz için ada ve sürüme göre yapılır ve istenen HAL sınıfında getService çağrılır:

// C++
sp<V1_1::IFooService> service = V1_1::IFooService::getService();
sp<V1_1::IFooService> alternateService = V1_1::IFooService::getService("another_foo_service");
// Java
V1_1.IFooService service = V1_1.IFooService.getService(true /* retry */);
V1_1.IFooService alternateService = V1_1.IFooService.getService("another", true /* retry */);

HIDL arayüzünün her versiyonu ayrı bir arayüz olarak ele alınır. Böylece, IFooService sürüm 1.1 ve IFooService sürüm 2.2'nin her ikisi de "foo_service" olarak kaydedilebilir ve her iki arayüzde de getService("foo_service") o arayüz için kayıtlı hizmeti alır. Bu nedenle çoğu durumda kayıt veya keşif için hiçbir ad parametresinin sağlanmasına gerek yoktur ("varsayılan ad" anlamına gelir).

Satıcı Arayüzü Nesnesi aynı zamanda iade edilen arayüzün taşıma yönteminde de rol oynar. android.hardware.foo@1.0 paketindeki bir IFoo arayüzü için, IFoo::getService tarafından döndürülen arayüz, giriş mevcutsa her zaman cihaz bildiriminde android.hardware.foo için bildirilen taşıma yöntemini kullanır; ve taşıma yöntemi mevcut değilse nullptr döndürülür.

Bazı durumlarda hizmet almadan dahi hemen devam etmek gerekebilmektedir. Bu, (örneğin) bir müşteri hizmet bildirimlerini kendisi yönetmek istediğinde veya tüm hwservices'i alması ve alması gereken bir teşhis programında ( atrace gibi) meydana gelebilir. Bu durumda, C++'da tryGetService veya Java'da getService("instance-name", false) gibi ek API'ler sağlanır. Java'da sağlanan eski API getService de hizmet bildirimleriyle birlikte kullanılması gerekir. Bu API'nin kullanılması, istemcinin bu yeniden denemesiz API'lerden biriyle talep etmesinden sonra sunucunun kendisini kaydettirdiği yarış durumunu engellemez.

Hizmet ölümü bildirimleri

Bir hizmet sona erdiğinde bilgilendirilmek isteyen müşteriler, çerçeve tarafından gönderilen ölüm bildirimlerini alabilirler. Bildirim almak için müşterinin şunları yapması gerekir:

  1. HIDL sınıfını/arayüzünü hidl_death_recipient alt sınıfına alın (HIDL'de değil, C++ kodunda).
  2. serviceDied() yöntemini geçersiz kılın.
  3. hidl_death_recipient alt sınıfının bir nesnesini oluşturun.
  4. IDeathRecipient 'ın arayüz nesnesini ileterek izlemek için hizmetteki linkToDeath() yöntemini çağırın. Bu yöntemin, ölüm alıcısının veya çağrıldığı proxy'nin sahipliğini almadığını unutmayın.

Bir sözde kod örneği (C++ ve Java benzerdir):

class IMyDeathReceiver : hidl_death_recipient {
  virtual void serviceDied(uint64_t cookie,
                           wp<IBase>& service) override {
    log("RIP service %d!", cookie);  // Cookie should be 42
  }
};
....
IMyDeathReceiver deathReceiver = new IMyDeathReceiver();
m_importantService->linkToDeath(deathReceiver, 42);

Aynı ölüm alıcısı birden fazla farklı hizmete kayıtlı olabilir.

Veri aktarımı

Veriler, .hal dosyalarındaki arayüzlerde tanımlanan yöntemlerin çağrılması yoluyla bir servise gönderilebilir. İki tür yöntem vardır:

  • Engelleme yöntemleri, sunucu bir sonuç üretene kadar bekler.
  • Tek yönlü yöntemler verileri yalnızca tek yönde gönderir ve engellemez. RPC çağrılarında hareket halindeki veri miktarı uygulama sınırlarını aşarsa, çağrılar ya engellenebilir ya da bir hata göstergesi döndürebilir (davranış henüz belirlenmemiştir).

Değer döndürmeyen ancak oneway olarak bildirilmeyen bir yöntem hâlâ engelliyor demektir.

HIDL arayüzünde bildirilen tüm yöntemler, HAL'den veya HAL'e tek bir yönde çağrılır. Arayüz hangi yönde çağrılacağını belirtmez. Çağrıların HAL'den kaynaklanması gereken mimariler, HAL paketinde iki (veya daha fazla) arayüz sağlamalı ve her işlemden uygun arayüzü sunmalıdır. İstemci ve sunucu kelimeleri, arayüzün çağrı yönüne göre kullanılır (yani HAL, bir arayüzün sunucusu ve başka bir arayüzün istemcisi olabilir).

Geri aramalar

Geri arama sözcüğü, senkronize geri arama ve senkronize olmayan geri arama ile ayırt edilen iki farklı kavramı ifade eder.

Veri döndüren bazı HIDL yöntemlerinde eşzamanlı geri aramalar kullanılır. Birden fazla değer döndüren (veya ilkel olmayan türde bir değer döndüren) bir HIDL yöntemi, sonuçlarını bir geri çağırma işlevi aracılığıyla döndürür. Yalnızca bir değer döndürülürse ve bu ilkel bir türse, geri çağırma kullanılmaz ve yöntemden değer döndürülür. Sunucu HIDL yöntemlerini uygular ve istemci geri aramaları uygular.

Eşzamansız geri aramalar, HIDL arayüzünün sunucusunun aramaları başlatmasına olanak tanır. Bu, ikinci bir arayüzün bir örneğinin birinci arayüzden geçirilmesiyle yapılır. İlk arayüzün istemcisi, ikinci arayüzün sunucusu olarak hareket etmelidir. Birinci arayüzün sunucusu ikinci arayüz nesnesindeki yöntemleri çağırabilir. Örneğin, bir HAL uygulaması, kendisini kullanan sürece, o süreç tarafından oluşturulan ve sunulan bir arayüz nesnesindeki yöntemleri çağırarak bilgileri eşzamansız olarak geri gönderebilir. Eşzamansız geri çağırma için kullanılan arayüzlerdeki yöntemler engelliyor olabilir (ve arayan kişiye değerleri döndürebilir) veya oneway olabilir. Örnek için, HIDL C++' daki "Eşzamansız geri aramalar" konusuna bakın.

Bellek sahipliğini basitleştirmek için yöntem çağrıları ve geri aramalar yalnızca in alır ve out veya inout parametrelerini desteklemez.

İşlem başına limitler

HIDL yöntemlerinde ve geri aramalarda gönderilen veri miktarına işlem başına sınırlama getirilmez. Ancak işlem başına 4 KB'yi aşan çağrılar aşırı kabul edilir. Eğer bu görülüyorsa, verilen HIDL arayüzünün yeniden mimarisinin oluşturulması tavsiye edilir. Diğer bir sınırlama ise birden fazla eş zamanlı işlemi gerçekleştirmek için HIDL altyapısının kullanabileceği kaynaklardır. Bir işleme çağrı gönderen birden çok iş parçacığı veya işlem veya alma işlemi tarafından hızlı bir şekilde ele alınmayan birden çok oneway çağrı nedeniyle birden çok işlem aynı anda hareket halinde olabilir. Tüm eşzamanlı işlemler için kullanılabilen maksimum toplam alan varsayılan olarak 1 MB'tır.

İyi tasarlanmış bir arayüzde bu kaynak sınırlamalarının aşılmaması gerekir; eğer öyleyse, bunları aşan çağrı ya kaynaklar kullanılabilir hale gelene kadar bloke edebilir ya da bir aktarım hatası sinyali verebilir. İşlem başına limitlerin aşıldığı veya toplu hareket halindeki işlemler nedeniyle HIDL uygulama kaynaklarının taştığı her olay, hata ayıklamayı kolaylaştırmak için günlüğe kaydedilir.

Yöntem uygulamaları

HIDL, hedef dilde (C++ veya Java) gerekli türleri, yöntemleri ve geri aramaları bildiren başlık dosyaları oluşturur. HIDL tanımlı yöntemlerin ve geri aramaların prototipi, hem istemci hem de sunucu kodu için aynıdır. HIDL sistemi, arayan tarafta IPC aktarımı için verileri düzenleyen yöntemlerin proxy uygulamalarını ve aranan tarafta verileri yöntemlerin geliştirici uygulamalarına aktaran saplama kodunu sağlar.

Bir işlevi çağıran kişi (HIDL yöntemi veya geri çağırma), işleve aktarılan veri yapılarının sahipliğine sahiptir ve çağrıdan sonra da sahipliği korur; her durumda aranan kişinin depolamayı serbest bırakmasına veya serbest bırakmasına gerek yoktur.

  • C++'da veriler salt okunur olabilir (buna yazma girişimleri segmentasyon hatasına neden olabilir) ve çağrı süresince geçerlidir. İstemci, çağrının ötesine yaymak için verileri derin kopyalayabilir.
  • Java'da kod, verilerin yerel bir kopyasını (normal bir Java nesnesi) alır ve bu kopyayı saklayabilir, değiştirebilir veya çöp toplama işlemine izin verebilir.

RPC olmayan veri aktarımı

HIDL'nin RPC çağrısı kullanmadan veri aktarmanın iki yolu vardır: paylaşılan bellek ve Hızlı Mesaj Kuyruğu (FMQ), her ikisi de yalnızca C++'da desteklenir.

  • Paylaşılan hafıza Yerleşik HIDL tipi memory tahsis edilen paylaşılan belleği temsil eden bir nesneyi iletmek için kullanılır. Paylaşılan hafızayı haritalamak için bir alma işleminde kullanılabilir.
  • Hızlı Mesaj Kuyruğu (FMQ) . HIDL, beklemesiz mesaj iletimini uygulayan şablonlu bir mesaj kuyruğu türü sağlar. Geçişli veya bağlayıcı modda çekirdeği veya zamanlayıcıyı kullanmaz (cihazlar arası iletişim bu özelliklere sahip olmayacaktır). Tipik olarak HAL, yerleşik HIDL tipi MQDescriptorSync veya MQDescriptorUnsync parametresi aracılığıyla RPC'den geçirilebilecek bir nesne oluşturarak kuyruğun sonunu ayarlar. Bu nesne, alma işlemi tarafından kuyruğun diğer ucunu ayarlamak için kullanılabilir.
    • Senkronizasyon kuyruklarının taşmasına izin verilmez ve yalnızca bir okuyucu bulunabilir.
    • Senkronize olmayan kuyrukların taşmasına izin verilir ve çok sayıda okuyucuya sahip olabilir; bunların her birinin verileri zamanında okuması veya kaybetmesi gerekir.
    Her iki türün de taşmasına izin verilmez (boş bir kuyruktan okuma başarısız olur) ve her türün yalnızca bir yazıcısı olabilir.

FMQ hakkında daha fazla ayrıntı için bkz. Hızlı Mesaj Kuyruğu (FMQ) .