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 }));
با
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);
تخصیص
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); ...
Dealocate
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
مشترک استفاده می کند که اولین باری که یکی ازMemoryBlock
های آن نقشه برداری می شودmmap()
-ed است و زمانی که هیچ چیزی به آن اشاره نمی کند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(...);