继IMS构造方法分析完成后,看看IMS中的start方法
public void start() {
Slog.i(TAG, "Starting input manager");
// 之前初始化了InputManager->inputDispatcher&&inputReader
// 这里开始start它们,并且会创建InputThread线程,也就是InputReaderThread和InputDispatcherThread
// InputThread是一个自定义的类,它接受三个参数:一个字符串作为线程名,
// 一个lambda表达式作为线程函数,另一个lambda表达式在线程结束时被调用
nativeStart(mPtr);
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
//注册触摸点速度和是否显示功能的观察者
registerPointerSpeedSettingObserver();
registerShowTouchesSettingObserver();
...
// 更新触摸点的速度
updatePointerSpeedFromSettings();
// 是否在屏幕上显示触摸点
updateShowTouchesFromSettings();
updateAccessibilityLargePointerFromSettings();
updateDeepPressStatusFromSettings("just booted");
updateMaximumObscuringOpacityForTouchFromSettings();
updateBlockUntrustedTouchesModeFromSettings();
}
以上只关注nativeStart(mPtr);,mPtr指向的就是NativeInputManager,之前初始化了InputManager->inputDispatcher&&inputReader,这里开始start它们,并且会创建InputThread线程,也就是InputReaderThread和InputDispatcherThread
// **com_android_server_input_InputManagerService.cpp**
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
// 获取InputManager,调用它的start
status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
// **InputManager.cpp**
status_t InputManager::start() {
// 调用inputDispatcher的start()
status_t result = mDispatcher->start();
if (result) {
ALOGE("Could not start InputDispatcher thread due to error %d.", result);
return result;
}
// 调用inputReader的start()
result = mReader->start();
if (result) {
ALOGE("Could not start InputReader due to error %d.", result);
mDispatcher->stop();
return result;
}
return OK;
}
也就是在InputManager中调用了mDispatcher->start();和mReader->start();去分别创建对应的线程,并让Inputeader和InputDispatcher执行具体逻辑。先来看看InputReader中的start方法
status_t InputReader::start() {
if (mThread) {
return ALREADY_EXISTS;
}
// InputThread是一个自定义的类,它接受三个参数:一个字符串作为线程名,一个lambda表达式作为线程函数,
// 另一个lambda表达式在线程结束时被调用
mThread = std::make_unique<InputThread>(
"InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
return OK;
}
// 这里就是start后的主要内容
// 读取eventHub里面的设备节点内容
// 调用的是 mEventHub->getEvents
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
...
// 读取设备里的所有事件,存放到了mEventBuffer
// RawEvent mEventBuffer[EVENT_BUFFER_SIZE] GUARDED_BY(mLock);
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
...
if (count) {
// 关键代码
processEventsLocked(mEventBuffer, count);
}
...
mQueuedListener->flush();
}
首先调用了mEventHub中的getEvents方法其获取输入的原始事件,并存放到RawEvent中,所以该实体类中存放的是原始输入事件,然后调用了之前初始化创建的mQueuedListener,调用flush()将事件发送给InputDispatcher中,继续看看EventHub中的getEvents
方法
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer/*缓存事件*/, size_t bufferSize/*256*/) {
struct input_event readBuffer[bufferSize];
// 原始事件
RawEvent* event = buffer;
// 256
size_t capacity = bufferSize;
bool awoken = false;
// 循环读取设备节点
for (;;) {
...
// std::vector> mOpeningDevices;
// 初始化动作,主要是打开设备和扫描设备
// 扫描设备,并打开每个设备目录/dev/input/...
scanDevicesLocked();
while (!mOpeningDevices.empty()) {
// 获取mOpeningDevices中的设备/dev/input/目录下的文件:event1/2/3/4等
std::unique_ptr<Device> device = std::move(*mOpeningDevices.rbegin());
mOpeningDevices.pop_back();
ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());
// 将每个设备打包生成RawEvent(event)形式进行存储对应的信息
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
// 添加设备的事件
event->type = DEVICE_ADDED;
event += 1;
...
}
// 这里是开始处理每个设备中的事件
while (mPendingEventIndex < mPendingEventCount) {
// 从mPendingEventCount读取事件
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
...
// 打开/dev/input/... event1/2/3等设备文件
Device* device = getDeviceByFdLocked(eventItem.data.fd);
if (device == nullptr) {
ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.", eventItem.events,
eventItem.data.fd);
ALOG_ASSERT(!DEBUG);
continue;
}
...
// This must be an input event
// 读取设备中的输入事件
if (eventItem.events & EPOLLIN) {
// 读取设备里面的事件内容
int32_t readSize =
read(device->fd, readBuffer, sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
// Device was removed before INotify noticed.
ALOGW("could not get event, removed? (fd: %d size: %" PRId32
" bufferSize: %zu capacity: %zu errno: %d)\n",
device->fd, readSize, bufferSize, capacity, errno);
deviceChanged = true;
// 没有事件则关闭设备
closeDeviceLocked(*device);
} ... else {
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
// 获取设备输入事件的数量
size_t count = size_t(readSize) / sizeof(struct input_event);
for (size_t i = 0; i < count; i++) {
// 将每个事件打包生成RawEvent
struct input_event& iev = readBuffer[i];
event->when = processEventTimestamp(iev);
event->readTime = systemTime(SYSTEM_TIME_MONOTONIC);
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
...
}
}
...
}
...
// poll之前先释放锁
mLock.unlock(); // release lock before poll
// 等待input事件的到来
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
// 事件到来就请求锁
mLock.lock(); // reacquire lock after poll
...
// All done, return the number of events we read.
// 返回所读取的事件个数
return event - buffer;
}
以上内容就是scanDevicesLocked
做初始化动作,扫描设备,打开设备,将设备保存到mOpeningDevices中,然后循环读取每个设备中的事件,将每个事件封装成RawEvent并加上了DEVICE_ADDED
这个标志(后面会用到,来决定是移除还是新增),再保存到buffer(mEventBuffer)
里面,如果设备中没有事件了则会关闭设备,然后通过epoll_wait
来一直等等下一次的input事件到来,所以我们回到InputReader.cpp#loopOnce中继续分析processEventsLocked(mEventBuffer, count);
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
// rawEvents保存了通过EventHub中获取的设备里的事件
// count是事件数量
for (const RawEvent* rawEvent = rawEvents; count;) {
int32_t type = rawEvent->type;
size_t batchSize = 1;
if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
...
// 事件的处理
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
// 在EventHub.getEvents中有处理,每个事件都会封装为RawEvent,并且而加上了DEVICE_ADDED标志
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
// 创建设备,eventHubId设备唯一id,通过id可获取设备
// 这里主要是创建InputDevice,根据device判断是鼠标类型触摸事件,还是键盘类,或触摸屏类
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减少
count -= batchSize;
// 处理完事件,指针向后移动一个
rawEvent += batchSize;
}
}
void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
size_t count) {
auto deviceIt = mDevices.find(eventHubId);
...
// 调用InputDevice的process
// 传递原始事件+事件数量
device->process(rawEvents, count);
}
首先会走addDeviceLocked来创建InputDevice,因为/dev/input里每个device的功能都不同,有的处理指纹事件,有的处理鼠标键盘类数据,有的处理屏幕触摸事件,然后再执行到processEventsForDeviceLocked
,因为processEventsForDeviceLocked
执行之前已经创建了各个类型的InputDevice
,这里就是调用对应类型的InputDevice.process方法,那随便找一个TouchInputMapper.cpp
来分析吧,触摸事件
frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp
void TouchInputMapper::process(const RawEvent* rawEvent/*原始事件*/) {
// 鼠标按下,滚动,触摸
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
// 主要关注sync
sync(rawEvent->when, rawEvent->readTime);
}
}
sync会继续调用processRawTouches
,接着看
// 它处理原始触摸输入数据并将其转换为可读的触摸事件。
// 首先,它检查设备模式是否为DISABLED。如果是,它将取消当前的触摸,并清空当前的状态(mCurrentCookedState),然后更新触摸点。
// 接下来,它会处理任何待处理的原始触摸状态。这些状态被存储在mRawStatesPending中。
// 如果当前状态是一个stylus(触笔)状态,则会检查是否需要等待stylus数据。
// 如果需要等待,它将退出循环。否则,它会将当前状态设为下一个待处理状态,并通过cookAndDispatch函数将其转换为可读的触摸事件
void TouchInputMapper::processRawTouches(bool timeout) {
// 检查设备是否处于disabled状态
if (mDeviceMode == DeviceMode::DISABLED) {
// Drop all input if the device is disabled.
cancelTouch(mCurrentRawState.when, mCurrentRawState.readTime);
...
return;
}
// 它会处理任何待处理的原始触摸状态,这些状态被存储在mRawStatesPending中。
const size_t N = mRawStatesPending.size();
size_t count;
// 待处理的原始事件 RawEvent
for (count = 0; count < N; count++) {
...
// 继续调用,主要就是将原始事件转换为可读的触摸事件
cookAndDispatch(mCurrentRawState.when, mCurrentRawState.readTime);
}
...
}
简要说明一下cookAndDispatch
方法的作用,判断事件的类型属于手势触摸还是鼠标等类型,假设是手势触摸则调用dispatchPointerGestures
进行事件分发,然后判断事件是否移动,tap按下等状态,进行单独处理和事件分发,并把当前手指通过markBit(id);
存入一个整型变量中,所以不管有多少个手指触摸,都以进制形式存放在一个变量中,内存开销小,最后调用dispatchMotion
方法将事件的状态,例如是否按下,按下的时间,事件动作,以及事件id封装到NotifyMotionArgs
中,然后进行分发(也就是通知消息并携带该args给InputDispatcher),实际是调用getListener()->notifyMotion(&args);
所以继续看看InputDispatcher.cpp中的notifyMotion方法,进入下一个阶段
总结:
2.然后再继续调用了processEventsLocked
判断原始事件属于什么类型,例如触摸,鼠标,键盘等,创建对应的InputDevice
processEventsForDeviceLocked
来处理InputDevice→process
,然后继续分析了TouchInputMapper.cpp,因为这个mapper就是InputDevice的其中一种类型,根据事件类型,判断是否点击,滑动,多个手势,将事件信息封装成NotifyMotionArgs
,将手指封装到整型变量中,代表有多少个手指,然后分发给InputDispatcher