总结一下,Android按键事件发布流程
|
1
2
3
4
5
6
7
8
9
10
|
//InputReader.cppvoidInputReader::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.cppvoidInputReader::processEventsLocked(constRawEvent* rawEvents, size_t count) { ... processEventsForDeviceLocked(deviceId, rawEvent, batchSize); ...} |
随后调动上述方法,把事件发送给指定设备。
|
1
2
3
4
5
6
7
|
//InputReader.cppvoidInputReader::processEventsForDeviceLocked(int32_t deviceId, constRawEvent* rawEvents, size_t count) { ... device->process(rawEvents, count); ...} |
设备处理该事件
|
1
2
3
4
5
6
|
//InputReader.cppvoidInputDevice::process(constRawEvent* rawEvents, size_t count) { ... mapper->process(rawEvent); ...} |
每个设备可能有多种mapper,比如既有按键又有触摸板,把事件发给相应的mapper
|
1
2
3
4
5
6
7
|
//InputReader.cppvoidKeyboardInputMapper::process(constRawEvent* rawEvent) { ... processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags); ...} |
键盘mapper处理事件
|
1
2
3
4
5
6
7
8
|
//InputReader.cppvoidKeyboardInputMapper::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.cppvoidInputDispatcher::notifyKey(constNotifyKeyArgs* args) { .... needWake = enqueueInboundEventLocked(newEntry); if(needWake){ mLooper->wake(); } } |
notify函数,将事件加入inputDispatcher的 inbound队列,此时应需要选择是否唤醒inputDispatcher线程
|
1
2
3
4
5
6
7
|
//InputDispatcher.cppbool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { bool needWake = mInboundQueue.isEmpty(); mInboundQueue.enqueueAtTail(entry); .... returnneedWake;} |
|
1
2
3
4
5
6
7
|
//InputDispatcher.cppvoidInputDispatcher::dispatchOnce(){ ... dispatchOnceInnerLocked(&nextWakeupTime); ... mLooper->pollOnce(timeoutMillis);} |
唤醒后,inputdispatcher线程,继续执行dispatchOnce函数,如果没有事件,则休眠在looper的pollOnce函数。
|
1
2
3
4
5
6
|
//InputDispatcher.cppvoidInputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { ... dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); ... } |
如果有事件发生,则发布。
|
1
2
3
4
5
6
7
8
9
10
11
12
|
//InputDispatcher.cppbool 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.cppvoidInputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, constVector<inputtarget>& inputTargets) { ... for(size_t i = 0; i < inputTargets.size(); i++) { constInputTarget& 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.cppvoidInputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, constsp<connection>& connection, EventEntry* eventEntry, constInputTarget* inputTarget){ ... enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget); ... }</connection> |
|
1
2
3
4
5
6
7
8
9
|
//InputDispathcer.cppvoidInputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, constsp<connection>& connection, EventEntry* eventEntry, constInputTarget* inputTarget) { ... startDispatchCycleLocked(currentTime, connection); ...}</connection> |
将事件加入到outbound队列,准备发送到app
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//InputDispatcher.cppvoidInputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, constsp<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.cppstatus_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) { ... returnmChannel->sendMessage(&msg);} |
通过通道,发送事件消息
|
1
2
3
4
5
6
7
8
|
//InputTransport.cppstatus_t InputChannel::sendMessage(constInputMessage* 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.cppintLooper::pollInner(inttimeoutMillis) { struct epoll_event eventItems[EPOLL_MAX_EVENTS]; //等待消息 inteventCount = 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) { intfd = response.request.fd; intevents = response.events; void* data = response.request.data; // callback--------NativeInputEventRecieverd intcallbackResult = response.request.callback->handleEvent(fd, events, data); if(callbackResult == 0) { removeFd(fd); } response.request.callback.clear(); result = ALOOPER_POLL_CALLBACK; } } returnresult;} |
app looper会监测channel下socket fd,当fd发生变化,回调当时注册的函数NativeInputEventReciever
|
1
2
3
4
5
6
7
|
//android_view_InputEventReceiver.cppintNativeInputEventReceiver::handleEvent(intreceiveFd, intevents, 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.cppstatus_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.cppstatus_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") privatevoid dispatchInputEvent(intseq, InputEvent event) { mSeqMap.put(event.getSequenceNumber(), seq); onInputEvent(event); } |
此处onInputEent调用重写的子类方法。即WindowInputEventReceiver的方法
|
1
2
3
4
5
6
7
8
9
10
|
//ViewRootImpl.javafinalclass WindowInputEventReceiver extendsInputEventReceiver { publicWindowInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); } @Override publicvoid onInputEvent(InputEvent event) { enqueueInputEvent(event,this,0,true); } |
|
1
2
3
4
5
6
7
8
9
10
11
12
|
//ViewRootImpl.javavoidenqueueInputEvent(InputEvent event, InputEventReceiver receiver, intflags, booleanprocessImmediately) { 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