目录

Android系统的事件输入基于linux的Input子系统。触控屏事件和按键事件,从哪里输入又往哪里输出,虽然这个流程大部分对于Android系统来说是透明的,但是在多display,多窗口,多屏幕的情况下是值得研究的。

input对应各种输入事件,通过IMS,WMS,给到对应的window去处理事件,附一张最简化的事件传递流程:

1. Android Input子系统简介

1.1 事件的输入

事件的输入,是从不同类获的设备得到不同的事件类型,事件类型也都是定义在/include/linux/input.h文件中。

1adb shell getevent -l -c 16 2 3add device 1: /dev/input/event0 4 name: "ACCDET" 5add device 2: /dev/input/event3 6 name: "goodix_ts" 7add device 3: /dev/input/event2 8 name: "aw8697_haptic" 9add device 4: /dev/input/event1 10 name: "mtk-kpd" 11 12//按键 13adb shell getevent -l /dev/input/event1 14EV_KEY KEY_VOLUMEDOWN DOWN 15EV_SYN SYN_REPORT 00000000 16EV_KEY KEY_VOLUMEDOWN UP 17EV_SYN SYN_REPORT 00000000 18EV_KEY KEY_VOLUMEUP DOWN 19EV_SYN SYN_REPORT 00000000 20EV_KEY KEY_VOLUMEUP UP 21EV_SYN SYN_REPORT 00000000 22 23//触摸 24adb shell getevent -l /dev/input/event3 25EV_ABS ABS_MT_TRACKING_ID 0000036c 26EV_ABS ABS_MT_POSITION_X 000001fe 27EV_ABS ABS_MT_POSITION_Y 00000717 28EV_KEY BTN_TOUCH DOWN 29EV_SYN SYN_REPORT 00000000 30EV_ABS ABS_MT_POSITION_X 00000207 31EV_SYN SYN_REPORT 00000000 32EV_ABS ABS_MT_POSITION_X 00000219 33EV_ABS ABS_MT_POSITION_Y 00000716

Android设备可以同时连接多个输入设备,比如说触摸屏,键盘,鼠标等等。用户在任何一个设备上的输入就会产生一个中断,经由Linux内核的中断处理以及设备驱动转换成一个Event,并专递给用户空间的应用程序进行处理。每个输入设备都有自己的驱动程序,数据接口也不尽相同,如何在一个线程里(上面说过只有一个nputReader Thread)把所有的用户输入都给捕捉到:这首先要归功于Linux 内核的输入子系统 (Input Subsystem),它在各种各样的设备驱动程序上加了一个抽象层,只要底层的设备驱动程席按照这层抽象接口来实现,上层应用就可以通过统的接口来访问所有的输入设备。

1.2 事件在IMS中的流程

输入子系统对input设备和event处理分发的枢纽是EventHub,以下构造函数,主要是通过mEpollFd和mINotifyFd监听input事件和设备增删事件:

1EventHub::EventHub(void) 2 : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), 3 mNextDeviceId(1), 4 mControllerNumbers(), 5 mNeedToSendFinishedDeviceScan(false), 6 mNeedToReopenDevices(false), 7 mNeedToScanDevices(true), 8 mPendingEventCount(0), 9 mPendingEventIndex(0), 10 mPendingINotify(false) { 11 ensureProcessCanBlockSuspend(); 12 13 mEpollFd = epoll_create1(EPOLL_CLOEXEC); 14 LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno)); 15 16 mINotifyFd = inotify_init(); 17 mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); 18 LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH, 19 strerror(errno)); 20 if (isV4lScanningEnabled()) { 21 mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE); 22 LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s", 23 VIDEO_DEVICE_PATH, strerror(errno)); 24 } else { 25 mVideoWd = -1; 26 ALOGI("Video device scanning disabled"); 27 } 28 29 struct epoll_event eventItem = {}; 30 eventItem.events = EPOLLIN | EPOLLWAKEUP; 31 eventItem.data.fd = mINotifyFd; 32 int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); 33 LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno); 34 35 int wakeFds[2]; 36 result = pipe(wakeFds); 37 LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno); 38 39 mWakeReadPipeFd = wakeFds[0]; 40 mWakeWritePipeFd = wakeFds[1]; 41 42 result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); 43 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d", 44 errno); 45 46 result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); 47 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d", 48 errno); 49 50 eventItem.data.fd = mWakeReadPipeFd; 51 result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); 52 LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", 53 errno); 54}

这个方法的调用在InputReader里面启了一个线程,循环调用去读事件mEventHub->getEvents和处理 processEventsLocked(mEventBuffer, count);

1status_t InputReader::start() { 2 if (mThread) { 3 return ALREADY_EXISTS; 4 } 5 mThread = std::make_unique<InputThread>( 6 "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); }); 7 return OK; 8} 9 10... 11 12void InputReader::loopOnce() { 13 int32_t oldGeneration; 14 int32_t timeoutMillis; 15 bool inputDevicesChanged = false; 16 std::vector<InputDeviceInfo> inputDevices; 17 { // acquire lock 18 std::scoped_lock _l(mLock); 19 20 oldGeneration = mGeneration; 21 timeoutMillis = -1; 22 23 uint32_t changes = mConfigurationChangesToRefresh; 24 if (changes) { 25 mConfigurationChangesToRefresh = 0; 26 timeoutMillis = 0; 27 refreshConfigurationLocked(changes); 28 } else if (mNextTimeout != LLONG_MAX) { 29 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); 30 timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); 31 } 32 } // release lock 33 34 size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); 35 36 if (count) { 37 processEventsLocked(mEventBuffer, count); 38 } 39 40... 41 42// mEventHub->getEvents 43 44 mLock.unlock(); // release lock before poll 45 46 int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); 47 48 mLock.lock(); // reacquire lock after poll
1status_t InputReader::start() { 2 if (mThread) { 3 return ALREADY_EXISTS; 4 } 5 mThread = std::make_unique<InputThread>( 6 "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); }); 7 return OK; 8} 9 10... 11 12void InputReader::loopOnce() { 13 int32_t oldGeneration; 14 int32_t timeoutMillis; 15 bool inputDevicesChanged = false; 16 std::vector<InputDeviceInfo> inputDevices; 17 { // acquire lock 18 std::scoped_lock _l(mLock); 19 20 oldGeneration = mGeneration; 21 timeoutMillis = -1; 22 23 uint32_t changes = mConfigurationChangesToRefresh; 24 if (changes) { 25 mConfigurationChangesToRefresh = 0; 26 timeoutMillis = 0; 27 refreshConfigurationLocked(changes); 28 } else if (mNextTimeout != LLONG_MAX) { 29 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); 30 timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); 31 } 32 } // release lock 33 34 size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); 35 36 if (count) { 37 processEventsLocked(mEventBuffer, count); 38 } 39 40... 41 42// mEventHub->getEvents 43 44 mLock.unlock(); // release lock before poll 45 46 int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); 47 48 mLock.lock(); // reacquire lock after poll

输入事件处理,从这里找到指定的设备来处理。

1void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents, 2 size_t count) { 3 auto deviceIt = mDevices.find(eventHubId); 4 if (deviceIt == mDevices.end()) { 5 ALOGW("Discarding event for unknown eventHubId %d.", eventHubId); 6 return; 7 } 8 9 std::shared_ptr<InputDevice>& device = deviceIt->second; 10 if (device->isIgnored()) { 11 // ALOGD("Discarding event for ignored deviceId %d.", deviceId); 12 return; 13 } 14 15 device->process(rawEvents, count); 16}

再之后经过一系统复杂的调用,到InputDispacher来进行分发,具体分析流程可以见博文,讲得非常详细

https://www.jianshu.com/p/d10cfe854654
,同时在这些调用中,可以发现安卓事件分发响应为啥这么耗时,因为这里面流程复杂,且有相当多的耗时函数。这里的注释意思是所有事件都要保存按顺序执行。

1// Process all of the events in order for each mapper. 2// We cannot simply ask each mapper to process them in bulk because mappers may 3// have side-effects that must be interleaved. For example, joystick movement events and 4// gamepad button presses are handled by different mappers but they should be dispatched 5// in the order received.

分发过程中,要确定targetdisplayid,inputTargets,就是拿到channels。

1bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry, 2 DropReason* dropReason, nsecs_t* nextWakeupTime) { 3 // Preprocessing. 4... 5 6 // Add monitor channels from event's or focused display. 7 addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry)); 8 9 // Dispatch the key. 10 dispatchEventLocked(currentTime, entry, inputTargets); 11 return true; 12}

InputPublisher通过 InputChannel::sendMessage将DispatchEntry发送给焦点窗口,而InputChannel的创建也就到了WMS给每个应用进程创建window的过程。

2. Input与WMS的连接InputChannel

IMS里面InputChannel::sendMessage发送消息

1void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, 2 std::shared_ptr<EventEntry> eventEntry, 3 const std::vector<InputTarget>& inputTargets) { 4 ATRACE_CALL(); 5#if DEBUG_DISPATCH_CYCLE 6 ALOGD("dispatchEventToCurrentInputTargets"); 7#endif 8 9 updateInteractionTokensLocked(*eventEntry, inputTargets); 10 11 ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true 12 13 pokeUserActivityLocked(*eventEntry); 14 15 for (const InputTarget& inputTarget : inputTargets) { 16 sp<Connection> connection = 17 getConnectionLocked(inputTarget.inputChannel->getConnectionToken()); 18 if (connection != nullptr) { 19 prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget); 20 } else { 21 if (DEBUG_FOCUS) { 22 ALOGD("Dropping event delivery to target with channel '%s' because it " 23 "is no longer registered with the input dispatcher.", 24 inputTarget.inputChannel->getName().c_str()); 25 } 26 } 27 }

最终会调到enqueueDispatchEntryLocked里的 connection->outboundQueue.push_back(dispatchEntry.release());

1void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection, 2 std::shared_ptr<EventEntry> eventEntry, 3 const InputTarget& inputTarget, 4 int32_t dispatchMode) { 5 ... 6 7 // Enqueue the dispatch entry. 8 connection->outboundQueue.push_back(dispatchEntry.release()); 9 traceOutboundQueueLength(*connection); 10}

发送消息和选取window是事件需要处理的两个问题,当确定哪个inputchannel的时候就已经有这两个答案了。

InputChannel其实就是linux unix socket的一种封装, unixsocket是linux的一种跨进程通信方式。系统创建InputChannel对即unix socket对,系统server端和程序client各只有其中一个,这样通过unix socket就可以给对方发送消息,而这里的事件就是通过这种方式从系统进程传递到程序进程的。系统InputChannel的整个处理逻辑如下:

在上篇中,viewroot创建时会根据需要创建一个inputchannel,传递给wms,window创建完之后,WMS addwindow的过程中,创建channel对,一个保存在window里,另一个传到程序端。

1/** 2 * Does not construct an input channel for this window. The channel will therefore 3 * be incapable of receiving input. 4 * 5 * @hide 6 */ 7 public static final int INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002; 8 9 10 if ((mWindowAttributes.inputFeatures 11 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { 12 mInputChannel = new InputChannel(); 13 }
1void openInputChannel(InputChannel outInputChannel) { 2 if (mInputChannel != null) { 3 throw new IllegalStateException("Window already has an input channel."); 4 } 5 String name = getName(); 6 InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); 7 mInputChannel = inputChannels[0]; 8 mClientChannel = inputChannels[1]; 9 mInputWindowHandle.token = mClient.asBinder(); 10 if (outInputChannel != null) { 11 mClientChannel.transferTo(outInputChannel); 12 mClientChannel.dispose(); 13 mClientChannel = null; 14 } else { 15 // If the window died visible, we setup a dummy input channel, so that taps 16 // can still detected by input monitor channel, and we can relaunch the app. 17 // Create dummy event receiver that simply reports all events as handled. 18 mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel); 19 } 20 mWmService.mInputManager.registerInputChannel(mInputChannel, mClient.asBinder()); 21 }

InputChannel.openInputChannelPair(name)在实现在native中,

frameworks/base/core/jni/android_view_inputChannel.cpp,frameworks/native/libs/input/InputTransport.cpp

通过registerInputChannel注册到native层。客户端ViewRootImpl.setView的时候会把创建的inputchannel,注册并加到线程的looper里面。

1public InputEventReceiver(InputChannel inputChannel, Looper looper) { 2 if (inputChannel == null) { 3 throw new IllegalArgumentException("inputChannel must not be null"); 4 } 5 if (looper == null) { 6 throw new IllegalArgumentException("looper must not be null"); 7 } 8 9 mInputChannel = inputChannel; 10 mMessageQueue = looper.getQueue(); 11 mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this), 12 inputChannel, mMessageQueue); 13 14 mCloseGuard.open("dispose"); 15}

frameworks/base/core/jni/android_view_inputEventReceiver.cpp

1status_t NativeInputEventReceiver::initialize() { 2 setFdEvents(ALOOPER_EVENT_INPUT); 3 return OK; 4}
1void NativeInputEventReceiver::setFdEvents(int events) { 2 if (mFdEvents != events) { 3 mFdEvents = events; 4 int fd = mInputConsumer.getChannel()->getFd(); 5 if (events) { 6 mMessageQueue->getLooper()->addFd(fd, 0, events, this, nullptr); 7 } else { 8 mMessageQueue->getLooper()->removeFd(fd); 9 } 10 } 11}

至此InputChannel在ViewRootImpl中创建,在wms中创建连接socket,保存到IMS的连接池的过程就完成了。Input子系统的事件可以传到应用进程了。当接收到事件的时候,就会在应用层按如下流程处理,基本都是标准流程,就不展开说明了。

Anrdoid事件流程流程大体如文中几个图所示,需要特别注意的是:对系统来说,Inputdispatcher.cpp是一个非常重要的类,event的监听,设备的监听,与client端channel的连接,window的分发都是由他来处理的。

参考资料