HIDL MemoryBlock es una capa abstracta construida sobre 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 de rendimiento
El uso de MemoryBlock en las aplicaciones puede reducir significativamente la cantidad de fallas de segmentación del espacio de usuario y mmap
/ munmap
, mejorando así el rendimiento. Por ejemplo:
- El uso por
hidl_memory
para cada asignación de búfer promedia 238 us/1 de asignación. - Usar
MemoryBlock
y compartir una solahidl_memory
promedia 2,82 us/1 de asignación.
Arquitectura
La arquitectura HIDL MemoryBlock incluye servicios HIDL con varios bloques de memoria que comparten un solo montón de memoria:
Figura 1. Arquitectura HIDL MemoryBlock
uso normal
Esta sección proporciona un ejemplo del uso de MemoryBlock declarando primero la HAL y luego implementando la HAL.
Declaración de la HAL
Para el siguiente ejemplo IFoo HAL:
import android.hidl.memory.block@1.0::MemoryBlock;
interface IFoo {
getSome() generates(MemoryBlock block);
giveBack(MemoryBlock block);
};
El Android.bp
es el siguiente:
hidl_interface {
...
srcs: [
"IFoo.hal",
],
interfaces: [
"android.hidl.memory.block@1.0",
...
};
Implementando el HAL
Para implementar el HAL de ejemplo:
Obtenga
hidl_memory
(para obtener detalles, 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 }));
Haz un
HidlMemoryDealer
con lahidl_memory
adquirida:#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);
Asignar
MemoryBlock
, que es una estructura definida con HIDL.Ejemplo
MemoryBlock
:struct MemoryBlock { IMemoryToken token; uint64_t size; uint64_t offset; };
Ejemplo usando el
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); ...
MemoryBlock
:Return<void> Foo::giveBack(const MemoryBlock& block) { memory_dealer->deallocate(block.offset); ...
Manipular 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()));
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 el flujo para determinar si necesita
lockMemory
.Normalmente, el MemoryBlock usa el conteo de referencias para mantener la
hidl_memory
compartida, que esmmap()
-ed la primera vez que se mapea uno de susMemoryBlock
s y esmunmap()
-ed cuando nada se refiere a él. Para mantener lahidl_memory
siempre asignada, puede usarlockMemory
, un objeto de estilo RAII que mantiene lahidl_memory
correspondiente asignada durante todo el ciclo de vida de la cerradura. Ejemplo:#include <hidlmemory/mapping.h> sp<RefBase> lockMemory(const sp<IMemoryToken> key);
Uso extendido
Esta sección proporciona detalles sobre el uso extendido de MemoryBlock
.
Uso del recuento de referencias para administrar Memoryblock
En la mayoría de las situaciones, la forma más eficiente de usar MemoryBlock es asignar/desasignar explícitamente. Sin embargo, en aplicaciones complicadas, usar el recuento de referencias para la recolección de elementos no utilizados podría ser una mejor idea. Para tener un recuento de referencias en MemoryBlock, puede vincular MemoryBlock con un objeto de vinculación, lo que ayuda a contar las referencias y desasignar MemoryBlock cuando el recuento disminuye a cero.
Declaración de la HAL
Al declarar la HAL, describa una estructura HIDL que contenga un MemoryBlock y una IBase:
import android.hidl.memory.block@1.0::MemoryBlock;
struct MemoryBlockAllocation {
MemoryBlock block;
IBase refcnt;
};
Use MemoryBlockAllocation
para reemplazar MemoryBlock
y elimine el método para devolver MemoryBlock
. Se desasignará por referencia contando con MemoryBlockAllocation
. Ejemplo:
interface IFoo {
allocateSome() generates(MemoryBlockAllocation allocation);
};
Implementando el HAL
Ejemplo de la implementación del lado del servicio de la 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);
Ejemplo de la implementación del lado del cliente de la HAL:
ifoo->allocateSome([&](const MemoryBlockAllocation& allocation){
...
);
Adjuntar/recuperar metadatos
Algunas aplicaciones necesitan datos adicionales para enlazar con el MemoryBlock
asignado. Puede agregar/recuperar metadatos usando dos métodos:
Si la aplicación accede a los metadatos con tanta frecuencia como el propio bloque, agregue los metadatos y páselos todos en una estructura. Ejemplo:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; MetaDataStruct metaData; };
Si la aplicación accede a los metadatos con mucha menos frecuencia que el 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, vincule los metadatos con el MemoryBlock utilizando el Memory Dealer. Ejemplo:
MemoryBlockWithMetaData memory_block; memory_block.block = dealer->allocate(size); if(HidlMemoryDealer::isOk(block)){ memory_block.metaData = new MetaData(...);