AShmem匿名共享内存为Binder机制添砖加瓦

Android的AShmem匿名共享内存是在Linux的共享内存基础上实现的。Ashmem的用处很多,如进行较大数据的从一个进程到另一个进程,那么Ashmem是不二的首选,首选避免binder进程间直接数据传递的一次数据拷贝,通过传递共享内存文件描述符来操作共享内存。如App进程和SurfaceFlinger进程是两个不同的进程,那么在进行View绘制的时候,如果采用binder机制传递数据的话,那么需要一次数据拷贝显然性能没那么好,而直接采用匿名内存共享,实际就是操作同个内存块了。当然,匿名共享内存核心还是用到了我们的基石——binder机制。当然,什么时候使用AShmem,什么时候不需要AShmem呢?一般就是在不同进程中传递数据量比较大的时候用到,binder机制传输需要拷贝数据,数据量大,需要的时间就越大,而当数据量很小,只是简单的数据获取以及信息命令传递,那么使用binder机制进行进程间通信,因为AShmem的创建也是需要较大的开销的。AShemem匿名共享内存的流程如下:


AShmem匿名共享内存为Binder机制添砖加瓦

匿名共享内存文件在Server进程(MemoryService)中创建,Client要获得共享内存文件的描述符,肯定不能直接通过binder机制获取Server进程的描述符,这里之所以说不能直接,是因为Server进程的文件描述符是只有在进程内私有的,而其他进程即使获得这个描述符,也不能操作Server进程的共享内存。那么只能在获得文件描述符之后再Binder Driver进行处理,Binder Driver在拿到MemoryService的FD之后,通过fget取回文件描述符所对应的打开文件结构file = fget(fp->handle);这个file是struct file指针,表示一个打开文件结构,而在linux中,这个struct file是可以在进程中进行共享的。然后在目标进程(Client)中创建一个空闲文件描述符target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);这样,空闲文件描述符、文件结构在目标进程已有,那么就需要关联这个空闲文件符和文件结构,task_fd_install(target_proc, target_fd, file);Binder对象是直接返回给Client的,所以在Binder对象中,修改handle值,指向target_fd,fp->handle = target_fd;这样Client进程就拿到能操作共享内存的文件描述符了。

一段内存,既有创建,也有回收。Android的匿名共享内存通过binder驱动在辅助系统进行内存管理。Ashmem的pin和unpin用来对内存进行锁定和解锁,标识哪些内存正在被使用,哪些没有,通过这些标识,共享内存驱动程序可以辅助系统进行内存回收。匿名共享内存创建之初,所有的内存都是pinned状态,用户主动申请,会unpin一块内存,只有对于unpin状态的内存,用户才可以重新pin。unpin内存存在一个unpin列表unpined_list。每当unpin一块内存的时候,需要重新arrange已在列表中的unpin内存起始区间。同样,每当pin的时候,也从unpin列表中剪出,并重新arrange列表中的unpin内存起始区间。