Android 常见的 View Touch 事件的分发,相信大家都已经耳熟能详了。但是这是触摸事件的消费处理过程,有没有想过 touch 事件是由谁产生,又是如何传递给 View 的。本文从源码角度浅析一下 Touch 事件的产生过程。
1 InputManagerService 的创建
在系统启动的时候会调用 SystemServer 进行启动并初始化大量的服务
[-> SystemServer.java]
private void startOtherServices() {
try {
、、、
traceBeginAndSlog("StartInputManagerService");
inputManager = new InputManagerService(context);
traceEnd();
traceBeginAndSlog("StartWindowManagerService");
// WMS needs sensor service ready
ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
mSensorServiceStart = null;
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
// 将名为"window"的系统服务添加到Binder大管家ServiceManager,在其他地方就可以通过Context.WINDOW_SERVICE拿到WindowManagerService
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
// 将名为"input"的系统服务添加到Binder大管家ServiceManager,在其他地方就可以通过Context.INPUT_SERVICE拿到InputManagerService
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
traceEnd();
traceBeginAndSlog("SetWindowManagerService");
mActivityManagerService.setWindowManager(wm);
traceEnd();
traceBeginAndSlog("WindowManagerServiceOnInitReady");
wm.onInitReady();
traceEnd();
// Start receiving calls from HIDL services. Start in in a separate thread
// because it need to connect to SensorManager. This have to start
// after START_SENSOR_SERVICE is done.
SystemServerInitThreadPool.get().submit(() -> {
TimingsTraceLog traceLog = new TimingsTraceLog(
SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
traceLog.traceBegin(START_HIDL_SERVICES);
startHidlServices();
traceLog.traceEnd();
}, START_HIDL_SERVICES);
if (!isWatch && enableVrService) {
traceBeginAndSlog("StartVrManagerService");
mSystemServiceManager.startService(VrManagerService.class);
traceEnd();
}
traceBeginAndSlog("StartInputManager");
// 为InputManagerService设置WindowManagerCallbacks,这样WMS与IM就可以互相通信了
inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
inputManager.start();
traceEnd();
、、、
} catch (RuntimeException e) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting core service", e);
}
、、、
}
2 InputManagerService 的初始化
[ -> InputManagerService ]
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
+ mUseDevInputEventForAudioJack);
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
String doubleTouchGestureEnablePath = context.getResources().getString(
R.string.config_doubleTouchGestureEnableFile);
mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
new File(doubleTouchGestureEnablePath);
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
public void start() {
Slog.i(TAG, "Starting input manager");
nativeStart(mPtr);
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
// 通过ContentObserver监听SettingsProvider中input相关设置项的值
registerPointerSpeedSettingObserver();
registerShowTouchesSettingObserver();
registerAccessibilityLargePointerSettingObserver();
// 监听用户切换的广播,并更新SettingsProvider中input相关设置项的值
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
updateAccessibilityLargePointerFromSettings();
}
}, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
// InputManagerService创建时会主动触发一次input相关设置项的刷新
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
updateAccessibilityLargePointerFromSettings();
}
nativeInit 与 nativeStart 是 native 的方法
[-> com_android_server_input_InputManagerService.cpp ]
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == nullptr) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
//返回一个long类型的指针数据给java层,java层会保存这个数据,在调用NativeInputManager相关的函数时将指针再传回native层
return reinterpret_cast<jlong>(im);
}
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
//这个ptr就是nativeInit 创建的NativeInputManager实例的指针
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
此时 java 层的 InputManagerService 就与 native 层的 NativeInputManager 建立了联系。
3 native 层 NativeInputManager 初始化
在 1.2 中 native 层创建了一个 NativeInputManager 实例,并将对应指针返回了 java 层,在 nativeStart 的时候又调用了 start 函数。
[-> com_android_server_input_InputManagerService.cpp ]
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mServiceObj = env->NewGlobalRef(serviceObj);
{
AutoMutex _l(mLock);
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
mLocked.pointerCapture = false;
mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
}
mInteractive = true;
//创建InputManager实例,并添加到ServiceManager
mInputManager = new InputManager(this, this);
defaultServiceManager()->addService(String16("inputflinger"),
mInputManager, false);
}
4 InputManager
[ -> InputManager.cpp ]
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mClassifier = new InputClassifier(mDispatcher);
mReader = createInputReader(readerPolicy, mClassifier);
initialize();
}
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputDispatcher thread due to error %d.", result);
return result;
}
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputReader thread due to error %d.", result);
mDispatcherThread->requestExit();
return result;
}
return OK;
}
可以看到 InputDispathcer 和 InputReader 启动了 2 个非常重要的线程,它们确保了 input 子系统能够源源不断的从底层获取输入事件,并将事件经过层层包装之后上报给当前的焦点窗口去处理
InputDispathcer 与 InputReader 内部都有一个线程,不停的调用 loopOnce 函数。
4 Touch 事件的产生
[-> InputReader.cpp]
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
std::vector<InputDeviceInfo> inputDevices;
{ // acquire lock
AutoMutex _l(mLock);
oldGeneration = mGeneration;
timeoutMillis = -1;
uint32_t changes = mConfigurationChangesToRefresh;
if (changes) {
mConfigurationChangesToRefresh = 0;
timeoutMillis = 0;
refreshConfigurationLocked(changes);
} else if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
}
} // release lock
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
processEventsLocked(mEventBuffer, count);
}
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now);
}
}
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
getInputDevicesLocked(inputDevices);
}
} // release lock
// Send out a message that the describes the changed input devices.
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);
}
// Flush queued events out to the listener.
// This must happen outside of the lock because the listener could potentially call
// back into the InputReader's methods, such as getScanCodeState, or become blocked
// on another thread similarly waiting to acquire the InputReader lock thereby
// resulting in a deadlock. This situation is actually quite plausible because the
// listener is actually the input dispatcher, which calls into the window manager,
// which occasionally calls into the input reader.
mQueuedListener->flush();
}
这里有个 EventHub,它主要是利用 Linux 的 inotify 和 epoll 机制,监听设备事件:包括设备插拔及各种触摸、按钮事件等,可以看作是一个不同设备的集线器,主要面向的是/dev/input 目录下的设备节点,比如说/dev/input/event0 上的事件就是输入事件,通过 EventHub 的 getEvents 就可以监听并获取该事件:
通过 mEventHub 读取输入到 buffer 内,然后通过一个 processEventsLocked->processEventsForDeviceLocked->Device::process->MultiTouchInputMapper::process->TouchInputMapper::process->TouchInputMapper::sync->TouchInputMapper::processRawTouches->TouchInputMapper::cookAndDispatch->TouchInputMapper::dispatchTouches->TouchInputMapper::dispatchMotion
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
int32_t action, int32_t actionButton, int32_t flags,
int32_t metaState, int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp,
const PointerProperties* properties, const PointerCoords* coords,
const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId,
float xPrecision, float yPrecision, nsecs_t downTime) {
PointerCoords pointerCoords[MAX_POINTERS];
PointerProperties pointerProperties[MAX_POINTERS];
uint32_t pointerCount = 0;
while (!idBits.isEmpty()) {
uint32_t id = idBits.clearFirstMarkedBit();
uint32_t index = idToIndex[id];
pointerProperties[pointerCount].copyFrom(properties[index]);
pointerCoords[pointerCount].copyFrom(coords[index]);
if (changedId >= 0 && id == uint32_t(changedId)) {
action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
pointerCount += 1;
}
ALOG_ASSERT(pointerCount != 0);
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) {
action = AMOTION_EVENT_ACTION_UP;
} else {
// Can't happen.
ALOG_ASSERT(false);
}
}
const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE);
const int32_t deviceId = getDeviceId();
std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId);
std::for_each(frames.begin(), frames.end(),
[this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId,
source, displayId, policyFlags,
action, actionButton, flags, metaState, buttonState, MotionClassification::NONE,
edgeFlags, deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime, std::move(frames));
getListener()->notifyMotion(&args);
}
getListener()获取的是创建 InputReader 时候传入的参数,InputClassifier 的一个实例
InputClassifier 又将事件传给了 mListener,也就是 InputDispatcher,此时 touch 事件由 InputReader(生产者),传递给了 InputDispatcher(分发者)。
5 总结
系统在启动的时候 SystemServer 会启动 InputManagerService 与 WindowManagerService,并且会建立两者的联系。InputManagerService 在初始化的时候会在 native 层 NativeInputManager 实例,并且启动 NativeInputManager。NativeInputManager 又会创建 InputManager,InputManager 才是事件的产生&分发事件的实际执行者。
InputManager 内有一个 InputReader 与 InputDispatcher 实例,两个对象分别运行在一个单独线程内,负责事件的读取产生与分发工作。InputReader 在从 EventHub 从各个 device 节点读取到事件后收集起来通过接口回调抛给 InputDispatcher。
本文由mdnice多平台发布