概述
Android在分发Input event(Key, Motion, Pointer,TrackBall)的流程牵扯到的WindowMangerService,ViewRootImpl和InputDispatcherThread三位角色.这三位角色的工作关系会依以下三个阶段来分析.
1. 起源.
2. 指定接受者.
3. 处理输入事件流程.
起源
在之前的输入法研究分析可以知道, 在android一开机的时候会去启动InputManager service, 此service会再去启动InputReaderThread和InputDispatcherThread,前者是从driver哪边获取inputevent放入Queue中在通知InputDispatcherThread去Queue中捞出来放进linux中的共享内存, 之后在通知ViewRootImpl去作分发的处理. 这一篇着重在于分发的过程. 至于inputevent在android中的流程机制之前就有作过分析了. 这里就不再重复描述. 就从InputDispatcherThread被启动的流程开始分析.
threadLoop @InputDispatcher.cpp
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
threadLoop @InputDispatcher.cpp
void InputDispatcher::dispatchOnce() {
// do something
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime,
nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
1
}
1. 开始针对目前process的looper作polling状态. 检查是否有新的inputevent
pollOnce @Looper.cpp
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
for (;;) {
// do something
result = pollInner(timeoutMillis);
}
}
pollInner@ Looper.cpp
int Looper::pollInner(int timeoutMillis) {
//do something
int result = ALOOPER_POLL_WAKE;
mResponses.clear();
mResponseIndex = 0;
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd, eventItems,
EPOLL_MAX_EVENTS, timeoutMillis);
1
//处理所监听到的相关事件
//do something
sp<MessageHandler> handler = messageEnvelope.handler;
Message message = messageEnvelope.message;
mMessageEnvelopes.removeAt(0);
mSendingMessage = true;
mLock.unlock();
handler->handleMessage(message);
2
//do something
if (response.request.ident == ALOOPER_POLL_CALLBACK) {
int fd = response.request.fd;
int events = response.events;
void* data = response.request.data;
int callbackResult = response.request.callback->handleEvent(fd,
events, data);
3
if (callbackResult == 0) {
removeFd(fd);
}
response.request.callback.clear();
result = ALOOPER_POLL_CALLBACK;
}
1. 利用epoll_wait函数来监听目前looper上的event,一有event其eventCount就会回传event的数目. 假若在最后一个参数指定的 timeoutMillis内都没有事件发生, 其eventCount就会回传0,若有发生错误回传-1.由 EPOLL_MAX_EVENTS 的定义值可以知道, 所监听到的event数最多为16个event.
2. 呼叫执行所有在looper中的闲置中的Message所带的CallBackfunction handleMessage
3. 呼叫执行所有在looper中的reponse eventCallBack function handleEvent
由上面的程序代码分析可以知道在一开始InputDispatcherThread就会一直开始监听目前looper上是否有message或是event需要处理.
指定接受者.
当Android app一开始要去绘制整个layout时,WindowsManager会先作 addView 的处理还将自己的View先设定到目前的Window上. 就从WindowManager的addViewfunction开始分析.
addView@ WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
//do something
root.setView(view, wparams, panelParentView);
//do something
}
setView@ ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
//do something
mInputEventReceiver = new
WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
1
//do something
}
WindowInputEventReceiver@ ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper
looper) {
super(inputChannel, looper);
2
}
@Override
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);
}
@Override
public void onBatchedInputEventPending() {
scheduleConsumeBatchedInput();
}
@Override
public void dispose() {
unscheduleConsumeBatchedInput();
super.dispose();
}
}
1. 产生一个带有两个CallBack function实作的
WindowInputEventReceiver物件 . 这两个CallBack function
onInputEvent 和
onBatchedInputEventPending 会跟在nativelayer的 InputDispatcherThread 监听事件处理有相关.
2. 跟目前所在的Looper注册request CallBackobject NativeInputEventReceiver
处理输入事件流程.
由前面起源的分析可以知道, InputDispatcherThread一直处在监听looper上的事件阶段, 一旦监听到looper上有event就会接者呼叫执行event所带的CallBackfunctionhandleEvent . 至于是呼叫哪一个event所带的handleEvent函数. 这就要由程序代码 response.request.callback->handleEvent 开始分析. 就由前面指定接受者的第二个步骤开始分析.
WindowInputEventReceiver@ ViewRootImpl.java
public WindowInputEventReceiver(InputChannel inputChannel, Looper
looper) {
super(inputChannel, looper);
}
InputEventReceiver@ InputEventReceiver.java
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
//do something
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(this, inputChannel, mMessageQueue);
//do somthing
}
nativeInit@ android_view_InputEventReceiver.cpp
static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
jobject inputChannelObj, jobject messageQueueObj) {
//do something
status_t status = receiver->initialize();
//do something
}
NativeInputEventReceiver::initialize@ android_view_InputEventReceiver.cpp
status_t NativeInputEventReceiver::initialize() {
int receiveFd = mInputConsumer.getChannel()->getFd();
mMessageQueue->getLooper()->addFd(receiveFd, 0,
ALOOPER_EVENT_INPUT, this, NULL);
return OK;
}
Looper::addFd@Looper.cpp
int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>&
callback, void* data) {
//do something
Request request;
request.fd = fd;
request.ident = ident;
request.callback = callback;
request.data = data;
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event));
eventItem.events = epollEvents;
eventItem.data.fd = fd;
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex < 0) {
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &
eventItem);
if (epollResult < 0) {
ALOGE("Error adding epoll events for fd %d, errno=%d", fd,
errno);
return -1;
}
mRequests.add(fd, request);
} else {
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, &
eventItem);
if (epollResult < 0) {
ALOGE("Error modifying epoll events for fd %d, errno=%d",
fd, errno);
return -1;
}
mRequests.replaceValueAt(requestIndex, request);
}
//do something
}
由上面的程序代码流程可以知道, 在一开始初始化WindowInputEventReceiver对象时, 又去呼叫父类别InputEventReceiver建构子. 这时就又去呼叫JNI函数nativeInit去做初始化流程, 此初始化的流程就正式注册Looper上的CallBackevent 所带的信息. 也就是说先把request的information记录下来, 等到要回reponse的时候就知道要回给哪一个request.由此可知, 此程序代码
response.request.callback->handleEvent 等同于
(NativeInputEventReceiver*)receiver-> handleEvent.
NativeInputEventReceiver::handleEvent@ android_view_InputEventReceiver.cpp
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
//do something
status_t status = consumeEvents(env, false /*consumeBatches*/, -1);
//do something
return status == OK || status == NO_MEMORY ? 1 : 0;
}
NativeInputEventReceiver::consumeEvents@ android_view_InputEventReceiver.cpp
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime) {
//do something
for (;;) {
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
//do something
switch (inputEvent->getType()) {
case AINPUT_EVENT_TYPE_KEY:
inputEventObj = android_view_KeyEvent_fromNative(env,
static_cast<KeyEvent*>(inputEvent));
break;
case AINPUT_EVENT_TYPE_MOTION:
inputEventObj =
android_view_MotionEvent_obtainAsCopy(env,
static_cast<MotionEvent*>(inputEvent));
break;
default:
assert(false);
inputEventObj = NULL;
}
env->CallVoidMethod(mReceiverObjGlobal,
gInputEventReceiverClassInfo.dispatchInputEvent,
seq, inputEventObj);
//do something
}
}
dispatchInputEvent@ InputEventReceiver.java
// Called from native code.
@SuppressWarnings("unused")
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}
这一路下来, 由native layer的 handleEventfunction 藉由
InputConsumer对象将新的input event取出来, 然后就传给javalayer的 dispatchInputEvent 函数继续作分发的处理. 这里值得一提的是我们发现dispatchInputEvent函数会继续将event传给
onInputEvent函数, 然而此函数所属的InputEventReceiver是一个抽像类别, 抽象类是无法实体化的, 所以此函数最有可能实作在抽像类别所衍生的类别里. InputEventReceiver类别衍生的类别是 WindowInputEventReceiver类别, 所以就继续从WindowInputEventReceiver的
onInputEvent函数分析
onInputEvent@ ViewRootImpl.java
@Override
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);
}
enqueueInputEvent @ ViewRootImpl.java
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
//do something
if (processImmediately) {
doProcessInputEvents();
} else {
scheduleProcessInputEvents();
}
}
doProcessInputEvents@ ViewRootImpl.java
void doProcessInputEvents() {
while (mCurrentInputEvent == null && mFirstPendingInputEvent != null)
{
QueuedInputEvent q = mFirstPendingInputEvent;
mFirstPendingInputEvent = q.mNext;
q.mNext = null;
mCurrentInputEvent = q;
deliverInputEvent(q);
}
// We are done processing all input events that we can process right now
// so we can clear the pending flag immediately.
if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}
deliverInputEvent @ ViewRootImpl.java
private void deliverInputEvent(QueuedInputEvent q) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
try {
if (q.mEvent instanceof KeyEvent) {
deliverKeyEvent(q);
} else {
final int source = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0)
{
deliverPointerEvent(q);
} else if ((source &
InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
deliverTrackballEvent(q);
} else {
deliverGenericMotionEvent(q);
}
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
deliverKeyEvent @ ViewRootImpl.java
private void deliverKeyEvent(QueuedInputEvent q) {
//do something
deliverKeyEventPostIme(q);
}
deliverKeyEventPostIme @ ViewRootImpl.java
private void deliverKeyEventPostIme(QueuedInputEvent q) {
//do something
mView.dispatchKeyEvent(event)
//do something
}
dispatchKeyEvent @View.java
public boolean dispatchKeyEvent(KeyEvent event) {
//do something
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnKeyListener != null && (mViewFlags &
ENABLED_MASK) == ENABLED
&& li.mOnKeyListener.onKey(this,
event.getKeyCode(), event)) {
1
return true;
}
if (event.dispatch(this, mAttachInfo != null
? mAttachInfo.mKeyDispatchState : null, this)) {
2
return true;
}
//do something
}
1. 自定义的view若有注册Key Listener,就会由此接收到
Key event.
2. 一般的Key event是由此函数 dispatch来作分发.
dispatch @ KeyEvent.java
public final boolean dispatch(Callback receiver, DispatcherState state,
Object target) {
//do something
switch (mAction) {
case ACTION_DOWN:
//do something
receiver.onKeyDown(mKeyCode, this);
case ACTION_UP:
//do something
receiver.onKeyUp(mKeyCode, this);
case ACTION_MULTIPLE:
//do something
receiver.onKeyMultiple(code, count, this)
}
}
最后
以上就是自觉犀牛为你收集整理的Key event 分发流程研究心得的全部内容,希望文章能够帮你解决Key event 分发流程研究心得所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复