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 múltiples bloques de memoria para compartir un único montón de memoria.
Mejoras de rendimiento
El uso de MemoryBlock en aplicaciones puede reducir significativamente la cantidad de mmap
/ munmap
y fallas de segmentación del espacio de usuario, mejorando así el rendimiento. Por ejemplo:
- El uso de per
hidl_memory
para cada asignación de búfer promedia 238 us/1 asignación. - Usar
MemoryBlock
y compartir una únicahidl_memory
promedia 2,82 us/1 asignación.
Arquitectura
La arquitectura HIDL MemoryBlock incluye servicios HIDL con múltiples bloques de memoria que comparten un único montón de memoria:
Figura 1. Arquitectura HIDL MemoryBlock
Uso normal
Esta sección proporciona un ejemplo del uso de MemoryBlock declarando primero HAL y luego implementando HAL.
Declarando el 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 ejemplo HAL:
Obtenga
hidl_memory
(para más 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 }));
Cree 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);
Asigne
MemoryBlock
, que es una estructura definida con HIDL.Ejemplo
MemoryBlock
:struct MemoryBlock { IMemoryToken token; uint64_t size; uint64_t offset; };
Ejemplo de uso de
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); ...
Desasignar
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, MemoryBlock utiliza el recuento de referencias para mantener la
hidl_memory
compartida que tienemmap()
la primera vez que se asigna uno de susMemoryBlock
ymunmap()
cuando nada hace referencia a él. Para mantenerhidl_memory
siempre mapeado, puede usarlockMemory
, un objeto de estilo RAII que mantiene elhidl_memory
correspondiente mapeado durante todo el ciclo de vida del bloqueo. 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 gestionar Memoryblock
En la mayoría de las situaciones, la forma más eficaz de utilizar MemoryBlock es asignar/desasignar explícitamente. Sin embargo, en aplicaciones complicadas, utilizar el recuento de referencias para la recolección de basura podría ser una mejor idea. Para tener un recuento de referencias en MemoryBlock, puede vincular MemoryBlock con un objeto de carpeta, lo que ayuda a contar las referencias y desasignar el MemoryBlock cuando el recuento disminuye a cero.
Declarando el HAL
Al declarar 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;
};
Utilice 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 de servicio de 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 HAL:
ifoo->allocateSome([&](const MemoryBlockAllocation& allocation){
...
);
Adjuntar/recuperar metadatos
Algunas aplicaciones necesitan datos adicionales para vincularse con el MemoryBlock
asignado. Puede agregar/recuperar metadatos usando dos métodos:
Si la aplicación accede a los metadatos con tanta frecuencia como al bloque mismo, 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 MemoryBlock utilizando Memory Dealer. Ejemplo:
MemoryBlockWithMetaData memory_block; memory_block.block = dealer->allocate(size); if(HidlMemoryDealer::isOk(block)){ memory_block.metaData = new MetaData(...);