大学IT网 - 最懂大学生的IT学习网站! QQ资料交流群:367606806
当前位置:大学IT网 > Android技巧 > Android输入输出机制之来龙去脉

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

关键词:来龙去脉输入输出机制Android  阅读(537) 赞(14)

[摘要]本文是对Android输入输出机制之来龙去脉的讲解,对学习Android编程技术有所帮助,与大家分享。
Java代码
openInputChannelPair(

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

Anonymous pipes和Anonymous Shared Memory。

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

第一处是创建:

Java代码
mInputChannel=newInputChannel();
try{
res=sWindowSession.add(mWindow,mWindowAttributes,
getHostVisibility(),mAttachInfo.mContentInsets,
mInputChannel);

第二处是注册:

Java代码
InputQueue.registerInputChannel(mInputChannel,mInputHandler,
Looper.myQueue());

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

Java代码
res=sWindowSession.add(mWindow,mWindowAttributes,
getHostVisibility(),mAttachInfo.mContentInsets,
mInputChannel);

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

Java代码
publicintadd(IWindowwindow,WindowManager.LayoutParamsattrs,
intviewVisibility,RectoutContentInsets,InputChanneloutInputChannel){
returnaddWindow(this,window,attrs,viewVisibility,outContentInsets,
outInputChannel);
}

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

Java代码
if(outInputChannel!=null){
Stringname=win.makeInputChannelName();
InputChannel[]inputChannels=InputChannel.openInputChannelPair(name);
win.mInputChannel=inputChannels[0];
inputChannels[1].transferToBinderOutParameter(outInputChannel);

mInputManager.registerInputChannel(win.mInputChannel);
}

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

Cpp代码
staticjobjectArrayandroid_view_InputChannel_nativeOpenInputChannelPair(JNIEnv*env,
jclassclazz,jstringnameObj){
constchar*nameChars=env->GetStringUTFChars(nameObj,NULL);
String8name(nameChars);
env->ReleaseStringUTFChars(nameObj,nameChars);

sp<InputChannel>serverChannel;
sp<InputChannel>clientChannel;
status_tresult=InputChannel::openInputChannelPair(name,serverChannel,clientChannel);
}

最重要的是

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

Cpp代码
status_tInputChannel::openInputChannelPair(constString8&name,
sp<InputChannel>&outServerChannel,sp<InputChannel>&outClientChannel){
status_tresult;

intserverAshmemFd=ashmem_create_region(name.string(),DEFAULT_MESSAGE_BUFFER_SIZE);
if(serverAshmemFd<0){
result=-errno;
LOGE("channel'%s'~Couldnotcreatesharedmemoryregion.errno=%d",
name.string(),errno);
}else{
result=ashmem_set_prot_region(serverAshmemFd,PROT_READ|PROT_WRITE);
if(result<0){
LOGE("channel'%s'~Error%dtryingtosetprotectionofashmemfd%d.",
name.string(),result,serverAshmemFd);
}else{
//Dupthefiledescriptorbecausetheserverandclientinputchannelobjectsthat
//arereturnedmayhavedifferentlifetimesbuttheysharethesamesharedmemoryregion.
intclientAshmemFd;
clientAshmemFd=dup(serverAshmemFd);
if(clientAshmemFd<0){
result=-errno;
LOGE("channel'%s'~Couldnotdup()sharedmemoryregionfd.errno=%d",
name.string(),errno);
}else{
intforward[2];
if(pipe(forward)){
result=-errno;
LOGE("channel'%s'~Couldnotcreateforwardpipe.errno=%d",
name.string(),errno);
}else{
intreverse[2];
if(pipe(reverse)){
result=-errno;
LOGE("channel'%s'~Couldnotcreatereversepipe.errno=%d",
name.string(),errno);
}else{
String8serverChannelName=name;
serverChannelName.append("(server)");
outServerChannel=newInputChannel(serverChannelName,
serverAshmemFd,reverse[0],forward[1]);

String8clientChannelName=name;
clientChannelName.append("(client)");
outClientChannel=newInputChannel(clientChannelName,
clientAshmemFd,forward[0],reverse[1]);
returnOK;
}
::close(forward[0]);
::close(forward[1]);
}
::close(clientAshmemFd);
}
}
::close(serverAshmemFd);
}

outServerChannel.clear();
outClientChannel.clear();
returnresult;
}

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



相关评论