Android InputFlinger简单分析(主要分析Touch)
来源:互联网 发布:网络女歌手歌曲大全 编辑:程序博客网 时间:2024/06/02 05:19
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> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);... NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,messageQueue->getLooper()); im->incStrong(0); return reinterpret_cast<jlong>(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<NativeInputManager*>(ptr);status_t result = im->getInputManager()->start();...}
即用nativeInit中new的NativeInputManager对象调用start函数。
那NativeInputManager是什么呢?
inline sp<InputManager> 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<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { mDispatcher = new InputDispatcher(dispatcherPolicy); //注意第三个参数 mReader = new InputReader(eventHub, readerPolicy, mDispatcher); initialize();}
InputReader的构造函数:
InputReader::InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, //这个 const sp<InputListenerInterface>& 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: 69V/EventHub( 1691): Opening device: /dev/input/event7V/EventHub( 1691): Created descriptor: raw=:0000:0000:name:Atmel maXTouch Touchscreen, cooked=37118057a971f33d58dfff27cf9e19bbe8914acaV/EventHub( 1691): add device 7: /dev/input/event7V/EventHub( 1691): bus: 0018V/EventHub( 1691): vendor 0000V/EventHub( 1691): product 0000V/EventHub( 1691): version 0000V/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.1D/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=trueV/EventHub( 1691): Reporting device opened: id=7, name=/dev/input/event7V/InputReader( 1691): ZDQ after mEventHub->getEvents//DEVICE_ADDED = 0x10000000//这次调用来自mEventHub->getEventsV/InputReader( 1691): ZDQ InputReader::processEventsLocked type = 10000000//mode 1:DEVICE_MODE_DIRECTI/InputReader( 1691): Device reconfigured: id=7, name='Atmel maXTouch Touchscreen', size 1920x720, orientation 0, mode 1, display id 0I/InputReader( 1691): Device added: id=7, name='Atmel maXTouch Touchscreen', sources=0x00005002//FINISHED_DEVICE_SCAN = 0x30000000V/InputReader( 1691): ZDQ InputReader::processEventsLocked type = 30000000
然后,我们来看看一次单点touch事件的log做个预热
getevent -lr /dev/input/event7EV_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 0EV_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 = ffffffffSYN_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 InputMapperclass SingleTouchInputMapper : public TouchInputMapperclass 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->codeSlot* 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变成0x106if (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 = -1if (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<InputWindowHandle> 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<InputTarget> 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<InputTarget>& 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> connection = mConnectionsByFd.valueAt(connectionIndex); prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); } } ...}
InputDispatcher::registerInputChannel关联connection和fd的事情以后再谈,我们先继续看
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& 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>& 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>& 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>& 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
onKeyDownonKeyLongPressonKeyUp等接口
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);
- Android InputFlinger简单分析(主要分析Touch)
- Android touch事件分析
- Android的Touch事件分发机制简单分析
- Android Keyboard/Touch Panel分析
- Android Keyboard/Touch Panel分析
- Android On Touch 事件分析
- android中 Touch事件分析
- android 功耗分析主要步骤
- 简单分析一下uboot的主要数据结构
- 关于android touch事件源代码分析
- 分析Android的Touch事件分发机制
- 【android】点击touch事件流程分析
- Android touch mode和focusableInTouchMode分析
- Android touch mode和focusableInTouchMode分析
- Android touch mode和focusableInTouchMode分析
- Android touch mode和focusableInTouchMode分析
- 从android源码角度分析touch机制
- Android Touch事件传递原理分析
- tf.assign()
- 【设计模式】状态模式
- 串的模式匹配-KMP详解
- spi flash驱动
- ios打包ipa文件并上传到托管平台
- Android InputFlinger简单分析(主要分析Touch)
- React Native 集成 Redux
- 详解C结构体、C++结构体 和 C++类的区别
- 常碰到的问题
- C++泛型编程(模板)
- 私服的搭建
- java
- [蓝桥杯]算法训练 Anagrams问题
- 机器学习怎么学