قفل الذاكرة HIDL

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

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

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

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

هندسة معمارية

تتضمّن بنية 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()-ها في المرة الأولى التي تم فيها ربط أحد 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` على مدار دورة حياة قفل. مثال:

    #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(...);