Android按键事件发布流程

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

//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,没有则休眠。

//InputReader.cpp
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
     ...
     processEventsForDeviceLocked(deviceId, rawEvent, batchSize);

     ...
}

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

//InputReader.cpp
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
        const RawEvent* rawEvents, size_t count) {
      ...
      device->process(rawEvents, count);
      ...
}

设备处理该事件

//InputReader.cpp
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    ...
    mapper->process(rawEvent);
    ...
}

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

//InputReader.cpp
void KeyboardInputMapper::process(const RawEvent* rawEvent) {
    ...
    processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
    ...

}

键盘mapper处理事件

//InputReader.cpp
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
        int32_t scanCode, uint32_t policyFlags) {
    ...
    getListener()->notifyKey(&args);
    ...

}

调用InputDispatcher的notifyKey函数。

//InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
    ....
    needWake = enqueueInboundEventLocked(newEntry);
    if(needWake){
     mLooper->wake();
    }
 }

notify函数,将事件加入inputDispatcher的 inbound队列,此时应需要选择是否唤醒inputDispatcher线程

//InputDispatcher.cpp
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
    bool needWake = mInboundQueue.isEmpty();
    mInboundQueue.enqueueAtTail(entry);
    ....
    return needWake;
}
//InputDispatcher.cpp
void InputDispatcher::dispatchOnce(){
  ...
   dispatchOnceInnerLocked(&nextWakeupTime);
  ...
   mLooper->pollOnce(timeoutMillis);
}

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

//InputDispatcher.cpp
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
     ...
     dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
     ...
 }

如果有事件发生,则发布。

//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);
     ...
}

首先寻找获得焦点的窗口,并将事件发送给它

//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);
        }
       ...
    }
}
//InputDispatcher.cpp
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget){
   ...
   enqueueDispatchEntriesLocked(currentTime, connection,
                    splitMotionEntry, inputTarget);
   ...
 }
//InputDispathcer.cpp
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
    ...
    startDispatchCycleLocked(currentTime, connection);
    ...

}

将事件加入到outbound队列,准备发送到app

//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);

      ...

}
//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);
}

通过通道,发送事件消息

//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);
     ...
}
//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

//android_view_InputEventReceiver.cpp
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
   ...
    status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
   ...

}
//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);
...

}

通过jni调用java函数,dispatchInputevent

//InputTransport.cpp
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
        bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
        ...
            status_t result = mChannel->receiveMessage(&mMsg);
        ...
}

//通过通道收取消息,初始化按键事件

 //InputEventReceiver.java
// Called from native code.
    @SuppressWarnings("unused")
    private void dispatchInputEvent(int seq, InputEvent event) {
        mSeqMap.put(event.getSequenceNumber(), seq);
        onInputEvent(event);
    }

此处onInputEent调用重写的子类方法。即WindowInputEventReceiver的方法

//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);
        }
//ViewRootImpl.java
void enqueueInputEvent(InputEvent event,
            InputEventReceiver receiver, int flags, boolean processImmediately) {
        QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);

        ...
        if (processImmediately) {
            doProcessInputEvents();
        } else {
            scheduleProcessInputEvents();
        }
    }
时间: 2024-10-26 21:17:27

Android按键事件发布流程的相关文章

Android View 按键事件分发流程 onTouch onTouchEvent onClick onLongClick 和 onKey onKeyDown onClick

1.为了测试,我们同时将View 设置 onTouch  onTouchEvent  onClick onLongClick 四个事件,经过加打印测试发现,按键分发流程是这样的 如果是短按:onTouch-->>onTouchEvent--->>onClick .长按:onTouch-->>onTouchEvent--->>onLongClick-->>onClick.为什么会是这样? 我们看View 源码 public boolean disp

Android webkit 事件传递流程通道分析

前言:基于android webview 上定制自己使用的可移植浏览器apk,遇到好多按键处理的问题.所以索性研究了一下keyevent 事件的传递流程. frameworks 层 keyevent 事件开始是从/frameworks/base/core/java/android/webkit目录下WebViewClassic.java 中的onKeyDown() 函数开始的 // Bubble up the key event if          // 1. it is a system

Android webkit 事件传递流程详解

前言:基于android webview 上定制自己使用的可移植浏览器apk,遇到好多按键处理的问题.所以索性研究了一下keyevent 事件的传递流程. frameworks 层 keyevent 事件开始是从/frameworks/base/core/java/android/webkit目录下WebViewClassic.java 中的onKeyDown() 函数开始的 // Bubble up the key event if          // 1. it is a system

Android webkit 事件传递流程

前言:基于android webview 上定制自己使用的可移植浏览器apk,遇到好多按键处理的问题.所以索性研究了一下keyevent 事件的传递流程. frameworks 层 keyevent 事件开始是从/frameworks/base/core/java/android/webkit目录下WebViewClassic.java 中的onKeyDown() 函数开始的 // Bubble up the key event if // 1. it is a system key; or /

Win7平台下React-Native开发之Android项目打包发布流程

一.bundle文件 React-Native开发步骤中,有一个步骤是使用命令 react-native start 去启动一个基于Node.js的服务,名字为packager.这个packager的主要功能是:1.监视当前目录下相关文件的改动:2.监听在本机的8081(默认)端口,为正确的请求提供相应的bundle文件.总结一点来说就是:bundle文件是根据项目目录下相应文件的最新内容来动态生成的,这样在开发过程中就能实时地观察我们修改JS文件所带来的程序的改变.因为这个bundle文件就是

android touch事件分发流程

韩梦飞沙  韩亚飞  [email protected]  yue31313  han_meng_fei_sha 三个方法:分发触摸事件dispatchTouchEvent.在触摸事件的时候onTouchEvent.在拦截触摸事件的时候onInterceptTouchEvent. dispatch是派遣的意思. 就是分发的意思.  分发触摸事件. intercept 是拦截的意思. on 不仅有 在什么之上的意思,还有 在什么时候的意思. 触摸事件通常从 活动activity 通过 分发触摸事件

android源码解析(三十)--&gt;触摸事件分发流程

前面一篇文章中我们分析了App返回按键的分发流程,从Native层到ViewRootImpl层到DocorView层到Activity层,以及在Activity中的dispatchKeyEvent方法中分发事件,最终调用了Activity的finish方法,即销毁Activity,所以一般情况下假如我们不重写Activity的onBackPress方法或者是onKeyDown方法,当我们按下并抬起返回按键的时候默认都是销毁当前Activity.而本文中我们主要介绍触摸事件的分发流程,从Nativ

Android touch事件的派发流程

http://blog.csdn.net/xyz_lmn/article/details/12517911 通过流程图了解touch事件派发过程. http://blog.csdn.net/stonecao/article/details/6759189 从代码的层面分析,尽管目前代码已经变化了,但是作者的分析对Android touch事件派发流程的理解还是很有帮助的. http://www.2cto.com/kf/201504/388625.html 通过实例了解Button的touch事件

从源码角度带你分析 Android View 事件分发 dispatchTouchEvent,onTouch,onTouchEvent,onClick逻辑顺序过程(一)

关于Android View 事件分发过程的文章网络上可以搜到一把大,这里贴一篇代码性的文章,作者也是个牛人:Android事件分发机制完全解析,带你从源码的角度彻底理解(上). 虽然讲的很好,但是看完之后还是感觉有那么点一知半解,于是自己花了点时间从源码研究android 触摸事件分发流程,以下内容仅仅个人理解,如有差错希望指出. 我们先从一个例子看起,先重写一个MyButton 继承Button,代码如下: public class MyButton extends Button { pub