0. 关键字
InputFilnger, InputManager, InputReader, InputDispatcher
1.参考文档
参考1:参考网址
参考2:Android Input系统简介
参考3:Android Framework 输入子系统(05)InputDispatcher解读
2.InputManager的初始化
- 2.1 InputManagerService在systemserver进程中被启动
//frameworks\base\services\java\com\android\server\SystemServer.java// 1.构造inputManager = new InputManagerService(context);// 2 注册服务ServiceManager.addService(Context.INPUT_SERVICE, inputManager,/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);// 3inputManager.start();
- 2.2 初始化的内容:
- 2.2.1 InputManagerService的构造函数
调用到nativeInit(), 会通过JNI调用到C/C++的Java_com_android_server_InputManagerService_nativeInit
//frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,jobject serviceObj, jobject contextObj, jobject messageQueueObj) {sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);if (messageQueue == nullptr) {jniThrowRuntimeException(env, "MessageQueue is not initialized.");return 0;}NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,messageQueue->getLooper()); // 1im->incStrong(0);return reinterpret_cast<jlong>(im);
}static const JNINativeMethod gInputManagerMethods[] = {/* name, signature, funcPtr */{"nativeInit","(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/""MessageQueue;)J",(void*)nativeInit},//省略
3. new NativeInputManager的初始化
3.1 InputReader部分
3.1.1 InputReader的初始化----createInputReader
sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy,const sp<InputListenerInterface>& listener) {return new InputReader(std::make_unique<EventHub>(), policy, listener); //
}
// 启动InputReader的线程
mReader = createInputReader(readerPolicy, mClassifier);
mReader->start(); // 调用到 InputReader::start
3.1.2 InputReader::start
status_t InputReader::start() {if (mThread) {return ALREADY_EXISTS;}mThread = std::make_unique<InputThread>("InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });return OK;
}
创建线程"InputReader"—执行loopOnce函数
3.1.3 InputReader::loopOnce执行 getEvent函数来获取输入事件
void InputReader::loopOnce() {
。。。。。size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); //
。。。。。
}
3.1.4 调用到EventHub::getEvents
主要就是下面的部分: 循环的拿到传上来的事件,
......int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); // 等待fdSet关注的Fd事件
.......if (eventItem.events & EPOLLIN) { // 处理常规输入事件{ // 拿到正常的输入事件int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;size_t count = size_t(readSize) / sizeof(struct input_event);for (size_t i = 0; i < count; i++) { // 逐帧读取RawEventstruct input_event& iev = readBuffer[i];event->when = processEventTimestamp(iev);event->readTime = systemTime(SYSTEM_TIME_MONOTONIC);event->deviceId = deviceId;event->type = iev.type;event->code = iev.code;event->value = iev.value;event += 1;capacity -= 1;}........
3.1.5 InputReader::loopOnce()中的 processEventsLocked
调用到 InputReader::processEventsForDeviceLocked
---->调用到 device->process(rawEvents, count);
3.1.6 调用到InputDevice::process
关键是调用下面的mapper.process, mapper是InputMapper类型变量。
会找到触摸屏对应的devices—TouchInputMapper
for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {mapper.process(rawEvent); // InputMapper 执行process操作,// InputMapper是基类----找到比如MouseInputMapper(鼠标输入处理类)// TouchInputMapper 是触摸屏
3.1.7 TouchInputMapper::process 会处理点击事件
sync会最终调用到processRawTouches, 会调用到cookAndDispatch, 最后调用到dispatchTouches将本次的触摸事件传递给InputDispater线程。
void TouchInputMapper::process(const RawEvent* rawEvent) { // 处理点击事件mCursorButtonAccumulator.process(rawEvent); // "鼠标滑动"事件mCursorScrollAccumulator.process(rawEvent); // "鼠标滚轮"事件mTouchButtonAccumulator.process(rawEvent); // "鼠标点击"事件if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {sync(rawEvent->when, rawEvent->readTime);}
}
3.1.8 dispatchTouches
getListener()->notifyMotion(&args);
// class InputDispatcher : public android::InputDispatcherInterface,
// InputDispatcherInterface 继承 InputListenerInterface
// getListener()->notifyMotion最终对应到InputDispatcher::notifyMotion方法。void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {。。。。。needWake = enqueueInboundEventLocked(std::move(newEntry));}
- enqueueInboundEventLocked最终会将数据写入mInboundQueue队列
3.1.9 InputReader的关键流程:
- open设备节点**/dev/input**, 当有输入事件,则会写入/dev/input
- 通过InputManager实例化InputReader
- 然后InputReader::start来启动loopOnce()线程
- loopOnce()线程首先会在循环中在epoll_wait中拿到关注的**/dev/input**的相关事件。
- loopOnce()线程会通过EventHub::getEvent方法来读取"Input事件",
- loopOnce()线程通过processEventLocked(), 在通过层层调用,调用到sync,把事件最终传递给InputDispater.
3.2 InputDispater部分
3.2.1 InputDispater的初始化----createInputReader
InputManager::InputManager(const sp<InputReaderPolicyInterface>& readerPolicy,const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {mDispatcher = createInputDispatcher(dispatcherPolicy);
.......
}
// 启动InputDispatcher线程status_t result = mDispatcher->start();
3.2.1 启动InputDispatcher线程
- InputDispatcher::start()
创建名为"InputDispatcher"的线程,调用dispatchOnce()函数
status_t InputDispatcher::start() {if (mThread) {return ALREADY_EXISTS;}mThread = std::make_unique<InputThread>("InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });return OK;
}
3.2.3 InputDispatcher::dispatchOnce()
void InputDispatcher::dispatchOnce() {nsecs_t nextWakeupTime = LONG_LONG_MAX;......if (!haveCommandsLocked()) {//判断CommandQueue是否有命令dispatchOnceInnerLocked(&nextWakeupTime);}
..........mLooper->pollOnce(timeoutMillis);
}
- 首先 pollOnce阻塞等待InputReader调用wake()唤醒
- 调用到dispatchOnceInnerLocked来分发事件
3.2.4 dispatchOnceInnerLocked
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
....................if (!mPendingEvent) {//当InputReader队列中插入一个输入事件后,此处mInboundQueue不为空if (mInboundQueue.empty()) {.................} else { // 拿到InputReader写入mInboundQueue 队列的EventmPendingEvent = mInboundQueue.front(); // 从 mInboundQueue 队列取出一条事件.......}}//...switch (mPendingEvent->type) {//...case EventEntry::TYPE_KEY: {KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);...// 分发按键事件done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);break;}}
3.2.5 dispatchKeyLocked
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,DropReason* dropReason, nsecs_t* nextWakeupTime) {
..........// Identify targets.Vector<InputTarget> inputTargets;//找到当前激活的Window窗口,并将其加入到inputTargets中int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,entry, inputTargets, nextWakeupTime);//将按键分发到上面Vendor的InputChannel中dispatchEventLocked(currentTime, entry, inputTargets);return true;
}
3.2.6 dispatchEventLocked
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {pokeUserActivityLocked(eventEntry);// 遍历inputTargetsfor (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);}}
}
- 遍历inputTargets,找到connection,调用prepareDispatchCycleLocked进行分发
3.2.7 prepareDispatchCycleLocked
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
......enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
...............// If the outbound queue was previously empty, start the dispatch cycle going.if (wasEmpty && !connection->outboundQueue.isEmpty()) {startDispatchCycleLocked(currentTime, connection);}
}
3.2.8 startDispatchCycleLocked
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,const sp<Connection>& connection) { //
.........while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {// 从connection->outboundQueue取出事件DispatchEntry* dispatchEntry = connection->outboundQueue.front();dispatchEntry->deliveryTime = currentTime;const std::chrono::nanoseconds timeout =getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());dispatchEntry->timeoutTime = currentTime + timeout.count();// Publish the event.status_t status;const EventEntry& eventEntry = *(dispatchEntry->eventEntry);switch (eventEntry.type) {case EventEntry::Type::KEY: {const KeyEntry& keyEntry = static_cast<const KeyEntry&>(eventEntry);std::array<uint8_t, 32> hmac = getSignature(keyEntry, *dispatchEntry);// Publish the key event.publishKeyEvent完成分发事件status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,dispatchEntry->resolvedEventId, keyEntry.deviceId,keyEntry.source, keyEntry.displayId,std::move(hmac), dispatchEntry->resolvedAction,dispatchEntry->resolvedFlags, keyEntry.keyCode,keyEntry.scanCode, keyEntry.metaState,keyEntry.repeatCount, keyEntry.downTime,keyEntry.eventTime);break;}
3.2.9 publishKeyEvent
status_t InputPublisher::publishKeyEvent(uint32_t seq,//...nsecs_t downTime,nsecs_t eventTime) {//...InputMessage msg;msg.header.type = InputMessage::TYPE_KEY;//...msg.body.key.eventTime = eventTime;return mChannel->sendMessage(&msg); // 对应InputChannel::sendMessage
}
3.2.10 sendMessage
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);} while (nWrite == -1 && errno == EINTR);//...if (size_t(nWrite) != msgLength) {return DEAD_OBJECT;}return OK;
}
- 最终是调用的socket的send方法来发送到对应的APP
3.2.11 总结
- InputReader调用getListener()->notifyMotion()发送消息到InputDispatcher(本质上是写入mInboundQueue队列)
- InputDispatcher在InputManager被初始化,调用了InputDispatcher::start方法来启动一个名为“InputDispatcher”的线程,并循环调用InputManager::dispatchOnce方法。
- pollOnce阻塞等待消息,然后拿到消息后。调用dispatchOnceInnerLocked
- 以按键事件为例,会调用到dispatchKeyLocked
- 一步步调用到publishKeyEvent将InputMessage, 通过socket发送到server端。
4. InputEventReceiver
- 主要就是WMS中的mInputEventReceiver作为接收线程,接收来自InputDispatcher的消息。
>frameworks/base/core/java/android/view/ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {if ((mWindowAttributes.inputFeatures& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {mInputChannel = new InputChannel();}try {mOrigWindowType = mWindowAttributes.type;mAttachInfo.mRecomputeGlobalAttributes = true;collectViewAttributes();res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel); // 将mInputChannel 注册到WMS中} catch (RemoteException e) {...}if (mInputChannel != null) {if (mInputQueueCallback != null) {mInputQueue = new InputQueue();mInputQueueCallback.onInputQueueCreated(mInputQueue);}// 创建app端监听,即WindowInputEventReceiver 作为事件的接收端mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());}}
5. 点击屏幕到响应这个流程是怎样的?
- 首先点击了之后,会被硬件捕获,然后此事件被输入到驱动程序,并传递到Android系统。
通过adb shell getevent,监测**/dev/input**目录来看linux是否传递了点击事件上来。
然后点击屏幕,会发现有点击事件。 - 输入事件传入InputReader
- InputReader将消息转给InputDispatcher
- WMS 中的InputEventReceiver会收到InputDispatcher发送出来的消息。