O HIDL MemoryBlock é uma camada abstrata construída em hidl_memory
, HIDL @1.0::IAllocator
e HIDL @1.0::IMapper
. Ele é projetado para serviços HIDL que possuem vários blocos de memória para compartilhar um único heap de memória.
Melhorias de desempenho
O uso de MemoryBlock em aplicativos pode reduzir significativamente o número de falhas de segmentação de mmap
/ munmap
e de espaço do usuário, melhorando assim o desempenho. Por exemplo:
- Usar per
hidl_memory
para cada alocação de buffer resulta em média de 238 us/1 alocação. - Usando
MemoryBlock
e compartilhando uma únicahidl_memory
média de alocação é de 2,82 us/1.
Arquitetura
A arquitetura HIDL MemoryBlock inclui serviços HIDL com vários blocos de memória compartilhando um único heap de memória:
Figura 1. Arquitetura HIDL MemoryBlock
Uso normal
Esta seção fornece um exemplo de uso do MemoryBlock declarando primeiro o HAL e implementando o HAL.
Declarando o HAL
Para o seguinte exemplo IFoo HAL:
import android.hidl.memory.block@1.0::MemoryBlock;
interface IFoo {
getSome() generates(MemoryBlock block);
giveBack(MemoryBlock block);
};
O Android.bp
é o seguinte:
hidl_interface {
...
srcs: [
"IFoo.hal",
],
interfaces: [
"android.hidl.memory.block@1.0",
...
};
Implementação do HAL
Para implementar o exemplo HAL:
Obtenha o
hidl_memory
(para obter detalhes, consulte 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 }));
Faça um
HidlMemoryDealer
com ohidl_memory
adquirido:#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);
Alocar
MemoryBlock
, que é uma estrutura definida com HIDL.Exemplo
MemoryBlock
:struct MemoryBlock { IMemoryToken token; uint64_t size; uint64_t offset; };
Exemplo usando o
MemoryDealer
para alocar umMemoryBlock
:#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
:Return<void> Foo::giveBack(const MemoryBlock& block) { memory_dealer->deallocate(block.offset); ...
Manipule os dados:
#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()));
Configurar
Android.bp
:shared_libs: [ "android.hidl.memory@1.0", "android.hidl.memory.block@1.0" "android.hidl.memory.token@1.0", "libhidlbase", "libhidlmemory",
Revise o fluxo para determinar se você precisa
lockMemory
.Normalmente, o MemoryBlock usa a contagem de referência para manter o
hidl_memory
compartilhado que émmap()
-ed na primeira vez que um de seusMemoryBlock
s é mapeado e émunmap()
-ed quando nada se refere a ele. Para manter ohidl_memory
sempre mapeado, você pode usarlockMemory
, um objeto estilo RAII que mantém ohidl_memory
correspondente mapeado durante todo o ciclo de vida do bloqueio. Exemplo:#include <hidlmemory/mapping.h> sp<RefBase> lockMemory(const sp<IMemoryToken> key);
Uso estendido
Esta seção fornece detalhes sobre o uso estendido de MemoryBlock
.
Usando contagem de referência para gerenciar Memoryblock
Na maioria das situações, a maneira mais eficiente de usar MemoryBlock é alocar/desalocar explicitamente. No entanto, em aplicativos complicados, usar contagem de referência para coleta de lixo pode ser uma ideia melhor. Para ter uma contagem de referência em MemoryBlock, você pode vincular MemoryBlock a um objeto binder, que ajuda a contar as referências e desalocar o MemoryBlock quando a contagem diminui para zero.
Declarando o HAL
Ao declarar o HAL, descreva uma estrutura HIDL que contém um MemoryBlock e um IBase:
import android.hidl.memory.block@1.0::MemoryBlock;
struct MemoryBlockAllocation {
MemoryBlock block;
IBase refcnt;
};
Use o MemoryBlockAllocation
para substituir MemoryBlock
e remova o método para devolver o MemoryBlock
. Ele será desalocado por contagem de referência com MemoryBlockAllocation
. Exemplo:
interface IFoo {
allocateSome() generates(MemoryBlockAllocation allocation);
};
Implementação do HAL
Exemplo da implementação do lado do serviço do 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);
Exemplo da implementação do lado do cliente do HAL:
ifoo->allocateSome([&](const MemoryBlockAllocation& allocation){
...
);
Anexar/recuperar metadados
Alguns aplicativos precisam de dados adicionais para vincular com o MemoryBlock
alocado. Você pode anexar/recuperar metadados usando dois métodos:
Se o aplicativo acessar os metadados com a mesma frequência que o próprio bloco, anexe os metadados e passe-os todos em um struct. Exemplo:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; MetaDataStruct metaData; };
Se o aplicativo acessa os metadados com muito menos frequência do que o bloco, é mais eficiente passar os metadados passivamente com uma interface. Exemplo:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; IMetaData metaData; };
Em seguida, vincule os metadados ao MemoryBlock usando o Memory Dealer. Exemplo:
MemoryBlockWithMetaData memory_block; memory_block.block = dealer->allocate(size); if(HidlMemoryDealer::isOk(block)){ memory_block.metaData = new MetaData(...);