Das HIDL MemoryBlock
ist eine abstrakte Ebene, die auf hidl_memory
, HIDL
@1.0::IAllocator
und HIDL @1.0::IMapper
basiert. Sie ist für HIDL-Dienste mit mehreren Speicherblöcken konzipiert, die einen gemeinsamen Speicher-Heap teilen.
Leistungsverbesserungen
Durch die Verwendung von MemoryBlock
in Apps lässt sich die Anzahl der mmap
/munmap
- und User-Space-Segmentierungsfehler 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 IFoo HAL-Beispiel:
import android.hidl.memory.block@1.0::MemoryBlock;
interface IFoo {
getSome() generates(MemoryBlock block);
giveBack(MemoryBlock block);
};
Android.bp
sieht so aus:
hidl_interface {
...
srcs: [
"IFoo.hal",
],
interfaces: [
"android.hidl.memory.block@1.0",
...
};
HAL implementieren
So implementieren Sie die 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()));
Konfiguration
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);
Verlängerte Nutzung
In diesem Abschnitt finden Sie Details zur erweiterten Verwendung von MemoryBlock
.
Referenzanzahl 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
Für einige Apps sind zusätzliche Daten erforderlich, um sie an die zugewiesene MemoryBlock
zu binden.
Sie können Metadaten mit zwei Methoden anfügen und abrufen:
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(...);