HIDL Bellek Bloğu

HIDL MemoryBlock, hidl_memory , HIDL @1.0::IAllocator ve HIDL @1.0::IMapper üzerine kurulu soyut bir katmandır. Tek bir bellek yığınını paylaşmak için birden fazla bellek bloğuna sahip HIDL hizmetleri için tasarlanmıştır.

Performans geliştirmeleri

MemoryBlock'un uygulamalarda kullanılması, mmap / munmap ve kullanıcı alanı bölümleme hatalarının sayısını önemli ölçüde azaltabilir, böylece performansı artırabilir. Örneğin:

  • Her arabellek tahsisi için hidl_memory başına kullanım ortalama 238 us/1 tahsis anlamına gelir.
  • MemoryBlock kullanmak ve tek bir hidl_memory paylaşmak ortalama 2,82 us/1 tahsis anlamına gelir.

Mimari

HIDL MemoryBlock mimarisi, tek bir bellek yığınını paylaşan birden fazla bellek bloğuna sahip HIDL hizmetlerini içerir:

HIDL Bellek Bloğu

Şekil 1. HIDL MemoryBlock mimarisi

Normal kullanım

Bu bölümde, önce HAL'in bildirilmesi ve ardından HAL'in uygulanması yoluyla MemoryBlock'un kullanılmasına ilişkin bir örnek verilmektedir.

HAL'ın bildirilmesi

Aşağıdaki örnek için IFoo HAL:

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

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

Android.bp aşağıdaki gibidir:

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

HAL'in uygulanması

HAL örneğini uygulamak için:

  1. hidl_memory alın (ayrıntılar için HIDL C++' a bakın).

    #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. Edinilen hidl_memory ile bir HidlMemoryDealer oluşturun:

    #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. HIDL ile tanımlanan bir yapı olan MemoryBlock ayırın.

    Örnek MemoryBlock :

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

    MemoryBlock tahsis etmek için MemoryDealer kullanıldığı örnek:

    #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. MemoryBlock yerini serbest bırakın:

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

    #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. Android.bp yapılandırın:

    shared_libs: [
            "android.hidl.memory@1.0",
    
            "android.hidl.memory.block@1.0"
    
            "android.hidl.memory.token@1.0",
            "libhidlbase",
            "libhidlmemory",
    
  7. lockMemory gerekip gerekmediğini belirlemek için akışı inceleyin.

    Normalde MemoryBlock, paylaşılan hidl_memory korumak için referans sayısını kullanır; bu, MemoryBlock biri ilk kez eşlendiğinde mmap() -ed olur ve hiçbir şey ona gönderme yapmadığında munmap() -ed olur. hidl_memory her zaman eşlenmiş halde kalmasını sağlamak için, karşılık gelen hidl_memory kilit yaşam döngüsü boyunca eşlenmiş halde tutan RAII tarzı bir nesne olan lockMemory kullanabilirsiniz. Örnek:

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

Genişletilmiş kullanım

Bu bölümde MemoryBlock genişletilmiş kullanımına ilişkin ayrıntılar verilmektedir.

Memoryblock'u yönetmek için referans sayısını kullanma

Çoğu durumda, MemoryBlock'u kullanmanın en etkili yolu açıkça tahsis etmek/tahsiyi kaldırmaktır. Ancak karmaşık uygulamalarda çöp toplama için referans sayısını kullanmak daha iyi bir fikir olabilir. MemoryBlock'ta referans sayımına sahip olmak için, MemoryBlock'u bir ciltleyici nesneyle bağlayabilirsiniz; bu, referansların sayılmasına ve sayı sıfıra düştüğünde MemoryBlock'un yerinin belirlenmesine yardımcı olur.

HAL'ın bildirilmesi

HAL'ı bildirirken MemoryBlock ve IBase içeren bir HIDL yapısını tanımlayın:

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

struct MemoryBlockAllocation {
    MemoryBlock block;
    IBase refcnt;
};

MemoryBlock değiştirmek için MemoryBlockAllocation kullanın ve MemoryBlock geri verme yöntemini kaldırın. MemoryBlockAllocation ile referans sayımı yoluyla serbest bırakılacaktır. Örnek:

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

HAL'in uygulanması

HAL'in hizmet tarafı uygulamasına örnek:

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);

HAL'in istemci tarafında uygulanmasına örnek:

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

Meta verileri ekleme/alma

Bazı uygulamalar, tahsis edilen MemoryBlock bağlanmak için ek verilere ihtiyaç duyar. İki yöntemi kullanarak meta verileri ekleyebilir/alabilirsiniz:

  • Uygulama meta verilere bloğun kendisi kadar sık ​​erişiyorsa, meta verileri ekleyin ve hepsini bir yapıya iletin. Örnek:

    import android.hidl.memory.block@1.0::MemoryBlock;
    
    struct MemoryBlockWithMetaData{
        MemoryBlock block;
        MetaDataStruct metaData;
    };
    
  • Uygulama meta verilere bloktan çok daha az sıklıkta erişiyorsa meta verileri bir arayüzle pasif olarak aktarmak daha verimli olur. Örnek:

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

    Daha sonra, Memory Dealer'ı kullanarak meta verileri MemoryBlock'a bağlayın. Örnek:

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