HIDL MemoryBlock

‫HIDL MemoryBlock لایه انتزاعی است که روی hidl_memory،‏ HIDL @1.0::IAllocator، و HIDL @1.0::IMapper ساخته شده است. این ویژگی برای سرویس‌های HIDL طراحی شده است که چندین بلوک حافظه دارند تا یک پشته حافظه را هم‌رسانی کنند.

بهبود عملکرد

استفاده از MemoryBlock در برنامه‌ها می‌تواند تعداد خطاهای mmap/munmap و خطاهای تقسیم‌بندی فضای کاربر را به‌طور قابل‌توجهی کاهش دهد و درنتیجه عملکرد را بهبود بخشد. برای مثال:

  • Using per hidl_memory for each buffer allocation averages 238 us/1 allocation.
  • Using MemoryBlock and sharing a single hidl_memory averages 2.82 us/1 allocation.

معماری

معماری HIDL MemoryBlock شامل سرویس‌های HIDL با چندین بلوک حافظه است که یک توده حافظه واحد را به اشتراک می‌گذارند:

HIDL MemoryBlock

شکل ۱. معماری HIDL MemoryBlock

مصرف عادی

این بخش نمونه‌ای از استفاده از MemoryBlock را با ابتدا اعلام HAL و سپس پیاده‌سازی HAL ارائه می‌دهد.

اعلام کردن HAL

برای مثال زیر IFoo HAL:

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

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

Android.bp به‌صورت زیر است:

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

پیاده‌سازی لایه انتزاع سخت‌افزار

برای پیاده‌سازی HAL نمونه:

  1. hidl_memory را دریافت کنید (برای جزئیات، به 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. با hidl_memory خریداری‌شده، نمونه HidlMemoryDealer بسازید:

    #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. ‫MemoryBlock را اختصاص دهید که ساختاری است که با HIDL تعریف شده است.

    مثال MemoryBlock:

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

    مثال استفاده از MemoryDealer برای تخصیص 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. لغو تخصیص MemoryBlock:

    Return<void> Foo::giveBack(const MemoryBlock& block) {
        memory_dealer->deallocate(block.offset);
    ...
    
  5. برزش داده‌ها:

    #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:

    shared_libs: [
            "android.hidl.memory@1.0",
    
            "android.hidl.memory.block@1.0"
    
            "android.hidl.memory.token@1.0",
            "libhidlbase",
            "libhidlmemory",
    
  7. جریان را مرور کنید تا تعیین کنید که آیا باید lockMemory.

    به‌طور معمول، MemoryBlock از شمارش مرجع برای حفظ hidl_memory هم‌رسانی‌شده استفاده می‌کند که اولین‌بار یکی از 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 در سراسر چرخه حیات قفل mmap()نگاشت می‌شود. مثال:

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

استفاده طولانی‌مدت

این بخش جزئیاتی درباره استفاده گسترده از MemoryBlock ارائه می‌دهد.

استفاده از شمارش مرجع برای مدیریت MemoryBlock

در اکثر موارد، کارآمدترین روش برای استفاده از MemoryBlock این است که به‌طور صریح تخصیص/تخصیص‌زدایی کنید. اما در برنامه‌های پیچیده، استفاده از شمارش ارجاع برای زباله‌روبی ممکن است ایده بهتری باشد. برای داشتن تعداد مرجع در MemoryBlock، می‌توانید MemoryBlock را با یک شیء پیونددهنده پیوند دهید که به شمارش مراجع و تخصیص‌زدایی MemoryBlock وقتی تعداد به صفر کاهش می‌یابد کمک می‌کند.

اعلام کردن HAL

هنگام اعلام HAL، ساختار HIDL را که حاوی MemoryBlock نمونه و IBase است توصیف کنید:

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

struct MemoryBlockAllocation {
    MemoryBlock block;
    IBase refcnt;
};

از MemoryBlockAllocation برای جایگزین کردن MemoryBlock استفاده کنید و روش را بردارید تا MemoryBlock را پس دهید. با شمارش مرجع با MemoryBlockAllocation از تخصیص خارج می‌شود. مثال:

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

پیاده‌سازی لایه انتزاع سخت‌افزار

نمونه‌ای از پیاده‌سازی سمت سرویس 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);

نمونه‌ای از پیاده‌سازی سمت کارخواه HAL:

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

پیوست و بازیابی فراداده

برخی‌از برنامه‌ها برای اتصال به MemoryBlock اختصاص‌داده‌شده به داده‌های بیشتری نیاز دارند. می‌توانید بااستفاده از دو روش فراداده را پیوست و بازیابی کنید:

  • اگر برنامه به همان اندازه که به خود بلوک دسترسی دارد به فراداده نیز دسترسی دارد، فراداده را اضافه کنید و همه آن‌ها را در یک ساختار ارسال کنید. مثال:

    import android.hidl.memory.block@1.0::MemoryBlock;
    
    struct MemoryBlockWithMetaData{
        MemoryBlock block;
        MetaDataStruct metaData;
    };
    
  • اگر برنامه خیلی کمتر از بلوک به فراداده دسترسی پیدا می‌کند، کارآمدتر است که فراداده را به‌صورت غیرفعال با یک میانای عبور دهید. مثال:

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

    سپس، فراداده را با MemoryBlock بااستفاده از MemoryDealer پیوند دهید. مثال:

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