MemoryBlock HIDL

HIDL MemoryBlock è un livello astratto basato su hidl_memory, HIDL @1.0::IAllocator e HIDL @1.0::IMapper. È progettata per i servizi HIDL con più blocchi di memoria per condividere un singolo heap di memoria.

Miglioramenti delle prestazioni

L'utilizzo di MemoryBlock nelle app può ridurre notevolmente il numero di mmap/munmap e errori di segmentazione dello spazio utente, con un conseguente miglioramento del rendimento. Ad esempio:

  • L'utilizzo per hidl_memory per ogni allocazione del buffer ha una media di 238 us/1 l'allocazione delle risorse.
  • L'uso di MemoryBlock e la condivisione di un singolo hidl_memory hanno una media di 2,82 us/1 l'allocazione delle risorse.

Architettura

L'architettura HIDL MemoryBlock include servizi HIDL con memoria multipla la condivisione di un singolo heap di memoria:

MemoryBlock HIDL

Figura 1. Architettura HIDL MemoryBlock

Utilizzo normale

Questa sezione fornisce un esempio di utilizzo di MemoryBlock dichiarando prima il HAL quindi implementa l'HAL.

Dichiara l'HAL

Per il seguente esempio IFoo HAL:

import android.hidl.memory.block@1.0::MemoryBlock;

interface IFoo {
    getSome() generates(MemoryBlock block);
    giveBack(MemoryBlock block);
};

Il Android.bp è il seguente:

hidl_interface {
    ...
    srcs: [
        "IFoo.hal",
    ],
    interfaces: [
        "android.hidl.memory.block@1.0",
        ...
};

Implementare l'HAL

Per implementare l'HAL di esempio:

  1. Scarica hidl_memory (per maggiori dettagli, fai riferimento a 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 un'istanza HidlMemoryDealer con l'oggetto hidl_memory acquisito:

    #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. Alloca MemoryBlock, uno struct definito con HIDL.

    Esempio MemoryBlock:

    struct MemoryBlock {
    IMemoryToken token;
    uint64_t size;
    uint64_t offset;
    };
    

    Esempio di utilizzo di MemoryDealer per allocare 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. Dealloca MemoryBlock:

    Return<void> Foo::giveBack(const MemoryBlock& block) {
        memory_dealer->deallocate(block.offset);
    ...
    
  5. Manipolare i dati:

    #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. Configurazione Android.bp:

    shared_libs: [
            "android.hidl.memory@1.0",
    
            "android.hidl.memory.block@1.0"
    
            "android.hidl.memory.token@1.0",
            "libhidlbase",
            "libhidlmemory",
    
  7. Esamina il flusso per determinare se devi lockMemory.

    Normalmente, MemoryBlock utilizza il conteggio dei riferimenti per mantenere l'elemento hidl_memory, che è mmap()-ed è la prima volta che una delle sue 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" è stata mappata in tutto il blocco lifecycle. Esempio:

    #include <hidlmemory/mapping.h>
    
    sp<RefBase> lockMemory(const sp<IMemoryToken> key);
    

Utilizzo esteso

Questa sezione fornisce dettagli sull'utilizzo esteso di MemoryBlock.

Utilizzare il conteggio dei riferimenti per gestire MemoryBlock

Nella maggior parte delle situazioni, il modo più efficiente per utilizzare MemoryBlock è quello di e allocare/deallocate. Tuttavia, nelle app complicate che utilizzano il conteggio dei riferimenti, per la garbage collection potrebbe essere un'idea migliore. Per contare i riferimenti MemoryBlock, puoi associare MemoryBlock a un oggetto binder, che aiuta a: conta i riferimenti e dealula MemoryBlock quando il conteggio diminuisce a zero.

Dichiara l'HAL

Quando dichiari l'HAL, descrivi uno struct HIDL che contiene un'istruzione MemoryBlock. e un IBase:

import android.hidl.memory.block@1.0::MemoryBlock;

struct MemoryBlockAllocation {
    MemoryBlock block;
    IBase refcnt;
};

Utilizza MemoryBlockAllocation per sostituire MemoryBlock e rimuovere il metodo per restituire MemoryBlock. Viene distribuito mediante il conteggio dei riferimenti con MemoryBlockAllocation. Esempio:

interface IFoo {
    allocateSome() generates(MemoryBlockAllocation allocation);
};

Implementare l'HAL

Esempio di implementazione lato servizio dell'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);

Esempio di implementazione lato client dell'HAL:

ifoo->allocateSome([&](const MemoryBlockAllocation& allocation){
    ...
);

Allega e recupera i metadati

Alcune app richiedono dati aggiuntivi per essere associate all'oggetto MemoryBlock allocato. Puoi aggiungere e recuperare i metadati utilizzando due metodi:

  • Se l'app accede ai metadati con la stessa frequenza del blocco stesso, aggiungere i metadati e trasmetterli tutti in uno struct. Esempio:

    import android.hidl.memory.block@1.0::MemoryBlock;
    
    struct MemoryBlockWithMetaData{
        MemoryBlock block;
        MetaDataStruct metaData;
    };
    
  • Se l'app accede ai metadati molto meno frequentemente rispetto alla blocco, è più efficiente passare i metadati in modo passivo con a riga di comando. Esempio:

    import android.hidl.memory.block@1.0::MemoryBlock;
    
    struct MemoryBlockWithMetaData{
        MemoryBlock block;
        IMetaData metaData;
    };
    

    Successivamente, associa i metadati a MemoryBlock utilizzando MemoryDealer. Esempio:

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