3. 任意进程间通信(socketpair_binder)

进程每执行一次open打开文件,都会在内核中有一个file结构体表示它;

对每一个进程在内核中都会有一个task_struct表示进程,这个结构体内部有个files_struct结构体,这个结构体里面有个fdtble结构体,这个结构体里有个struct file **fd,fd就是个数组,fd[open时返回的句柄]就保存的对应文件的file结构体

因此不同进程的文件句柄只在本进程中有含义,如果想要在进程外面使用这个文件句柄,需要让外面进程的fd[任何句柄都可以]指向需要获得的目的进程的file

这里使用binder来传输文件句柄:

(1)APP1  open(file)得到fd1;

(2)通过binder驱动,根据fd1得到file:files->fdt->fd[fd1]

(3)从APP2的files->fdt->fd取出空项fd2,让fd[fd2]指向该file

(4)APP1通过fd1,APP2通过fd2就可以访问同一个file文件了,fd1和fd2不一样

取出APP_0004_Binder_CPP_App V4来修改:
1、server

(1)test_server.cpp :fd = open("1.txt");

(2)BnHelloService.cpp:添加结果get_fd:把fd传给client

(3)IHelloService.h:添加get_fd接口

2、client

(1)test_client.cpp:fd=service->get_fd();read(fd,buf);printf

(2)BpHelloService:添加get_fd向server发请求

IHelloService.h:(参考:IMediaPlayerService.h)

ifndef ANDROID_IHELLOERVICE_H

#define ANDROID_IHELLOERVICE_H

................头文件..................

#define HELLO_SVR_CMD_SAYHELLO 1

#define HELLO_SVR_CMD_SAYHELLO_TO 2

#define HELLO_SVR_CMD_GET_FD 3

namespace android{

class IHelloService:public IInterface

{

public:

  DECLARE_META_INTERFACE(HelloService);

  virtual void sayhello(void) = 0;

  virtual int sayhello_to(const char *name) = 0;

  virtual int get_fd(void) = 0;

};

class BnHelloService:public BnInterface<IHelloService>

{

private:

  int fd;

public:

  virtual status_t onTransact(uint32_t code,const Parcel& data,Parcel* reply,uint32_t flags = 0);

  virtual void sayhello(void);

  virtual int sayhello_to(const char *name);

  virtual int get_to(void);

  BnHelloService();

  BnHelloService(int fd);

}

}

#endfi

BnHelloService.cpp(参考:IMediaPlayerService.cpp)

#include LOG_TAG "HelloService"

#include "IHelloService.h"

namespace android{

  BnHelloService::BnHelloService()

  {

  }

  BnHelloService::BnHelloService(int fd)

  {

    this->fd = fd;

  }

  status_t BnHelloService::onTransact(uint32_t code,const Parcel& data,Parcel* reply,uint32_t flags)

  {

    //解析数据,调用sayhello/sayhello_to

    switch(code){

      case HELLO_SVR_CMD_SAYHELLO:{

        sayhello();

        return NO_ERROR;

      }break;

      case HELLO_SVR_CMD_SAYHELLO_TO:{

        //从data中取出参数

        int32_t policy = data->readInt32();//把四字节的全零数据读出来

        String16 name16 =data->readString16();

        String8 name8(name16);

        int cnt = sayhello_to(name8.string());

        //把返回值写入reply传回去

        reply->writeInt32(cnt);

        return NO_ERROR;

      }break;

      case HELLO_SVR_CMD_GET_FD :{

        int fd = this->get_fd();

        reply->writeInt32(cnt);

        /*

        参考frameworks\base\core\jni\android_view_InputChannel.cpp 里面的android_view_InputChannel_nativeWriteToParcel函数

        */

        reply->writeDupFileDescriptor(fd);//这里使用writeDupFile....的原因是reply在析构的时候会close(fd),所以需要dup复制出一个同样的fd让其去close,而不会影响client使用该文件

        return NO_ERROR;

      }break;

      default:

        return BBinder::onTransact(code,data,reply,flags);

    }

  }

  void BnHelloService::sayhello(void);

  {

      static int cnt = 0;

      ALOGI("say hello : %d\n", ++cnt);

  }

  int BnHelloService::sayhello_to(const char *name);

  {

      static int cnt = 0;
      ALOGI("say hello to %s : %d\n", name, ++cnt);
      return cnt;

  }

  int BnHelloService::sayhello_to(const char *name);

  {

      static int cnt = 0;
      ALOGI("say hello to %s : %d\n", name, ++cnt);
      return cnt;

  }

  int BnHelloService::get_fd(void);

  {

      return fd;

  }

  

}

BpHelloService.cpp(参考:IMediaPlayerService.cpp)

#include "IHelloService.h"

namespace android{

class BpHelloService:public BpInterface<IHelloService>

{

public:

  BpHelloService(const sp<IBinder>& impl):BpInterface<IHelloService>(impl)

  {

  }

  void sayhello(void)

  {

  //构造/发送数据

  Parcel data,reply;

  data.writeInt32(0);//data数据域可以自己定义,这里是为了统一

  remote()->transact(HELLO_SVR_CMD_SAYHELLO,data,&reply);

  }

  void sayhello_to(const char *name)

  {

  //构造/发送数据

  Parcel data,reply;

  int exception;

  data.writeInt32(0);//data数据域可以自己定义,这里是为了统一

  data.writeString16(String16("IHelloService"));

  data.writeString16(String16(name));

  remote()->transact(HELLO_SVR_CMD_SAYHELLO_TO,data,&reply);

  exception = reply.readInt32();

  if(exception)

    return -1;

  else

    return reply.readInt32();

  }

  int get_fd(void)

  {

  //构造/发送数据

  Parcel data,reply;

  int exception;

  data.writeInt32(0);//data数据域可以自己定义,这里是为了统一

  data.writeString16(String16("IHelloService"));

  remote()->transact(HELLO_SVR_GET_FD,data,&reply);

  exception = reply.readInt32();

  if(exception)

    return -1;

  else{

    int rawFd=reply.readFileDescriptor();

    return dup(rawFd);//dup会复制一个fd,即有两个fd指向同一个文件,当函数退出的时候,reply被析构,会close(rawFd),而我们通过dup继续保持文件的fd,这样就不会影响对文件的访问

  }

  }

}

IMPLEMENT_META_INTERFACE(HelloService,"android.meida.In");

}

test_server.cpp(参考:Main_mediaserver.cpp)

#define LOG_TAG “HelloService”

#include "IHelloService.h"

.................头文件.......................

using namespace android;

/*usage:test_server <file>*/

int main(void)

{

  int fd;

  if(argc == 2)

    fd = open(argv[1],O_RDWR);

  //add service   //while(1){read data,解析数据,调用服务函数}

  //打开驱动,mmap

  sp<ProcessState> proc(ProcessState::self());

  //获得BpServiceManager

  sp<IServiceManager> sm = defaultServiceManager();

  sm->addService(String16("hello"),new BnHelloService(fd));

  //循环体

  ProcessState::self()->startThreadPool();

  IPCThreadState::self()->joinThreadPool();

  return 0;

}

test_client.cpp

#define LOG_TAG “HelloService”

#include "IHelloService.h"

.................头文件.......................

using namespace android;

void main(int argc,char **argv)

{

    int cnt;
  if (argc < 2){
        ALOGI("Usage:\n");
        ALOGI("%s hello\n", argv[0]);
    ALOGI("%s <readfile>\n", argv[0]);
        ALOGI("%s hello <name>\n", argv[0]);
        return -1;
    }
  //getService

  //打开驱动,mmap

  sp<ProcessState> proc(ProcessState::self());

  //获得BpServiceManager

  sp<IServiceManager> sm = defaultServiceManager();

  

  if(strcmp(arfv[1],"hello") == 0)

  {

    sp<IBinder> binder = sm->getService(String16("hello"));

    if(binder  == 0)

    {

      ALOGI("can't get hello service\n");

      return -1;

    }

    //service肯定是BpHelloService指针

    sp<IHelloService> service = interface_cast<IHelloService>(binder);

    //调用Service函数

    if(argc < 3){

      service->sayhello();

      ALOGI("client call sayhello");

    }

    else{

      cnt = service->sayhello_to(argv[2]);

      ALOGI("client call sayhello_to,cnt = %d ",cnt);

    }

  }

  else if(strcmp(arfv[1],"readfile") == 0)

  {

    sp<IBinder> binder = sm->getService(String16("hello"));

    if(binder  == 0)

    {

      ALOGI("can't get hello service\n");

      return -1;

    }

    //service肯定是BpHelloService指针

    sp<IHelloService> service = interface_cast<IHelloService>(binder);

    //调用Service函数

    int fd = service->get_fd();

    lseek(fd,0,SEEK_SET);//移动文件指针,指向头部,否则不能重复读,因为读一次都文件指针一道最后面了,这个时候读数据为空,只能在写入后读取

    char buf[500];

    int len = read(fd,buf,500);

    buf[len] = '\0';

    ALOGI("client call get_fd= %d ",fd);

    ALOGI("client read file:%s ",buf);

  }

  return 0;

}

参考代码:
frameworks\base\core\jni\android_view_InputChannel.cpp (用binder传文件句柄)
server端写fd: android_view_InputChannel_nativeWriteToParcel
parcel->writeDupFileDescriptor
client端读fd: android_view_InputChannel_nativeReadFromParcel
int rawFd = parcel->readFileDescriptor();
int dupFd = dup(rawFd);

frameworks\native\libs\binder\Parcel.cpp

支持传输文件句柄的程序 v5:
第一次:
git clone https://github.com/weidongshan/APP_0004_Binder_CPP_App.git

更新:
git pull origin

取出指定版本:
git checkout v5 // v5, use binder to transfer file descriptor

编译:
把 APP_0004_Binder_CPP_App 放入 /work/android-5.0.2/frameworks/testing

cd /work/android-5.0.2/
. setenv
lunch //选择单板
mmm frameworks/testing/APP_0004_Binder_CPP_App
cp /work/android-5.0.2/out/target/product/tiny4412/system/bin/test_* /work/nfs_root/android_fs/

测试:
su
busybox mount -t nfs -o nolock,vers=2 192.168.1.123:/work/nfs_root /mnt
logcat HelloService:* GoodbyeService:* TestService:* *:S &
echo asfsdfasdf > 1.txt
./test_server 1.txt &
./test_client readfile

通过ls -l /proc/进程号/fd  可以查看文件fd指向的文件  比如:3 -> /mnt/android_fs/1.txt

10.3、android输入系统_必备Linux编程知识_任意进程双向通信(scoketpair+binder)的更多相关文章

  1. 10.2、android输入系统_必备Linux编程知识_双向通信(scoketpair)

    2. 双向通信(socketpair) 输入系统肯定涉及进程通讯:进程A读取/分发输入事件,APP处理输入事件,进程A给APP发送输入事件,APP处理完事件回复信息给进程A,APP关闭的时候也要发信息 ...

  2. 10.1、android输入系统_必备Linux编程知识_inotify和epoll

    1. inotify和epoll 怎么监测键盘接入与拔出? (1)hotplug机制:内核发现键盘接入/拔出==>启动hotplug进程==>发消息给输入系统 (2)inotify机制:输 ...

  3. 10.9 android输入系统_APP跟输入系统建立联系和Dispatcher线程_分发dispatch

    12. 输入系统_APP跟输入系统建立联系_InputChannel和Connection核心: socketpair // 第9课第3节_输入系统_必备Linux编程知识_任意进程双向通信(scok ...

  4. 10.5 android输入系统_Reader线程_使用EventHub读取事件和核心类及配置文件_实验_分析

    4. Reader线程_使用EventHub读取事件 使用inotify监测/dev/input下文件的创建和删除 使用epoll监测有无数据上报 细节: a.fd1 = inotify_init(& ...

  5. 10.4 android输入系统_框架、编写一个万能模拟输入驱动程序、reader/dispatcher线程启动过程源码分析

    1. 输入系统框架 android输入系统官方文档 // 需FQhttp://source.android.com/devices/input/index.html <深入理解Android 卷 ...

  6. 10.7 android输入系统_Dispatcher线程情景分析_Reader线程传递事件和dispatch前处理

    android输入系统C++最上层文件是com_android_serve_input_InputManagerService.cpp global key:按下按键,启动某个APP可以自己指定,修改 ...

  7. 10.11 android输入系统_补充知识_activity_window_decor_view关系

    android里:1个application, 有1个或多个activity(比如支付宝有:首页.财富.口碑.朋友.我的,这些就是activity)1个activity, 有1个window(每个ac ...

  8. 10.6 android输入系统_Dispatcher线程_总体框架

    图解Android - Android GUI 系统 (5) - Android的Event Input System - 漫天尘沙 - 博客园.htm // 关注里面的Dispatcher处理流程h ...

  9. 10.12 android输入系统_InputStage理论

    android应用程序对输入系统的处理分为多个阶段,我们把这些阶段称为InputStage 理论处理流程: (1)activity发给window,如果window不能处理,再由activity处理; ...

随机推荐

  1. 73,QT指针数组实战(指针数组与数组指针)

    //指针数组,每一个指针都是一个MainWindow // MainWindow *w[3][4]; // for(int i=0;i<3;i++) // { // for(int j=0;j& ...

  2. [Javascript] Identify the most important words in a document using tf-idf in Natural

    Tf-idf, or term frequency-inverse document frequency, is a statistic that indicates how important a ...

  3. APACHE2.4 指定目录中的字符编码

    APACHE2.4 指定目录中的字符编码 xampp 的 apache2.4 默认字符编码是西文,中文字符显示乱码,在 httpd.conf 没有 AddDefaultCharset utf-8 这样 ...

  4. redmine-bug 问题修改流程

    1.当我们接受到测试发过来的bug以后,首先就是针对描述,弄清出问题,如果不能重现或者是对问题不清楚,那么可以去找提出者确认 注意:有时候一个问题可能是经过几次重开或者追加提出的,这时候你一定要从头到 ...

  5. animation- 动画效果实现(xml形式实现)

    1.定义xml动画 1)在anim文件夹下定义xml文件 解释:这个文件夹下面的文件会被默认为动画文件,如果这个文件不存在,需要自己创建 display_result_anim.xml <?xm ...

  6. 4.使用 WSDL 指定的标准 SOAP 消息格式

    转自:https://technet.microsoft.com/zh-cn/sysinternals/x2ccke44(v=vs.94) 为 XML 文档(定义 Web 服务)定义架构的行业标准 W ...

  7. Linux下基于LDAP统一用户认证的研究

    Linux下基于LDAP统一用户认证的研究                   本文出自 "李晨光原创技术博客" 博客,谢绝转载!

  8. SVN和Git代码管理小结

    SVN和Git代码管理小结  之前,先用的是SVN,后来用了Git,最近又在用SVN.  关于代码管理,写几句.    由于自己参与的项目,人通常不超过10个人,版本不是很多,协作比较正常,感觉SVN ...

  9. CISP/CISA 每日一题 13

    监控信息系统人员所提供服务的效率和效果的工具: 1.例外报告:识别所有没有成功完成的或出了故障的应用 2.作业重运行报告:大多数异常终止作业都会导致重起 3.操作员问题报告:记录计算机运行问题及解决方 ...

  10. Direct2D开发:MFC下从资源文件中加载位图

    转载请注明出处:http://www.cnblogs.com/ye-ming 0X01 概述: 相对于GDI处理界面,Direct2D有得天独厚的优势,下图就是Direct2D与GDI的效果对比,wi ...