Der 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 über mehrere Speicherblöcke verfügen, um einen einzelnen Speicherheap gemeinsam zu nutzen.
Leistungsverbesserungen
Durch die Verwendung von MemoryBlock in Anwendungen kann die Anzahl der mmap
/ munmap
und User Space-Segmentierungsfehler erheblich reduziert und so die Leistung verbessert werden. Zum Beispiel:
- Die Verwendung von pro
hidl_memory
für jede Pufferzuweisung beträgt durchschnittlich 238 us/1 Zuweisung. - Die Verwendung
MemoryBlock
und die gemeinsame Nutzung eines einzelnenhidl_memory
erfordert durchschnittlich 2,82 us/1 Zuweisung.
Die Architektur
Die HIDL MemoryBlock-Architektur umfasst HIDL-Dienste mit mehreren Speicherblöcken, die sich einen einzigen Speicherheap teilen:
Abbildung 1. HIDL MemoryBlock-Architektur
Normaler Gebrauch
Dieser Abschnitt enthält ein Beispiel für die Verwendung von MemoryBlock, indem zuerst die HAL deklariert und dann die HAL implementiert wird.
Deklaration des HAL
Für das folgende Beispiel IFoo HAL:
import android.hidl.memory.block@1.0::MemoryBlock;
interface IFoo {
getSome() generates(MemoryBlock block);
giveBack(MemoryBlock block);
};
Die Android.bp
lautet wie folgt:
hidl_interface {
...
srcs: [
"IFoo.hal",
],
interfaces: [
"android.hidl.memory.block@1.0",
...
};
Implementierung des HAL
So implementieren Sie das Beispiel-HAL:
Holen Sie sich
hidl_memory
(Einzelheiten 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 einen
HidlMemoryDealer
mit dem erworbenenhidl_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);
Allocate
MemoryBlock
, eine mit HIDL definierte Struktur.Beispiel
MemoryBlock
:struct MemoryBlock { IMemoryToken token; uint64_t size; uint64_t offset; };
Beispiel für die Verwendung des
MemoryDealer
zum Zuweisen einesMemoryBlock
:#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); ...
Bearbeiten Sie die Daten:
#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()));
Konfigurieren Sie
Android.bp
:shared_libs: [ "android.hidl.memory@1.0", "android.hidl.memory.block@1.0" "android.hidl.memory.token@1.0", "libhidlbase", "libhidlmemory",
Überprüfen Sie den Ablauf, um festzustellen, ob Sie
lockMemory
benötigen.Normalerweise verwendet der MemoryBlock den Referenzzähler, um den gemeinsam genutzten
hidl_memory
zu verwalten, dermmap()
-ed wird, wenn einer seinerMemoryBlock
s zum ersten Mal zugeordnet wird, undmunmap()
-ed wird, wenn nichts darauf verweist. Um denhidl_memory
immer zugeordnet zu halten, können SielockMemory
verwenden, ein Objekt im RAII-Stil, das den entsprechendenhidl_memory
während des gesamten Sperrlebenszyklus zugeordnet hält. Beispiel:#include <hidlmemory/mapping.h> sp<RefBase> lockMemory(const sp<IMemoryToken> key);
Erweiterte Nutzung
Dieser Abschnitt enthält Details zur erweiterten Verwendung von MemoryBlock
.
Verwenden der Referenzanzahl zum Verwalten von Memoryblock
In den meisten Situationen besteht die effizienteste Möglichkeit, MemoryBlock zu verwenden, darin, die Zuordnung explizit zuzuweisen bzw. aufzuheben. In komplizierten Anwendungen ist es jedoch möglicherweise besser, den Referenzzähler für die Speicherbereinigung zu verwenden. Um einen Referenzzähler für MemoryBlock zu haben, können Sie MemoryBlock mit einem Binderobjekt binden, was dabei hilft, die Referenzen zu zählen und den MemoryBlock freizugeben, wenn der Zähler auf Null sinkt.
Deklaration des HAL
Beschreiben Sie beim Deklarieren des HAL eine HIDL-Struktur, die einen MemoryBlock 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 die Methode zu entfernen, um MemoryBlock
zurückzugeben. Die Zuordnung wird durch Referenzzählung mit MemoryBlockAllocation
aufgehoben. Beispiel:
interface IFoo {
allocateSome() generates(MemoryBlockAllocation allocation);
};
Implementierung des HAL
Beispiel für die serviceseitige 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 des HAL:
ifoo->allocateSome([&](const MemoryBlockAllocation& allocation){
...
);
Anhängen/Abrufen von Metadaten
Einige Anwendungen benötigen zusätzliche Daten, um sich an den zugewiesenen MemoryBlock
zu binden. Sie können Metadaten mit zwei Methoden anhängen/abrufen:
Wenn die Anwendung genauso 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 Anwendung 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; };
Als nächstes binden Sie die Metadaten mithilfe des Memory Dealer an den MemoryBlock. Beispiel:
MemoryBlockWithMetaData memory_block; memory_block.block = dealer->allocate(size); if(HidlMemoryDealer::isOk(block)){ memory_block.metaData = new MetaData(...);