HIDL MemoryBlock
è uno strato astratto basato su hidl_memory
, HIDL
@1.0::IAllocator
e HIDL @1.0::IMapper
. È progettato per i servizi HIDL
che hanno più blocchi di memoria per condividere un singolo heap di memoria.
Miglioramenti delle prestazioni
L'utilizzo di MemoryBlock
nelle app può ridurre notevolmente il numero di errori di segmentazione dello spazio utente e mmap
/munmap
, migliorando così le prestazioni.
Ad esempio:
- L'utilizzo di
hidl_memory
per ogni allocazione del buffer ha un tempo medio di 238 us/1 allocazione. - L'utilizzo di
MemoryBlock
e la condivisione di un singolohidl_memory
comportano in media 2,82 us/allocazione.
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 poi implementandolo.
Dichiarare l'HAL
Per l'esempio seguente HAL IFoo:
import android.hidl.memory.block@1.0::MemoryBlock;
interface IFoo {
getSome() generates(MemoryBlock block);
giveBack(MemoryBlock block);
};
Android.bp
è il seguente:
hidl_interface {
...
srcs: [
"IFoo.hal",
],
interfaces: [
"android.hidl.memory.block@1.0",
...
};
Implementa l'HAL
Per implementare l'HAL di esempio:
Ottieni il
hidl_memory
(per maggiori dettagli, consulta 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'istanza
HidlMemoryDealer
con ilhidl_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);
Alloca
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); ...
Salloca
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()));
Config
Android.bp
:shared_libs: [ "android.hidl.memory@1.0", "android.hidl.memory.block@1.0" "android.hidl.memory.token@1.0", "libhidlbase", "libhidlmemory",
Esamina il flusso per determinare se devi
lockMemory
.Normalmente,
MemoryBlock
utilizza il conteggio dei riferimenti per mantenere ilhidl_memory
condiviso, ovverommap()
-ed è la prima volta che una delle sueMemoryBlock 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` è mappata durante il ciclo di vita del blocco. Esempio:#include <hidlmemory/mapping.h> sp<RefBase> lockMemory(const sp<IMemoryToken> key);
Utilizzo esteso
Questa sezione fornisce dettagli sull'utilizzo esteso di MemoryBlock
.
Utilizza il conteggio dei riferimenti per gestire MemoryBlock
Nella maggior parte delle situazioni, il modo più efficiente per utilizzare MemoryBlock
è allocare/deallocalizzare esplicitamente. Tuttavia, in app complesse, l'utilizzo del conteggio dei riferimenti per la raccolta dei rifiuti potrebbe essere una soluzione migliore. Per avere il conteggio dei riferimenti su
MemoryBlock
, puoi associare MemoryBlock
a un oggetto binder, che consente di
contare i riferimenti e di deallocare MemoryBlock
quando il conteggio diminuisce
a zero.
Dichiarare l'HAL
Quando dichiari l'HAL, descrivi uno struct HIDL che contenga un'istanza MemoryBlock
e un IBase:
import android.hidl.memory.block@1.0::MemoryBlock;
struct MemoryBlockAllocation {
MemoryBlock block;
IBase refcnt;
};
Utilizza MemoryBlockAllocation
per sostituire MemoryBlock
e rimuovi il metodo per restituire MemoryBlock
. Viene deallocato tramite il conteggio dei riferimenti
con MemoryBlockAllocation
. Esempio:
interface IFoo {
allocateSome() generates(MemoryBlockAllocation allocation);
};
Implementa l'HAL
Esempio di 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 di implementazione lato client dell'HAL:
ifoo->allocateSome([&](const MemoryBlockAllocation& allocation){
...
);
Allega e recupera i metadati
Alcune app richiedono dati aggiuntivi per l'associazione con il MemoryBlock
allocato.
Puoi aggiungere e recuperare i metadati utilizzando due metodi:
Se l'app accede ai metadati con la stessa frequenza del blocco stesso, aggiungi i metadati e passali tutti in uno struct. Esempio:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; MetaDataStruct metaData; };
Se l'app accede ai metadati con una frequenza molto inferiore rispetto al blocco, è più efficiente trasmetterli passivamente con un'interfaccia. Esempio:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; IMetaData metaData; };
Successivamente, associa i metadati a
MemoryBlock
utilizzandoMemoryDealer
. Esempio:MemoryBlockWithMetaData memory_block; memory_block.block = dealer->allocate(size); if(HidlMemoryDealer::isOk(block)){ memory_block.metaData = new MetaData(...);