Android InputFlinger简单分析(主要分析Touch)
首先,它有个服务,InputManagerService.
InputManagerService启动
startOtherServices@SystemServer
...
inputManager = new InputManagerService(context);
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
...
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
...
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
...
看看构造函数:
public InputManagerService(Context context) {
...
mPtr = nativeInit(this, mContext,mHandler.getLooper().getQueue());
...
}
这个mPrt之后作为了其他native函数的第一个参数。先看看nativeInit
(位置base/services/core/jni/com_android_server_input_InputManagerService.cpp)
static jlong nativeInit(JNIEnv* env, jclass clazz,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
...
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast(im);
}
简单来理解就是获取java层的消息队列,然后构造了一个NativeInputManager对象,然后返回java层,赋值给mPtr。
前文,startOtherServices@SystemServer中还调用了
inputManager.start();
start()@InputManagerService
...
nativeStart(mPtr);
...
nativeStart:
static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) {
NativeInputManager* im = reinterpret_cast(ptr);
status_t result = im->getInputManager()->start();
...
}
即用nativeInit中new的NativeInputManager对象调用start函数。
那NativeInputManager是什么呢?
inline sp getInputManager() const { return mInputManager; }
直接去看InputManager调用start函数就好了。
接下来,我们的工作目录就集中到
frameworks/native/services/inputflinger
从InputManager::start开始
...
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
...
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
...
mDispatcherThread和mReaderThread的run函数,都会去调用threadLoop函数(就当是常识了)。
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
从名字上来看,一个专门去读取input,一个专门去分发input.可是为什么只运行一次(loopOnce)呢?
我们这次主要关注的是touch事件,即MotionEvent.
InputDispatcher.h
struct MotionEntry : EventEntry {
Motion是Event的一种!
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);
这几个函数功能应该类似,只不过Event种类不同。
在InputDispatcher.cpp中竟然找不到调用。嗯!yes!搜索结果如下:
InputReader.cpp:2551: getListener()->notifyMotion(&args);
...
getListener@InputReader:
class InputReader : public InputReaderInterface {
...
virtual InputListenerInterface* getListener();
InputDispatcher.h:
class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface
...
class InputDispatcher : public InputDispatcherInterface
回头过去看一下InputManager的构造函数,就都明白了
InputManager::InputManager
InputManager::InputManager(
const sp& eventHub,
const sp& readerPolicy,
const sp& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
//注意第三个参数
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
InputReader的构造函数:
InputReader::InputReader(const sp& eventHub,
const sp& policy,
//这个
const sp& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);
而
InputListenerInterface* InputReader::ContextImpl::getListener() {
return mReader->mQueuedListener.get();
}
总的来说就是,notifyMotion函数的调用来自InputReader.读到input之后notify!
InputReader分析
InputReader::loopOnce
//引出一个EventHub,getEvents也非常类似平时在adb shell中使用的命令
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
...
processEventsLocked(mEventBuffer, count);
...
InputReader::processEventsLocked
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count;) {
...
//type不是
//DEVICE_ADDED,DEVICE_REMOVED,FINISHED_DEVICE_SCAN这三个
if(type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
...
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
}
}
}
我们来看看一个开机加载Touch device的log
V/EventHub( 1691): EventHub::readNotify nfd: 69
V/EventHub( 1691): Opening device: /dev/input/event7
V/EventHub( 1691): Created descriptor: raw=:0000:0000:name:Atmel maXTouch Touchscreen, cooked=37118057a971f33d58dfff27cf9e19bbe8914aca
V/EventHub( 1691): add device 7: /dev/input/event7
V/EventHub( 1691): bus: 0018
V/EventHub( 1691): vendor 0000
V/EventHub( 1691): product 0000
V/EventHub( 1691): version 0000
V/EventHub( 1691): name: "Atmel maXTouch Touchscreen"
V/EventHub( 1691): location: "i2c-5-004a/input0"
V/EventHub( 1691): unique id: ""
V/EventHub( 1691): descriptor: "37118057a971f33d58dfff27cf9e19bbe8914aca"
V/EventHub( 1691): driver: v1.0.1
D/EventHub( 1691): No input device configuration file found for device 'Atmel maXTouch Touchscreen'.
I/EventHub( 1691): New device: id=7, fd=213, path='/dev/input/event7', name='Atmel maXTouch Touchscreen', classes=0x14, configuration='', keyLayout='', keyCharacterMap='', builtinKeyboard=false, wakeMechanism=EPOLLWAKEUP, usingClockIoctl=true
V/EventHub( 1691): Reporting device opened: id=7, name=/dev/input/event7
V/InputReader( 1691): ZDQ after mEventHub->getEvents
//DEVICE_ADDED = 0x10000000
//这次调用来自mEventHub->getEvents
V/InputReader( 1691): ZDQ InputReader::processEventsLocked type = 10000000
//mode 1:DEVICE_MODE_DIRECT
I/InputReader( 1691): Device reconfigured: id=7, name='Atmel maXTouch Touchscreen', size 1920x720, orientation 0, mode 1, display id 0
I/InputReader( 1691): Device added: id=7, name='Atmel maXTouch Touchscreen', sources=0x00005002
//FINISHED_DEVICE_SCAN = 0x30000000
V/InputReader( 1691): ZDQ InputReader::processEventsLocked type = 30000000
然后,我们来看看一次单点touch事件的log做个预热
getevent -lr /dev/input/event7
EV_ABS ABS_MT_TRACKING_ID 00000069
EV_ABS ABS_MT_POSITION_X 00000608
EV_ABS ABS_MT_POSITION_Y 00000075
EV_KEY BTN_TOUCH DOWN
EV_ABS ABS_X 00000608
EV_ABS ABS_Y 00000075
EV_SYN SYN_REPORT 00000000 rate 0
EV_ABS ABS_MT_TRACKING_ID ffffffff
EV_KEY BTN_TOUCH UP
EV_SYN SYN_REPORT 00000000 rate 13
第一列是rawEvent->type
第二列是rawEvent->code,在函数MultiTouchMotionAccumulator::process中进行解析
第三列是value
整个event解析出来就是:
1.ABS_MT_TRACKING_ID = 0x00000069,坐标为(0x608,0x75)即
(1544,117)的一个DOWN事件
2.ABS_MT_TRACKING_ID = ffffffff
SYN_REPORT:似乎这个组合(EV_SYN,SYN_REPORT)之后就是下一个事件了
很多的process里头都是这么写的:
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
sync(rawEvent->when);
}
InputReader::processEventsForDeviceLocked之后
1.InputDevice::process
Process all of the events in order for each mapper.
We cannot simply ask each mapper to process them in bulk because mappers may
have side-effects that must be interleaved. For example, joystick movement events and gamepad button presses are handled by different mappers but they should be dispatched in the order received.
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent);
}
2.mapper->process
class TouchInputMapper : public InputMapper
class SingleTouchInputMapper : public TouchInputMapper
class MultiTouchInputMapper : public TouchInputMapper
MultiTouchInputMapper::process
void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
TouchInputMapper::process(rawEvent);
mMultiTouchMotionAccumulator.process(rawEvent);
}
TouchInputMapper::process:
void TouchInputMapper::process(const RawEvent* rawEvent) {
//应该是给鼠标用的
//专门负责EV_KEY BTN_LEFT/BTN_MIDDLE/BTN_RIGHT...这种
mCursorButtonAccumulator.process(rawEvent);
//EV_REL REL_WHEEL/REL_HWHEEL
mCursorScrollAccumulator.process(rawEvent);
//专门负责EV_KEY BTN_TOUCH...
//触摸事件就这
//EV_KEY BTN_TOUCH的时候,就一件事:
//mBtnTouch = rawEvent->value;
mTouchButtonAccumulator.process(rawEvent);
//开始报点
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
sync(rawEvent->when);
}
...
}
TouchInputMapper::sync
...
// Sync touch state.
bool havePointerIds = true;
//mCurrentRawPointerData会在这里被清掉
mCurrentRawPointerData.clear();
//纯虚函数
syncTouch(when, &havePointerIds);
...
//加工点的数据
cookPointerData();
由于syncTouch是纯虚函数,所以,syncTouch的实现在SingleTouchInputMapper,MultiTouchInputMapper中都有.
那这个地方怎么调用呢?
前面看过的一次开机log中
I/EventHub( 1691): New device: id=7, fd=213, path='/dev/input/event7', name='Atmel maXTouch Touchscreen', classes=0x14, configuration='', keyLayout='', keyCharacterMap='', builtinKeyboard=false, wakeMechanism=EPOLLWAKEUP, usingClockIoctl=true
可以看到classes=0x14
EventHub.h
/* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */
INPUT_DEVICE_CLASS_TOUCH = 0x00000004,
/* The input device is a multi-touch touchscreen. */
INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010,
而InputReader::addDeviceLocked中调用了createDeviceLocked
InputReader::createDeviceLocked:
// 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));
}
也就是说在这种情况下,SingleTouchInputMapper这个类基本是用不上的.
那前面的疑问就没了,调用的就是
//这个函数通过mMultiTouchMotionAccumulator(多点触控累加器?什么鬼?)给mCurrentRawPointerData赋了值!
void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
//Slot?槽?
size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();//configure的时候赋值,这里是16
size_t outCount = 0;
for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
const MultiTouchMotionAccumulator::Slot* inSlot =
mMultiTouchMotionAccumulator.getSlot(inIndex);
if (!inSlot->isInUse()) {
//16个slot中,not inUse的全在这continue!只有inUse的才会赋值给mCurrentRawPointerData
continue;
}
...
RawPointerData::Pointer& outPointer =
mCurrentRawPointerData.pointers[outCount];
outPointer.x = inSlot->getX();
outPointer.y = inSlot->getY();
...
outCount += 1;
}
...
}
inSlot->isInUse()怎么判定?
void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
...
Slot* slot = &mSlots[mCurrentSlot];
case ABS_MT_POSITION_X:
slot->mInUse = true;
slot->mAbsMTPositionX = rawEvent->value;
break;
case ABS_MT_POSITION_Y:
slot->mInUse = true;
...
}
可以说,主要由mCurrentSlot来决定!16个Slot中,有一个被选中,成为mCurrentSlot,这个对应的slot就成了inUse!
那么什么时候取消mInUse呢?就是驱动上报这样的事件:
EV_ABS ABS_MT_TRACKING_ID ffffffff
不信你看
case ABS_MT_TRACKING_ID:
if (mUsingSlotsProtocol && rawEvent->value < 0) {
// The slot is no longer in use but it retains its previous contents,
// which may be reused for subsequent touches.
//(翻译下上面的英文)这个slot不再inUse了,但是它保留它之前的(那些可以被随后的touches重新使用)内容
slot->mInUse = false;
} else {
slot->mInUse = true;
slot->mAbsMTTrackingId = rawEvent->value;
}
前面说到,给mCurrentRawPointerData赋值的主体主要是:
mMultiTouchMotionAccumulator.getSlot(inIndex);
而
inline const Slot* getSlot(size_t index) const { return &mSlots[index]; }
赋值的地方只有一个:
void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
if (rawEvent->type == EV_ABS) {
...
switch (rawEvent->code) {
case ABS_MT_POSITION_X:
slot->mInUse = true;
//这么取值
//inline int32_t getX() const { return mAbsMTPositionX; }
slot->mAbsMTPositionX = rawEvent->value;
break;
...
case ABS_MT_TRACKING_ID:
if (mUsingSlotsProtocol && rawEvent->value < 0) {
// The slot is no longer in use but it retains its previous contents,
// which may be reused for subsequent touches.
slot->mInUse = false;
} else {
slot->mInUse = true;
slot->mAbsMTTrackingId = rawEvent->value;
}
break;
...
}
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {
// MultiTouch Sync: The driver has returned all data for *one* of the pointers.
mCurrentSlot += 1;
}
}
MultiTouchMotionAccumulator::process
if (rawEvent->type == EV_ABS) {
bool newSlot = false;
//log来看,这个值为true
if (mUsingSlotsProtocol) {
if (rawEvent->code == ABS_MT_SLOT) {
//底层会上报多个值,一跟手指0,两根0,1...
mCurrentSlot = rawEvent->value;
newSlot = true;
}
} else if (mCurrentSlot < 0) {
mCurrentSlot = 0;
}
//开始解析rawEvent->code
Slot* slot = &mSlots[mCurrentSlot];
switch (rawEvent->code) {
...
case ABS_MT_POSITION_X:
slot->mInUse = true;
slot->mAbsMTPositionX = rawEvent->value;
break;
...
}
mUsingSlotsProtocol在这里就是B协议,详细情况可以参考这篇文章:
http://www.cnblogs.com/ljf181275034/articles/3343222.html
接着看看前面说到的加工点数据的cookPointerData
void TouchInputMapper::cookPointerData() {
uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount;
...
// Walk through the the active pointers and map device coordinates onto
// surface coordinates and adjust for display orientation.
for (uint32_t i = 0; i < currentPointerCount; i++) {
const RawPointerData::Pointer& in = mCurrentRawPointerData.pointers[i];
//接下来就是从in中去解析
//Size
//Pressure
//Tilt and Orientation
//Distance
//Coverage
//Adjust X, Y, and coverage coords for surface orientation.(根据surface orientation调整x,y坐标)
// Write output coords.
PointerCoords& out = mCurrentCookedPointerData.pointerCoords[i];
out.clear();
out.setAxisValue(AMOTION_EVENT_AXIS_X, x);
out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
...
// Write output properties.
// Write id index.
}
...
}
cookPointerData把mCurrentRawPointerData加工成了mCurrentCookedPointerData!
再之后就是dispatchTouches(when, policyFlags)
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits;
BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits;
...
if (currentIdBits == lastIdBits) {
//没有pointer id变化,所以,这是一个move事件
//注意是所有点(xxxxBits用bit位包含所有点的id)
...
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 {
//如果lastIdBits == currentIdBits,upIdBits就是0
//但是这个else是!=,所以这个结果就是把少掉的点(即已经up的点)找出来
BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
//同理,这个是多出来的点(down)
BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);
//
BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);
//根据不同的情况,分别做
//AMOTION_EVENT_ACTION_POINTER_UP
//AMOTION_EVENT_ACTION_MOVE
//AMOTION_EVENT_ACTION_POINTER_DOWN
...
dispatchMotion...
}
TouchInputMapper::dispatchMotion:
...
//0x5(DOWN)的ACTION经过这处理,变成0x105
//同理,0x6变成0x106
if (changedId >= 0 && id == uint32_t(changedId)) {
action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
...
NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
action, flags, metaState, buttonState, edgeFlags,
mViewport.displayId, pointerCount, pointerProperties, pointerCoords,xPrecision, yPrecision, downTime);
getListener()->notifyMotion(&args);
...
简单总结下整个过程:
1.eventhub上报:
(多点的时候)EV_ABS ABS_MT_SLOT 00000000
if (rawEvent->code == ABS_MT_SLOT) {
mCurrentSlot = rawEvent->value;//设置当前slot为0
newSlot = true;
}
EV_ABS ABS_MT_TRACKING_ID id
调用MultiTouchMotionAccumulator::process
mSlots[0]->mAbsMTTrackingId = id//给mSlots[mCurrentSlot]赋值
2.EV_ABS ABS_MT_POSITION_X x
调用MultiTouchMotionAccumulator::process
mSlots[0]->mAbsMTPositionX = x//给mSlot[mCurrentSlot]s赋值
3.EV_ABS ABS_MT_POSITION_Y y
调用MultiTouchMotionAccumulator::process
mSlots[0]->mAbsMTPositionY = y//给mSlots[mCurrentSlot]赋值
4.EV_SYN SYN_REPORT
TouchInputMapper::process
TouchInputMapper::sync
(1)MultiTouchInputMapper::syncTouch
对mCurrentRawPointerData.pointers[0]进行赋值.
(2)MultiTouchInputMapper::cookPointerData();
加工mCurrentRawPointerData.pointers[0]数据
(3)dispatchTouches
dispatchMotion
getListener()->notifyMotion(&args);
5.EV_ABS ABS_MT_TRACKING_ID ffffffff
调用MultiTouchMotionAccumulator::process
mSlots[0]->mAbsMTTrackingId = ffffffff(超出范围,所以是-1)
所以这里就
//打日志得到的
//mUsingSlotsProtocol = 1,rawEvent->value = -1
if (mUsingSlotsProtocol && rawEvent->value < 0) {
slot->mInUse = false;
}
进而isInUse函数就会返回false啦!
6.EV_SYN SYN_REPORT 00000000
TouchInputMapper::process
TouchInputMapper::sync
(1)MultiTouchInputMapper::syncTouch
走入
if (!inSlot->isInUse()) {
continue;
}
(2)cookPointerData这里什么都没干
(3)dispatchTouches
dispatchMotion
getListener()->notifyMotion(&args);
InputDispatcher分析
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
...
needWake = enqueueInboundEventLocked(newEntry);//是否需要唤醒
...
if (needWake) {
//
mLooper->wake();//如果需要唤醒,唤醒之,具体一会儿说
}
...
}
我们先看看needWake的判定
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
...
//mInboundQueue(入站队列)为空的时候,需要唤醒
bool needWake = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(entry);
...
switch (entry->type) {
case EventEntry::TYPE_KEY: {
//notifyKey走这一支
}
...
case EventEntry::TYPE_MOTION: {
...
sp touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y);
if (touchedWindowHandle != NULL
&& touchedWindowHandle->inputApplicationHandle
!= mInputTargetWaitApplicationHandle) {
// User touched a different application than the one we are waiting on.
// Flag the event, and start pruning the input queue.
mNextUnblockedEvent = motionEntry;
needWake = true;
}
...
}
...
}
简单总结下就是,之前在休眠,mInboundQueue为空的时候需要唤醒.用户触摸另一个application时候需要唤醒.
那前面说到,需要唤醒的时候,会调用mLooper->wake()
这之后的过程,连猜带Google,得出的结论就是会执行
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
void InputDispatcher::dispatchOnce() {
...
// Run a dispatch loop if there are no pending commands.
// The dispatch loop might enqueue commands to run afterwards.
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
...
//总之参数就是一个很大很大的超时时间
mLooper->pollOnce(timeoutMillis);
}
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
...
case EventEntry::TYPE_MOTION: {
done = dispatchMotionLocked(currentTime, typedEntry,
&dropReason, nextWakeupTime);
}
...
}
bool InputDispatcher::dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
...
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
// Identify targets.
Vector inputTargets;
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
//找到目标窗口
//这个方法很复杂,先这样吧
injectionResult = findTouchedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
}
...
//分发MotionEvent啦!
dispatchEventLocked(currentTime, entry, inputTargets);
}
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector& inputTargets) {
...
//戳用户Activity?暂时不知道是干嘛的
pokeUserActivityLocked(eventEntry);
//
for (size_t i = 0; i < inputTargets.size(); i++) {
const InputTarget& inputTarget = inputTargets.itemAt(i);
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
//mConnectionsByFd在InputDispatcher::registerInputChannel中被关联
//mConnectionsByFd.add(fd, connection);
sp connection = mConnectionsByFd.valueAt(connectionIndex);
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
}
}
...
}
InputDispatcher::registerInputChannel关联connection和fd的事情以后再谈,我们先继续看
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
...
// Not splitting. Enqueue dispatch entries for the event as is.
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
//这时候已经变成outbound了
bool wasEmpty = connection->outboundQueue.isEmpty();
// Enqueue dispatch entries for the requested modes.
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
...
// If the outbound queue was previously empty, start the dispatch cycle going.
//之前空,后来不空
if (wasEmpty && !connection->outboundQueue.isEmpty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
void InputDispatcher::enqueueDispatchEntryLocked(
const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
int32_t dispatchMode) {
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
//构造一个dispatchEntry
DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
inputTarget->scaleFactor);
...
case EventEntry::TYPE_MOTION: {
//对dispatchEntry做一些处理
}
...
//将dispatchEntry加到outboundQueue的队尾
connection->outboundQueue.enqueueAtTail(dispatchEntry);
}
enqueueDispatchEntriesLocked中,connection->outboundQueue不为空的时候就会调用
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp& connection) {
while (connection->status == Connection::STATUS_NORMAL
&& !connection->outboundQueue.isEmpty()) {
...
case EventEntry::TYPE_KEY:
status = connection->inputPublisher.publishKeyEvent(...
...
// Publish the motion event.
case EventEntry::TYPE_MOTION:
status = connection->inputPublisher.publishMotionEvent(
...
//出站dispatchEntry
connection->outboundQueue.dequeue(dispatchEntry);
...
//将dispatchEntry加入connection->waitQueue
connection->waitQueue.enqueueAtTail(dispatchEntry);
...
}
}
publishKeyEvent和publishMotionEvent就进入InputChannel
(位于frameworks/native/libs/input/InputTransport.cpp)里啦!
InputDispathcher的部分就分析完了!
java层其他
1.View implements
KeyEvent.Callback
onKeyDown
onKeyLongPress
onKeyUp
等接口
KeyEvent extends InputEvent
按键输入是所有输入的一个子集!可以理解
2.MotionEvent
(dispatchTouchEvent的参数)
touch事件的细节
MotionEvent KeyEvent extends InputEvent
基本都调用的native方法
3.调用堆栈
java层:
jni调用上来的?:
ViewRootImpl.java:WindowInputEventReceiver:
onInputEvent
ViewRootImpl.java:enqueueInputEvent
ViewRootImpl.java:processPointerEvent
->View.java:dispatchPointerEvent
->View.java:dispathTouchEvent
->listenerInfo.mOnTouchListener.onTouch
InputEventReceiver.java中
像dispatchInputEvent()这种函数是Called from native code的
每一次触控,会被native层调用,然后往上传递事件,比如一次点击事件的down,move,up事件。我简直觉得这里是最重要的关口之一!
回调点:
android_view_InputEventReceiver.cpp:
NativeInputEventReceiver::consumeEvents
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);