您的位置:首页 > 移动开发 > Android开发

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

2017-08-07 10:24 357 查看
openInputChannelPair(

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

Anonymous pipes

和Anonymous Shared Memory。

 

首先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。

 

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: