HIDL MemoryBlock
ist eine abstrakte Schicht, 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 kann die Anzahl der mmap
/munmap
- und User-Space-Segmentierungsfehler erheblich reduziert und so die Leistung verbessert werden.
Beispiel:
- Bei der 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 Speicherblöcken, die sich einen einzigen Speicher-Heap teilen:
Abbildung 1: HIDL MemoryBlock-Architektur
Normale Nutzung
In diesem Abschnitt wird ein Beispiel für die Verwendung von MemoryBlock
gezeigt. Dabei wird zuerst die HAL deklariert und dann implementiert.
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 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 }));
Erstelle 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, einem mit HIDL definierten Typ.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 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()));
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 einer 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. Die Deaktivierung erfolgt durch Referenzzählung mit MemoryBlockAllocation
. 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.
Es gibt zwei Möglichkeiten, Metadaten anzuhängen und abzurufen:
Wenn die App genauso oft auf die Metadaten zugreift wie auf den Block selbst, fügen 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 auf die Metadaten zugreift als auf den Block, 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(...);