Android 5.0输入系统分析之InputDispatcher线程分析
来源:互联网 发布:mac see sheer真人试色 编辑:程序博客网 时间:2024/05/29 15:07
上编分析知道是InputReader线程唤醒了InputDispatcher线程分析,InputDispatcher线程是从dispatchOnce启动,从dispatchOnce函数进行分析。
void InputDispatcher::dispatchOnce() { if (!haveCommandsLocked()) { dispatchOnceInnerLocked(&nextWakeupTime); } if (runCommandsLockedInterruptible()) { nextWakeupTime = LONG_LONG_MIN; } mLooper->pollOnce(timeoutMillis);}
调用了haveCommandsLocked,就是调用了InputDispatcher.cpp中的haveCommandsLocked函数:
bool InputDispatcher::haveCommandsLocked() const { return !mCommandQueue.isEmpty();}
检查mCommandQueue队例是否有数据,刚进来的时候mCommandQueue队例是空的,所以接着调用dispatchOnceInnerLocked函数,也就是调用了InputDispatcher.cpp中的dispatchOnceInnerLocked函数
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {if (! mPendingEvent) { mPendingEvent = mInboundQueue.dequeueAtHead(); } switch (mPendingEvent->type) { case EventEntry::TYPE_KEY: { KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent); done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; } if (done) { if (dropReason != DROP_REASON_NOT_DROPPED) { dropInboundEventLocked(mPendingEvent, dropReason); }}
haveCommandsLocked函数就是从mInboundQueue队例中取出数据,然后调用了dispatchKeyLocked进行了分发,分发成功后调用了dropInboundEventLocked清空mPendingEvent等操作。具体是如何分发的,对它详细分析.调用了InputDispatcher.cpp中的dispatchKeyLocked
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { ...... if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); if (mFocusedWindowHandle != NULL) { commandEntry->inputWindowHandle = mFocusedWindowHandle; } commandEntry->keyEntry = entry; entry->refCount += 1; return false; } ......}
刚进来entry->interceptKeyResult = INTERCEPT_KEY_RESULT_UNKNOWN,所以会走这个分支,调用postCommandLocked函数把命令加入到队例中,然后返回false,即是done = false。再看postCommandLocked函数
InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) { CommandEntry* commandEntry = new CommandEntry(command); mCommandQueue.enqueueAtTail(commandEntry); return commandEntry;}
把命令加入mCommandQueue队例头,传入的参数据就是InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible函数,后面会用到。
返回到dispatchOnceInnerLocked调用了InputDispatcher.cpp中的runCommandsLockedInterruptible函数:
bool InputDispatcher::runCommandsLockedInterruptible() { if (mCommandQueue.isEmpty()) { return false; } do { CommandEntry* commandEntry = mCommandQueue.dequeueAtHead(); Command command = commandEntry->command; (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible' commandEntry->connection.clear(); delete commandEntry; } while (! mCommandQueue.isEmpty()); return true;}
从mCommandQueue取出数据,然后执行它,就是上面加入队例的InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible。那么就是调用了InputDispatcher.cpp中的doInterceptKeyBeforeDispatchingLockedInterruptible函数
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( CommandEntry* commandEntry) { KeyEntry* entry = commandEntry->keyEntry; KeyEvent event; initializeKeyEvent(&event, entry); mLock.unlock(); nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle, &event, entry->policyFlags); mLock.lock(); if (delay < 0) { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP; } else if (!delay) { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; } else { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER; entry->interceptKeyWakeupTime = now() + delay; } entry->release();}
调用了mPolicy->interceptKeyBeforeDispatching函数,mPolicy是什么东东?前面《Android 5.0输入系统分析之InputReader线程分析》可知是调用了com_android_server_input_InputManagerService.cpp中
interceptKeyBeforeDispatching
nsecs_t NativeInputManager::interceptKeyBeforeDispatching( const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags) { jlong delayMillis = env->CallLongMethod(mServiceObj, gServiceClassInfo.interceptKeyBeforeDispatching, inputWindowHandleObj, keyEventObj, policyFlags); return result;}
调用了PhoneWindowManager.java中interceptKeyBeforeDispatching函数
public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) { final boolean keyguardOn = keyguardOn(); final int keyCode = event.getKeyCode(); final int repeatCount = event.getRepeatCount(); final int metaState = event.getMetaState(); final int flags = event.getFlags(); final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; final boolean canceled = event.isCanceled(); if (DEBUG_INPUT) { Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount=" + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed + " canceled=" + canceled); } // If we think we might have a volume down & power key chord on the way // but we're not sure, then tell the dispatcher to wait a little while and // try again later before dispatching. if (mScreenshotChordEnabled && (flags & KeyEvent.FLAG_FALLBACK) == 0) { if (mScreenshotChordVolumeDownKeyTriggered && !mScreenshotChordPowerKeyTriggered) { final long now = SystemClock.uptimeMillis(); final long timeoutTime = mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS; if (now < timeoutTime) { return timeoutTime - now; } } if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mScreenshotChordVolumeDownKeyConsumed) { if (!down) { mScreenshotChordVolumeDownKeyConsumed = false; } return -1; } } // Cancel any pending meta actions if we see any other keys being pressed between the down // of the meta key and its corresponding up. if (mPendingMetaAction && !KeyEvent.isMetaKey(keyCode)) { mPendingMetaAction = false; } // First we always handle the home key here, so applications // can never break it, although if keyguard is on, we do let // it handle it, because that gives us the correct 5 second // timeout. if (keyCode == KeyEvent.KEYCODE_HOME) { // If we have released the home key, and didn't do anything else // while it was pressed, then it is time to go home! if (!down) { cancelPreloadRecentApps(); mHomePressed = false; if (mHomeConsumed) { mHomeConsumed = false; return -1; } if (canceled) { Log.i(TAG, "Ignoring HOME; event canceled."); return -1; } // If an incoming call is ringing, HOME is totally disabled. // (The user is already on the InCallUI at this point, // and his ONLY options are to answer or reject the call.) TelecomManager telecomManager = getTelecommService(); if (telecomManager != null && telecomManager.isRinging()) { Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); return -1; } // Delay handling home if a double-tap is possible. if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) { mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case mHomeDoubleTapPending = true; mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable, ViewConfiguration.getDoubleTapTimeout()); return -1; } handleShortPressOnHome(); return -1; } // If a system window has focus, then it doesn't make sense // right now to interact with applications. WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null; if (attrs != null) { final int type = attrs.type; if (type == WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { // the "app" is keyguard, so give it the key return 0; } final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length; for (int i=0; i<typeCount; i++) { if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) { // don't do anything, but also don't pass it to the app return -1; } } } // Remember that home is pressed and handle special actions. if (repeatCount == 0) { mHomePressed = true; if (mHomeDoubleTapPending) { mHomeDoubleTapPending = false; mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); handleDoubleTapOnHome(); } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI || mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) { preloadRecentApps(); } } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) { if (!keyguardOn) { handleLongPressOnHome(); } } return -1; } else if (keyCode == KeyEvent.KEYCODE_MENU) { // Hijack modified menu keys for debugging features final int chordBug = KeyEvent.META_SHIFT_ON; if (down && repeatCount == 0) { if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) { Intent intent = new Intent(Intent.ACTION_BUG_REPORT); mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, null, null, 0, null, null); return -1; } else if (SHOW_PROCESSES_ON_ALT_MENU && (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) { Intent service = new Intent(); service.setClassName(mContext, "com.android.server.LoadAverageService"); ContentResolver res = mContext.getContentResolver(); boolean shown = Settings.Global.getInt( res, Settings.Global.SHOW_PROCESSES, 0) != 0; if (!shown) { mContext.startService(service); } else { mContext.stopService(service); } Settings.Global.putInt( res, Settings.Global.SHOW_PROCESSES, shown ? 0 : 1); return -1; } } } else if (keyCode == KeyEvent.KEYCODE_SEARCH) { if (down) { if (repeatCount == 0) { mSearchKeyShortcutPending = true; mConsumeSearchKeyUp = false; } } else { mSearchKeyShortcutPending = false; if (mConsumeSearchKeyUp) { mConsumeSearchKeyUp = false; return -1; } } return 0; } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) { if (!keyguardOn) { if (down && repeatCount == 0) { preloadRecentApps(); } else if (!down) { toggleRecentApps(); } } return -1; } else if (keyCode == KeyEvent.KEYCODE_ASSIST) { if (down) { if (repeatCount == 0) { mAssistKeyLongPressed = false; } else if (repeatCount == 1) { mAssistKeyLongPressed = true; if (!keyguardOn) { launchAssistLongPressAction(); } } } else { if (mAssistKeyLongPressed) { mAssistKeyLongPressed = false; } else { if (!keyguardOn) { launchAssistAction(); } } } return -1; } else if (keyCode == KeyEvent.KEYCODE_VOICE_ASSIST) { if (!down) { Intent voiceIntent; if (!keyguardOn) { voiceIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH); } else { voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE); voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, true); } startActivityAsUser(voiceIntent, UserHandle.CURRENT_OR_SELF); } } else if (keyCode == KeyEvent.KEYCODE_SYSRQ) { if (down && repeatCount == 0) { mHandler.post(mScreenshotRunnable); } return -1; } else if (keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP || keyCode == KeyEvent.KEYCODE_BRIGHTNESS_DOWN) { if (down) { int direction = keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP ? 1 : -1; // Disable autobrightness if it's on int auto = Settings.System.getIntForUser( mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT_OR_SELF); if (auto != 0) { Settings.System.putIntForUser(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT_OR_SELF); } int min = mPowerManager.getMinimumScreenBrightnessSetting(); int max = mPowerManager.getMaximumScreenBrightnessSetting(); int step = (max - min + BRIGHTNESS_STEPS - 1) / BRIGHTNESS_STEPS * direction; int brightness = Settings.System.getIntForUser(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, mPowerManager.getDefaultScreenBrightnessSetting(), UserHandle.USER_CURRENT_OR_SELF); brightness += step; // Make sure we don't go beyond the limits. brightness = Math.min(max, brightness); brightness = Math.max(min, brightness); Settings.System.putIntForUser(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, brightness, UserHandle.USER_CURRENT_OR_SELF); startActivityAsUser(new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG), UserHandle.CURRENT_OR_SELF); } return -1; } else if (KeyEvent.isMetaKey(keyCode)) { if (down) { mPendingMetaAction = true; } else if (mPendingMetaAction) { launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD); } return -1; } // Shortcuts are invoked through Search+key, so intercept those here // Any printing key that is chorded with Search should be consumed // even if no shortcut was invoked. This prevents text from being // inadvertently inserted when using a keyboard that has built-in macro // shortcut keys (that emit Search+x) and some of them are not registered. if (mSearchKeyShortcutPending) { final KeyCharacterMap kcm = event.getKeyCharacterMap(); if (kcm.isPrintingKey(keyCode)) { mConsumeSearchKeyUp = true; mSearchKeyShortcutPending = false; if (down && repeatCount == 0 && !keyguardOn) { Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, metaState); if (shortcutIntent != null) { shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivityAsUser(shortcutIntent, UserHandle.CURRENT); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping shortcut key combination because " + "the activity to which it is registered was not found: " + "SEARCH+" + KeyEvent.keyCodeToString(keyCode), ex); } } else { Slog.i(TAG, "Dropping unregistered shortcut key combination: " + "SEARCH+" + KeyEvent.keyCodeToString(keyCode)); } } return -1; } } // Invoke shortcuts using Meta. if (down && repeatCount == 0 && !keyguardOn && (metaState & KeyEvent.META_META_ON) != 0) { final KeyCharacterMap kcm = event.getKeyCharacterMap(); if (kcm.isPrintingKey(keyCode)) { Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, metaState & ~(KeyEvent.META_META_ON | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON)); if (shortcutIntent != null) { shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivityAsUser(shortcutIntent, UserHandle.CURRENT); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping shortcut key combination because " + "the activity to which it is registered was not found: " + "META+" + KeyEvent.keyCodeToString(keyCode), ex); } return -1; } } } // Handle application launch keys. if (down && repeatCount == 0 && !keyguardOn) { String category = sApplicationLaunchKeyCategories.get(keyCode); if (category != null) { Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivityAsUser(intent, UserHandle.CURRENT); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping application launch key because " + "the activity to which it is registered was not found: " + "keyCode=" + keyCode + ", category=" + category, ex); } return -1; } } // Display task switcher for ALT-TAB. if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) { if (mRecentAppsHeldModifiers == 0 && !keyguardOn) { final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK; if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)) { mRecentAppsHeldModifiers = shiftlessModifiers; showRecentApps(true); return -1; } } } else if (!down && mRecentAppsHeldModifiers != 0 && (metaState & mRecentAppsHeldModifiers) == 0) { mRecentAppsHeldModifiers = 0; hideRecentApps(true, false); } // Handle keyboard language switching. if (down && repeatCount == 0 && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH || (keyCode == KeyEvent.KEYCODE_SPACE && (metaState & KeyEvent.META_CTRL_MASK) != 0))) { int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1; mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction); return -1; } if (mLanguageSwitchKeyPressed && !down && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH || keyCode == KeyEvent.KEYCODE_SPACE)) { mLanguageSwitchKeyPressed = false; return -1; } if (isValidGlobalKey(keyCode) && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {//GlobalKey广播 return -1; } // Reserve all the META modifier combos for system behavior if ((metaState & KeyEvent.META_META_ON) != 0) { return -1; } // Let the application handle the key. return 0; }
此函数是对于系统按键处理(比如:KEYCODE_MENU)和GlobalKey处理,都是返回-1.其它返回0.
if (delay < 0) { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP; } else if (!delay) { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; } else { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER; entry->interceptKeyWakeupTime = now() + delay; }
检查按键是还INTERCEPT_KEY_RESULT_SKIP还是INTERCEPT_KEY_RESULT_CONTINUE。上面分析知道对于系统按键(比如:KEYCODE_MENU)和GlobalKey都是INTERCEPT_KEY_RESULT_SKIP,直接处理的,其它会传给APP处理。InputDispatcher::runCommandsLockedInterruptible()处理完后,返回结果是true,那么 nextWakeupTime = LONG_LONG_MIN;也就是mLooper->pollOnce(timeoutMillis);不会等待数据 ,直接执行InputDispatcher::dispatchOnce() 。这里又从新开始分析InputDispatcher::dispatchOnce()函数
void InputDispatcher::dispatchOnce() { nsecs_t nextWakeupTime = LONG_LONG_MAX; { if (!haveCommandsLocked()) { dispatchOnceInnerLocked(&nextWakeupTime); } if (runCommandsLockedInterruptible()) { nextWakeupTime = LONG_LONG_MIN; } mLooper->pollOnce(timeoutMillis);}
调用了haveCommandsLocked检看是否有命令,由于执行了命令,haveCommandsLocked是空的,所以会再次调用dispatchOnceInnerLocked,调用过程也是一样的,不同的点是InputDispatcher::dispatchKeyLocked中的
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { Vector<InputTarget> inputTargets; int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { return false; } setInjectionResultLocked(entry, injectionResult); if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { return true; } addMonitoringTargetsLocked(inputTargets); dispatchEventLocked(currentTime, entry, inputTargets); return true;}这一次就是搜索焦点窗口,找到后调用InputDispatcher.cpp中的dispatchEventLocked进行数据分发。void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) { for (size_t i = 0; i < inputTargets.size(); i++) { const InputTarget& inputTarget = inputTargets.itemAt(i); ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); if (connectionIndex >= 0) { sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); } }
从目标窗口中找到connection ,然后调用InputDispatcher.cpp中的prepareDispatchCycleLocked把数据分发。
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { bool wasEmpty = connection->outboundQueue.isEmpty(); // Enqueue dispatch entries for the requested modes. enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_OUTSIDE); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_IS); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); // If the outbound queue was previously empty, start the dispatch cycle going. if (wasEmpty && !connection->outboundQueue.isEmpty()) { startDispatchCycleLocked(currentTime, connection); }}
最后调用了InputDispatcher.cpp中的startDispatchCycleLocked把数据分发。
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection) { while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.isEmpty()) { DispatchEntry* dispatchEntry = connection->outboundQueue.head; dispatchEntry->deliveryTime = currentTime; // Publish the event. status_t status; EventEntry* eventEntry = dispatchEntry->eventEntry; switch (eventEntry->type) { case EventEntry::TYPE_KEY: { KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); // Publish the key event. status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId, keyEntry->source, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, keyEntry->keyCode, keyEntry->scanCode, keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime, keyEntry->eventTime); break; } }}
比如按键类,调用了connection->inputPublisher.publishKeyEvent函数
status_t InputPublisher::publishKeyEvent( uint32_t seq, int32_t deviceId, int32_t source, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime) { if (!seq) { ALOGE("Attempted to publish a key event with sequence number 0."); return BAD_VALUE; } InputMessage msg; msg.header.type = InputMessage::TYPE_KEY; msg.body.key.seq = seq; msg.body.key.deviceId = deviceId; msg.body.key.source = source; msg.body.key.action = action; msg.body.key.flags = flags; msg.body.key.keyCode = keyCode; msg.body.key.scanCode = scanCode; msg.body.key.metaState = metaState; msg.body.key.repeatCount = repeatCount; msg.body.key.downTime = downTime; msg.body.key.eventTime = eventTime; return mChannel->sendMessage(&msg);}
然后调用mChannel->sendMessage(&msg);把数据发送给APP。
- Android 5.0输入系统分析之InputDispatcher线程分析
- Android 5.0输入系统分析之InputReader和InputDispatcher线程启动过程
- Android 5.0输入系统分析之InputReader线程分析
- Android输入子系统之InputDispatcher分发键盘消息过程分析
- Android输入事件InputReader和InputDispatcher分析
- Android 输入系统之InputDispatcher篇
- ANR源码分析之InputDispatcher Timeout
- Android Input流程分析(四):InputDispatcher
- 输入事件from InputDispatcher to ViewRootImpl 的分析
- Android系统分析之JobScheduler源码分析
- Android系统分析之JobScheduler源码分析
- Android 输入系统分析
- Android 输入系统分析
- Android GWES 输入系统分析
- Android 输入系统分析
- Linux系统分析之线程
- Android4.4——InputManagerService之InputDispatcher线程
- Android入门之把窗口信息传递给InputDispatcher
- HDU-6178 Monkeys
- glOrtho,gluOrtho2D,glFrustum,glViewport解析
- SpringMVC拦截器(Interceptor)
- 解决jk安装时出现的问题:autoconf not found.You need autoconf version 2.59 or newer installed
- hdu 1210 洗牌
- Android 5.0输入系统分析之InputDispatcher线程分析
- C/C++基础及高频率面试知识总结
- cookie
- SSH框架总结分析
- SmartRefreshLayout+CommonAdapter打造上拉加载下拉刷新界面
- 关于在mysql 中新建用户
- Struts2入门实例-Helloworld
- SpringInAction学习笔记——第15章 使用远程服务
- CodeForces 106C Buns (多重背包)