欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新

Android输入输出机制之来龙去脉,android输入输出

来源: 开发者 投稿于  被查看 44760 次 评论:288

Android输入输出机制之来龙去脉,android输入输出


Java代码  收藏代码
  1. openInputChannelPair(  

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

Anonymous pipes 和Anonymous Shared Memory。

 

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

 

第一处是创建:

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

第二处是注册:

 

Java代码  收藏代码
  1. InputQueue.registerInputChannel(mInputChannel, mInputHandler,  
  2.                            Looper.myQueue());  

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

Java代码  收藏代码
  1. res = sWindowSession.add(mWindow, mWindowAttributes,  
  2.         getHostVisibility(), mAttachInfo.mContentInsets,  
  3.         mInputChannel);  

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

 

Java代码  收藏代码
  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比较长,仅仅列出重要的几行代码:

 

Java代码  收藏代码
  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.       
  7.     mInputManager.registerInputChannel(win.mInputChannel);  
  8. }  

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

 

Cpp代码  收藏代码
  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.   
  7.     sp<InputChannel> serverChannel;  
  8.     sp<InputChannel> clientChannel;  
  9.     status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);  
  10. }  

 最重要的是

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

 

 

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

 

   这段代码又长又臭,总而言之就是创建用来【发送和接受信号】的接受和发送描述符,和生成用来【传递事件】的匿名共享内存,生成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消息处理机制的问题 来解析一下

下面和大家分享一下android中非常重要的消息处理机制,说到消息处理,Message,MessageQueue,Looper,Handler这四个类的作用是我们必须要明白的。

下面分别谈谈他们的作用:

MessageQueue

MessageQueue表示消息队列,存放消息的地方,按照“先进先出”的规则执行,每一个线程只可以拥有一个MessageQueue。当创建Looper对象的时候会创建一个MessageQueue对象。

Message

Message表示消息对象,MessageQueue中存放的对象,一个MessageQueue中可以存放多个Message对象。通过调用Message类的obtain()方法或者调用Handler类的obtainMessage()方法获取Message对象,但是这样并不一定会创建一个新的Message对象,如果消息池中有可用的Message对象则直接取出返回这个对象,否则如果消息池中没有可用的Message对象,则会创建一个新的Message对象。当消息队列中的Message对象被系统处理完之后,该Message对象会从MessageQueue中删除,然后放入消息池中。

Looper

Looper是用来操作MessageQueue的,每一个Looper对应一个MessageQueue,可以通过调用Looper.myLooper()方法获取当前线程的Looper对象,Looper循环从MessageQueue中取出Message对象,交给Handler调用handleMessage方法进行处理,处理完之后Message对象被放入消息池中。

Handler

Handler是消息的处理者,Handler将需要传递的信息封装成Message对象,然后调用sendMessage方法将Message放入MessageQueue中,当MessageQueue循环到该Message时,调用相应Handler对象的handleMessage方法对其进行处理。 d-android.com/developer/
注意在UI线程也就是主线程中默认会创建Looper对象和MessageQueue对象,如果在我们自己新开的线程中要进行消息处理,必须创建Looper对象和MessageQueue对象,通过调用Looper.prepare()方法可以创建Looper对象和MessageQueue对象,调用Looper.loop()方法可以启动消息循环队列。
这里 d-android.com/developer/thread-25343-1-1.html还有个例子,你可以参照一下,求给分啊!!!
 

android handler机制的原理

andriod提供了 Handler 和 Looper 来满足线程间的通信。
Handler 先进先出原则。
Looper类用来管理特定线程内对象之间的消息交换(Message Exchange)。

  1)Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的Message Queue(消息队列)。

  2)Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到Message Queue里;或者接收Looper从Message Queue取出)所送来的消息。

  3) Message Queue(消息队列):用来存放线程放入的消息。

  4)线程:UI thread 通常就是main thread,而Android启动程序时会替它建立一个Message Queue。
 

用户评论