InputManagerService:输入事件分发与ANR机制

引言

在前面的文章中,我们学习了AMS如何管理Activity生命周期,PMS如何管理应用安装,WMS如何管理窗口显示。但有一个关键问题:当用户触摸屏幕或按下按键时,这些输入事件是如何准确地传递到目标窗口的?

想象你点击屏幕上的一个按钮:

  1. 触摸屏硬件检测到触摸
  2. 系统如何知道你点击的是哪个窗口?
  3. 事件如何跨进程传递到应用?
  4. 如果应用处理太慢会发生什么?

这一切的答案都指向InputManagerService(IMS)------Android系统中负责输入事件管理的核心服务。

scss 复制代码
用户触摸屏幕
    ↓
触摸屏中断 → Input Driver
    ↓
/dev/input/eventX
    ↓
EventHub (epoll监听)
    ↓
InputReader (读取+解析)
    ↓
InputDispatcher (分发+ANR检测)
    ↓
InputChannel (Socket传输)
    ↓
应用进程 ViewRootImpl
    ↓
Activity/View 处理事件

如果继续用政府部门的比喻:

  • AMS是"劳动局",管理进程的工作和生命周期
  • PMS是"户籍管理局",管理应用的身份和权限
  • WMS是"城市规划局",管理窗口的位置和层级
  • IMS是"邮政局",负责把用户的"信件"(输入事件)准确投递到正确的"收件人"(窗口)

系列前置阅读:建议先阅读第18篇(WMS核心机制)和第19篇(WMS多窗口模式),理解窗口管理的基本概念。


IMS是什么?

IMS的核心职责

InputManagerService是Android系统中管理所有输入设备和输入事件的核心服务。它在SystemServer中作为核心服务启动,与WMS紧密协作。

职责 具体内容 关键组件
设备管理 监听输入设备的连接/断开 EventHub
事件读取 从设备节点读取原始事件 InputReader
事件分发 将事件分发到目标窗口 InputDispatcher
ANR检测 检测应用响应超时 InputDispatcher
策略控制 处理系统按键(如电源键) InputManagerCallback

IMS整体架构

图1: InputManagerService整体架构,展示了从Linux内核到应用层的完整层次结构

IMS的架构分为四层:

1. Linux Kernel层

  • 输入设备驱动(Touch/Keyboard/Mouse等)
  • 设备节点/dev/input/eventX
  • 通过evdev接口提供标准化的事件格式

2. Native层(C++)

  • EventHub: 使用epoll监听所有输入设备节点
  • InputReader: 从EventHub读取原始事件,解析成标准格式
  • InputDispatcher: 查找目标窗口,分发事件,检测ANR

3. Framework层(Java)

  • InputManagerService: 系统服务的Java入口
  • WindowManagerService: 提供窗口信息给InputDispatcher

4. Application层

  • InputEventReceiver: 接收来自InputDispatcher的事件
  • ViewRootImpl: 开始View树的事件分发
  • Activity/View: 应用代码处理事件

Android 15的输入系统优化

优化项 Android 14及之前 Android 15
输入延迟 平均8-12ms 平均4-6ms
高刷屏支持 基础支持 输入采样与刷新率同步
手写笔 基础支持 预测算法优化,延迟降低30%
ANR检测 固定5秒超时 动态调整+更精确的诊断
多设备 基础支持 更好的多输入设备并发处理

IMS启动流程

SystemServer中的启动

IMS在SystemServer的startOtherServices()阶段启动,并与WMS紧密关联:

java 复制代码
// SystemServer.java (Android 15)
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    // ...

    t.traceBegin("StartInputManagerService");
    // 创建IMS实例
    inputManager = new InputManagerService(context);
    t.traceEnd();

    t.traceBegin("StartWindowManagerService");
    // 创建WMS,传入IMS引用
    // WMS和IMS需要相互配合:
    // - WMS告诉IMS当前的窗口布局
    // - IMS告诉WMS输入焦点变化
    wm = WindowManagerService.main(context, inputManager, ...);
    t.traceEnd();

    // 设置IMS的回调,用于处理系统按键等
    t.traceBegin("SetWindowManagerService");
    inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
    inputManager.start();  // 启动Native层的InputReader和InputDispatcher线程
    t.traceEnd();

    // ...
}

IMS初始化详解

java 复制代码
// frameworks/base/services/core/java/com/android/server/input/InputManagerService.java (Android 15)
public class InputManagerService extends IInputManager.Stub
        implements Watchdog.Monitor {
    static final String TAG = "InputManager";

    private final NativeInputManagerService mNative;
    private final Context mContext;
    private final InputManagerHandler mHandler;

    public InputManagerService(Context context) {
        this(new Injector(context, DisplayThread.get().getLooper(), new UEventManager() {}));
    }

    @VisibleForTesting
    InputManagerService(Injector injector) {
        // The static association map is accessed by both java and native code, so it must be
        // initialized before initializing the native service.
        mStaticAssociations = loadStaticInputPortAssociations();

        mContext = injector.getContext();
        mHandler = new InputManagerHandler(injector.getLooper());
        mNative = injector.getNativeService(this);
        mSettingsObserver = new InputSettingsObserver(mContext, mHandler, this, mNative);
        mKeyboardLayoutManager = new KeyboardLayoutManager(mContext, mNative, mDataStore,
                injector.getLooper());
        mBatteryController = new BatteryController(mContext, mNative, injector.getLooper(),
                injector.getUEventManager());
        mKeyboardBacklightController = injector.getKeyboardBacklightController(mNative, mDataStore);
        mStickyModifierStateController = new StickyModifierStateController();
        mKeyGestureController = new KeyGestureController(mContext, injector.getLooper());
        // ... 其他控制器初始化
    }

    public void start() {
        Slog.i(TAG, "Starting input manager");
        // 启动Native层的InputReader和InputDispatcher线程
        mNative.start();

        // Add ourselves to the Watchdog monitors.
        // 如果IMS卡死,Watchdog会触发系统重启
        Watchdog.getInstance().addMonitor(this);
    }

    // 系统完全启动后调用
    public void systemRunning() {
        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
        mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);

        mSettingsObserver.registerAndUpdate();
        // ... 初始化各种开关状态
    }
}

Native层初始化

cpp 复制代码
// com_android_server_input_InputManagerService.cpp (Android 15)
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {

    // 获取消息队列的Looper
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    sp<Looper> looper = messageQueue->getLooper();

    // 创建NativeInputManager
    // 这是Java层和Native层的桥梁
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, looper);

    // 设置为强引用,防止被回收
    im->incStrong(0);

    return reinterpret_cast<jlong>(im);
}

// NativeInputManager构造函数
NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) {

    // 保存Java对象引用
    mServiceObj = env->NewGlobalRef(serviceObj);

    // 创建InputManager(包含EventHub、InputReader、InputDispatcher)
    mInputManager = new InputManager(this, this);
}

InputReader:事件读取

EventHub设备监听

EventHub是输入系统的最底层,负责监听所有输入设备:

cpp 复制代码
// EventHub.cpp (Android 15)
EventHub::EventHub(void) :
        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),
        mNextDeviceId(1),
        mOpeningDevices(0),
        mClosingDevices(0) {

    // 创建epoll实例,用于高效监听多个文件描述符
    mEpollFd = epoll_create1(EPOLL_CLOEXEC);

    // 创建inotify,监听/dev/input目录的变化
    // 当有新设备连接或断开时会收到通知
    mINotifyFd = inotify_init1(IN_CLOEXEC);

    // 监听/dev/input目录
    // IN_CREATE: 新设备文件创建(设备连接)
    // IN_DELETE: 设备文件删除(设备断开)
    mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);

    // 将inotify加入epoll监听
    struct epoll_event eventItem = {};
    eventItem.events = EPOLLIN | EPOLLWAKEUP;
    eventItem.data.fd = mINotifyFd;
    epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);

    // 创建唤醒管道,用于主动唤醒epoll_wait
    int wakeFds[2];
    pipe2(wakeFds, O_CLOEXEC | O_NONBLOCK);
    mWakeReadPipeFd = wakeFds[0];
    mWakeWritePipeFd = wakeFds[1];

    // 将唤醒管道加入epoll监听
    eventItem.data.fd = mWakeReadPipeFd;
    epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
}

// 获取输入事件
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    size_t count = 0;

    for (;;) {
        // 处理待关闭的设备
        while (mClosingDevices) {
            Device* device = mClosingDevices;
            mClosingDevices = device->next;
            // 生成设备移除事件
            event->when = systemTime(SYSTEM_TIME_MONOTONIC);
            event->deviceId = device->id;
            event->type = DEVICE_REMOVED;
            event += 1;
            count++;
            delete device;
        }

        // 处理待打开的设备
        while (mOpeningDevices != nullptr) {
            Device* device = mOpeningDevices;
            mOpeningDevices = device->next;
            // 生成设备添加事件
            event->when = systemTime(SYSTEM_TIME_MONOTONIC);
            event->deviceId = device->id;
            event->type = DEVICE_ADDED;
            event += 1;
            count++;
        }

        // 读取设备事件
        for (auto& [_, device] : mDevices) {
            if (device->fd >= 0) {
                struct input_event readBuffer[256];
                // 从设备文件读取事件
                int32_t readSize = read(device->fd, readBuffer, sizeof(readBuffer));
                if (readSize > 0) {
                    // 转换为RawEvent格式
                    for (size_t i = 0; i < numEvents; i++) {
                        event->when = ...;
                        event->deviceId = device->id;
                        event->type = readBuffer[i].type;
                        event->code = readBuffer[i].code;
                        event->value = readBuffer[i].value;
                        event++;
                        count++;
                    }
                }
            }
        }

        if (count > 0) {
            return count;
        }

        // 没有事件,使用epoll等待
        int pollResult = epoll_wait(mEpollFd, mPendingEventItems,
                                    EPOLL_MAX_EVENTS, timeoutMillis);

        // 处理epoll返回的事件...
    }
}

InputReader事件处理

InputReader在独立线程中循环读取和处理事件:

cpp 复制代码
// frameworks/native/services/inputflinger/reader/InputReader.cpp (Android 15)
InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
                         const sp<InputReaderPolicyInterface>& policy,
                         InputListenerInterface& listener)
      : mContext(this),
        mEventHub(eventHub),
        mPolicy(policy),
        mNextListener(listener),
        mKeyboardClassifier(std::make_unique<KeyboardClassifier>()),
        mGlobalMetaState(AMETA_NONE),
        mLedMetaState(AMETA_NONE),
        mGeneration(1),
        mNextInputDeviceId(END_RESERVED_ID),
        mDisableVirtualKeysTimeout(LLONG_MIN),
        mNextTimeout(LLONG_MAX),
        mConfigurationChangesToRefresh(0) {
    refreshConfigurationLocked(/*changes=*/{});
    updateGlobalMetaStateLocked();
}

status_t InputReader::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    // 创建InputReader线程,循环调用loopOnce
    mThread = std::make_unique<InputThread>(
            "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
    return OK;
}

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    std::vector<InputDeviceInfo> inputDevices;
    std::list<NotifyArgs> notifyArgs;

    { // acquire lock
        std::scoped_lock _l(mLock);

        oldGeneration = mGeneration;
        timeoutMillis = -1;

        // 检查配置变化
        uint32_t changes = mConfigurationChangesToRefresh;
        if (changes) {
            mConfigurationChangesToRefresh = 0;
            timeoutMillis = 0;
            refreshConfigurationLocked(changes);
        }
        // ... 后续处理事件并通知InputDispatcher
    }
}

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
        switch (rawEvent->type) {
        case DEVICE_ADDED:
            // 新设备连接,创建对应的InputDevice和InputMapper
            addDeviceLocked(rawEvent->when, rawEvent->deviceId);
            break;

        case DEVICE_REMOVED:
            // 设备断开,移除对应的InputDevice
            removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
            break;

        default:
            // 普通输入事件,交给对应设备的Mapper处理
            processEventsForDeviceLocked(deviceId, rawEvent, 1);
            break;
        }
    }
}

// InputMapper将原始事件转换为Android标准事件
// 例如TouchInputMapper处理触摸事件
void TouchInputMapper::process(const RawEvent* rawEvent) {
    // 根据事件类型处理
    if (rawEvent->type == EV_ABS) {
        // 绝对坐标事件(触摸屏)
        switch (rawEvent->code) {
        case ABS_MT_POSITION_X:
            // 多点触摸X坐标
            mCurrentSlot.mAbsMTPositionX = rawEvent->value;
            break;
        case ABS_MT_POSITION_Y:
            // 多点触摸Y坐标
            mCurrentSlot.mAbsMTPositionY = rawEvent->value;
            break;
        case ABS_MT_TRACKING_ID:
            // 触摸点ID
            mCurrentSlot.mAbsMTTrackingId = rawEvent->value;
            break;
        // ... 其他触摸属性
        }
    } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
        // SYN_REPORT表示一帧事件结束,开始处理
        sync(rawEvent->when);
    }
}

void TouchInputMapper::sync(nsecs_t when) {
    // 将原始触摸数据转换为MotionEvent
    // 包括:坐标映射、多点触摸合并、手势识别等

    // 通知InputDispatcher
    NotifyMotionArgs args(mContext->getNextId(), when, ...);
    getListener().notifyMotion(&args);
}

InputDispatcher:事件分发

分发流程概述

图2: 输入事件从硬件到应用的完整分发流程

InputDispatcher是输入系统的核心,负责:

  1. 查找目标窗口
  2. 将事件分发到目标窗口
  3. 检测ANR超时
cpp 复制代码
// frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp (Android 15)
void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LLONG_MAX;
    { // acquire lock
        std::scoped_lock _l(mLock);
        mDispatcherIsAlive.notify_all();

        // Run a dispatch loop if there are no pending commands.
        // The dispatch loop might enqueue commands to run afterwards.
        if (!haveCommandsLocked()) {
            dispatchOnceInnerLocked(/*byref*/ nextWakeupTime);
        }

        // Run all pending commands if there are any.
        // If any commands were run then force the next poll to wake up immediately.
        if (runCommandsLockedInterruptable()) {
            nextWakeupTime = LLONG_MIN;
        }

        // If we are still waiting for ack on some events,
        // we might have to wake up earlier to check if an app is anr'ing.
        const nsecs_t nextAnrCheck = processAnrsLocked();
        nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);

        // We are about to enter an infinitely long sleep, because we have no commands or
        // pending or queued events
        if (nextWakeupTime == LLONG_MAX) {
            mDispatcherEnteredIdle.notify_all();
        }
    } // release lock

    // Wait for callback or timeout or wake. (make sure we round up, not down)
    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    mLooper->pollOnce(timeoutMillis);
}

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    // 从队列取出事件
    mPendingEvent = mInboundQueue.front();
    mInboundQueue.pop_front();

    // 根据事件类型分发
    switch (mPendingEvent->type) {
    case EventEntry::Type::MOTION: {
        // 触摸/鼠标事件
        MotionEntry& motionEntry = static_cast<MotionEntry&>(*mPendingEvent);
        done = dispatchMotionLocked(currentTime, motionEntry, ...);
        break;
    }
    case EventEntry::Type::KEY: {
        // 按键事件
        KeyEntry& keyEntry = static_cast<KeyEntry&>(*mPendingEvent);
        done = dispatchKeyLocked(currentTime, keyEntry, ...);
        break;
    }
    // ...
    }
}

查找目标窗口

cpp 复制代码
// InputDispatcher.cpp
InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
        nsecs_t currentTime, const MotionEntry& entry,
        std::vector<InputTarget>& inputTargets, ...) {

    // 1. 获取触摸点坐标
    int32_t x = entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
    int32_t y = entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
    int32_t displayId = entry.displayId;

    // 2. 遍历窗口列表,查找触摸点所在的窗口
    // 窗口列表由WMS提供,按Z-order从上到下排列
    for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
        const WindowInfo& windowInfo = *windowHandle->getInfo();

        // 检查窗口是否可见、可触摸
        if (!windowInfo.isVisible() ||
            !windowInfo.isTouchable() ||
            windowInfo.inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE)) {
            continue;
        }

        // 检查触摸点是否在窗口区域内
        // 需要考虑窗口的变换矩阵(缩放、旋转等)
        if (!windowInfo.touchableRegionContainsPoint(x, y)) {
            continue;
        }

        // 找到目标窗口!
        newTouchedWindowHandle = windowHandle;
        break;
    }

    // 3. 如果没有找到目标窗口
    if (newTouchedWindowHandle == nullptr) {
        // 可能是点击了壁纸或系统装饰区域
        // 根据策略决定是否丢弃或发送给特定窗口
        ...
    }

    // 4. 构建InputTarget
    if (newTouchedWindowHandle != nullptr) {
        InputTarget target;
        target.inputChannel = newTouchedWindowHandle->getInputChannel();
        target.flags = InputTarget::FLAG_FOREGROUND;
        // 设置坐标变换矩阵
        target.setDefaultPointerTransform(windowInfo.transform);
        inputTargets.push_back(target);
    }

    return InputEventInjectionResult::SUCCEEDED;
}

事件发送与InputChannel

cpp 复制代码
// InputDispatcher.cpp
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        std::shared_ptr<EventEntry> eventEntry,
        const std::vector<InputTarget>& inputTargets) {

    for (const InputTarget& inputTarget : inputTargets) {
        // 获取目标窗口的Connection
        // Connection封装了与应用进程通信的InputChannel
        sp<Connection> connection = getConnectionLocked(inputTarget.inputChannel);

        if (connection != nullptr) {
            // 准备发送
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
        }
    }
}

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection) {

    while (connection->status == Connection::Status::NORMAL
           && !connection->outboundQueue.empty()) {

        DispatchEntry* dispatchEntry = connection->outboundQueue.front();

        // 序列化事件
        InputMessage msg;
        switch (eventEntry.type) {
        case EventEntry::Type::MOTION: {
            MotionEntry& motionEntry = static_cast<MotionEntry&>(eventEntry);
            // 填充MotionEvent数据
            msg.header.type = InputMessage::Type::MOTION;
            msg.body.motion.eventTime = motionEntry.eventTime;
            msg.body.motion.action = motionEntry.action;
            msg.body.motion.pointerCount = motionEntry.pointerCount;
            // ... 填充坐标等信息
            break;
        }
        // ...
        }

        // 通过InputChannel发送
        // InputChannel底层是Unix Socket
        status_t status = connection->inputPublisher.publishMotionEvent(...);

        if (status == OK) {
            // 发送成功,移动到等待队列
            // 等待应用返回finish信号
            connection->outboundQueue.erase(connection->outboundQueue.begin());
            connection->waitQueue.push_back(dispatchEntry);

            // 启动ANR计时!
            // 如果应用在规定时间内没有响应,将触发ANR
            traceOutboundQueueLength(*connection);
        }
    }
}

InputChannel通信机制

InputChannel是IMS和应用进程之间的通信桥梁:

cpp 复制代码
// InputChannel.cpp (Android 15)
status_t InputChannel::openInputChannelPair(const std::string& name,
        std::unique_ptr<InputChannel>& outServerChannel,
        std::unique_ptr<InputChannel>& outClientChannel) {

    // 创建Unix Domain Socket对
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
        return -errno;
    }

    // 设置缓冲区大小
    // 需要足够大以避免阻塞
    int bufferSize = SOCKET_BUFFER_SIZE;
    setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));

    // 创建Server端Channel(给InputDispatcher使用)
    outServerChannel = InputChannel::create(name + " (server)",
                                            base::unique_fd(sockets[0]), ...);

    // 创建Client端Channel(给应用进程使用)
    outClientChannel = InputChannel::create(name + " (client)",
                                            base::unique_fd(sockets[1]), ...);

    return OK;
}

// 发送消息
status_t InputPublisher::publishMotionEvent(...) {
    InputMessage msg;
    msg.header.type = InputMessage::Type::MOTION;
    msg.header.seq = seq;
    // ... 填充消息内容

    // 通过socket发送
    return mChannel->sendMessage(&msg);
}

status_t InputChannel::sendMessage(const InputMessage* msg) {
    const size_t msgLength = msg->size();

    // 使用send发送,SOCK_SEQPACKET保证消息边界
    ssize_t nWrite;
    do {
        nWrite = ::send(getFd(), msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == -1 && errno == EINTR);

    if (nWrite != msgLength) {
        return -errno;
    }
    return OK;
}

ANR检测机制

什么是输入ANR?

ANR(Application Not Responding)是Android系统对无响应应用的一种保护机制。当应用在规定时间内没有处理完输入事件时,系统会认为应用"卡死"了。

图3: 输入事件ANR检测机制,展示了从事件发送到ANR触发的完整流程

ANR超时阈值

cpp 复制代码
// frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp (Android 15)
// Default input dispatching timeout if there is no focused application or paused window
// from which to determine an appropriate dispatching timeout.
const std::chrono::duration DEFAULT_INPUT_DISPATCHING_TIMEOUT = std::chrono::milliseconds(
        android::os::IInputConstants::UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
        HwTimeoutMultiplier());

// IInputConstants.UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS = 5000ms
// HwTimeoutMultiplier() 在普通设备上返回1,在调试环境可能返回更大值

// 详细的超时类型:
// 1. 按键事件: 5秒(可由窗口自定义)
// 2. 触摸事件: 5秒(可由窗口自定义)
// 3. 窗口焦点获取: 5秒
// 4. 无焦点窗口: 等待焦点窗口出现的超时也是5秒

ANR检测实现

cpp 复制代码
// frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp (Android 15)

/**
 * Check if any of the connections' wait queues have events that are too old.
 * If we waited for events to be ack'ed for more than the window timeout, raise an ANR.
 * Return the time at which we should wake up next.
 */
nsecs_t InputDispatcher::processAnrsLocked() {
    const nsecs_t currentTime = now();
    nsecs_t nextAnrCheck = LLONG_MAX;

    // Check if we are waiting for a focused window to appear. Raise ANR if waited too long
    if (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) {
        if (currentTime >= *mNoFocusedWindowTimeoutTime) {
            processNoFocusedWindowAnrLocked();
            mAwaitedFocusedApplication.reset();
            mNoFocusedWindowTimeoutTime = std::nullopt;
            return LLONG_MIN;
        } else {
            // Keep waiting. We will drop the event when mNoFocusedWindowTimeoutTime comes.
            nextAnrCheck = *mNoFocusedWindowTimeoutTime;
        }
    }

    // Check if any connection ANRs are due
    // 使用AnrTracker追踪所有等待响应的事件
    nextAnrCheck = std::min(nextAnrCheck, mAnrTracker.firstTimeout());
    if (currentTime < nextAnrCheck) { // most likely scenario
        return nextAnrCheck;          // everything is normal. Let's check again at nextAnrCheck
    }

    // If we reached here, we have an unresponsive connection.
    std::shared_ptr<Connection> connection = getConnectionLocked(mAnrTracker.firstToken());
    if (connection == nullptr) {
        ALOGE("Could not find connection for entry %" PRId64, mAnrTracker.firstTimeout());
        return nextAnrCheck;
    }
    connection->responsive = false;
    // Stop waking up for this unresponsive connection
    mAnrTracker.eraseToken(connection->getToken());
    onAnrLocked(connection);
    return LLONG_MIN;
}

void InputDispatcher::processConnectionUnresponsiveLocked(
        Connection& connection, std::string reason) {

    // 1. 标记Connection为不响应状态
    connection.responsive = false;

    // 2. 收集ANR信息
    // 包括: 窗口信息、等待时间、待处理事件数等
    std::shared_ptr<InputApplicationHandle> application =
            getApplicationHandleLocked(connection.inputChannel);

    // 3. 调用policy上报ANR
    // 这会触发ANR对话框的显示
    mPolicy.notifyUnresponsiveWindow(connection.inputChannel->getToken(),
                                     connection.pid,
                                     std::move(reason));

    // 4. 丢弃该连接的后续事件
    // 避免事件堆积
    releaseDispatchedEntryLocked(connection);
}

ANR信息收集

java 复制代码
// InputManagerService.java (Android 15)
// ANR信息会回调到Java层处理
private void notifyUnresponsiveWindow(IBinder token, int pid, String reason) {
    // 转发给WindowManagerService处理
    mWindowManagerCallbacks.notifyUnresponsiveWindow(token, pid, reason);
}

// WindowManagerService.java
void notifyInputManagerOfUnresponsiveWindow(IBinder token, int pid, String reason) {
    // 最终触发ANR处理流程
    mAmInternal.inputDispatchingTimedOut(
            pid,
            false /* aboveSystem */,
            reason);
}

// ActivityManagerService.java
public boolean inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason) {
    // 1. 获取进程信息
    ProcessRecord proc = mPidsSelfLocked.get(pid);

    // 2. 收集堆栈信息
    // 生成traces.txt
    File tracesFile = ActivityManagerService.dumpStackTraces(
            firstPids, processCpuTracker, ...);

    // 3. 显示ANR对话框
    mUiHandler.post(() -> {
        handleShowAnrUi(new AnrRecord(proc, reason, firstPids, ...));
    });

    // 4. 记录到DropBox
    addErrorToDropBox("anr", proc, ...);

    return true;
}

Android 15 ANR优化

Android 15在ANR检测方面做了重要改进:

cpp 复制代码
// InputDispatcher.cpp (Android 15)
// 新增: 更精确的ANR诊断
void InputDispatcher::processConnectionUnresponsiveLocked(...) {
    // Android 15新增: 收集更详细的诊断信息
    AnrTracker::AnrInfo anrInfo;

    // 1. 记录最后一个被处理的事件
    anrInfo.lastProcessedEventTime = connection.lastEventFinishTime;

    // 2. 记录当前等待的事件数量
    anrInfo.pendingEventCount = connection.waitQueue.size();

    // 3. 记录输入管道状态
    anrInfo.inputChannelStatus = connection.inputPublisher.getStatus();

    // 4. 检查是否因为GPU渲染导致
    // Android 15新增: 与RenderThread协作诊断
    anrInfo.gpuCompletion = checkGpuCompletion(connection);

    // 5. 记录主线程状态
    // 帮助开发者快速定位问题
    anrInfo.mainThreadState = captureMainThreadState(connection.pid);

    mPolicy.notifyUnresponsiveWindow(..., anrInfo);
}

// Android 15新增: 动态超时调整
std::chrono::nanoseconds InputDispatcher::getTimeoutForConnection(
        const Connection& connection) {
    // 根据应用状态动态调整超时
    if (connection.inputPublisherBlocked) {
        // 如果发送通道阻塞,使用更短超时
        return 500ms;
    }

    if (isDebuggable(connection.pid)) {
        // 如果是可调试应用,给更长时间
        // 方便开发者调试
        return 60s;
    }

    // 默认5秒
    return DEFAULT_INPUT_DISPATCHING_TIMEOUT;
}

应用层事件处理

InputEventReceiver接收事件

java 复制代码
// InputEventReceiver.java (Android 15)
public abstract class InputEventReceiver {
    // Native层指针
    private long mReceiverPtr;

    // InputChannel客户端
    private InputChannel mInputChannel;

    public InputEventReceiver(InputChannel inputChannel, Looper looper) {
        mInputChannel = inputChannel;
        mMessageQueue = looper.getQueue();

        // 初始化Native层
        // 将InputChannel的fd加入Looper监听
        mReceiverPtr = nativeInit(new WeakReference<>(this),
                inputChannel, mMessageQueue);
    }

    // 当有事件到达时,由Native层回调
    // Called from native code
    private void dispatchInputEvent(int seq, InputEvent event) {
        // 默认实现是立即完成
        // 子类(如WindowInputEventReceiver)会覆盖此方法
        onInputEvent(event);
        finishInputEvent(event, true);
    }

    // 通知InputDispatcher事件已处理
    public final void finishInputEvent(InputEvent event, boolean handled) {
        nativeFinishInputEvent(mReceiverPtr, seq, handled);
    }
}

ViewRootImpl事件分发

java 复制代码
// ViewRootImpl.java (Android 15)
final class WindowInputEventReceiver extends InputEventReceiver {
    @Override
    public void onInputEvent(InputEvent event) {
        // 包装事件,加入处理队列
        enqueueInputEvent(event, this, 0, true);
    }
}

void enqueueInputEvent(InputEvent event, InputEventReceiver receiver,
        int flags, boolean processImmediately) {
    // 创建QueuedInputEvent
    QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);

    // 加入队列尾部
    QueuedInputEvent last = mPendingInputEventTail;
    if (last == null) {
        mPendingInputEventHead = q;
        mPendingInputEventTail = q;
    } else {
        last.mNext = q;
        mPendingInputEventTail = q;
    }
    mPendingInputEventCount++;

    // 立即处理或异步处理
    if (processImmediately) {
        doProcessInputEvents();
    } else {
        scheduleProcessInputEvents();
    }
}

void doProcessInputEvents() {
    while (mPendingInputEventHead != null) {
        QueuedInputEvent q = mPendingInputEventHead;
        mPendingInputEventHead = q.mNext;

        // 通过InputStage责任链处理事件
        deliverInputEvent(q);
    }
}

private void deliverInputEvent(QueuedInputEvent q) {
    InputEvent event = q.mEvent;

    // InputStage责任链:
    // 1. NativePreImeInputStage - 原生预IME处理
    // 2. ViewPreImeInputStage - View预IME处理
    // 3. ImeInputStage - 输入法处理
    // 4. EarlyPostImeInputStage - IME后早期处理
    // 5. NativePostImeInputStage - 原生IME后处理
    // 6. ViewPostImeInputStage - View树分发(最重要!)
    // 7. SyntheticInputStage - 合成事件处理

    InputStage stage = mFirstInputStage;
    if (stage != null) {
        stage.deliver(q);
    }
}

View树事件分发

java 复制代码
// ViewPostImeInputStage处理触摸事件
final class ViewPostImeInputStage extends InputStage {
    @Override
    protected int onProcess(QueuedInputEvent q) {
        if (q.mEvent instanceof MotionEvent) {
            return processPointerEvent(q);
        }
        return FORWARD;
    }

    private int processPointerEvent(QueuedInputEvent q) {
        MotionEvent event = (MotionEvent) q.mEvent;

        // 分发给DecorView开始View树分发
        boolean handled = mView.dispatchPointerEvent(event);

        return handled ? FINISH_HANDLED : FORWARD;
    }
}

// View.java
public final boolean dispatchPointerEvent(MotionEvent event) {
    if (event.isTouchEvent()) {
        return dispatchTouchEvent(event);
    } else {
        return dispatchGenericMotionEvent(event);
    }
}

// ViewGroup.java - 事件分发核心逻辑
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    boolean handled = false;

    // 1. 检查是否拦截
    boolean intercepted = onInterceptTouchEvent(ev);

    if (!intercepted) {
        // 2. 查找子View处理
        for (int i = childrenCount - 1; i >= 0; i--) {
            View child = children[i];

            // 检查触摸点是否在子View区域内
            if (!child.canReceivePointerEvents() ||
                !isTransformedTouchPointInView(x, y, child, null)) {
                continue;
            }

            // 分发给子View
            if (dispatchTransformedTouchEvent(ev, child)) {
                // 子View处理了事件
                mFirstTouchTarget = child;
                handled = true;
                break;
            }
        }
    }

    // 3. 如果没有子View处理,自己处理
    if (!handled) {
        handled = super.dispatchTouchEvent(ev);
    }

    return handled;
}

实战:调试与问题诊断

dumpsys input分析

bash 复制代码
# 查看输入系统整体状态
adb shell dumpsys input

# 输出示例:
INPUT MANAGER (dumpsys input)

Event Hub State:
  # 已连接的输入设备
  Device 1: sec_touchscreen
    Path: /dev/input/event2
    Classes: 0x00000015 (TOUCH | TOUCH_MT | EXTERNAL_STYLUS)
    Enabled: true

Input Reader State:
  # 各设备的状态
  Device 1: sec_touchscreen
    Generation: 2
    IsExternal: false
    Sources: TOUCHSCREEN | STYLUS
    # 触摸屏参数
    Touch Input Mapper:
      Parameters:
        GestureMode: MULTI_TOUCH
        DeviceType: TOUCH_SCREEN
        OrientationAware: true

Input Dispatcher State:
  # 分发状态
  DispatchEnabled: true
  DispatchFrozen: false

  # 焦点窗口
  FocusedDisplayId: 0
  FocusedApplications:
    displayId=0, name='com.example.app'

  # 焦点窗口
  FocusedWindows:
    displayId=0, name='com.example.app/MainActivity'

  # 等待响应的Connection(可能ANR)
  Connections:
    0: channelName='com.example.app/MainActivity (server)'
      status=NORMAL, monitor=false
      outboundQueue length=0
      waitQueue length=1  # 有1个事件在等待响应!

getevent实时监听

bash 复制代码
# 查看所有输入设备
adb shell getevent -pl

# 实时监听触摸事件(带时间戳)
adb shell getevent -lt /dev/input/event2

# 输出示例:
[    1234.567890] /dev/input/event2: EV_ABS ABS_MT_TRACKING_ID 00000001
[    1234.567890] /dev/input/event2: EV_ABS ABS_MT_POSITION_X  000001f4
[    1234.567890] /dev/input/event2: EV_ABS ABS_MT_POSITION_Y  00000320
[    1234.567890] /dev/input/event2: EV_ABS ABS_MT_PRESSURE    00000064
[    1234.567890] /dev/input/event2: EV_SYN SYN_REPORT         00000000

ANR问题诊断

bash 复制代码
# 1. 查看ANR日志
adb logcat -b events | grep anr
# 或
adb logcat | grep "ANR in"

# 2. 获取ANR traces
adb pull /data/anr/traces.txt

# 3. 分析traces.txt
# 重点关注主线程(main)的堆栈
# 常见ANR原因:
# - 主线程执行耗时操作(网络/数据库/文件IO)
# - 主线程等待锁
# - 主线程Binder调用阻塞
# - 系统资源不足

# 4. 使用strictmode检测
adb shell setprop debug.strict.mode 1

常见问题与解决方案

问题1: 触摸不响应

bash 复制代码
# 1. 检查设备是否识别
adb shell getevent -pl

# 2. 检查EventHub
adb shell dumpsys input | grep -A 20 "Event Hub State"

# 3. 检查窗口是否可触摸
adb shell dumpsys input | grep "Touchable"

# 解决方案:
# - 检查设备驱动
# - 检查窗口FLAG_NOT_TOUCHABLE
# - 检查触摸区域是否被遮挡

问题2: 输入延迟高

bash 复制代码
# 1. 使用systrace分析
python systrace.py -o trace.html input view

# 2. 检查主线程耗时
# 在trace中查找InputDispatcher -> ViewRootImpl的延迟

# 解决方案:
# - 减少主线程工作
# - 使用硬件加速
# - 优化View层级

问题3: 频繁ANR

java 复制代码
// 解决方案1: 耗时操作移到后台线程
new Thread(() -> {
    // 耗时操作
    runOnUiThread(() -> {
        // 更新UI
    });
}).start();

// 解决方案2: 使用HandlerThread
HandlerThread handlerThread = new HandlerThread("Worker");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
handler.post(() -> {
    // 耗时操作
});

// 解决方案3: 优化事件处理
@Override
public boolean onTouchEvent(MotionEvent event) {
    // 避免在这里做耗时操作!
    // 只做必要的状态更新
    return super.onTouchEvent(event);
}

Android 15输入系统新特性

1. 输入延迟优化

cpp 复制代码
// Android 15: 输入预测算法
// 在高刷新率屏幕上,通过预测减少感知延迟

// InputReader.cpp
void TouchInputMapper::processMotion(nsecs_t when, ...) {
    // Android 15新增: 触摸预测
    if (mConfig.touchPrediction) {
        // 基于历史轨迹预测下一个触摸点
        MotionPrediction prediction = predictNextPosition(
                mLastTouchPoints, mVelocityTracker);

        // 将预测点也加入事件
        notifyMotion(..., prediction);
    }
}

2. 手写笔支持增强

java 复制代码
// Android 15: 手写笔低延迟模式
// frameworks/base/core/java/android/view/MotionEvent.java

public class MotionEvent {
    // Android 15新增: 获取手写笔预测点
    public MotionEvent.PointerCoords getPredictedCoords(int pointerIndex) {
        return nativeGetPredictedCoords(mNativePtr, pointerIndex);
    }

    // Android 15新增: 手写笔倾斜和方位角
    public float getAxisValue(int axis, int pointerIndex) {
        // AXIS_TILT - 倾斜角度
        // AXIS_ORIENTATION - 方位角
        // 用于实现更自然的书写效果
    }
}

3. 多设备输入改进

java 复制代码
// Android 15: 更好的多设备支持
// 同时处理触摸、鼠标、键盘输入

// InputManagerService.java
public void onInputDevicesChanged(InputDevice[] devices) {
    // Android 15新增: 智能输入模式切换
    for (InputDevice device : devices) {
        if (device.isExternal()) {
            // 外接设备连接
            // 自动调整输入策略
            updateInputPolicyForDevice(device);
        }
    }
}

总结

本文深入分析了Android 15 InputManagerService的核心机制:

核心要点回顾

  1. 架构分层:

    • Kernel层提供设备驱动和事件接口
    • Native层(EventHub/InputReader/InputDispatcher)实现核心逻辑
    • Framework层(IMS)提供Java API
    • Application层接收和处理事件
  2. 事件流转:

    • 硬件中断 → Input Driver → /dev/input/eventX
    • EventHub(epoll) → InputReader(解析) → InputDispatcher(分发)
    • InputChannel(Socket) → InputEventReceiver → ViewRootImpl → View树
  3. ANR机制:

    • 默认5秒超时
    • InputDispatcher检测响应超时
    • 收集堆栈、显示对话框、记录日志
  4. Android 15优化:

    • 输入延迟从8-12ms降到4-6ms
    • 手写笔预测算法优化
    • ANR诊断信息更详细

参考资料

源码路径 (Android 15 AOSP)

bash 复制代码
frameworks/native/services/inputflinger/
├── InputManager.cpp                    # 输入管理器(组合InputReader和InputDispatcher)
├── InputManager.h
├── InputThread.cpp                     # InputReader/Dispatcher线程封装
├── reader/
│   ├── EventHub.cpp                    # 设备监听(epoll+inotify)
│   ├── InputReader.cpp                 # 事件读取主循环
│   ├── InputDevice.cpp                 # 输入设备抽象
│   └── mapper/
│       ├── TouchInputMapper.cpp        # 触摸事件映射
│       └── KeyboardInputMapper.cpp     # 键盘事件映射
├── dispatcher/
│   ├── InputDispatcher.cpp             # 事件分发核心(334KB, 8000+行)
│   ├── InputDispatcher.h
│   ├── AnrTracker.cpp                  # ANR超时追踪
│   ├── Connection.cpp                  # 窗口连接管理
│   ├── FocusResolver.cpp               # 焦点窗口解析
│   └── Entry.cpp                       # 事件队列条目
└── include/

frameworks/base/services/core/java/com/android/server/input/
├── InputManagerService.java            # Java层服务入口(146KB)
├── NativeInputManagerService.java      # Native层JNI封装
├── InputSettingsObserver.java          # 输入设置监听
├── KeyboardLayoutManager.java          # 键盘布局管理
└── BatteryController.java              # 输入设备电池管理

frameworks/base/core/java/android/view/
├── InputEventReceiver.java             # 应用层事件接收器
├── MotionEvent.java                    # 触摸/鼠标事件
├── KeyEvent.java                       # 按键事件
└── InputChannel.java                   # IPC通道

调试命令速查

bash 复制代码
# 输入系统状态
adb shell dumpsys input

# 实时监听输入事件
adb shell getevent -lt

# 查看焦点窗口
adb shell dumpsys input | grep Focus

# ANR日志
adb logcat | grep "ANR in"
adb pull /data/anr/traces.txt

# systrace输入分析
python systrace.py -o trace.html input view

系列文章


本文基于Android 15 (API Level 35)源码分析,不同厂商的定制ROM可能存在差异。 欢迎来我中的个人主页找到更多有用的知识和有趣的产品

相关推荐
张小潇4 小时前
AOSP15 Input专题InputManager源码分析
android·操作系统
RdoZam7 小时前
Android-封装基类Activity\Fragment,从0到1记录
android·kotlin
奥陌陌12 小时前
android 打印函数调用堆栈
android
用户9851200358312 小时前
Compose Navigation 3 深度解析(二):基础用法
android·android jetpack
恋猫de小郭12 小时前
Android 官方正式官宣 AI 支持 AppFunctions ,Android 官方 MCP 和系统级 OpenClaw 雏形
android·前端·flutter
黄林晴13 小时前
Android 17 Beta 2,隐私这把锁又拧紧了
android
Kapaseker13 小时前
研究表明,开发者对Kotlin集合的了解不到 20%
android·kotlin
bqliang14 小时前
Compose 媒体查询 (Media Query API) 🖱️👇🕹️
android·android jetpack
程序员陆业聪1 天前
Android 平台 AI Agent 技术架构深度解析
android·人工智能