Android按键拦截interceptKeyBeforeQueueing和interceptKeyBeforeDispatching分析

1.interceptKeyBeforeQueueing
顾名思义在加入队列之前拦截事件,调用过程如下分析
inputDispatch.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
    ...
    mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
    ...
}
此处的mPolicy对应的就是com_android_server_input_InputManagerService.cpp的this.即是此类
详细见这个方法
NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    ...
    sp<EventHub> eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}

调用mPolicy->interceptKeyBeforeQueueing也就是调用com_android_server_input_InputManagerService.cpp的interceptKeyBeforeQueueing
代码如下:
void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
        uint32_t& policyFlags) {
    // Policy:
    // - Ignore untrusted events and pass them along.
    // - Ask the window manager what to do with normal events and trusted injected events.
    // - For normal events wake and brighten the screen if currently off or dim.
    bool interactive = mInteractive.load();
    if (interactive) {
        policyFlags |= POLICY_FLAG_INTERACTIVE;
    }
    if ((policyFlags & POLICY_FLAG_TRUSTED)) {
        nsecs_t when = keyEvent->getEventTime();
        JNIEnv* env = jniEnv();
        jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
        jint wmActions;
        if (keyEventObj) {
        //此处表示调用InputManagerService.java层的interceptKeyBeforeQueueing
            wmActions = env->CallIntMethod(mServiceObj,
                    gServiceClassInfo.interceptKeyBeforeQueueing,
                    keyEventObj, policyFlags);
        
            if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
                wmActions = 0;
            }
            android_view_KeyEvent_recycle(env, keyEventObj);
            env->DeleteLocalRef(keyEventObj);
        } else {
            ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
            wmActions = 0;
        }

        handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
    } else {
        if (interactive) {
            policyFlags |= POLICY_FLAG_PASS_TO_USER;
        }
    }
}
wmActions = env->CallIntMethod(mServiceObj,
                    gServiceClassInfo.interceptKeyBeforeQueueing,
                    keyEventObj, policyFlags);
此为jni的调用方式,表示调用java层的interceptKeyBeforeQueueing方法
handleInterceptActions这个方法会把返回值wmActions转换为policyFlags的值,policyFlags会封装成KeyEntry类型给inputDispatch.后面会根据这个值表示要不要传递给应用
到了InputManagerService.java层的interceptKeyBeforeQueueing方法
    // Native callback.
    private int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
        return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
                whenNanos, policyFlags);
    }
此处mWindowManagerCallbacks对应的是InputMonitor(在systemServer.java里设置inputManager.setWindowManagerCallbacks(wm.getInputMonitor());)
InputMonitor.cpp
    @Override
    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
        if(mService.mTestFlag)//for POWER_KEY
            return 0x00000001;
        return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
    }
此处mPolicy对应的就是PhoneWindowManager.java


InputDispatcher::notifyKey是在inputReader.cpp里面通过方法processKey调用
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
        int32_t usageCode) {
    ...
    getListener()->notifyKey(&args);
}
此处见博客Android输入InputManagerService的启动和事件读取过程中有说明
到此interceptKeyBeforeQueueing结束

2.interceptKeyBeforeDispatching
顾名思义在分发之前拦截
在inputDispatch.cpp里面的方法dispatchKeyLocked处理.
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
        DropReason* dropReason, nsecs_t* nextWakeupTime) {
    ...
    // Give the policy a chance to intercept the key.
    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; // wait for the command to run
        } else {
            entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
        }
    } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
        if (*dropReason == DROP_REASON_NOT_DROPPED) {
            *dropReason = DROP_REASON_POLICY;
        }
    }
    ...
}
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();
}
doInterceptKeyBeforeDispatchingLockedInterruptible调用mPolicy->interceptKeyBeforeDispatching,
mPolicy同上,对应的是com_android_server_input_InputManagerService.cpp
代码如下
nsecs_t NativeInputManager::interceptKeyBeforeDispatching(
        const sp<InputWindowHandle>& inputWindowHandle,
        const KeyEvent* keyEvent, uint32_t policyFlags) {
    // Policy:
    // - Ignore untrusted events and pass them along.
    // - Filter normal events and trusted injected events through the window manager policy to
    //   handle the HOME key and the like.
    nsecs_t result = 0;
    if (policyFlags & POLICY_FLAG_TRUSTED) {
        JNIEnv* env = jniEnv();

        // Note: inputWindowHandle may be null.
        jobject inputWindowHandleObj = getInputWindowHandleObjLocalRef(env, inputWindowHandle);
        jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
        if (keyEventObj) {
            jlong delayMillis = env->CallLongMethod(mServiceObj,
                    gServiceClassInfo.interceptKeyBeforeDispatching,
                    inputWindowHandleObj, keyEventObj, policyFlags);
            bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
            android_view_KeyEvent_recycle(env, keyEventObj);
            env->DeleteLocalRef(keyEventObj);
            if (!error) {
                if (delayMillis < 0) {
                    result = -1;
                } else if (delayMillis > 0) {
                    result = milliseconds_to_nanoseconds(delayMillis);
                }
            }
        } else {
            ALOGE("Failed to obtain key event object for interceptKeyBeforeDispatching.");
        }
        env->DeleteLocalRef(inputWindowHandleObj);
    }
    return result;
}
interceptKeyBeforeDispatching调用的是InputManagerService.java层的interceptKeyBeforeQueueing.其它同上调用过程,最后到PhoneWindowManager.java的interceptKeyBeforeDispatching

nn

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值