Android系统--输入系统(十六)APP跟输入系统建立联系_InputChannel和Connection

0. 核心:socketpair机制

1. 回顾Dispatch处理过程:

1.1 放入队列前稍加处理

  • 分类:Global Key/System Key/User Key
  • 处理紧急事件(比如来电的时候按下音量键静音)

1.2 InputReader线程将读到的输入事件稍加处理后放入mInboundQueue队列中,接着唤醒Dispatch线程

1.3 Dispatch从mInboundQueue队列中将输入事件取出,并稍加处理。

  • 对于Global Key/System Key按键处理:放入mCommandQueue队列中,依次处理,处理之后就release
  • 对于User Key,放入队列:查找目标APP,得到Connection,放入其OutBoundQueue队列中,稍后取出处理

2. 引入--如何找出目标应用程序,输入系统和应用程序如何建立联系?

PC和安卓系统都是运行着多个应用程序,但是只有屏幕最前面的应用程序才可以接收到输入事件,谁来告诉输入事件哪个是运行在屏幕最前面的应用程序呢?

2.1 引入WindowServiceManager窗口管理服务

  • 对于每一个应用程序,WindowServiceManager都有一个结构体WindowSate来表示该应用程序。假设新启动一个APP,通过binder通信,调用addToDisplay,会导致AddWindow被调用,AddWindow创建了WindowSate表示该应用程序,接着创建一个socketpair得到两个文件句柄fd0和fd1,fd1直接返回给应用程序,fd0将其封装为InputChannel类,一方面InputChannel会放进该APPWindowState中,另外一方面,他会将InputChannel注册给InputDispatch。

2.2 Dispatch线程

  • InputDispatch线程中里面有KeyedVector包含含有多个connection,这些connection可以通过注册实现,创建一个connection(含有InputChannel,InputChannel含有文件句柄fd),将创建好的connection放入Vector当中。
// All registered connections mapped by channel file descriptor.
KeyedVector<int, sp<Connection> > mConnectionsByFd;

2.3 引入connection

  • 对于每一个能够接受输入事件应用程序,在InputDispatch当中都有一个connection。假设还有一个应用程序APP,在WindowServiceManager中也有一个WindowState,在InputDispatch中也有一个对应的connection,放入Vector容器中,在connection中含有InputChannel和fd,其中fd来自Socketpair的fd0,另外一个fd1通过Binder通信返回给APP4。这样子InputDispatch线程想把输入事件发送给APP时候,先要找出当前在屏幕最前面的应用程序,然后从vector容器中找到他的connection,然后将数据写入fd当中既可。

2.4 总结

  • Dispatch线程从输入事件中读到数据后,可以通过Vector当中找出某个connection,把输入事件放入fd当中,另外一个应用程序可以从另外一个文件句柄中得到输入事件,将得到的文件句柄封装为InputChannel,再封装为WindowInputEventReceiver,最后把fd放入Looper中,使用Epoll机制查询等待数据,具体可以见下面关系图。

2.5 补充

  • InputReader线程、InputDispatch线程和WindowServiceManager都处于System进程当中,故这三个线程可以直接通信不需要Binder介入,而APP如果想跟这三个线程通信则需要通过Binder机制来实现或者通过事先建立好的Socketpair再通过Binder将文件句柄返回给APP,故其文件句柄可能发生变化。

3. APP获得SocketPair的fd过程分析

  • 发起addToDisplay的操作
ViewRootImpl.java
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mInputChannel);
  • 导致同文件下的onTransact被调用
IWindowSession.java
mRemote.transact(Stub.TRANSACTION_addToDisplay, _data, _reply, 0);
  • 根据code值调用本地的addToDisplay
IWindowSession.java
int _result = this.addToDisplay(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6);
- 得到两个文件句柄
Session.java
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets,
InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outInputChannel);
}
WindowManagerService.java
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
- 把fd1写给InputChanne
WindowManagerService.java
inputChannels[1].transferTo(outInputChannel); //outInputChannel含有fd1,实际上就是arg6
  • 根据_arg6的返回结果,把fd写给Binder驱动程序
IWindowSession.java
_arg6.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
- 最终调用该函数把fd写入bind驱动中
android_view_InputChannel.cpp
parcel->writeDupFileDescriptor(inputChannel->getFd());
  • 远程操作之后,从驱动程序读出fd
outContentInsets.readFromParcel(_reply);
- 从Binder驱动中读出fd
android_view_InputChannel.cpp
int rawFd = parcel->readFileDescriptor();
int dupFd = dup(rawFd);

4. 具体调用过程时序图

具体源码可以根据下面的时序图进行具体分析。注:引用韦东山老师

Android系统--输入系统(十六)APP跟输入系统建立联系_InputChannel和Connection的更多相关文章

  1. 第十六篇:Linux系统编程中环境变量的使用

    前言 在 UNIX Like 系统中,存有各类系统/应用程序的环境变量,可通过修改之改变系统/应用程序的执行效果:除此之外,用户还可以定义自己的环境变量,供自己写的程序使用. 本文将说明如何在程序中设 ...

  2. 第三十六节,os系统级别操作模块

    在使用os模块时需要先 import os 引入模块 os.getcwd()模块函数 功能:获取当前工作目录,即当前python脚本工作的目录路径[无参] 使用方法:os.getcwd() 格式如:a ...

  3. Android笔记(二十六) Android中的广播——BroadcastReceiver

    为了方便进行系统级别的消息通知,Android有一套类似广播的消息机制,每个应用程序都可以对自己感兴趣的广播进行注册,这样该程序就只会接收自己所关心的广播内容,这些广播可能是来自于系统,也可能是来自于 ...

  4. Android开发系列(十六):【Android小游戏成语连连看】第二篇

    写的晚了,在分工个Z市高中的一个成绩查询的系统,原系统居然是用VB写的,我不得不佩服原本写系统的那位哥们真能耐得住. 明天搭建下SVN就等着先发project款然后開始项目了.想想有工资进账,心里也为 ...

  5. Android核心分析之十六Android电话系统-概述篇

    Android电话系统之概述篇 首先抛开Android的一切概念来研究一下电话系统的最基本的描述.我们的手机首先用来打电话的,随后是需要一个电话本,随后是PIM,随后是网络应用,随后是云计算,随后是想 ...

  6. 【转】Pro Android学习笔记(十六):用户界面和控制(4):ImageView控件

    目录(?)[-] XML片段 代码设置ImageView ImageView是基础的控件,它是android.widget.ImageView的继承类. XML片段      <LinearLa ...

  7. Android学习笔记(十六) ContentProvider

    1.相关概念 ContentProvider:不同应用程序之间进行数据交换的标准API:程序“暴露”数据的方法. ContentResolver:一个程序访问另一个程序被“暴露”的数据的方法. Uri ...

  8. Android笔记(五十六) Android四大组件之一——ContentProvider,实现自己的ContentProvider

    有时候我们自己的程序也需要向外接提供数据,那么就需要我们自己实现ContentProvider. 自己实现ContentProvider的话需要新建一个类去继承ContentProvider,然后重写 ...

  9. Android笔记(四十六) Android中的数据存储——XML(二)PULL解析

    PULL 的工作原理: XML pull提供了开始元素和结束元素.当某个元素开始时,可以调用parser.nextText()从XML文档中提取所有字符数据.当解析到一个文档结束时,自动生成EndDo ...

随机推荐

  1. vmware和centOS的安装

    如果勾上了,会立即在本机开辟20g的空间,需要很长时间 选择电脑中ISO镜像的位置,之后点击开启虚拟机! 这个密码是root用户的密码!管理员密码! 可以选择我们的Minimal没有界面的!

  2. Python教程(2.6)——list和tuple简介

    Python中内置的类型有list和tuple. List list类似于C/C++的数组,可以存储多个数字.例如你可能会需要存储一个班里所有人的名字.这时就可以用到list.list中存储的数据叫做 ...

  3. JavaScript面向对象轻松入门之概述(demo by ES5、ES6、TypeScript)

    写在前面的话 这是一个JavaScript面向对象系列的文章,本篇文章主要讲概述,介绍面向对象,后面计划还会有5篇文章,讲抽象.封装.继承.多态,最后再来一个综合. 说实话,写JavaScript面向 ...

  4. 正则表达式入门案例C#

    ---恢复内容开始--- 在网上百度了好多关于正则表达式的,不过好多都是关于语法的,没有一个具体的案例,有点让人难以入门,毕竟我还是喜欢由具体到抽象的认识.所以我就在这先提供了一个入门小案例(学了了6 ...

  5. javaSE_06Java中的数组(array)-提高练习

    1.求1!+2!+3!+···+30!的和,定义一个方法 public class Test1{ public static void main(String[] args){ //1.求1!+2!+ ...

  6. 机器学习:Python实现聚类算法(三)之总结

    考虑到学习知识的顺序及效率问题,所以后续的几种聚类方法不再详细讲解原理,也不再写python实现的源代码,只介绍下算法的基本思路,使大家对每种算法有个直观的印象,从而可以更好的理解函数中参数的意义及作 ...

  7. Java中SimpleDateFormat用法详解

    所有已实现的接口: Serializable, Cloneable SimpleDateFormat 是一个以与语言环境有关的方式来格式化和解析日期的具体类.它允许进行格式化(日期 -> 文本) ...

  8. 匿名属性 anonymous property

    利用匿名属性可以用很简洁的语法来自动声明不可变(immutable)的元组(tuple)类型. 属性:在字段用来表示类型和对象的状态的前提下,希望状态不被随意的更改,字段一般应该设置为private, ...

  9. 浅析TCP/IP 协议

    TCP/IP协议不是TCP和IP这两个协议的合称,而是指因特网整个TCP/IP协议族. TCP/IP协议模块关系 从协议分层模型方面来讲,TCP/IP由四个层次组成:网络接口层.网络层.传输层.应用层 ...

  10. 获取当前 系统时间 + 获取当前URL 键值;

    一://系统当前时间 function show(){ var mydate = new Date(); var str = "" + mydate.getFullYear() + ...