HIDL MemoryBlock

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

بهبود عملکرد

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

  • استفاده از هر hidl_memory برای هر تخصیص بافر به طور متوسط ​​238 us/1 تخصیص است.
  • استفاده از MemoryBlock و به اشتراک گذاری یک hidl_memory به طور میانگین 2.82 us/1 تخصیص دارد.

معماری

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

HIDL MemoryBlock

شکل 1. معماری 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 را اجرا کنید

برای پیاده سازی مثال 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. Dealocate 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 آن نگاشت می‌شود mmap() -ed MemoryBlock instances is mapped and is -ed when nothing refers to it. To keep hidl_memory always mapped, you can use , a RAII style object that keeps the corresponding . مثال:

    #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 را اجرا کنید

نمونه ای از اجرای سمت سرویس 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;
    };
    

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

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