美文网首页
Android Framework——Input事件分发

Android Framework——Input事件分发

作者: Peakmain | 来源:发表于2021-06-08 11:59 被阅读0次

input事件分发的过程

我们都知道事件一般会传递到 activity 根布局 view 的 dispatchTouchEvent 方法,那么事件的源头在哪里?

IMS的启动过程

SystemServer.java的main方法

    public static void main(String[] args) {
        new SystemServer().run();
    }
    private void run() {
        try {
             //启动引导服务
            startBootstrapServices();
           //启动核心服务
            startCoreServices();
            //启动其他服务
            startOtherServices();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        }

        // For debug builds, log event loop stalls to dropbox for analysis.
        if (StrictMode.conditionallyEnableDebugLogging()) {
            Slog.i(TAG, "Enabled StrictMode for system server main thread.");
        }

        // Loop forever.
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
  • startBootstrapServices主要启动ActivityManagerService、PowerManagerServer、PackageManagerServer
  • startCoreServices启动BatteryService、UsageStatsService和WebViewUpdateService
  • startOtherServices启动CameraService(摄像头相关服务)、AlarmManagerService(定时器管理服务)、InputManagerService(管理输入事件)、WindowManagerService(窗口管理服务)、LocationManagerService(定位管理服务)

startOtherServices源码分析

 private void startOtherServices() {
              //创建IMS
            inputManager = new InputManagerService(context);

            Slog.i(TAG, "Window Manager");
             //WMS的main方法,第二个参数就是IMS
            wm = WindowManagerService.main(context, inputManager,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore);
            ServiceManager.addService(Context.WINDOW_SERVICE, wm);
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager);

            mActivityManagerService.setWindowManager(wm);

            inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
            inputManager.start();
}
InputManagerService的构造函数
    public InputManagerService(Context context) {
        this.mContext = context;
            //创建一个InputManagerHandler
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());

        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                + mUseDevInputEventForAudioJack);
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
        LocalServices.addService(InputManagerInternal.class, new LocalService());
    }
 

com_android_server_input_InputManagerService.cpp的nativeInit方法

static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
      //创建一个NativeInputManager
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}
NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();;
     //创建EventHub并传给InputManager
    sp<EventHub> eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}
namespace android {
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();
}

void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
  • EventHub通过Linux内核的INotify与Epoll机制监听设备节点
  • 通过EventHub的getEvent函数读取设备节点的增删事件和原始输入事件
image.png
InputManagerService.start源码分析
    public void start() {
        nativeStart(mPtr);
        // Add ourself to the Watchdog monitors.
        Watchdog.getInstance().addMonitor(this);
    }

watchDog用于定时检测系统关键服务(AMS和WMS)是否可能产生死锁

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
      //获取NativeInputManager
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
       // im->getInputManager()实际是InputManager
    status_t result = im->getInputManager()->start();
}
status_t InputManager::start() {
    //运行InputDispatchThread
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    //运行InputReaderThread
    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
    return OK;
}

1、InputDispatchThread的启动过程分析
InputDispatch.cpp

bool InputDispatcherThread::threadLoop() {
    mDispatcher->dispatchOnce();
    return true;
}
void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // acquire lock
        AutoMutex _l(mLock);
        mDispatcherIsAliveCondition.broadcast();
        //检测是否有等待的命令
        if (!haveCommandsLocked()) {
             //没有等待的命令,将输入事件分发给合适的window
            dispatchOnceInnerLocked(&nextWakeupTime);
        }

        if (runCommandsLockedInterruptible()) {
            nextWakeupTime = LONG_LONG_MIN;
        }
    } // release lock
      //获取当前时间
    nsecs_t currentTime = now();
        //获取睡眠的时间
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
         //InputDispatchThread进入睡眠状态
    mLooper->pollOnce(timeoutMillis);
}
  • InputReader则会唤起InputDispatchThread

dispatchOnceInnerLocked函数处理进行事件分发

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    nsecs_t currentTime = now();
     //1、判断是否被冻结,如果被冻结,则直接return
    if (mDispatchFrozen) {
#if DEBUG_FOCUS
        ALOGD("Dispatch frozen.  Waiting some more.");
#endif
        return;
    }
   //2、isAppSwitchDue为true则说明没有及时响应Home键等操作
    bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
    if (mAppSwitchDueTime < *nextWakeupTime) {
        *nextWakeupTime = mAppSwitchDueTime;
    }

    // 3、如果还没有待分发的时间,去mInboundQueue中取出一个事件
    if (! mPendingEvent) {
        //如果mInboundQueue为空,并且没有待分发的事件,就return
        if (mInboundQueue.isEmpty()) {
            if (!mPendingEvent) {
                return;
            }
        } else {
           //如果不为空,则取出队头的EventEntry赋值给mPendingEvent
            mPendingEvent = mInboundQueue.dequeueAtHead();
            traceInboundQueueLengthLocked();
        }

        // Poke user activity for this event.
        if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
            pokeUserActivityLocked(mPendingEvent);
        }

        // Get ready to dispatch the event.
        resetANRTimeoutsLocked();
    }
  //事件丢弃的原因
     DropReason dropReason = DROP_REASON_NOT_DROPPED;
    //4、根据不同的type做分区处理
    switch (mPendingEvent->type) {
    case EventEntry::TYPE_MOTION: {
        MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
           //如果没有及时响应窗口切换操作
        if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
            dropReason = DROP_REASON_APP_SWITCH;
        } 
       //事件过期
        if (dropReason == DROP_REASON_NOT_DROPPED
                && isStaleEventLocked(currentTime, typedEntry)) {
            dropReason = DROP_REASON_STALE;
        }
        //阻碍其他窗口获取事件
        if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
            dropReason = DROP_REASON_BLOCKED;
        }
  //5、这个事件寻找合适的窗口
        done = dispatchMotionLocked(currentTime, typedEntry,
                &dropReason, nextWakeupTime);
        break;
    }
 
    default:
        ALOG_ASSERT(false);
        break;
    }

    if (done) {
        if (dropReason != DROP_REASON_NOT_DROPPED) {
            dropInboundEventLocked(mPendingEvent, dropReason);
        }
        mLastDropReason = dropReason;
         //释放本次事件处理的对象
        releasePendingEventLocked();
            //让InputDispatcher快速处理下一个请求
        *nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
    }
}

dispatchMotionLocked分发到窗口

bool InputDispatcher::dispatchMotionLocked(
        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
    if (! entry->dispatchInProgress) {
           //当前进入分发的过程
        entry->dispatchInProgress = true;
        logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
    }

    //如果事件需要丢弃,则返回true
    if (*dropReason != DROP_REASON_NOT_DROPPED) {
      ....
        return true;
    }
 
    bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;

    //目标窗口列表存储在inputTargets
    Vector<InputTarget> inputTargets;

    bool conflictingPointerActions = false;
    int32_t injectionResult;
    if (isPointerEvent) {
      //处理点击形式的事件,比如触摸屏幕
        injectionResult = findTouchedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
    } else {
     //处理非触摸形式的事件,比如轨迹球
        injectionResult = findFocusedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime);
    }
        //输入事件被挂起,说明找到了窗口并且窗口无响应
    if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
        return false;
    }

    setInjectionResultLocked(entry, injectionResult);
    //输入事件分发成功,说明没有找到合适窗口
    if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
        if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
            CancelationOptions::Mode mode(isPointerEvent ?
                    CancelationOptions::CANCEL_POINTER_EVENTS :
                    CancelationOptions::CANCEL_NON_POINTER_EVENTS);
            CancelationOptions options(mode, "input event injection failed");
            synthesizeCancelationEventsForMonitorsLocked(options);
        }
        return true;
    }

    // TODO: support sending secondary display events to input monitors
    if (isMainDisplay(entry->displayId)) {
   //分发目标添加到inputTargets列表中
        addMonitoringTargetsLocked(inputTargets);
    }

    // Dispatch the motion.
    if (conflictingPointerActions) {
        CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
                "conflicting pointer actions");
        synthesizeCancelationEventsForAllConnectionsLocked(options);
    }
     //将事件分发给inputTargets列表中的目标
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}

findTouchedWindowTargetsLocked点击

 int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
        const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
        bool* outConflictingPointerActions) {

    if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
        // 遍历所有的 mWindowHandles
        size_t numWindows = mWindowHandles.size();
        for (size_t i = 0; i < numWindows; i++) {
            sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
            const InputWindowInfo* windowInfo = windowHandle->getInfo();
            if (windowInfo->displayId != displayId) {
                  //如果displayId不匹配,开始下一次循环
                continue; // wrong display
            }
            int32_t flags = windowInfo->layoutParamsFlags;
            if (windowInfo->visible) {
                // 可见,并且 flags 属性不是 InputWindowInfo::FLAG_NOT_TOUCHABLE
                if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
                    isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
                            | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
                    // 点击的是不是当前 window 的覆盖
                    if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
                        // found touched window, exit window loop
                        // 找到了当前触摸的 window 
                        newTouchedWindowHandle = windowHandle;
                        break;
                    }
                }
            }
        } 
        
        mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
    } else {
       ...
    }
    // 再把 mTempTouchState 收集到的 windows 添加到 inputTargets 中
    for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
        const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
        addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
                touchedWindow.pointerIds, inputTargets);
    }
    ...
    return injectionResult;
  }

dispatchEventLocked源码分析

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
#if DEBUG_DISPATCH_CYCLE
    ALOGD("dispatchEventToCurrentInputTargets");
#endif

    ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true

    pokeUserActivityLocked(eventEntry);

    for (size_t i = 0; i < inputTargets.size(); i++) {
        const InputTarget& inputTarget = inputTargets.itemAt(i);
         //遍历inputTargets列表
        ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
        if (connectionIndex >= 0) {
           //获取保存在mConnectionsByFd容器中的Connection
            sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
        } else {
#if DEBUG_FOCUS
            ALOGD("Dropping event delivery to target with channel '%s' because it "
                    "is no longer registered with the input dispatcher.",
                    inputTarget.inputChannel->getName().string());
#endif
        }
    }
}

2、InputReaderThread的启动过程
InputReader.cpp

bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}
void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    Vector<InputDeviceInfo> inputDevices;
    { 
   //通过eventHub的getEvents函数获取事件信息存在mEventBuffer中.事件信息主要有两种,一种是设备节点的增删事件(设备事件),一种是原始输入事件
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
    { 
        if (count) {
            //如果有事件信息,调用processEventsLocked函数对事件进行加工处理
            processEventsLocked(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;
            }
#if DEBUG_RAW_EVENTS
            ALOGD("BatchSize: %d Count: %d", batchSize, count);
#endif
         //处理deviceId所对应的设备的原始输入事件
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {
           //对设备事件进行处理
            switch (rawEvent->type) {
            case EventHubInterface::DEVICE_ADDED:
                addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::DEVICE_REMOVED:
                removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::FINISHED_DEVICE_SCAN:
                handleConfigurationChangedLocked(rawEvent->when);
                break;
            default:
                ALOG_ASSERT(false); // can't happen
                break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}
  • inputReader的processEventsLocked函数首先遍历所有事件,这些事件用RawEvent对象表示
  • 事件分为原始事件和设备事件
  • 设备事件分为DEVICE_ADDED、DEVICE_ADDED、FINISHED_DEVICE_SCAN,生成时机是EventHub的getEvent函数中生成得
  • 如果是DEVICE_ADD事件(设备添加事件),InputReader会新建InputDevice对象,用来存储设备信息

processEventsForDeviceLocked源码分析

void InputReader::processEventsForDeviceLocked(int32_t deviceId,
        const RawEvent* rawEvents, size_t count) {
          //根据deviceId获取deviceIndex
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
     //deviceIndex根据deviceIndex获取InputDevice
    InputDevice* device = mDevices.valueAt(deviceIndex);
     //调用InputDevice的process
    device->process(rawEvents, count);
}
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    size_t numMappers = mMappers.size();
       //遍历InputDevice所有事件
    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
#if DEBUG_RAW_EVENTS
  
#endif
       //mDropUntilNextSync默认是false,如果设备设备事件缓存区溢出则为true
        if (mDropUntilNextSync) {
        
#endif
            } else {
            //遍历所有的事件
            for (size_t i = 0; i < numMappers; i++) {
                  //加工原始数据的是InputMapper对象
                InputMapper* mapper = mMappers[i];
                mapper->process(rawEvent);
            }
        }
    }
}

这里以KeyboardInputMapper为例

void KeyboardInputMapper::process(const RawEvent* rawEvent) {
    switch (rawEvent->type) {
    case EV_KEY: {//按键类型
        int32_t scanCode = rawEvent->code;
        int32_t usageCode = mCurrentHidUsage;
        mCurrentHidUsage = 0;

        if (isKeyboardOrGamepadKey(scanCode)) {
            processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
        }
        break;
    }

    }
}
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
        int32_t usageCode) {
      //封装参数
    NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);

    getListener()->notifyKey(&args);
}
InputListenerInterface* InputReader::ContextImpl::getListener() {
    return mReader->mQueuedListener.get();
}

InputDispatcher继承了InputDispatcherInterface,也就是说实际调用的是InputDispatch的notifyKey方法

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {

    bool needWake;
    { // acquire lock
        mLock.lock();

        if (shouldSendKeyToInputFilterLocked(args)) {
            mLock.unlock();

            policyFlags |= POLICY_FLAG_FILTERED;
            if (!mPolicy->filterInputEvent(&event, policyFlags)) {
                return; // event was consumed by the filter
            }

            mLock.lock();
        }

        int32_t repeatCount = 0;
         //分局NotifyKeyArgs封装成KeyEntry独享
        KeyEntry* newEntry = new KeyEntry(args->eventTime,
                args->deviceId, args->source, policyFlags,
                args->action, flags, keyCode, args->scanCode,
                metaState, repeatCount, args->downTime);
       //根据newEntry判断是否需要唤醒
        needWake = enqueueInboundEventLocked(newEntry);
        mLock.unlock();
    } // release lock
    if (needWake) {
       //Looper进行唤醒操作
        mLooper->wake();
    }
}
  • IMS启动了InputDispatchThread和InputReadThread,分别用来运行InputDispatcher和InputReader
  • InputDispatcher的dispatchOnceInnerLocked函数用来将事件分发给合适的window,inputDispatcher没有输入事件处理会进入睡眠状态,等待InputReader通知唤醒
  • InputReader通过EventHub的getEvents函数获取事件信息,如果是原始输入事件,就将这些原始输入事件交由不同的InputMapper来处理,最终交由InputDispatcher来进行分发。
  • InputDispatcher的notifyKey函数中会根据按键数据来判断InputDispatcher是否要被唤醒,InputDispatcher被唤醒后,会重新调用dispatchOnceInnerLocked函数将输入事件分发给合适的Window。


    image.png

参考文章

Android输入系统——http://liuwangshu.cn/framework/ims/2-inputevent.html

相关文章

网友评论

      本文标题:Android Framework——Input事件分发

      本文链接:https://www.haomeiwen.com/subject/jjydeltx.html