Key event 分发流程研究心得

http://my.eoe.cn/10407/archive/1176.html

Key event 分发流程研究心得
0

作者:powq更新于 02月27日访问(578)评论(2

Android在分发Input event(Key, Motion, Pointer, TrackBall)的流程牵扯到的WindowMangerService, ViewRootImpl和InputDispatcher Thread三位角色. 这三位角色的工作关系会依以下三个阶段来分析.
1. 起源.
2. 指定接受者.
3. 处理输入事件流程.
起源
在之前的输入法研究分析可以知道, 在android一开机的时候会去启动Input Manager service, 此service会再去启动InputReaderThread和InputDispatcherThread, 前者是从driver哪边获取input event放入Queue中在通知InputDispatcherThread去Queue中捞出来放进linux中的共享内存, 之后在通知 ViewRootImpl去作分发的处理. 这一篇着重在于分发的过程. 至于input event在android中的流程机制之前就有作过分析了. 这里就不再重复描述. 就从InputDispatcherThread被启动的流程开始分析.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
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状态. 检查是否有新的input event
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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所带的CallBack function handleMessage

  3. 呼叫执行所有在looper中的reponse event CallBack function handleEvent
    由上面的程序代码分析可以知道在一开始InputDispatcherThread就会一直开始监听目前looper上是否有message或是event需要处理.
    指定接受者.
    当Android app一开始要去绘制整个layout时, WindowsManager会先作 addView 的处理还将自己的View先设定到目前的Window上. 就从WindowManager的addView function开始分析.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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 会跟在native layer的 InputDispatcherThread 监听事件处理有相关.

  2. 跟目前所在的Looper注册request CallBack object NativeInputEventReceiver
    处理输入事件流程.
    由前面起源的分析可以知道, InputDispatcherThread 一直处在监听looper上的事件阶段, 一旦监听到looper上有event就会接者呼叫执行event所带的CallBack function handleEvent . 至于是呼叫哪一个event所带的handleEvent 函数. 这就要由程序代码 response.request.callback->handleEvent 开始分析. 就由前面指定接受者的第二个步骤开始分析.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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上的CallBack event 所带的信息. 也就是说先把request的information记录下来, 等到要回reponse的时候就知道要回给哪一个request. 由此可知, 此程序代码 response.request.callback->handleEvent 等同于
(NativeInputEventReceiver *)receiver-> handleEvent.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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的 handleEvent function 藉由InputConsumer 对象将新的input event取出来, 然后就传给java layer的 dispatchInputEvent 函数继续作分发的处理. 这里值得一提的是我们发现dispatchInputEvent函数会继续将event传给onInputEvent函数, 然而此函数所属的InputEventReceiver是一个抽像类别, 抽象类是无法实体化的, 所以此函数最有可能实作在抽像类别所衍生的类别里. InputEventReceiver类别衍生的类别是 WindowInputEventReceiver类别, 所以就继续从WindowInputEventReceiver的onInputEvent函数分析

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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来作分发.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
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)
  }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值