frameworks 之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;
}
// 初始化NativeInputManager
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
// 将im指针转换为jlong类型,返回给java 后续其他对象可通过该值获取 NativeInputManager
return 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;
// 初始化 InputManager
InputManager* im = new InputManager(this, this);
mInputManager = im;
// 添加该服务到 sm 中 inputflinger
defaultServiceManager()->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 创建 InputDispatcher
mDispatcher = createInputDispatcher(dispatcherPolicy);
// 将 dispatcher 传入 InputClassifier
mClassifier = new InputClassifier(mDispatcher);
// 通过 InputReaderFactory 创建 reader
mReader = 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();
// 创建epoll
mEpollFd = 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 lock
std::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 lock
std::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_EVENTS
ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
mNextTimeout = 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 变为true
if (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());
// 添加 对应的 event
event->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 names
for (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 EPOLLRDHUP
struct 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());
// 添加 对应的 event
event->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 names
for (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 poll
if (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 lock
std::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_EVENTS
ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
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;
}
}
设备的添加和删除处理
以添加为例,可以看到调用了 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中的 InputDeviceIdentifier
InputDeviceIdentifier 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 set
mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
// Must change generation to flag this device as changed
bumpGeneration();
}
总结 添加和删除 将 device转化为 InputDevice,生成的时候 添加对应的事件处理mapper。并方法 mDevices map中,移除则为移除该设备从map中。
触摸事件的处理
触摸事件会将同个设备一系列事件,通过 processEventsForDeviceLocked 进行处理。
// frameworks/native/services/inputflinger/reader/InputReader.cpp
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);
#endif
processEventsForDeviceLocked(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) {
// 多指触碰是 MultiTouchMotionAccumulator
mapper.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_POINTERS
if (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 scroll
next.rawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
next.rawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
mCursorScrollAccumulator.finishSync();
// Sync touch
// 调用多指 MultiTouchInputMapper的syncTouch
syncTouch(when, &next);
// The last RawState is the actually second to last, since we just added a new state
const 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_POINTERS
ALOGI("Stop processing slot %zu for it received a palm event from device %s", inIndex,
getDeviceName().c_str());
#endif
continue;
}
if (outCount >= MAX_POINTERS) {
#if DEBUG_POINTERS
ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; "
"ignoring the rest.",
getDeviceName().c_str(), MAX_POINTERS);
#endif
break; // 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) {
// 获取对应的ID
int32_t trackingId = inSlot->getTrackingId();
int32_t id = -1;
if (trackingId >= 0) {
// 将mPointerIdBits 赋值给idBits,第一次为0,
for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) {
// 拿前导位有多少 然后清空当前的位为0
uint32_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依旧为1
outState->rawPointerData.idToIndex[id] = outCount;
outState->rawPointerData.markIdBit(id, isHovering);
// 标记下新的位数,因为前面mPointerIdBits 不会清除,比如抬起第一个手指 这时候mPointerIdBits 还是1100000
// 所以要用新的变量记录最新的手指按下情况
newPointerIdBits.markBit(id);
}
}
outCount += 1;
}
// 记录手指数量
outState->rawPointerData.pointerCount = outCount;
// 赋值给 newPointerIdBits 这样抬起的位数就变为0
mPointerIdBits = 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位数表示为 10000000000000000000000000000000
static 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.
// 对该位赋值为1
inline 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 输出28
inline 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
// 返回1
inline 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 scroll
next.rawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
next.rawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
mCursorScrollAccumulator.finishSync();
// Sync touch
// 调用多指 MultiTouchInputMapper的syncTouch
syncTouch(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_FUSION
ALOGD("Timeout expired, synthesizing event with new stylus data");
#endif
const nsecs_t readTime = when; // consider this synthetic event to be zero latency
cookAndDispatch(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 加工为 PointerCoords
cookPointerData();
// 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];
...
// Distance
float 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 right
switch (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.
// 将值写进 PointerCoords
PointerCoords& 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和id
mCurrentCookedState.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);
}
}
}
dispatchMotion 将传入的参数进行判断,最终整合为 NotifyMotionArgs 参数 通过 getListener()->notifyMotion 方法放进去堆栈。
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) {
...
// 变成 NotifyMotionArgs
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));
// 丢到数组里面的 通过flush刷新数据
getListener()->notifyMotion(&args);
}
最终在 loopOnce 执行循环后 执行 flush 将堆栈里面的内容遍历 拿出来进行通知。
void InputReader::loopOnce() {
...
// 读取完从队列调用通知
mQueuedListener->flush();
}
总结 将分析对应的事件是down还是 move事件 最终 PointerCoords 转化为 NotifyMotionArgs 再放进数组 然后在通过 flush 进行刷新。