Android按键事件发布流程实例源码介绍



Android按键事件发布流程

总结一下,Android按键事件发布流程

 

1
2
3
4
5
6
7
8
9
10
//InputReader.cpp
voidInputReader::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
voidInputReader::processEventsLocked(constRawEvent* rawEvents, size_t count) {
     ...
     processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
     ...
}

随后调动上述方法,把事件发送给指定设备。

 

 

1
2
3
4
5
6
7
//InputReader.cpp
voidInputReader::processEventsForDeviceLocked(int32_t deviceId,
        constRawEvent* rawEvents, size_t count) {
      ...
      device->process(rawEvents, count);
      ...
}

设备处理该事件

 

 

1
2
3
4
5
6
//InputReader.cpp
voidInputDevice::process(constRawEvent* rawEvents, size_t count) {
    ...
    mapper->process(rawEvent);
    ...
}

 

每个设备可能有多种mapper,比如既有按键又有触摸板,把事件发给相应的mapper

 

1
2
3
4
5
6
7
//InputReader.cpp
voidKeyboardInputMapper::process(constRawEvent* rawEvent) {
    ...
    processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
    ...
}

 

键盘mapper处理事件

 

1
2
3
4
5
6
7
8
//InputReader.cpp
voidKeyboardInputMapper::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
voidInputDispatcher::notifyKey(constNotifyKeyArgs* 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);
    ....
    returnneedWake;
}

 

 

 

1
2
3
4
5
6
7
//InputDispatcher.cpp
voidInputDispatcher::dispatchOnce(){
  ...
   dispatchOnceInnerLocked(&nextWakeupTime);
  ...
   mLooper->pollOnce(timeoutMillis);
}

唤醒后,inputdispatcher线程,继续执行dispatchOnce函数,如果没有事件,则休眠在looper的pollOnce函数。

1
2
3
4
5
6
//InputDispatcher.cpp
voidInputDispatcher::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
voidInputDispatcher::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.cpp
voidInputDispatcher::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.cpp
voidInputDispatcher::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.cpp
voidInputDispatcher::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.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) {
    ...
    returnmChannel->sendMessage(&msg);
}

通过通道,发送事件消息

1
2
3
4
5
6
7
8
//InputTransport.cpp
status_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.cpp
intLooper::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.cpp
intNativeInputEventReceiver::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.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")
    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.java
finalclass 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.java
voidenqueueInputEvent(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