Android系统匿名共享内存Ashmem(Anonymous Shared Memory)在进程间共享的原理分析

简介:

 在前面一篇文章Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析中,我们系统地介绍了Android系统匿名共享内存的实现原理,其中着重介绍了它是如何辅助内存管理系统来有效地管理内存的,在再前面一篇文章Android系统匿名共享内存Ashmem(Anonymous Shared Memory)简要介绍和学习计划中,我们还提到,Android系统匿名共享内存的另外一特点是通过Binder进程间通信机制来实现进程间共享的,本文中,将详细介绍Android系统匿名共享内存是如何使用Binder进程间通信机制来实现进程间共享的。

        由于Android系统匿名共享内存在进程间共享的原理涉及到Binder进程间通信机制的相关知识,所以希望读者在继续阅读本文之前,最好对Android系统的Binder进程间通信机制有一定的了解,具体可以参考Android进程间通信(IPC)机制Binder简要介绍和学习计划这篇文章。

        在Android系统匿名共享内存Ashmem(Anonymous Shared Memory)简要介绍和学习计划这篇文章中,我们举了一个例子来简要地介绍了Android系统的匿名共享内存机制及其使用方法,在这篇文章中,我们继续以这个实例来说明Android系统的匿名共享内存是如何使用Binder进程间通信机制来实现进程间共享的。为了方便描述,结合前面的Binder进程间通信机制知识,我们通过下面这个序列图来总结这个实例中的匿名共享内存文件的文件描述符在进程间传输的过程:

        这里, 我们需要关注的便是虚线框部分了,它在Binder驱动程序中实现了在两个进程中共享同一个打开文件的方法。我们知道,在Linux系统中,文件描述符其实就是一个整数。每一个进程在内核空间都有一个打开文件的数组,这个文件描述符的整数值就是用来索引这个数组的,而且,这个文件描述符只是在本进程内有效,也就是说,在不同的进程中,相同的文件描述符的值,代表的可能是不同的打开文件。因此,在进程间传输文件描述符时,不能简要地把一个文件描述符从一个进程传给另外一个进程,中间必须做一过转换,使得这个文件描述在目标进程中是有效的,并且它和源进程的文件描述符所对应的打开文件是一致的,这样才能保证共享。

        在浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路一文中,我们介绍了用来传输的Binder对象的数据结构struct flat_binder_object,它定义在kernel/common/drivers/staging/android/binder.h 文件中:

 
 
  1. /*  
  2.  * This is the flattened representation of a Binder object for transfer  
  3.  * between processes.  The 'offsets' supplied as part of a binder transaction 
  4.  * contains offsets into the data where these structures occur.  The Binder  
  5.  * driver takes care of re-writing the structure type and data as it moves  
  6.  * between processes.  
  7.  */  
  8. struct flat_binder_object {  
  9.     /* 8 bytes for large_flat_header. */  
  10.     unsigned long       type;  
  11.     unsigned long       flags;  
  12.  
  13.     /* 8 bytes of data. */  
  14.     union {  
  15.         void        *binder;    /* local object */  
  16.         signed long handle;     /* remote object */  
  17.     };  
  18.  
  19.     /* extra data associated with local object */  
  20.     void            *cookie;  
  21. }; 

       域type是一个枚举类型,它的取值范围是:

 
 
  1. enum {  
  2.     BINDER_TYPE_BINDER  = B_PACK_CHARS('s''b''*', B_TYPE_LARGE),  
  3.     BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w''b''*', B_TYPE_LARGE),  
  4.     BINDER_TYPE_HANDLE  = B_PACK_CHARS('s''h''*', B_TYPE_LARGE),  
  5.     BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w''h''*', B_TYPE_LARGE),  
  6.     BINDER_TYPE_FD      = B_PACK_CHARS('f''d''*', B_TYPE_LARGE),  
  7. }; 

        这里我们要介绍的Binder对象的type便是BINDER_TYPE_FD了,要传输的文件描述符的值保存在handle域中。

 

        在Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析一文中,我们详细介绍了Binder对象在进程间通信传输的完整过程,这里就不再详述了,有兴趣的读都可以回过头去参考一下。这里,我们只关注文件描述符类型的Binder对象在Binder驱动程序中的相关处理逻辑。

        文件描述符类型的Binder对象在Binder驱动程序中的相关处理逻辑实现在binder_transact函数,这个函数定义在kernel/common/drivers/staging/android/binder.c文件中:

 
 
  1. static void  
  2. binder_transaction(struct binder_proc *proc, struct binder_thread *thread,  
  3. struct binder_transaction_data *tr, int reply)  
  4. {  
  5.     struct binder_transaction *t;  
  6.     struct binder_work *tcomplete;  
  7.     size_t *offp, *off_end;  
  8.     struct binder_proc *target_proc;  
  9.     struct binder_thread *target_thread = NULL;  
  10.     struct binder_node *target_node = NULL;  
  11.     struct list_head *target_list;  
  12.     wait_queue_head_t *target_wait;  
  13.     struct binder_transaction *in_reply_to = NULL;  
  14.     struct binder_transaction_log_entry *e;  
  15.     uint32_t return_error;  
  16.  
  17.     ......  
  18.       
  19.  
  20.     offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));  
  21.  
  22.     ......  
  23.  
  24.     off_end = (void *)offp + tr->offsets_size;  
  25.     for (; offp < off_end; offp++) {  
  26.         struct flat_binder_object *fp;  
  27.         ......  
  28.         fp = (struct flat_binder_object *)(t->buffer->data + *offp);  
  29.         switch (fp->type) {  
  30.         ......  
  31.         case BINDER_TYPE_FD: {  
  32.             int target_fd;  
  33.             struct file *file;  
  34.  
  35.             if (reply) {  
  36.                 if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {  
  37.                     binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n",  
  38.                                     proc->pid, thread->pid, fp->handle);  
  39.                     return_error = BR_FAILED_REPLY;  
  40.                     goto err_fd_not_allowed;  
  41.                 }  
  42.             } else if (!target_node->accept_fds) {  
  43.                 binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n",  
  44.                                 proc->pid, thread->pid, fp->handle);  
  45.                 return_error = BR_FAILED_REPLY;  
  46.                 goto err_fd_not_allowed;  
  47.             }  
  48.  
  49.             file = fget(fp->handle);  
  50.             if (file == NULL) {  
  51.                 binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n",  
  52.                                     proc->pid, thread->pid, fp->handle);  
  53.                 return_error = BR_FAILED_REPLY;  
  54.                 goto err_fget_failed;  
  55.             }  
  56.             target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);  
  57.             if (target_fd < 0) {  
  58.                 fput(file);  
  59.                 return_error = BR_FAILED_REPLY;  
  60.                 goto err_get_unused_fd_failed;  
  61.             }  
  62.             task_fd_install(target_proc, target_fd, file);  
  63.             if (binder_debug_mask & BINDER_DEBUG_TRANSACTION)  
  64.                     printk(KERN_INFO "        fd %ld -> %d\n", fp->handle, target_fd);  
  65.             /* TODO: fput? */  
  66.             fp->handle = target_fd;  
  67.         } break;  
  68.  
  69.         ......  
  70.         }  
  71.     }  
  72.       
  73.     ......  
  74.  

        这里,我们先明确一下在Android系统匿名共享内存Ashmem(Anonymous Shared Memory)简要介绍和学习计划这篇文章中所举的例子获取匿名共享内存文件的文件描述符的场景。匿名共享内存文件是在Server进程创建的,Client通过IMemoryService.getFileDescriptor去获取Server进程所创建的匿名共享内存文件的文件描述符,Server进程在返回这个文件描述符的过程中进入到Binder驱动程序,即这里的binder_transact函数。因此,这里的当前执行binder_transact函数的进程是Server进程,即源进程是Server进程,而目标进程是Client进程,就是这里的target_proc所表示的进程了。

 

        函数binder_transaction处理文件描述符类型的Binder对象就在中间的for循环里面。

       首先是获得Binder对象,并保存在本地变量fp中:

 
 
  1. fp = (struct flat_binder_object *)(t->buffer->data + *offp); 

       文件描述符的值就保存在fp->handle中,通过fget函数取回这个文件描述符所对应的打开文件结构:

 
 
  1. file = fget(fp->handle); 

      这里的file是一个struct file指针,它表示一个打开文件结构。注间,在Linux系统中,打开文件结构struct file是可以在进程间共享的,它与文件描述符不一样。

 

       接着在目标进程中获得一个空闲的文件描述符:

 
 
  1. target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC); 

       现在,在目标进程中,打开文件结构有了,文件描述符也有了,接下来就可以把这个文件描述符和这个打开文件结构关联起来就可以了:

 
 
  1. task_fd_install(target_proc, target_fd, file); 

       由于这个Binder对象最终是要返回给目标进程的,所以还要修改fp->handle的值,它原来表示的是在源进程中的文件描述符,现在要改成目标进程的文件描述符:

 
 
  1. fp->handle = target_fd; 
      

       这样,对文件描述符类型的Binder对象的处理就完成了。目标进程拿到这个文件描述符后,就可以和源进程一起共享打开文件了。

 

       至此,Android系统匿名共享内存利用Binder进程间通信机制来实现进程间共享的学习就结束了,整个Android系统匿名共享内存机制的学习也完成了,希望对读者有所帮助,重新学习Android系统匿名共享内存机制请回到Android系统匿名共享内存Ashmem(Anonymous Shared Memory)简要介绍和学习计划一文。





本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/965501,如需转载请自行联系原作者

目录
相关文章
|
24天前
|
搜索推荐 Android开发 iOS开发
安卓与iOS系统的用户界面设计对比分析
本文通过对安卓和iOS两大操作系统的用户界面设计进行对比分析,探讨它们在设计理念、交互方式、视觉风格等方面的差异及各自特点,旨在帮助读者更好地理解和评估不同系统的用户体验。
18 1
|
26天前
|
存储 算法 编译器
【C++ 内存管理 重载new/delete 运算符 新特性】深入探索C++14 新的/删除的省略(new/delete elision)的原理与应用
【C++ 内存管理 重载new/delete 运算符 新特性】深入探索C++14 新的/删除的省略(new/delete elision)的原理与应用
43 0
|
21天前
|
缓存 Java C#
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍(一)
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍
60 0
|
11天前
|
存储 算法
深入理解操作系统内存管理:原理与实践
【4月更文挑战第8天】 在现代计算机系统中,操作系统扮演着关键角色,特别是在内存资源的管理上。本文将深入探讨操作系统中的内存管理机制,包括虚拟内存、物理内存的分配与回收,以及页面置换算法等关键技术。通过分析不同内存管理策略的优势与局限性,本文旨在为读者提供一套系统的内存管理知识框架,帮助理解操作系统如何高效、安全地管理有限的内存资源以满足多任务处理的需求。
|
17天前
|
存储 算法 安全
深入理解操作系统内存管理:原理与实践
【4月更文挑战第2天】 在现代计算机系统中,操作系统的内存管理是核心功能之一,它负责协调和分配系统内存资源。本文将探讨操作系统内存管理的基本原理,包括内存的分配与回收、分页机制、虚拟内存的使用以及内存保护。通过对这些概念的细致剖析,我们不仅能够理解操作系统如何高效利用有限的物理内存,还能够认识到内存管理对系统稳定性和性能的重要性。文章还将简要讨论现代操作系统中内存管理的创新趋势及其对未来计算技术的潜在影响。
14 2
|
24天前
|
存储 缓存 安全
深入理解内存映射:mmap映射的背后原理以及和共享内存的差异
深入理解内存映射:mmap映射的背后原理以及和共享内存的差异
53 0
|
24天前
|
监控 Linux Shell
Linux 进程问题调查探秘:分析和排查频繁创建进程问题
Linux 进程问题调查探秘:分析和排查频繁创建进程问题
39 0
|
24天前
|
存储 Linux 程序员
【Linux C/C++ 堆内存分布】深入理解Linux进程的堆空间管理
【Linux C/C++ 堆内存分布】深入理解Linux进程的堆空间管理
70 0
|
24天前
|
消息中间件 存储 网络协议
Linux IPC 进程间通讯方式的深入对比与分析和权衡
Linux IPC 进程间通讯方式的深入对比与分析和权衡
65 0
|
24天前
|
存储 算法 Linux
【Linux 系统标准 进程资源】Linux 创建一个最基本的进程所需的资源分析,以及线程资源与之的差异
【Linux 系统标准 进程资源】Linux 创建一个最基本的进程所需的资源分析,以及线程资源与之的差异
25 0

热门文章

最新文章

相关实验场景

更多