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,如需转载请自行联系原作者
目录
相关文章
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
1407 4
|
8月前
|
安全 C语言 C++
比较C++的内存分配与管理方式new/delete与C语言中的malloc/realloc/calloc/free。
在实用性方面,C++的内存管理方式提供了面向对象的特性,它是处理构造和析构、需要类型安全和异常处理的首选方案。而C语言的内存管理函数适用于简单的内存分配,例如分配原始内存块或复杂性较低的数据结构,没有构造和析构的要求。当从C迁移到C++,或在C++中使用C代码时,了解两种内存管理方式的差异非常重要。
278 26
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
存储 监控 算法
员工屏幕监控系统之 C++ 图像差分算法
在现代企业管理中,员工屏幕监控系统至关重要。本文探讨了其中常用的图像差分算法,该算法通过比较相邻两帧图像的像素差异,检测屏幕内容变化,如应用程序切换等。文中提供了C++实现代码,并介绍了其在实时监控、异常行为检测和数据压缩等方面的应用,展示了其实现简单、效率高的特点。
443 15
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
701 15
Android 系统缓存扫描与清理方法分析
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
956 21
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
253 8
|
存储 Linux Android开发
Android底层:通熟易懂分析binder:1.binder准备工作
本文详细介绍了Android Binder机制的准备工作,包括打开Binder驱动、内存映射(mmap)、启动Binder主线程等内容。通过分析系统调用和进程与驱动层的通信,解释了Binder如何实现进程间通信。文章还探讨了Binder主线程的启动流程及其在进程通信中的作用,最后总结了Binder准备工作的调用时机和重要性。
Android底层:通熟易懂分析binder:1.binder准备工作
|
存储 程序员 编译器
什么是内存泄漏?C++中如何检测和解决?
大家好,我是V哥。内存泄露是编程中的常见问题,可能导致程序崩溃。特别是在金三银四跳槽季,面试官常问此问题。本文将探讨内存泄露的定义、危害、检测方法及解决策略,帮助你掌握这一关键知识点。通过学习如何正确管理内存、使用智能指针和RAII原则,避免内存泄露,提升代码健壮性。同时,了解常见的内存泄露场景,如忘记释放内存、异常处理不当等,确保在面试中不被秒杀。最后,预祝大家新的一年工作顺利,涨薪多多!关注威哥爱编程,一起成为更好的程序员。
658 0
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
735 4