Input子系统框架之InputDispatcher

本文深入探讨了Android系统中InputDispatcher的运作机制,包括其初始化过程、事件分发流程及超时处理策略。揭示了InputDispatcher如何从mInboundQueue获取事件,通过dispatchOnce()进行事件分发,并详细解析了按键事件的处理逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原始链接:http://gityuan.com/2016/12/17/input-dispatcher/

一. InputDispatcher起点

上篇文章输入系统之InputReader线程,介绍InputReader利用EventHub获取数据后生成EventEntry事件,加入到InputDispatcher的mInboundQueue队列,再唤醒InputDispatcher线程。本文将介绍InputDispatcher,同样从threadLoop为起点开始分析。

1.1 threadLoop

先来回顾一下InputDispatcher对象的初始化过程:

InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
    mPolicy(policy),
    mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED),
    mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
    mNextUnblockedEvent(NULL),
    mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
    mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
   
   
    //创建Looper对象
    mLooper = new Looper(false);

    mKeyRepeatState.lastKeyEntry = NULL;
    //获取分发超时参数
    policy->getDispatcherConfiguration(&mConfig);
}

该方法主要工作:

创建属于自己线程的Looper对象;
超时参数来自于IMS,参数默认值keyRepeatTimeout = 500,keyRepeatDelay = 50。

[-> InputDispatcher.cpp]

bool InputDispatcherThread::threadLoop() {
   
   
    mDispatcher->dispatchOnce(); //【见小节1.2】
    return true;
}

整个过程不断循环地调用InputDispatcher的dispatchOnce()来分发事件

1.2 dispatchOnce

[-> InputDispatcher.cpp]

void InputDispatcher::dispatchOnce() {
   
   
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    {
   
   
        AutoMutex _l(mLock);
        //唤醒等待线程,monitor()用于监控dispatcher是否发生死锁
        mDispatcherIsAliveCondition.broadcast();

        if (!haveCommandsLocked()) {
   
   
            //当mCommandQueue不为空时处理【见小节2.1】
            dispatchOnceInnerLocked(&nextWakeupTime);
        }

        //【见小节3.1】
        if (runCommandsLockedInterruptible()) {
   
   
            nextWakeupTime = LONG_LONG_MIN;
        }
    }

    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    mLooper->pollOnce(timeoutMillis); //进入epoll_wait
}

线程执行Looper->pollOnce,进入epoll_wait等待状态,当发生以下任一情况则退出等待状态:

callback:通过回调方法来唤醒;
timeout:到达nextWakeupTime时间,超时唤醒;
wake: 主动调用Looper的wake()方法;

二. InputDispatcher

2.1 dispatchOnceInnerLocked

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
   
   
    nsecs_t currentTime = now(); //当前时间,也是后面ANR计时的起点

    if (!mDispatchEnabled) {
   
    //默认值为false
        resetKeyRepeatLocked(); //重置操作
    }
    if (mDispatchFrozen) {
   
    //默认值为false
        return; //当分发被冻结,则不再处理超时和分发事件的工作,直接返回
    }

    //优化app切换延迟,当切换超时,则抢占分发,丢弃其他所有即将要处理的事件。
    bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
    ...

    if (!mPendingEvent) {
   
   
        if (mInboundQueue.isEmpty()) {
   
   
            if (!mPendingEvent) {
   
   
                return; //没有事件需要处理,则直接返回
            }
        } else {
   
   
            //从mInboundQueue取出头部的事件
            mPendingEvent = mInboundQueue.dequeueAtHead();
        }
        ...
        resetANRTimeoutsLocked(); //重置ANR信息[见小节2.1.1]
    }

    bool done = false;
    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;
    }
    ...

    switch (mPendingEvent->type) {
   
   
      case EventEntry::TYPE_KEY: {
   
   
          KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
          if (isAppSwitchDue) {
   
   
              if (isAppSwitchKeyEventLocked(typedEntry)) {
   
   
                  resetPendingAppSwitchLocked(true);
                  isAppSwitchDue = false;
              } else if (dropReason == DROP_REASON_NOT_DROPPED) {
   
   
                  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;
          }
          // 分发按键事件[见小节2.2]
          done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
          break;
      }
      ...
    }
    ...

    //分发操作完成,则进入该分支
    if (done) {
   
   
        if (dropReason != DROP_REASON_NOT_DROPPED) {
   
   
            //[见小节2.1.2]
            dropInboundEventLocked(mPendingEvent, dropReason);
        }
        mLastDropReason = dropReason;
        releasePendingEventLocked(); //释放pending事件见小节2.10]
        *nextWakeupTime = LONG_LONG_MIN; //强制立刻执行轮询
    }
}

在enqueueInboundEventLocked()的过程中已设置mAppSwitchDueTime等于eventTime加上500ms:

mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;

该方法主要功能:

mDispatchFrozen用于决定是否冻结事件分发工作不再往下执行;
当事件分发的时间点距离该事件加入mInboundQueue的时间超过500ms,则认为app切换过期,即isAppSwitchDue=true;
mInboundQueue不为空,则取出头部的事件,放入mPendingEvent变量;并重置ANR时间;
根据EventEntry的type类型分别处理,比如按键调用dispatchKeyLocked分发事件;再根据分发结果来决定是否进入done;
执行完成(done)的处理:
根据dropReason(默认NOT_DROPPED不处理)来决定是否丢失事件; dropInboundEventLocked
释放当前正在处理的事件(即mPendingEvent); releasePendingEventLocked
关于dispatchKeyLocked分发事件,

不会执行done过情况:
当前Event时间小于唤醒时间;
让policy有机会执行拦截操作;
调用findFocusedWindowTargetsLocked方法的返回结果是INPUT_EVENT_INJECTION_PENDING, 即targets没有处于Ready状态;
会执行done的情况:
该事件需要丢弃, 即dropReason != DROP_REASON_NOT_DROPPED;
findFocusedWindowTargetsLocked的返回结果不是INPUT_EVENT_INJECTION_PENDING(没有正在处理的事件);
接下来以按键为例来展开说明, 则进入[小节2.2] dispatchKeyLocked.

2.1.1 resetANRTimeoutsLocked
void InputDispatcher::resetANRTimeoutsLocked() {
   
   
    // 重置等待超时cause和handle
    mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
    mInputTargetWaitApplicationHandle.clear();
}
2.1.2 dropInboundEventLocked
void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) {
   
   
    const char* reason;
    switch (dropReason) {
   
   
    case DROP_REASON_POLICY:
        reason = "inbound event was dropped because the policy consumed it";
        break;
    case DROP_REASON_DISABLED:
        if (mLastDropReason != DROP_REASON_DISABLED) {
   
   
            ALOGI("Dropped event because input dispatch is disabled.");
        }
        reason = "inbound event was dropped because input dispatch is disabled";
        break;
    case DROP_REASON_APP_SWITCH:
        ALOGI("Dropped event because of pending overdue app switch.");
        reason = "inbound event was dropped because of pending overdue app switch";
        break;
    case DROP_REASON_BLOCKED:
        ALOGI("Dropped event because the current application is not responding and the user "
                "has started interacting with a different application."
<think>好的,我现在需要帮助用户了解或实现得物签名的相关技术,特别是签名算法的实现方式。首先,我需要收集已有的信息。根据用户提供的引用,特别是引用[4]和[5],得物的签名算法可能涉及逆向工程分析,使用了JavaScript中的XMLHttpRequest重写来拦截请求,并在请求中包含特定的sign参数。这可能意味着签名生成是在客户端进行的,通常在前端JavaScript代码中完成。 接下来,我应该考虑常见的签名生成方法。常见的Web应用签名算法通常使用HMAC、AES、RSA或自定义的哈希组合。引用[1]提到了RSA算法,但得物的签名可能更倾向于使用HMAC-SHA256之类的哈希算法,结合时间戳、随机数和请求参数进行签名,以防止篡改和重放攻击。 用户可能需要具体的步骤,比如逆向分析得物的JavaScript代码,找到生成sign的函数,提取关键参数和加密逻辑。引用[5]中的代码片段展示了如何重写XMLHttpRequest的open方法来拦截请求,这可能用于调试和定位签名生成的代码位置。 此外,引用[4]提到使用Python进行算法还原,所以可能需要在Python中复现JavaScript的签名生成逻辑。这通常涉及分析请求参数如何排序、拼接,以及如何与密钥结合进行哈希或加密。需要注意反爬机制,如obfuscation(代码混淆)或动态密钥,这可能需要使用AST(抽象语法树)解析或动态执行来还原算法。 用户可能还需要了解如何应对反调试措施,比如在Chrome开发者工具中使用断点调试,或者使用工具如Frida进行Hook。同时,引用[3]和[4]强调了法律和合规问题,确保研究仅用于学习目的,不用于非法用途。 最后,应该提醒用户注意法律风险,遵循网站的使用条款,避免侵犯知识产权或违反计算机安全法律。总结起来,实现得物签名需要逆向工程分析前端代码,提取关键算法,处理可能的混淆和反调试,最后用目标语言如Python复现算法。</think>### 得物签名算法实现方式分析 得物签名算法主要用于接口请求的身份验证和防篡改保护,常见实现方式涉及以下技术点: #### 1. **签名参数组成** 签名通常由以下参数动态生成: - 请求参数(经排序、过滤空值后拼接) - 时间戳(如:$timestamp=1620000000$) - 随机数(如:$nonce=5a8s3d$) - 设备指纹(如:$device\_id=abcdef$) - 应用密钥(加密盐值,可能动态获取)[^4] 示例参数拼接逻辑: $$ \text{sign\_str} = \text{path} + \text{sorted\_params} + \text{timestamp} + \text{nonce} $$ #### 2. **加密算法类型** 根据逆向分析,得物可能采用以下组合: - **HMAC-SHA256**:对拼接字符串进行哈希运算 - **AES/Base64编码**:对结果二次处理 - **自定义位移/异或操作**:增加逆向难度[^5] #### 3. **JavaScript代码混淆** 关键函数可能被混淆,例如: ```javascript function _0x12ab5(a, b) { return a ^ b << 3; } // 需要AST解析还原控制流 ``` #### 4. **Python算法还原示例** ```python import hmac import hashlib def generate_sign(params, secret_key): # 1. 参数排序并拼接 sorted_str = '&'.join([f"{k}={v}" for k,v in sorted(params.items())]) # 2. HMAC-SHA256加密 sign = hmac.new(secret_key.encode(), sorted_str.encode(), hashlib.sha256).hexdigest() # 3. 自定义处理(示例) return sign.upper() + str(int(time.time())) ``` #### 5. **反爬对抗措施** - 动态密钥:通过接口定期更新加密盐值 - 环境检测:验证是否在真机环境运行 - 请求频率限制:异常高频触发验证码[^5]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值