MemoryBlock de HIDL

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 solo hidl_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:

MemoryBlock de HIDL

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:

  1. 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
      }));
    
  2. Crea una instancia de HidlMemoryDealer con el hidl_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);
    
  3. 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 un MemoryBlock:

    #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);
        ...
    
  4. Anula la asignación de MemoryBlock:

    Return<void> Foo::giveBack(const MemoryBlock& block) {
        memory_dealer->deallocate(block.offset);
    ...
    
  5. 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()));
    
  6. 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",
    
  7. Revisa el flujo para determinar si necesitas lockMemory.

    Por lo general, MemoryBlock usa el recuento de referencias para mantener el valor compartido hidl_memory, que tiene una mmap()-ed la primera vez que uno de sus MemoryBlock instances is mapped and ismunmap()-ed when nothing refers to it. To keephidl_memoryalways mapped, you can uselockMemory, a RAII style object that keeps the correspondinghidl_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 mediante MemoryDealer. Ejemplo:

    MemoryBlockWithMetaData memory_block;
    memory_block.block = dealer->allocate(size);
    if(HidlMemoryDealer::isOk(block)){
        memory_block.metaData = new MetaData(...);