HIDL MemoryBlock

MemoryBlock في HIDL هي طبقة مجرّدة تستند إلى hidl_memory وHIDL @1.0::IAllocator وHIDL @1.0::IMapper. وهي مصمَّمة لخدمات HIDL التي تتضمّن عدة وحدات ذاكرة لمشاركة مجموعة ذاكرة واحدة.

أضفنا تحسينات على الأداء

يمكن أن يؤدي استخدام MemoryBlock في التطبيقات إلى تقليل عدد أخطاء تقسيم مساحة المستخدمين mmap/munmap بشكل كبير، ما يؤدي إلى تحسين الأداء. مثلاً:

  • يبلغ متوسط استخدام hidl_memory لكل عملية تخصيص لذاكرة التخزين المؤقت 238 ميكروثانية/عملية تخصيص واحدة.
  • يبلغ متوسط استخدام MemoryBlock ومشاركة hidl_memory واحدة 2.82 ميكروثانية/1 عملية تخصيص.

البنية

يتضمّن تصميم HIDL MemoryBlock خدمات HIDL مع عدة وحدات ذاكرة تشترك في مساحة تخزين واحدة للذاكرة:

HIDL MemoryBlock

الشكل 1. بنية MemoryBlock في HIDL

الاستخدام العادي

يقدّم هذا القسم مثالاً على استخدام 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. أنشئ مثيلاً من 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 المشترَكة التي يتم mmap()ها في المرة الأولى التي يتم فيها ربط أحد MemoryBlock instances is mapped and isunmap()-ed when nothing refers to it. To keephidl_memoryalways mapped, you can uselockMemory, a RAII style object that keeps the correspondinghidl_memory خلال دورة حياة القفل. مثال:

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

    بعد ذلك، اربط البيانات الوصفية بعنصر MemoryBlock باستخدام MemoryDealer. مثال:

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