كتلة ذاكرة HIDL

إن 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. أنشئ 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() -ed في المرة الأولى التي يتم فيها تعيين إحدى وحدات MemoryBlock الخاصة به ويكون munmap() -ed عندما لا يشير أي شيء إليه. للحفاظ على تعيين hidl_memory دائمًا، يمكنك استخدام lockMemory ، وهو كائن نمط RAII يحافظ على تعيين hidl_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 باستخدام Memory Dealer. مثال:

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