zoukankan      html  css  js  c++  java
  • Android系统--输入系统(十四)Dispatcher线程情景分析_dispatch前处理

    Android系统--输入系统(十四)Dispatcher线程情景分析_dispatch前处理

    1. 回顾

    我们知道Android输入系统是Reader线程通过驱动程序得到上报的输入事件,还要经过处理,才可以将输入事件发送给应用程序,现在回顾一下是具体做哪些处理。

    1. 首先Reader线程会将输入事件放入mInboundQueue队列当中,但是放入队列之前需要进行稍加处理。
      1.1 处理类型
      - 紧急事件,马上处理(来电振铃时,按下音量键,会马上静音)
      - 对输入事件添加Flag,决定输入事件是否传给用户

    2. Dispatch线程从mInboundQueue中取出事件,稍加处理之后,查找到目标的应用程序后,便会放入某个应用程序的输出队列(mOutBoundQueue)

    3. 从输出队列中将事件取出,发送给应用程序

    2. Dispatch前处理总体分析

    2.1 命令队列为空时时候
    • 从mIboundQueue取出事件
    • 用它来生成一个命令,放入命令队列或者直接丢弃(对于!Pass_To_User的事件)
    • 对于经过处理的事件,dispatch它
      • 对于Global Key丢弃
      • System Key 丢弃
      • User Key 找到target,dispatch
    InputDispatch.cpp
    if (!haveCommandsLocked()) {
        dispatchOnceInnerLocked(&nextWakeupTime);
    }
    
    2.2 命令队列有数据,执行命令
    • Global Key 发广播
    • System Key 直接处理
    • User Key 不做处理
    InputDispatch.cpp
    if (runCommandsLockedInterruptible()) {
        nextWakeupTime = LONG_LONG_MIN;
    }
    

    3. dispatch前处理情景分析

    3.1 !Pass_To_User
    • 当policyFlags = !Pass_To_User,则会执行dispatchOnceInnerLocked函数,设置dropreason
    DropReason dropReason = DROP_REASON_NOT_DROPPED;
    if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
            dropReason = DROP_REASON_POLICY;
    } else if (!mDispatchEnabled) {
            dropReason = DROP_REASON_DISABLED;
    }
    
    • 假设是一个按键类型的输入事件,便会调用dispatchKeyLocked处理
    // Clean up if dropping the event.
    if (*dropReason != DROP_REASON_NOT_DROPPED) {
            setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
                ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
            return true;
    }
    
    3.2 Pass_To_User
    • 需要分为Global Key/System Key/User Key三种情况,但是都是首先放入命令队列中,并执行命令,执行的命令根据各个按键的返回值决定。
    • 放入命令队列
    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; // wait for the command to run
    
    • 执行命令
    if (runCommandsLockedInterruptible()) {
        nextWakeupTime = LONG_LONG_MIN;
    }
    
    CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
    
    Command command = commandEntry->command;
    (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'
    //command执行doInterceptKeyBeforeDispatchingLockedInterruptible函数
    
    //最终调用PhoneWindowManager.java里面的同名函数
    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;
    }
    
    • 处理全局按键(Global Key)的代码,返回-1,根据Global_Key.xml发送广播给某个主键
    if (mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {
        return -1;
    }
    
    • System Key:直接处理,return -1,意味着不会上传给APP
    • User Key:return 0,事件解析结果是continue,让APP来处理。再次执行dispatchOnceInnerLocked,最终会找到目标应用程序,然后将该事件发给应用程序
    // Identify targets.
    Vector<InputTarget> inputTargets;
    int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
    entry, inputTargets, nextWakeupTime);
    
    // Dispatch the key.
    dispatchEventLocked(currentTime, entry, inputTargets);
    

    4. 总结

    本篇博文主要分析dispatc前的处理过程,如下图所示:

    1. 对于Reader线程读到的输入事件,会先进行解析,解析之后进行过滤,如果可以过滤就释放,就不会放入mInBoundQueue队列当中,不可以过滤的话,无论是否Pass_To_User,都会放入mInBoundQueue队列当中
    2. 从mInBoundQueue队列当中取出输入事件,判断是否Pass_To_User,如果不是Pass_To_User则释放掉,否则放入mCommandQueue当中
    3. 再从mCommandQueue队列当中,再次做解析,解析之后如果决定可以把他丢弃掉的话就直接release掉,否则则是放在mOutBoundQueue队列中去,APP取出使用。下篇博文会具体分析这一步。
  • 相关阅读:
    C语言的AES加密
    curl指定域名的IP
    gdb调试知识
    C++获取寄存器eip的值
    C++嵌入lua
    [置顶] python字典和nametuple互相转换例子
    【python】redis基本命令和基本用法详解
    xshell登录到CentOS7上时出现“The remote SSH server rejected X11 forwarding request.
    selinue引起的ssh连接错误
    SCP和SFTP相同点和区别
  • 原文地址:https://www.cnblogs.com/lkq1220/p/7170107.html
Copyright © 2011-2022 走看看