Le HIDL MemoryBlock est une couche abstraite construite sur hidl_memory
, HIDL @1.0::IAllocator
et HIDL @1.0::IMapper
. Il est conçu pour les services HIDL disposant de plusieurs blocs de mémoire pour partager un seul tas de mémoire.
Amélioration des performances
L'utilisation de MemoryBlock dans les applications peut réduire considérablement le nombre de défauts de segmentation mmap
/ munmap
et de l'espace utilisateur, améliorant ainsi les performances. Par exemple:
- L'utilisation par
hidl_memory
pour chaque allocation de tampon équivaut en moyenne à 238 us/1 allocation. - L'utilisation
MemoryBlock
et le partage d'un seulhidl_memory
équivaut en moyenne à une allocation de 2,82 us/1.
Architecture
L'architecture HIDL MemoryBlock comprend des services HIDL avec plusieurs blocs de mémoire partageant un seul tas de mémoire :
Figure 1. Architecture HIDL MemoryBlock
Utilisation normale
Cette section fournit un exemple d'utilisation de MemoryBlock en déclarant d'abord le HAL, puis en implémentant le HAL.
Déclarer le HAL
Pour l'exemple suivant IFoo HAL :
import android.hidl.memory.block@1.0::MemoryBlock;
interface IFoo {
getSome() generates(MemoryBlock block);
giveBack(MemoryBlock block);
};
Le Android.bp
est le suivant :
hidl_interface {
...
srcs: [
"IFoo.hal",
],
interfaces: [
"android.hidl.memory.block@1.0",
...
};
Implémentation du HAL
Pour implémenter l'exemple HAL :
Obtenez le
hidl_memory
(pour plus de détails, reportez-vous à 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 }));
Créez un
HidlMemoryDealer
avec lehidl_memory
acquis :#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);
Allouez
MemoryBlock
, qui est une structure définie avec HIDL.Exemple
MemoryBlock
:struct MemoryBlock { IMemoryToken token; uint64_t size; uint64_t offset; };
Exemple utilisant le
MemoryDealer
pour allouer unMemoryBlock
:#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); ...
Désallouer
MemoryBlock
:Return<void> Foo::giveBack(const MemoryBlock& block) { memory_dealer->deallocate(block.offset); ...
Manipulez les données :
#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()));
Configuration
Android.bp
:shared_libs: [ "android.hidl.memory@1.0", "android.hidl.memory.block@1.0" "android.hidl.memory.token@1.0", "libhidlbase", "libhidlmemory",
Examinez le flux pour déterminer si vous devez
lockMemory
.Normalement, le MemoryBlock utilise le nombre de références pour conserver la
hidl_memory
partagée qui estmmap()
-ed la première fois qu'un de sesMemoryBlock
est mappé et estmunmap()
-ed lorsque rien n'y fait référence. Pour que lehidl_memory
toujours mappé, vous pouvez utiliserlockMemory
, un objet de style RAII qui conserve lehidl_memory
correspondant mappé tout au long du cycle de vie du verrou. Exemple:#include <hidlmemory/mapping.h> sp<RefBase> lockMemory(const sp<IMemoryToken> key);
Utilisation étendue
Cette section fournit des détails sur l'utilisation étendue de MemoryBlock
.
Utiliser le nombre de références pour gérer Memoryblock
Dans la plupart des situations, le moyen le plus efficace d’utiliser MemoryBlock consiste à allouer/désallouer explicitement. Cependant, dans les applications complexes, l'utilisation du nombre de références pour le garbage collection peut s'avérer une meilleure idée. Pour avoir un nombre de références sur MemoryBlock, vous pouvez lier MemoryBlock avec un objet binder, ce qui permet de compter les références et de libérer le MemoryBlock lorsque le nombre diminue jusqu'à zéro.
Déclarer le HAL
Lors de la déclaration du HAL, décrivez une structure HIDL qui contient un MemoryBlock et un IBase :
import android.hidl.memory.block@1.0::MemoryBlock;
struct MemoryBlockAllocation {
MemoryBlock block;
IBase refcnt;
};
Utilisez MemoryBlockAllocation
pour remplacer MemoryBlock
et supprimez la méthode pour restituer le MemoryBlock
. Il sera libéré par comptage de références avec MemoryBlockAllocation
. Exemple:
interface IFoo {
allocateSome() generates(MemoryBlockAllocation allocation);
};
Implémentation du HAL
Exemple de mise en œuvre côté service de 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);
Exemple d'implémentation côté client du HAL :
ifoo->allocateSome([&](const MemoryBlockAllocation& allocation){
...
);
Attacher/récupérer des métadonnées
Certaines applications ont besoin de données supplémentaires pour se lier au MemoryBlock
alloué. Vous pouvez ajouter/récupérer des métadonnées à l'aide de deux méthodes :
Si l'application accède aux métadonnées aussi souvent que le bloc lui-même, ajoutez les métadonnées et transmettez-les toutes dans une structure. Exemple:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; MetaDataStruct metaData; };
Si l'application accède aux métadonnées beaucoup moins fréquemment que le bloc, il est plus efficace de transmettre passivement les métadonnées avec une interface. Exemple:
import android.hidl.memory.block@1.0::MemoryBlock; struct MemoryBlockWithMetaData{ MemoryBlock block; IMetaData metaData; };
Ensuite, liez les métadonnées avec le MemoryBlock à l’aide du Memory Dealer. Exemple:
MemoryBlockWithMetaData memory_block; memory_block.block = dealer->allocate(size); if(HidlMemoryDealer::isOk(block)){ memory_block.metaData = new MetaData(...);