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()
-edMemoryBlock instances is mapped and is
-ed when nothing refers to it. To keep
hidl_memoryalways mapped, you can use
, a RAII style object that keeps the corresponding
. مثال:#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; };
سپس، با استفاده از
MemoryDealer
، متادیتا را باMemoryBlock
پیوند دهید. مثال:MemoryBlockWithMetaData memory_block; memory_block.block = dealer->allocate(size); if(HidlMemoryDealer::isOk(block)){ memory_block.metaData = new MetaData(...);