10.3、android输入系统_必备Linux编程知识_任意进程双向通信(scoketpair+binder)
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"
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; }//打开驱动,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)的更多相关文章
- 10.2、android输入系统_必备Linux编程知识_双向通信(scoketpair)
2. 双向通信(socketpair) 输入系统肯定涉及进程通讯:进程A读取/分发输入事件,APP处理输入事件,进程A给APP发送输入事件,APP处理完事件回复信息给进程A,APP关闭的时候也要发信息 ...
- 10.1、android输入系统_必备Linux编程知识_inotify和epoll
1. inotify和epoll 怎么监测键盘接入与拔出? (1)hotplug机制:内核发现键盘接入/拔出==>启动hotplug进程==>发消息给输入系统 (2)inotify机制:输 ...
- 10.9 android输入系统_APP跟输入系统建立联系和Dispatcher线程_分发dispatch
12. 输入系统_APP跟输入系统建立联系_InputChannel和Connection核心: socketpair // 第9课第3节_输入系统_必备Linux编程知识_任意进程双向通信(scok ...
- 10.5 android输入系统_Reader线程_使用EventHub读取事件和核心类及配置文件_实验_分析
4. Reader线程_使用EventHub读取事件 使用inotify监测/dev/input下文件的创建和删除 使用epoll监测有无数据上报 细节: a.fd1 = inotify_init(& ...
- 10.4 android输入系统_框架、编写一个万能模拟输入驱动程序、reader/dispatcher线程启动过程源码分析
1. 输入系统框架 android输入系统官方文档 // 需FQhttp://source.android.com/devices/input/index.html <深入理解Android 卷 ...
- 10.7 android输入系统_Dispatcher线程情景分析_Reader线程传递事件和dispatch前处理
android输入系统C++最上层文件是com_android_serve_input_InputManagerService.cpp global key:按下按键,启动某个APP可以自己指定,修改 ...
- 10.11 android输入系统_补充知识_activity_window_decor_view关系
android里:1个application, 有1个或多个activity(比如支付宝有:首页.财富.口碑.朋友.我的,这些就是activity)1个activity, 有1个window(每个ac ...
- 10.6 android输入系统_Dispatcher线程_总体框架
图解Android - Android GUI 系统 (5) - Android的Event Input System - 漫天尘沙 - 博客园.htm // 关注里面的Dispatcher处理流程h ...
- 10.12 android输入系统_InputStage理论
android应用程序对输入系统的处理分为多个阶段,我们把这些阶段称为InputStage 理论处理流程: (1)activity发给window,如果window不能处理,再由activity处理; ...
随机推荐
- 第一天,Mysql安装,DDL(数据库定义语言),DBA,DML(数据库操纵语言),导入外面的sql文件
把“D:\mysql-5.6.22-winx64\bin”添加到系统环境变量path中了,然后在任意目录可访问mysql等命令,这样如登录等操作就不需要进入MySQL安装目录才好执行! MySQL下载 ...
- 【深入篇】Android常用布局方式简介
LinearLayout 线性布局是程序中最常见的布局方式.一般分为水平线性布局和竖直线性布局,通过android.orientation属性可以设置线性布局的方向. 在布局中操作颜色时,要用的是十六 ...
- cf1089d Distance Sum
题目大意 给一个有n个点,m条边的无向连通图,求所有点两两之间的最短路.$(2<=n<=10^5;n-1<=m<=n+42)$ solution 我们注意到$m-n+1$很小. ...
- matplotlib散点图笔记
定义: 由一组不连续的点完成的图形 散点图: 包含正相关性,负相关性和不相关性. 散点图生成函数: plt.scatter(x,y) 演示代码如下: import numpy as np import ...
- 解决xorm逆向mssql报datetime2不兼容的异常错误
xorm作为golang开发者的一大利器,深受大家的喜爱,可是最近在逆向mssql的时候,报了这么一个错误: 最后找了半天发现xorm没有预置DateTime2类型,经过几番折腾,在xorm源码的en ...
- HDFS简单介绍及用C语言訪问HDFS接口操作实践
一.概述 近年来,大数据技术如火如荼,怎样存储海量数据也成了当今的热点和难点问题,而HDFS分布式文件系统作为Hadoop项目的分布式存储基础,也为HBASE提供数据持久化功能,它在大数据项目中有很广 ...
- 从”茄子快传”看应用程序怎样获取手机已安装程序的apk文件
"茄子快传"是联想开发的一款近距离文件共享软件.它通过wifi-direct(速度飞快,不须要联网)或者普通的网络(速度慢)在不同手机间传递文件. 不知为何.它就火了起来,火的也飞 ...
- notification-应用实例
这几天接触到了notification,现在就把它的常用方法总结下. 直接看如下代码就行了 ComponentName componetName = new ComponentName("c ...
- Java 8 Stream Tutorial--转
原文地址:http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/ This example-driven tutori ...
- 洛谷 P3386 【模板】二分图匹配 Dinic版
题目背景 二分图 题目描述 给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数 输入输出格式 输入格式: 第一行,n,m,e 第二至e+1行,每行两个正整数u,v,表示u,v有一条连边 ...