1. openInputChannelPair(

阅读本文的前提条件是知道匿名管道和匿名共享内存是怎么一回事,否则阅读相应的文章。

Anonymous pipes 和Anonymous Shared Memory。

首先ViewRoot的SetView方法中的关键地方:

第一处是创建:

  1. mInputChannel = new InputChannel();
  2. try {
  3. res = sWindowSession.add(mWindow, mWindowAttributes,
  4. getHostVisibility(), mAttachInfo.mContentInsets,
  5. mInputChannel);

第二处是注册:

  1. InputQueue.registerInputChannel(mInputChannel, mInputHandler,
  2. Looper.myQueue());

创建部分的第一个方法InputChanel()构造函数是个空函数。重要的是第二个函数,

  1. res = sWindowSession.add(mWindow, mWindowAttributes,
  2. getHostVisibility(), mAttachInfo.mContentInsets,
  3. mInputChannel);

这个函数调用的是系统服务,所谓的系统服务,就是运行在SYstem进程的服务程序。代码进入到了android系统服务进程的WindowManagerService类的Session类的add方法,下面是add方法:

  1. public int add(IWindow window, WindowManager.LayoutParams attrs,
  2. int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) {
  3. return addWindow(this, window, attrs, viewVisibility, outContentInsets,
  4. outInputChannel);
  5. }

add调用addWindow,下面进入addWindow,addWindow比较长,仅仅列出重要的几行代码:

  1. if (outInputChannel != null) {
  2. String name = win.makeInputChannelName();
  3. InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
  4. win.mInputChannel = inputChannels[0];
  5. inputChannels[1].transferToBinderOutParameter(outInputChannel);
  6. mInputManager.registerInputChannel(win.mInputChannel);
  7. }

这里就牵涉到了匿名管道了,进入OpenInputChannelPair来看,调用了nativeOpenInputChannelPair,下面看nativeOpenInputChannelPair做了什么事情:

  1. static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
  2. jclass clazz, jstring nameObj) {
  3. const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
  4. String8 name(nameChars);
  5. env->ReleaseStringUTFChars(nameObj, nameChars);
  6. sp<InputChannel> serverChannel;
  7. sp<InputChannel> clientChannel;
  8. status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
  9. }

最重要的是

status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);这一行

  1. status_t InputChannel::openInputChannelPair(const String8& name,
  2. sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
  3. status_t result;
  4. int serverAshmemFd = ashmem_create_region(name.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
  5. if (serverAshmemFd < 0) {
  6. result = -errno;
  7. LOGE("channel '%s' ~ Could not create shared memory region. errno=%d",
  8. name.string(), errno);
  9. } else {
  10. result = ashmem_set_prot_region(serverAshmemFd, PROT_READ | PROT_WRITE);
  11. if (result < 0) {
  12. LOGE("channel '%s' ~ Error %d trying to set protection of ashmem fd %d.",
  13. name.string(), result, serverAshmemFd);
  14. } else {
  15. // Dup the file descriptor because the server and client input channel objects that
  16. // are returned may have different lifetimes but they share the same shared memory region.
  17. int clientAshmemFd;
  18. clientAshmemFd = dup(serverAshmemFd);
  19. if (clientAshmemFd < 0) {
  20. result = -errno;
  21. LOGE("channel '%s' ~ Could not dup() shared memory region fd. errno=%d",
  22. name.string(), errno);
  23. } else {
  24. int forward[2];
  25. if (pipe(forward)) {
  26. result = -errno;
  27. LOGE("channel '%s' ~ Could not create forward pipe.  errno=%d",
  28. name.string(), errno);
  29. } else {
  30. int reverse[2];
  31. if (pipe(reverse)) {
  32. result = -errno;
  33. LOGE("channel '%s' ~ Could not create reverse pipe.  errno=%d",
  34. name.string(), errno);
  35. } else {
  36. String8 serverChannelName = name;
  37. serverChannelName.append(" (server)");
  38. outServerChannel = new InputChannel(serverChannelName,
  39. serverAshmemFd, reverse[0], forward[1]);
  40. String8 clientChannelName = name;
  41. clientChannelName.append(" (client)");
  42. outClientChannel = new InputChannel(clientChannelName,
  43. clientAshmemFd, forward[0], reverse[1]);
  44. return OK;
  45. }
  46. ::close(forward[0]);
  47. ::close(forward[1]);
  48. }
  49. ::close(clientAshmemFd);
  50. }
  51. }
  52. ::close(serverAshmemFd);
  53. }
  54. outServerChannel.clear();
  55. outClientChannel.clear();
  56. return result;
  57. }

这段代码又长又臭,总而言之就是创建用来【发送和接受信号】的接受和发送描述符,和生成用来【传递事件】的匿名共享内存,生成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。

Android输入输出机制之来龙去脉的更多相关文章

  1. Android随笔之——Android广播机制Broadcast详解

    在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,如果某个程序接收了这个广播,就会做相应的处理.这个广播跟我们传统意义中的电台广播有些相似之处.之所以叫做广播,就 ...

  2. Android广播机制的深入学习

    部分内容转载自http://www.cnblogs.com/lwbqqyumidi/p/4168017.html 1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者 ...

  3. Android签名机制

    Android APK 签名比对 发布过Android应用的朋友们应该都知道,Android APK的发布是需要签名的.签名机制在Android应用和框架中有着十分重要的作用. 例如,Android系 ...

  4. (转)Android消息处理机制(Handler、Looper、MessageQueue与Message)

    转自 http://www.cnblogs.com/angeldevil/p/3340644.html Android消息处理机制(Handler.Looper.MessageQueue与Messag ...

  5. Android消息机制

    每一个Android应用在启动的时候都会创建一个线程,这个线程被称为主线程或者UI线程,Android应用的所有操作默认都会运行在这个线程中. 但是当我们想要进行数据请求,图片下载,或者其他耗时操作时 ...

  6. Android总结篇系列:Android广播机制

    1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器).广播作为Android组件间的通 ...

  7. 理解Android安全机制

    本文从Android系统架构着手,分析Android的安全机制以SE Android,最后给出一些Android安全现状和常见的安全解决方案. 1.Android系统架构 Android采用分层的系统 ...

  8. 【Android 开发】: Android 消息处理机制之一: Handler 与 Message

    最近几讲内容,我们学习了Android中关于多线程的一些知识,上一讲我们讲解了异步任务 AsyncTask 的操作,Android中还提供了其他的线程操作,如Handler Message Messa ...

  9. Android消息机制:Looper,MessageQueue,Message与handler

    Android消息机制好多人都讲过,但是自己去翻源码的时候才能明白. 今天试着讲一下,因为目标是讲清楚整体逻辑,所以不追究细节. Message是消息机制的核心,所以从Message讲起. 1.Mes ...

随机推荐

  1. STL六大组件之——算法小小小小的解析

    参考自侯捷的<stl源码剖析> stl算法主要分为非可变序列算法(指不直接修改其所操作的容器内容的算法),可变序列算法(指可以修改它们所操作的容器内容的算法),排序算法(包括对序列进行排序 ...

  2. bzoj2940: [Poi2000]条纹

    2940: [Poi2000]条纹 条纹游戏是一个双人的游戏.所需要的物品有一个棋盘以及三种颜色的长方形条纹,这三种颜色分别是红色.绿色和蓝色.所有的红色条纹的尺寸是c*1,所有的绿色条纹的尺寸是z* ...

  3. 成为IBM精英讲师-一分耕耘 一份收获 同时也多了一份责任!

    成为IBM精英讲师 一分耕耘 一份收获 同时也多了一份责任! http://www.webspherechina.net/?action-iste-type-lecturerlist 650) thi ...

  4. ICON的设计很重要

    ICON的设计很重要 发布者: wuye | 发布时间: 2014-12-19 17:45| 评论数: 0 游戏类型:手游游戏/平板游戏  设计类型:[功能/模块/UI] 作者:小金狮的UI分享 每个 ...

  5. Speex for Android

    http://blog.csdn.net/chenfeng0104/article/details/7088138在Android开发中,需要录音并发送到对方设备上.这时问题来了,手机常会是GPRS. ...

  6. redhat6.4升级openssh至6.7

    1:简介 最近浙江电信对线上服务器进行漏洞扫描,暴露出原有的openssh有漏洞,建议升级openssh版本: 2:操作环境 Red Hat Enterprise Linux Server relea ...

  7. getGuid()

    function GetGUID: string;var  LTep: TGUID;begin  CreateGUID(LTep);  Result := GUIDToString(LTep);  R ...

  8. Python输入输出(IO)

    程序会有输入和输出,输入可以从标准输入或是从一个文件读入数据,程序的输出可以以一种友好可读的方式(human-readable)打印出来,或是写进一个文件,而标准输入和标准输出(键盘和显示器)在程序的 ...

  9. ASP.NET的分页方法(二)

    第二讲主要使用到了常用的分页控件aspnetpager,这里对他就行一个简单的应用,具体大家可以到杨涛的博客上去寻找相关的DLL, 首先要先引用AspNetPager.dll,然后把这个DLL同时添加 ...

  10. Jquery 获取文件内容

    $('.ke-edit-iframe').contents().find('body').text() <iframe class="ke-edit-iframe" hide ...