HIDL MemoryBlock è un livello astratto costruito su hidl_memory
, HIDL @1.0::IAllocator
e HIDL @1.0::IMapper
. È progettato per i servizi HIDL che dispongono di più blocchi di memoria per condividere un singolo heap di memoria.
Miglioramenti delle prestazioni
L'utilizzo di MemoryBlock nelle applicazioni può ridurre significativamente il numero di errori di segmentazione mmap
/ munmap
e dello spazio utente, migliorando così le prestazioni. Per esempio:
- L'utilizzo di per
hidl_memory
per ogni allocazione del buffer ha una media di 238 us/1 allocazione. - L'utilizzo
MemoryBlock
e la condivisione di un singolohidl_memory
ha un'allocazione media di 2,82 us/1.
Architettura
L'architettura HIDL MemoryBlock include servizi HIDL con più blocchi di memoria che condividono un singolo heap di memoria:
Figura 1. Architettura HIDL MemoryBlock
Utilizzo normale
Questa sezione fornisce un esempio di utilizzo di MemoryBlock dichiarando prima l'HAL e quindi implementando l'HAL.
Dichiarare l'HAL
Per il seguente esempio IFoo HAL:
import android.hidl.memory.block@1.0::MemoryBlock;
interface IFoo {
getSome() generates(MemoryBlock block);
giveBack(MemoryBlock block);
};
Il Android.bp
è il seguente:
hidl_interface {
...
srcs: [
"IFoo.hal",
],
interfaces: [
"android.hidl.memory.block@1.0",
...
};
Implementazione dell'HAL
Per implementare l'HAL di esempio:
Ottieni
hidl_memory
(per i dettagli, fai riferimento a 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 }));
Crea un
HidlMemoryDealer
con l'hidl_memory
acquisito:#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);
Allocare
MemoryBlock
, che è una struttura definita con HIDL.Esempio
MemoryBlock
:struct MemoryBlock { IMemoryToken token; uint64_t size; uint64_t offset; };
Esempio di utilizzo di
MemoryDealer
per allocare unMemoryBlock
:#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); ...
Deallocare
MemoryBlock
:Return<void> Foo::giveBack(const MemoryBlock& block) { memory_dealer->deallocate(block.offset); ...
Manipolare i dati:
#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()));
Configurazione
Android.bp
:shared_libs: [ "android.hidl.memory@1.0", "android.hidl.memory.block@1.0" "android.hidl.memory.token@1.0", "libhidlbase", "libhidlmemory",
Esaminare il flusso per determinare se è necessario
lockMemory
.Normalmente, MemoryBlock utilizza il conteggio dei riferimenti per mantenere la
hidl_memory
condivisa che vienemmap()
la prima volta che uno dei suoiMemoryBlock
viene mappato e vienemunmap()
quando nulla si riferisce ad esso. Per mantenerehidl_memory
sempre mappato, puoi utilizzarelockMemory
, un oggetto in stile RAII che mantiene il corrispondentehidl_memory
mappato per tutto il ciclo di vita del blocco. Esempio:#include <hidlmemory/mapping.h> sp<RefBase> lockMemory(const sp<IMemoryToken> key);
Utilizzo prolungato
Questa sezione fornisce dettagli sull'utilizzo esteso di MemoryBlock
.
Utilizzo del conteggio dei riferimenti per gestire Memoryblock
Nella maggior parte delle situazioni, il modo più efficiente per utilizzare MemoryBlock è allocare/deallocare in modo esplicito. Tuttavia, in applicazioni complesse, l'utilizzo del conteggio dei riferimenti per la garbage collection potrebbe essere un'idea migliore. Per avere il conteggio dei riferimenti su MemoryBlock, puoi associare MemoryBlock a un oggetto raccoglitore, che aiuta a contare i riferimenti e deallocare MemoryBlock quando il conteggio diminuisce a zero.
Dichiarare l'HAL
Quando dichiari l'HAL, descrivi una struttura HIDL che contiene un MemoryBlock e un IBase:
import android.hidl.memory.block@1.0::MemoryBlock;
struct MemoryBlockAllocation {
MemoryBlock block;
IBase refcnt;
};
Utilizzare MemoryBlockAllocation
per sostituire MemoryBlock
e rimuovere il metodo per restituire MemoryBlock
. Verrà deallocato tramite il conteggio dei riferimenti con MemoryBlockAllocation
. Esempio:
interface IFoo {
allocateSome() generates(MemoryBlockAllocation allocation);
};
Implementazione dell'HAL
Esempio dell'implementazione lato servizio dell'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);
Esempio dell'implementazione lato client dell'HAL:
ifoo->allocateSome([&](const MemoryBlockAllocation& allocation){
...
);
Allegare/recuperare metadati
Alcune applicazioni necessitano di dati aggiuntivi da associare al MemoryBlock
allocato. Puoi aggiungere/recuperare metadati utilizzando due metodi:
Se l'applicazione accede ai metadati con la stessa frequenza del blocco stesso, aggiungi i metadati e passali tutti in una struttura. Esempio:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; MetaDataStruct metaData; };
Se l'applicazione accede ai metadati molto meno frequentemente rispetto al blocco, è più efficiente passare passivamente i metadati con un'interfaccia. Esempio:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; IMetaData metaData; };
Successivamente, associa i metadati con MemoryBlock utilizzando Memory Dealer. Esempio:
MemoryBlockWithMetaData memory_block; memory_block.block = dealer->allocate(size); if(HidlMemoryDealer::isOk(block)){ memory_block.metaData = new MetaData(...);