MemoryBlock
HIDL là một lớp trừu tượng được xây dựng trên hidl_memory
, HIDL
@1.0::IAllocator
và HIDL @1.0::IMapper
. Lớp này được thiết kế cho các dịch vụ HIDL có nhiều khối bộ nhớ để chia sẻ một vùng nhớ khối xếp.
Cải thiện hiệu suất
Việc sử dụng MemoryBlock
trong ứng dụng có thể làm giảm đáng kể số lượng lỗi phân đoạn mmap
/munmap
và không gian người dùng, nhờ đó cải thiện hiệu suất.
Ví dụ:
- Việc sử dụng mỗi
hidl_memory
cho mỗi lượt phân bổ bộ đệm trung bình là 238 us/1 lượt phân bổ. - Việc sử dụng
MemoryBlock
và chia sẻ mộthidl_memory
trung bình là 2,82 us/1 lượt phân bổ.
Kiến trúc
Cấu trúc MemoryBlock
HIDL bao gồm các dịch vụ HIDL có nhiều khối bộ nhớ chia sẻ một vùng nhớ khối xếp:
Hình 1. Cấu trúc HIDL MemoryBlock
Mức sử dụng thông thường
Phần này đưa ra một ví dụ về cách sử dụng MemoryBlock
bằng cách khai báo HAL trước, sau đó triển khai HAL.
Khai báo HAL
Đối với ví dụ sau đây về IFoo HAL:
import android.hidl.memory.block@1.0::MemoryBlock;
interface IFoo {
getSome() generates(MemoryBlock block);
giveBack(MemoryBlock block);
};
Android.bp
như sau:
hidl_interface {
...
srcs: [
"IFoo.hal",
],
interfaces: [
"android.hidl.memory.block@1.0",
...
};
Triển khai HAL
Cách triển khai HAL mẫu:
Tải
hidl_memory
(để biết thông tin chi tiết, hãy tham khảo 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 }));
Tạo một thực thể
HidlMemoryDealer
bằnghidl_memory
đã thu nạp:#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);
Phân bổ
MemoryBlock
(một cấu trúc được xác định bằng HIDL).Ví dụ
MemoryBlock
:struct MemoryBlock { IMemoryToken token; uint64_t size; uint64_t offset; };
Ví dụ về cách sử dụng
MemoryDealer
để phân bổ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); ...
Giải phóng
MemoryBlock
:Return<void> Foo::giveBack(const MemoryBlock& block) { memory_dealer->deallocate(block.offset); ...
Thao tác với dữ liệu:
#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()));
Cấu hình
Android.bp
:shared_libs: [ "android.hidl.memory@1.0", "android.hidl.memory.block@1.0" "android.hidl.memory.token@1.0", "libhidlbase", "libhidlmemory",
Xem lại quy trình để xác định xem bạn có cần
lockMemory
hay không.Thông thường,
MemoryBlock
sử dụng số lượt tham chiếu để duy trìhidl_memory
dùng chung đượcmmap()
trong lần đầu tiên một trong cácMemoryBlock instances is mapped and is
munmap()-ed when nothing refers to it. To keep
hidl_memoryalways mapped, you can use
lockMemory, a RAII style object that keeps the corresponding
hidl_memory` được ánh xạ trong suốt vòng đời khoá. Ví dụ:#include <hidlmemory/mapping.h> sp<RefBase> lockMemory(const sp<IMemoryToken> key);
Mở rộng phạm vi sử dụng
Phần này cung cấp thông tin chi tiết về việc sử dụng mở rộng MemoryBlock
.
Sử dụng số lượt tham chiếu để quản lý MemoryBlock
Trong hầu hết các trường hợp, cách hiệu quả nhất để sử dụng MemoryBlock
là phân bổ/giải phóng một cách rõ ràng. Tuy nhiên, trong các ứng dụng phức tạp, bạn nên sử dụng số lượt tham chiếu để thu gom rác. Để có số lượt tham chiếu trên MemoryBlock
, bạn có thể liên kết MemoryBlock
với một đối tượng liên kết. Điều này giúp đếm các lượt tham chiếu và giải phóng MemoryBlock
khi số lượt tham chiếu giảm xuống còn 0.
Khai báo HAL
Khi khai báo HAL, hãy mô tả một cấu trúc HIDL chứa một thực thể MemoryBlock
và một IBase:
import android.hidl.memory.block@1.0::MemoryBlock;
struct MemoryBlockAllocation {
MemoryBlock block;
IBase refcnt;
};
Sử dụng MemoryBlockAllocation
để thay thế MemoryBlock
và xoá phương thức để trả lại MemoryBlock
. Vùng nhớ này được giải phóng bằng cách đếm tham chiếu bằng MemoryBlockAllocation
. Ví dụ:
interface IFoo {
allocateSome() generates(MemoryBlockAllocation allocation);
};
Triển khai HAL
Ví dụ về cách triển khai HAL phía dịch vụ:
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);
Ví dụ về cách triển khai HAL phía máy khách:
ifoo->allocateSome([&](const MemoryBlockAllocation& allocation){
...
);
Đính kèm và truy xuất siêu dữ liệu
Một số ứng dụng cần thêm dữ liệu để liên kết với MemoryBlock
được phân bổ.
Bạn có thể nối và truy xuất siêu dữ liệu bằng hai phương thức:
Nếu ứng dụng truy cập siêu dữ liệu thường xuyên như chính khối đó, hãy thêm siêu dữ liệu và truyền tất cả siêu dữ liệu đó trong một cấu trúc. Ví dụ:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; MetaDataStruct metaData; };
Nếu ứng dụng truy cập vào siêu dữ liệu ít thường xuyên hơn nhiều so với khối, thì việc truyền siêu dữ liệu một cách thụ động bằng giao diện sẽ hiệu quả hơn. Ví dụ:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; IMetaData metaData; };
Tiếp theo, hãy liên kết siêu dữ liệu với
MemoryBlock
bằngMemoryDealer
. Ví dụ:MemoryBlockWithMetaData memory_block; memory_block.block = dealer->allocate(size); if(HidlMemoryDealer::isOk(block)){ memory_block.metaData = new MetaData(...);