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
El uso de MemoryBlock
en las apps puede reducir significativamente la cantidad de fallas de segmentación de espacio de usuario y mmap
/munmap
, lo que mejora el rendimiento.
Por ejemplo:
- El uso de
hidl_memory
por cada asignación de búfer tiene un promedio de 238 μs por 1 asignación. - El uso de
MemoryBlock
y el uso compartido de un solohidl_memory
tienen un promedio de 2.82 μs/1 asignación.
Arquitectura
La arquitectura MemoryBlock
del HIDL incluye servicios HIDL con varios bloques de memoria 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
. Primero, se declara el HAL y, luego, se implementa.
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);
};
El Android.bp
es el siguiente:
hidl_interface {
...
srcs: [
"IFoo.hal",
],
interfaces: [
"android.hidl.memory.block@1.0",
...
};
Implementa el HAL
Para implementar la HAL de ejemplo, haz lo siguiente:
Obtén el
hidl_memory
(para obtener más información, 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 estructura definida con HIDL.Ejemplo de
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); ...
Libera
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()));
Config
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 elhidl_memory
compartido, que semmap()
-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 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 reasignar de forma explícita. Sin embargo, en apps complicadas que usan 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
, puedes vincular MemoryBlock
con un objeto Binder, que ayuda a contar las referencias y desasignar MemoryBlock
cuando el recuento disminuye a cero.
Cómo declarar la HAL
Cuando declares la HAL, describe una estructura 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 quita el método para devolver MemoryBlock
. Se desaloca mediante el 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 lado del cliente del HAL:
ifoo->allocateSome([&](const MemoryBlockAllocation& allocation){
...
);
Adjunta y recupera metadatos
Algunas apps necesitan datos adicionales para vincularse con el MemoryBlock
asignado.
Puedes adjuntar y recuperar metadatos con dos métodos:
Si la app accede a los metadatos con la misma frecuencia que al bloque, adjúntalos y pásalos todos en una estructura. 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 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; };
Luego, 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(...);