【Android源码 栏目提醒】:网学会员Android源码 为您提供Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析 - 电子设计参考,解决您在Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析 - 电子设计学习中工作中的难题,参考学习。
Android系统匿名共享内存Anonymous Shared MemoryC调用接口分析 在
Android系统中针对移动设备内存空间有限的特点提供了一种在进程间共享数据的机制匿名共享内存它能够辅助内存管理系统来有效地管理内存它的实现原理我们在前面已经分析过了。
为了方便使用匿名共享内存机制系统还提供了Java调用接口MemoryFile和C调用接口MemoryHeapBase、MemoryBaseJava接口在前面也已经分析过了本文中将继续分析它的C接口。
在前面一篇文章
Android系统匿名共享内存AshmemAnonymous Shared Memory驱动程序源代码分析中我们分析了匿名共享内存驱动程序Ashmem的实现重点介绍了它是如何辅助内存管理系统来有效地管理内存的简单来说它就是给使用者提供锁机制来辅助管理内存当我们申请了一大块匿名共享内存时中间过程有一部分不需要使用时我们就可以将这一部分内存块解锁这样内存管理系统就可以把它回收回去了。
接着又在前面一篇文章
Android系统匿名共享内存AshmemAnonymous Shared Memory在进程间共享的原理分析中我们分析了匿名共享内存是如何通过Binder进程间通信机制来实现在进程间共享的简单来说就是每一个匿名共享内存块都是一个文件当我们需要在进程间共享时就把这个文件的打开描述符通过Binder进程间通信机制传递给另一外进程在传递的过程中Binder驱动程序就通过这个复制这个打开文件描述符到目标进程中去从而实现数据共享。
在文章
Android系统匿名共享内存AshmemAnonymous Shared Memory简要介绍和学习计划中我们介绍了如何在
Android应用程序中使用匿名共享内存主要是通过应用程序框架层提供的MemoryFile接口来使用的而MemoryFile接口是通过JNI方法调用到系统运行时库层中的匿名共享内存C接口最终通过这些C接口来使用内核空间中的匿名共享内存驱动模块。
为了方便开发者灵活地使用匿名共享内存
Android系统在应用程序框架层中还提供了使用匿名共享内存的C接口例如
Android应用程序四大组件之一Content Provider它在应用程序间共享数据时就是通过匿名共享内存机制来实现但是它并不是通过MemoryFile接口来使用而是通过调用C接口中的MemoryBase类和MemoryHeapBase类来使用。
在接下来的内容中我们就详细分析MemoryHeapBase类和MemoryBase类的实现以及它们是如何实现在进程间共享数据的。
如果我们想在进程间共享一个完整的匿名共享内存块可以通过使用MemoryHeapBase接口来实现如果我们只想在进程间共享一个匿名共享内存块中的其中一部分时就可以通过MemoryBase接口来实现。
MemoryBase接口是建立在MemoryHeapBase接口的基础上面的它们都可以作为一个Binder对象来在进程间传输因此希望读者在继续阅读本文之前对
Android系统的Binder进程间通信机制有一定的了解具体可以参考前面一篇文章
Android进程间通信IPC机制Binder简要介绍和学习计划。
下面我们就首先分析MemoryHeapBase接口的实现然后再分析MemoryBase接口的实现最后通过一个实例来说明它们是如何使用的。
1. MemoryHeapBase 前面说到MemoryHeapBase类的对象可以作为Binder对象在进程间传输作为一个Binder对象就有Server端对象和Client端引用的概念其中Server端对象必须要实现一个BnInterface接口而Client端引用必须要实现一个BpInterface接口。
下面我们就先看一下MemoryHeapBase在Server端实现的类图 这个类图中的类可以划分为两部分一部分是和业务相关的即跟匿名共享内存操作相关的类包括MemoryHeapBase、IMemoryBase和RefBase三个类另一部分是和Binder机制相关的包括IInterface、BnInterface、BnMemoryHeap、IBinder、BBinder、ProcessState和IPCThreadState七个类。
我们先来看跟匿名共享内存业务相关的这部分类的逻辑关系。
IMemoryBase定义了匿名共享内操作的接口而MemoryHeapBase是作为Binder机制中的Server角色的因此它需要实现IMemoryBase接口此外MemoryHeapBase还继承了RefBase类。
从前面一篇文章
Android系统的智能指针轻量级指针、强指针和弱指针的实现原理分析中我们知道继承了RefBase类的子类它们的对象都可以结合
Android系统的智能指针来使用因此我们在实例化MemoryHeapBase类时可以通过智能指针来管理它们的生命周期。
再来看和Binder机制相关的这部分类的逻辑关系。
从
Android系统进程间通信IPC机制Binder中的Server启动过程源代码分析这篇文章中我们知道所有的Binder对象都必须实现IInterface接口无论是Server端实体对象还是Client端引用对象通过这个接口的asBinder成员函数我们可以获得Binder对象的IBinder接口然后通过Binder驱动程序把它传输给另外一个进程。
当一个类的对象作为Server端的实体对象时它还必须实现一个模板类BnInterface这里负责实例化模板类BnInterface的类便是BnMemoryHeap类了它里面有一个重要的成员函数onTransact当Client端引用请求Server端对象执行命令时Binder系统就会调用BnMemoryHeap类的onTransact成员函数来执行具体的命令。
当一个类的对象作为Server端的实体对象时它还要继承于BBinder类这是一个实现了IBinder接口的类它里面有一个重要的成员函数transact当我们从Server端线程中接收到Client端的请求时就会调用注册在这个线程中的BBinder对象的transact函数来处理这个请求而这个transact函数会将这些Client端请求转发给BnMemoryHeap类的onTransact成员函数来处理。
最后ProcessState和IPCThreadState两个类是负责和Binder驱动程序打交道的其中ProcessState负责打开Binder设备文件/dev/binder打开了这个Binder设备文件后就会得到一个打开设备文件描述符而IPCThreadState就是通过这个设备文件描述符来和Binder驱动程序进行交互的例如它通过一个for循环来不断地等待Binder驱动程序通知它有新的Client端请求到来了一旦有新的Client端请求到来它就会调用相应的BBinder对象的transact函数来处理。
本文我们主要是要关注和匿名共享内存业务相关的这部分类即IMemoryBase和MemoryHeapBase类的实现和Binder机制相关的这部分类的实现可以参考
Android进程间通信IPC机制Binder简要介绍和学习计划一文。
IMemoryBase类主要定义了几个重要的操作匿名共享内存的方法它定义在frameworks/base/include/binder/IMemory.h文件中 cpp view plaincopy 1. class IMemoryHeap : public IInterface 2. 3. public: 4. ...... 5. 6. virtual int getHeapID const 0 7. virtual void getBase const 0 8. virtual size_t getSize const 0 9. 10. ...... 11. 成员函数getHeapID是用来获得匿名共享内存块的打开文件描述符的成员函数getBase是用来获得匿名共享内存块的基地址的有了这个地址之后我们就可以在程序里面直接访问这块共享内存了成员函数getSize是用来获得匿名共享内存块的大小的。
MemoryHeapBase类主要用来实现上面IMemoryBase类中列出来的几个成员函数的这个类声明在frameworks/base/include/binder/MemoryHeapBase.h文件中 cpp view plaincopy 1. class MemoryHeapBase : public virtual BnMemoryHeap 2. 3. public: 4. ...... 5. 6. / 7. maps memory from ashmem with the given name for debugging 8. / 9. MemoryHeapBasesize_t size uint32_t flags 0 char const name NULL 10. 11. ...... 12. 13. / implement IMemoryHeap interface / 14. virtual int getHeapID const 15. virtual void getBase const 16. virtual size_t getSize const 17. 18. ...... 19. private: 20. int mFD 21. size_t mSize 22. void mBase 23. 24. ...... 25. MemoryHeapBase类的实现定义在frameworks/base/libs/binder/MemoryHeapBase.cpp文件中我们先来看一下它的构造函数的实现 cpp view plaincopy 1. MemoryHeapBase::MemoryHeapBasesize_t size uint32_t flags char const name 2. : mFD-1 mSize0 mBaseMAP_FAILED mFlagsflags 3. mDevice0 mNeedUnmapfalse 4. 5. const size_t pagesize getpagesize 6. size size pagesize-1 amp pagesize-1 7. int fd ashmem_create_regionname NULL quotMemoryHeapBasequot : name size 8. LOGE_IFfdlt0 quoterror creating ashmem region: squot strerrorerrno 9. if fd gt 0 10. if mapfdfd size NO_ERROR 11. if flags amp READ_ONLY 12. ashmem_set_prot_regionfd PROT_READ 13. 14. 15. 16. 这个构造函数有三个参数其中size表示要创建的匿名共享内存的大小flags是用来设置这块匿名共享内存的属性的例如是可读写的还是只读的name是用来标识这个匿名共享内存的名字的可以传空值进来这个参数只是作为调试信息使用的。
MemoryHeapBase类创建的匿名共享内存是以页为单位的页的大小一般为4K但是是可以设置的这个函数首先通过getpagesize函数获得系统中一页内存的大小值然后把size参数对齐到页大小去即如果size不是页大小的整数倍时就增加它的大小使得它的值为页大小的整数倍 cpp view plaincopy 1. const size_t pagesize getpagesize 2. size size pagesize-1 amp pagesize-1 调整好size的大小后就调用系统运行时库层的C接口ashmem_create_region来创建一块共享内存了 cpp view plaincopy 1. int fd ashmem_create_regionname NULL quotMemoryHeapBasequot : name size 这个函数我们在前面一篇文章
Android系统匿名共享内存AshmemAnonymous Shared Memory驱动程序源代码分析中可以介绍过了这里不再详细它只要就是通过Ashmem驱动程序来创建一个匿名共享内存文件因此它的返回值是一个文件描述符。
得到了这个匿名共享内存的文件描述符后还需要调用mapfd成函数把它映射到进程地址空间去 cpp view plaincopy 1. status_t MemoryHeapBase::mapfdint fd size_t size uint32_t offset 2. 3. ...... 4. 5. if mFlags amp DONT_MAP_LOCALLY 0 6. void base uint8_tmmap0 size 7. PROT_READPROT_WRITE MAP_SHARED fd offset 8. ...... 9. mBase base 10. ...... 11. else 12. ...... 13. 14. 15. mFD fd 16. mSize size 17. return NO_ERROR 18. 一般我们创建MemoryHeapBase类的实例时都是需要把匿名共享内存映射到本进程的地址空间去的因此这里的条件mFlags amp DONT_MAP_LOCALLY 0为true于是执行系统调用mmap来执行内存映射的操作。
cpp view plaincopy 1. void base uint8_tmmap0 size 2. PROT_READPROT_WRITE MAP_SHARED fd offset 传进去的第一个参数0表示由内核来决定这个匿名共享内存文件在进程地址空间的起始位置第二个参数size表示要映射的匿名共享内文件的大小第三个参数PROT_READPROT_WRITE表示这个匿名共享内存是可读写的第四个参数fd指定要映射的匿名共享内存的文件描述符第五个参数offset表示要从这个文件的哪个偏移位置开始映射。
调用了这个函数之后最后会进入到内核空间的ashmem驱动程序模块中去执行ashmem_map函数这个函数的实现具体可以参考
Android系统匿名共享内存AshmemAnonymous Shared Memory驱动程序源代码分析一文这里就不同详细描述了。
调用mmap函数返回之后就得这块匿名共享内存在本进程地址空间中的起始访问地址了将这个地址保存在成员变量mBase中最后还将这个匿名共享内存的文件描述符和以及大小分别保存在成员变量mFD和mSize中。
回到前面MemoryHeapBase类的构造函数中将匿名共享内存映射到本进程的地址空间去后还看继续设置这块匿名共享内存的读写属性 cpp view plaincopy 1. if fd gt 0 2. if mapfdfd size NO_ERROR 3. if flags amp READ_ONLY 4. ashmem_set_prot_regionfd PROT_READ 5. 6. 7. 上面调用mapfd函数来映射匿名共享内存时指定这块内存是可读写的但是如果传进来的参数flags设置了只读属性那么还需要调用系统运行时库存层的ashmem_set_prot_region函数来设置这块匿名共享内存为只读这个函数定义在system/core/libcutils/ashmem-dev.c文件有兴趣的读者可以自己去研究一下。
这样通过这个构造函数一块匿名共享内存就建立好了其余的三个成员函数getHeapID、getBase和getSize就简单了 cpp view plaincopy 1. int MemoryHeapBase::getHeapID const 2. return mFD 3. 4. 5. void MemoryHeapBase::getBase const 6. return mBase 7. 8. 9. size_t MemoryHeapBase::getSize const 10. return mSize 11. 接下来我们再来看一下MemoryHeapBase在Client端实现的类图 这个类图中的类也是可以划分为两部分一部分是和业务相关的即跟匿名共享内存操作相关的类包括BpMemoryHeap、IMemoryBase和RefBase三个类另一部分是和Binder机制相关的包括IInterface、BpInterface、BpRefBase、IBinder、BpBinder、ProcessState和IPCThreadState七个类。
在和匿名共享内存操作相关的类中BpMemoryHeap类是前面分析的MemoryHeapBase类在Client端进程的远接接口类当Client端进程从Service Manager或者其它途径获得了一个MemoryHeapBase对象的引用之后就会在本地创建一个BpMemoryHeap对象来代表这个引用。
BpMemoryHeap类同样是要实现IMemoryHeap接口同时它是从RefBase类继承下来的因此它可以与智能指针来结合使用。
在和Binder机制相关的类中和Server端实现不一样的地方是Client端不需要实现BnInterface和BBinder两个类但是需要实现BpInterface、BpRefBase和BpBinder三个类。
BpInterface类继承于BpRefBase类而在BpRefBase类里面有一个成员变量mRemote它指向一个BpBinder对象当BpMemoryHeap类需要向Server端对象发出请求时它就会通过这个BpBinder对象的transact函数来发出这个请求。
这里的BpBinder对象是如何知道要向哪个Server对象发出请深圳市的呢它里面有一个成员变量mHandle它表示的是一个Server端Binder对象的引用值BpBinder对象就是要通过这个引用值来把请求发送到相应的Server端对象去的了这个引用值与Server端Binder对象的对应关系是在Binder驱动程序内部维护的。
这里的ProcessSate类和IPCThreadState类的作用和在Server端的作用是类似的它们都是负责和底层的Binder驱动程序进行交互例如BpBinder对象的transact函数就通过线程中的IPCThreadState对象来将Client端请求发送出去的。
这些实现具体可以参考
Android系统进程间通信IPC机制Binder中的Client获得Server远程接口过程源代码分析一文。
这里我们主要关注BpMemoryHeap类是如何实现IMemoryHeap接口的这个类声明和定义在frameworks/base/libs/binder/IMemory.cpp文件中 cpp view plaincopy 1. class BpMemoryHeap : public BpInterfaceltIMemoryHeapgt 2. 3. public: 4. BpMemoryHeapconst spltIBindergtamp impl 5. ...... 6. 7. virtual int getHeapID const 8. virtual void getBase const 9. virtual size_t getSize const 10. 11. ...... 12. private: 13. mutable volatile int32_t mHeapId 14. mutable void mBase 15. mutable size_t mSize 16. 17. ...... 18. 先来看构造函数BpMemoryHeap的实现 cpp view plaincopy 1. BpMemoryHeap::BpMemoryHeapconst spltIBindergtamp impl 2. : BpInterfaceltIMemoryHeapgtimpl 3. mHeapId-1 mBaseMAP_FAILED mSize0 mFlags0 mRealHeapfalse 4. 5. 它的实现很简单只是初始化一下各个成员变量例如表示匿名共享内存文件描述符的mHeapId值初化为-1、表示匿名内共享内存基地址的mBase值初始化为MAP_FAILED以及表示匿名共享内存大小的mSize初始为为0它们都表示在Client端进程中这个匿名共享内存还未准备就绪要等到第一次使用时才会去创建。
这里还需要注意的一点参数impl指向的是一个BpBinder对象它里面包含了一个指向Server端Binder对象即MemoryHeapBase对象的引用。
其余三个成员函数getHeapID、getBase和getSize的实现是类似的 cpp view plaincopy 1. int BpMemoryHeap::getHeapID const 2. assertMapped 3. return mHeapId 4. 5. 6. void BpMemoryHeap::getBase const 7. assertMapped 8. return mBase 9. 10. 11. size_t BpMemoryHeap::getSize const 12. assertMapped 13. return mSize 14. 即它们在使用之前都会首先调用assertMapped函数来保证在Client端的匿名共享内存是已经准备就绪了的 cpp view plaincopy 1. void BpMemoryHeap::assertMapped const 2. 3. if mHeapId -1 4. spltIBindergt binderconst_castltBpMemoryHeapgtthis-gtasBinder 5. spltBpMemoryHeapgt heapstatic_castltBpMemoryHeapgtfind_heapbinder.get 6. heap-gtassertReallyMapped 7. if heap-gtmBase MAP_FAILED 8. Mutex::Autolock _lmLock 9. if mHeapId -1 10. mBase heap-gtmBase 11. mSize heap-gtmSize 12.
android_atomic_write dup heap-gtmHeapId ampmHeapId 13. 14. else 15. // something went wrong 16. free_heapbinder 17. 18. 19. 在解释这个函数之前我们需要先了解一下BpMemoryHeap是如何知道自己内部维护的这块匿名共享内存有没有准备就绪的。
在frameworks/base/libs/binder/IMemory.cpp文件中定义了一个全局变量gHeapCache cpp view plaincopy 1. static spltHeapCachegt gHeapCache new HeapCache 它的类型为HeapCache这也是一个定义在frameworks/base/libs/binder/IMemory.cpp文件的类它里面维护了本进程中所有的MemoryHeapBase对象的引用。
由于在Client端进程中可能会有多个引用即多个BpMemoryHeap对象对应同一个MemoryHeapBase对象这是由于可以用同一个BpBinder对象来创建多个BpMemoryHeap对象因此当第一个BpMemoryHeap对象在本进程中映射好这块匿名共享内存之后后面的BpMemoryHeap对象就可以直接使用了不需要再映射一次当然重新再映射一次没有害处但是会是多此一举Google在设计这个类时可以说是考虑得非常周到的。
我们来看一下HeapCache的实现 cpp view plaincopy 1. class HeapCache : public IBinder::DeathRecipient 2. 3. public: 4. HeapCache 5. virtual HeapCache 6. 7. ...... 8. 9. spltIMemoryHeapgt find_heapconst spltIBindergtamp binder 10. void free_heapconst spltIBindergtamp bi.
上一篇:
Android应用自动化动态测试工具的研究及实现
下一篇:
阿克苏教育学院论文查重比例|阿克苏教育学院论文抄袭比例