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
MemoryBlockund Freigabe einer einzelnenhidl_memorysind 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_memoryab (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
MemoryBlockzu. 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
MemoryBlockmitMemoryDealer:#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); ...MemoryBlockfreigeben: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
lockMemorymüssen.Normalerweise verwendet
MemoryBlockdie Referenzanzahl, um die gemeinsam genutztehidl_memorybeizubehalten, die beim ersten Mal, wenn eine ihrerMemoryBlock instances is mapped and ismunmap()-ed when nothing refers to it. To keephidl_memoryalways mapped, you can uselockMemory, a RAII style object that keeps the correspondinghidl_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
MemoryBlockmithilfe vonMemoryDealer. Beispiel:MemoryBlockWithMetaData memory_block; memory_block.block = dealer->allocate(size); if(HidlMemoryDealer::isOk(block)){ memory_block.metaData = new MetaData(...);