总结一下,Android按键事件发布流程
1
2
3
4
5
6
7
8
9
10
|
//InputReader.cpp void InputReader::loopOnce() { ... size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); if (count) { processEventsLocked(mEventBuffer, count); } ... } |
InputReader线程启动后,循环调用loopOnce,loopOnce调用mEventHub的getEvents函数,有事件返回底层事件数count,没有则休眠。
1
2
3
4
5
6
7
|
//InputReader.cpp void InputReader::processEventsLocked( const RawEvent* rawEvents, size_t count) { ... processEventsForDeviceLocked(deviceId, rawEvent, batchSize); ... } |
随后调动上述方法,把事件发送给指定设备。
1
2
3
4
5
6
7
|
//InputReader.cpp void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) { ... device->process(rawEvents, count); ... } |
设备处理该事件
1
2
3
4
5
6
|
//InputReader.cpp void InputDevice::process( const RawEvent* rawEvents, size_t count) { ... mapper->process(rawEvent); ... } |
每个设备可能有多种mapper,比如既有按键又有触摸板,把事件发给相应的mapper
1
2
3
4
5
6
7
|
//InputReader.cpp void KeyboardInputMapper::process( const RawEvent* rawEvent) { ... processKey(rawEvent->when, rawEvent->value != 0 , keyCode, scanCode, flags); ... } |
键盘mapper处理事件
1
2
3
4
5
6
7
8
|
//InputReader.cpp void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) { ... getListener()->notifyKey(&args); ... } |
调用InputDispatcher的notifyKey函数。
1
2
3
4
5
6
7
8
|
//InputDispatcher.cpp void InputDispatcher::notifyKey( const NotifyKeyArgs* args) { .... needWake = enqueueInboundEventLocked(newEntry); if (needWake){ mLooper->wake(); } } |
notify函数,将事件加入inputDispatcher的 inbound队列,此时应需要选择是否唤醒inputDispatcher线程
1
2
3
4
5
6
7
|
//InputDispatcher.cpp bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { bool needWake = mInboundQueue.isEmpty(); mInboundQueue.enqueueAtTail(entry); .... return needWake; } |
1
2
3
4
5
6
7
|
//InputDispatcher.cpp void InputDispatcher::dispatchOnce(){ ... dispatchOnceInnerLocked(&nextWakeupTime); ... mLooper->pollOnce(timeoutMillis); } |
唤醒后,inputdispatcher线程,继续执行dispatchOnce函数,如果没有事件,则休眠在looper的pollOnce函数。
1
2
3
4
5
6
|
//InputDispatcher.cpp void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { ... dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); ... } |
如果有事件发生,则发布。
1
2
3
4
5
6
7
8
9
10
11
12
|
//InputDispatcher.cpp bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { ... int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); dispatchEventLocked(currentTime, entry, inputTargets); ... } |
首先寻找获得焦点的窗口,并将事件发送给它
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//InputDispatcher.cpp void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, const Vector<inputtarget>& inputTargets) { ... for (size_t i = 0 ; i < inputTargets.size(); i++) { const InputTarget& inputTarget = inputTargets.itemAt(i); ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); if (connectionIndex >= 0 ) { sp<connection> connection = mConnectionsByFd.valueAt(connectionIndex); prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); } ... } } </connection></inputtarget> |
1
2
3
4
5
6
7
8
|
//InputDispatcher.cpp void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const sp<connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget){ ... enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget); ... }</connection> |
1
2
3
4
5
6
7
8
9
|
//InputDispathcer.cpp void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { ... startDispatchCycleLocked(currentTime, connection); ... } </connection> |
将事件加入到outbound队列,准备发送到app
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//InputDispatcher.cpp void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const sp<connection>& connection){ ... 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); ... }</connection> |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
//InputTransport.cpp 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) { ... return mChannel->sendMessage(&msg); } |
通过通道,发送事件消息
1
2
3
4
5
6
7
8
|
//InputTransport.cpp status_t InputChannel::sendMessage( const InputMessage* msg) { size_t msgLength = msg->size(); ssize_t nWrite; do { nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); ... } |
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
|
//Looper.cpp int Looper::pollInner( int timeoutMillis) { struct epoll_event eventItems[EPOLL_MAX_EVENTS]; //等待消息 int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis); … Done: 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; } |
app looper会监测channel下socket fd,当fd发生变化,回调当时注册的函数NativeInputEventReciever
1
2
3
4
5
6
7
|
//android_view_InputEventReceiver.cpp int NativeInputEventReceiver::handleEvent( int receiveFd, int events, void * data) { ... status_t status = consumeEvents(env, false /*consumeBatches*/ , - 1 , NULL); ... } |
1
2
3
4
5
6
7
8
9
10
11
12
|
//android_view_InputEventReceiver.cpp status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) { .... status_t status = mInputConsumer.consume(&mInputEventFactory, consumeBatches, frameTime, &seq, &inputEvent); ... env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj); ... } |
1
|
|
通过jni调用java函数,dispatchInputevent
1
2
3
4
5
6
7
|
//InputTransport.cpp status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) { ... status_t result = mChannel->receiveMessage(&mMsg); ... } |
//通过通道收取消息,初始化按键事件
1
2
3
4
5
6
7
|
//InputEventReceiver.java // Called from native code. @SuppressWarnings ( "unused" ) private void dispatchInputEvent( int seq, InputEvent event) { mSeqMap.put(event.getSequenceNumber(), seq); onInputEvent(event); } |
此处onInputEent调用重写的子类方法。即WindowInputEventReceiver的方法
1
2
3
4
5
6
7
8
9
10
|
//ViewRootImpl.java final class WindowInputEventReceiver extends InputEventReceiver { public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) { super (inputChannel, looper); } @Override public void onInputEvent(InputEvent event) { enqueueInputEvent(event, this , 0 , true ); } |
1
2
3
4
5
6
7
8
9
10
11
12
|
//ViewRootImpl.java void enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) { QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); ... if (processImmediately) { doProcessInputEvents(); } else { scheduleProcessInputEvents(); } } |
U kernel/include/linux/input.h
U frameworks/native/include/android/keycodes.h
U frameworks/base/core/jni/android_os_SystemProperties.cpp
U frameworks/base/core/java/android/os/Build.java
U frameworks/base/core/java/android/view/KeyEvent.java
U frameworks/base/core/res/res/values/attrs.xml
U frameworks/base/include/androidfw/KeycodeLabels.h
U frameworks/base/libs/androidfw/Input.cpp
U frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
U mediatek/platform/mt6589/kernel/drivers/keypad/kpd.c
U mediatek/config/smarttimes89_wet_jb2/mtk-kpd.kl
A mediatek/config/mt6589/navi.xml
U mediatek/config/mt6589/AndroidBoard.mk
A mediatek/config/mt6589/baidu.sh
U mediatek/config/mt6589/init.rc
U mediatek/custom/st8988/kernel/dct/dct/codegen.dws