Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析(3)

简介:
  回到前面BpMemoryHeap类中的assertMapped函数中,如果本BpMemoryHeap对象中的mHeapID等于-1,那么就说明这个BpMemoryHeap对象中的匿名共享内存还没准备就绪,因此,需要执行一次映射匿名共享内存的操作。
        在执行映射操作之作,先要看看在本进程中是否有其它映射到同一个MemoryHeapBase对象的BpMemoryHeap对象存在:
  1. sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder());  
  2. sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));  
       这里的find_heap函数是BpMemoryHeap的成员函数,最终它调用了前面提到的全局变量gHeapCache来直正执行查找的操作:
  1. class BpMemoryHeap : public BpInterface<IMemoryHeap>  
  2. {     
  3. ......  
  4.   
  5. private:  
  6.     static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {  
  7.         return gHeapCache->find_heap(binder);  
  8.     }  
  9.   
  10.     ......  
  11. }  
        注意,这里通过find_heap函数得到BpMemoryHeap对象可能是和正在执行assertMapped函数中的BpMemoryHeap对象一样,也可能不一样,但是这没有关系,这两种情况的处理方式都是一样的,都是通过调用这个通过find_heap函数得到BpMemoryHeap对象的assertReallyMapped函数来进一步确认它内部的匿名共享内存是否已经映射到进程空间了:
  1. void BpMemoryHeap::assertReallyMapped() const  
  2. {  
  3.     if (mHeapId == -1) {  
  4.   
  5.         // remote call without mLock held, worse case scenario, we end up  
  6.         // calling transact() from multiple threads, but that's not a problem,  
  7.         // only mmap below must be in the critical section.  
  8.   
  9.         Parcel data, reply;  
  10.         data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());  
  11.         status_t err = remote()->transact(HEAP_ID, data, &reply);  
  12.         int parcel_fd = reply.readFileDescriptor();  
  13.         ssize_t size = reply.readInt32();  
  14.         uint32_t flags = reply.readInt32();  
  15.   
  16.         LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%ld, err=%d (%s)",  
  17.             asBinder().get(), parcel_fd, size, err, strerror(-err));  
  18.   
  19.         int fd = dup( parcel_fd );  
  20.         LOGE_IF(fd==-1, "cannot dup fd=%d, size=%ld, err=%d (%s)",  
  21.             parcel_fd, size, err, strerror(errno));  
  22.   
  23.         int access = PROT_READ;  
  24.         if (!(flags & READ_ONLY)) {  
  25.             access |= PROT_WRITE;  
  26.         }  
  27.   
  28.         Mutex::Autolock _l(mLock);  
  29.         if (mHeapId == -1) {  
  30.             mRealHeap = true;  
  31.             mBase = mmap(0, size, access, MAP_SHARED, fd, 0);  
  32.             if (mBase == MAP_FAILED) {  
  33.                 LOGE("cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d (%s)",  
  34.                     asBinder().get(), size, fd, strerror(errno));  
  35.                 close(fd);  
  36.             } else {  
  37.                 mSize = size;  
  38.                 mFlags = flags;  
  39.                 android_atomic_write(fd, &mHeapId);  
  40.             }  
  41.         }  
  42.     }  
  43. }  
        如果成员变量mHeapId的值为-1,就说明还没有把在Server端的MemoryHeapBase对象中的匿名共享内存映射到本进程空间来,于是,就通过一个Binder进程间调用把Server端的MemoryHeapBase对象中的匿名共享内存对象信息取回来:
  1. Parcel data, reply;  
  2. data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());  
  3. status_t err = remote()->transact(HEAP_ID, data, &reply);  
  4. int parcel_fd = reply.readFileDescriptor();  
  5. ssize_t size = reply.readInt32();  
  6. uint32_t flags = reply.readInt32();  
  7.   
  8. ......  
  9.   
  10. int fd = dup( parcel_fd );  
  11.           
  12. ......  
        取回来的信息包括MemoryHeapBase对象中的匿名共享内存在本进程中的文件描述符fd、大小size以及访问属性flags。如何把MemoryHeapBase对象中的匿名共享内存作为本进程的一个打开文件描述符,请参考前面一篇文章 Android系统匿名共享内存Ashmem(Anonymous Shared Memory)在进程间共享的原理分析 。有了这个文件描述符fd后,就可以对它进行内存映射操作了:
  1. Mutex::Autolock _l(mLock);  
  2. if (mHeapId == -1) {  
  3.     mRealHeap = true;  
  4.     mBase = mmap(0, size, access, MAP_SHARED, fd, 0);  
  5.     if (mBase == MAP_FAILED) {  
  6.         LOGE("cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d (%s)",  
  7.             asBinder().get(), size, fd, strerror(errno));  
  8.         close(fd);  
  9.     } else {  
  10.         mSize = size;  
  11.         mFlags = flags;  
  12.         android_atomic_write(fd, &mHeapId);  
  13.     }  
  14. }  
        前面已经判断过mHeapId是否为-1了,这里为什么又要重新判断一次呢?这里因为,在上面执行Binder进程间调用的过程中,很有可能也有其它的线程也对这个BpMemoryHeap对象执行匿名共享内存映射的操作,因此,这里还要重新判断一下mHeapId的值是否为-1,如果是的话,就要执行匿名共享内存映射的操作了,这是通过调用mmap函数来进行的,这个函数我们前面在分析MemoryHeapBase类的实现时已经见过了。
 
        从assertReallyMapped函数返回到assertMapped函数中:
  1. if (heap->mBase != MAP_FAILED) {  
  2.     Mutex::Autolock _l(mLock);  
  3.     if (mHeapId == -1) {  
  4.         mBase   = heap->mBase;  
  5.         mSize   = heap->mSize;  
  6.         android_atomic_write( dup( heap->mHeapId ), &mHeapId );  
  7.     }  
  8. else {  
  9.     // something went wrong  
  10.     free_heap(binder);  
  11. }  
        如果heap->mBase的值不为MAP_FAILED,就说明这个heap对象中的匿名共享内存已经映射好了。进入到里面的if语句,如果本BpMemoryHeap对象中的mHeap成员变量的值不等待-1,就说明前面通过find_heap函数得到的BpMemoryHeap对象和正在执行assertMapped函数的BpMemoryHeap对象是同一个对象了,因此,什么也不用做就可以返回了,否则的话,就要初始化一下本BpMemoryHeap对象的相关成员变量了:
  1. mBase   = heap->mBase;  
  2. mSize   = heap->mSize;  
  3. android_atomic_write( dup( heap->mHeapId ), &mHeapId );  
        注意,由于这块匿名共享内存已经在本进程中映射好了,因此,这里不需要再执行一次mmap操作,只需要把heap对象的相应成员变量的值拷贝过来就行了,不过对于文件描述符,需要通过dup函数来复制一个。
 
        这样,BpMemoryHeap对象中的匿名共享内存就准备就绪了,可以通过使用的它mBase成员变量来直接访问这块匿名共享内存。
        至此,MemoryHeapBase类的实现就分析完了,下面我们继续分析MemoryBase类的实现。




本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966904,如需转载请自行联系原作者
目录
相关文章
|
19天前
|
算法 程序员
深入理解操作系统内存管理:分页系统的优势与挑战
【4月更文挑战第7天】 在现代操作系统中,内存管理是一项至关重要的任务,它确保了计算机能够高效、安全地运行各种程序。分页系统作为内存管理的一种技术,通过将物理内存分割成固定大小的单元——页面,为每个运行的程序提供了一种独立且连续的内存地址空间。该技术不仅简化了内存分配,还允许更高效的内存使用和保护。本文探讨了分页系统的核心原理,优势以及面临的挑战,旨在为读者揭示其在操作系统设计中的重要性。
|
15天前
|
存储 算法 Linux
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
39 6
|
1月前
|
算法 安全 大数据
【C/C++ 随机函数行为】深入探索C++中的随机数:std::random_device与rand的行为分析(二)
【C/C++ 随机函数行为】深入探索C++中的随机数:std::random_device与rand的行为分析
48 0
|
3天前
|
存储 人工智能 程序员
【重学C++】【内存】关于C++内存分区,你可能忽视的那些细节
【重学C++】【内存】关于C++内存分区,你可能忽视的那些细节
33 1
|
19天前
|
Prometheus 监控 Cloud Native
【Linux】查看系统内存命令(详细讲解)
【Linux】查看系统内存命令(详细讲解)
|
1月前
|
存储 缓存 监控
Linux 系统 内存通用指标以及查询方式
Linux 系统 内存通用指标以及查询方式
18 0
|
1月前
|
算法 Java C++
【C/C++ 内存知识扩展】内存不足的可能性分析
【C/C++ 内存知识扩展】内存不足的可能性分析
12 0
|
1月前
|
存储 算法 Linux
深入理解Linux内存管理brk 和 sbrk 与以及使用C++ list实现内存分配器
深入理解Linux内存管理brk 和 sbrk 与以及使用C++ list实现内存分配器
36 0
|
1月前
|
存储 监控 Linux
Linux 使用getrusage系统调用获取cpu信息:一个C++实例分析
Linux 使用getrusage系统调用获取cpu信息:一个C++实例分析
49 0
|
1月前
|
存储 算法 C语言
【C/C++ 链表结构】探索链表迭代器:C++实现的深入分析与优化策略
【C/C++ 链表结构】探索链表迭代器:C++实现的深入分析与优化策略
38 0