Android11 touch的传递流程主要涉及到以下内容:
1. ViewRootImpl 注册InputChannel 2
2. InputFlinger 从kernel读取touch数据(重点)
3. InputFlinger把touch数据发送到View(重点)
4. ViewRootImp接收touch数据发送到app
概括:app往wms那边添加窗口的同时,wms创建一对socket pair,用InputChannel封装,一个给app,一个给InputFlinger,之后InputFlinger通过这个unix socket fd把touch数据发给app。
此文主要介绍InputFlinger其它内容请看,https://blog.csdn.net/goodnight1994/article/details/119328739
在Android系统中,framwork/native/service/inputflinger会进行framwork层各种输入事件(按键,触摸等)的收集、处理、和分发。
InputManger.cpp是inputflinger的入口类。也就是inputflinger第一个执行的文件。
结合上图可以看出inputflinger主要包括两个很重要的类,来完成所有事件的读取和派发
InputReader
: 这个类主要从input读取所有设备产生的input事件(包括,单点触摸,多点触摸,按键,电磁笔等)InputDispatcher
:这个类负责事件的分发工作。它们对应两个干活的线程(也是两个类):
InputReaderThread
:这个线程负责不停的调用inputReader事件,进行数据的收集。
InuptDispatcherThread
: 这个线程会不停的轮训事件队列是否有数据需要处理。
看一下`InputReaderThread`:
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
EvenetHub
获取输入的事件,将输入事件存到保存输入事件的Buffer里面,并返回输入事件的个数。int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
//监听并等待事件到来(这就是上面添加到epoll_wait)
processEvenetLocked()
进行事件原始的处理,这样上层才能更好的使用。比如多点触摸,电磁触摸,单点触摸等processEventslocked()
解析: void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex < 0) {
ALOGW("Discarding event for unknown deviceId %d.", deviceId);
return;
}
InputDevice* device = mDevices.valueAt(deviceIndex);
if (device->isIgnored()) {
//ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
}
device->process(rawEvents, count);
//这里就是对不同设备的事件进行不同的处理了,在不同的android版本上这里的实现也不太一样
}
//frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
status_t InputDispatcher::start() {
if (mThread) {
return ALREADY_EXISTS;
}
mThread = std::make_unique<InputThread>(
"InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
return OK;
}
//创建了一个线程去跑dispatchOnce()函数,
//没事件时睡下去,有事件时被前面的入队事件唤醒后开始工作
void InputDispatcher::dispatchOnce() {
//.......
dispatchOnceInnerLocked(&nextWakeupTime);
//.......
}
//接着看
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
//.......
done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
//......
}
bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
//.......
//TODO 这边会去选出到底是要把touch数据给到哪个View,选完装到inputTargets里边
//具体咋选的后面再单独研究下
injectionResult =
findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime,
&conflictingPointerActions);
//......
//选完View后,接着继续发数据
dispatchEventLocked(currentTime, entry, inputTargets);
//......
}
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,
const std::vector<InputTarget>& inputTargets) {
//.......
//根据inputTarget取出前面note13 注册的connection,其中里边包含用来和View通信的InputChannel
sp<Connection> connection =
getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
//.......
}
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget) {
//.......
//从这进去,接着看
enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget);
//......
}
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget) {
//.......
//从这进去
startDispatchCycleLocked(currentTime, connection);
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
//......
status =connection->inputPublisher.publishKeyEvent(dispatchEntry->seq, dispatchEntry->resolvedEventId,
keyEntry->deviceId, keyEntry->source,
keyEntry->displayId, std::move(hmac),
dispatchEntry->resolvedAction,
dispatchEntry->resolvedFlags, keyEntry->keyCode,
keyEntry->scanCode, keyEntry->metaState,
keyEntry->repeatCount, keyEntry->downTime,
keyEntry->eventTime);
//....
}
//走到InputPublisher去了,看下
//frameworks/native/libs/input/InputTransport.cpp
status_t InputPublisher::publishKeyEvent(uint32_t seq, int32_t eventId, int32_t deviceId,
int32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac, int32_t action,
int32_t flags, int32_t keyCode, int32_t scanCode,
int32_t metaState, int32_t repeatCount, nsecs_t downTime,
nsecs_t eventTime) {
//.......
//好了到底了,这边通过InputChannel用unix socket把数据发给View
return mChannel->sendMessage(&msg);
}
//至于这把mChannel是怎么来的为何是前面app通过wms传过来的InputChannel,
//咱们从note13 再看下
//frameworks/native/services/inputflinger/dispatcher/Connection.cpp
Connection::Connection(const sp<InputChannel>& inputChannel, bool monitor,
const IdGenerator& idGenerator)
: status(STATUS_NORMAL),
inputChannel(inputChannel),
monitor(monitor),
inputPublisher(inputChannel),
inputState(idGenerator) {}
//frameworks/native/libs/input/InputTransport.cpp
InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
mChannel(channel) {
}
主要就是从队列里面去读取并把它们分发出去。
我自己主要是项目需求做了一个优先级的需求,就是在手指触摸和电磁笔同时进行输入时,让电磁笔优先进行输入。
主要的思路就是:
在inputReader.cpp处理事件里
1 设置一个static的clock,去进行时间计数,在该时间内关闭其它输入只允许电磁笔输入
2 根据vendorid和productid去过滤相关的事件。只上报电磁笔产生的事件。从而实现输入过滤。