HIDL MemoryBlock

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

بهبود عملکرد

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

  • استفاده از per hidl_memory برای هر تخصیص بافر، به طور متوسط ​​​​۲۳۸ us/1 تخصیص می‌دهد.
  • استفاده از MemoryBlock و اشتراک‌گذاری یک hidl_memory به طور میانگین ۲.۸۲ us/1 تخصیص می‌دهد.

معماری

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

بلوک حافظه HIDL

شکل 1. معماری بلوک حافظه HIDL

استفاده عادی

این بخش مثالی از استفاده از MemoryBlock را ارائه می‌دهد که در آن ابتدا 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

برای پیاده‌سازی مثال 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-alloca&te(2048, [](bool success, const h&idl_memory mem)
      {
            if (!success) { /* error */ }
            // you can now use the hidl_memory object 'mem' or pass it
      }));
    
  2. یک نمونه HidlMemoryDealer با hidl_memory اکتسابی ایجاد کنید:

    #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 is آن، mmap() -ed و -ed when nothing refers to it. To keep hidl_memory always mapped, you can use lockMemory , a RAII style object that keeps the corresponding استفاده کنید. مثال:

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

استفاده گسترده

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

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

در بیشتر مواقع، کارآمدترین روش برای استفاده MemoryBlock تخصیص/حذف صریح منابع است. با این حال، در برنامه‌های پیچیده، استفاده از تعداد مرجع برای جمع‌آوری زباله ممکن است ایده بهتری باشد. برای داشتن تعداد مرجع در MemoryBlock ، می‌توانید MemoryBlock با یک شیء binder متصل کنید، که به شمارش منابع و آزادسازی 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

مثالی از پیاده‌سازی سمت سرویس 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 اختصاص داده شده به داده‌های اضافی نیاز دارند. می‌توانید با استفاده از دو روش، متادیتا را اضافه و بازیابی کنید:

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

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

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

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