android binder 共享内存,Binder之 IMemory理解02 binder上如何实现高效的内存共享

IMemory,IMemoryHeap都是在binder上使用的,用于进程间内存共享的操作,用于在binder上传输大内存块的操作。因为parcel提供的共享内存块大小有限,并来回地复制,效率太低。故引入这两个接口来高效实现内存共享(传输)

1.IMemory public IInterface

表示一个内存块,并提供了访问这些内存块的基本操作,如pointer() size() 等

android里IMemory的实现并不实际分配内存,内存都是由IMemoryHeap的实现类来分配的。IMemory的实际内存指向了IMemoryHeap的实现类。IMemory可以看成是一个对IMemoryHeap的adapter模式,让IMemoryHeap更容易用。

2.IMemoryHeap public IInterface

表示一个内存块,一般来说其实现类为

MemoryHeapBase 表示的是 Ashmem

的一个包装实现。Ashmem是android一个驱动,主要用于进程间的内存共享

而设计,它可以记录内存和进程间的引用次数,但分配的内存在物理上不是连续的

MemoryHeapPmem 对pmem驱动的一个包装实现,pmem是android的一个驱动,提供连接物理内存的进程间共享操

作,它和MemoryHeapBase最大的区别在于分配的内存是连接的,这个用于dma会方面些。

3. 如何在进程间共享内存?

具体实现在

BpMemoryHeap,BnMemoryHeap上.

其中BpMemoryHeap 是客户端(proxy class)的使用,

BnMemoryHeap 是服务端的使用

BpMemoryHeap

可参考IMemory.cpp的实现,特别是对BpMemoryHeap的实现上

3.1

BnMemoryHeap 提供 HEAP_ID ,这个功能把 在BnMemoryHeap上打开的 Ashmem或者pmem的

设备fd 通过binder的writeFileDescriptor写给客户端

代码如下:

status_t BnMemoryHeap::onTransact(

uint32_t code, const Parcel& data, Parcel* reply,

uint32_t flags)

{

switch(code)

{

case HEAP_ID: {

CHECK_INTERFACE(IMemoryHeap, data, reply);

reply->writeFileDescriptor(getHeapID()); //将pmem,或者ashmem的fd写给客户端

reply->writeInt32(getSize());

reply->writeInt32(getFlags());

return NO_ERROR;

} break;

default:

return BBinder::onTransact(code, data, reply, flags);

}

}

3.2 BpMemoryHeap 的实现中,会对从BnMemoryHeap

传回来的id做处理,dup(remotefd)用mmap再次打开,以实现真正的进程间内存共享

void* BpMemoryHeap::getBase() const {

assertMapped(); //处理进程间的内存map

return

mBase;

}

void BpMemoryHeap::assertMapped() const

{

if (mHeapId

== -1) {

sp

binder(const_cast(this)->asBinder());

sp

heap(static_cast(find_heap(binder).get()));

heap->assertReallyMapped(); //调用

if (heap->mBase != MAP_FAILED) {

Mutex::Autolock _l(mLock);

if (mHeapId == -1) {

mBase =

heap->mBase;

mSize =

heap->mSize;

android_atomic_write( dup( heap->mHeapId ),

&mHeapId );

}

} else {

// something went wrong

free_heap(binder);

}

}

}

void BpMemoryHeap::assertReallyMapped() const

{

if (mHeapId

== -1) {

// remote call without mLock held, worse case scenario, we end

up

// calling transact() from multiple threads, but that's not a

problem,

// only mmap below must be in the critical section.

Parcel data, reply;

data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());

status_t err = remote()->transact(HEAP_ID, data,

&reply);

int parcel_fd =

reply.readFileDescriptor();//从binder里取回BnMemoryHeap写回的fd

ssize_t size = reply.readInt32();

uint32_t flags = reply.readInt32();

LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%ld, err=%d

(%s)",

asBinder().get(), parcel_fd, size, err, strerror(-err));

int fd = dup( parcel_fd );//dup一个,为什么这么做?parcel类里有注解

LOGE_IF(fd==-1, "cannot dup fd=%d, size=%ld, err=%d (%s)",

parcel_fd, size, err, strerror(errno));

int access = PROT_READ;

if (!(flags & READ_ONLY)) {

access |= PROT_WRITE;

}

Mutex::Autolock _l(mLock);

if (mHeapId == -1) {

mRealHeap = true;

mBase = mmap(0, size, access, MAP_SHARED, fd,

0);//真的做mmap了,终于实现了内存共享

if (mBase == MAP_FAILED) {

LOGE("cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d

(%s)",

asBinder().get(), size, fd, strerror(errno));

close(fd);

} else {

mSize = size;

mFlags = flags;

android_atomic_write(fd, &mHeapId);

}

}

}

}

看来android上对内存共享上效率的考虑还是做的很充分的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值