MemoryBlock HIDL

Le MemoryBlock HIDL est une couche abstraite basée sur hidl_memory, HIDL @1.0::IAllocator et HIDL @1.0::IMapper. Il est conçu pour les services HIDL qui comportent plusieurs blocs de mémoire pour partager un seul tas de mémoire.

Amélioration des performances

L'utilisation de MemoryBlock dans les applications peut réduire considérablement le nombre mmap/munmap et les erreurs de segmentation de l'espace utilisateur, ce qui améliore les performances. Exemple :

  • L'utilisation par hidl_memory pour chaque allocation de tampon coûte en moyenne 238 us/1. l'allocation de ressources.
  • Utiliser MemoryBlock et partager un seul hidl_memory coûte en moyenne 2,82 us/1. l'allocation de ressources.

Architecture

L'architecture HIDL MemoryBlock inclut des services HIDL avec plusieurs mémoires partagent un seul tas de mémoire:

MemoryBlock HIDL

Figure 1 : Architecture MemoryBlock HIDL

Utilisation normale

Cette section fournit un exemple d'utilisation de MemoryBlock en déclarant d'abord le puis implémenter le HAL.

Déclarer le HAL

Pour l'exemple IFoo HAL suivant:

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

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

Le Android.bp se présente comme suit:

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

Implémenter le HAL

Pour implémenter l'exemple HAL:

  1. Récupérez le hidl_memory (pour en savoir plus, consultez 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. Créez une instance HidlMemoryDealer avec le hidl_memory acquis:

    #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. Allouez MemoryBlock, qui est une structure définie avec HIDL.

    Exemple MemoryBlock:

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

    Exemple d'utilisation de MemoryDealer pour allouer 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. Annulez l'allocation de MemoryBlock:

    Return<void> Foo::giveBack(const MemoryBlock& block) {
        memory_dealer->deallocate(block.offset);
    ...
    
  5. Manipuler les données:

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

    shared_libs: [
            "android.hidl.memory@1.0",
    
            "android.hidl.memory.block@1.0"
    
            "android.hidl.memory.token@1.0",
            "libhidlbase",
            "libhidlmemory",
    
  7. Examinez la procédure pour déterminer si vous devez lockMemory.

    Normalement, MemoryBlock utilise le nombre de références pour gérer le bloc partagé hidl_memory, qui est mis en mmap() la première fois que l'une de ses 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` a été mappée tout au long du verrou. tout au long du cycle de vie. Exemple :

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

Utilisation étendue

Cette section fournit des informations sur l'utilisation étendue de MemoryBlock.

Utiliser le nombre de références pour gérer MemoryBlock

Dans la plupart des cas, le moyen le plus efficace d'utiliser MemoryBlock consiste à explicitement l'allocation et la désallocation. Toutefois, dans les applications complexes utilisant le nombre de références, pour la récupération de mémoire peut être une meilleure idée. Activer le nombre de références MemoryBlock, vous pouvez lier MemoryBlock à un objet de liaison, ce qui permet de compter les références et désallouer MemoryBlock lorsque le nombre diminue sur zéro.

Déclarer le HAL

Lorsque vous déclarez le HAL, décrivez une structure HIDL contenant un MemoryBlock et une instance iBase:

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

struct MemoryBlockAllocation {
    MemoryBlock block;
    IBase refcnt;
};

Utilisez MemoryBlockAllocation pour remplacer MemoryBlock et supprimer la méthode pour offrir MemoryBlock. Il est désaffecté par le comptage des références avec MemoryBlockAllocation. Exemple :

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

Implémenter le HAL

Exemple d'implémentation côté service du 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);

Exemple d'implémentation côté client du HAL:

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

Associer et récupérer des métadonnées

Certaines applis ont besoin de données supplémentaires pour être liées au MemoryBlock alloué. Vous pouvez ajouter et récupérer des métadonnées à l'aide de deux méthodes:

  • Si l'application accède aux métadonnées aussi souvent que le bloc lui-même, les métadonnées et les transmettre toutes dans un struct. Exemple :

    import android.hidl.memory.block@1.0::MemoryBlock;
    
    struct MemoryBlockWithMetaData{
        MemoryBlock block;
        MetaDataStruct metaData;
    };
    
  • Si l'application accède aux métadonnées beaucoup moins souvent que il est plus efficace de transmettre les métadonnées de manière passive de commande. Exemple :

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

    Ensuite, liez les métadonnées au MemoryBlock à l'aide de MemoryDealer. Exemple :

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