Android 输入系统【2】Native 层输入事件的处理机制

Android 输入系统系列文章第二篇

  1. Android 输入系统【1】通过 IMS 的创建理解 Android 的输入流程

在上一篇文章中介绍了 IMS 构造方法中执行的底层逻辑,本文来到了系统服务 IMS 启动过程中剩下的步骤,下面的代码展示了本文的关键逻辑:

    private void startOtherServices(@NonNull TimingsTraceAndSlog t) {       
        WindowManagerService wm = null;
        InputManagerService inputManager = null;
        try {
           // 通过 IMS 创建 WMS
            wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
                    new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
      // ...
            t.traceBegin("IMS 添加 callback ,并启动");
            inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
            inputManager.start();
            t.traceEnd();
        } catch (Throwable e) {
            throw e;
        }
        // ... 
       final InputManagerService inputManagerF = inputManager;
        mActivityManagerService.systemReady(() -> {
            t.traceBegin("MakeInputManagerServiceReady");
            try {
                // TODO(BT) 将参数传递给输入管理器
                if (inputManagerF != null) {
                    inputManagerF.systemRunning(); // 【5】
                }
            } catch (Throwable e) {
                reportWtf("Notifying InputManagerService running", e);
            }
            t.traceEnd();
        }, t);
  }

startOtherServices 中关于 IMS 的剩下的步骤如下:

  1. 通过 IMS 创建 WMS;
  2. IMS 添加来自 WMS 的回调;
  3. IMS 调用 start 方法;
  4. 当 AMS 准备完成后,调用 IMS 的 systemRunning 完成系统的初始化,这里的 IMS 主要是处理更新一些设备的状态,比如麦克风、相机等。

在这几个步骤中,可以窥探出 IMS 和 WMS 存在密切的关系,并且 IMS 的核心逻辑应该是通过 start 方法来启动的,最后 AMS 准备完成后回调执行 IMS 的 systemRunning 来更新系统设备的一些信息。

WMS 初始化中的 IMS

WindowManagerService 通过 main 方法实例化:

public static WindowManagerService main(final Context context, final InputManagerService im, final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy, ActivityTaskManagerService atm) {
    return main(context, im, showBootMsgs, onlyCore, policy, atm, 
        new DisplayWindowSettingsProvider(), SurfaceControl.Transaction::new, Surface::new, SurfaceControl.Builder::new);
}

同名方法:

// 创建并返回WindowManagerService的一个实例。此调用允许调用方覆盖可用于在测试期间存根本机调用的工厂。
@VisibleForTesting
public static WindowManagerService main(final Context context, final InputManagerService im,
        final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
        ActivityTaskManagerService atm, DisplayWindowSettingsProvider
        displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
        Supplier<Surface> surfaceFactory,
        Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory)
 
{
    final WindowManagerService[] wms = new WindowManagerService[1];
    DisplayThread.getHandler().runWithScissors(() ->
            wms[0] = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
                    atm, displayWindowSettingsProvider, transactionFactory, surfaceFactory,
                    surfaceControlFactory), 0);
    return wms[0];
}

WMS 实例化切换到了 DisplayThread 线程,追踪到 WMS 的构造方法:

private WindowManagerService(Context context, InputManagerService inputManager,
        boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
        ActivityTaskManagerService atm, DisplayWindowSettingsProvider
        displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
        Supplier<Surface> surfaceFactory,
        Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory)
 
{
    //...
 mInTouchMode = context.getResources().getBoolean(com.android.internal.R.bool.config_defaultInTouchMode);
    inputManager.setInTouchMode(mInTouchMode, myPid(), myUid(), /* hasPermission = */ true);
    //...
    mInputManager = inputManager; // Must be before createDisplayContentLocked.
    //...
}

setInTouchMode 的作用是给IMS 设置触摸模式的状态,WMS 内部是触摸模式状态的真实来源,需要在 IMS 保存这个状态副本。

然后将 IMS 对象保存为 mInputManager ,供 WMS 内部使用。

IMS 添加 WMS 回调

inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());

WMS 中 getInputManagerCallback 方法:

public InputManagerCallback getInputManagerCallback() {
  return mInputManagerCallback;
}

mInputManagerCallback :

final InputManagerCallback mInputManagerCallback = new InputManagerCallback(this);

这个 InputManagerCallback 的构造方法需要一个 WMS 参数。它提供了一些由 IMS 调用,WMS 进行响应的方法,例如:

// 通知窗口管理器输入通道中断。
@Override
public void notifyInputChannelBroken(IBinder token)

// 通知窗口管理器有应用程序没有响应,因为它没有聚焦窗口。
@Override
public void notifyNoFocusedWindowAnr(@NonNull InputApplicationHandle applicationHandle)

/** 通知输入设备配置已更改。 */
@Override
public void notifyConfigurationChanged()
  
// ...

这些函数在 IMS 中由 Native 层进行回调,例如:

// Native callback
@SuppressWarnings("unused")
private void notifyFocusChanged(IBinder oldToken, IBinder newToken) {
  mWindowManagerCallbacks.notifyFocusChanged(oldToken, newToken);
}

IMS start

第三步是调用 IMS 的 start 方法,Java 层通过 JNI 调用 Native 层的逻辑都是从这里入手的:

public void start() {
    mNative.start(); // 【1】
            
    // 注册一些回调
    registerPointerSpeedSettingObserver();
    registerShowTouchesSettingObserver();
    registerAccessibilityLargePointerSettingObserver();
    registerLongPressTimeoutObserver();
    registerMaximumObscuringOpacityForTouchSettingObserver();
    registerBlockUntrustedTouchesModeSettingObserver();

    // 通过广播接收更新回调
    mContext.registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            updatePointerSpeedFromSettings();
            updateShowTouchesFromSettings();
            updateAccessibilityLargePointerFromSettings();
            updateDeepPressStatusFromSettings("user switched");
        }
    }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);

    // 首次调用更新回调
    updatePointerSpeedFromSettings();
    updateShowTouchesFromSettings();
    updateAccessibilityLargePointerFromSettings();
    updateDeepPressStatusFromSettings("just booted");
    updateMaximumObscuringOpacityForTouchFromSettings();
    updateBlockUntrustedTouchesModeFromSettings();
}

核心在 mNative 调用 start 方法,mNative 是 NativeInputManagerService ,start 方法也会调用到 native 层的

static const JNINativeMethod gInputManagerMethods[] = {
        /* name, signature, funcPtr */
        {"init",
         "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/"
         "MessageQueue;)J",
         (void*)nativeInit},
        {"start""()V", (void*)nativeStart},
      //...
}

这里的 JNI 配置说明了 start 方法调用的是 frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp 中的 nativeStart 方法:

static void nativeStart(JNIEnv* env, jobject nativeImplObj) {
    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);

    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}

在 nativeStart 中,逻辑指向了 InputManager 的 start 方法:

// frameworks/native/services/inputflinger/InputManager.cpp
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;
}

InputManager 中先后调用了 InputDispatcher 和 InputReader 的 start 方法。

InputDispatcher 的启动流程

status_t InputDispatcher::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    mThread = std::make_unique<InputThread>(
            "InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
    return OK;
}

InputDispatcher 创建了一个 InputThread 线程,并且确保证实唯一的。

InputThread 是一个用来持续循环处理输入事件直到被销毁的线程。创建后会立即启动,线程开始循环执行 loop 函数,直到被销毁。第二个参数 wake 函数则是用于当该线程销毁时,唤醒循环中休眠的所有对象。

public:
    explicit InputThread(std::string name, std::function<void()> loop,
                         std::function<void()> wake = nullptr)
;

在上面的调用中,loop 函数是

[this]() { dispatchOnce(); }

wake 函数是

[this]() { mLooper->wake(); }

也就是一直在循环执行 InputDispatcher 的 dispatchOnce 方法。

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // 请求锁
        std::scoped_lock _l(mLock);
        mDispatcherIsAlive.notify_all();

        // 初始化一个处理事件队列的调度循环
        if (!haveCommandsLocked()) {
            dispatchOnceInnerLocked(&nextWakeupTime); // 【1】
        }

        // 如果我们仍在等待某些事件导致超时,触发 ANR
        const nsecs_t nextAnrCheck = processAnrsLocked(); // 【2】
        nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck); 

        // 我们即将进入无限长的睡眠,因为我们没有命令或未决或排队的事件
        if (nextWakeupTime == LONG_LONG_MAX) {
            mDispatcherEnteredIdle.notify_all();
        }
    } // 释放锁

    // 等待回调或超时或唤醒。 (确保我们向上取整,而不是向下取整)
    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    mLooper->pollOnce(timeoutMillis);
}

在这个循环中,第一个方法是 dispatchOnceInnerLocked 函数,在这个函数中,进行了事件的分发:

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    // ...
    switch (mPendingEvent->type) {
        case EventEntry::Type::CONFIGURATION_CHANGED: { ... }
        case EventEntry::Type::DEVICE_RESET: { ... }
        case EventEntry::Type::FOCUS: { ... }
        case EventEntry::Type::TOUCH_MODE_CHANGED: { ... }
        case EventEntry::Type::POINTER_CAPTURE_CHANGED: { ... }
        case EventEntry::Type::DRAG: { ... }
        case EventEntry::Type::KEY: { ... }
        case EventEntry::Type::MOTION: {
            std::shared_ptr<MotionEntry> motionEntry =
                    std::static_pointer_cast<MotionEntry>(mPendingEvent);
            done = dispatchMotionLocked(currentTime, motionEntry, &dropReason, nextWakeupTime);
            break;
        }
        case EventEntry::Type::SENSOR: { ... }
    }

    if (done) {
        // ...
        releasePendingEventLocked();
        *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
    }
}

这里根据 EventEntry::Type 类型进行了不同的处理,完成了调度器的使命。

还有一点值得注意的是,如果事件等待太久,会调用 processAnrsLocked 触发 ANR 。

InputReader 的启动流程

InputReader 的 start 方法:

status_t InputReader::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    mThread = std::make_unique<InputThread>(
            "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
    return OK;
}

与 InputDispatcher 相同,也是创建了一个 InputThread 执行循环,loopOnce 函数:

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    std::vector<InputDeviceInfo> inputDevices;
    
    // ... 处理设备变化

    // 从 EventHub 读取事件数量
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { // acquire lock
        std::scoped_lock _l(mLock);
        mReaderIsAliveCondition.notify_all();
        if (count) {
            // 同步处理事件
            processEventsLocked(mEventBuffer, count);
        }
       // 处理超时
    // 处理设备变化
    } // release lock

    // 发出一个描述输入设备发生变化的消息
    if (inputDevicesChanged) {
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }
    // 将队列中的事件刷新到 listener
    mQueuedListener.flush();
}

在这个循环逻辑中,处理事件的逻辑来到了 processEventsLocked 方法中:

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    for (const RawEvent* rawEvent = rawEvents; count;) {
        int32_t type = rawEvent->type;
        size_t batchSize = 1;
      
       // 【1】 事件类型 < FIRST_SYNTHETIC_EVENT ,表示不是设备变化
       // FIRST_SYNTHETIC_EVENT = DEVICE_ADDED = 0x10000000 [添加设备时发送]
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
           // 事件对应的设备 id
            int32_t deviceId = rawEvent->deviceId;
            while (batchSize < count) { 
                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT ||
                    rawEvent[batchSize].deviceId != deviceId) {
                    break;
                }
                batchSize += 1;
            }
            if (DEBUG_RAW_EVENTS) {
                ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
            }
           // 处理设备事件
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {
           // 设备变化的事件
            switch (rawEvent->type) {
                case EventHubInterface::DEVICE_ADDED:
                    addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                case EventHubInterface::DEVICE_REMOVED:
                    removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                case EventHubInterface::FINISHED_DEVICE_SCAN:
                    handleConfigurationChangedLocked(rawEvent->when);
                    break;
                default:
                    ALOG_ASSERT(false); // can't happen
                    break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}

在这个处理事件的方法中,执行了一个 for 循环,挨个事件进行处理。根据事件的 type 进行判断,如果是设备变化的事件(type >= EventHubInterface::FIRST_SYNTHETIC_EVENT)则自身调用 addDeviceLocked、removeDeviceLocked 和 handleConfigurationChangedLocked 函数来处理;非输入设备变化的事件,通过 processEventsForDeviceLocked 函数处理:

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;
    }
    // 【1】
    device->process(rawEvents, count);
}

processEventsForDeviceLocked 函数中,通过事件中的 deviceId 来从设备中找到处理事件的设备,然后调用 【1】处的process 函数:

void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    // 按照每个 mapper 的顺序处理所有事件。[mapper 下文称映射器]
   // 我们不能简单地要求每个映射器批量处理它们,因为映射器可能有必须交替的副作用。例如,操纵杆移动事件和手柄按键按压由不同的映射器处理,但它们应该按照接收到的顺序分配。
    for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
        if (mDropUntilNextSync) {
            if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
                mDropUntilNextSync = false;  
            } 
        } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
            mDropUntilNextSync = true;
            reset(rawEvent->when);
        } else {
            for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {
                mapper.process(rawEvent);
            });
        }
        --count;
    }
}

InputReader 初始化时提到的它有一组 InputMappers ,mapper 在这里起了作用,调用了 process 方法来处理事件,mapper 有很多实现:

Android 输入系统【2】Native 层输入事件的处理机制
image-20221118112307938.png

这些实现实现了不同的功能,例如 TouchInputMapper 处理了触摸事件;SensorInputMapper 处理了传感器相关的事件;KeyboardInputMapper 处理了键盘输入。

以 TouchInputMapper 为例,最终调用到 dispatchMotion 方法,在这个方法中处理了 action 、坐标等 MotonEvent 相关的信息,最后通过 InputListener 发送出去:

void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t policyFlags,
                                      uint32_t source, int32_t action, int32_t actionButton,
                                      int32_t flags, int32_t metaState, int32_t buttonState,
                                      int32_t edgeFlags, const PointerProperties* properties,
                                      const PointerCoords* coords, const uint32_t* idToIndex,
                                      BitSet32 idBits, int32_t changedId, float xPrecision,
                                      float yPrecision, nsecs_t downTime)
 
{
    // ...                                    

    if (changedId >= 0 && pointerCount == 1) {
        // Replace initial down and final up action.
        // We can compare the action without masking off the changed pointer index
        // because we know the index is 0.
        if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
            action = AMOTION_EVENT_ACTION_DOWN;
        } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
            if ((flags & AMOTION_EVENT_FLAG_CANCELED) != 0) {
                action = AMOTION_EVENT_ACTION_CANCEL;
            } else {
                action = AMOTION_EVENT_ACTION_UP;
            }
        } else {
            ALOG_ASSERT(false);
        }
    }
    float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
    float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
    if (mDeviceMode == DeviceMode::POINTER) {
        mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
    }
    const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE);
    const int32_t deviceId = getDeviceId();
    std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
    std::for_each(frames.begin(), frames.end(),
                  [this](TouchVideoFrame& frame) { frame.rotate(this->mInputDeviceOrientation); });
    NotifyMotionArgs args(getContext()->getNextId(), when, readTime, deviceId, source, displayId,
                          policyFlags, action, actionButton, flags, metaState, buttonState,
                          MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,
                          pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,
                          downTime, std::move(frames))
;
    getListener().notifyMotion(&args);
}

上一篇文章提到 InputManager 中的组件将事件通过 InputListener 进行传递,在这里得到了验证:

InputReader -> UnwantedInteractionBlocker -> InputClassifier -> InputDispatcher

这里跳过 Blocker 和 Classifier ,直接看看 InputDispatcher 实现的 notifyMotion 方法:

void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
    if (!validateMotionEvent(args->action, args->actionButton, args->pointerCount, args->pointerProperties)) {
        return;
    }

    uint32_t policyFlags = args->policyFlags;
    policyFlags |= POLICY_FLAG_TRUSTED;

    android::base::Timer t;
    mPolicy->interceptMotionBeforeQueueing(args->displayId, args->eventTime, /*byref*/ policyFlags);
    bool needWake = false;
    { // acquire lock
        mLock.lock();

        if (shouldSendMotionToInputFilterLocked(args)) {
            ui::Transform displayTransform;
            if (const auto it = mDisplayInfos.find(args->displayId); it != mDisplayInfos.end()) {
                displayTransform = it->second.transform;
            }

            mLock.unlock();
            // 【1】构造 MotionEvent
            MotionEvent event;
            event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC,
                             args->action, args->actionButton, args->flags, args->edgeFlags,
                             args->metaState, args->buttonState, args->classification,
                             displayTransform, args->xPrecision, args->yPrecision,
                             args->xCursorPosition, args->yCursorPosition, displayTransform,
                             args->downTime, args->eventTime, args->pointerCount,
                             args->pointerProperties, args->pointerCoords);

            policyFlags |= POLICY_FLAG_FILTERED;
            if (!mPolicy->filterInputEvent(&event, policyFlags)) {
                return// event was consumed by the filter
            }

            mLock.lock();
        }

        // 创建 MotionEntry ,并将其加入事件队列
        std::unique_ptr<MotionEntry> newEntry =
                std::make_unique<MotionEntry>(args->id, args->eventTime, args->deviceId,
                                              args->source, args->displayId, policyFlags,
                                              args->action, args->actionButton, args->flags,
                                              args->metaState, args->buttonState,
                                              args->classification, args->edgeFlags,
                                              args->xPrecision, args->yPrecision,
                                              args->xCursorPosition, args->yCursorPosition,
                                              args->downTime, args->pointerCount,
                                              args->pointerProperties, args->pointerCoords);

        if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
            IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER &&
            !mInputFilterEnabled) {
            const bool isDown = args->action == AMOTION_EVENT_ACTION_DOWN;
            mLatencyTracker.trackListener(args->id, isDown, args->eventTime, args->readTime);
        }
        // 【2】入队
        needWake = enqueueInboundEventLocked(std::move(newEntry));
        mLock.unlock();
    } // release lock

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

核心只有两步:

  1. 构造 MotionEvent
  2. 创建 MotionEntry ,并将其加入事件队列

enqueueInboundEventLocked 为入队方法:

bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newEntry) {
    
    switch (entry.type) {
        case EventEntry::Type::KEY: {
            // ...
            break;
        }
        case EventEntry::Type::MOTION: {
            if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(entry))) {
                mNextUnblockedEvent = mInboundQueue.back();
                needWake = true;
            }
            break;
        }
        case EventEntry::Type::FOCUS: {
            break;
        }
        case EventEntry::Type::TOUCH_MODE_CHANGED:
        case EventEntry::Type::CONFIGURATION_CHANGED:
        case EventEntry::Type::DEVICE_RESET:
        case EventEntry::Type::SENSOR:
        case EventEntry::Type::POINTER_CAPTURE_CHANGED:
        case EventEntry::Type::DRAG: {
            // nothing to do
            break;
        }
    }

    return needWake;
}

到这一步,就和 InputDispatcher 中的轮询处理不同 EventEntry::Type 的逻辑打通了。

总结

IMS 启动后,在 Native 层通过 InputManager 来管理事件的处理流程,核心是 InputReader 和 InputDispatcher 。

InputReader 用来读取原始事件,它启动了一个 InputThread 线程,执行循环逻辑,从 EventHub 读取原始事件,查找对应的输入设备,并根据原始事件的类型分发给不同的 InputMapper ,InputMapper 最终通过 InputListener 通知给下一层处理(Blocker 、Classifier、Dispatcher)。

InputDispatcher 的主要作用是分发事件,它也启动了一个 InputThread 线程,执行调度循环,通过 InputListener 回调,来处理经过封装后的事件,这些事件将最终分发给各自的处理逻辑。


原文始发于微信公众号(八千里路山与海):Android 输入系统【2】Native 层输入事件的处理机制

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/85002.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!