文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6666491

在前面一篇文章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. /* 8 bytes of data. */
  13. union {
  14. void        *binder;    /* local object */
  15. signed long handle;     /* remote object */
  16. };
  17. /* extra data associated with local object */
  18. void            *cookie;
  19. };

域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. offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
  18. ......
  19. off_end = (void *)offp + tr->offsets_size;
  20. for (; offp < off_end; offp++) {
  21. struct flat_binder_object *fp;
  22. ......
  23. fp = (struct flat_binder_object *)(t->buffer->data + *offp);
  24. switch (fp->type) {
  25. ......
  26. case BINDER_TYPE_FD: {
  27. int target_fd;
  28. struct file *file;
  29. if (reply) {
  30. if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {
  31. binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n",
  32. proc->pid, thread->pid, fp->handle);
  33. return_error = BR_FAILED_REPLY;
  34. goto err_fd_not_allowed;
  35. }
  36. } else if (!target_node->accept_fds) {
  37. binder_user_error("binder: %d:%d got transaction 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. file = fget(fp->handle);
  43. if (file == NULL) {
  44. binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n",
  45. proc->pid, thread->pid, fp->handle);
  46. return_error = BR_FAILED_REPLY;
  47. goto err_fget_failed;
  48. }
  49. target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
  50. if (target_fd < 0) {
  51. fput(file);
  52. return_error = BR_FAILED_REPLY;
  53. goto err_get_unused_fd_failed;
  54. }
  55. task_fd_install(target_proc, target_fd, file);
  56. if (binder_debug_mask & BINDER_DEBUG_TRANSACTION)
  57. printk(KERN_INFO "        fd %ld -> %d\n", fp->handle, target_fd);
  58. /* TODO: fput? */
  59. fp->handle = target_fd;
  60. } break;
  61. ......
  62. }
  63. }
  64. ......
  65. }

这里,我们先明确一下在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)简要介绍和学习计划一文。

老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注!

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

  1. Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6939890 在Android系统中,针对移动设 ...

  2. Android系统匿名共享内存(Anonymous Shared Memory)Java调用接口分析

    一.Ashmem驱动程序 ~/Android/kernel/goldfish ----include ----linux ----ashmem.h ----mm ----ashmem.c 驱动程序具体 ...

  3. Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6664554 在上一文章Android系统匿名共 ...

  4. Windows进程间共享内存通信实例

    Windows进程间共享内存通信实例 抄抄补补整出来 采用内存映射文件实现WIN32进程间的通讯:Windows中的内存映射文件的机制为我们高效地操作文件提供了一种途径,它允许我们在WIN32进程中保 ...

  5. 【VS开发】内存映射文件进程间共享内存

    内存映射文件进程间共享内存 内存映射文件的另一个功能是在进程间共享数据,它提供了不同进程共享内存的一个有效且简单的方法.后面的许多例子都要用到共享内存.共享内存主要是通过映射机制实现的.Windows ...

  6. Swoole 中使用 Table 内存表实现进程间共享数据

    背景 在多进程模式下进程之间的内存是相互隔离的,在一个工作进程中的全局变量和超全局变量,在另一个工作进程中是无法读取和操作的. 如果只有一个工作进程,则不存在进程隔离问题,可以使用全局变量和超全局变量 ...

  7. DLL入门浅析(5)——使用DLL在进程间共享数据

    转载自:http://www.cppblog.com/suiaiguo/archive/2009/07/21/90734.html 在Win16环境中,DLL的全局数据对每个载入它的进程来说都是相同的 ...

  8. 【C++】DLL内共享数据区在进程间共享数据(重要)

    因项目需要,需要在DLL中共享数据,即DLL中某一变量只执行一次,在运行DLL中其他函数时该变量值不改变:刚开始想法理解错误,搜到了DLL进程间共享数据段,后面发现直接在DLL中定义全局变量就行,当时 ...

  9. windows核心编程之进程间共享数据

    有时候我们会遇到window进程间共享数据的需求,例如说我想知道系统当前有多少某个进程的实例. 我们能够在程序中定义一个全局变量.初始化为0.每当程序启动后就加1.当然我们我们能够借助第三方介质来储存 ...

随机推荐

  1. thinking in java知识小记(一)

    知识点一(javadoc): 使用javadoc时特别注意选择encoding和charset为utf-8,要不然生成的javadoc会是乱码,命令:javadoc -encoding utf-8 - ...

  2. asp Eval()函数的一些使用总结

    一.函数的原型: Eval(string s); s可以是变量,表达式,语句: 二.使用: 1.s为变量时,返回该变量的值,如:string s = "sss";Eval(s);/ ...

  3. (转)sql语句中charindex的用法

    假如你写过很多程序,你可能偶尔会碰到要确定字符或字符窜串否包含在一段文字中,在这篇文章中,我将讨论使用CHARINDEX和PATINDEX函数来搜索文字列和字符串.我将告诉你这两个函数是如何运转的,解 ...

  4. C# string的一些函数

    创建string: string (char[])      使用指定的字符串数组构建一个新的string对象 Copy(string) 使用指定的string构建一个新的string对象 比较函数: ...

  5. JavaScript高级程序设计第14章表单脚本 (学习笔记)

    第十四章 表单脚本 1.阻止默认表单提交 1.提交表单数据 1.使用type=submit提交按钮 2.使用submit():方法 注意:当用户点击提交按钮时,会触发submit事件,从而在这里我们有 ...

  6. 数据链路层-点对点协议PPP

    在通信质量较差的年代,在数据链路层使用可靠传输协议曾是一个好的办法.因此,能实现可靠传输的高级数据链路控制HDLC(High-Level Data Link Control)就称为当时比较流行的数据链 ...

  7. smarty 常用参数

    section的产生是为解决foreach的不足的,与foreach一样,它用于设计模板内的循环块,它较为复杂,可极大程序上满足程序需要,所以在程序中我习惯使用它而不使用foreach,基本原形为:{ ...

  8. python中的StringIO模块

    python中的StringIO模块 标签:python StringIO 此模块主要用于在内存缓冲区中读写数据.模块是用类编写的,只有一个StringIO类,所以它的可用方法都在类中.此类中的大部分 ...

  9. 使用POI插件,提取导出excel的工具类

    在网站的不同的模块都需要使用到导入导出excel的功能,我们就需要写一个通用的工具类ExcelUtil. 我的思路:首先,导入和导出的Excel的文件格式固定:主标题,二级标题,数据行(姑且就这么叫) ...

  10. SVN - 详细文档

    1.首先打开Cornerstone 2.然后如下图所示: 3.选择对应的仓库,如下图所示 4.然后Import完成之后,就把本地的文件提交到SVN服务器上了,如下图所示,另外如果你想要使用SVN进行版 ...