前面的“锤子快捷键”相关文章已经分析了输入事件的读取,处理,分发。我们知道事件的传递是以window为单位传递的,即server只负责将事件传递给某一个或者多个window,window然后再将事件传递给某一个具体的view。一个activity或者dialog对应一个window,但是事件只传递给合适的window,比如对于按键事件,就必须是获得焦点的window,也就是说只能传递给一个window,通常是最上面的程序。找到了合适的window,然后就是将事件添加到window的Connection的事件队列上。其实,到这为止输入事件还只是在server端,即system_server这个进程里,要想让程序获取到事件,肯定必须将事件信息传递到程序端的进程里。这个就是Connection的实现问题了,这个connection的真正逻辑是InputChannel, InputChannel其实就是linux unix socket的一种封装, unixsocket是linux的一种跨进程通信方式。系统创建InputChannel对即unix socket对,系统server端和程序client各只有其中一个,这样通过unix socket就可以给对方发送消息,而这里的事件就是通过这种方式从系统进程传递到程序进程的。整个系统框架图如下:



系统server端的InputChannel

系统InputChannel的整个处理逻辑如下:

Server端 InputChannel的创建

Server端 InputChannel是在window被创建的时候创建的:

    //addWindow会创建一个channel对,其实上就是unix socket对,其中一个unix socket
//通过传入参数outInputChannel被传递到程序端,
//另外一个unix socket保存在server的window中并注册到native的InputManager
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, InputChannel outInputChannel) {
//创建window的数据对象WindowState
win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
if (outInputChannel != null && (attrs.inputFeatures &
WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
String name = win.makeInputChannelName();
//创建channel对,即会返回两个InputChannel
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
//一个unix socket保存到window里
win.setInputChannel(inputChannels[0]);
//另外一个unix socket传递到程序端
inputChannels[1].transferTo(outInputChannel);
//这个函数很重要,这个会将server端的unix socket注册到native层
//的InputManager, win.mInputChannel就是上面的inputChannels[0]
mInputManager.registerInputChannel(win.mInputChannel,
win.mInputWindowHandle);
}
}
return res;
}

public static InputChannel[] openInputChannelPair(String name) {
return nativeOpenInputChannelPair(name);
}

static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
jclass clazz, jstring nameObj) {
sp<InputChannel> serverChannel;
sp<InputChannel> clientChannel;
//创建input channel对
status_t result = InputChannel::openInputChannelPair(name,
serverChannel, clientChannel);
jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
//创建inputChannel对应的java对象
jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
new NativeInputChannel(serverChannel));
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
new NativeInputChannel(clientChannel));
//将两个channel放到channel数组中
env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
return channelPair;
}
//InputTransport.cpp
status_t InputChannel::openInputChannelPair(const String8& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
int sockets[2];
//很早的android 版本是使用双向管道实现的,而是现在是使用unix socket双通道
//来通信
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
return result;
}

int bufferSize = SOCKET_BUFFER_SIZE;
setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));

String8 serverChannelName = name;
serverChannelName.append(" (server)");
//创建InputChannel,并把通信文件句柄传入
outServerChannel = new InputChannel(serverChannelName, sockets[0]);

String8 clientChannelName = name;
clientChannelName.append(" (client)");
//创建InputChannel,并把通信文件句柄传入
outClientChannel = new InputChannel(clientChannelName, sockets[1]);
return OK;
}

Server端 InputChannel事件监听器安装

InputDispatcher要能够发送事件数据,必须的要让其知道对应的window的InputChannel,这个通过注册实现的。

public void registerInputChannel(InputChannel inputChannel,
InputWindowHandle inputWindowHandle) {
nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
}

status_t NativeInputManager::registerInputChannel(JNIEnv* env,
const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
//调用InputDispatcher的函数
return mInputManager->getDispatcher()->registerInputChannel(
inputChannel, inputWindowHandle, monitor);
}

status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
{ // acquire lock
AutoMutex _l(mLock);
//这个将inputChannel封装为Connection
sp<Connection> connection = new Connection(inputChannel,
inputWindowHandle, monitor);
//这个就是unix socket文件句柄
int fd = inputChannel->getFd();
//将connection保存到映射表中
mConnectionsByFd.add(fd, connection);
//监听该unix socket文件,当unix socket有数据时即client发送消息过来了,
//函数handleReceiveCallback就会被执行
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock

// Wake the looper because some connections have changed.
mLooper->wake();
return OK;
}

Server端的InputChannel事件数据发送

在上几篇文章“锤子快捷键配置”中,已经讲到了事件分发,并最后将事件放到了connection的事件队列中,InputChannel事件发送就是从开始的
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
bool wasEmpty = connection->outboundQueue.isEmpty();
// Enqueue dispatch entries for the requested modes.
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_IS);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);

// 原来是空,现在不空,则立刻分发事件
if (wasEmpty && !connection->outboundQueue.isEmpty()) {
startDispatchCycleLocked(currentTime, connection);
}
}

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
//遍历所有发送队列中的事件
while (connection->status == Connection::STATUS_NORMAL
&& !connection->outboundQueue.isEmpty()) {
//获取最早的需要发送的事件
DispatchEntry* dispatchEntry = connection->outboundQueue.head;
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);

//真正发送事件.
status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
keyEntry->deviceId, keyEntry->source,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
keyEntry->keyCode, keyEntry->scanCode,
keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
keyEntry->eventTime);
break;
}

// Check the result.
if (status) {
if (status == WOULD_BLOCK) {
if (connection->waitQueue.isEmpty()) {
} else {
connection->inputPublisherBlocked = true;
}
}
//发送成功,返回执行下一次循环
return;
}

// 事件发送失败,重新放进待发送队列
connection->outboundQueue.dequeue(dispatchEntry);
connection->waitQueue.enqueueAtTail(dispatchEntry);
}
}

status_t InputPublisher::publishKeyEvent(
uint32_t seq,
int32_t deviceId,
int32_t source,
int32_t action,
int32_t flags,
int32_t keyCode,
int32_t scanCode,
int32_t metaState,
int32_t repeatCount,
nsecs_t downTime,
nsecs_t eventTime) {
InputMessage msg;
//将输入事件转化为unix socket通信的格式
msg.header.type = InputMessage::TYPE_KEY;
msg.body.key.seq = seq;
msg.body.key.deviceId = deviceId;
msg.body.key.source = source;
msg.body.key.action = action;
msg.body.key.flags = flags;
msg.body.key.keyCode = keyCode;
msg.body.key.scanCode = scanCode;
msg.body.key.metaState = metaState;
msg.body.key.repeatCount = repeatCount;
msg.body.key.downTime = downTime;
msg.body.key.eventTime = eventTime;
//调用unix socket消息发送机制
return mChannel->sendMessage(&msg);
}

status_t InputChannel::sendMessage(const InputMessage* msg) {
size_t msgLength = msg->size();
ssize_t nWrite;
do {
//通过unix socket将事件数据发送到程序端
nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
return OK;
}

程序client端的InputChannel

client的InputChannel相关的处理逻辑如下:

Client 端的InputChannel创建

Client接受事件,肯定必须先获得inputChannel,这个是在addWindow时系统返回回来的。

public void setView(View view, WindowManager.LayoutParams attrs, 
View panelParentView) {
synchronized (this) {
if ((mWindowAttributes.inputFeatures&
WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
try {
//该函数会返回一个InputChannel
res = mWindowSession.addToDisplay(mWindow, mSeq,
mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mInputChannel);
}
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
//为InputChannel注册监听器
mInputEventReceiver = new WindowInputEventReceiver(
mInputChannel,
Looper.myLooper());
}<pre name="code" class="java" style="font-size: 14px;"> }
}

 

Client端的 InputChannel监听器安装

InputChannel监听器安装在WindowInputEventReceiver初始化的时候

final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
}
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);

mCloseGuard.open("dispose");
}

static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
//获取native层的InputChannel
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
//获取java层InputEventReceiver对象的native层的消息队列
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
//创建native对应的InputEventReceiver对象
sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
receiverWeak, inputChannel, messageQueue);
//这个是真正安装监听的函数
status_t status = receiver->initialize();
return reinterpret_cast<jint>(receiver.get());
}


status_t NativeInputEventReceiver::initialize() {
//安装监听器
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}

void NativeInputEventReceiver::setFdEvents(int events) {
if (mFdEvents != events) {
mFdEvents = events;
int fd = mInputConsumer.getChannel()->getFd();
if (events) {
//用looper监听inputChannel对应的unix socket文件句柄
mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
}
}
}

int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) {
return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data);
}

int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
{ // acquire lock
AutoMutex _l(mLock);
//将监听参数封装
Request request;
request.fd = fd;
request.ident = ident;
//这个很重要,当被监听的文件发生变化时就会调用该callback函数
request.callback = callback;
request.data = data;

ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex < 0) {
//epoll该文件,也就是讲unix socket文件添加到监听文件列表中
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
mRequests.add(fd, request);
}
} // release lock
return 1;
}


Client端的InputChannel中的事件接收

从上面可以看出,Java的InputEventReceiver层的native层的NativeInputEventReceiver负责监听事件,当有事件时,就会调用它。

int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for (;;) {
while (mResponseIndex < mResponses.size()) {
const Response& response = mResponses.itemAt(mResponseIndex++);
int ident = response.request.ident;
if (ident >= 0) {
int fd = response.request.fd;
int events = response.events;
void* data = response.request.data;
if (outFd != NULL) *outFd = fd;
if (outEvents != NULL) *outEvents = events;
if (outData != NULL) *outData = data;
return ident;
}
}
result = pollInner(timeoutMillis);
}
}

int Looper::pollInner(int timeoutMillis) {
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
//等待消息
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeReadPipeFd) {
if (epollEvents & EPOLLIN) {
awoken();
}
} else {
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex >= 0) {
int events = 0;
if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;
if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
//将事件放到事件队列上
pushResponse(events, mRequests.valueAt(requestIndex));
}
}
}
Done: ;
//处理前面加入的response事件
for (size_t i = 0; i < mResponses.size(); i++) {
Response& response = mResponses.editItemAt(i);
if (response.request.ident == ALOOPER_POLL_CALLBACK) {
int fd = response.request.fd;
int events = response.events;
void* data = response.request.data;
// 下面的callback就是 NativeInputEventRecieverd
int callbackResult = response.request.callback->handleEvent(fd, events, data);
if (callbackResult == 0) {
removeFd(fd);
}
response.request.callback.clear();
result = ALOOPER_POLL_CALLBACK;
}
}
return result;
}


int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {

if (events & ALOOPER_EVENT_INPUT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
//处理事件
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
return status == OK || status == NO_MEMORY ? 1 : 0;
}
return 1;
}

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
for (;;) {
uint32_t seq;
InputEvent* inputEvent;
//从buffer中还原出事件
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
if (!skipCallbacks) {
jobject inputEventObj;
switch (inputEvent->getType()) {
case AINPUT_EVENT_TYPE_KEY:
//转换为java层的InputEvent
inputEventObj = android_view_KeyEvent_fromNative(env,
static_cast<KeyEvent*>(inputEvent));
break;
}
if (inputEventObj) {
//这个就会调用到java层的函数InputEventReceiver->dispatchInputEvent
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq,
inputEventObj);
}
}
}
}

Client端对输入事件的处理

到此为止,事件开始传递到了JAVA层了,然后就是JAVA层开始对事件进行处理,我们通常接触的事件处理也是在java层实现的,这个将在下一篇介绍。


/********************************

* 本文来自博客 “爱踢门”

* 转载请标明出处:http://blog.csdn.net/itleaks

******************************************/

更多相关文章

  1. android 模拟键盘鼠标事件(adb shell)
  2. 防止回收利用触摸事件
  3. android里通过什么什么事件可以拿到由于click后的EditText的光标
  4. java中的事件监听问题,如何将菜单项与组合框相关联
  5. java中的大事件
  6. Javascript 事件对象(六)事件默认行为
  7. javaweb常用监听器
  8. javascript(六)js事件绑定浏览器兼容解决方案 attachEvent addEve
  9. 在JComboBox箭头JButton上附加动作事件

随机推荐

  1. Android属性系统
  2. 收货地址
  3. Android实例收藏
  4. Android获得电话本中的数据(ContentProvid
  5. Android(安卓)Studio 0.8 下载
  6. android:configChanges属性,横竖屏切换
  7. android带有文字的图片按钮的两种实现方
  8. Spring Roo
  9. This Android SDK requires And...te ADT
  10. 基于蓝牙socket开发Android蓝牙通信