Input事件流程:修订间差异
无编辑摘要 |
无编辑摘要 |
||
| 第4行: | 第4行: | ||
这里没有显式的使用 new创建,而是调用了类中静态函数 WindowManagerService.main,同时我们也看到 WindowManagerService的构建函数为private类型: | 这里没有显式的使用 new创建,而是调用了类中静态函数 WindowManagerService.main,同时我们也看到 WindowManagerService的构建函数为private类型: | ||
< | <source lang="c"> | ||
private WindowManagerService(Context context, PowerManagerService pm, | private WindowManagerService(Context context, PowerManagerService pm, | ||
DisplayManagerService displayManager, InputManagerService inputManager, | DisplayManagerService displayManager, InputManagerService inputManager, | ||
| 第10行: | 第10行: | ||
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) | boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) | ||
... | ... | ||
</ | </source> | ||
其实这是非常常见的单实例类,这里不过多描述,继续看: | 其实这是非常常见的单实例类,这里不过多描述,继续看: | ||
'''''SystemServer.java''''' | '''''SystemServer.java''''' | ||
< | <source lang="c"> | ||
class ServerThread extends Thread { | class ServerThread extends Thread { | ||
... | ... | ||
| 第31行: | 第31行: | ||
ServiceManager.addService(Context.WINDOW_SERVICE, wm); | ServiceManager.addService(Context.WINDOW_SERVICE, wm); | ||
... | ... | ||
</ | </source> | ||
进入该 main函数: | 进入该 main函数: | ||
'''''WindowManagerService.java''''' | '''''WindowManagerService.java''''' | ||
< | <source lang="c"> | ||
public static WindowManagerService main(Context context, | public static WindowManagerService main(Context context, | ||
PowerManagerService pm, boolean haveInputMethods, boolean allowBootMsgs) { | PowerManagerService pm, boolean haveInputMethods, boolean allowBootMsgs) { | ||
| 第52行: | 第52行: | ||
} | } | ||
} | } | ||
</ | </source> | ||
创建了WMThread并start,呵呵,看到start应该条件反射地想到run了: | 创建了WMThread并start,呵呵,看到start应该条件反射地想到run了: | ||
< | <source lang="c"> | ||
static class WMThread extends Thread { | static class WMThread extends Thread { | ||
... | ... | ||
| 第69行: | 第69行: | ||
} | } | ||
} | } | ||
</ | </source> | ||
果然,是在这里创建了 WindowManagerService,继续跟进: | 果然,是在这里创建了 WindowManagerService,继续跟进: | ||
< | <source lang="c"> | ||
private WindowManagerService(Context context, PowerManagerService pm, | private WindowManagerService(Context context, PowerManagerService pm, | ||
boolean haveInputMethods, boolean showBootMsgs) { | boolean haveInputMethods, boolean showBootMsgs) { | ||
| 第79行: | 第79行: | ||
... | ... | ||
} | } | ||
</ | </source> | ||
嗯,终于看到与 "Input"相关的东东了:InputManager,看名字应该是 Input事件的管理类。 | 嗯,终于看到与 "Input"相关的东东了:InputManager,看名字应该是 Input事件的管理类。 | ||
'''''InputManager.java''''' | '''''InputManager.java''''' | ||
< | <source lang="c"> | ||
public InputManager(Context context, WindowManagerService windowManagerService) { | public InputManager(Context context, WindowManagerService windowManagerService) { | ||
this.mContext = context; | this.mContext = context; | ||
| 第97行: | 第97行: | ||
Watchdog.getInstance().addMonitor(this); | Watchdog.getInstance().addMonitor(this); | ||
} | } | ||
</ | </source> | ||
构建函数很简单,无非是一些成员变量的赋值,除此之外就是两个函数:nativeInit和Watchdog.getInstance().addMonitor(this)。第一个函数我们要深入分析才知道干了些啥;第个二则是将此实例加入Watchdog的监视列表mMonitors. | 构建函数很简单,无非是一些成员变量的赋值,除此之外就是两个函数:nativeInit和Watchdog.getInstance().addMonitor(this)。第一个函数我们要深入分析才知道干了些啥;第个二则是将此实例加入Watchdog的监视列表mMonitors. | ||
'''''com_android_server_InputManager.cpp''''' | '''''com_android_server_InputManager.cpp''''' | ||
< | <source lang="c"> | ||
{ "nativeInit", "(Landroid/content/Context;" | { "nativeInit", "(Landroid/content/Context;" | ||
"Lcom/android/server/wm/InputManager$Callbacks;Landroid/os/MessageQueue;)V", | "Lcom/android/server/wm/InputManager$Callbacks;Landroid/os/MessageQueue;)V", | ||
(void*) android_server_InputManager_nativeInit }, | (void*) android_server_InputManager_nativeInit }, | ||
... | ... | ||
</ | </source> | ||
< | <source lang="c"> | ||
static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz, | static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz, | ||
jobject contextObj, jobject callbacksObj, jobject messageQueueObj) { | jobject contextObj, jobject callbacksObj, jobject messageQueueObj) { | ||
| 第118行: | 第118行: | ||
} | } | ||
} | } | ||
</ | </source> | ||
可以看到开始转入了 native环境,并在这里创建了 NativeInputManager,同时把 mContext, mCallbacks 和 looper.getQueue()作为参数传入其中。 | 可以看到开始转入了 native环境,并在这里创建了 NativeInputManager,同时把 mContext, mCallbacks 和 looper.getQueue()作为参数传入其中。 | ||
< | <source lang="c"> | ||
NativeInputManager::NativeInputManager(jobject contextObj, | NativeInputManager::NativeInputManager(jobject contextObj, | ||
jobject callbacksObj, const sp<Looper>& looper) : | jobject callbacksObj, const sp<Looper>& looper) : | ||
| 第129行: | 第129行: | ||
mInputManager = new InputManager(eventHub, this, this); //HERE | mInputManager = new InputManager(eventHub, this, this); //HERE | ||
} | } | ||
</ | </source> | ||
哦,原来 native层也有 InputManager | 哦,原来 native层也有 InputManager | ||
'''''InputManager.cpp''''' | '''''InputManager.cpp''''' | ||
< | <source lang="c"> | ||
InputManager::InputManager( | InputManager::InputManager( | ||
const sp<EventHubInterface>& eventHub, | const sp<EventHubInterface>& eventHub, | ||
| 第142行: | 第142行: | ||
initialize(); | initialize(); | ||
} | } | ||
</ | </source> | ||
< | <source lang="c"> | ||
void InputManager::initialize() { | void InputManager::initialize() { | ||
mReaderThread = new InputReaderThread(mReader); //HERE | mReaderThread = new InputReaderThread(mReader); //HERE | ||
mDispatcherThread = new InputDispatcherThread(mDispatcher); //HERE | mDispatcherThread = new InputDispatcherThread(mDispatcher); //HERE | ||
} | } | ||
</ | </source> | ||
可以看到这里又创建了 InputDispatcher、InputReader的实例,同时还创建了两个线程:InputReaderThread和 InputDispatcherThread. | 可以看到这里又创建了 InputDispatcher、InputReader的实例,同时还创建了两个线程:InputReaderThread和 InputDispatcherThread. | ||
| 第158行: | 第158行: | ||
首先来看 InputReaderThread: | 首先来看 InputReaderThread: | ||
'''''InputReader.h''''' | '''''InputReader.h''''' | ||
< | <source lang="c"> | ||
/* Reads raw events from the event hub and processes them, endlessly. */ | /* Reads raw events from the event hub and processes them, endlessly. */ | ||
class InputReaderThread : public Thread { | class InputReaderThread : public Thread { | ||
| 第170行: | 第170行: | ||
virtual bool threadLoop(); //HERE | virtual bool threadLoop(); //HERE | ||
}; | }; | ||
</ | </source> | ||
'''''InputReader.cpp''''' | '''''InputReader.cpp''''' | ||
< | <source lang="c"> | ||
bool InputReaderThread::threadLoop() { | bool InputReaderThread::threadLoop() { | ||
mReader->loopOnce(); //HERE | mReader->loopOnce(); //HERE | ||
return true; | return true; | ||
} | } | ||
</ | </source> | ||
< | <source lang="c"> | ||
void InputReader::loopOnce() { | void InputReader::loopOnce() { | ||
int32_t timeoutMillis; | int32_t timeoutMillis; | ||
| 第215行: | 第215行: | ||
mQueuedListener->flush(); | mQueuedListener->flush(); | ||
} | } | ||
</ | </source> | ||
我们看这一行:mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); | 我们看这一行:mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); | ||
| 第223行: | 第223行: | ||
'''''EventHub.cpp''''' | '''''EventHub.cpp''''' | ||
< | <source lang="c"> | ||
EventHub::EventHub(void) : | EventHub::EventHub(void) : | ||
mBuiltInKeyboardId(-1), mNextDeviceId(1), | mBuiltInKeyboardId(-1), mNextDeviceId(1), | ||
| 第453行: | 第453行: | ||
return 0; | return 0; | ||
} | } | ||
</ | </source> | ||
而devicePath则正是/dev/input/目录下的文件,openDeviceLocked的被调用关系如下: | 而devicePath则正是/dev/input/目录下的文件,openDeviceLocked的被调用关系如下: | ||
| 第459行: | 第459行: | ||
取其中一个函数看一下: | 取其中一个函数看一下: | ||
< | <source lang="c"> | ||
status_t EventHub::readNotifyLocked() { | status_t EventHub::readNotifyLocked() { | ||
int res; | int res; | ||
| 第501行: | 第501行: | ||
return 0; | return 0; | ||
} | } | ||
</ | </source> | ||
| 第509行: | 第509行: | ||
'''''InputReader.cpp''''' | '''''InputReader.cpp''''' | ||
< | <source lang="c"> | ||
void InputReader::loopOnce() { | void InputReader::loopOnce() { | ||
... | ... | ||
| 第525行: | 第525行: | ||
mQueuedListener->flush(); | mQueuedListener->flush(); | ||
} | } | ||
</ | </source> | ||
取出的事件以数组的形式、按顺序存在 mEventBuffer当中,count保存了所取出的事件的个数。 | 取出的事件以数组的形式、按顺序存在 mEventBuffer当中,count保存了所取出的事件的个数。 | ||
< | <source lang="c"> | ||
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { | void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { | ||
for (const RawEvent* rawEvent = rawEvents; count;) { | for (const RawEvent* rawEvent = rawEvents; count;) { | ||
| 第562行: | 第562行: | ||
} | } | ||
} | } | ||
</ | </source> | ||
上面这三个case,与 inotify监听相对应,我们这里就常规的input事件分发继续分析: | 上面这三个case,与 inotify监听相对应,我们这里就常规的input事件分发继续分析: | ||
< | <source lang="c"> | ||
void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) { | void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) { | ||
ssize_t deviceIndex = mDevices.indexOfKey(deviceId); | ssize_t deviceIndex = mDevices.indexOfKey(deviceId); | ||
| 第580行: | 第580行: | ||
device->process(rawEvents, count); //HERE | device->process(rawEvents, count); //HERE | ||
} | } | ||
</ | </source> | ||
< | <source lang="c"> | ||
void InputDevice::process(const RawEvent* rawEvents, size_t count) { | void InputDevice::process(const RawEvent* rawEvents, size_t count) { | ||
size_t numMappers = mMappers.size(); | size_t numMappers = mMappers.size(); | ||
| 第603行: | 第603行: | ||
} | } | ||
} | } | ||
</ | </source> | ||
上面所使用的mMapper[]数组在 iNotify监控到/dev/input/下文件有增加,进而 addDeviceLocked时会有以下操作: | 上面所使用的mMapper[]数组在 iNotify监控到/dev/input/下文件有增加,进而 addDeviceLocked时会有以下操作: | ||
< | <source lang="c"> | ||
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, | InputDevice* InputReader::createDeviceLocked(int32_t deviceId, | ||
| 第660行: | 第660行: | ||
return device; | return device; | ||
} | } | ||
</ | </source> | ||
== (一)触屏事件 == | == (一)触屏事件 == | ||
| 第667行: | 第667行: | ||
'''''InputReader.cpp''''' | '''''InputReader.cpp''''' | ||
< | <source lang="c"> | ||
void MultiTouchInputMapper::process(const RawEvent* rawEvent) { | void MultiTouchInputMapper::process(const RawEvent* rawEvent) { | ||
TouchInputMapper::process(rawEvent); | TouchInputMapper::process(rawEvent); | ||
| 第673行: | 第673行: | ||
mMultiTouchMotionAccumulator.process(rawEvent); | mMultiTouchMotionAccumulator.process(rawEvent); | ||
} | } | ||
</ | </source> | ||
< | <source lang="c"> | ||
void TouchInputMapper::process(const RawEvent* rawEvent) { | void TouchInputMapper::process(const RawEvent* rawEvent) { | ||
mCursorButtonAccumulator.process(rawEvent); | mCursorButtonAccumulator.process(rawEvent); | ||
| 第685行: | 第685行: | ||
} | } | ||
} | } | ||
</ | </source> | ||
从上面看来,只是将rawEvent->when所传入到sync当中,那其他信息呢? | 从上面看来,只是将rawEvent->when所传入到sync当中,那其他信息呢? | ||
| 第691行: | 第691行: | ||
是不是这样呢? 我们再继续分析~ | 是不是这样呢? 我们再继续分析~ | ||
< | <source lang="c"> | ||
void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { | void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { | ||
if (rawEvent->type == EV_ABS) { //此次上报数据类型为 EV_ABS, | if (rawEvent->type == EV_ABS) { //此次上报数据类型为 EV_ABS, | ||
| 第735行: | 第735行: | ||
} | } | ||
} | } | ||
</ | </source> | ||
基本明白了,原来一个触点所包含的坐标、压力等信息是分别上报上来的,InputReader线程接收后通过"accumulator"进行综合,每次上报事件"(rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_MT_REPORT) "代表一个触点信息的完结。 | 基本明白了,原来一个触点所包含的坐标、压力等信息是分别上报上来的,InputReader线程接收后通过"accumulator"进行综合,每次上报事件"(rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_MT_REPORT) "代表一个触点信息的完结。 | ||
继续看 TouchInputMapper::process函数: | 继续看 TouchInputMapper::process函数: | ||
< | <source lang="c"> | ||
void TouchInputMapper::process(const RawEvent* rawEvent) { | void TouchInputMapper::process(const RawEvent* rawEvent) { | ||
mCursorButtonAccumulator.process(rawEvent); | mCursorButtonAccumulator.process(rawEvent); | ||
| 第749行: | 第749行: | ||
} | } | ||
} | } | ||
</ | </source> | ||
这里又调用了三个process,这三个process分别对应三种类型的触摸设备事件:CursorButton、CursorScroll、TouchButton,设计理念与mapper一样,也是在各自的process中判断type,匹配才进行处理,加到"accumulator"中,如: | 这里又调用了三个process,这三个process分别对应三种类型的触摸设备事件:CursorButton、CursorScroll、TouchButton,设计理念与mapper一样,也是在各自的process中判断type,匹配才进行处理,加到"accumulator"中,如: | ||
< | <source lang="c"> | ||
void CursorScrollAccumulator::process(const RawEvent* rawEvent) { | void CursorScrollAccumulator::process(const RawEvent* rawEvent) { | ||
if (rawEvent->type == EV_REL) { | if (rawEvent->type == EV_REL) { | ||
| 第764行: | 第764行: | ||
} | } | ||
} | } | ||
</ | </source> | ||
再看sync函数,sync意为同步,那这里应该是真正将数据上报的地方了: | 再看sync函数,sync意为同步,那这里应该是真正将数据上报的地方了: | ||
< | <source lang="c"> | ||
void TouchInputMapper::sync(nsecs_t when) { | void TouchInputMapper::sync(nsecs_t when) { | ||
// Sync button state. | // Sync button state. | ||
| 第946行: | 第946行: | ||
mCurrentRawHScroll = 0; | mCurrentRawHScroll = 0; | ||
} | } | ||
</ | </source> | ||
上面在处理数据时有对数据进行判断,当判断触点处于虚拟按键区域时,会生成对应的key事件,我们这里再来看一下它是怎么做的: | 上面在处理数据时有对数据进行判断,当判断触点处于虚拟按键区域时,会生成对应的key事件,我们这里再来看一下它是怎么做的: | ||
< | <source lang="c"> | ||
bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { | bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { | ||
// Check for release of a virtual key. | // Check for release of a virtual key. | ||
| 第1,057行: | 第1,057行: | ||
return false; | return false; | ||
} | } | ||
</ | </source> | ||
通过sync函数,我们发现,touch所有事件的分发,根据 device mode的不同,都是通过以下两种方式完成的: | 通过sync函数,我们发现,touch所有事件的分发,根据 device mode的不同,都是通过以下两种方式完成的: | ||
DEVICE_MODE_POINTER: | DEVICE_MODE_POINTER: | ||
< | <source lang="c"> | ||
dispatchPointerUsage(when, policyFlags, pointerUsage); | dispatchPointerUsage(when, policyFlags, pointerUsage); | ||
</ | </source> | ||
DEVICE_MODE_DIRECT: | DEVICE_MODE_DIRECT: | ||
< | <source lang="c"> | ||
dispatchHoverExit(when, policyFlags); | dispatchHoverExit(when, policyFlags); | ||
dispatchTouches(when, policyFlags); | dispatchTouches(when, policyFlags); | ||
dispatchHoverEnterAndMove(when, policyFlags); | dispatchHoverEnterAndMove(when, policyFlags); | ||
</ | </source> | ||
而上面这四个函数最终也都是通过调用 dispatchMotion,只是使用的参数(第四个参数, 即action)不一样罢了: | 而上面这四个函数最终也都是通过调用 dispatchMotion,只是使用的参数(第四个参数, 即action)不一样罢了: | ||
< | <source lang="c"> | ||
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, | void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, | ||
int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, | int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, | ||
| 第1,077行: | 第1,077行: | ||
const uint32_t* idToIndex, BitSet32 idBits, | const uint32_t* idToIndex, BitSet32 idBits, | ||
int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) | int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) | ||
</ | </source> | ||
这里贴出 dispatchTouches函数看一下: | 这里贴出 dispatchTouches函数看一下: | ||
< | <source lang="c"> | ||
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { | void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { | ||
BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits; | BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits; | ||
| 第1,169行: | 第1,169行: | ||
} | } | ||
} | } | ||
</ | </source> | ||
可以发现其action用到了 AMOTION_EVENT_ACTION_MOVE 和 AMOTION_EVENT_ACTION_POINTER_UP,所有的action包含以下几种: | 可以发现其action用到了 AMOTION_EVENT_ACTION_MOVE 和 AMOTION_EVENT_ACTION_POINTER_UP,所有的action包含以下几种: | ||
< | <source lang="c"> | ||
enum { | enum { | ||
AMOTION_EVENT_ACTION_MASK = 0xff, | AMOTION_EVENT_ACTION_MASK = 0xff, | ||
| 第1,187行: | 第1,187行: | ||
AMOTION_EVENT_ACTION_HOVER_EXIT = 10, | AMOTION_EVENT_ACTION_HOVER_EXIT = 10, | ||
}; | }; | ||
</ | </source> | ||
进入 dispatchMotion: | 进入 dispatchMotion: | ||
< | <source lang="c"> | ||
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, | void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, | ||
int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, | int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, | ||
| 第1,232行: | 第1,232行: | ||
getListener()->notifyMotion(&args); | getListener()->notifyMotion(&args); | ||
} | } | ||
</ | </source> | ||
发现最终是调用 getListener()->notifyMotion(&args),继续看代码(确实有点累了): | 发现最终是调用 getListener()->notifyMotion(&args),继续看代码(确实有点累了): | ||
getListener()获取的是 mQueuedListener: | getListener()获取的是 mQueuedListener: | ||
< | <source lang="c"> | ||
InputListenerInterface* InputReader::ContextImpl::getListener() { | InputListenerInterface* InputReader::ContextImpl::getListener() { | ||
return mReader->mQueuedListener.get(); | return mReader->mQueuedListener.get(); | ||
} | } | ||
</ | </source> | ||
< | <source lang="c"> | ||
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) { | void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) { | ||
mArgsQueue.push(new NotifyMotionArgs(*args)); | mArgsQueue.push(new NotifyMotionArgs(*args)); | ||
} | } | ||
</ | </source> | ||
哦,原来只是用参数构建 NotifyMotionArgs对象加入队列。 | 哦,原来只是用参数构建 NotifyMotionArgs对象加入队列。 | ||
| 第1,251行: | 第1,251行: | ||
我们再回过头来看一下 InputReader::loopOnce这个函数: | 我们再回过头来看一下 InputReader::loopOnce这个函数: | ||
< | <source lang="c"> | ||
void InputReader::loopOnce() { | void InputReader::loopOnce() { | ||
int32_t timeoutMillis; | int32_t timeoutMillis; | ||
| 第1,297行: | 第1,297行: | ||
mQueuedListener->flush(); | mQueuedListener->flush(); | ||
} | } | ||
</ | </source> | ||
我们这一节的分析都集中在 mEventHub->getEvents 和 processEventsLocked当中,但在最后它还调用了一个函数 flush(),一看到这个函数大家应该马上会想到写文件时的flush吧!——即所有真正的磁盘写动作都是在flush时完成的!那这里是不是类似呢? | 我们这一节的分析都集中在 mEventHub->getEvents 和 processEventsLocked当中,但在最后它还调用了一个函数 flush(),一看到这个函数大家应该马上会想到写文件时的flush吧!——即所有真正的磁盘写动作都是在flush时完成的!那这里是不是类似呢? | ||
< | <source lang="c"> | ||
void QueuedInputListener::flush() { | void QueuedInputListener::flush() { | ||
size_t count = mArgsQueue.size(); | size_t count = mArgsQueue.size(); | ||
| 第1,309行: | 第1,309行: | ||
mArgsQueue.clear(); | mArgsQueue.clear(); | ||
} | } | ||
</ | </source> | ||
继续看一下 NotifyArgs这个类: | 继续看一下 NotifyArgs这个类: | ||
< | <source lang="c"> | ||
/* Superclass of all input event argument objects */ | /* Superclass of all input event argument objects */ | ||
struct NotifyArgs { | struct NotifyArgs { | ||
| 第1,318行: | 第1,318行: | ||
virtual void notify(const sp<InputListenerInterface>& listener) const = 0; | virtual void notify(const sp<InputListenerInterface>& listener) const = 0; | ||
}; | }; | ||
</ | </source> | ||
可以发现这是一个无法实例化的父类,因为其 notify函数是纯虚函数,我们再看一下它有多少子类: | 可以发现这是一个无法实例化的父类,因为其 notify函数是纯虚函数,我们再看一下它有多少子类: | ||
< | <source lang="c"> | ||
struct NotifyConfigurationChangedArgs : public NotifyArgs | struct NotifyConfigurationChangedArgs : public NotifyArgs | ||
struct NotifyKeyArgs : public NotifyArgs | struct NotifyKeyArgs : public NotifyArgs | ||
| 第1,326行: | 第1,326行: | ||
struct NotifySwitchArgs : public NotifyArgs | struct NotifySwitchArgs : public NotifyArgs | ||
struct NotifyDeviceResetArgs : public NotifyArgs | struct NotifyDeviceResetArgs : public NotifyArgs | ||
</ | </source> | ||
在上面所示的 dispatchMotion函数中可以看到,触屏事件分发时所用的 NotifyArgs子类为 NotifyMotionArgs: | 在上面所示的 dispatchMotion函数中可以看到,触屏事件分发时所用的 NotifyArgs子类为 NotifyMotionArgs: | ||
< | <source lang="c"> | ||
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const { | void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const { | ||
listener->notifyMotion(this); | listener->notifyMotion(this); | ||
} | } | ||
</ | </source> | ||
这个listener是何方神圣? | 这个listener是何方神圣? | ||
首先看到是这里传入的: | 首先看到是这里传入的: | ||
< | <source lang="c"> | ||
void QueuedInputListener::flush() { | void QueuedInputListener::flush() { | ||
size_t count = mArgsQueue.size(); | size_t count = mArgsQueue.size(); | ||
| 第1,346行: | 第1,346行: | ||
mArgsQueue.clear(); | mArgsQueue.clear(); | ||
} | } | ||
</ | </source> | ||
而这个成员变量 mInnerListener又是在构建函数中传入的: | 而这个成员变量 mInnerListener又是在构建函数中传入的: | ||
< | <source lang="c"> | ||
QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) : | QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) : | ||
mInnerListener(innerListener) { | mInnerListener(innerListener) { | ||
} | } | ||
</ | </source> | ||
而 QueuedInputListener又是在 InputReader实例化的: | 而 QueuedInputListener又是在 InputReader实例化的: | ||
< | <source lang="c"> | ||
InputReader::InputReader(const sp<EventHubInterface>& eventHub, | InputReader::InputReader(const sp<EventHubInterface>& eventHub, | ||
const sp<InputReaderPolicyInterface>& policy, | const sp<InputReaderPolicyInterface>& policy, | ||
| 第1,366行: | 第1,366行: | ||
... | ... | ||
} | } | ||
</ | </source> | ||
listener这个参数还是传进来的,必须再找到 InputReader构建的地方: | listener这个参数还是传进来的,必须再找到 InputReader构建的地方: | ||
< | <source lang="c"> | ||
InputManager::InputManager( | InputManager::InputManager( | ||
const sp<EventHubInterface>& eventHub, | const sp<EventHubInterface>& eventHub, | ||
| 第1,377行: | 第1,377行: | ||
initialize(); | initialize(); | ||
} | } | ||
</ | </source> | ||
一切都明白了!原来这个listener就是 InputDispatcher的对象 mDispatcher! | 一切都明白了!原来这个listener就是 InputDispatcher的对象 mDispatcher! | ||
我们来看一下 interceptMotionBeforeQueueing这个函数,直接从名字上看,应该是说在将motion事件加入队列前进行拦截 | 我们来看一下 interceptMotionBeforeQueueing这个函数,直接从名字上看,应该是说在将motion事件加入队列前进行拦截 | ||
< | <source lang="c"> | ||
void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { | void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { | ||
// Policy: | // Policy: | ||
| 第1,415行: | 第1,415行: | ||
} | } | ||
} | } | ||
</ | </source> | ||
那这个 gCallbacksClassInfo.interceptMotionBeforeQueueingWhenScreenOff到底最终调用的是哪个函数呢? | 那这个 gCallbacksClassInfo.interceptMotionBeforeQueueingWhenScreenOff到底最终调用的是哪个函数呢? | ||
'''''InputManager.java''''' | '''''InputManager.java''''' | ||
< | <source lang="c"> | ||
@SuppressWarnings("unused") | @SuppressWarnings("unused") | ||
public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) { | public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) { | ||
| 第1,425行: | 第1,425行: | ||
policyFlags); | policyFlags); | ||
} | } | ||
</ | </source> | ||
继续: | 继续: | ||
'''''InputMonitor.java''''' | '''''InputMonitor.java''''' | ||
< | <source lang="c"> | ||
/* Provides an opportunity for the window manager policy to intercept early | /* Provides an opportunity for the window manager policy to intercept early | ||
* motion event processing when the screen is off since these events are normally | * motion event processing when the screen is off since these events are normally | ||
| 第1,436行: | 第1,436行: | ||
return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(policyFlags); | return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(policyFlags); | ||
} | } | ||
</ | </source> | ||
找到了: | 找到了: | ||
'''''PhoneWindowManager.java''''' | '''''PhoneWindowManager.java''''' | ||
< | <source lang="c"> | ||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||
@Override | @Override | ||
| 第1,462行: | 第1,462行: | ||
return result; | return result; | ||
} | } | ||
</ | </source> | ||
< | <source lang="c"> | ||
void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when, | void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when, | ||
uint32_t& policyFlags) { | uint32_t& policyFlags) { | ||
| 第1,492行: | 第1,492行: | ||
} | } | ||
} | } | ||
</ | </source> | ||
=四、笔记= | =四、笔记= | ||
< | <source lang="c"> | ||
updateInputWindowsLw -> setInputWindows -> nativeSetInputWindows -> setInputWindows -> | updateInputWindowsLw -> setInputWindows -> nativeSetInputWindows -> setInputWindows -> | ||
mInputManager->getDispatcher()->setInputWindows(windowHandles) -> 更新 mFocusedWindowHandle | mInputManager->getDispatcher()->setInputWindows(windowHandles) -> 更新 mFocusedWindowHandle | ||
| 第1,569行: | 第1,569行: | ||
} | } | ||
</ | </source> | ||
2015年3月12日 (四) 13:42的最新版本
一、开机时input机制创建
开机时会创建 system_server,然后在其中创建service,下面这里是 WindowManagerService的创建。
这里没有显式的使用 new创建,而是调用了类中静态函数 WindowManagerService.main,同时我们也看到 WindowManagerService的构建函数为private类型:
private WindowManagerService(Context context, PowerManagerService pm,
DisplayManagerService displayManager, InputManagerService inputManager,
Handler uiHandler,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore)
...其实这是非常常见的单实例类,这里不过多描述,继续看:
SystemServer.java
class ServerThread extends Thread {
...
@Override
public void run() {
...
// Critical services...
try {
Slog.i(TAG, "Entropy Service");
ServiceManager.addService("entropy", new EntropyService());
...
Slog.i(TAG, "Window Manager");
wm = WindowManagerService.main(context, power,
factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
!firstBoot); //HERE
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
...进入该 main函数:
WindowManagerService.java
public static WindowManagerService main(Context context,
PowerManagerService pm, boolean haveInputMethods, boolean allowBootMsgs) {
WMThread thr = new WMThread(context, pm, haveInputMethods, allowBootMsgs); //HERE
thr.start(); //HERE
synchronized (thr) {
while (thr.mService == null) {
try {
thr.wait();
} catch (InterruptedException e) {
}
}
return thr.mService;
}
}创建了WMThread并start,呵呵,看到start应该条件反射地想到run了:
static class WMThread extends Thread {
...
public void run() {
Looper.prepare();
WindowManagerService s = new WindowManagerService(mContext, mPM,
mHaveInputMethods, mAllowBootMessages); //HERE
...
synchronized (this) {
mService = s;
notifyAll();
}
Looper.loop();
}
}果然,是在这里创建了 WindowManagerService,继续跟进:
private WindowManagerService(Context context, PowerManagerService pm,
boolean haveInputMethods, boolean showBootMsgs) {
...
mInputManager = new InputManager(context, this); //HERE
PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
...
}嗯,终于看到与 "Input"相关的东东了:InputManager,看名字应该是 Input事件的管理类。
InputManager.java
public InputManager(Context context, WindowManagerService windowManagerService) {
this.mContext = context;
this.mWindowManagerService = windowManagerService;
this.mCallbacks = new Callbacks();
Looper looper = windowManagerService.mH.getLooper();
Slog.i(TAG, "Initializing input manager");
nativeInit(mContext, mCallbacks, looper.getQueue()); //HERE
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
}构建函数很简单,无非是一些成员变量的赋值,除此之外就是两个函数:nativeInit和Watchdog.getInstance().addMonitor(this)。第一个函数我们要深入分析才知道干了些啥;第个二则是将此实例加入Watchdog的监视列表mMonitors.
com_android_server_InputManager.cpp
{ "nativeInit", "(Landroid/content/Context;"
"Lcom/android/server/wm/InputManager$Callbacks;Landroid/os/MessageQueue;)V",
(void*) android_server_InputManager_nativeInit },
...static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,
jobject contextObj, jobject callbacksObj, jobject messageQueueObj) {
if (gNativeInputManager == NULL) {
sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
gNativeInputManager = new NativeInputManager(contextObj, callbacksObj, looper); //HERE
} else {
LOGE("Input manager already initialized.");
jniThrowRuntimeException(env, "Input manager already initialized.");
}
}可以看到开始转入了 native环境,并在这里创建了 NativeInputManager,同时把 mContext, mCallbacks 和 looper.getQueue()作为参数传入其中。
NativeInputManager::NativeInputManager(jobject contextObj,
jobject callbacksObj, const sp<Looper>& looper) :
mLooper(looper) {
JNIEnv* env = jniEnv();
...
sp<EventHub> eventHub = new EventHub(); //HERE
mInputManager = new InputManager(eventHub, this, this); //HERE
}哦,原来 native层也有 InputManager
InputManager.cpp
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher); //HERE
initialize();
}void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader); //HERE
mDispatcherThread = new InputDispatcherThread(mDispatcher); //HERE
}可以看到这里又创建了 InputDispatcher、InputReader的实例,同时还创建了两个线程:InputReaderThread和 InputDispatcherThread.
——这几个对象的关系是什么?我们继续分析
二、input事件的扫描
首先来看 InputReaderThread:
InputReader.h
/* Reads raw events from the event hub and processes them, endlessly. */
class InputReaderThread : public Thread {
public:
InputReaderThread(const sp<InputReaderInterface>& reader);
virtual ~InputReaderThread();
private:
sp<InputReaderInterface> mReader;
virtual bool threadLoop(); //HERE
};InputReader.cpp
bool InputReaderThread::threadLoop() {
mReader->loopOnce(); //HERE
return true;
}void InputReader::loopOnce() {
int32_t timeoutMillis;
{ // acquire lock
AutoMutex _l(mLock);
uint32_t changes = mConfigurationChangesToRefresh;
if (changes) {
mConfigurationChangesToRefresh = 0;
refreshConfigurationLocked(changes);
}
timeoutMillis = -1;
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
}
} // release lock
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); //HERE
{ // acquire lock
AutoMutex _l(mLock);
if (count) {
processEventsLocked(mEventBuffer, count);
}
if (!count || timeoutMillis == 0) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now);
}
} // release lock
mQueuedListener->flush();
}我们看这一行:mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
没错,这就是最为关键的一行!
mEventHub是什么东东?如果读者留心的话,会发现在上面已经出现过了,在 NativeInputManager的构建函数中。至于这个具体是干什么用的,这里只要看其中的三个函数就能了解个大概:
EventHub.cpp
EventHub::EventHub(void) :
mBuiltInKeyboardId(-1), mNextDeviceId(1),
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);
mNumCpus = sysconf(_SC_NPROCESSORS_ONLN);
mEpollFd = epoll_create(EPOLL_SIZE_HINT); //epoll就不用解释了吧,linux标准的东西
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
mINotifyFd = inotify_init(); //inotify也是linux的东西,就是它能够监视某一文件,当其被创建、修改、读写时会有反映在生成的文件 mINotifyFd上
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); //这里是监视DEVICE_PATH(/dev/input)的删除、创建操作
LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s. errno=%d",
DEVICE_PATH, errno);
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = EPOLL_ID_INOTIFY;
//然后我们通过epoll对 mINotifyFd进行I/O侦听便可完成对 /dev/input/下文件的个数变化,如增加输入设备时可以及时加入监听列表中
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);
int wakeFds[2];
result = pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
errno);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno);
eventItem.data.u32 = EPOLL_ID_WAKE;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); //这里也是一样,增加了侦听mWakeReadPipeFd,暂且不看吧
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
}
...
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
...
// Grab the next input event.
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) { //被侦听的文件有事件发生,可能是notifyId、pipefd或input设备文件
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++]; //取出
if (eventItem.data.u32 == EPOLL_ID_INOTIFY) { //为notifyid,表示input设备文件被移除或添加
if (eventItem.events & EPOLLIN) {
mPendingINotify = true; //设置标志,后续重新扫描/dev/input/下文件
} else {
LOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
}
continue;
}
if (eventItem.data.u32 == EPOLL_ID_WAKE) { //被唤醒,上面侦听 mWakeReadPipeFd的返回,先不看
if (eventItem.events & EPOLLIN) {
LOGV("awoken after wake()");
awoken = true;
char buffer[16];
ssize_t nRead;
do {
nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
} else {
LOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
eventItem.events);
}
continue;
}
ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
if (deviceIndex < 0) {
LOGW("Received unexpected epoll event 0x%08x for unknown device id %d.",
eventItem.events, eventItem.data.u32);
continue;
}
Device* device = mDevices.valueAt(deviceIndex); //真正的input设备,开始取数据
if (eventItem.events & EPOLLIN) {
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity); //读出数据到readBuffer中
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
// Device was removed before INotify noticed.
LOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d capacity: %d errno: %d)\n",
device->fd, readSize, bufferSize, capacity, errno);
deviceChanged = true;
closeDeviceLocked(device);
} else if (readSize < 0) {
if (errno != EAGAIN && errno != EINTR) {
LOGW("could not get event (errno=%d)", errno);
}
} else if ((readSize % sizeof(struct input_event)) != 0) {
LOGE("could not get event (wrong size: %d)", readSize);
} else {
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++) {
const struct input_event& iev = readBuffer[i];
LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, value=%d",
device->path.string(),
(int) iev.time.tv_sec, (int) iev.time.tv_usec,
iev.type, iev.code, iev.value);
#ifdef HAVE_POSIX_CLOCKS
// Use the time specified in the event instead of the current time
// so that downstream code can get more accurate estimates of
// event dispatch latency from the time the event is enqueued onto
// the evdev client buffer.
//
// The event's timestamp fortuitously uses the same monotonic clock
// time base as the rest of Android. The kernel event device driver
// (drivers/input/evdev.c) obtains timestamps using ktime_get_ts().
// The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere
// calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a
// system call that also queries ktime_get_ts().
event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
+ nsecs_t(iev.time.tv_usec) * 1000LL;
LOGV("event time %lld, now %lld", event->when, now);
#else
event->when = now;
#endif
event->deviceId = deviceId;
event->type = iev.type;
event->scanCode = iev.code;
event->value = iev.value;
event->keyCode = AKEYCODE_UNKNOWN;
event->flags = 0;
if (iev.type == EV_KEY && device->keyMap.haveKeyLayout()) {
status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code,
&event->keyCode, &event->flags);
LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
iev.code, event->keyCode, event->flags, err);
}
event += 1;
}
capacity -= count;
if (capacity == 0) {
// The result buffer is full. Reset the pending event index
// so we will try to read the device again on the next iteration.
mPendingEventIndex -= 1;
break;
}
}
} else {
LOGW("Received unexpected epoll event 0x%08x for device %s.",
eventItem.events, device->identifier.name.string());
}
}
...
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); //等待新事件
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock
if (pollResult == 0) {
// Timed out.
mPendingEventCount = 0;
break;
}
if (pollResult < 0) {
// An error occurred.
mPendingEventCount = 0;
// Sleep after errors to avoid locking up the system.
// Hopefully the error is transient.
if (errno != EINTR) {
LOGW("poll failed (errno=%d)\n", errno);
usleep(100000);
}
} else {
// Some events occurred.
mPendingEventCount = size_t(pollResult);
// On an SMP system, it is possible for the framework to read input events
// faster than the kernel input device driver can produce a complete packet.
// Because poll() wakes up as soon as the first input event becomes available,
// the framework will often end up reading one event at a time until the
// packet is complete. Instead of one call to read() returning 71 events,
// it could take 71 calls to read() each returning 1 event.
//
// Sleep for a short period of time after waking up from the poll() to give
// the kernel time to finish writing the entire packet of input events.
if (mNumCpus > 1) {
usleep(250);
}
}
}
// All done, return the number of events we read.
return event - buffer;
}
status_t EventHub::openDeviceLocked(const char *devicePath) {
char buffer[80];
LOGV("Opening device: %s", devicePath);
int fd = open(devicePath, O_RDWR);
...
// Register with epoll.
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN; //EPOLLIN :表示对应的文件描述符可以读;
eventItem.data.u32 = deviceId;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { //将 devicePath加入监听
...
mDevices.add(deviceId, device);
device->next = mOpeningDevices;
mOpeningDevices = device;
return 0;
}而devicePath则正是/dev/input/目录下的文件,openDeviceLocked的被调用关系如下:
取其中一个函数看一下:
status_t EventHub::readNotifyLocked() {
int res;
char devname[PATH_MAX];
char *filename;
char event_buf[512];
int event_size;
int event_pos = 0;
struct inotify_event *event;
LOGV("EventHub::readNotify nfd: %d\n", mINotifyFd);
res = read(mINotifyFd, event_buf, sizeof(event_buf)); //取出 mINotifyFd中的数据
if(res < (int)sizeof(*event)) {
if(errno == EINTR)
return 0;
LOGW("could not get event, %s\n", strerror(errno));
return -1;
}
//printf("got %d bytes of event information\n", res);
strcpy(devname, DEVICE_PATH);
filename = devname + strlen(devname);
*filename++ = '/';
while(res >= (int)sizeof(*event)) {
event = (struct inotify_event *)(event_buf + event_pos);
//printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
if(event->len) {
strcpy(filename, event->name); //获取文件列表文件名
if(event->mask & IN_CREATE) {
openDeviceLocked(devname); //加入epoll监视列表
} else {
LOGI("Removing device '%s' due to inotify event\n", devname);
closeDeviceByPathLocked(devname);
}
}
event_size = sizeof(*event) + event->len;
res -= event_size;
event_pos += event_size;
}
return 0;
}
三、input事件的分发
从 mEventHub中取出数据后,就要想办法快速实时地传送给framework/app,这样才能达到人机交互的目的,现在我们就来看这一部分。
InputReader.cpp
void InputReader::loopOnce() {
...
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
if (count) {
processEventsLocked(mEventBuffer, count); //HERE
}
...
} // release lock
mQueuedListener->flush();
}取出的事件以数组的形式、按顺序存在 mEventBuffer当中,count保存了所取出的事件的个数。
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count;) {
int32_t type = rawEvent->type;
size_t batchSize = 1;
if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
int32_t deviceId = rawEvent->deviceId;
while (batchSize < count) {
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
|| rawEvent[batchSize].deviceId != deviceId) {
break;
}
batchSize += 1;
}
processEventsForDeviceLocked(deviceId, rawEvent, batchSize); //HERE
} else {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED: //input设备有增加
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED: //input设备有减少
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN: //input设备扫描完成
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
LOG_ASSERT(false); // can't happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
}上面这三个case,与 inotify监听相对应,我们这里就常规的input事件分发继续分析:
void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex < 0) {
LOGW("Discarding event for unknown deviceId %d.", deviceId);
return;
}
InputDevice* device = mDevices.valueAt(deviceIndex);
if (device->isIgnored()) {
//LOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
}
device->process(rawEvents, count); //HERE
}void InputDevice::process(const RawEvent* rawEvents, size_t count) {
size_t numMappers = mMappers.size();
for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
if (mDropUntilNextSync) {
if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) {
mDropUntilNextSync = false;
} else {
}
} else if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_DROPPED) {
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent); //HERE, 将所有类型的mapper跑一遍
//ps.只有与rawEvent类型匹配的mapper才会真正作有意义的处理
//因为在所有的process中均会对rawEvent进行类型判断,只有匹配才作进一步处理
}
}
}
}上面所使用的mMapper[]数组在 iNotify监控到/dev/input/下文件有增加,进而 addDeviceLocked时会有以下操作:
InputDevice* InputReader::createDeviceLocked(int32_t deviceId,
const String8& name, uint32_t classes) {
InputDevice* device = new InputDevice(&mContext, deviceId, name, classes);
// External devices.
if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
device->setExternal(true);
}
// Switch-like devices.
if (classes & INPUT_DEVICE_CLASS_SWITCH) {
device->addMapper(new SwitchInputMapper(device)); //开关类输入设备
}
// Keyboard-like devices.
uint32_t keyboardSource = 0;
int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
keyboardSource |= AINPUT_SOURCE_KEYBOARD;
}
if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
}
if (classes & INPUT_DEVICE_CLASS_DPAD) {
keyboardSource |= AINPUT_SOURCE_DPAD;
}
if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
keyboardSource |= AINPUT_SOURCE_GAMEPAD;
}
if (keyboardSource != 0) {
device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); //键盘类设备
}
// Cursor-like devices.
if (classes & INPUT_DEVICE_CLASS_CURSOR) {
device->addMapper(new CursorInputMapper(device)); //??尚不大清楚是何种输入设备
}
// Touchscreens and touchpad devices.
if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
device->addMapper(new MultiTouchInputMapper(device)); //多点触模屏
} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
device->addMapper(new SingleTouchInputMapper(device)); //单点触摸屏
}
// Joystick-like devices.
if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
device->addMapper(new JoystickInputMapper(device)); //手柄
}
return device;
}(一)触屏事件
以下为触屏事件对应的mapper,我们以多点触摸屏为例:
InputReader.cpp
void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
TouchInputMapper::process(rawEvent);
mMultiTouchMotionAccumulator.process(rawEvent);
}void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) {
sync(rawEvent->when);
}
}从上面看来,只是将rawEvent->when所传入到sync当中,那其他信息呢?
在 MultiTouchInputMapper::process中,我们看到还调用了MultiTouchMotionAccumulator::process,并传入了整个 rawEvent,"accumulator"翻译成中文是"蓄电池、累加器"的意思,那么我们现在猜想,这一步中的sync并未将当前的rawEvent进行同步分发,而是只是将此事件放在 mMultiTouchMotionAccumulator中暂时累积起来而已。
是不是这样呢? 我们再继续分析~
void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
if (rawEvent->type == EV_ABS) { //此次上报数据类型为 EV_ABS,
bool newSlot = false;
if (mUsingSlotsProtocol) {
if (rawEvent->scanCode == ABS_MT_SLOT) {
mCurrentSlot = rawEvent->value;
newSlot = true;
}
} else if (mCurrentSlot < 0) {
mCurrentSlot = 0;
}
if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) {
//mSlotCount,这个值表示当前触摸屏支持多点触摸的最大点数,
//由 InputDevice::addDeviceLocked -> InputDevice::configure
//-> TouchInputMapper::configure -> MultiTouchInputMapper::configureRawPointerAxes
//-> MultiTouchMotionAccumulator::configure设置,即由驱动确定
//mCurrentSlot表示当前实际的触摸点数
...
} else {
Slot* slot = &mSlots[mCurrentSlot]; //使slot指向&mSlots[mCurrentSlot],mCureentSlot表示当前有几个手指同时点触
//支持多点触控的触摸屏所报上来的数据为一个椭圆,
//以下为此椭圆的各项参数
//压力等
switch (rawEvent->scanCode) {
case ABS_MT_POSITION_X:
slot->mInUse = true;
slot->mAbsMTPositionX = rawEvent->value;
break;
case ABS_MT_POSITION_Y:
slot->mInUse = true;
slot->mAbsMTPositionY = rawEvent->value;
break;
case ABS_MT_TOUCH_MAJOR:
...
}
}
} else if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_MT_REPORT) { //上报此类型数据表示一次完整的touch事件已经上报完成
// MultiTouch Sync: The driver has returned all data for *one* of the pointers.
mCurrentSlot += 1; //mCurrentSlot加1,指向下一个slot(每一个slot代表一个完整的触点信息)
}
}基本明白了,原来一个触点所包含的坐标、压力等信息是分别上报上来的,InputReader线程接收后通过"accumulator"进行综合,每次上报事件"(rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_MT_REPORT) "代表一个触点信息的完结。
继续看 TouchInputMapper::process函数:
void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) {
sync(rawEvent->when);
}
}这里又调用了三个process,这三个process分别对应三种类型的触摸设备事件:CursorButton、CursorScroll、TouchButton,设计理念与mapper一样,也是在各自的process中判断type,匹配才进行处理,加到"accumulator"中,如:
void CursorScrollAccumulator::process(const RawEvent* rawEvent) {
if (rawEvent->type == EV_REL) {
switch (rawEvent->scanCode) {
case REL_WHEEL:
mRelWheel = rawEvent->value;
break;
case REL_HWHEEL:
mRelHWheel = rawEvent->value;
break;
}
}
}再看sync函数,sync意为同步,那这里应该是真正将数据上报的地方了:
void TouchInputMapper::sync(nsecs_t when) {
// Sync button state.
// 将 mCursorButtonAccumulator.process 和 mTouchButtonAccumulator.process
// 中处理得到的最新状态获取并同步到 mCurrentButtonState上来
mCurrentButtonState = mTouchButtonAccumulator.getButtonState()
| mCursorButtonAccumulator.getButtonState();
// Sync scroll state.
// 将通过 mCursorScrollAccumulator.process处理得到的最新状态同步到
// mCurrentRawVScroll和 mCurrentRawHScroll当中
mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
mCursorScrollAccumulator.finishSync();
// Sync touch state.
// 同样, 将通过 mMultiTouchMotionAccumulator.process处理得到的多点触控数据
// 同步(同步至成员变量 mCurrentRawPointerData中)
bool havePointerIds = true;
mCurrentRawPointerData.clear();
syncTouch(when, &havePointerIds);
#if DEBUG_RAW_EVENTS
if (!havePointerIds) {
LOGD("syncTouch: pointerCount %d -> %d, no pointer ids",
mLastRawPointerData.pointerCount,
mCurrentRawPointerData.pointerCount);
} else {
LOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
"hovering ids 0x%08x -> 0x%08x",
mLastRawPointerData.pointerCount,
mCurrentRawPointerData.pointerCount,
mLastRawPointerData.touchingIdBits.value,
mCurrentRawPointerData.touchingIdBits.value,
mLastRawPointerData.hoveringIdBits.value,
mCurrentRawPointerData.hoveringIdBits.value);
}
#endif
// Reset state that we will compute below.
mCurrentFingerIdBits.clear();
mCurrentStylusIdBits.clear();
mCurrentMouseIdBits.clear();
mCurrentCookedPointerData.clear();
if (mDeviceMode == DEVICE_MODE_DISABLED) { //disable mode, 丢弃
// Drop all input if the device is disabled.
mCurrentRawPointerData.clear();
mCurrentButtonState = 0;
} else {
// Preprocess pointer data.
if (!havePointerIds) {
assignPointerIds();
}
// Handle policy on initial down or hover events.
uint32_t policyFlags = 0;
//针对多点触摸事件, mLastRawPointerData无数据&&mCurrentRawPointerData中有数据, 意味着现在是首次按下
bool initialDown = mLastRawPointerData.pointerCount == 0
&& mCurrentRawPointerData.pointerCount != 0;
//针对触摸按键事件, mLastButtonState状态为空&&mCurrentButtonState状态不为空则认为按键动作为DOWN
bool buttonsPressed = mCurrentButtonState & ~mLastButtonState;
if (initialDown || buttonsPressed) {
// If this is a touch screen, hide the pointer on an initial down.
if (mDeviceMode == DEVICE_MODE_DIRECT) {
getContext()->fadePointer();
}
// Initial downs on external touch devices should wake the device.
// We don't do this for internal touch screens to prevent them from waking
// up in your pocket.
// TODO: Use the input device configuration to control this behavior more finely.
if (getDevice()->isExternal()) {
policyFlags |= POLICY_FLAG_WAKE_DROPPED;
}
}
// Synthesize key down from raw buttons if needed.
// 根据 policyFlags, mLastButtonState和mCurrentButtonState等这些事件, 软件生成相应的
// 按键事件, 然后通过 notyfyKey上报
synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
policyFlags, mLastButtonState, mCurrentButtonState);
// Consume raw off-screen touches before cooking pointer data.
// If touches are consumed, subsequent code will not receive any pointer data.
// 对 mCurrentRawPointerData进行判断, 如果是虚拟按键则生成对应按键并上报
if (consumeRawTouches(when, policyFlags)) {
// 返回 TRUE则表示为虚拟按键事件, 已经处理完毕, 清除 mCurrentRawPointerData
mCurrentRawPointerData.clear();
}
// Cook pointer data. This call populates the mCurrentCookedPointerData structure
// with cooked pointer data that has the same ids and indices as the raw data.
// The following code can use either the raw or cooked data, as needed.
// 呵呵, 这个函数名字取得很形象
// 前面说过, 之前的数据是保存在 mCurrentRawPointerData当中, 数据是未处理的, 是raw
// 而这里则是进行加工, cook, 比如pressure换算, x&y坐标翻转等, 结果存在 mCurrentCookedPointerData中
// 即 mCurrentRawPointerData -> mCurrentCookedPointerData
cookPointerData();
// Dispatch the touches either directly or by translation through a pointer on screen.
// 开始分发 mCurrentCookedPointerData
// 如果设备模式为 DEVICE_MODE_POINTER, 则要先作一下 mapping, 即映射(是否类似于电脑触摸板???)
if (mDeviceMode == DEVICE_MODE_POINTER) {
// 转换设备类型标志位
for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) {
uint32_t id = idBits.clearFirstMarkedBit();
const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
|| pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
mCurrentStylusIdBits.markBit(id);
} else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
|| pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
mCurrentFingerIdBits.markBit(id);
} else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
mCurrentMouseIdBits.markBit(id);
}
}
for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) {
uint32_t id = idBits.clearFirstMarkedBit();
const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
|| pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
mCurrentStylusIdBits.markBit(id);
}
}
// Stylus takes precedence over all tools, then mouse, then finger.
// 这里说了, Stylus优先级最高, 其次为mouse , 再为finger
PointerUsage pointerUsage = mPointerUsage;
if (!mCurrentStylusIdBits.isEmpty()) {
mCurrentMouseIdBits.clear();
mCurrentFingerIdBits.clear();
pointerUsage = POINTER_USAGE_STYLUS;
} else if (!mCurrentMouseIdBits.isEmpty()) {
mCurrentFingerIdBits.clear();
pointerUsage = POINTER_USAGE_MOUSE;
} else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) {
pointerUsage = POINTER_USAGE_GESTURES;
}
// 终于开始dispatch了
dispatchPointerUsage(when, policyFlags, pointerUsage);
} else {
// 设备模式为触摸屏
if (mDeviceMode == DEVICE_MODE_DIRECT
&& mConfig.showTouches && mPointerController != NULL) {
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
mPointerController->setButtonState(mCurrentButtonState);
mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords,
mCurrentCookedPointerData.idToIndex,
mCurrentCookedPointerData.touchingIdBits);
}
// 开始分发
dispatchHoverExit(when, policyFlags);
dispatchTouches(when, policyFlags);
dispatchHoverEnterAndMove(when, policyFlags);
}
// Synthesize key up from raw buttons if needed. - 作者已经说得很明白了
synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
policyFlags, mLastButtonState, mCurrentButtonState);
}
// Copy current touch to last touch in preparation for the next cycle.
mLastRawPointerData.copyFrom(mCurrentRawPointerData);
mLastCookedPointerData.copyFrom(mCurrentCookedPointerData);
mLastButtonState = mCurrentButtonState;
mLastFingerIdBits = mCurrentFingerIdBits;
mLastStylusIdBits = mCurrentStylusIdBits;
mLastMouseIdBits = mCurrentMouseIdBits;
// Clear some transient state.
mCurrentRawVScroll = 0;
mCurrentRawHScroll = 0;
}上面在处理数据时有对数据进行判断,当判断触点处于虚拟按键区域时,会生成对应的key事件,我们这里再来看一下它是怎么做的:
bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) {
// Check for release of a virtual key.
// 虚拟按键当前为 DOWN状态
if (mCurrentVirtualKey.down) {
// 当前手指未按下任何区域
if (mCurrentRawPointerData.touchingIdBits.isEmpty()) {
// Pointer went up while virtual key was down.
mCurrentVirtualKey.down = false;
if (!mCurrentVirtualKey.ignored) {
#if DEBUG_VIRTUAL_KEYS
LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
#endif
//制造一个 UP事件并上报
dispatchVirtualKey(when, policyFlags,
AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
}
return true;
}
if (mCurrentRawPointerData.touchingIdBits.count() == 1) {
uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit();
const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
//手指当前所触控区域仍然为 mCurrentVirtualKey所存储按键
if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) {
// Pointer is still within the space of the virtual key.
return true;
}
}
// Pointer left virtual key area or another pointer also went down.
// Send key cancellation but do not consume the touch yet.
// This is useful when the user swipes through from the virtual key area
// into the main display surface.
// 手指当前按下区域已经不是之前触控按键所在区域
mCurrentVirtualKey.down = false;
if (!mCurrentVirtualKey.ignored) {
#if DEBUG_VIRTUAL_KEYS
LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
#endif
//制造一个 UP事件并上报
dispatchVirtualKey(when, policyFlags,
AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY
| AKEY_EVENT_FLAG_CANCELED);
}
}
//判断是否符合DOWN事件特征
if (mLastRawPointerData.touchingIdBits.isEmpty()
&& !mCurrentRawPointerData.touchingIdBits.isEmpty()) {
// Pointer just went down. Check for virtual key press or off-screen touches.
uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit();
const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
if (!isPointInsideSurface(pointer.x, pointer.y)) {
// If exactly one pointer went down, check for virtual key hit.
// Otherwise we will drop the entire stroke.
if (mCurrentRawPointerData.touchingIdBits.count() == 1) {
// 根据pointer坐标确定keyCode等
const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
if (virtualKey) {
mCurrentVirtualKey.down = true;
mCurrentVirtualKey.downTime = when;
mCurrentVirtualKey.keyCode = virtualKey->keyCode;
mCurrentVirtualKey.scanCode = virtualKey->scanCode;
mCurrentVirtualKey.ignored = mContext->shouldDropVirtualKey(
when, getDevice(), virtualKey->keyCode, virtualKey->scanCode);
if (!mCurrentVirtualKey.ignored) {
#if DEBUG_VIRTUAL_KEYS
LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
mCurrentVirtualKey.keyCode,
mCurrentVirtualKey.scanCode);
#endif
// 创造 DOWN事件并上报
dispatchVirtualKey(when, policyFlags,
AKEY_EVENT_ACTION_DOWN,
AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
}
}
}
return true;
}
}
// Disable all virtual key touches that happen within a short time interval of the
// most recent touch within the screen area. The idea is to filter out stray
// virtual key presses when interacting with the touch screen.
//
// Problems we're trying to solve:
//
// 1. While scrolling a list or dragging the window shade, the user swipes down into a
// virtual key area that is implemented by a separate touch panel and accidentally
// triggers a virtual key.
//
// 2. While typing in the on screen keyboard, the user taps slightly outside the screen
// area and accidentally triggers a virtual key. This often happens when virtual keys
// are layed out below the screen near to where the on screen keyboard's space bar
// is displayed.
// 在mConfig.virtualKeyQuietTime这个时间内禁止所有虚拟按键
if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawPointerData.touchingIdBits.isEmpty()) {
mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime);
}
return false;
}通过sync函数,我们发现,touch所有事件的分发,根据 device mode的不同,都是通过以下两种方式完成的:
DEVICE_MODE_POINTER:
dispatchPointerUsage(when, policyFlags, pointerUsage);DEVICE_MODE_DIRECT:
dispatchHoverExit(when, policyFlags);
dispatchTouches(when, policyFlags);
dispatchHoverEnterAndMove(when, policyFlags);而上面这四个函数最终也都是通过调用 dispatchMotion,只是使用的参数(第四个参数, 即action)不一样罢了:
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
const PointerProperties* properties, const PointerCoords* coords,
const uint32_t* idToIndex, BitSet32 idBits,
int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime)这里贴出 dispatchTouches函数看一下:
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits;
BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits;
int32_t metaState = getContext()->getGlobalMetaState();
int32_t buttonState = mCurrentButtonState;
if (currentIdBits == lastIdBits) {
if (!currentIdBits.isEmpty()) {
// No pointer id changes so this is a move event.
// The listener takes care of batching moves so we don't have to deal with that here.
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
mCurrentCookedPointerData.pointerProperties,
mCurrentCookedPointerData.pointerCoords,
mCurrentCookedPointerData.idToIndex,
currentIdBits, -1,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
} else {
// There may be pointers going up and pointers going down and pointers moving
// all at the same time.
BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);
BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);
BitSet32 dispatchedIdBits(lastIdBits.value);
// Update last coordinates of pointers that have moved so that we observe the new
// pointer positions at the same time as other pointers that have just gone up.
bool moveNeeded = updateMovedPointers(
mCurrentCookedPointerData.pointerProperties,
mCurrentCookedPointerData.pointerCoords,
mCurrentCookedPointerData.idToIndex,
mLastCookedPointerData.pointerProperties,
mLastCookedPointerData.pointerCoords,
mLastCookedPointerData.idToIndex,
moveIdBits);
if (buttonState != mLastButtonState) {
moveNeeded = true;
}
// Dispatch pointer up events.
while (!upIdBits.isEmpty()) {
uint32_t upId = upIdBits.clearFirstMarkedBit();
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0,
mLastCookedPointerData.pointerProperties,
mLastCookedPointerData.pointerCoords,
mLastCookedPointerData.idToIndex,
dispatchedIdBits, upId,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
dispatchedIdBits.clearBit(upId);
}
// Dispatch move events if any of the remaining pointers moved from their old locations.
// Although applications receive new locations as part of individual pointer up
// events, they do not generally handle them except when presented in a move event.
if (moveNeeded) {
LOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0,
mCurrentCookedPointerData.pointerProperties,
mCurrentCookedPointerData.pointerCoords,
mCurrentCookedPointerData.idToIndex,
dispatchedIdBits, -1,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
// Dispatch pointer down events using the new pointer locations.
while (!downIdBits.isEmpty()) {
uint32_t downId = downIdBits.clearFirstMarkedBit();
dispatchedIdBits.markBit(downId);
if (dispatchedIdBits.count() == 1) {
// First pointer is going down. Set down time.
mDownTime = when;
}
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
mCurrentCookedPointerData.pointerProperties,
mCurrentCookedPointerData.pointerCoords,
mCurrentCookedPointerData.idToIndex,
dispatchedIdBits, downId,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
}
}可以发现其action用到了 AMOTION_EVENT_ACTION_MOVE 和 AMOTION_EVENT_ACTION_POINTER_UP,所有的action包含以下几种:
enum {
AMOTION_EVENT_ACTION_MASK = 0xff,
AMOTION_EVENT_ACTION_POINTER_INDEX_MASK = 0xff00,
AMOTION_EVENT_ACTION_DOWN = 0,
AMOTION_EVENT_ACTION_UP = 1,
AMOTION_EVENT_ACTION_MOVE = 2,
AMOTION_EVENT_ACTION_CANCEL = 3,
AMOTION_EVENT_ACTION_OUTSIDE = 4,
AMOTION_EVENT_ACTION_POINTER_DOWN = 5,
AMOTION_EVENT_ACTION_POINTER_UP = 6,
AMOTION_EVENT_ACTION_HOVER_MOVE = 7,
AMOTION_EVENT_ACTION_SCROLL = 8,
AMOTION_EVENT_ACTION_HOVER_ENTER = 9,
AMOTION_EVENT_ACTION_HOVER_EXIT = 10,
};进入 dispatchMotion:
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
const PointerProperties* properties, const PointerCoords* coords,
const uint32_t* idToIndex, BitSet32 idBits,
int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
PointerCoords pointerCoords[MAX_POINTERS];
PointerProperties pointerProperties[MAX_POINTERS];
uint32_t pointerCount = 0;
while (!idBits.isEmpty()) {
uint32_t id = idBits.clearFirstMarkedBit();
uint32_t index = idToIndex[id];
pointerProperties[pointerCount].copyFrom(properties[index]);
pointerCoords[pointerCount].copyFrom(coords[index]);
if (changedId >= 0 && id == uint32_t(changedId)) {
action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
pointerCount += 1;
}
LOG_ASSERT(pointerCount != 0);
if (changedId >= 0 && pointerCount == 1) {
// Replace initial down and final up action.
// We can compare the action without masking off the changed pointer index
// because we know the index is 0.
if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
action = AMOTION_EVENT_ACTION_DOWN;
} else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
action = AMOTION_EVENT_ACTION_UP;
} else {
// Can't happen.
LOG_ASSERT(false);
}
}
NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
action, flags, metaState, buttonState, edgeFlags,
pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime);
getListener()->notifyMotion(&args);
}发现最终是调用 getListener()->notifyMotion(&args),继续看代码(确实有点累了):
getListener()获取的是 mQueuedListener:
InputListenerInterface* InputReader::ContextImpl::getListener() {
return mReader->mQueuedListener.get();
}void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
mArgsQueue.push(new NotifyMotionArgs(*args));
}哦,原来只是用参数构建 NotifyMotionArgs对象加入队列。
看到这里,相信很多人都会有疑问,事件只是经过一系列处理、转换后存到了mArgsQueue中,还是没有上报上去啊!?上报的动作到底在哪里呢?
我们再回过头来看一下 InputReader::loopOnce这个函数:
void InputReader::loopOnce() {
int32_t timeoutMillis;
{ // acquire lock
AutoMutex _l(mLock);
uint32_t changes = mConfigurationChangesToRefresh;
if (changes) {
mConfigurationChangesToRefresh = 0;
refreshConfigurationLocked(changes);
}
timeoutMillis = -1;
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
}
} // release lock
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
if (count) {
processEventsLocked(mEventBuffer, count);
}
if (!count || timeoutMillis == 0) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
#if DEBUG_RAW_EVENTS
LOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now);
}
} // release lock
// Flush queued events out to the listener.
// This must happen outside of the lock because the listener could potentially call
// back into the InputReader's methods, such as getScanCodeState, or become blocked
// on another thread similarly waiting to acquire the InputReader lock thereby
// resulting in a deadlock. This situation is actually quite plausible because the
// listener is actually the input dispatcher, which calls into the window manager,
// which occasionally calls into the input reader.
mQueuedListener->flush();
}我们这一节的分析都集中在 mEventHub->getEvents 和 processEventsLocked当中,但在最后它还调用了一个函数 flush(),一看到这个函数大家应该马上会想到写文件时的flush吧!——即所有真正的磁盘写动作都是在flush时完成的!那这里是不是类似呢?
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener); //如果没猜错的话,这里应该就是真正的事件分发了吧!
delete args;
}
mArgsQueue.clear();
}继续看一下 NotifyArgs这个类:
/* Superclass of all input event argument objects */
struct NotifyArgs {
virtual ~NotifyArgs() { }
virtual void notify(const sp<InputListenerInterface>& listener) const = 0;
};可以发现这是一个无法实例化的父类,因为其 notify函数是纯虚函数,我们再看一下它有多少子类:
struct NotifyConfigurationChangedArgs : public NotifyArgs
struct NotifyKeyArgs : public NotifyArgs
struct NotifyMotionArgs : public NotifyArgs
struct NotifySwitchArgs : public NotifyArgs
struct NotifyDeviceResetArgs : public NotifyArgs在上面所示的 dispatchMotion函数中可以看到,触屏事件分发时所用的 NotifyArgs子类为 NotifyMotionArgs:
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyMotion(this);
}这个listener是何方神圣?
首先看到是这里传入的:
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener); //如果没猜错的话,这里应该就是真正的事件分发了吧!
delete args;
}
mArgsQueue.clear();
}而这个成员变量 mInnerListener又是在构建函数中传入的:
QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
mInnerListener(innerListener) {
}而 QueuedInputListener又是在 InputReader实例化的:
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mGlobalMetaState(0), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);
{ // acquire lock
...
}listener这个参数还是传进来的,必须再找到 InputReader构建的地方:
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}一切都明白了!原来这个listener就是 InputDispatcher的对象 mDispatcher!
我们来看一下 interceptMotionBeforeQueueing这个函数,直接从名字上看,应该是说在将motion事件加入队列前进行拦截
void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
// Policy:
// - Ignore untrusted events and pass them along.
// - No special filtering for injected events required at this time.
// - Filter normal events based on screen state.
// - For normal events brighten (but do not wake) the screen if currently dim.
if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) {
if (isScreenOn()) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
if (!isScreenBright()) {
policyFlags |= POLICY_FLAG_BRIGHT_HERE;
}
} else {
JNIEnv* env = jniEnv();
// 由register_android_server_InputManager可知,这里实际调用的是
// com/android/server/wm/InputManager类中的 interceptMotionBeforeQueueingWhenScreenOff函数
jint wmActions = env->CallIntMethod(mCallbacksObj,
gCallbacksClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
policyFlags);
if (checkAndClearExceptionFromCallback(env,
"interceptMotionBeforeQueueingWhenScreenOff")) {
wmActions = 0;
}
policyFlags |= POLICY_FLAG_WOKE_HERE | POLICY_FLAG_BRIGHT_HERE;
// 根据 interceptMotionBeforeQueueingWhenScreenOff返回的wmAction进行处理
handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
}
} else {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
}
}那这个 gCallbacksClassInfo.interceptMotionBeforeQueueingWhenScreenOff到底最终调用的是哪个函数呢?
InputManager.java
@SuppressWarnings("unused")
public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
return mWindowManagerService.mInputMonitor.interceptMotionBeforeQueueingWhenScreenOff(
policyFlags);
}继续:
InputMonitor.java
/* Provides an opportunity for the window manager policy to intercept early
* motion event processing when the screen is off since these events are normally
* dropped. */
public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
}找到了:
PhoneWindowManager.java
/** {@inheritDoc} */
@Override
public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
int result = 0;
final boolean isWakeMotion = (policyFlags
& (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
if (isWakeMotion) {
// 如果当前界面为锁屏界面
if (mKeyguardMediator.isShowing()) {
// If the keyguard is showing, let it decide what to do with the wake motion.
// 让锁屏进行一些处理
mKeyguardMediator.onWakeMotionWhenKeyguardShowingTq();
} else {
// Otherwise, wake the device ourselves.
// 设置标志 ACTION_POKE_USER_ACTIVITY
result |= ACTION_POKE_USER_ACTIVITY;
}
}
return result;
}
void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
uint32_t& policyFlags) {
if (wmActions & WM_ACTION_GO_TO_SLEEP) {
#if DEBUG_INPUT_DISPATCHER_POLICY
LOGD("handleInterceptActions: Going to sleep.");
#endif
//调用 PowerManagerService::goToSleep
android_server_PowerManagerService_goToSleep(when);
}
if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
#if DEBUG_INPUT_DISPATCHER_POLICY
LOGD("handleInterceptActions: Poking user activity.");
#endif
//调用 PowerManagerService::userActivity
android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT);
}
if (wmActions & WM_ACTION_PASS_TO_USER) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
} else {
#if DEBUG_INPUT_DISPATCHER_POLICY
LOGD("handleInterceptActions: Not passing key to user.");
#endif
}
}四、笔记
updateInputWindowsLw -> setInputWindows -> nativeSetInputWindows -> setInputWindows ->
mInputManager->getDispatcher()->setInputWindows(windowHandles) -> 更新 mFocusedWindowHandle
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor)
=>更新 mMonitoringChannels
//InputDispatcher.cpp
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Preprocessing.
...
// Handle case where the policy asked us to try again later last time.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) {
if (currentTime < entry->interceptKeyWakeupTime) {
if (entry->interceptKeyWakeupTime < *nextWakeupTime) {
*nextWakeupTime = entry->interceptKeyWakeupTime;
}
return false; // wait until next wakeup
}
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
entry->interceptKeyWakeupTime = 0;
}
// Give the policy a chance to intercept the key.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); //interceptKeyBeforeDispatching
if (mFocusedWindowHandle != NULL) {
commandEntry->inputWindowHandle = mFocusedWindowHandle;
}
commandEntry->keyEntry = entry;
entry->refCount += 1;
return false; // wait for the command to run
} else {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
}
} else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
if (*dropReason == DROP_REASON_NOT_DROPPED) {
*dropReason = DROP_REASON_POLICY;
}
}
// Clean up if dropping the event.
if (*dropReason != DROP_REASON_NOT_DROPPED) {
setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
return true;
}
// Identify targets.
Vector<InputTarget> inputTargets;
int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime); //将 mFocusedWindowHandle 加入 inputTargets
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
return false;
}
setInjectionResultLocked(entry, injectionResult);
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
return true;
}
addMonitoringTargetsLocked(inputTargets); //将 mMonitoringChannels 加入 inputTargets
// Dispatch the key.
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}