HIDL MemoryBlock
は、hidl_memory
、HIDL
@1.0::IAllocator
、HIDL @1.0::IMapper
上に構築された抽象レイヤです。複数のメモリブロックが 1 つのメモリヒープを共有する HIDL サービス用に設計されています。
パフォーマンスの改善
アプリで MemoryBlock
を使用すると、mmap
/ munmap
とユーザー空間セグメンテーション違反の数を大幅に削減して、パフォーマンスを改善できます。次に例を示します。
- バッファ割り当てごとに
hidl_memory
を使用すると、平均して 238 us/1 割り当てになります。 MemoryBlock
を使用して 1 つのhidl_memory
を共有すると、平均して 2.82 us/1 割り当てになります。
アーキテクチャ
HIDL MemoryBlock
アーキテクチャには、複数のメモリブロックが 1 つのメモリヒープを共有する HIDL サービスが含まれています。
図 1: HIDL MemoryBlock アーキテクチャ
通常の使用方法
このセクションでは、最初に HAL を宣言し、次に HAL を実装して、MemoryBlock
を使用する例を示します。
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); ...
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 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` のいずれかがロックのライフサイクルを通じて初めてマッピングされたときにmmap()
されます。次に例を示します。#include <hidlmemory/mapping.h> sp<RefBase> lockMemory(const sp<IMemoryToken> key);
拡張された使用方法
このセクションでは、MemoryBlock
の拡張された使用方法の詳細について説明します。
参照カウントを使用した MemoryBlock の管理
ほとんどの場合、MemoryBlock
を使用する最も効率的な方法は、明示的に割り当てと割り当て解除を行うことです。しかし、複雑なアプリでは、ガベージ コレクションに参照カウントを使用したほうが良い場合があります。MemoryBlock
で参照カウントを使用するには、MemoryBlock
をバインダ オブジェクトにバインドします。これにより、参照数がカウントされ、カウントがゼロになると MemoryBlock
の割り当てが解除されます。
HAL の宣言
HAL を宣言する場合は、MemoryBlock
インスタンスと IBase を含む HIDL 構造体を記述します。
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
にバインドする追加のデータが必要です。メタデータは、次の 2 つの方法で追加または取得できます。
アプリがブロック自体と同じ頻度でメタデータにアクセスする場合は、メタデータを追加してすべて構造体に渡します。次に例を示します。
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(...);