AIDL desteği için aşağıdaki kaynaklara da bakabilirsiniz: AIDL ile FMQ.
HIDL'nin uzak prosedür çağrısı (RPC) altyapısı Bağlayıcı mekanizmaları kullanır, Yani çağrılar ek yük gerektirir, çekirdek işlemleri gerektirir ve planlayıcı işlemidir. Ancak, özellikle mobil ağlar arasında veri aktarımının gerekli olduğu daha az ek yük ve çekirdek dahil olmayan süreçlerle, Fast Message Queue (FMQ) sisteminin kullanılması.
FMQ, istenen özelliklerle mesaj sıraları oluşturur.
MQDescriptorSync
veya MQDescriptorUnsync
nesnesi olabilir
HIDL RPC çağrısı üzerinden gönderilmiş ve alma işlemi tarafından
ileti sırası.
Hızlı Mesaj Sıraları yalnızca C++ ve cihazlarda desteklenir Android 8.0 ve daha yeni bir sürüm kullanıyorsanız.
MessageQueue türleri
Android, iki sıra türünü (aroma olarak bilinir) destekler:
- Senkronize edilmemiş sıraların taşmasına izin verilir ve çok sayıda okuyucular; Her okuyucunun verileri zamanında okuması gerekir; aksi halde bu verileri kaybedebilir.
- Senkronize edilmiş sıraların taşmasına izin verilmez ve yalnızca bir okuyucu.
Her iki sıra türünün de göz ardı edilmesine izin verilmez (boş bir kuyruktan okuma) başarısız olur) ve yalnızca bir yazarı olabilir.
Senkronize edilmedi
Senkronize edilmemiş bir sıranın yalnızca bir yazarı vardır, ancak okuyucular. Sıra için bir yazma konumu vardır. ancak her okuyucu okuma konumunu izlemesine olanak tanır.
Sıraya yazma işlemleri yapılandırılmış sıra kapasitesinden ( sıra kapasitesi hemen başarısız olur. Her okuyucunun okuması farklı olabilir her okuyucunun her veri parçasını okumasını beklemek yerine, yeni yazmalar için alana ihtiyaç duyulduğunda sıradan çıkmasına izin verilir.
Okuyucular, sıraya ekleyebilirsiniz. Mevcut olandan daha fazla veri okumaya çalışan bir okuma hemen başarısız olursa (engelleme yoksa) veya yeterli verinin kullanılabilmesini beklerken (eğer engelleme). Her zaman sıra kapasitesinden daha fazla veri okumaya çalışan okuma işlemi hemen başarısız olur.
Okuyucu, bir yazarın gerisinde kalmazsa okuyucu tarafından henüz okunmamış olması ihtimaline karşı bir sonraki okuma veri döndürmez; okuyucunun okuma hızını sıfırlar konumunu en son yazma konumuna eşit olacak şekilde ayarlayıp hata döndürür. Öğe okunabilecek veriler taşma işleminden sonra kontrol edilir, ancak bir sonraki okuma işleminden önce sıra kapasitesinden daha fazla verinin okunabileceğini gösterir. taşma oluştu. (Sıra, kullanılabilir veriler kontrol edildikten sonra taşarsa çalışırken, taşmanın tek göstergesi okuma işlemi başarısız olur.)
Senkronize edilmemiş bir sıranın okuyucuları, büyük olasılıkla sıfırlamak istemiyor sıranın okuma ve yazma işaretçilerini kullanır. Bu nedenle, tanımlayıcı okuyucular "resetPointers" için "false" bağımsız değişkeni kullanmalıdır parametresinden sonra bir değer girin.
Senkronize edildi
Senkronize edilmiş bir sıranın tek bir yazma özelliğine sahip bir yazarı ve bir okuyucusu vardır ve tek bir okuma konumuna sahip olur. Bir ekipten çok daha fazla sırada, sıranın şu anda bulundurduğundan daha fazla veri için alan vardır veya bu verilerin okunduğundan daha fazladır. Engellemeyen veya engellemeyen yazma ya da okuma işlevinin çağrılır, kullanılabilir alanı aşmaya çalışır veya veri döndürme hatası hemen kullanabilir veya istenen işlem tamamlanana kadar engelleyebilirsiniz. Şunları dener: sıra kapasitesinden daha fazla veri okuma veya yazma işlemi her zaman anında başarısız olur.
FMQ kurulumu
İleti sırası için birden fazla MessageQueue
nesne gerekiyor: biri -
bir veya daha çok kaynak
okunabilir. Uygunsuz bir belge yok
yazma veya okuma için kullanılacak nesnenin yapılandırılması; konu hakkında
emin olmak için kullanıcının hem okuma hem de yazma için
en fazla bir yazar olabilir ve senkronize edilmiş sıralar için
yardımcı olur.
İlk MessageQueue nesnesini oluşturma
Bir mesaj sırası tek bir çağrıyla oluşturulur ve yapılandırılır:
#include <fmq/MessageQueue.h> using android::hardware::kSynchronizedReadWrite; using android::hardware::kUnsynchronizedWrite; using android::hardware::MQDescriptorSync; using android::hardware::MQDescriptorUnsync; using android::hardware::MessageQueue; .... // For a synchronized non-blocking FMQ mFmqSynchronized = new (std::nothrow) MessageQueue<uint16_t, kSynchronizedReadWrite> (kNumElementsInQueue); // For an unsynchronized FMQ that supports blocking mFmqUnsynchronizedBlocking = new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite> (kNumElementsInQueue, true /* enable blocking operations */);
MessageQueue<T, flavor>(numElements)
başlatıcı İleti sırası işlevini destekleyen bir nesne oluşturur ve başlatır.MessageQueue<T, flavor>(numElements, configureEventFlagWord)
başlatıcısı bir nesne oluşturur ve ilk kullanıma hazırlar engelleme özelliğiyle ileti sırası işlevini destekleyenflavor
, değeri içinkSynchronizedReadWrite
olabilir senkronize edilmiş sıra veya senkronize edilmemiş bir öğe içinkUnsynchronizedWrite
sıra.uint16_t
(bu örnekte) herhangi bir olabilir HIDL tarafından tanımlanmış tür: iç içe yerleştirilmiş arabellekler (string
veyavec
değil) içermez kullanıcı adları veya arayüzler.kNumElementsInQueue
, sıranın şu sayıda boyutunu gösterir: girişlerin sayısı; bu işlem, ayrılan depolama alanına ayrılan paylaşılan bellek arabelleğinin boyutunu sıraya ekleyin.
İkinci MessageQueue nesnesini oluşturma
İleti sırasının ikinci tarafı
İlk taraftan MQDescriptor
nesne alındı. İlgili içeriği oluşturmak için kullanılan
İşleme bir HIDL veya AIDL RPC çağrısı üzerinden MQDescriptor
nesnesi gönderilir
bulunur. İlgili içeriği oluşturmak için kullanılan
MQDescriptor
, sırayla ilgili aşağıdakiler gibi bilgileri içerir:
- Arabelleği eşleme ve işaretçi yazma bilgileri.
- Okuma işaretçisini eşleyecek bilgiler (sıra senkronize edilmişse).
- Etkinlik işareti kelimeyi eşleyecek bilgiler (sıradaki engelleme engelleniyorsa).
- Şunları içeren nesne türü (
<T, flavor>
): HIDL tarafından tanımlanan tür: sıra öğeleri ve sıra aroma (senkronize edilmiş veya senkronize edilmemiş).
MQDescriptor
nesnesi,
MessageQueue
nesne:
MessageQueue<T, flavor>::MessageQueue(const MQDescriptor<T, flavor>& Desc, bool resetPointers)
resetPointers
parametresi, okuma değerinin sıfırlanıp sıfırlanmayacağını gösterir
ve bu MessageQueue
nesnesini oluştururken konumları 0 olarak yazın.
Senkronize edilmemiş bir sırada, okuma konumu (her bir
senkronize edilmemiş sıralardaki MessageQueue
nesnesi) her zaman 0 değerine ayarlanır
dikkat edin. MQDescriptor
, genellikle şu işlem sırasında başlatılır:
ilk ileti sırası nesnesinin oluşturulması. Paylaşılan ortak kontroller üzerinde ekstra kontrol
kullanıyorsanız MQDescriptor
cihazını manuel olarak ayarlayabilirsiniz
(MQDescriptor
, şurada tanımlanıyor:
system/libhidl/base/include/hidl/MQDescriptor.h
)
daha sonra, bu bölümde açıklandığı şekilde her MessageQueue
nesnesini oluşturun.
Sıraları ve etkinlik işaretlerini engelle
Varsayılan olarak, sıralar okuma/yazma işlemlerini engellemeyi desteklemez. İki türü vardır engellemesiyle ilgili daha fazla bilgi edinin:
- Üç parametre (veri işaretçisi, öğe sayısı,
zaman aşımı) ekleyebilirsiniz. Tek bir cihazda bağımsız okuma/yazma işlemlerinde engellemeyi destekler
sıra. Bu form kullanılırken sıra, etkinlik işaretini ve bit maskelerini işler
ve ilk ileti sırası nesnesi
ikinci bir
true
parametresiyle başlatılmalıdır. Örnek:// For an unsynchronized FMQ that supports blocking mFmqUnsynchronizedBlocking = new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite> (kNumElementsInQueue, true /* enable blocking operations */);
. - Altı parametreli (etkinlik bayrağı ve bit maskeleri dahil) uzun biçim.
Birden fazla sıra arasında paylaşılan
EventFlag
nesnesinin kullanılmasını destekler ve kullanılacak bildirim bit maskelerinin belirtilmesine olanak tanır. Bu durumda, her okuma ve yazma çağrısına etkinlik işareti ve bit maskeleri sağlanmalıdır.
Uzun biçim için EventFlag
açıkça
Her bir readBlocking()
ve writeBlocking()
çağrısı. Şunlardan biri:
sıralar, dahili bir etkinlik işaretiyle başlatılabilir. Bunun ardından
kullanılarak sıranın MessageQueue
nesnesinden ayıklandı.
getEventFlagWord()
ve EventFlag
oluşturmak için kullanıldı
her işlemde başka FMQ'larla kullanmak için. Alternatif olarak,
EventFlag
nesne, uygun paylaşılan herhangi bir nesneyle başlatılabilir
hafızada bulabilirsiniz.
Genel olarak her sıra, engellemeyen, kısa biçimli videolardan yalnızca birini kullanmalıdır. veya uzun biçimli engellemedir. Bunları karıştırmak bir hata değildir ancak programlamanın önemi var.
Hafızayı salt okunur olarak işaretle
Paylaşılan bellek, varsayılan olarak okuma ve yazma izinlerine sahiptir. Senkronize edilmemiş
sıralar (kUnsynchronizedWrite
) varsa yazar tüm cihazlar için yazma izinlerini kaldırmak
MQDescriptorUnsync
nesneleri bırakmadan önce
okurlar. Bu, diğer
işlemleri sıraya yazamaz. Bu, hatalara ve kötü davranışlara karşı koruma için önerilir.
kısa bir ifadedir.
Yazar,
Sıranın okunan tarafını oluşturmak için MQDescriptorUnsync
işlemi gerçekleştirildiğinde anı işaretlenemez.
salt okunur olarak belirleyin. Bu, "MessageQueue" kurucusunun varsayılan davranışıdır. Önceden oluşturulmuş
varsa, bu kullanıcıların kodlarını değiştirerek sıra oluşturmak için
resetPointer=false
- Yazar:
MQDescriptor
dosya tanımlayıcısıylaashmem_set_prot_region
öğesini çağırın ve bölge salt okunur (PROT_READ
) olarak ayarlanmış:int res = ashmem_set_prot_region(mqDesc->handle->data[0], PROT_READ)
- Reader:
resetPointer=false
ile ileti sırası oluşturun ( varsayılan değertrue
):mFmq = new (std::nothrow) MessageQueue(mqDesc, false);
MessageQueue'yu kullanma
MessageQueue
nesnesinin herkese açık API'si:
size_t availableToWrite() // Space available (number of elements). size_t availableToRead() // Number of elements available. size_t getQuantumSize() // Size of type T in bytes. size_t getQuantumCount() // Number of items of type T that fit in the FMQ. bool isValid() // Whether the FMQ is configured correctly. const MQDescriptor<T, flavor>* getDesc() // Return info to send to other process. bool write(const T* data) // Write one T to FMQ; true if successful. bool write(const T* data, size_t count) // Write count T's; no partial writes. bool read(T* data); // read one T from FMQ; true if successful. bool read(T* data, size_t count); // Read count T's; no partial reads. bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0); bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0); // Allows multiple queues to share a single event flag word std::atomic<uint32_t>* getEventFlagWord(); bool writeBlocking(const T* data, size_t count, uint32_t readNotification, uint32_t writeNotification, int64_t timeOutNanos = 0, android::hardware::EventFlag* evFlag = nullptr); // Blocking write operation for count Ts. bool readBlocking(T* data, size_t count, uint32_t readNotification, uint32_t writeNotification, int64_t timeOutNanos = 0, android::hardware::EventFlag* evFlag = nullptr) // Blocking read operation for count Ts; //APIs to allow zero copy read/write operations bool beginWrite(size_t nMessages, MemTransaction* memTx) const; bool commitWrite(size_t nMessages); bool beginRead(size_t nMessages, MemTransaction* memTx) const; bool commitRead(size_t nMessages);
availableToWrite()
ve availableToRead()
kullanılabilir
tek bir işlemde ne kadar veri aktarılabileceğini belirleyin.
senkronize edilmemiş sıra:
availableToWrite()
, her zaman sıranın kapasitesini döndürür.- Her okuyucunun kendi okuma konumu vardır ve okuyucunun
availableToRead()
- Yavaş bir okuyucu açısından sıranın taşmasına izin verilir.
bu,
availableToRead()
ürününün şundan daha büyük bir değer döndürmesine neden olabilir: sıranın boyutunu belirler. Bir taşma başarısız olduktan sonraki ilk okuma işlemi o okuyucunun okuma konumu, geçerli yazma işaretçisine eşit olarak ayarlanır. taşmanın Google Ads üzerindenavailableToRead()
read()
ve write()
yöntemleri şu sonucu döndürür:
İstenen tüm veriler şuralara/kaynaklardan aktarılabiliyorsa (ve bu veriler aktarılmışsa) true
sıraya ekleyebilirsiniz. Bu yöntemler ya başarılı olur (ve ya da
true
) veya hemen iade hatası (false
) olabilir.
readBlocking()
ve writeBlocking()
yöntemleri bekler
istenen işlem tamamlanana kadar veya işlem zaman aşımına uğrayana kadar (bir
timeOutNanos
değerinin 0 olması hiçbir zaman zaman aşımına uğramayacağı anlamına gelir).
Engelleme işlemleri, bir etkinlik işareti kelimesi kullanılarak uygulanır. Varsayılan olarak
her bir sıra, hikayenin kısa biçimini desteklemek için kendi işaret kelimesini
readBlocking()
ve writeBlocking()
. Birbirinden farklı
tek bir kelimeyi paylaşmak için birden fazla kuyruğa sahiptir. Böylece işlem, yazma veya
okumayı kuyruğa sokar. Bir sıranın etkinlik işareti kelimesine işaret eden
getEventFlagWord()
çağrısıyla elde edilir ve bu işaretçi (veya
uygun bir paylaşılan bellek konumuna işaret etme) kullanılabilir.
EventFlag
nesne
Farklı bir kullanıcı için readBlocking()
ve writeBlocking()
sıra. readNotification
ve writeNotification
Parametreler, okuma ve veri işleme göstergeleri için etkinlik işaretindeki hangi bitlerin kullanılması gerektiğini belirtir
yazması için bir fırsattır. readNotification
ve
writeNotification
, 32 bit bit maskeleridir.
readBlocking()
, writeNotification
bitte bekler;
bu parametre 0 ise çağrı her zaman başarısız olur. Öğe
readNotification
değeri 0 ise çağrı başarısız olmaz ancak
başarılı okuma işlemi herhangi bir bildirim biti ayarlamaz. Senkronize edilmiş bir sırada,
bu, ilgili writeBlocking()
çağrısının
Bit başka bir yere ayarlanmadığı sürece hiçbir zaman uyanmaz. Senkronize edilmemiş bir sırada,
writeBlocking()
beklemez (yine de
yazma bildirimi biti) kullanır ve okumaların, herhangi bir değer
bildirim bit'leri için de geçerlidir. Benzer şekilde, writeblocking()
readNotification
değeri 0'dır ve başarılı bir yazma işlemi, belirtilen
writeNotification
bit.
Aynı anda birden fazla sırayı beklemek için EventFlag
nesnesinin
Bildirim bit maskesi üzerinde beklemek için wait()
yöntemi. İlgili içeriği oluşturmak için kullanılan
wait()
yöntemi,
uyanma vakti geldi. Bu bilgiler daha sonra ilgili sıranın mevcut olmadığını doğrulamak için kullanılır.
istenen yazma/okuma işlemi için yeterli alan veya veri sağlayın ve
engellenmeyen write()
/read()
. Yükleme işlemi almak için
bildirim için başka bir çağrı kullanın: EventFlag
wake()
yöntemi. EventFlag
tanımı için
soyutlama, referans
system/libfmq/include/fmq/EventFlag.h
Sıfır kopyalama işlemi
İlgili içeriği oluşturmak için kullanılan
read
/write
/readBlocking
/writeBlocking()
API'ler, işaretçiyi bağımsız değişken olarak giriş/çıkış arabelleğine götürür ve
memcpy()
aynı ile
FMQ halka arabelleği. Performansı iyileştirmek için Android 8.0 ve sonraki sürümler,
Halka arabelleğine doğrudan işaretçi erişimi sağlayarak
memcpy
çağrılarını kullanmanız gerekiyor.
Sıfır kopyalı FMQ işlemleri için aşağıdaki herkese açık API'leri kullanın:
bool beginWrite(size_t nMessages, MemTransaction* memTx) const; bool commitWrite(size_t nMessages); bool beginRead(size_t nMessages, MemTransaction* memTx) const; bool commitRead(size_t nMessages);
beginWrite
yöntemi, FMQ halkasına taban işaretçiler sağlar arabellek. Veriler yazıldıktan sonracommitWrite()
işlevini kullanarak kaydedin.beginRead
/commitRead
yöntemleri aynı şekilde çalışır.beginRead
/Write
yöntemleri okunacak/yazılacak mesajların sayısını belirler ve olanak tanır. Okuma veya yazma mümkünsememTx
struct, doğrudan işaretçi için kullanılabilecek temel işaretçilerle doldurulur halka arabelleği paylaşılan belleğe erişme.MemRegion
struct, bir bellek bloğuyla ilgili ayrıntıları içerir. taban işaretçi (hafıza bloğunun ana adresi) ve uzunluğu da dahil olmak üzereT
(HIDL tarafından tanımlanan sıranın türünü seçin).MemTransaction
yapısı ikiMemRegion
içerir struct,first
vesecond
okuma veya yazma olarak kullanılır halka arabelleğinde, sıranın başına sarmalama gerekebilir. Bu FMQ'ya veri okumak/yazmak için iki temel işaretçinin olması gerektiği anlamına gelir. halka arabelleği.
MemRegion
yapısından temel adresi ve uzunluğu almak için:
T* getAddress(); // gets the base address size_t getLength(); // gets the length of the memory region in terms of T size_t getLengthInBytes(); // gets the length of the memory region in bytes
Belirli bir zaman dilimi içinde birinci ve ikinci MemRegion
ile ilgili referanslar almak için
MemTransaction
nesne:
const MemRegion& getFirstRegion(); // get a reference to the first MemRegion const MemRegion& getSecondRegion(); // get a reference to the second MemRegion
Sıfır kopya API'lerini kullanarak FMQ'ya yazma örneği:
MessageQueueSync::MemTransaction tx; if (mQueue->beginRead(dataLen, &tx)) { auto first = tx.getFirstRegion(); auto second = tx.getSecondRegion(); foo(first.getAddress(), first.getLength()); // method that performs the data write foo(second.getAddress(), second.getLength()); // method that performs the data write if(commitWrite(dataLen) == false) { // report error } } else { // report error }
Aşağıdaki yardımcı yöntemler de MemTransaction
kapsamındadır:
T* getSlot(size_t idx);
.
Şunun içindekiidx
alanına bir işaretçi döndürür: BuMemTransaction
kapsamındakiMemRegions
nesnesini tanımlayın.MemTransaction
nesnesi, belleği temsil ediyorsa T türünde N öğe okunacak/yazılacak bölge, ardından geçerli aralıkidx
, 0 ile N-1 arasındadır.bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
.
Bellek bölgelerine T türündenMessages
öğe yazınstartIdx
dizininden başlayarak nesne tarafından açıklanır. Bu yöntemmemcpy()
kullanıyor ve sıfır kopya için kullanılmamalıdır işlemidir.MemTransaction
nesnesi, T türünde N öğe okuma/yazma yapıyorsanız geçerliidx
aralığı arasında yer alır.bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
.nMessages
startIdx
tarihinden itibaren nesne tarafından açıklanan bellek bölgeleri. Bu yöntemindememcpy()
kullanılmaktadır ve sıfır kopya için kullanılmamalıdır işlemidir.
Sırayı HIDL üzerinden gönder
İçerik üretme tarafında:
- Yukarıda açıklandığı şekilde ileti sırası nesnesi oluşturun.
isValid()
ile nesnenin geçerli olduğunu doğrulayın.- Birden fazla sıra bekliyorsanız
EventFlag
biçiminin uzun biçiminereadBlocking()
/writeBlocking()
etkinlik bayrağı işaretçisi (getEventFlagWord()
kullanılarak) İşareti oluşturmak için başlatılanMessageQueue
nesnesi ve gerekliEventFlag
nesnesini oluşturmak için bu işareti kullanın. MessageQueue
getDesc()
yöntemini kullanarak açıklayıcı nesneden en iyi şekilde yararlanabilirsiniz..hal
dosyasında yönteme şu türde bir parametre verin:fmq_sync
veyafmq_unsync
, buradaT
bir ve HIDL tarafından tanımlanan uygun bir türdür. Bu komutu,getDesc()
tarihinde almalısınız.
Alıcı tarafta:
MessageQueue
nesnesi oluşturmak için açıklayıcı nesneyi kullanın. aynı sıra aromasını ve veri türünü kullandığınızdan emin olun. Aksi takdirde, şablon derler.- Bir etkinlik işaretini çıkardıysanız
Alıcı işlemde
MessageQueue
nesne var. - Verileri aktarmak için
MessageQueue
nesnesini kullanın.