引言
在前面的文章中,我们学习了AMS如何管理Activity生命周期,PMS如何管理应用安装,WMS如何管理窗口显示。但有一个关键问题:当用户触摸屏幕或按下按键时,这些输入事件是如何准确地传递到目标窗口的?
想象你点击屏幕上的一个按钮:
- 触摸屏硬件检测到触摸
- 系统如何知道你点击的是哪个窗口?
- 事件如何跨进程传递到应用?
- 如果应用处理太慢会发生什么?
这一切的答案都指向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是输入系统的核心,负责:
- 查找目标窗口
- 将事件分发到目标窗口
- 检测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的核心机制:
核心要点回顾
-
架构分层:
- Kernel层提供设备驱动和事件接口
- Native层(EventHub/InputReader/InputDispatcher)实现核心逻辑
- Framework层(IMS)提供Java API
- Application层接收和处理事件
-
事件流转:
- 硬件中断 → Input Driver → /dev/input/eventX
- EventHub(epoll) → InputReader(解析) → InputDispatcher(分发)
- InputChannel(Socket) → InputEventReceiver → ViewRootImpl → View树
-
ANR机制:
- 默认5秒超时
- InputDispatcher检测响应超时
- 收集堆栈、显示对话框、记录日志
-
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可能存在差异。 欢迎来我中的个人主页找到更多有用的知识和有趣的产品