android framework java层是如何拦截并分发底层传送来的按键事件

按键事件首先通过PhoneWindowManager的interceptKeyBeforeDispatching方法被拦截,然后分发到应用层,一些系统事件:HOME,MENU,SEARCH,会在这里做下预处理。那底层事件是如何传到interceptKeyBeforeDispatching方法中呢?

通过查看谁调用了此方法(eclipse中右键单击此方法名,选择open call hierarchy),发现InputMonitor.java调用了此方法:

public long interceptKeyBeforeDispatching(
            InputWindowHandle focus, KeyEvent event, int policyFlags) {
        WindowState windowState = focus != null ? (WindowState) focus.windowState : null;
        return mService.mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags);
    }

同样的方法我们发现InputManager.java中的Callbacks调用了InputMonitor的interceptKeyBeforeDispatching方法:

@SuppressWarnings("unused")
        public long interceptKeyBeforeDispatching(InputWindowHandle focus,
                KeyEvent event, int policyFlags) {
            return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(
                    focus, event, policyFlags);
        }

java层就是通过InputManager.java和C++层完成事件交互,通过上述我们知道是Callbacks调用了interceptKeyBeforeDispatching方法,而Callbacks是什么呢,顾名思义,Callbacks是C++层回调InputManager.java的一个接口。那Callbacks是如何初始化和注册的呢?InputManager.java的构造方法给出了答案:

public InputManager(Context context, WindowManagerService windowManagerService) {
        this.mContext = context;
        this.mWindowManagerService = windowManagerService;
        this.mCallbacks = new Callbacks();

        Looper looper = windowManagerService.mH.getLooper();

        Slog.i(TAG, "Initializing input manager");
        nativeInit(mContext, mCallbacks, looper.getQueue());

        // Add ourself to the Watchdog monitors.
        Watchdog.getInstance().addMonitor(this);
    }

nativeInit(mContext, mCallbacks, looper.getQueue());这是一个native方法,java层通过jni调用C++层相对应的方法。C++层相对应的方法会去初始化C++层的InputManager和注册Callbacks。

那么如何找到C++层这个相对应的方法呢?其实很简单,我们看下InputManager.java的路径

\frameworks\base\services\java\com\android\server\wm

通常在和java(\frameworks\base\services\java)同目录下会有相对应的jni的目录结构(\frameworks\base\services\jni)

通过Source Insight 搜索对应目录(PS这样快)下的nativeInit字串,发现这样的一个数组:

static JNINativeMethod gInputManagerMethods[] = {
    /* name, signature, funcPtr */
    { "nativeInit", "(Landroid/content/Context;"
            "Lcom/android/server/wm/InputManager$Callbacks;Landroid/os/MessageQueue;)V",
            (void*) android_server_InputManager_nativeInit },

android_server_InputManager_nativeInit就是C++层相对应的方法,在com_android_server_InputManager.cpp中:

static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,
        jobject contextObj, jobject callbacksObj, jobject messageQueueObj) {
    if (gNativeInputManager == NULL) {
        sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
        gNativeInputManager = new NativeInputManager(contextObj, callbacksObj, looper);
    } else {
        LOGE("Input manager already initialized.");
        jniThrowRuntimeException(env, "Input manager already initialized.");
    }
}

NativeInputManager的构造函数中:

mInputManager = new InputManager(eventHub, this, this);

InputManager.cpp 存在于frameworks\base\services\input,构造函数中:

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();
}

InputDispatcher中的doInterceptKeyBeforeDispatchingLockedInterruptible函数调用了mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
            &event, entry->policyFlags);传入事件,mPolicy就是上面代码中的dispatcherPolicy对象。

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();
}

InputDispatcher负责分发c++层获得的linux设备的按键事件,交由dispatcherPolicy,也就是NativeInputManager处理,NativeInputManager,通过Callbacks然后上报java层。

对于c++层如何获得的linux设备的按键事件,以及如何通过InputDispatcher分发这些事件感兴趣的,可以查看frameworks\base\services\input下的代码,可以先从InputManager.cpp的构造函数入手,或者查看网上相关文章。这里暂时不描述了。

文章错误之处请指出,大家共同进步,转载请注明出处,谢谢!

    原文作者:cool_ping
    原文地址: https://blog.csdn.net/cool_ping/article/details/8363212
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞