Android input 系统之一 :InputReader线程
touch事件处理流程:
底层触摸事件上报至framework层,事件未分发之前的数据读取与处理流程:
"InputReader 线程"
bool InputReaderThread::threadLoop() frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::loopOnce()
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); //从EventHub读取事件,其中EVENT_BUFFER_SIZE = 256
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) frameworks/native/services/inputflinger/EventHub.cpp
scanDevicesLocked();//扫描设备,会把dev/input下所有可用的输入设备打开并储存到Device结构体中
int32_t readSize = read(device->fd, readBuffer, sizeof(struct input_event) * capacity); //从设备不断读取事件,放入到readBuffer
//将input_event信息, 封装成"RawEvent"
>>(event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL + nsecs_t(iev.time.tv_usec) * 1000LL;
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;)
return event - buffer; //返回所读取的事件个数
processEventsLocked(mEventBuffer, count);//事件处理
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count)
>>>>>>> "if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {"
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count)
device->process(rawEvents, count);
void InputDevice::process(const RawEvent* rawEvents, size_t count)
mapper->process(rawEvent);//调用具体mapper来处理( 以MultiTouch为例 )
SwitchInputMapper::process(const RawEvent* rawEvent);
KeyboardInputMapper::process(const RawEvent* rawEvent);
CursorInputMapper::process(const RawEvent* rawEvent);
RotaryEncoderInputMapper::process(const RawEvent* rawEvent);
TouchInputMapper::process(const RawEvent* rawEvent);
SingleTouchInputMapper::process(const RawEvent* rawEvent);
ExternalStylusInputMapper::process(const RawEvent* rawEvent);
JoystickInputMapper::process(const RawEvent* rawEvent);
MultiTouchInputMapper::process(const RawEvent* rawEvent);
>>TouchInputMapper::process(rawEvent);
>>mMultiTouchMotionAccumulator.process(rawEvent);
void TouchInputMapper::process(const RawEvent* rawEvent)//由于多点触摸屏中没有Button,Scroll,因此这里不做处理
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
//多点触摸的前几个点是不会执行sync的,所有点上报完后input_sync()上报的
sync(rawEvent->when); //同步
void TouchInputMapper::sync(nsecs_t when)
syncTouch(when, next);
processRawTouches(false /*timeout*/);
cookAndDispatch(mCurrentRawState.when);
void TouchInputMapper::cookAndDispatch(nsecs_t when)
>>>>>>>>>>>>>>>>>>>>>>>> "if (mDeviceMode == DEVICE_MODE_DIRECT) {
//touchScreen:触摸屏,覆盖在LCD屏上,可以操作各种图标
//stylus(笔尖),gestrue(手势),mouse(鼠标)
//touchPad:触摸板,不是覆盖在LCD屏上,需要在LCD屏上显示一个光标以便定位。"
// touchScreen:触摸屏,覆盖在LCD屏上,可以操作各种图标
// touchPad:触摸板,不是覆盖在LCD屏上,需要在LCD屏上显示一个光标以便定位。
// pointer:和touchPad类似,但是多一些手势功能
// default:由系统根据某些算法来确定类型。
cookPointerData();//将原始的输入事件(坐标)转变为屏幕坐标
void TouchInputMapper::cookPointerData()
//驱动上报touch信息时,不仅仅会上报坐标点,同时还会有tracking_id,pressure ,touch_major等属性值;
//属性值会在cookPointerData函数中经过简单计算然后再上报,例如坐标转换、压力值归一化
dispatchPointerUsage(when, policyFlags, pointerUsage);
void TouchInputMapper::dispatchPointerUsage
case POINTER_USAGE_GESTURES:
dispatchPointerGestures(when, policyFlags, false /*isTimeout*/);
dispatchMotion();
void TouchInputMapper::dispatchMotion
getListener()->notifyMotion(&args); //getListener()=mReader->mQueuedListener.get()=InputListenerInterface
void QueuedInputListener::notifyMotion frameworks/native/services/inputflinger/InputListener.cpp
mArgsQueue.push(new NotifyMotionArgs(*args)); //InputListenerInterface::notifyMotion, NotifyArgs=mArgsQueue
//look at mQueuedListener->flush();
>>>>>>>>>>>>>>>>>>>>>>> " }else{"
if (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches && mPointerController != NULL){
if (!mCurrentMotionAborted) {
dispatchButtonRelease(when, policyFlags);
dispatchHoverExit(when, policyFlags);
dispatchTouches(when, policyFlags);
dispatchHoverEnterAndMove(when, policyFlags);
dispatchButtonPress(when, policyFlags);
dispatchMotion(...);
getListener()->notifyMotion(&args); //getListener()=mReader->mQueuedListener.get()=InputListenerInterface
mArgsQueue.push(new NotifyMotionArgs(*args)); //InputListenerInterface::notifyMotion, NotifyArgs=mArgsQueue
//look at mQueuedListener->flush();
}
}
>>>>>>>>>>> "} else {"
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId)
InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes)
//添加键盘类设备InputMapper
if (keyboardSource != 0) {
device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
}
//添加鼠标类设备InputMapper
if (classes & INPUT_DEVICE_CLASS_CURSOR) {
device->addMapper(new CursorInputMapper(device));
}
//添加触摸屏设备InputMapper
if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
device->addMapper(new MultiTouchInputMapper(device));
}
device->configure(when, &mConfig, 0);//依次调用了inputDevice::configure()和TouchInputMapper::configure()两个函数,
//去获取监听设备的配置信息(包括在驱动中配置的TP分辨率)和display信息。值得注意的是,
//上面提到的设备配置信息仅会在这里更新一次;如果配置出现异常将无法恢复,直到再次开关机
void InputDevice::configure
mapper->configure(when, config, changes);
void TouchInputMapper::configure
configureSurface(when, &resetNeeded);//主要是根据当前显示视图的旋转角度来分别计算TP坐标到显示坐标的转换系数。
//当手机竖直放置时(旋转角度为0),X轴转换系数= (LCD_width) / (TP_X_max) , Y轴转换系数 =(LCD_height) /(TP_Y_max)
}
>>>>>>>>> "mQueuedListener->flush();" //QueuedInputListeners=mQueuedListener
void QueuedInputListener::flush()
args->notify(mInnerListener); //NotifyKeyArgs:NotifyArgs=args
void NotifyKeyArgs::notify(const sp& listener)
listener->notifyKey(this); //InputDispatcher:InputDispatcherInterface:InputListenerInterface
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) frameworks/native/services/inputflinger/InputDispatcher.cpp
event.initialize() //KeyEvent event; & 将NotifyKeyArgs转换为KeyEvent
void KeyEvent::initialize frameworks/native/libs/input/Input.cpp
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); //intercept=拦截, //mPolicy=NativeInputManager =>PhoneWindowManager
"//mPolicy是指NativeInputManager对象"
调用NativeInputManager.interceptKeyBeforeQueueing,加入队列前执行拦截动作,但并不改变流程,调用链:
//IMS.interceptKeyBeforeQueueing
//InputMonitor.interceptKeyBeforeQueueing (继承IMS.WindowManagerCallbacks)
//PhoneWindowManager.interceptKeyBeforeQueueing (继承WindowManagerPolicy)
void NativeInputManager::interceptMotionBeforeQueueing frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
JNIEnv* env = jniEnv(); // 调用Java层的IMS.interceptKeyBeforeQueueing
jint wmActions = env->CallIntMethod(mServiceObj,gServiceClassInfo.interceptMotionBeforeQueueingNonInteractive,when, policyFlags);
private int interceptMotionBeforeQueueingNonInteractive //native callback frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
virtual void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) //定义fameworks/native/services/inputflinger/tests/InputDispatcher_test.cpp
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) "frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java "
// https://blog.csdn.net/qidabing/article/details/73614621
//Android7.0 PowerManagerService亮灭屏分析(一)
bool needWake;
//当inputEventObj不为空, 则事件被filter所拦截
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
return;
}
NativeInputManager::filterInputEvent frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
bool NativeInputManager::filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags)
JNIEnv* env = jniEnv();
if (!inputEventObj) {
return true; // 当inputEventObj为空, 则走事件正常的分发流程
}
//当inputEventObj不为空,则调用Java层的IMS.filterInputEvent()
jboolean pass = env->CallBooleanMethod(mServiceObj, gServiceClassInfo.filterInputEvent, inputEventObj, policyFlags);
final boolean filterInputEvent(InputEvent event, int policyFlags) frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
needWake = enqueueInboundEventLocked(newEntry); //将newEntry即本次keyevent送到队列中
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) frameworks/native/services/inputflinger/InputDispatcher.cpp
mInboundQueue.enqueueAtTail(entry); //将该事件放入mInboundQueue队列尾部
switch (entry->type) {
case EventEntry::TYPE_KEY:
//其中APP_SWITCH_TIMEOUT=500ms
mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
case EventEntry::TYPE_MOTION:
//当前App无响应且用户希望切换到其他应用窗口,则drop该窗口事件,并处理其他窗口事件
//查询可触摸的窗口
sp touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); // InputDispatcher.cpp
//从前台到后台来遍历查询可触摸的窗口
if (needWake) {
mLooper->wake(); } //唤醒InputDispatcher线程, EVENT_REPORT_SIGN1_WAKE1 如果需要唤醒mLooper则马上唤醒,唤醒后事件将立马进行分发 & InputDispatcher::mLooper