Das HIDL MemoryBlock
ist eine abstrakte Ebene, die auf hidl_memory
, HIDL
@1.0::IAllocator
und HIDL @1.0::IMapper
basiert. Es ist für HIDL-Dienste konzipiert, die mehrere Speicherblöcke haben, um einen einzelnen Speicher-Heap zu teilen.
Leistungsverbesserungen
Die Verwendung von MemoryBlock
in Apps kann die Anzahl der mmap
-/munmap
- und Nutzerbereichs-Segmentierungsfehler erheblich reduzieren und so die Leistung verbessern.
Beispiel:
- Die Verwendung von „per
hidl_memory
“ für jede Pufferzuweisung dauert durchschnittlich 238 Mikrosekunden pro Zuweisung. - Bei Verwendung von
MemoryBlock
und Freigabe einer einzelnenhidl_memory
sind durchschnittlich 2,82 µs/Zuweisung erforderlich.
Architektur
Die HIDL-Architektur MemoryBlock
umfasst HIDL-Dienste mit mehreren Speicherblöcken, die sich einen einzelnen Speicher-Heap teilen:
Abbildung 1: HIDL-MemoryBlock-Architektur
Normale Nutzung
In diesem Abschnitt wird ein Beispiel für die Verwendung von MemoryBlock
gezeigt. Dazu wird zuerst die HAL deklariert und dann implementiert.
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);
};
Der Android.bp
sieht so aus:
hidl_interface {
...
srcs: [
"IFoo.hal",
],
interfaces: [
"android.hidl.memory.block@1.0",
...
};
HAL implementieren
So implementieren Sie das Beispiel-HAL:
Rufen Sie die
hidl_memory
ab (weitere Informationen finden Sie unter HIDL 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 einer
MemoryBlock
mitMemoryDealer
:#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
freigeben:Return<void> Foo::giveBack(const MemoryBlock& block) { memory_dealer->deallocate(block.offset); ...
Daten bearbeiten:
#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
die Referenzanzahl, um die gemeinsam genutztehidl_memory
beizubehalten, die beim ersten Mal, wenn eine ihrerMemoryBlock 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 Sperrlebenszyklus zugeordnet wird,mmap()
-ed wird. Beispiel:#include <hidlmemory/mapping.h> sp<RefBase> lockMemory(const sp<IMemoryToken> key);
Verlängerte Nutzung
Dieser Abschnitt enthält Details zur erweiterten Nutzung von MemoryBlock
.
Verwenden der Referenzanzahl zum Verwalten von MemoryBlock
In den meisten Situationen ist es am effizientesten, MemoryBlock
explizit zuzuweisen bzw. freizugeben. Bei komplexen Apps kann es jedoch besser sein, die Referenzzählung für die Garbage Collection zu verwenden. Um die Referenzanzahl für MemoryBlock
zu ermitteln, können Sie MemoryBlock
an ein Binder-Objekt binden. So können die Referenzen gezählt und MemoryBlock
freigegeben werden, wenn die Anzahl auf null sinkt.
HAL deklarieren
Beschreiben Sie beim Deklarieren des 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;
};
Verwenden Sie MemoryBlockAllocation
, um MemoryBlock
zu ersetzen, und entfernen Sie die Methode, um MemoryBlock
zurückzugeben. Der Speicher wird durch Referenzzählung mit MemoryBlockAllocation
freigegeben. Beispiel:
interface IFoo {
allocateSome() generates(MemoryBlockAllocation allocation);
};
HAL implementieren
Beispiel für die serverseitige Implementierung des 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 mit dem zugewiesenen MemoryBlock
zu verknüpfen.
Sie haben zwei Möglichkeiten, Metadaten anzuhängen und abzurufen:
Wenn die App so oft auf die Metadaten zugreift wie auf den Block selbst, hängen Sie die Metadaten an und übergeben Sie sie alle in einer Struktur. Beispiel:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; MetaDataStruct metaData; };
Wenn die App viel seltener auf die Metadaten zugreift als der Block, ist es effizienter, die Metadaten passiv über eine Schnittstelle zu übergeben. Beispiel:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; IMetaData metaData; };
Binden Sie als Nächstes die Metadaten mit
MemoryBlock
mithilfe vonMemoryDealer
. Beispiel:MemoryBlockWithMetaData memory_block; memory_block.block = dealer->allocate(size); if(HidlMemoryDealer::isOk(block)){ memory_block.metaData = new MetaData(...);