Android 从问题出发探索KeyEvent分发流程(1) PhoneWindowManager是如何收到事件的

源码环境是Android13,所有非必要代码都做了省略处理,最大程度简化主干分析过程

1. 代码分析小目标

按照3个小问题来看下KeyEvent的传递过程

  1. PhoneWindowManager是如何收到事件的
  2. Activity是如何收到KeyEvent的
  3. View的keyListener是如何收到事件的

Step 1: SystemServermain 方法创建InputManagerServiceWindowManagerService 对象,并将WMS内部的InputManagerCallback传入IMS方便接收新数据

base/services/java/com/android/server/SystemServer.java

java 复制代码
    /**
     * The main entry point from zygote.
     */
    public static void main(String[] args) {
        new SystemServer().run();
    }
    
    private void run() {
         try {
            startOtherServices(t);
        } catch (Throwable ex) {

        } finally {
        }
    }
    
    private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
            // WMS needs sensor service ready
            wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
                    new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
            ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
                    DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
                    /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
                    /.../
           inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
           inputManager.start();
    }
    
    // InputManagerService.start内部其实是调用了他的mNative实现
public void start() {
    Slog.i(TAG, "Starting input manager");
    mNative.start();
}

Step 2: KeyEvent是从InputManager转发过来,真正的处理过程实际是Native去做的,所以我们先找到IMS的Native实现,众所周知,java转到Native肯定有jni定义,我们如何找到jni文件呢,jni文件一般是包名加类名 ,也就是com_android_server_input_InputManagerService.cpp ,C层最终业务的实际的实现类是InputManager.cpp,内部调用start创建并启动InputReader和InputDispatcher

/base/services/core/jni/com_android_server_input_InputManagerService.cpp

cpp 复制代码
NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();

    mServiceObj = env->NewGlobalRef(serviceObj);

    {
        AutoMutex _l(mLock);
        mLocked.systemUiLightsOut = false;
        mLocked.pointerSpeed = 0;
        mLocked.pointerAcceleration = android::os::IInputConstants::DEFAULT_POINTER_ACCELERATION;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
        mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
    }
    mInteractive = true;
    mTouchWakeup = property_get_bool("ro.duershow.touchwakeup.enable", 0);
    InputManager* im = new InputManager(this, this);
    mInputManager = im;
    defaultServiceManager()->addService(String16("inputflinger"), im);
}

/native/services/inputflinger/InputManager.cpp

c++ 复制代码
InputManager::InputManager(
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = createInputDispatcher(dispatcherPolicy);
    mClassifier = std::make_unique<InputClassifier>(*mDispatcher);
    mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mClassifier);
    // Dispatcher类被一层层包装后混进了Inputeader获取情报
    mReader = createInputReader(readerPolicy, *mBlocker);
}

status_t InputManager::start() {
    status_t result = mDispatcher->start();
    if (result) {
        ALOGE("Could not start InputDispatcher thread due to error %d.", result);
        return result;
    }

    result = mReader->start();
    if (result) {
        ALOGE("Could not start InputReader due to error %d.", result);

        mDispatcher->stop();
        return result;
    }

    return OK;
}

Step 3: InputReader 借助EventHub 获取到设备事件,最终调用getListener()->notifyKey 发送事件,这个流程稍微长一点,涉及到InputReaderInputDevice , 从Step 2最后一段代码可以知道,InputReader创建时候将InputDispatcher作为listener,所以实际调用的是InputDispatcher的notifyKey.

/native/services/inputflinger/reader/InputReader.cpp

InputReader::loopOnce() -> InputReader::processEventsLocked -> InputReader::processEventsForDeviceLocked

cpp 复制代码
void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
                                               size_t count) {
    auto deviceIt = mDevices.find(eventHubId);
    if (deviceIt == mDevices.end()) {
        ALOGW("Discarding event for unknown eventHubId %d.", eventHubId);
        return;
    }

    std::shared_ptr<InputDevice>& device = deviceIt->second;
    if (device->isIgnored()) {
        // ALOGD("Discarding event for ignored deviceId %d.", deviceId);
        return;
    }

    device->process(rawEvents, count);
}

逻辑转到InputDevice里面,调用process

/native/services/inputflinger/reader/InputDevice.cpp

cpp 复制代码
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    // Process all of the events in order for each mapper.
    // We cannot simply ask each mapper to process them in bulk because mappers may
    // have side-effects that must be interleaved.  For example, joystick movement events and
    // gamepad button presses are handled by different mappers but they should be dispatched
    // in the order received.
    for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {
                mapper.process(rawEvent);
            });
        --count;
    }
}

遍历map这个map保存的是不同设备的数据几何,比如我们现在探索的就是KeyboardInputMapper ,代表键盘设备,android有很多的InputMapper但是最终都是通过getListener 调用不同的函数将事件交给InputDispatcher

cpp 复制代码
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->readTime, rawEvent->value != 0, scanCode,
                           usageCode);
            }
            break;
        }
    }
}
cpp 复制代码
void KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down, int32_t scanCode,
                                     int32_t usageCode) {

    NotifyKeyArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
                       getDisplayId(), policyFlags,
                       down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
                       AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
    getListener().notifyKey(&args);
}

Step 4: InputDispatcher收到事件是需要检查然后加入队列,在加入队列之前会先调用mPolicy->interceptKeyBeforeQueueing入队列前给一次处理机会

cpp 复制代码
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {

    mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);


        needWake = enqueueInboundEventLocked(std::move(newEntry));
  
    } // release lock

    if (needWake) {
        mLooper->wake();
    }
}

mPolicy的赋值是在InputDispatcher构造函数 处理,所以需要我们往回找他的实现,从Step 2 的代码可以知道InputDispatcher 是在InputManager 构造里创建的,且是透传的参数,InputManager 又是在com_android_server_input_InputManagerService.cpp 内创建,且参数传的都是this ,也就是NativeInputManager ,所以实际调用NativeInputManagerinterceptKeyBeforeQueueing

Step 5: NativeInputManager调用java层的同名函数

/base/services/core/jni/com_android_server_input_InputManagerService.cpp

cpp 复制代码
void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
        uint32_t& policyFlags) {

    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) {
        // C反向调用java代码,也就是InputManagerService.java的interceptKeyBeforeQueueing
            wmActions = env->CallIntMethod(mServiceObj,
                    gServiceClassInfo.interceptKeyBeforeQueueing,
                    keyEventObj, policyFlags);
         
    } else {
        if (interactive) {
            policyFlags |= POLICY_FLAG_PASS_TO_USER;
        }
    }
}

Step 6: InputManagerServcie继续透传到WMS

/base/services/core/java/com/android/server/input/InputManagerService.java

java 复制代码
private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
    // 还记得step 1提到的WMS安插的间谍
    return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
}

/base/services/core/java/com/android/server/wm/InputManagerCallback.java

java 复制代码
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
    return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
}

mService 就是WindowManagerServicemPolicy 是在WindowManagerServicemain 函数调用构造时候传入,在SystemServer 调用main 时候传入的PhoneWindowManager

Step 7: WMS回调PhoneWindowManagerinterceptKeyBeforeQueueing,至此,PhoneWindowManager如何收到的KeyEvent就结束了,这个时候KeyEvent还没有进入分发流程

相关推荐
私人珍藏库1 小时前
[Android] APK提取器(1.3.7)版本
android
m0_748232641 小时前
mysql的主从配置
android·mysql·adb
秋长愁1 小时前
Android监听应用前台的实现方案解析
android
胖虎12 小时前
2025 新版Android Studio创建Java语言项目
android·java·android studio·创建java项目
JabamiLight3 小时前
Lineageos 22.1(Android 15)Launcer简单调整初始化配置
android·android 15·lineageos 22.1·launcer
敲代码的鱼哇5 小时前
设备唯一ID获取,支持安卓/iOS/鸿蒙Next(uni-device-id)UTS插件
android·ios·uniapp·harmonyos
太空漫步116 小时前
android滑动看新闻
android
KdanMin7 小时前
“让App玩捉迷藏:Android教育平板的‘隐身术’开发实录”
android
韩曙亮7 小时前
【Android】Android 悬浮窗开发 ( 动态权限请求 | 前台服务和通知 | 悬浮窗创建 )
android·service·悬浮窗·服务·前台服务·动态权限·通知通道
双鱼大猫7 小时前
一句话说透Android里面的BufferQueue机制
android·程序员