frameworks 之InputReader
- InputManagerService 初始化
- InputManagerService 启动
- InputReader 事件的读取
- 设备节点注册和监听
- 设备输入事件的读取
- InputReader 事件的处理
- 设备的添加和删除处理
- 触摸事件的处理
- 数据的加工和分发
android 输入事件 主要分 2个流程 事件读取 和 事件分发。本文讲解事件输入流程。
涉及到的类如下
-frameworks/base/services/java/com/android/server/SystemServer.java
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
frameworks/native/services/inputflinger/InputManager.cpp
frameworks/native/services/inputflinger/dispatcher/InputDispatcherFactory.cpp
frameworks/native/services/inputflinger/reader/InputReaderFactory.cpp
frameworks/native/services/inputflinger/reader/EventHub.cpp
frameworks/native/services/inputflinger/reader/InputReader.cpp
frameworks/native/services/inputflinger/InputThread.cpp
frameworks/native/services/inputflinger/reader/include/EventHub.h
frameworks/native/services/inputflinger/reader/InputDevice.cpp
frameworks/native/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp
system/core/libutils/include/utils/BitSet.h
InputManagerService 初始化
SystemService启动时候,启动了一系列服务包括 InputManagerService 。在 startOtherServices 方法中 ,初始化了该服务。
// frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {...InputManagerService inputManager = null;...t.traceBegin("StartInputManagerService");// 初始化服务inputManager = new InputManagerService(context);t.traceEnd();
}
查看该类构造函数,里面最重要为调用了 nativeInit 接口。初始化相关数据,该方法为 c++ 方法。
// frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public InputManagerService(Context context) {this.mContext = context;this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());mStaticAssociations = loadStaticInputPortAssociations();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());}
nativeInit 方法初始化了 NativeInputManager 并把对应的指针地址转化为long类型返回。
// frameworks/base/services/core/jni/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;}// 初始化NativeInputManagerNativeInputManager* im = new NativeInputManager(contextObj, serviceObj,messageQueue->getLooper());im->incStrong(0);// 将im指针转换为jlong类型,返回给java 后续其他对象可通过该值获取 NativeInputManagerreturn reinterpret_cast<jlong>(im);
}
而 NativeInputManager 对应的构造函数又初始化了 InputManager,传入当前对象。
// frameworks/base/services/core/jni/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.systemUiLightsOut = false;mLocked.pointerSpeed = 0;mLocked.pointerGesturesEnabled = true;mLocked.showTouches = false;mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;}mInteractive = true;// 初始化 InputManagerInputManager* im = new InputManager(this, this);mInputManager = im;// 添加该服务到 sm 中 inputflingerdefaultServiceManager()->addService(String16("inputflinger"), im);
}
InputManager 里又初始化了 InputDispatcher, InputClassifier,InputReader 等3个类。然后将 对应 InputDispatcher 作为参数传入 InputClassifier, 而 InputClassifier 又作为参数传入 InputReader里。所以可知 InputClassifier 作为 InputDispatcher 和 InputReader的中间沟通桥梁。事件读取后 通过 InputClassifier 通知 InputDispatcher 进行分发。
// frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager(const sp<InputReaderPolicyInterface>& readerPolicy,const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {// 通过 InputDispatcherFactory 创建 InputDispatchermDispatcher = createInputDispatcher(dispatcherPolicy);// 将 dispatcher 传入 InputClassifiermClassifier = new InputClassifier(mDispatcher);// 通过 InputReaderFactory 创建 readermReader = createInputReader(readerPolicy, mClassifier);
}// frameworks/native/services/inputflinger/reader/InputReaderFactory.cpp
sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy,const sp<InputListenerInterface>& listener) {return new InputReader(std::make_unique<EventHub>(), policy, listener);
}// frameworks/native/services/inputflinger/dispatcher/InputDispatcherFactory.cpp
sp<InputDispatcherInterface> createInputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) {return new android::inputdispatcher::InputDispatcher(policy);
}
而 InputReaderFactory 对 inputReader 的构造方法中,又初始化了 EventHub 类,作为参数传入,后续该类作为读取节点数据的作用。 EventHub 构造函数中 初始化了 Epoll, 并添加对应dev/input 文件夹删除和添加监听,和 getEvents 一样。
// frameworks/native/services/inputflinger/reader/EventHub.cpp
EventHub::EventHub(void): mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),mNextDeviceId(1),mControllerNumbers(),mNeedToSendFinishedDeviceScan(false),mNeedToReopenDevices(false),mNeedToScanDevices(true),mPendingEventCount(0),mPendingEventIndex(0),mPendingINotify(false) {ensureProcessCanBlockSuspend();// 创建epollmEpollFd = epoll_create1(EPOLL_CLOEXEC);LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));// 跟getEvent一样 创建对应文件夹mINotifyFd = inotify_init();// 添加对dev/input增加和删除监听mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH,strerror(errno));if (isV4lScanningEnabled()) {mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",VIDEO_DEVICE_PATH, strerror(errno));} else {mVideoWd = -1;ALOGI("Video device scanning disabled");}struct epoll_event eventItem = {};eventItem.events = EPOLLIN | EPOLLWAKEUP;eventItem.data.fd = mINotifyFd;// 添加到epoll监听中int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);int wakeFds[2];result = pipe(wakeFds);LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);mWakeReadPipeFd = wakeFds[0];mWakeWritePipeFd = wakeFds[1];result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",errno);result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",errno);eventItem.data.fd = mWakeReadPipeFd;result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",errno);
}
总结 InputMangerService 会初始化一系列的变量。包含读取和分发相关类。并监听对应输入文件夹的变化。
InputManagerService 启动
初始化,就会启动对应的事件读取,开启一个循环不断进行读取对应的节点事件。
InputMangerService 通过start 方法进行开启
// frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {t.traceBegin("StartInputManager");inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());// 通过start 启动事件监听循环inputManager.start();t.traceEnd();
}
进入start 方法查看,该方法主要进行相关配置的读取和监听,其中最重要的就是 nativeStart 方法。
public void start() {Slog.i(TAG, "Starting input manager");nativeStart(mPtr);// Add ourself to the Watchdog monitors.Watchdog.getInstance().addMonitor(this);// 注册相关触摸监听设置registerPointerSpeedSettingObserver();...updateBlockUntrustedTouchesModeFromSettings();}
查看 nativeStart 方法,该方法将传入的指针做转换为 NativeInputManager,并调用 里面 InputManger 的 start 方法。
// frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);// 调用 NativeInputManager 里面的 inputManger 的start 方法status_t result = im->getInputManager()->start();if (result) {jniThrowRuntimeException(env, "Input manager could not be started.");}
}
进入 start 方法,该方法 分别调用 inputReader 和 InputDispatcher 的 start 方法开启线程。
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;
}
以 inputReader 为例, 方法第一次 创建了 InputThread类,并将 loopOnce 函数作为参数传入 InputThread里。
// frameworks/native/services/inputflinger/reader/InputReader.cpp
status_t InputReader::start() {if (mThread) {return ALREADY_EXISTS;}// 创建 InputThread 线程, 传入参数为 loopOnce 函数,等于里面 run 执行threadLoop方法时候会执行该函数mThread = std::make_unique<InputThread>("InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });return OK;
}
InputThread 构造参数中, 又创建了线程类 InputThreadImpl 并通过 run 方法启动线程。
// frameworks/native/services/inputflinger/InputThread.cpp
InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake): mName(name), mThreadWake(wake) {mThread = new InputThreadImpl(loop);// 创建后 执行run方法mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);
}
启动线程类后 会执行对应的 threadLoop 方法,而 threadLoop 又会执行 mThreadLoop 函数,该参数就是 InputRead 的 loopOnce 函数。这样就等于 loopOnce 函数循环读取对应设备节点事件,并处理。
class InputThreadImpl : public Thread {
public:explicit InputThreadImpl(std::function<void()> loop): Thread(/* canCallJava */ true), mThreadLoop(loop) {}~InputThreadImpl() {}private:std::function<void()> mThreadLoop;bool threadLoop() override {mThreadLoop();return true;}
};
总结 通过 start 方法 一步步调用到 inputReader 等start 方法并创建对应的线程类开始运作读取底层事件。
InputReader 事件的读取
启动线程后,会一直执行对应的 loopOnce 函数。该函数一开始判断对应的配置是否改变,改变则刷新,并通过 EventHub 的 getEvents 方法读取事件。
// frameworks/native/services/inputflinger/reader/InputReader.cpp
void InputReader::loopOnce() {int32_t oldGeneration;int32_t timeoutMillis;bool inputDevicesChanged = false;std::vector<InputDeviceInfo> inputDevices;{ // acquire lockstd::scoped_lock _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 lockstd::scoped_lock _l(mLock);mReaderIsAliveCondition.notify_all();// 如果有事件if (count) {// 解析对应的事件processEventsLocked(mEventBuffer, count);}if (mNextTimeout != LLONG_MAX) {nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTSALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endifmNextTimeout = LLONG_MAX;timeoutExpiredLocked(now);}}if (oldGeneration != mGeneration) {inputDevicesChanged = true;inputDevices = getInputDevicesLocked();}} // 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();
}
进入 getEvents 方法。这里主要有个路径,如输入设备变化的注册和监听,已经设备事件输入的读取 。方法传入了 RawEvent数组 该数组和监听事件的 input_event 数组一样大小。
设备节点注册和监听
因为默认 mNeedToReopenDevices 为 false。所以第一个判断不会进入,接下来会判断是否有关闭的设备有的话 将创建对应的 RawEvent 对象 type 为 DEVICE_REMOVED。接下来 因为默认的 mNeedToScanDevices 为 true,所以会调用对应 的 scanDevicesLocked 对设备进行扫描。
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {ALOG_ASSERT(bufferSize >= 1);std::scoped_lock _l(mLock);// 跟 RawEvent 一样的大小struct input_event readBuffer[bufferSize];RawEvent* event = buffer;size_t capacity = bufferSize;bool awoken = false;for (;;) {nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);// Reopen input devices if needed.// 默认为false, 第一次会将 mNeedToScanDevices 变为trueif (mNeedToReopenDevices) {mNeedToReopenDevices = false;ALOGI("Reopening all input devices due to a configuration change.");closeAllDevicesLocked();mNeedToScanDevices = true;break; // return to the caller before we actually rescan}// Report any devices that had last been added/removed.// 判断列表里面是否有关闭的设备,有的话向event数组添加对应的事件for (auto it = mClosingDevices.begin(); it != mClosingDevices.end();) {std::unique_ptr<Device> device = std::move(*it);ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());event->when = now;event->deviceId = (device->id == mBuiltInKeyboardId)? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID: device->id;event->type = DEVICE_REMOVED;event += 1;// 容器中移除当前迭代器 it 指向的元素,并更新迭代器 it 到下一个元素it = mClosingDevices.erase(it);mNeedToSendFinishedDeviceScan = true;if (--capacity == 0) {break;}}// 第一次为true, 通过 scanDevicesLocked 将对应的设备节点数据处理后放到 mOpeningDevices 数组中if (mNeedToScanDevices) {mNeedToScanDevices = false;scanDevicesLocked();mNeedToSendFinishedDeviceScan = true;}// 第一次不为空,会进入while (!mOpeningDevices.empty()) {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());// 添加 对应的 eventevent->when = now;event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;event->type = DEVICE_ADDED;event += 1;// Try to find a matching video device by comparing device namesfor (auto it = mUnattachedVideoDevices.begin(); it != mUnattachedVideoDevices.end();it++) {std::unique_ptr<TouchVideoDevice>& videoDevice = *it;if (tryAddVideoDeviceLocked(*device, videoDevice)) {// videoDevice was transferred to 'device'it = mUnattachedVideoDevices.erase(it);break;}}// 将对应 device 放到 mDevices map中auto [dev_it, inserted] = mDevices.insert_or_assign(device->id, std::move(device));if (!inserted) {ALOGW("Device id %d exists, replaced.", device->id);}mNeedToSendFinishedDeviceScan = true;if (--capacity == 0) {break;}}// 有新增设备的时候,添加 finish事件if (mNeedToSendFinishedDeviceScan) {mNeedToSendFinishedDeviceScan = false;event->when = now;event->type = FINISHED_DEVICE_SCAN;event += 1;if (--capacity == 0) {break;}}...// Report added or removed devices immediately.// 有设备变化则马上返回if (deviceChanged) {continue;}// Return now if we have collected any events or if we were explicitly awoken.// 如果有任何的事件则马上退出循环if (event != buffer || awoken) {break;}...}// All done, return the number of events we read.return event - buffer;
}
scanDevicesLocked 又会通过对 scanDirLocked 方法进行扫描, 传入的 DEVICE_PATH 为 dev/input 。
// frameworks/native/services/inputflinger/reader/EventHub.cpp
void EventHub::scanDevicesLocked() {// dev/input 文件夹下status_t result = scanDirLocked(DEVICE_PATH);if (result < 0) {ALOGE("scan dir failed for %s", DEVICE_PATH);}if (isV4lScanningEnabled()) {result = scanVideoDirLocked(VIDEO_DEVICE_PATH);if (result != OK) {ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);}}if (mDevices.find(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) == mDevices.end()) {createVirtualKeyboardLocked();}
}
scanDirLocked 通过 std::filesystem::directory_iterator 开始遍历。遍历到就调用 openDeviceLocked 方法
// 遍历文件夹下面的文件
status_t EventHub::scanDirLocked(const std::string& dirname) {for (const auto& entry : std::filesystem::directory_iterator(dirname)) {openDeviceLocked(entry.path());}return 0;
}
openDeviceLocked 方法,主要通过 open 加载对应节点文件符,并通过 ioctl 获取对应的设备信息,并将信息放到 InputDeviceIdentifier 实体类中,最终将 InputDeviceIdentifier 作为属性 放到 Device 实体类中, 在调用 registerDeviceForEpollLocked 注册到 epoll 中,最后通过 addDeviceLocked 放到 mOpeningDevices 数组中。
void EventHub::openDeviceLocked(const std::string& devicePath) {...// 判断是否已注册 注册就不用for (const auto& [deviceId, device] : mDevices) {if (device->path == devicePath) {return; // device was already registered}}char buffer[80];ALOGV("Opening device: %s", devicePath.c_str());// 打开对应的节点int fd = open(devicePath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);if (fd < 0) {ALOGE("could not open %s, %s\n", devicePath.c_str(), strerror(errno));return;}// 将数据放到 InputDeviceIdentifier 实体类InputDeviceIdentifier identifier;// Get device name.// 获取名称if (ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {ALOGE("Could not get device name for %s: %s", devicePath.c_str(), strerror(errno));} else {buffer[sizeof(buffer) - 1] = '\0';identifier.name = buffer;}...int32_t deviceId = mNextDeviceId++;// 生成 device实体类std::unique_ptr<Device> device = std::make_unique<Device>(fd, deviceId, devicePath, identifier);...// 添加到 epoll 中if (registerDeviceForEpollLocked(*device) != OK) {return;}device->configureFd();...// 添加到 mOpeningDevices 中addDeviceLocked(std::move(device));
}
status_t EventHub::registerDeviceForEpollLocked(Device& device) {status_t result = registerFdForEpoll(device.fd);if (result != OK) {ALOGE("Could not add input device fd to epoll for device %" PRId32, device.id);return result;}if (device.videoDevice) {registerVideoDeviceForEpollLocked(*device.videoDevice);}return result;
}status_t EventHub::registerFdForEpoll(int fd) {// TODO(b/121395353) - consider adding EPOLLRDHUPstruct epoll_event eventItem = {};eventItem.events = EPOLLIN | EPOLLWAKEUP;eventItem.data.fd = fd;if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {ALOGE("Could not add fd to epoll instance: %s", strerror(errno));return -errno;}return OK;
}
// frameworks/native/services/inputflinger/reader/EventHub.cpp
void EventHub::addDeviceLocked(std::unique_ptr<Device> device) {reportDeviceAddedForStatisticsLocked(device->identifier, device->classes);mOpeningDevices.push_back(std::move(device));
}
扫描完成后,添加到 mOpeningDevices 数组,即该数组不为空,回到 getEvents 方法中 则会进入判断,遍历对应的数组,并添加 RawEvent事件对应的,type为 DEVICE_ADDED。并将对应devvice 放到对应 map中。最后因为有设备添加又会添加 FINISHED_DEVICE_SCAN 事件。因为事件和数组不相等会进入break,退出循环。这样设备节点的添加和监听就完成。
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {....while (!mOpeningDevices.empty()) {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());// 添加 对应的 eventevent->when = now;event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;event->type = DEVICE_ADDED;event += 1;// Try to find a matching video device by comparing device namesfor (auto it = mUnattachedVideoDevices.begin(); it != mUnattachedVideoDevices.end();it++) {std::unique_ptr<TouchVideoDevice>& videoDevice = *it;if (tryAddVideoDeviceLocked(*device, videoDevice)) {// videoDevice was transferred to 'device'it = mUnattachedVideoDevices.erase(it);break;}}// 将对应 device 放到 mDevices map中auto [dev_it, inserted] = mDevices.insert_or_assign(device->id, std::move(device));if (!inserted) {ALOGW("Device id %d exists, replaced.", device->id);}mNeedToSendFinishedDeviceScan = true;if (--capacity == 0) {break;}}// 有新增设备的时候,添加 finish事件if (mNeedToSendFinishedDeviceScan) {mNeedToSendFinishedDeviceScan = false;event->when = now;event->type = FINISHED_DEVICE_SCAN;event += 1;if (--capacity == 0) {break;}}...// 如果有任何的事件则马上退出循环if (event != buffer || awoken) {break;}
}
设备输入事件的读取
当添加完又会进入下一个循环,再一次进入 getEvents方法。进入后 即会进入 epoll_wait等待输入事件,当事件返回后,则将对应的数量赋值给 mPendingEventCount ,最后又进入下一次循环。
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {...mPendingEventIndex = 0;mLock.unlock(); // release lock before poll// epoll在等待消息产生,产生消息EventItem都会放到 mPendingEventItems 中,会跟mPendingEventCount比较int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);mLock.lock(); // reacquire lock after pollif (pollResult == 0) {// Timed out.mPendingEventCount = 0;break;}if (pollResult < 0) {// An error occurred.mPendingEventCount = 0;// Sleep after errors to avoid locking up the system.// Hopefully the error is transient.if (errno != EINTR) {ALOGW("poll failed (errno=%d)\n", errno);usleep(100000);}} else {// Some events occurred.// 有多少个输入事件mPendingEventCount = size_t(pollResult);}
}
进入下一次循环后, mPendingEventCount 不为0 ,则会大于 mPendingEventIndex 进入事件的读取,判断对应的fd类型,进行相对应的处理。在通过 getDeviceByFdLocked 从 map中获取对应的device。在通过 read 函数读取对应的数据,并判断是否是input_event的整数倍,不是则为异常数据。最后在读取相关的 code,type,value。放到 RawEvent 中。并返回。
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {...// 有相关输入事件的时候走这里bool deviceChanged = false;while (mPendingEventIndex < mPendingEventCount) {const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];if (eventItem.data.fd == mINotifyFd) {if (eventItem.events & EPOLLIN) {mPendingINotify = true;} else {ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);}continue;}if (eventItem.data.fd == mWakeReadPipeFd) {if (eventItem.events & EPOLLIN) {ALOGV("awoken after wake()");awoken = true;char wakeReadBuffer[16];ssize_t nRead;do {nRead = read(mWakeReadPipeFd, wakeReadBuffer, sizeof(wakeReadBuffer));} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(wakeReadBuffer));} else {ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",eventItem.events);}continue;}// 通过文件描述符获取对应的设备节点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 if (readSize < 0) {if (errno != EAGAIN && errno != EINTR) {ALOGW("could not get event (errno=%d)", errno);}} else if ((readSize % sizeof(struct input_event)) != 0) {// 一定是inputEvent的整数倍ALOGE("could not get event (wrong size: %d)", readSize);} else {int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;// 一定是inputEvent的整数倍size_t count = size_t(readSize) / sizeof(struct input_event);for (size_t i = 0; i < count; i++) {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;}if (capacity == 0) {// The result buffer is full. Reset the pending event index// so we will try to read the device again on the next iteration.mPendingEventIndex -= 1;break;}}} else if (eventItem.events & EPOLLHUP) {ALOGI("Removing device %s due to epoll hang-up event.",device->identifier.name.c_str());deviceChanged = true;closeDeviceLocked(*device);} else {ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,device->identifier.name.c_str());}}
}
总结 事件的读取 通过 getEvents 注册和监听各种事件 并组装成RawEvents实体类返回,如 底层的 input_event 转化为 RawEvents。
InputReader 事件的处理
getEvents 获取后,则要进行事件的处理,processEventsLocked 进行事件的处理。是事件的处理分为 输入事件 和 设备的添加 移除 扫描结束等。
void InputReader::loopOnce() {...size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);{ // acquire lockstd::scoped_lock _l(mLock);mReaderIsAliveCondition.notify_all();// 如果有事件if (count) {// 解析对应的事件processEventsLocked(mEventBuffer, count);}...} // release lock
}
processEventsLocked 开始依次遍历对应的 rawEvents ,因为 DEVICE_ADDED定义的值很大,所以低于 DEVICE_ADDED 都作为输入事件。
// frameworks/native/services/inputflinger/reader/include/EventHub.h
DEVICE_ADDED = 0x10000000,
// Sent when a device is removed.
DEVICE_REMOVED = 0x20000000,
// Sent when all added/removed devices from the most recent scan have been reported.
// This event is always sent at least once.
FINISHED_DEVICE_SCAN = 0x30000000,FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,// frameworks/native/services/inputflinger/reader/InputReader.cpp
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {for (const RawEvent* rawEvent = rawEvents; count;) {int32_t type = rawEvent->type;size_t batchSize = 1;// 输入触摸事件// 比 DEVICE_ADDED 小于都是输入事件if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {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_EVENTSALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endifprocessEventsForDeviceLocked(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 happenbreak;}}count -= batchSize;rawEvent += batchSize;}
}
设备的添加和删除处理
以添加为例,可以看到调用了 addDeviceLocked 方法,该方法 又通过 createDeviceLocked 方法创建对应的 InputDevice 设备 ,将对应的 设备添加 mDevices map中。(这里将getEvents中的 device 又转化为了 InputDevice中)。
void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) {if (mDevices.find(eventHubId) != mDevices.end()) {ALOGW("Ignoring spurious device added event for eventHubId %d.", eventHubId);return;}// 从 mDevices 获取对应的device中的 InputDeviceIdentifierInputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);// 创建对应 InputDevice, 添加到 inputReader的 mdevices中,指定了对应mapper 用于后续的事件处理std::shared_ptr<InputDevice> device = createDeviceLocked(eventHubId, identifier);device->configure(when, &mConfig, 0);device->reset(when);if (device->isIgnored()) {ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s' ""(ignored non-input device)",device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str());} else {ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s',sources=0x%08x",device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str(),device->getSources());}mDevices.emplace(eventHubId, device);// Add device to device to EventHub ids map.const auto mapIt = mDeviceToEventHubIdsMap.find(device);if (mapIt == mDeviceToEventHubIdsMap.end()) {std::vector<int32_t> ids = {eventHubId};mDeviceToEventHubIdsMap.emplace(device, ids);} else {mapIt->second.push_back(eventHubId);}bumpGenerationLocked();if (device->getClasses().test(InputDeviceClass::EXTERNAL_STYLUS)) {notifyExternalStylusPresenceChangedLocked();}// Sensor input device is noisy, to save power disable it by default.// Input device is classified as SENSOR when any sub device is a SENSOR device, check Eventhub// device class to disable SENSOR sub device only.if (mEventHub->getDeviceClasses(eventHubId).test(InputDeviceClass::SENSOR)) {mEventHub->disableDevice(eventHubId);}
}
createDeviceLocked 方法中 最重要的方法是 addEventHubDevice 方法 该方法根据对应的设备类型,添加对应的mapper。而mapper作为后续输入事件对应的处理方法。
std::shared_ptr<InputDevice> InputReader::createDeviceLocked(int32_t eventHubId, const InputDeviceIdentifier& identifier) {// 通过 find_if 搜索对应的 看是否有对应的auto deviceIt = std::find_if(mDevices.begin(), mDevices.end(), [identifier](auto& devicePair) {return devicePair.second->getDescriptor().size() && identifier.descriptor.size() &&devicePair.second->getDescriptor() == identifier.descriptor;});std::shared_ptr<InputDevice> device;if (deviceIt != mDevices.end()) {device = deviceIt->second;} else {int32_t deviceId = (eventHubId < END_RESERVED_ID) ? eventHubId : nextInputDeviceIdLocked();device = std::make_shared<InputDevice>(&mContext, deviceId, bumpGenerationLocked(),identifier);}device->addEventHubDevice(eventHubId);return device;
}
addEventHubDevice 通过对应的class 判断,这里分析的是多指触摸,所以添加的 mapper 为 MultiTouchInputMapper 。
// frameworks/native/services/inputflinger/reader/InputDevice.cpp
void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {// 如果存在则不处理if (mDevices.find(eventHubId) != mDevices.end()) {return;}std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));Flags<InputDeviceClass> classes = contextPtr->getDeviceClasses();std::vector<std::unique_ptr<InputMapper>> mappers;// Check if we should skip population...// Touchscreens and touchpad devices.// 如果是触摸的,分多指和单指,大部分都是单指if (classes.test(InputDeviceClass::TOUCH_MT)) {mappers.push_back(std::make_unique<MultiTouchInputMapper>(*contextPtr));} else if (classes.test(InputDeviceClass::TOUCH)) {mappers.push_back(std::make_unique<SingleTouchInputMapper>(*contextPtr));}// Joystick-like devices.if (classes.test(InputDeviceClass::JOYSTICK)) {mappers.push_back(std::make_unique<JoystickInputMapper>(*contextPtr));}...// insert the context into the devices setmDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});// Must change generation to flag this device as changedbumpGeneration();
}
总结 添加和删除 将 device转化为 InputDevice,生成的时候 添加对应的事件处理mapper。并方法 mDevices map中,移除则为移除该设备从map中。
触摸事件的处理
触摸事件会将同个设备一系列事件,通过 processEventsForDeviceLocked 进行处理。
// frameworks/native/services/inputflinger/reader/InputReader.cppint32_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_EVENTSALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endifprocessEventsForDeviceLocked(deviceId, rawEvent, batchSize); // 处理事件
该方法里面又会通过 eventHubId 获取对应的InputDevice,并调用 process 方法进行处理。
// frameworks/native/services/inputflinger/reader/InputReader.cpp
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;// mapper为空,不处理if (device->isIgnored()) {// ALOGD("Discarding event for ignored deviceId %d.", deviceId);return;}device->process(rawEvents, count);
}
InputDevice 的 process 方法又会将之前设备添加 mapper 进行遍历,之前说过多指触摸的mapper 为 MultiTouchInputMapper ,所以会调用到他的 process 方法。
// frameworks/native/services/inputflinger/reader/InputDevice.cpp
void InputDevice::process(const RawEvent* rawEvents, size_t count) {for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {...} else {for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {// 多指触碰是 MultiTouchMotionAccumulatormapper.process(rawEvent);});}--count;}
}
对应的 process 方法第一步 先进入 TouchInputMapper::process, 但是该方法里面判断为系列事件结束才会进入,所以事件刚开始并不会执行里面逻辑,而是执行 下一个方法。而 mMultiTouchMotionAccumulator.process 则是将对应 type 为 EV_ABS 进行读取 并赋值到 Slot 实体中,最终再由 TouchInputMapper 结束事件统一处理。
// 先执行这个方法
void MultiTouchInputMapper::process(const RawEvent* rawEvent) {// 处理sync SYN_REPORT 事件TouchInputMapper::process(rawEvent);// 处理ABS事件mMultiTouchMotionAccumulator.process(rawEvent);
}
最大支持触摸为16个, 其中 mCurrentSlot 是通过底层驱动给的值,并通过 mSlots 中获取对应 Slot 实体类,在将拿的值和类型填充到对应的属性。注意如果 ABS_MT_TRACKING_ID 为负数,则表示抬起,所以 mInUse 会被值为 false。
// frameworks/native/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {if (rawEvent->type == EV_ABS) {bool newSlot = false;// 是否符合多指触摸的b协议if (mUsingSlotsProtocol) {// 代表一个触摸点,接下来所有事件属于这个触摸点if (rawEvent->code == ABS_MT_SLOT) {mCurrentSlot = rawEvent->value;newSlot = true;}} else if (mCurrentSlot < 0) {mCurrentSlot = 0;}// 最大支持16个手指if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) {
#if DEBUG_POINTERSif (newSlot) {ALOGW("MultiTouch device emitted invalid slot index %d but it ""should be between 0 and %zd; ignoring this slot.",mCurrentSlot, mSlotCount - 1);}
#endif} else {Slot* slot = &mSlots[mCurrentSlot];// If mUsingSlotsProtocol is true, it means the raw pointer has axis info of// ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while// updating the slot.if (!mUsingSlotsProtocol) {slot->mInUse = true;}// 根据对应的code 将对应的值 赋值到 slot属性中switch (rawEvent->code) {case ABS_MT_POSITION_X:slot->mAbsMTPositionX = rawEvent->value;warnIfNotInUse(*rawEvent, *slot);break;case ABS_MT_POSITION_Y:slot->mAbsMTPositionY = rawEvent->value;warnIfNotInUse(*rawEvent, *slot);break;case ABS_MT_TOUCH_MAJOR:slot->mAbsMTTouchMajor = rawEvent->value;break;case ABS_MT_TOUCH_MINOR:slot->mAbsMTTouchMinor = rawEvent->value;slot->mHaveAbsMTTouchMinor = true;break;case ABS_MT_WIDTH_MAJOR:slot->mAbsMTWidthMajor = rawEvent->value;break;case ABS_MT_WIDTH_MINOR:slot->mAbsMTWidthMinor = rawEvent->value;slot->mHaveAbsMTWidthMinor = true;break;case ABS_MT_ORIENTATION:slot->mAbsMTOrientation = rawEvent->value;break;case ABS_MT_TRACKING_ID:// 对应ID 如果是 FFFFFFF 小于0,表示抬起if (mUsingSlotsProtocol && rawEvent->value < 0) {// The slot is no longer in use but it retains its previous contents,// which may be reused for subsequent touches.slot->mInUse = false;} else {slot->mInUse = true;slot->mAbsMTTrackingId = rawEvent->value;}break;case ABS_MT_PRESSURE:slot->mAbsMTPressure = rawEvent->value;break;case ABS_MT_DISTANCE:slot->mAbsMTDistance = rawEvent->value;break;case ABS_MT_TOOL_TYPE:slot->mAbsMTToolType = rawEvent->value;slot->mHaveAbsMTToolType = true;break;}}} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {// 表示事件结束// MultiTouch Sync: The driver has returned all data for *one* of the pointers.mCurrentSlot += 1;}
}
组装好 slot数据后,就会进入到事件结束标志位 SYN_REPORT,所以会调用 sync 方法。
// 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(rawEvent->when, rawEvent->readTime);}
}
进入 sync 方法,会拿出 RawState 对象并进行清空 操作。在调用 syncTouch 方法。该方法即为 MultiTouchInputMapper.cpp 的 syncTouch 方法。
// frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp
void TouchInputMapper::sync(nsecs_t when, nsecs_t readTime) {// Push a new state.mRawStatesPending.emplace_back();// 获取rawState,并对变量进行重置RawState& next = mRawStatesPending.back();next.clear();next.when = when;next.readTime = readTime;// Sync button state.next.buttonState =mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState();// Sync scrollnext.rawVScroll = mCursorScrollAccumulator.getRelativeVWheel();next.rawHScroll = mCursorScrollAccumulator.getRelativeHWheel();mCursorScrollAccumulator.finishSync();// Sync touch// 调用多指 MultiTouchInputMapper的syncTouchsyncTouch(when, &next);// The last RawState is the actually second to last, since we just added a new stateconst RawState& last =mRawStatesPending.size() == 1 ? mCurrentRawState : mRawStatesPending.rbegin()[1];// Assign pointer ids.if (!mHavePointerIds) {assignPointerIds(last, next);}...// 对数据进行加工processRawTouches(false /*timeout*/);
}
回到 MultiTouchInputMapper 中, 该返回获取对应的事件数量,并进行遍历。判断到 isInUse 为 false 表示抬起 不处理。接着从 outState 取出 RawPointerData类,因为上一部已经清空,所以里面不会有内容。并将值赋值给了他。
里面有比较重要的属性是 idToIndex 以及 id。他对应了 ToucheEvent里面的 index 和他对应的value 。由一个32位的int值控制,从高位开始排起,记录每个手指对应的id。
第一步: mPointerIdBits 赋值给临时的 idBits,并通过 clearFirstMarkedBit (先获取对应的前导0,在将该位1值为0),获取到对应的位数后,在从 mPointerTrackingIdMap 判断是否和 trackingId相等 相等则表示id 为n, 不相等则进入下一步
第二步:当id小于0 , 则通过 markFirstUnmarkedBit (对该数值取反得到前导0,在将该位变1),并将前导0 作为该id。
第三步:将对应的 outCount(outCount遍历一次加1) 赋值给index,id赋值给id。并通过markBit(针对哪位变为1) 对 newPointerIdBits 新变量 记录 有手指的标志位 。因为抬起的时候需要将该位变为0,上面只是添加,所以最后在将 newPointerIdBits 赋值给 mPointerIdBits,用于下一次事件的判断。
void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();size_t outCount = 0;BitSet32 newPointerIdBits;mHavePointerIds = true;for (size_t inIndex = 0; inIndex < inCount; inIndex++) {const MultiTouchMotionAccumulator::Slot* inSlot =mMultiTouchMotionAccumulator.getSlot(inIndex);// 抬起为false不处理if (!inSlot->isInUse()) {continue;}if (inSlot->getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) {std::optional<int32_t> id = getActiveBitId(*inSlot);if (id) {outState->rawPointerData.canceledIdBits.markBit(id.value());}
#if DEBUG_POINTERSALOGI("Stop processing slot %zu for it received a palm event from device %s", inIndex,getDeviceName().c_str());
#endifcontinue;}if (outCount >= MAX_POINTERS) {
#if DEBUG_POINTERSALOGD("MultiTouch device %s emitted more than maximum of %d pointers; ""ignoring the rest.",getDeviceName().c_str(), MAX_POINTERS);
#endifbreak; // too many fingers!}// 将数据从slot 转化为rawPointerData, 拿出来为空的.outState传进来已被清空RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];outPointer.x = inSlot->getX();outPointer.y = inSlot->getY();outPointer.pressure = inSlot->getPressure();outPointer.touchMajor = inSlot->getTouchMajor();outPointer.touchMinor = inSlot->getTouchMinor();outPointer.toolMajor = inSlot->getToolMajor();outPointer.toolMinor = inSlot->getToolMinor();outPointer.orientation = inSlot->getOrientation();outPointer.distance = inSlot->getDistance();outPointer.tiltX = 0;outPointer.tiltY = 0;outPointer.toolType = inSlot->getToolType();if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {outPointer.toolType = mTouchButtonAccumulator.getToolType();if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;}}bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE &&(mTouchButtonAccumulator.isHovering() ||(mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0));outPointer.isHovering = isHovering;// Assign pointer id using tracking id if available.// 处理事件 touch 里面 index 以值的关系if (mHavePointerIds) {// 获取对应的IDint32_t trackingId = inSlot->getTrackingId();int32_t id = -1;if (trackingId >= 0) {// 将mPointerIdBits 赋值给idBits,第一次为0,for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) {// 拿前导位有多少 然后清空当前的位为0uint32_t n = idBits.clearFirstMarkedBit();// 从map拿出 如果相等则id赋值给他if (mPointerTrackingIdMap[n] == trackingId) {id = n;}}if (id < 0 && !mPointerIdBits.isFull()) {// 如果没找到,则取反返回前导0的位,并将该位置为1,并保存到map中id = mPointerIdBits.markFirstUnmarkedBit();mPointerTrackingIdMap[id] = trackingId;}}if (id < 0) {mHavePointerIds = false;outState->rawPointerData.clearIdBits();newPointerIdBits.clear();} else {// 对应值outPointer.id = id;// 对应touchEvent的 index,当2个手指按下抬起第一个,outCount变为0,id依旧为1outState->rawPointerData.idToIndex[id] = outCount;outState->rawPointerData.markIdBit(id, isHovering);// 标记下新的位数,因为前面mPointerIdBits 不会清除,比如抬起第一个手指 这时候mPointerIdBits 还是1100000// 所以要用新的变量记录最新的手指按下情况newPointerIdBits.markBit(id);}}outCount += 1;}// 记录手指数量outState->rawPointerData.pointerCount = outCount;// 赋值给 newPointerIdBits 这样抬起的位数就变为0mPointerIdBits = newPointerIdBits;mMultiTouchMotionAccumulator.finishSync();
}
对应32位工具类方法的讲解
// system/core/libutils/include/utils/BitSet.h
/** Copyright (C) 2010 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#ifndef UTILS_BITSET_H
#define UTILS_BITSET_H#include <stdint.h>
#include <utils/TypeHelpers.h>/** A class to provide efficient manipulation of bitsets.** Consider using std::bitset<32> or std::bitset<64> if all you want is a class to do basic bit* manipulation (i.e. AND / OR / XOR / flip / etc). These classes are only needed if you want to* efficiently perform operations like finding the first set bit in a bitset and you want to* avoid using the built-in functions (e.g. __builtin_clz) on std::bitset::to_ulong.*/namespace android {// A simple set of 32 bits that can be individually marked or cleared.
struct BitSet32 {uint32_t value;inline BitSet32() : value(0UL) { }explicit inline BitSet32(uint32_t value) : value(value) { }// Gets the value associated with a particular bit index.// 函数作用表示向右移动多少位// 0x80000000UL 32位数表示为 10000000000000000000000000000000static inline uint32_t valueForBit(uint32_t n) { return 0x80000000UL >> n; }// Clears the bit set.inline void clear() { clear(value); }static inline void clear(uint32_t& value) { value = 0UL; }// Returns the number of marked bits in the set.inline uint32_t count() const { return count(value); }static inline uint32_t count(uint32_t value) {return static_cast<uint32_t>(__builtin_popcountl(value));}// Returns true if the bit set does not contain any marked bits.inline bool isEmpty() const { return isEmpty(value); }static inline bool isEmpty(uint32_t value) { return ! value; }// Returns true if the bit set does not contain any unmarked bits.inline bool isFull() const { return isFull(value); }static inline bool isFull(uint32_t value) { return value == 0xffffffffUL; }// Returns true if the specified bit is marked.inline bool hasBit(uint32_t n) const { return hasBit(value, n); }static inline bool hasBit(uint32_t value, uint32_t n) { return value & valueForBit(n); }// Marks the specified bit.inline void markBit(uint32_t n) { markBit(value, n); }static inline void markBit (uint32_t& value, uint32_t n) { value |= valueForBit(n); }// Clears the specified bit.// 向右移动多少位在取反,在与运算,等于保留其他位,将特定的位取反inline void clearBit(uint32_t n) { clearBit(value, n); }static inline void clearBit(uint32_t& value, uint32_t n) { value &= ~ valueForBit(n); }// Finds the first marked bit in the set.// Result is undefined if all bits are unmarked.inline uint32_t firstMarkedBit() const { return firstMarkedBit(value); }static uint32_t firstMarkedBit(uint32_t value) { return clz_checked(value); }// Finds the first unmarked bit in the set.// Result is undefined if all bits are marked.inline uint32_t firstUnmarkedBit() const { return firstUnmarkedBit(value); }static inline uint32_t firstUnmarkedBit(uint32_t value) { return clz_checked(~ value); }// Finds the last marked bit in the set.// Result is undefined if all bits are unmarked.inline uint32_t lastMarkedBit() const { return lastMarkedBit(value); }static inline uint32_t lastMarkedBit(uint32_t value) { return 31 - ctz_checked(value); }// Finds the first marked bit in the set and clears it. Returns the bit index.// Result is undefined if all bits are unmarked.// 第一步先获取前导0多少位,则第一个为1前面多少位0// 第二步清除对应位数的1变为0// 返回前面有多少位inline uint32_t clearFirstMarkedBit() { return clearFirstMarkedBit(value); }static inline uint32_t clearFirstMarkedBit(uint32_t& value) {uint32_t n = firstMarkedBit(value);clearBit(value, n);return n;}// Finds the first unmarked bit in the set and marks it. Returns the bit index.// Result is undefined if all bits are marked.// 1.先获取前导数量为0的个数// 2.对对应的位数标记为1// 3.返回前导数量inline uint32_t markFirstUnmarkedBit() { return markFirstUnmarkedBit(value); }static inline uint32_t markFirstUnmarkedBit(uint32_t& value) {uint32_t n = firstUnmarkedBit(value);markBit(value, n);return n;}// Finds the last marked bit in the set and clears it. Returns the bit index.// Result is undefined if all bits are unmarked.inline uint32_t clearLastMarkedBit() { return clearLastMarkedBit(value); }static inline uint32_t clearLastMarkedBit(uint32_t& value) {uint32_t n = lastMarkedBit(value);clearBit(value, n);return n;}// Gets the index of the specified bit in the set, which is the number of// marked bits that appear before the specified bit.inline uint32_t getIndexOfBit(uint32_t n) const {return getIndexOfBit(value, n);}static inline uint32_t getIndexOfBit(uint32_t value, uint32_t n) {return static_cast<uint32_t>(__builtin_popcountl(value & ~(0xffffffffUL >> n)));}inline bool operator== (const BitSet32& other) const { return value == other.value; }inline bool operator!= (const BitSet32& other) const { return value != other.value; }inline BitSet32 operator& (const BitSet32& other) const {return BitSet32(value & other.value);}inline BitSet32& operator&= (const BitSet32& other) {value &= other.value;return *this;}inline BitSet32 operator| (const BitSet32& other) const {return BitSet32(value | other.value);}inline BitSet32& operator|= (const BitSet32& other) {value |= other.value;return *this;}private:// We use these helpers as the signature of __builtin_c{l,t}z has "unsigned int" for the// input, which is only guaranteed to be 16b, not 32. The compiler should optimize this away.static inline uint32_t clz_checked(uint32_t value) {if (sizeof(unsigned int) == sizeof(uint32_t)) {return static_cast<uint32_t>(__builtin_clz(value));} else {return static_cast<uint32_t>(__builtin_clzl(value));}}static inline uint32_t ctz_checked(uint32_t value) {if (sizeof(unsigned int) == sizeof(uint32_t)) {return static_cast<uint32_t>(__builtin_ctz(value));} else {return static_cast<uint32_t>(__builtin_ctzl(value));}}
};ANDROID_BASIC_TYPES_TRAITS(BitSet32)// A simple set of 64 bits that can be individually marked or cleared.
struct BitSet64 {uint64_t value;inline BitSet64() : value(0ULL) { }explicit inline BitSet64(uint64_t value) : value(value) { }// Gets the value associated with a particular bit index.// 右移动几位static inline uint64_t valueForBit(uint32_t n) { return 0x8000000000000000ULL >> n; }// Marks the specified bit.// 对该位赋值为1inline void markBit(uint32_t n) { markBit(value, n); }static inline void markBit(uint64_t& value, uint32_t n) { value |= valueForBit(n); }// Clears the specified bit.inline void clearBit(uint32_t n) { clearBit(value, n); }static inline void clearBit(uint64_t& value, uint32_t n) { value &= ~ valueForBit(n); }// Finds the first marked bit in the set.// Result is undefined if all bits are unmarked.// 输出前导为0的个数,如 8 32位数// 0000 0000 0000 0000 0000 0000 0000 1000 28个前导0 输出28inline uint32_t firstMarkedBit() const { return firstMarkedBit(value); }static inline uint32_t firstMarkedBit(uint64_t value) {return static_cast<uint32_t>(__builtin_clzll(value));}// Finds the first unmarked bit in the set.// Result is undefined if all bits are marked.// 输出前导为0的个数,如 8 32位数// 注意这里取反获取// 1000 0000 0000 0000 0000 0000 0000 0000// 取反得 0111 1111 1111 1111 1111 1111 1111 1111// 返回1inline uint32_t firstUnmarkedBit() const { return firstUnmarkedBit(value); }static inline uint32_t firstUnmarkedBit(uint64_t value) {return static_cast<uint32_t>(__builtin_clzll(~value));}// Finds the first unmarked bit in the set and marks it. Returns the bit index.// Result is undefined if all bits are marked.// 1.先获取前导数量为0的个数 里面做了取反// 2.对对应的位数标记为1// 3.返回前导数量inline uint32_t markFirstUnmarkedBit() { return markFirstUnmarkedBit(value); }static inline uint32_t markFirstUnmarkedBit(uint64_t& value) {uint32_t n = firstUnmarkedBit(value);markBit(value, n);return n;}
};ANDROID_BASIC_TYPES_TRAITS(BitSet64)} // namespace android#endif // UTILS_BITSET_H
总结 输入事件 先将对应的RawEvent 转化为 slot 类,在将 slot类转化为 RawPointerData,并算出触摸对应的id 和index。
数据的加工和分发
事件处理完后, 要到 inputDispatcher 还需要进一步的加工 ,执行完 syncTouch后,调用 processRawTouches。对事件进行一个加工。
void TouchInputMapper::sync(nsecs_t when, nsecs_t readTime) {// Push a new state.mRawStatesPending.emplace_back();// 获取rawState,并对变量进行重置RawState& next = mRawStatesPending.back();next.clear();next.when = when;next.readTime = readTime;// Sync button state.next.buttonState =mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState();// Sync scrollnext.rawVScroll = mCursorScrollAccumulator.getRelativeVWheel();next.rawHScroll = mCursorScrollAccumulator.getRelativeHWheel();mCursorScrollAccumulator.finishSync();// Sync touch// 调用多指 MultiTouchInputMapper的syncTouchsyncTouch(when, &next);...// 对数据进行加工processRawTouches(false /*timeout*/);
}
查看对应的方法,一开始对 mDeviceMode属性进行判断,如果为 disable 则不处理事件。然后会调用 cookAndDispatch 方法进行事件的处理和分发。
// frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp
void TouchInputMapper::processRawTouches(bool timeout) {// 如果不允许触摸就拦截if (mDeviceMode == DeviceMode::DISABLED) {// Drop all input if the device is disabled.cancelTouch(mCurrentRawState.when, mCurrentRawState.readTime);mCurrentCookedState.clear();updateTouchSpots();return;}// Drain any pending touch states. The invariant here is that the mCurrentRawState is always// valid and must go through the full cook and dispatch cycle. This ensures that anything// touching the current state will only observe the events that have been dispatched to the// rest of the pipeline.const size_t N = mRawStatesPending.size();size_t count;for (count = 0; count < N; count++) {const RawState& next = mRawStatesPending[count];// A failure to assign the stylus id means that we're waiting on stylus data// and so should defer the rest of the pipeline.if (assignExternalStylusId(next, timeout)) {break;}// All ready to go.clearStylusDataPendingFlags();mCurrentRawState.copyFrom(next);if (mCurrentRawState.when < mLastRawState.when) {mCurrentRawState.when = mLastRawState.when;mCurrentRawState.readTime = mLastRawState.readTime;}// 加工和分发cookAndDispatch(mCurrentRawState.when, mCurrentRawState.readTime);}if (count != 0) {mRawStatesPending.erase(mRawStatesPending.begin(), mRawStatesPending.begin() + count);}if (mExternalStylusDataPending) {if (timeout) {nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY;clearStylusDataPendingFlags();mCurrentRawState.copyFrom(mLastRawState);
#if DEBUG_STYLUS_FUSIONALOGD("Timeout expired, synthesizing event with new stylus data");
#endifconst nsecs_t readTime = when; // consider this synthetic event to be zero latencycookAndDispatch(when, readTime);} else if (mExternalStylusFusionTimeout == LLONG_MAX) {mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT;getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);}}
}
cookAndDispatch 方法 主要对 2步
- 调用 cookPointerData 将数据做一个转换,将对应的RawPointerData 加工为 PointerCoords,主要对数据跟设备的配置参数做一个校准,进行相对的转换,转换x ,y 符合屏幕数据
- 调用 dispatchTouches, 对事件是 down 还是 move ,up进行判断。
void TouchInputMapper::cookAndDispatch(nsecs_t when, nsecs_t readTime) {// Always start with a clean state.mCurrentCookedState.clear();// Apply stylus buttons to current raw state.applyExternalStylusButtonState(when);// Handle policy on initial down or hover events.bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 &&mCurrentRawState.rawPointerData.pointerCount != 0;uint32_t policyFlags = 0;bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState;if (initialDown || buttonsPressed) {// If this is a touch screen, hide the pointer on an initial down.if (mDeviceMode == DeviceMode::DIRECT) {getContext()->fadePointer();}if (mParameters.wake) {policyFlags |= POLICY_FLAG_WAKE;}}// Consume raw off-screen touches before cooking pointer data.// If touches are consumed, subsequent code will not receive any pointer data.// 消费屏幕外的输入事件if (consumeRawTouches(when, readTime, policyFlags)) {mCurrentRawState.rawPointerData.clear();}// Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure// with cooked pointer data that has the same ids and indices as the raw data.// The following code can use either the raw or cooked data, as needed.// 将对应的RawPointerData 加工为 PointerCoordscookPointerData();// Apply stylus pressure to current cooked state.applyExternalStylusTouchState(when);// Synthesize key down from raw buttons if needed.synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, readTime, getDeviceId(),mSource, mViewport.displayId, policyFlags, mLastCookedState.buttonState,mCurrentCookedState.buttonState);// Dispatch the touches either directly or by translation through a pointer on screen.if (mDeviceMode == DeviceMode::POINTER) {for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); !idBits.isEmpty();) {uint32_t id = idBits.clearFirstMarkedBit();const RawPointerData::Pointer& pointer =mCurrentRawState.rawPointerData.pointerForId(id);if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS ||pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {mCurrentCookedState.stylusIdBits.markBit(id);} else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER ||pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {mCurrentCookedState.fingerIdBits.markBit(id);} else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {mCurrentCookedState.mouseIdBits.markBit(id);}}for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits); !idBits.isEmpty();) {uint32_t id = idBits.clearFirstMarkedBit();const RawPointerData::Pointer& pointer =mCurrentRawState.rawPointerData.pointerForId(id);if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS ||pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {mCurrentCookedState.stylusIdBits.markBit(id);}}// Stylus takes precedence over all tools, then mouse, then finger.PointerUsage pointerUsage = mPointerUsage;if (!mCurrentCookedState.stylusIdBits.isEmpty()) {mCurrentCookedState.mouseIdBits.clear();mCurrentCookedState.fingerIdBits.clear();pointerUsage = PointerUsage::STYLUS;} else if (!mCurrentCookedState.mouseIdBits.isEmpty()) {mCurrentCookedState.fingerIdBits.clear();pointerUsage = PointerUsage::MOUSE;} else if (!mCurrentCookedState.fingerIdBits.isEmpty() ||isPointerDown(mCurrentRawState.buttonState)) {pointerUsage = PointerUsage::GESTURES;}dispatchPointerUsage(when, readTime, policyFlags, pointerUsage);} else {updateTouchSpots();if (!mCurrentMotionAborted) {dispatchButtonRelease(when, readTime, policyFlags);dispatchHoverExit(when, readTime, policyFlags);// 对事件进行分发,判断是move 还是down,up事件dispatchTouches(when, readTime, policyFlags);dispatchHoverEnterAndMove(when, readTime, policyFlags);dispatchButtonPress(when, readTime, policyFlags);}if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {mCurrentMotionAborted = false;}}// Synthesize key up from raw buttons if needed.synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, readTime, getDeviceId(), mSource,mViewport.displayId, policyFlags, mLastCookedState.buttonState,mCurrentCookedState.buttonState);// Clear some transient state.mCurrentRawState.rawVScroll = 0;mCurrentRawState.rawHScroll = 0;// Copy current touch to last touch in preparation for the next cycle.mLastRawState.copyFrom(mCurrentRawState);mLastCookedState.copyFrom(mCurrentCookedState);
}
cookPointerData 方法 ,开始遍历并通过 scale 等参数进行数据的转换,转换后存到 PointerCoords 中。
void TouchInputMapper::cookPointerData() {uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount;mCurrentCookedState.cookedPointerData.clear();mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount;mCurrentCookedState.cookedPointerData.hoveringIdBits =mCurrentRawState.rawPointerData.hoveringIdBits;mCurrentCookedState.cookedPointerData.touchingIdBits =mCurrentRawState.rawPointerData.touchingIdBits;mCurrentCookedState.cookedPointerData.canceledIdBits =mCurrentRawState.rawPointerData.canceledIdBits;if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {mCurrentCookedState.buttonState = 0;} else {mCurrentCookedState.buttonState = mCurrentRawState.buttonState;}// Walk through the the active pointers and map device coordinates onto// surface coordinates and adjust for display orientation.for (uint32_t i = 0; i < currentPointerCount; i++) {const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i];...// Distancefloat distance;switch (mCalibration.distanceCalibration) {case Calibration::DistanceCalibration::SCALED:distance = in.distance * mDistanceScale;break;default:distance = 0;}// Adjust X,Y coords for device calibration// TODO: Adjust coverage coords?// 转化为浮点数float xTransformed = in.x, yTransformed = in.y;mAffineTransform.applyTo(xTransformed, yTransformed);// 获取对应的x,y坐标rotateAndScale(xTransformed, yTransformed);// Adjust X, Y, and coverage coords for surface orientation.float left, top, right, bottom;// 根据屏幕方向算出对应的left rightswitch (mSurfaceOrientation) {case DISPLAY_ORIENTATION_90:left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;orientation -= M_PI_2;if (mOrientedRanges.haveOrientation &&orientation < mOrientedRanges.orientation.min) {orientation +=(mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);}break;case DISPLAY_ORIENTATION_180:left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;orientation -= M_PI;if (mOrientedRanges.haveOrientation &&orientation < mOrientedRanges.orientation.min) {orientation +=(mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);}break;case DISPLAY_ORIENTATION_270:left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;orientation += M_PI_2;if (mOrientedRanges.haveOrientation &&orientation > mOrientedRanges.orientation.max) {orientation -=(mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);}break;default:left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;break;}// Write output coords.// 将值写进 PointerCoordsPointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i];out.clear();out.setAxisValue(AMOTION_EVENT_AXIS_X, xTransformed);out.setAxisValue(AMOTION_EVENT_AXIS_Y, yTransformed);out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size);out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor);out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor);out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt);out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance);if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::BOX) {out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left);out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top);out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right);out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom);} else {out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor);out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);}...// Write id index and mark id as valid.// 对应的index和idmCurrentCookedState.cookedPointerData.idToIndex[id] = i;mCurrentCookedState.cookedPointerData.validIdBits.markBit(id);}
}
参数的读取 可以按以下方法。
执行 getevent -ltr 然后触摸获取对应的 触摸点 如获取到的为 /dev/input/event7。
然后在执行 dumpsys input 获取对应的信息,然后看对应的名称,如下图 /dev/input/event7 对应的是 synaptics_tcm_touch。
在通过查看对应的设备7 则可以看到相关的信息
dispatchTouches 方法中,则通过上一个事件的bit和当前的bit位,比较获取判断事件类型。
如果前后int值相等,则肯定为 move事件。
在通过与或判断是否有按下或者抬起事件,需要注意 move事件判断是否
void TouchInputMapper::dispatchTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {// 获取当前的触点BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;// 上一次的触点BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits;int32_t metaState = getContext()->getGlobalMetaState();int32_t buttonState = mCurrentCookedState.buttonState;// 前后一样,肯定是move事件if (currentIdBits == lastIdBits) {if (!currentIdBits.isEmpty()) {// No pointer id changes so this is a move event.// The listener takes care of batching moves so we don't have to deal with that here.dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0,metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,mCurrentCookedState.cookedPointerData.pointerProperties,mCurrentCookedState.cookedPointerData.pointerCoords,mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1,mOrientedXPrecision, mOrientedYPrecision, mDownTime);}} else {// There may be pointers going up and pointers going down and pointers moving// all at the same time.// 取出抬起的BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);// 取出按下的BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);// 取出移动的BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);BitSet32 dispatchedIdBits(lastIdBits.value);// Update last coordinates of pointers that have moved so that we observe the new// pointer positions at the same time as other pointers that have just gone up.// 判断移动的bits是否坐标一样,不一样需要移动bool moveNeeded =updateMovedPointers(mCurrentCookedState.cookedPointerData.pointerProperties,mCurrentCookedState.cookedPointerData.pointerCoords,mCurrentCookedState.cookedPointerData.idToIndex,mLastCookedState.cookedPointerData.pointerProperties,mLastCookedState.cookedPointerData.pointerCoords,mLastCookedState.cookedPointerData.idToIndex, moveIdBits);if (buttonState != mLastCookedState.buttonState) {moveNeeded = true;}// Dispatch pointer up events.// 遍历抬起的id,传递up事件while (!upIdBits.isEmpty()) {uint32_t upId = upIdBits.clearFirstMarkedBit();bool isCanceled = mCurrentCookedState.cookedPointerData.canceledIdBits.hasBit(upId);if (isCanceled) {ALOGI("Canceling pointer %d for the palm event was detected.", upId);}dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0,isCanceled ? AMOTION_EVENT_FLAG_CANCELED : 0, metaState, buttonState, 0,mLastCookedState.cookedPointerData.pointerProperties,mLastCookedState.cookedPointerData.pointerCoords,mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId,mOrientedXPrecision, mOrientedYPrecision, mDownTime);dispatchedIdBits.clearBit(upId);mCurrentCookedState.cookedPointerData.canceledIdBits.clearBit(upId);}// Dispatch move events if any of the remaining pointers moved from their old locations.// Although applications receive new locations as part of individual pointer up// events, they do not generally handle them except when presented in a move event.// 判断是否移动事件if (moveNeeded && !moveIdBits.isEmpty()) {ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0,metaState, buttonState, 0,mCurrentCookedState.cookedPointerData.pointerProperties,mCurrentCookedState.cookedPointerData.pointerCoords,mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, -1,mOrientedXPrecision, mOrientedYPrecision, mDownTime);}// Dispatch pointer down events using the new pointer locations.// 如果down不为空,遍历下while (!downIdBits.isEmpty()) {uint32_t downId = downIdBits.clearFirstMarkedBit();dispatchedIdBits.markBit(downId);if (dispatchedIdBits.count() == 1) {// First pointer is going down. Set down time.mDownTime = when;}dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN,0, 0, metaState, buttonState, 0,mCurrentCookedState.cookedPointerData.pointerProperties,mCurrentCookedState.cookedPointerData.pointerCoords,mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits,downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);}}
}