El MemoryBlock
de HIDL es una capa abstracta compilada en hidl_memory
, HIDL
@1.0::IAllocator
y HIDL @1.0::IMapper
. Se diseñó para servicios HIDL.
que comparten varios bloques de memoria
para compartir un solo montón de memoria.
Mejoras en el rendimiento
El uso de MemoryBlock
en apps puede reducir significativamente la cantidad de
Fallas de segmentación del espacio de usuario y mmap
/munmap
, lo que mejora el rendimiento.
Por ejemplo:
- El uso por
hidl_memory
para cada asignación de búfer promedia un promedio de 238 us/1 de asignación. - Usar
MemoryBlock
y compartir un solohidl_memory
cuesta 2.82 us/1. de asignación.
Arquitectura
La arquitectura MemoryBlock
de HIDL incluye servicios HIDL con varias memorias
bloques que comparten un solo montón de memoria:
Figura 1: Arquitectura de MemoryBlock de HIDL
Uso normal
En esta sección, se proporciona un ejemplo del uso de MemoryBlock
declarando primero el
Luego, la HAL implementa la HAL.
Cómo declarar la HAL
En el siguiente ejemplo de la HAL de IFoo:
import android.hidl.memory.block@1.0::MemoryBlock;
interface IFoo {
getSome() generates(MemoryBlock block);
giveBack(MemoryBlock block);
};
Android.bp
es el siguiente:
hidl_interface {
...
srcs: [
"IFoo.hal",
],
interfaces: [
"android.hidl.memory.block@1.0",
...
};
Implementa la HAL
Para implementar la HAL de ejemplo, haz lo siguiente:
Obtener el
hidl_memory
(para conocer más detalles, 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 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
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); ...
Anula la asignación de
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
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
.Por lo general,
MemoryBlock
usa el recuento de referencias para mantener el valor compartidohidl_memory
, que tiene unammap()
-ed 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 asignó en todo el bloqueo en el ciclo de vida del AA. 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
.
Cómo usar el recuento de referencias para administrar MemoryBlock
En la mayoría de los casos, la forma más eficiente de usar MemoryBlock
es
asignar/desasignar. Sin embargo, en las apps complicadas que usan el recuento de referencias
para la recolección de elementos no utilizados podría ser una mejor idea. Tener un recuento de referencia en
MemoryBlock
, puedes vincular MemoryBlock
con un objeto Binder, lo que ayuda a
contar las referencias y anular la asignación de MemoryBlock
cuando el recuento disminuye
a cero.
Cómo declarar la HAL
Cuando declares la HAL, describe una estructura de HIDL que contenga un MemoryBlock
y una 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 la HAL
Ejemplo de la implementación de la HAL 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 de la HAL del cliente:
ifoo->allocateSome([&](const MemoryBlockAllocation& allocation){
...
);
Adjunta y recupera 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 el bloque mismo, adjunta los metadatos y pásalos todos en un 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 la bloque, es más eficiente pasar los metadatos de forma pasiva con una interfaz de usuario. Ejemplo:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; IMetaData metaData; };
A continuación, vincula los metadatos con
MemoryBlock
medianteMemoryDealer
. Ejemplo:MemoryBlockWithMetaData memory_block; memory_block.block = dealer->allocate(size); if(HidlMemoryDealer::isOk(block)){ memory_block.metaData = new MetaData(...);