openInputChannelPair(
阅读本文的前提条件是知道匿名管道和匿名共享内存是怎么一回事,否则阅读相应的文章。
Anonymous pipes 和Anonymous Shared Memory。
共享内存缓冲区大小,大概缓存20个触屏事件。
framework/base/include/ui/Input.h /* * Maximum number of pointers supported per motion event. * Smallest number of pointers is 1. * (We want at least 10 but some touch controllers obstensibly configured for 10 pointers * will occasionally emit 11. There is not much harm making this constant bigger.) */ #define MAX_POINTERS 16 framework/base/libs/ui/InputTransport.cpp #define ROUND_UP(value, boundary) (((value) + (boundary) - 1) & ~((boundary) - 1)) #define MIN_HISTORY_DEPTH 20 // Must be at least sizeof(InputMessage) + sufficient space for pointer data static const int DEFAULT_MESSAGE_BUFFER_SIZE = ROUND_UP( sizeof(InputMessage) + MIN_HISTORY_DEPTH * (sizeof(InputMessage::SampleData) + MAX_POINTERS * sizeof(PointerCoords)), 4096);
JNI文件记录
InputQueue.java
android_view_InputQueue.cpp
android_view_InputChannel.cpp
InputManager.java
com_android_server_InputManager.cpp
framework/base/services/input/InputManager.h
framework/base/services/input/InputManager.cpp
framework/base/services/input/InputDispatcher.cpp
framework/base/services/input/InputDispatcher.cpp
framework/base/libs/ui/InputTransport.cpp
首先ViewRoot的SetView方法中的关键地方:
第一处是创建:
mInputChannel = new InputChannel(); try { res = sWindowSession.add(mWindow, mWindowAttributes, getHostVisibility(), mAttachInfo.mContentInsets, mInputChannel); }
第二处是注册:
InputQueue.registerInputChannel(mInputChannel, mInputHandler, Looper.myQueue());
创建部分的第一个方法InputChanel()构造函数是个空函数。重要的是第二个函数,
res = sWindowSession.add(mWindow, mWindowAttributes, getHostVisibility(), mAttachInfo.mContentInsets, mInputChannel);
这个函数调用的是系统服务,所谓的系统服务,就是运行在SYstem进程的服务程序。代码进入到了android系统服务进程的WindowManagerService类的Session类的add方法,下面是add方法:
public int add(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) { return addWindow(this, window, attrs, viewVisibility, outContentInsets, outInputChannel); }
add调用addWindow,下面进入addWindow,addWindow比较长,仅仅列出重要的几行代码:
if (outInputChannel != null) { String name = win.makeInputChannelName(); InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); win.mInputChannel = inputChannels[0]; inputChannels[1].transferToBinderOutParameter(outInputChannel); mInputManager.registerInputChannel(win.mInputChannel); }
这里就牵涉到了匿名管道了,进入OpenInputChannelPair来看,调用了nativeOpenInputChannelPair,下面看nativeOpenInputChannelPair做了什么事情:
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env, jclass clazz, jstring nameObj) { const char* nameChars = env->GetStringUTFChars(nameObj, NULL); String8 name(nameChars); env->ReleaseStringUTFChars(nameObj, nameChars); sp<InputChannel> serverChannel; sp<InputChannel> clientChannel; status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel); }
最重要的是
status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);这一行
status_t InputChannel::openInputChannelPair(const String8& name, sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) { status_t result; int serverAshmemFd = ashmem_create_region(name.string(), DEFAULT_MESSAGE_BUFFER_SIZE); if (serverAshmemFd < 0) { result = -errno; LOGE("channel '%s' ~ Could not create shared memory region. errno=%d", name.string(), errno); } else { result = ashmem_set_prot_region(serverAshmemFd, PROT_READ | PROT_WRITE); if (result < 0) { LOGE("channel '%s' ~ Error %d trying to set protection of ashmem fd %d.", name.string(), result, serverAshmemFd); } else { // Dup the file descriptor because the server and client input channel objects that // are returned may have different lifetimes but they share the same shared memory region. int clientAshmemFd; clientAshmemFd = dup(serverAshmemFd); if (clientAshmemFd < 0) { result = -errno; LOGE("channel '%s' ~ Could not dup() shared memory region fd. errno=%d", name.string(), errno); } else { int forward[2]; if (pipe(forward)) { result = -errno; LOGE("channel '%s' ~ Could not create forward pipe. errno=%d", name.string(), errno); } else { int reverse[2]; if (pipe(reverse)) { result = -errno; LOGE("channel '%s' ~ Could not create reverse pipe. errno=%d", name.string(), errno); } else { String8 serverChannelName = name; serverChannelName.append(" (server)"); outServerChannel = new InputChannel(serverChannelName, serverAshmemFd, reverse[0], forward[1]); String8 clientChannelName = name; clientChannelName.append(" (client)"); outClientChannel = new InputChannel(clientChannelName, clientAshmemFd, forward[0], reverse[1]); return OK; } ::close(forward[0]); ::close(forward[1]); } ::close(clientAshmemFd); } } ::close(serverAshmemFd); } outServerChannel.clear(); outClientChannel.clear(); return result; }
这段代码又长又臭,总而言之就是创建用来【发送和接受信号】的接受和发送描述符,和生成用来【传递事件】的匿名共享内存,生成InputChannel对象。创建好之后,AddWindow方法通过BInder机制返回给【用户进程】。 客户端对应的是【应用程序】(读),服务端对应的是【InputDispatcher】(写)。
理解本段代码的关键是:代码中的 reverse和forward是相对于server来说的。对于server来说,后向管道用来接收,前向管道用来发送。函数pipe出来的值,数组的0索引对应的描述符是发送端。1对应的是接收端。
上面的介绍基本上就结束了。后面也许,我们更想知道的是这两个InputChannel如何通信的。一个在ViewRoot中,一个在InputDiapacher中。通信方式几本上就是,
InputReader(InputReader.cpp中)启动无限循环,读取一个事件,发送给InputDispacher,InputDispatcher把事件写入到共享内存,并通过管道发送信号给ViewRoot中的InputChannel,InputChannel收到信号后,通过InputConsumer的consume方法来把事件发送给VIewRoot中的InputChannel。
相关推荐
### MFC源码剖析之——MFC来龙去脉 #### 一、MFC与传统C/SDK程序对比 在Windows编程中,开发者通常有两种选择:一种是使用Microsoft Foundation Classes (MFC),另一种则是直接使用Windows API(通常称为C/SDK编程...
这是因为Android的内存管理机制——Generational Heap Memory模型,当对象在年轻代(Young Generation)存活一段时间后,会逐渐晋升到老年代(Old Generation)和永久代(Permanent Generation)。一旦发生内存泄露...
本章介绍Android的来龙去脉,让读者以最短的时间直观地了解到Android的基础及发展的历史和趋势,并能清晰地知到自己可以在Android上做什么事情。 第2章 工欲善其事 必先利其器—搭建Android开发环境。本章介绍了在...
本章介绍Android的来龙去脉,让读者以最短的时间直观地了解到Android的基础及发展的历史和趋势,并能清晰地知到自己可以在Android上做什么事情。 第2章 工欲善其事 必先利其器—搭建Android开发环境。本章介绍了在...
本章介绍Android的来龙去脉,让读者以最短的时间直观地了解到Android的基础及发展的历史和趋势,并能清晰地知到自己可以在Android上做什么事情。 第2章 工欲善其事 必先利其器—搭建Android开发环境。本章介绍了在...
在“参考资料-斜坡补偿到的来龙去脉与实例.pdf”中,很可能会详细阐述斜坡补偿的发展历程,包括其早期的应用、理论基础,以及随着时间的推移和技术的进步,如何演变成现代控制系统中不可或缺的一部分。此外,该文档...
### MFC源码剖析之——MFC来龙去脉 #### MFC的起源与核心概念 MFC(Microsoft Foundation Classes)是由微软开发的一套用于Windows平台的C++类库,它封装了Windows API,简化了GUI应用程序的开发过程。通过使用MFC...
企业文化的来龙去脉
### X86指令编码的来龙去脉:深入解析与理解 #### 1、序言:初探X86指令编码 X86指令集架构是个人计算机领域中最广泛使用的指令集之一,其指令编码机制复杂而精细,是实现硬件与软件间桥梁的关键。在学习X86指令...
构件化编程的来龙去脉.ppt,构件编程详细解释
文档有Android、iOS、和后台服务器端,还是非常全的。 环信官网:http://www.easemob.com/ 本篇文章目的主要在于说明环信Demo如何实现即时通信的。我在集成环信SDK到我们自己开发的app之前,研究了一下环信demo的...
### MFC来龙去脉:深入理解MFC框架与Windows编程 #### MFC的历史与背景 MFC(Microsoft Foundation Classes)是微软为简化Windows应用程序开发而设计的一套类库,它基于C++语言,提供了对Windows API的封装,使得...
Android例子源码多种图片渲染处理源码是一款图片处理器的项目源码,类似美颜相机的各种处理照片一样,本项目也有多种处理照片的形式,比美颜相机有过之而无不及,而且它更增加了变形,扭曲等等让照片更加丰富多彩。...
在探讨丞相的来龙去脉时,我们不仅要了解其词源,更要从历史的发展脉络中,把握其职权的变迁和在中国政治史中的地位。 “丞相”一词中的“丞”在《说文解字》中解释为“帮助、辅助”。在古代官职中,“丞”往往是指...
系统组网图是整个机制的核心,它展示了从信息采集到处理,再到最终输出分析报告的整个工作流程。这个流程涉及多个技术组件的协同工作,包括深度多渠道的网络信息采集、信息预处理机制、索引分词机制、热点舆情识别、...
中华文明外来论的来龙去脉.docx