El MemoryBlock
de HIDL es una capa abstracta compilada en hidl_memory
, HIDL
@1.0::IAllocator
y HIDL @1.0::IMapper
. Está diseñado para servicios HIDL que tienen varios bloques de memoria para compartir un solo montón de memoria.
Mejoras en el rendimiento
Usar MemoryBlock
en las apps puede reducir significativamente la cantidad de errores de segmentación de mmap
/munmap
y del espacio del usuario, lo que mejora el rendimiento.
Por ejemplo:
- El uso de
hidl_memory
por cada asignación de búferes promedia 238 µs/1 asignación. - Usar
MemoryBlock
y compartir un solohidl_memory
promedia 2.82 us/1 asignación.
Arquitectura
La arquitectura de MemoryBlock
de HIDL incluye servicios HIDL con varios bloques de memoria que comparten una sola pila de memoria:
Figura 1: Arquitectura de MemoryBlock de HIDL
Uso normal
En esta sección, se proporciona un ejemplo del uso de MemoryBlock
. Primero, se declara el HAL y, luego, se implementa.
Cómo declarar el HAL
En el siguiente ejemplo de HAL de IFoo:
import android.hidl.memory.block@1.0::MemoryBlock;
interface IFoo {
getSome() generates(MemoryBlock block);
giveBack(MemoryBlock block);
};
La Android.bp
es la siguiente:
hidl_interface {
...
srcs: [
"IFoo.hal",
],
interfaces: [
"android.hidl.memory.block@1.0",
...
};
Implementa el HAL
Para implementar el HAL de ejemplo, haz lo siguiente:
Obtén el
hidl_memory
(para obtener detalles, consulta HIDL en 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 una instancia de
HidlMemoryDealer
con elhidl_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);
Asigna
MemoryBlock
, que es una struct definida con HIDL.Ejemplo de
MemoryBlock
:struct MemoryBlock { IMemoryToken token; uint64_t size; uint64_t offset; };
Ejemplo en el que se usa
MemoryDealer
para asignar 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); ...
Desasigna
MemoryBlock
:Return<void> Foo::giveBack(const MemoryBlock& block) { memory_dealer->deallocate(block.offset); ...
Manipula los datos:
#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()));
Configuración de
Android.bp
:shared_libs: [ "android.hidl.memory@1.0", "android.hidl.memory.block@1.0" "android.hidl.memory.token@1.0", "libhidlbase", "libhidlmemory",
Revisa el flujo para determinar si necesitas
lockMemory
.Normalmente,
MemoryBlock
usa el recuento de referencias para mantener elhidl_memory
compartido que semmap()
la primera vez que uno de susMemoryBlock 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` se asigna durante el ciclo de vida del bloqueo. Ejemplo:#include <hidlmemory/mapping.h> sp<RefBase> lockMemory(const sp<IMemoryToken> key);
Uso extendido
En esta sección, se proporcionan detalles sobre el uso extendido de MemoryBlock
.
Usa el recuento de referencias para administrar MemoryBlock
En la mayoría de las situaciones, la forma más eficiente de usar MemoryBlock
es asignar o liberar memoria de forma explícita. Sin embargo, en apps complicadas, usar el recuento de referencias para la recolección de basura podría ser una mejor idea. Para tener un recuento de referencias en MemoryBlock
, puedes vincular MemoryBlock
con un objeto vinculador, lo que ayuda a contar las referencias y a liberar MemoryBlock
cuando el recuento disminuye a cero.
Cómo declarar el HAL
Cuando declares la HAL, describe un struct de HIDL que contenga una instancia de MemoryBlock
y un IBase:
import android.hidl.memory.block@1.0::MemoryBlock;
struct MemoryBlockAllocation {
MemoryBlock block;
IBase refcnt;
};
Usa MemoryBlockAllocation
para reemplazar MemoryBlock
y quitar el método para devolver MemoryBlock
. Se desasigna por recuento de referencias con MemoryBlockAllocation
. Ejemplo:
interface IFoo {
allocateSome() generates(MemoryBlockAllocation allocation);
};
Implementa el HAL
Ejemplo de la implementación del HAL del lado del servicio:
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);
Ejemplo de la implementación del HAL del cliente:
ifoo->allocateSome([&](const MemoryBlockAllocation& allocation){
...
);
Cómo adjuntar y recuperar metadatos
Algunas apps necesitan datos adicionales para vincularse con el MemoryBlock
asignado.
Puedes agregar y recuperar metadatos con dos métodos:
Si la app accede a los metadatos con la misma frecuencia que al bloque en sí, agrega los metadatos y pásalos todos en una struct. Ejemplo:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; MetaDataStruct metaData; };
Si la app accede a los metadatos con mucha menos frecuencia que al bloque, es más eficiente pasar los metadatos de forma pasiva con una interfaz. Ejemplo:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; IMetaData metaData; };
A continuación, vincula los metadatos con
MemoryBlock
usandoMemoryDealer
. Ejemplo:MemoryBlockWithMetaData memory_block; memory_block.block = dealer->allocate(size); if(HidlMemoryDealer::isOk(block)){ memory_block.metaData = new MetaData(...);