“
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 的剩下的步骤如下:
-
通过 IMS 创建 WMS; -
IMS 添加来自 WMS 的回调; -
IMS 调用 start 方法; -
当 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 有很多实现:

这些实现实现了不同的功能,例如 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();
}
}
核心只有两步:
-
构造 MotionEvent -
创建 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