在android源码的驱动目录下,一般会有共享内存的相关实现源码,目录是:kernel\drivers\staging\android\ashmem.c。但是本篇文章不是讲解android共享内存的功能实现原理,而是讲怎么运用它。

  1. 

  在linux中,不同进程间拥有自己独立的内存空间,32位操作系统中好像一个进程能用的内存大小是4G吧。而且一般不同进程间不能够互相使用各自内存的数据。

  当然不同进程间共享数据方法很多,比如之前说的进程间通信binder,socket等等,不过android出了一个共享内存的概念,为的是不同进程间能够共同操作同一块内存数据,比如进程1001往一块共享内存addr里面写数据“hello world”,进程1009往这块共享内存addr读取出“hello world”,也能够往这块共享内存addr写数据“hello china”。这就是共同享用了一块内存的基本概念了(说白了就是同耕一块田)。讲的够仔细了吧,如果不清楚评论区见。

  注意:好像binder传输的数据实现也是类似于共享内存,读者可以自行去了解。

  

  2.

  先说一下等会写程序的思路:

  首先想想代码编译出两个可执行文件后如何操作,打开两个终端,都进入设备adb shell,第一个终端执行进程a,第二个终端执行进程b。在进程a输入一串数据后,在进程b中可以读出这段数据(也能够改写这段数据,读者可以自行添加这部分功能)。

  然后再想想实现的方式,

  进程a:1. 创建共享内存,设置共享内存大小,这时会得到一个fd。2. 获取共享内存地址。3. 先读取地址数据,然后往地址写入数据。4. 把fd通过binder发送给需要使用的进程。

  进程b:1. 通过binder读取到fd。2. 用fd获取共享内存地址。3. 读取共享内存数据,然后往地址写入数据。

  注意:linux一切皆文件,所以文件描述符fd很重要。  

  

  3. 

  3.1

  捋清思路后,就可以开始写代码了(android.mk的编写可以参考之前的文章),进程a,命名为mysharememory_a代码如下:

  

  1. #include <fcntl.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <linux/ashmem.h>
  5. #include <sys/mman.h>
  6. #include <sys/ioctl.h>
  7. #include <stddef.h>
  8. #include <linux/ipc.h>
  9. #include <linux/shm.h>
  10. #include <binder/IServiceManager.h>
  11. #include <binder/IPCThreadState.h>
  12. #include <binder/Parcel.h>
  13. #include <binder/IInterface.h>
  14.  
  15. #define DEVASHMEM "/dev/ashmem"
  16. #define SHNAME "hellomemory"
  17. #define MAXBUFSIZE 1024
  18. #define TRANSFDCODE 1000
  19. #define WRITEDATACODE 1001
  20.  
  21. using namespace android;
  22. int main(int argc, char *argv[])
  23. {
  24. int fd = open(DEVASHMEM, O_RDWR);
  25. if(fd < 0)
  26. {
  27. return -1;
  28. }
  29. int ret = ioctl(fd, ASHMEM_SET_NAME, SHNAME);
  30. if(ret < 0){
  31. close(fd);
  32. return -1;
  33. }
  34. char *get_sh_addr_write = NULL;
  35. ret = ioctl(fd, ASHMEM_SET_SIZE, MAXBUFSIZE);
  36. if(ret < 0){
  37. close(fd);
  38. return -1;
  39. }
  40. get_sh_addr_write = (char*)mmap(NULL, MAXBUFSIZE , PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  41. if(NULL == get_sh_addr_write)
  42. {
  43. return -1;
  44. }
  45. sp<IServiceManager> sm = defaultServiceManager();
  46. sp<IBinder> binder = sm->checkService(String16("mybindertag"));
  47. Parcel data, reply;
  48. data.writeDupFileDescriptor(fd);
  49. binder->transact(TRANSFDCODE, data, &reply);
  50. char input_data[MAXBUFSIZE] = {0};
  51. while(1)
  52. {
  53. printf("read share memory buf is %s\n", get_sh_addr_write);
  54. printf("please input data to buf :");
  55. scanf("%s", input_data);
  56. getchar();
  57. strcpy(get_sh_addr_write,input_data);
  58. binder->transact(WRITEDATACODE, data, &reply);
  59. }
  60. return ret;
  61. }

  3.2

   mysharememory_b代码如下:

  

  1. #include <fcntl.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <linux/ashmem.h>
  5. #include <sys/mman.h>
  6. #include <sys/ioctl.h>
  7. #include <stddef.h>
  8. #include <linux/ipc.h>
  9. #include <linux/shm.h>
  10. #include <binder/IServiceManager.h>
  11. #include <binder/IPCThreadState.h>
  12. #include <binder/Parcel.h>
  13. #include <binder/IInterface.h>
  14.  
  15. #define DEVASHMEM "/dev/ashmem"
  16. #define SHNAME "hellomemory"
  17. #define MAXBUFSIZE 1024
  18. #define TRANSFDCODE 1000
  19. #define WRITEDATACODE 1001
  20.  
  21. using namespace android;
  22. int g_sh_fd = 0;
  23. class MyBinderService : public BBinder{
  24. status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
  25. {
  26. int ret;
  27. char *get_sh_addr_read = NULL;
  28. int get_sh_size;
  29. printf("songsong!! **** onTransact ***** code = %d \n",code);
  30. switch(code)
  31. {
  32. case TRANSFDCODE:
  33. g_sh_fd = data.readFileDescriptor();
  34. break;
  35. case WRITEDATACODE:
  36. get_sh_size = ioctl(g_sh_fd, ASHMEM_GET_SIZE,NULL);
  37. if(get_sh_size > 0)
  38. {
  39. get_sh_addr_read = (char*)mmap(NULL, get_sh_size, PROT_READ | PROT_WRITE, MAP_SHARED, g_sh_fd, 0);
  40. }
  41. else
  42. {
  43. printf("mmap failed %d\n", get_sh_size);
  44. return -1;
  45. }
  46. printf("what is in the share memory: %s\n", get_sh_addr_read);
  47. break;
  48. default:
  49. break;
  50. }
  51. return NO_ERROR;
  52. }
  53. };
  54. int main(int argc, char *argv[])
  55. {
  56. defaultServiceManager()->addService(String16("mybindertag"), new MyBinderService());
  57. sp<ProcessState> proc(ProcessState::self());
  58. ProcessState::self()->startThreadPool();
  59. IPCThreadState::self()->joinThreadPool();
  60. return 0;
  61. }

 

  3.3

  回收关闭部分代码可选择添加在mysharememory_b中,如下:

  

  1. int ret;
  2. ret = munmap((void*)get_sh_addr_read, get_sh_size);
  3. if(ret == -1)
  4. {
  5. return -1;
  6. }
  7. ret = close(g_sh_fd);
  8. if(ret == -1)
  9. {
  10. return -1;
  11. }

 

  

 

  3.4 

  演示截图:

  

 

 

   4. 为了骗取评论,我不再解释代码,心累。不过您可以把代码直接拷贝去编译执行,再通过调试去理解代码的精髓,也是没问题的。

  

版权声明:本文为songsongman原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/songsongman/p/11249974.html