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,如需转载请自行联系原作者
目录
相关文章
|
15天前
|
存储 前端开发 Java
Android MVVM架构模式下如何避免内存泄漏
Android采用MVVM架构开发项目,如何避免内存泄漏风险?怎样避免内存泄漏?
47 1
|
13天前
|
存储 程序员 编译器
简述 C、C++程序编译的内存分配情况
在C和C++程序编译过程中,内存被划分为几个区域进行分配:代码区存储常量和执行指令;全局/静态变量区存放全局变量及静态变量;栈区管理函数参数、局部变量等;堆区则用于动态分配内存,由程序员控制释放,共同支撑着程序运行时的数据存储与处理需求。
58 21
|
1天前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
17天前
|
存储 算法 搜索推荐
对二叉堆的简单分析,c和c++的简单实现
这篇文章提供了对二叉堆数据结构的简单分析,并展示了如何在C和C++中实现最小堆,包括初始化、插入元素、删除最小元素和打印堆的函数,以及一个示例程序来演示这些操作。
30 19
|
6天前
|
编解码 Android开发 UED
构建高效Android应用:从内存优化到用户体验
【10月更文挑战第11天】本文探讨了如何通过内存优化和用户体验改进来构建高效的Android应用。介绍了使用弱引用来减少内存占用、懒加载资源以降低启动时内存消耗、利用Kotlin协程进行异步处理以保持UI流畅,以及采用响应式设计适配不同屏幕尺寸等具体技术手段。
21 2
|
5天前
|
存储 C语言 C++
【C++打怪之路Lv6】-- 内存管理
【C++打怪之路Lv6】-- 内存管理
22 0
【C++打怪之路Lv6】-- 内存管理
|
6天前
|
Ubuntu Linux Shell
C++ 之 perf+火焰图分析与调试
【10月更文挑战第8天】在遇到一些内存异常的时候,经常这部分的代码是很难去进行分析的,最近了解到Perf这个神器,这里也展开介绍一下如何使用Perf以及如何去画火焰图。
18 1
|
15天前
|
存储 C语言 C++
【C/C++内存管理】——我与C++的不解之缘(六)
【C/C++内存管理】——我与C++的不解之缘(六)
|
17天前
|
程序员 C语言 C++
C++入门5——C/C++动态内存管理(new与delete)
C++入门5——C/C++动态内存管理(new与delete)
48 1
|
17天前
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
71 1