إن 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 مع كتل ذاكرة متعددة تتشارك في كومة ذاكرة واحدة:
الشكل 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:
احصل على
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 }));
أنشئ
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);
تخصيص
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); ...
إلغاء تخصيص
MemoryBlock
:Return<void> Foo::giveBack(const MemoryBlock& block) { memory_dealer->deallocate(block.offset); ...
التعامل مع البيانات:
#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()));
تكوين
Android.bp
:shared_libs: [ "android.hidl.memory@1.0", "android.hidl.memory.block@1.0" "android.hidl.memory.token@1.0", "libhidlbase", "libhidlmemory",
قم بمراجعة التدفق لتحديد ما إذا كنت بحاجة إلى
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(...);