View机制深入学习 事件处理机制一
Posted 流云易采
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了View机制深入学习 事件处理机制一相关的知识,希望对你有一定的参考价值。
以TouchEvent为主,看一下View和ViewGroup内部是如何处理Input Events的;
首先来看事件的产生来源:
一、获取事件:
事件的来源可以分为“软件”,“硬件”两种;
主要的事件包含有:
按键事件(KeyEvent) :即物理按键按下产生的事件,相关的常用物理按键一般有HOME,BACK等
触摸事件(TouchEvent):
鼠标事件(MouseEvent)、轨迹球事件(TrackBallEvent)(这两个已经不常见);
针对所有事件的共性抽象出了InputEvent接口;其有两个子类:KeyEvent,MotionEvent;
1、事件的投递流程:
1>源信息采集
对“硬件源”产生的原始信息进行收集;它需要Linux内核驱动的支持,android系统通过/dev/input下的节点来访问当前发生的事件。
2>前期处理
对收集到信息进行筛选以及格式转化
3>WMS分配
WMS是窗口的Manager,同时也是InputEvent的派发者。
4>应用程序处理
WMS会先把事件传递到对应ViewRootImpl,ViewRootImpl分发事件,传递给相应的DecorView,DecorView在调用Activity中的Window.Callback将事件传递给Activity;然后Activity在通过dispatchTouchEvent分发事件,下面就来到熟悉的View事件分发机制;具体见《View机制深入学习(四)View的事件分发机制》
2、InputManagerService启动:
InputManagerService同样也是有SystemServer进程启动,这个在Android启动过程——init.rc,Zygote,SystemServer中已经提到过,
系统启动后创建init进程(pid=1),init进程创建出Zygote进程,然后Zygote进程孵化出SystemServer进程,在SystemServer进程中创建IMS:
/** @path: \\frameworks\\base\\services\\java\\com\\android\\server\\SystemServer.java */
class ServerThread extends Thread
@Override
public void run()
// 可以看到IMS和WMS是紧密相关的
......
// @value InputManagerService inputManager
inputManager = new InputManagerService(context, wmHandler);
Slog.i(TAG, "Window Manager");
// @value WindowManagerService wm
wm = WindowManagerService.main(context, power, display, inputManager,
uiHandler, wmHandler,
factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
!firstBoot, onlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
ActivityManagerService.self().setWindowManager(wm);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
.....
3、InputMangerService:
/** \\frameworks\\base\\services\\core\\java\\com\\android\\server\\input\\InputManagerService.java **/
public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor
// 指向native端IMS类对象的地址
private final long mPtr;
public InputManagerService(Context context)
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
// 创建native IMS对象
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
LocalServices.addService(InputManagerInternal.class, new LocalService());
可以看到Java层的IMS实际上只是对Native层的InputManager的一层包装;其创建主要是native层进行创建,并把native层的InputManager地址赋值给InputManagerService的mPtr变量;
而且注意nativeInit中传入了Looper中的MessageQueue变量;
4、native层的InputManagerService——NativeInputManager类:
/** \\frameworks\\base\\services\\core\\jni\\com_android_server_input_InputManagerService.cpp **/
class NativeInputManager : public virtual RefBase,
public virtual InputReaderPolicyInterface,
public virtual InputDispatcherPolicyInterface,
public virtual PointerControllerPolicyInterface
static jlong nativeInit(JNIEnv* env, jclass clazz,
jobject serviceObj, jobject contextObj, jobject messageQueueObj)
// 创建一个Message Queue
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL)
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
// 可以看到NativeInputManager中包含有一个Looper,用以进行事件分派
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
// 返回创建的IMS实例对象的地址(强制转化为long类型)
return reinterpret_cast<jlong>(im);
可以看到首先通过android_os_MessageQueue_getMessageQueue函数获取到本地端的MessageQueue,这个在Handler机制中的本地解析《Handler机制深入解析》中已经提到,该NativeMessageQueue对象在java层创建Looper时创建实例,然后将地址指针赋值为Looper对应的MessageQueue中的ptr变量中,这里根据指针来获取该NativeMessageQueue对象;
根据NativeMessageQueue对象获取其中对应的Looper(native),用以创建NativeInputManger;来看NativeInputManager的构造函数:
5、NativeInputManager#NativeInputManager:
/** \\frameworks\\base\\services\\core\\jni\\com_android_server_input_InputManagerService.cpp **/
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true)
JNIEnv* env = jniEnv();
// 全局引用
mContextObj = env->NewGlobalRef(contextObj);
mServiceObj = env->NewGlobalRef(serviceObj);
AutoMutex _l(mLock);
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
// 创建EventHUb
sp<EventHub> eventHub = new EventHub();
// 创建InputManager实例
mInputManager = new InputManager(eventHub, this, this);
NativeInputManager中保存了Looper(native)实例;并且创建了EventHub,以及InputManager两个重要的对象;
EventHub从名字就可以看出,它是用来收集以及存储外部的输入事件的;
而InputManager则是对Event事件进行处理分发;
先来看EventHub:
(一)EventHub:
/*\\frameworks\\native\\services\\inputflinger\\EventHub*/
static const char *DEVICE_PATH = "/dev/input";
EventHub::EventHub(void) :
mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
mOpeningDevices(0), mClosingDevices(0),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false), mNeedToScanDevices(true),
mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false)
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
// 创建epoll对象
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
// 采用inotify机制监听文件或目录的移动、读取、写入或删除等事件
// 创建一个inotify对象
mINotifyFd = inotify_init();
// 把监控项添加到mINotifyFd对象的监控列表中
// 这里监听的文件路径为"/dev/input"
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = EPOLL_ID_INOTIFY;
// 把inotify对象mINotifyFd添加到epoll对象的兴趣列表中,此处采用inotify与epoll机制结合起来检查文件
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
int wakeFds[2];
// 创建pipe
result = pipe(wakeFds);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
// 设置为非阻塞
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
eventItem.data.u32 = EPOLL_ID_WAKE;
// 添加到epoll的兴趣列表中
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
int major, minor;
getLinuxRelease(&major, &minor);
// EPOLLWAKEUP was introduced in kernel 3.5
mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
在前面进行了一系列的变量的初始化;
然后epoll_create创建了一个epoll对象,可以看到和Handler中一样,IMS中也用到了epoll机制进行监听;
而后可以看到IMS是INotify机制和Epoll机制同时使用的:inotify_init创建iNotify对象,inotify_add_watch则将”/dev/input”路径添加到监听列表中;当”/dev/input”中文件发生变化,将会产生响应;
了解INotifiy文件系统监听机制:
《inotify – Linux 2.6 内核中的文件系统变化通知机制》
《Inotify: 高效、实时的Linux文件系统事件监控框架》
然后将iNotify对象添加到Epoll的兴趣列表中,进行监听;
然后同Handler机制,创建一个Pipe,然后设置为非阻塞形式,然后添加到epoll的兴趣列表中;下面就注意在何时调用epoll_wait来开启监听即可;这里仅进行了初始化;
(二)InputManager:
1)构造函数:
/** \\frameworks\\native\\services\\inputflinger\\InputManager.cpp **/
class InputManagerInterface : public virtual RefBase
private:
sp<InputReaderInterface> mReader;
sp<InputReaderThread> mReaderThread;
sp<InputDispatcherInterface> mDispatcher;
sp<InputDispatcherThread> mDispatcherThread;
// 构造函数
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy)
// 创建InputDispatcher
mDispatcher = new InputDispatcher(dispatcherPolicy);
// 创建InputReader
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
/*** 进行初始化 **/
void InputManager::initialize()
// 创建两个Thread的实例
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
;
InputManager中传入了前面创建的EventHub对象;然后初始化了两个中重要的类,InputDispatcher,以及InputReader;
显然从名字可以看出 InputReader用来读取EventHub中的事件,然后通过InputDiapatcher进行分发(InputReader中持有InputDisptcher的引用);
先看InputDispatcher:
1.1)InputDispatcher:
继承关系:
class InputDispatcher : public InputDispatcherInterface
class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface
构造函数:
/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
mPolicy(policy),
mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE)
// 可以看到这里创建了一个Looper
mLooper = new Looper(false);
mKeyRepeatState.lastKeyEntry = NULL;
policy->getDispatcherConfiguration(&mConfig);
在构造函数中创建了一个Looper(native),注意这里是新创建了一个Looper对象,和ThreadLocal中该线程中的Looper是没有关系的;
再来看InputReader
1.2)InputReader:
class InputReader : public InputReaderInterface
class InputReaderInterface : public virtual RefBase
构造函数:
/** \\frameworks\\native\\services\\inputflinger\\InputReader.cpp **/
InputReader::InputReader(const sp<EventHubInterface>& eventHub, // 前面提到的创建的EventHub
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) : // 即传入进来的InputDispatcher
mContext(this), mEventHub(eventHub), mPolicy(policy), // 一系列初始化
mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0)
// 创建一个QueuedInputListener对象,赋值给mQueuedListener
mQueuedListener = new QueuedInputListener(listener);
// acquire lock
AutoMutex _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
// release lock
InputReader中包含了前面创建的EventHub,以及用以分发事件的InputDispatcher;在InputReader内部,将其封装成了QueuedInputListener类;
继续InputManager构造函数中内容,initialize进行初始化:
2)InputManager#initialize:
/*** 进行初始化 **/
void InputManager::initialize()
// 创建两个Thread的实例
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
新创建了两个对象,这两个类都是继承Thread的,即对应地使用InputReader,以及InputDispatcher为参数创建了两个线程;
分别来看:
2.1> InputReaderThread:
2.1.1)InputReaderThread类:
/** \\frameworks\\native\\services\\inputflinger\\InputReader.h **/
/** 无限循环从event hub中读取event,然后读取processes他们 */
class InputReaderThread : public Thread
public:
InputReaderThread(const sp<InputReaderInterface>& reader);
virtual ~InputReaderThread();
private:
sp<InputReaderInterface> mReader;
/** 继承Thread的子类必须实现该函数,因为这个其实是Thread的真正执行函数 **/
// Derived class must implement threadLoop(). The thread starts its life
// here. There are two ways of using the Thread object:
// 1) loop: if threadLoop() returns true, it will be called again if
// requestExit() wasn't called.
// 2) once: if threadLoop() returns false, the thread will exit upon return.
virtual bool threadLoop();
;
可以看到InputReaderThread是一个Thread类,它的线程函数入口为threadLoop;
2.1.2)InputReaderThread类构造函数:
/** \\frameworks\\native\\services\\inputflinger\\InputReader.cpp **/
InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
Thread(/*canCallJava*/true), mReader(reader)
// 这里初始化重要变量sp<InputReaderInterface> mReader
bool InputReaderThread::threadLoop()
// 调用mReader中的loopOnce函数,可以看出InputReaderInterface是该类的核心
mReader->loopOnce();
return true;
InputReaderThread的核心逻辑为调用InputReader的loopOnce函数;暂且停在这里,因为Thread只是创建,并未运行,等分析到具体运行代码时再作分析;
2.2>InputDispatcherThread
/* \\frameworks\\native\\services\\inputflinger\\InputDispatcher.h */
class InputDispatcherThread : public Thread
public:
explicit InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher);
~InputDispatcherThread();
private:
virtual boolthreadLoop();
sp<InputDispatcherInterface> mDispatcher;
;
bool InputDispatcherThread::threadLoop()
mDispatcher->dispatchOnce();
return true;
该类同样是一个Thread,其主要运行逻辑即调用InputDispatcher中的dispatchOnce函数;
回到InputManagerService在SystemServer进程中的创建过程知道,接下来创建WindowManagerService,然后将InputManagerService实例传递给WMS,然后调用InputManagerService.start开始工作。
7、InputManagerService#start:
/** \\frameworks\\base\\services\\core\\java\\com\\android\\server\\input\\InputManagerService.java **/
public void start()
......
nativeStart(mPtr);
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
......
private static native void nativeStart(long ptr);
可以看到start仅是对nativeStart本地方法进行封装,继续通过JNI来调用本地端的start函数;注意这里创建了WatchDog看门狗线程,并且把InputManagerService实例添加到WatchDog的监听;系统创建看门狗线程,每隔一段时间向管道中写入数据唤醒InputReader线程(后面会提到)去读取事件,看门狗WatchDog实际上也是一个线程,只不过会定时发送消息给InputReader线程读取输入事件。
8、NativeInputManager#nativeStart:
/** \\frameworks\\base\\services\\core\\jni\\com_android_server_input_InputManagerService.cpp **/
static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr)
// ptr为创建的IMS实例的地址,这里将其强制转化成为NativeInputManager类
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
// 这里进一步调用InputManager的star方法
status_t result = im->getInputManager()->start();
if (result)
jniThrowRuntimeException(env, "Input manager could not be started.");
// @value sp<InputManager> mInputManager;
inline sp<InputManager> getInputManager() const return mInputManager;
可以看到这里进一步调用了InputManager的start方法;IMS在Native层的主要实现实体其实是InputManager。
9、InputManager#start:
/** \\frameworks\\native\\services\\inputflinger\\InputManager.cpp **/
class InputManagerInterface : public virtual RefBase
private:
sp<InputReaderInterface> mReader;
sp<InputReaderThread> mReaderThread;
sp<InputDispatcherInterface> mDispatcher;
sp<InputDispatcherThread> mDispatcherThread;
// start函数
status_t InputManager::start()
// 可以看到这里会开启两个线程mDispatcherThread,与mReaderThread
// 分别对应InputReaderThread,InputDispatcherThread
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
......
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
if (result)
mDispatcherThread->requestExit();
return result;
return OK;
;
回到InputManager中来,来看start函数中所做的工作,在start中调用两个thread的run函数正是开启线程;由Thread的线程入口为threadLoop;前面已经提到了这两个Thread的入口函数,这里来看其中的具体工作逻辑;
10、InputDispatcherThread&InputReaderThread
InputDispatcherThread#threadLoop:
由前面知InputDispatcherThread中主要通过调用InputDispatcher的dispathOnce来实现的;
1)InputDispatcher::dispatchOnce:
/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::dispatchOnce()
nsecs_t nextWakeupTime = LONG_LONG_MAX;
// acquire lock
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();
// 在没有等待的commands事运行一个dispatch loop,这个loop之后可能enqueue commands
if (!haveCommandsLocked())
dispatchOnceInnerLocked(&nextWakeupTime);
// 如果有等待的commands的话,就运行所有的commands
// If any commands were run then force the next poll to wake up immediately.
if (runCommandsLockedInterruptible())
nextWakeupTime = LONG_LONG_MIN;
// release lock
// Wait for callback or timeout or wake. (make sure we round up, not down)
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
初始状态下是没有事件的,来到mLooper->pollOnce,了解Handler机制的native层知道,在pollOnce中调用epoll_wait对前面设置的兴趣事件进行监听,然后InputDispatchThread进入休眠等待唤醒;可想而知下面策略是InputReaderThread来对其进行唤醒;
InputReaderThread#threadLoop:
InputReaderThread中的主要逻辑是调用InputReader中的loopOnce函数
1)InputReader#loopOnce :
/** \\frameworks\\native\\services\\inputflinger\\InputReader.h **/
class InputReaderInterface : public virtual RefBase
class InputReader : public InputReaderInterface
/** \\frameworks\\native\\services\\inputflinger\\InputReader.cpp **/
// loopOnce即事件处理函数
void InputReader::loopOnce()
......
// 其实是通过mEventHub来获取Events的
// @value sp<EventHubInterface> mEventHub;
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
......
// @value sp<QueuedInputListener> mQueuedListener;
mQueuedListener->flush();
可以看到这里通过EventHub的getEvents来获取/dev/input中的Event事件,然后用到前面提到的封装了InputDispatcher的QueueListener来分发事件;
EventHub获取Events的具体流程:Android按键事件传递流程(一)
主要工作流程是注册这些监听的devices,然后调用epoll_wait使得InputReaderThread等待唤醒;
获取Events的过于复杂,直接跳过,来看事件的传递;当获取到Event之后,调用mQueuedListener的flush来传递消息;
二、事件分发
前面提到使用EventHub的getEvents来获取Events之后,通过mQueuedListener的flush开始消息的分发;
1、QueueInputListener#flush:
1)先看QueueInputListener的定义:
/** \\frameworks\\native\\services\\inputflinger\\InputListener.h **/
class QueuedInputListener : public InputListenerInterface
protected:
virtual ~QueuedInputListener();
public:
QueuedInputListener(const sp<InputListenerInterface>& innerListener);
virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
virtual void notifyKey(const NotifyKeyArgs* args);
virtual void notifyMotion(const NotifyMotionArgs* args);
virtual void notifySwitch(const NotifySwitchArgs* args);
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
void flush();
private:
sp<InputListenerInterface> mInnerListener;// mInnerListner即是InputDispatcher
Vector<NotifyArgs*> mArgsQueue; // 后面flush函数中将会用到
;
在InputReader的构造函数中,传递进来的mInnerListener即为InputDispatcher;
2)flush函数:
/** \\frameworks\\native\\services\\inputflinger\\InputListener.cpp **/
void QueuedInputListener::flush()
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++)
NotifyArgs* args = mArgsQueue[i];
// 调用NotifyArgs。notify函数
args->notify(mInnerListener);
delete args;
mArgsQueue.clear();
// 这里仅是一个封装函数,最终调用InputListenerInterface的notifyKey函数
void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const
listener->notifyKey(this);
前面最终调用InputListenerInterface(即InputDispatcher)的notifyKey回调函数;
总结前面的流程即InputReaderThread通过EventHub不断读取获取event信息,获得事件后,调用InputDispather的notifyKey函数来通知InputDispathcer进行处理。注意这里调用InputDispatcher的notifyKey函数依然是在InputReaderThread线程中进行的,此时InputDispathcerThread仍然是epoll_wait阻塞状态中;
2、InputDispatcher::notifyKey:
/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::notifyKey(const NotifyKeyArgs* args)
if (!validateKeyEvent(args->action)) // 判断event是否合法
return;
......
// 初始化KeyEvent
KeyEvent event;
event.initialize(args->deviceId, args->source, args->action,
flags, keyCode, args->scanCode, metaState, 0,
args->downTime, args->eventTime);
bool needWake;
// acquire lock
mLock.lock();
if (shouldSendKeyToInputFilterLocked(args))
mLock.unlock();
policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags))
return; // event was consumed by the filter
mLock.lock();
int32_t repeatCount = 0;
KeyEntry* newEntry = new KeyEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
args->action, flags, keyCode, args->scanCode,
metaState, repeatCount, args->downTime);
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
// release lock
// 唤醒InputDispatcherThread线程
if (needWake)
mLooper->wake();
该部分对传递过来的按键事件进行检查、验证,之后处理特殊按键,将原始按键信息封装成KeyEntry,再调用enqueueInboundEventLocked函数把KeyEntry添加到InboundQueue队列中,最后调用Looper对象的wake往管道中写入字符唤醒InputDispatcherThread线程(类似于Handler机制中的唤醒);
先来看enqueueInboundEventLocked添加事件到InboundQueue队列中:
1)InputDispatcher::enqueueInboundEventLocked:
/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry)
// @value Queue<EventEntry> mInboundQueue;
bool needWake = mInboundQueue.isEmpty();
// 将entry入队列
mInboundQueue.enqueueAtTail(entry);
switch (entry->type) // 如前面所述,InputEvent分为KeyEvent和MotionEvent进行分别处理
case EventEntry::TYPE_KEY: ......
case EventEntry::TYPE_MOTION: .....
return needWake;
将entry添加到InboundQueue队列尾部;然后判断是否需要唤醒,即needWake是否为true;当mInboundQueue不为空,则明显InputDispathcerThread仍处于运行状态来分发事件,因而不用进行唤醒;而当mInboundQueue为空时,测试InputDispatcherThread进行休眠状态,使用wake对其来唤醒;
InputDispatcherThread之前调用Looper的poolOnce函数阻塞休眠,这里调用wake将其唤醒;因为InputDispatcherThread的threadLoop返回值为true,表示该Thread是循环执行的,故继续调用其dispatchOnce函数;
3、InputDispatcher::dispatchOnce:
/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::dispatchOnce()
nsecs_t nextWakeupTime = LONG_LONG_MAX;
// acquire lock
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();
// 在没有等待的commands事运行一个dispatch loop,这个loop之后可能enqueue commands
if (!haveCommandsLocked())
dispatchOnceInnerLocked(&nextWakeupTime);
// 如果有等待的commands的话,就运行所有的commands
// If any commands were run then force the next poll to wake up immediately.
if (runCommandsLockedInterruptible())
nextWakeupTime = LONG_LONG_MIN;
// release lock
// Wait for callback or timeout or wake. (make sure we round up, not down)
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
来到dispatchOnceInnerLocked:
4、InputDispathcer#dispatchOnceInnerLocked:
/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime)
nsecs_t currentTime = now();
if (! mPendingEvent)
if (mInboundQueue.isEmpty()) // 当前mInboundQueue已经存在元素
......
else
// Inbound queue has at least one entry.
mPendingEvent = mInboundQueue.dequeueAtHead();
traceInboundQueueLengthLocked();
......
// Now we have an event to dispatch.
// All events are eventually dequeued and processed this way, even if we intend to drop them.
ALOG_ASSERT(mPendingEvent != NULL);
.......
// 根据mPendingEvent的Type的不同分别进行处理
switch (mPendingEvent->type)
case EventEntry::TYPE_CONFIGURATION_CHANGED:
......
done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped
break;
// KeyEvent采用dispatchKeyLocked进行处理
case EventEntry::TYPE_KEY:
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
......
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
// MotionEvent采用dispatchMotionLocked进行处理
case EventEntry::TYPE_MOTION:
......
done = dispatchMotionLocked(currentTime, typedEntry,
&dropReason, nextWakeupTime);
break;
default:
ALOG_ASSERT(false);
break;
if (done)
if (dropReason != DROP_REASON_NOT_DROPPED)
dropInboundEventLocked(mPendingEvent, dropReason);
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
可以看到是事件处理机制中常用的处理模式,类似于Handler机制,这里先dequeueAtHead使得InBoundQueue事件队列中的事件出队列(FIFO);然后根据事件的类似进行不同的处理;如TYPE_KEY类型事件采用dispatchKeyLocked;TYPE_MOTION类型事件采用dispatchMotionLocked处理
下面以KeyEvent为例进行分析,下面忽略对event的具体处理细节,具体来看事件是如何传递的;
5、InputDispatcher::dispatchKeyLocked:
/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime)
......
/** 确定事件的接收方(Target) **/
Vector<InputTarget> inputTargets;
int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
setInjectionResultLocked(entry, injectionResult);
addMonitoringTargetsLocked(inputTargets);
/** 将消息dispatch给Target **/
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
前面对event的处理细节忽略,重点来看系统是如何查找event对应的接收方(Target)的,这里的InputTarget指定一个输入事件如何被分发到一个特定窗口。该结构体包含了很多特征变量:x,y坐标,输入事件通道InputChannel等;
这里通过findFocusedWindowTargetsLocked来确定InputTarget的,然后调用dispatchEventLocked来将Event分发给具体的Target;
接下来分析函数findFocusedWindowTargetsLocked;
6、InputDispatcher::findFocusedWindowTargetsLocked:
/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime)
int32_t injectionResult;
String8 reason;
// mFocusedWindowHandle表示当前焦点窗口的句柄
// @value sp<InputWindowHandle> mFocusedWindowHandle;
/** 当获得焦点的窗口为null时,会丢弃这一事件 **/
if (mFocusedWindowHandle == NULL)
if (mFocusedApplicationHandle != NULL)
// 如果没有焦点窗口,但焦点窗口所在的应用程序进程存在,说明该应程序还在启动过程中,故等待nextWakeupTime后再重试
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
mFocusedApplicationHandle, NULL, nextWakeupTime,
"Waiting because no window has focus but there is a "
"focused application that may eventually add a window "
"when it finishes starting up.");
goto Unresponsive;
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
/** 如果执行到这里说明当前有焦点窗口 **/
// 先判断权限
if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState))
injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
goto Failed;
// 如果当前焦点窗口正在处理上一个事件,采取和最上面一样的作法,等待一段时间后重试
reason = checkWindowReadyForMoreInputLocked(currentTime,
mFocusedWindowHandle, entry, "focused");
if (!reason.isEmpty())
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());
goto Unresponsive;
// 成功找到匹配的窗口,通过addWindowTargetLocked添加到inputTargets变量中
injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
addWindowTargetLocked(mFocusedWindowHandle,
InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
inputTargets);
Failed:
Unresponsive:
nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
updateDispatchStatisticsLocked(currentTime, entry,
injectionResult, timeSpentWaitingForApplication);
return injectionResult;
上面查找焦点窗口的逻辑很清晰, 当mFocusedWindowHandle为null时,如果mFocusedApplicationHandle不为null,表示当前没有焦点窗口,但焦点窗口所在的应用程序进程存在,说明该应程序还在启动过程中,故等待nextWakeupTime后再重试;如果mFocusedApplicationHandle为null,则丢弃该事件,因为没有能够接收该事件的窗口;
如果mFocusedWindowHandle不为null,先判断当前窗口是否locked,如果是表示正在处理其他输入事件,这时采用和上面相同的策略,等待一段时间后,然后重试。
当找到匹配的目标窗口之后,赋值给InputTarget;先来看InputTarget的定义:
7、InputTarget:
/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.h **/
/*
* An input target specifies how an input event is to be dispatched to a particular window
* including the window's input channel, control flags, a timeout, and an X / Y offset to
* be added to input event coordinates to compensate for the absolute position of the
* window area.
*/
struct InputTarget
enum // 该枚举类列举个关于目标窗口的各种属性值描述
/* This flag indicates that the event is being delivered to a foreground application. */
FLAG_FOREGROUND = 1 << 0, // 说明目标窗口是前台应用
......
/** InputDispatcher与WMS建立关联通信的地方 */
sp<InputChannel> inputChannel;
;
这里引出了重要的类InputChannel,InputDispatcher与WMS之间的通信,正是通过InputChannel来实现的。
继续前面的dispatchKeyLocked函数,接下来会调用dispatchEventLocked来传递消息;
8、InputDispatcher#dispatchEventLocked
/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector<InputTarget>& inputTargets)
ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
pokeUserActivityLocked(eventEntry);
for (size_t i = 0; i < inputTargets.size(); i++)
const InputTarget& inputTarget = inputTargets.itemAt(i);
// 根据inputChannel(其中的fd)来获取对应的Connection
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0)
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
// 继续向下调用
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
这里根据InputChannel的fd值来获取对应的Connection对象,InputChannel以及Connection的相关知识可以西安看第三章;Connection是用来管理InputChannel的变量;然后接着调用 prepareDispatchCycleLocked;
/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget)
// Split a motion event if needed.
if (inputTarget->flags & InputTarget::FLAG_SPLIT)
ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION);
MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry);
if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount)
MotionEntry* splitMotionEntry = splitMotionEvent(
originalMotionEntry, inputTarget->pointerIds);
if (!splitMotionEntry)
return; // split event was dropped
enqueueDispatchEntriesLocked(currentTime, connection,
splitMotionEntry, inputTarget);
splitMotionEntry->release();
return;
// Not splitting. Enqueue dispatch entries for the event as is.
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
最后接着调用 enqueueDispatchEntriesLocked函数:
/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget)
bool wasEmpty = connection->outboundQueue.isEmpty();
// Enqueue dispatch entries for the requested modes.
// 将dispatch entries入队列
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_IS);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
// 开始分发事件
if (wasEmpty && !connection->outboundQueue.isEmpty())
startDispatchCycleLocked(currentTime, connection);
enqueueDispatchEntryLocked创建DispatchEntry(按键事件对象),并且把该对象作为一个发送数据包加入到outboundQueue队列中;
startDispatchCycleLocked取出outboundQueue队列头元素,赋给dispatchEntry,再取出事件对象KeyEntry,根据事件类型确定case语句分支,如果是按键事件,就调用connection的InputPublisher的publishKeyEvent函数发送到inputchannel中,如果publishKeyEvent返回0,表示按键事件发送成功;
InputDispathcer#enqueueDispatchEntryLocked:
/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::enqueueDispatchEntryLocked(
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
int32_t dispatchMode)
int32_t inputTargetFlags = inputTarget->flags;
// 如果inputTargetFlags和dispatchMode不匹配
if (!(inputTargetFlags & dispatchMode))
return;
inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;
// 创建DispatchEntry
DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
inputTarget->scaleFactor);
......
// Enqueue the dispatch entry.
// 添加到outboundQueue中
connection->outboundQueue.enqueueAtTail(dispatchEntry);
9、InputDispathcer#startDispatchCycleLocked:
/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection)
while (connection->status == Connection::STATUS_NORMAL
&& !connection->outboundQueue.isEmpty())
// 取出outboundQueue的首部元素
DispatchEntry* dispatchEntry = connection->outboundQueue.head;
dispatchEntry->deliveryTime = currentTime;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
// 根据EventEntry的Type类型进行处理
switch (eventEntry->type)
case EventEntry::TYPE_KEY:
KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
// Publish the key event.
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);
break;
case EventEntry::TYPE_MOTION:
以上是关于View机制深入学习 事件处理机制一的主要内容,如果未能解决你的问题,请参考以下文章