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

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

1. 代码分析小目标

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

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

Step 1: SystemServer 的main 方法创建InputManagerService 和WindowManagerService 对象,并将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 发送事件,这个流程稍微长一点,涉及到InputReader 和InputDevice , 从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 ,所以实际调用NativeInputManager 的interceptKeyBeforeQueueing

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 就是WindowManagerService ,mPolicy 是在WindowManagerService 的main 函数调用构造时候传入,在SystemServer 调用main 时候传入的PhoneWindowManager

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

相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone3 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc3 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo3 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077003 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone4 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen4 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone4 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui