android Framework 中用到了哪些跨进程通信方式?
创始人
2024-03-02 07:37:16

文章目录

    • Linux 有哪些跨进程的通信方式?
    • 管道
    • 本地 Socket
    • 共享内存
    • 信号

Linux 有哪些跨进程的通信方式?

  • Binder 机制是Android基于Linux的一种独特的IPC机制。我们常用的AMS,PMS 等都是通过Binder机制来完成跨进程通信的,那么除了Binder ,Linux 还有其他跨进程通信的方式可以选择。在Android Framework中主要用到以下方式

      1. 管道2. Socket3. 共享内存4. 信号
    

管道

  • 管道的特点:半双工的,单向

    管道描述符数据只能往一个方向,要么read要么write。如果向既可以读又可以写,则需要两个描述符才可以。Linux 基于这种情况提供了 pipe(fds) api,这个api可以生成一对描述符,一个用来写,一个用来读。

  • 一般是在父子进程之间使用

    无名管道一般是在父子进程之间使用。如果是有名管道,只要两个进程之间都知道名字就可以直接通信了。

  • 管道的使用方式
    在这里插入图片描述

#include
#includeint main()
{
int n,fd[2];                         // 这里的fd是文件描述符的数组,用于创建管道做准备的
pid_t pid;
char line[100];
if(pipe(fd)<0)                     //   创建管道,生成描述符 fd[1] 是用来写的 fd[0] 是用来读的printf("pipe create error/n");if((pid=fork())<0)              //利用fork()创建新进程printf("fork error/n");else if(pid>0){                   //这里是父进程,先关闭管道的读出端,然后在管道的写端写入“hello world"close(fd[0]);write(fd[1],"hello word/n",11);
}
else{close(fd[1]);                 //这里是子进程,先关闭管道的写入端,然后在管道的读出端读出数据n= read(fd[0],line,100);write(STDOUT_FILENO,line,n);
}
exit(0);
}
  • Framework 中 在Android 4.4 中 Looper 中使用到了管道,高版本更换了 eventfd 的方式。当有线程拿到写的描述符,往里写内容,那么读端就可以收到通知了。
Looper::Looper(bool allowNonCallbacks) :mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {int wakeFds[2];// 通过pipe 生成两个描述符int result = pipe(wakeFds);LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);// 0 元素对应的是 读mWakeReadPipeFd = wakeFds[0];// 1 对应的是写 mWakeWritePipeFd = wakeFds[1];result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);mIdling = false;// Allocate the epoll instance and register the wake pipe.mEpollFd = epoll_create(EPOLL_SIZE_HINT);struct epoll_event eventItem;memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field unioneventItem.events = EPOLLIN;eventItem.data.fd = mWakeReadPipeFd;// 通过 epoll_ctl 注册事件监听result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
}
  • epoll 是怎么监听读端事件的
int Looper::pollInner(int timeoutMillis) {// 。。。struct epoll_event eventItems[EPOLL_MAX_EVENTS];// epoll_wait 阻塞在这,当返回的时候 eventCount 代表有几个事件被触发了int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);// 然后依次处理for (int i = 0; i < eventCount; i++) {int fd = eventItems[i].data.fd;uint32_t epollEvents = eventItems[i].events;// 判断描述符 mWakeReadPipeFd ,如果是读描述符if (fd == mWakeReadPipeFd) {if (epollEvents & EPOLLIN) {// 从管道中读取数据awoken();} } else {// ... }}
}
  • 往管道中写数据,通过 Looper 的 wake() 函数写
void Looper::wake() {
#if DEBUG_POLL_AND_WAKEALOGD("%p ~ wake", this);
#endifssize_t nWrite;do {// 通过写描述符写nWrite = write(mWakeWritePipeFd, "W", 1);} while (nWrite == -1 && errno == EINTR);if (nWrite != 1) {if (errno != EAGAIN) {ALOGW("Could not write wake signal, errno=%d", errno);}}
}

管道在进程内可以用,跨进程也可以用,可以和 epoll 相结合监听读写事件,一般用在数据量不大的跨进程通信中使用。

本地 Socket

  • Socket 特点

      全双工,既可以读也可以写两个进程之间可以无亲缘关系
    
  • Android Framework 中在 Zygote 中,通过 Socket 来接收 AMS 请求,启动应用进程。在 ZygoteInit 的入口函数中

public static void main(String argv[]) {// 注册 Zygote 的 socket 监听接口,用来接收启动应用程序的消息zygoteServer.registerServerSocketFromEnv(socketName);// 通过调用 runSelectLoop 进入监听和接收消息的环节 里面有一个 while (true) caller = zygoteServer.runSelectLoop(abiList);
}
  • Runnable runSelectLoop(String abiList)  处理和返回Socket数据
    
Runnable runSelectLoop(String abiList) {while (true) {StructPollfd[] pollFds = new StructPollfd[fds.size()];// 。。。try {//	 用来检测有没有事件发生Os.poll(pollFds, -1);} catch (ErrnoException ex) {throw new RuntimeException("poll failed", ex);}if (i == 0) {// 处理新来的连接} else {// 处理发过来的数据}}}

共享内存

  • 共享内存的特点

      1. 很快,不需要多次拷贝。上面提到的管道和Socket数据量太大会很糟,因为会拷贝两次数据。共享内存拿到文件描述符后,把它同时交给两个进程,就可以进行通信了。2. 进程之间也不用存在亲缘关系
    
  • 具体匿名共享内存看之前的文章

  1. 匿名共享内存 ashmem
  2. 跨进程通信–共享内存(ashmem)实例

信号

  • 特点

      1. 单向发送:不关心发出去之后的事2. 只能带一个信号,不能带别的参数3. 知道进程 pid 就可以发信号了,而且可以群发信号
    
  • 哪里用到了信号?看下面的代码,大多数人都见过,一般我们安装或者重启应用的时候可能先kill掉自己。

android.os.Process.killProcess(android.os.Process.myPid())

killProcess 中就发送了一个信号

	public static final native void sendSignal(int pid, int signal);public static final void killProcess(int pid) {sendSignal(pid, SIGNAL_KILL);}
static void SetSigChldHandler() {struct sigaction sa;memset(&sa, 0, sizeof(sa)); //对sa地址内容进行清零操作sa.sa_handler = SigChldHandler;// zygote 关注的SIGCHLD信号,如果进程杀死了好及时回收资源int err = sigaction(SIGCHLD, &sa, NULL);
}

相关内容

热门资讯

北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...