HIDL MemoryBlock
ist eine abstrakte Schicht, die auf hidl_memory
, HIDL
@1.0::IAllocator
und HIDL @1.0::IMapper
basiert. Es wurde für HIDL-Dienste entwickelt, die mehrere Speicherblöcke haben, um einen einzelnen Arbeitsspeicher-Heap gemeinsam zu nutzen.
Leistungsverbesserungen
Die Verwendung von MemoryBlock
in Apps kann die Anzahl von mmap
/munmap
-Fehlern und die Segmentierung des Nutzerbereichs erheblich reduzieren und so die Leistung verbessern.
Beispiel:
- Bei Verwendung von „pro
hidl_memory
“ für jede Pufferzuordnung beträgt die durchschnittliche Wartezeit 238 µs/1 Zuordnung. - Wenn Sie
MemoryBlock
verwenden und eine einzelnehidl_memory
freigeben, beträgt die durchschnittliche Ausführungszeit 2,82 µs/1 Zuweisung.
Architektur
Die HIDL-MemoryBlock
-Architektur umfasst HIDL-Dienste mit mehreren Arbeitsspeicherblöcken, die sich einen einzelnen Arbeitsspeicher-Heap teilen:
Abbildung 1. HIDL MemoryBlock-Architektur
Normale Nutzung
Dieser Abschnitt enthält ein Beispiel für die Verwendung von MemoryBlock
, bei dem zuerst der HAL deklariert und dann der HAL implementiert wird.
HAL deklarieren
Für das folgende Beispiel-HAL IFoo:
import android.hidl.memory.block@1.0::MemoryBlock;
interface IFoo {
getSome() generates(MemoryBlock block);
giveBack(MemoryBlock block);
};
Der Android.bp
ist so aufgebaut:
hidl_interface {
...
srcs: [
"IFoo.hal",
],
interfaces: [
"android.hidl.memory.block@1.0",
...
};
HAL implementieren
So implementieren Sie das Beispiel-HAL:
Rufen Sie den
hidl_memory
ab. Weitere Informationen finden Sie unter HIDL für C++.#include <android/hidl/allocator/1.0/IAllocator.h> using ::android::hidl::allocator::V1_0::IAllocator; using ::android::hardware::hidl_memory; ... sp<IAllocator> allocator = IAllocator::getService("ashmem"); allocator->allocate(2048, [&](bool success, const hidl_memory& mem) { if (!success) { /* error */ } // you can now use the hidl_memory object 'mem' or pass it }));
Erstellen Sie eine
HidlMemoryDealer
-Instanz mit dem abgerufenenhidl_memory
:#include <hidlmemory/HidlMemoryDealer.h> using ::android::hardware::HidlMemoryDealer /* The mem argument is acquired in the Step1, returned by the ashmemAllocator->allocate */ sp<HidlMemoryDealer> memory_dealer = HidlMemoryDealer::getInstance(mem);
Weisen Sie
MemoryBlock
zu. Dies ist eine mit HIDL definierte Struktur.Beispiel
MemoryBlock
:struct MemoryBlock { IMemoryToken token; uint64_t size; uint64_t offset; };
Beispiel für die Zuweisung eines
MemoryBlock
mithilfe derMemoryDealer
:#include <android/hidl/memory/block/1.0/types.h> using ::android::hidl::memory::block::V1_0::MemoryBlock; Return<void> Foo::getSome(getSome_cb _hidl_cb) { MemoryBlock block = memory_dealer->allocate(1024); if(HidlMemoryDealer::isOk(block)){ _hidl_cb(block); ...
MemoryBlock
nicht mehr zuweisen:Return<void> Foo::giveBack(const MemoryBlock& block) { memory_dealer->deallocate(block.offset); ...
Daten manipulieren:
#include <hidlmemory/mapping.h> #include <android/hidl/memory/1.0/IMemory.h> using ::android::hidl::memory::V1_0::IMemory; sp<IMemory> memory = mapMemory(block); uint8_t* data = static_cast<uint8_t*>(static_cast<void*>(memory->getPointer()));
Config
Android.bp
:shared_libs: [ "android.hidl.memory@1.0", "android.hidl.memory.block@1.0" "android.hidl.memory.token@1.0", "libhidlbase", "libhidlmemory",
Prüfen Sie den Ablauf, um festzustellen, ob Sie
lockMemory
müssen.Normalerweise verwendet
MemoryBlock
eine Referenzzählung, um den freigegebenenhidl_memory
zu verwalten, der zum ersten Malmmap()
wird, wenn eines seinerMemoryBlock instances is mapped and is
munmap()-ed when nothing refers to it. To keep
hidl_memoryalways mapped, you can use
lockMemory, a RAII style object that keeps the corresponding
hidl_memory` während des gesamten Lebenszyklus der Sperre zugeordnet wird. Beispiel:#include <hidlmemory/mapping.h> sp<RefBase> lockMemory(const sp<IMemoryToken> key);
Erweiterte Nutzung
In diesem Abschnitt finden Sie Details zur erweiterten Verwendung von MemoryBlock
.
Referenzzählung zum Verwalten von MemoryBlock verwenden
In den meisten Fällen ist die effizienteste Verwendung von MemoryBlock
die explizite Zuweisung/Deaktivierung. Bei komplexen Apps ist die Verwendung der Referenzzählung für die Garbage Collection jedoch möglicherweise eine bessere Idee. Wenn Sie eine Referenzzählung für MemoryBlock
haben möchten, können Sie MemoryBlock
an ein Binder-Objekt binden. Dies hilft, die Verweise zu zählen und MemoryBlock
zu deallokieren, wenn die Anzahl auf null sinkt.
HAL deklarieren
Deklarieren Sie bei der Deklarierung der HAL eine HIDL-Struktur, die eine MemoryBlock
-Instanz und eine IBase enthält:
import android.hidl.memory.block@1.0::MemoryBlock;
struct MemoryBlockAllocation {
MemoryBlock block;
IBase refcnt;
};
Ersetzen Sie MemoryBlock
durch MemoryBlockAllocation
und entfernen Sie die Methode, um MemoryBlock
wiederherzustellen. Sie wird durch Referenzzählung mit MemoryBlockAllocation
freigegeben. Beispiel:
interface IFoo {
allocateSome() generates(MemoryBlockAllocation allocation);
};
HAL implementieren
Beispiel für die dienstseitige Implementierung der HAL:
class MemoryBlockRefCnt: public virtual IBase {
MemoryBlockRefCnt(uint64_t offset, sp<MemoryDealer> dealer)
: mOffset(offset), mDealer(dealer) {}
~MemoryBlockRefCnt() {
mDealer->deallocate(mOffset);
}
private:
uint64_t mOffset;
sp<MemoryDealer> mDealer;
};
Return<void> Foo::allocateSome(allocateSome_cb _hidl_cb) {
MemoryBlockAllocation allocation;
allocation.block = memory_dealer->allocate(1024);
if(HidlMemoryDealer::isOk(block)){
allocation.refcnt= new MemoryBlockRefCnt(...);
_hidl_cb(allocation);
Beispiel für die clientseitige Implementierung der HAL:
ifoo->allocateSome([&](const MemoryBlockAllocation& allocation){
...
);
Metadaten anhängen und abrufen
Einige Apps benötigen zusätzliche Daten, um sie an die zugewiesene MemoryBlock
zu binden.
Es gibt zwei Möglichkeiten, Metadaten anzuhängen und abzurufen:
Wenn die App genauso oft auf die Metadaten zugreift wie auf den Block selbst, hängen Sie die Metadaten an und übergeben Sie sie alle in einem String. Beispiel:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; MetaDataStruct metaData; };
Wenn die App viel seltener als der Block auf die Metadaten zugreift, ist es effizienter, die Metadaten passiv über eine Benutzeroberfläche zu übergeben. Beispiel:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; IMetaData metaData; };
Binden Sie als Nächstes die Metadaten mithilfe von
MemoryDealer
an dieMemoryBlock
. Beispiel:MemoryBlockWithMetaData memory_block; memory_block.block = dealer->allocate(size); if(HidlMemoryDealer::isOk(block)){ memory_block.metaData = new MetaData(...);