对input系统在framework层的分析从一次触摸屏丢失上报事件开始:由于设备节点/dev/input/input0存在,而且getevent能响应点触摸屏的动作,所以把问题定位到了EventHub和InputManager这一层。
InputManager的结构很简单,对外开放
- virtual status_t start();
- virtual status_t stop();
- virtual sp<InputReaderInterface> getReader();
- virtual sp<InputDispatcherInterface> getDispatcher();
四个成员函数,内部带有私有成员
- sp<InputReaderInterface> mReader;
- sp<InputReaderThread> mReaderThread;
- sp<InputDispatcherInterface> mDispatcher;
- sp<InputDispatcherThread> mDispatcherThread;
- mDispatcher = new InputDispatcher(dispatcherPolicy); -- 根据输入的参数构造一个dispatcher
- mReader = new InputReader(eventHub, readerPolicy, mDispatcher); -- 根据参数构造一个inputreader
- initialize();
- void InputManager::initialize() {
- mReaderThread = new InputReaderThread(mReader); -- 产生reader线程用于从设备节点读取input event
- mDispatcherThread = new InputDispatcherThread(mDispatcher); -- 产生dispachter线程分发event
- }
- status_t InputManager::start() {
- status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
- ...
- result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
- ...
- return OK;
- }
====================================================================================================================
接着先来分析InputReader:
InputReaderThread run之后会重复的调用
- bool InputReaderThread::threadLoop() {
- mReader->loopOnce();
- return true;
- }
亦即mReader->loopOnce();
- void InputReader::loopOnce() {
- RawEvent rawEvent;
- mEventHub->getEvent(& rawEvent);
- process(& rawEvent);
- }
InputReader上来就找EventHub要数据(getEvent()),所以我们要先看看EventHub的getEvent都做了些什么工作:
- bool EventHub::getEvent(RawEvent* outEvent)
- {
- outEvent->deviceId = 0;
- ...
- // 第一次调用getEvent的时候,需要调用openPlatformInput来搜索输入系统来查找可用的设备
- if (!mOpened) {
- mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
- mOpened = true;
- mNeedToSendFinishedDeviceScan = true;
- }
- }
- bool EventHub::openPlatformInput(void)
- {
- // 为poll()调用作准备
- mFDCount = 1;
- mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
- mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
- mFDs[0].events = POLLIN;
- mFDs[0].revents = 0;
- mDevices[0] = NULL;
- ...
- // 上面有赋值device_path = "/dev/input"
- res = scanDir(device_path);
- ...
- return true;
- }
- int EventHub::openDevice(const char *deviceName) {
- int version;
- int fd;
- struct pollfd *new_mFDs;
- device_t **new_devices;
- char **new_device_names;
- char name[80];
- char location[80];
- char idstr[80];
- struct input_id id;
- LOGV("Opening device: %s", deviceName);
- AutoMutex _l(mLock);
- // 根据路径打开文件获取version, id, name等信息
- fd = open(deviceName, O_RDWR);
- if(fd < 0) ...
- if(ioctl(fd, EVIOCGVERSION, &version))
- ...
- if(ioctl(fd, EVIOCGID, &id))
- ...
- if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1)
- ...
- // check to see if the device is on our excluded list - 如果此设备在排除名单内,忽略它
- List<String8>::iterator iter = mExcludedDevices.begin();
- List<String8>::iterator end = mExcludedDevices.end();
- for ( ; iter != end; iter++) {
- ...
- }
- // 读取location, idstr等信息
- if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1)
- ...
- if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1)
- ...
- // 将设备文件设置为非阻塞
- if (fcntl(fd, F_SETFL, O_NONBLOCK))
- ...
- // 在mDeviceById数组中寻找“空位”,扩充mDeviceById的空间并把新device加到尾部
- int devid = 0;
- while (devid < mNumDevicesById) {
- if (mDevicesById[devid].device == NULL) {
- break;
- }
- devid++;
- }
- if (devid >= mNumDevicesById) {
- device_ent* new_devids = (device_ent*)realloc(mDevicesById,
- sizeof(mDevicesById[0]) * (devid + 1));
- if (new_devids == NULL) {
- LOGE("out of memory");
- return -1;
- }
- mDevicesById = new_devids;
- mNumDevicesById = devid+1;
- mDevicesById[devid].device = NULL;
- mDevicesById[devid].seq = 0;
- }
- mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK;
- if (mDevicesById[devid].seq == 0) {
- mDevicesById[devid].seq = 1<<SEQ_SHIFT;
- }
- // 为后面用poll()来获取kernel层上报的input event作准备
- new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1));
- new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1));
- if (new_mFDs == NULL || new_devices == NULL) {
- LOGE("out of memory");
- return -1;
- }
- mFDs = new_mFDs;
- mDevices = new_devices;
- device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name);
- if (device == NULL) {
- LOGE("out of memory");
- return -1;
- }
- device->fd = fd;
- mFDs[mFDCount].fd = fd;
- mFDs[mFDCount].events = POLLIN;
- mFDs[mFDCount].revents = 0;
- // Figure out the kinds of events the device reports.
- // 分辨本device的输入类型: keypad? touchscreen? gamepad?
- uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
- memset(key_bitmask, 0, sizeof(key_bitmask));
- // 测试本device是否为键盘,是的话把key_bitmask保存下来
- LOGV("Getting keys...");
- if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
- ...
- }
- // 是否为轨迹球或鼠标
- // See if this is a trackball (or mouse).
- if (test_bit(BTN_MOUSE, key_bitmask)) {
- ...
- }
- // 是否为touchscreen,是否支持多点触摸
- // See if this is a touch pad.
- uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)];
- memset(abs_bitmask, 0, sizeof(abs_bitmask));
- LOGV("Getting absolute controllers...");
- if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) {
- ...
- }
- #ifdef EV_SW
- // 是否为switch设备,这个宏没有打开
- #endif
- // 如果是键盘的话,加载keypad-layout,即/usr/keylayout/中的xxx.kl文件
- if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
- ...
- status_t status = device->layoutMap->load(keylayoutFilename);
- if (status) {
- LOGE("Error %d loading key layout.", status);
- }
- ...
- // tell the world about the devname (the descriptive name) - 找一个首选keyboard出来
- if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) {
- // the built-in keyboard has a well-known device ID of 0,
- // this device better not go away.
- mHaveFirstKeyboard = true;
- mFirstKeyboardId = device->id;
- property_set("hw.keyboards.0.devname", name);
- } else {
- // ensure mFirstKeyboardId is set to -something-.
- if (mFirstKeyboardId == 0) {
- mFirstKeyboardId = device->id;
- }
- }
- // 如果键盘有数字键,方向键,游戏控制键等特殊按钮,都一一标记到classes中
- if (hasKeycodeLocked(device, AKEYCODE_Q))
- ...
- if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
- hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
- hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&
- hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&
- hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {
- device->classes |= INPUT_DEVICE_CLASS_DPAD;
- }
- // See if this device has a gamepad.
- for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {
- if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
- device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
- break;
- }
- }
- LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
- device->id, name, propName, keylayoutFilename);
- }
- // 如果不知道这个device是啥类型,忽略之
- if (device->classes == 0) {
- ...
- }
- // 加到mDevicesById和mOpeningDevices中,回头getEvent()会处理mOpenningDevices链表中的新增device
- mDevicesById[devid].device = device;
- device->next = mOpeningDevices;
- mOpeningDevices = device;
- mDevices[mFDCount] = device;
- mFDCount++;
- return 0;
- }
初始化折腾一番后,又回到了getEvent中来,getEvent除了在第一此进入需要加设备外,其主体就是一个大循环:
- bool EventHub::getEvent(RawEvent* outEvent)
- {
- ....
- // main loop here - 主循环体
- for (;;) {
- // Report any devices that had last been removed. - 当有设备从系统中移除时
- if (mClosingDevices != NULL) {
- ...
- }
- // Report any devices that had last been added - 当有设备加入到系统中时
- if (mOpeningDevices != NULL) {
- device_t* device = mOpeningDevices;
- LOGV("Reporting device opened: id=0x%x, name=%s\n",
- device->id, device->path.string());
- mOpeningDevices = device->next;
- if (device->id == mFirstKeyboardId) {
- outEvent->deviceId = 0;
- } else {
- outEvent->deviceId = device->id;
- }
- outEvent->type = DEVICE_ADDED;
- outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
- mNeedToSendFinishedDeviceScan = true;
- return true; // 一个设备上报一个DEVICE_ADDED事件
- }
- // After finish scanning all input devices in system, send finished siganal at boot time
- if (mNeedToSendFinishedDeviceScan) {
- mNeedToSendFinishedDeviceScan = false;
- outEvent->type = FINISHED_DEVICE_SCAN;
- outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
- return true;
- }
- // 下面为普通event获取和上报过程
- ... ...
- }
- }
从上面的代码段可知,对于mOpeningDevices中的device,getEvent()调用都是每读取一个马上上报DEVICE_ADDED事件并返回。所以如果我们的系统中有一个keypad和一个touchscreen,则在扫描阶段就会有3次getEvent()返回:键盘的DEVICE_ADDED,触摸屏的DEVICE_ADDED和表示扫描完成的FINISHED_DEVICE_SCAN。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
接上文对EventHub getEvent()的分析,InputReader::loopOnce()在getEvent()成功返回直接,就调用process(& rawEvent);开始分析报上来的rawEvent:
- void InputReader::process(const RawEvent* rawEvent) {
- switch (rawEvent->type) {
- case EventHubInterface::DEVICE_ADDED: // 加入新设备
- addDevice(rawEvent->deviceId);
- break;
- case EventHubInterface::DEVICE_REMOVED: // 移除完成
- removeDevice(rawEvent->deviceId);
- break;
- case EventHubInterface::FINISHED_DEVICE_SCAN: // 扫描完成,每次增加或移除设备后都会引发此事件
- handleConfigurationChanged(rawEvent->when);
- break;
- default:
- consumeEvent(rawEvent); // 普通event,按键触摸屏事件就在这个分支上处理
- break;
- }
- }
rawEvent的type对应着getEvent里面上报的几种类型,下面根据不同的分支看看inputReader如何处理这样事件。先看看一些关键数据结构:
- struct RawEvent {
- nsecs_t when; // when this happened
- int32_t deviceId; // from which device
- int32_t type; // DEVICE_REMOVED, DEVICE_ADDED, FINISHED_DEVICE_SCAN or others
- int32_t scanCode; // original event code from kernel driver
- int32_t keyCode; // code after keycode-mapping while this is a EV_KEY event
- int32_t value; // event value
- uint32_t flags; // additional info
- };
DEVICE_ADD事件的处理:
- void InputReader::addDevice(int32_t deviceId) {
- String8 name = mEventHub->getDeviceName(deviceId); // eventHub根据自己的mDevicesById返回device的name和classes
- uint32_t classes = mEventHub->getDeviceClasses(deviceId);
- // 调用createDevice建立一个与底层input device一一对应的device
- InputDevice* device = createDevice(deviceId, name, classes);
- device->configure();
- ...
- bool added = false; // 如果此device之前不存在,则加到名为mDevices的KeyedVector中
- { // acquire device registry writer lock
- RWLock::AutoWLock _wl(mDeviceRegistryLock);
- ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
- if (deviceIndex < 0) {
- mDevices.add(deviceId, device);
- added = true;
- }
- } // release device registry writer lock
- ....
- }
- void InputDevice::configure() {
- if (! isIgnored()) {
- mContext->getPolicy()->getInputDeviceCalibration(mName, mCalibration);
- }
- mSources = 0;
- // 调用mapper的configure和getSources来设置device的mSource来标示种类,但是mapper本身又是根据devices的classes来选的,很绕……
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
- mapper->configure();
- mSources |= mapper->getSources();
- }
- }
DEVICE_REMOVED事件的处理:
- void InputReader::removeDevice(int32_t deviceId) {
- bool removed = false;
- InputDevice* device = NULL;
- { // acquire device registry writer lock
- RWLock::AutoWLock _wl(mDeviceRegistryLock);
- // 最主要的是从mDevices中将其移除
- ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
- if (deviceIndex >= 0) {
- device = mDevices.valueAt(deviceIndex);
- mDevices.removeItemsAt(deviceIndex, 1);
- removed = true;
- }
- } // release device registry writer lock
- ...
- device->reset(); // reset会引发devices的mapper的reset()
- delete device;
- }
FINISHED_DEVICE_SCAN事件的处理:
- void InputReader::handleConfigurationChanged(nsecs_t when) {
- // Reset global meta state because it depends on the list of all configured devices.
- updateGlobalMetaState();
- // Update input configuration.更新inputReader当前的设置
- updateInputConfiguration();
- // Enqueue configuration changed.通知dispatcher了
- mDispatcher->notifyConfigurationChanged(when);
- }
普通输入事件的处理:
在函数consumeEvent中会根据rawEvent的deviceId从mDevices中选择上报事件的device然后调用device->process(rawEvent)来处理,device再调用自己mapper的process来处理,因此对于不同的mapper就有了不同的process具体实现。下面选择MultiTouchInputMapper的process函数分析:
- void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
- switch (rawEvent->type) {
- case EV_ABS: {
- uint32_t pointerIndex = mAccumulator.pointerCount;
- Accumulator::Pointer* pointer = & mAccumulator.pointers[pointerIndex];
- switch (rawEvent->scanCode) {
- case ABS_MT_POSITION_X:
- LOGE("-MT X-");
- pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_X;
- pointer->absMTPositionX = rawEvent->value;
- break;
- case ABS_MT_POSITION_Y:
- LOGE("-MT Y-");
- pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_Y;
- pointer->absMTPositionY = rawEvent->value;
- break;
- case ABS_MT_TOUCH_MAJOR:
- pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MAJOR;
- pointer->absMTTouchMajor = rawEvent->value;
- break;
- case ABS_MT_TOUCH_MINOR:
- pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MINOR;
- pointer->absMTTouchMinor = rawEvent->value;
- break;
- case ABS_MT_WIDTH_MAJOR:
- pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
- pointer->absMTWidthMajor = rawEvent->value;
- break;
- case ABS_MT_WIDTH_MINOR:
- pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MINOR;
- pointer->absMTWidthMinor = rawEvent->value;
- break;
- case ABS_MT_ORIENTATION:
- pointer->fields |= Accumulator::FIELD_ABS_MT_ORIENTATION;
- pointer->absMTOrientation = rawEvent->value;
- break;
- case ABS_MT_TRACKING_ID:
- pointer->fields |= Accumulator::FIELD_ABS_MT_TRACKING_ID;
- pointer->absMTTrackingId = rawEvent->value;
- break;
- case ABS_MT_PRESSURE:
- pointer->fields |= Accumulator::FIELD_ABS_MT_PRESSURE;
- pointer->absMTPressure = rawEvent->value;
- break;
- }
- break;
- }
- case EV_SYN:
- switch (rawEvent->scanCode) { // 对于多点触摸来说,一次可以向dispatcher报1~10个pointer的数据(10点是android2.3的上限)
- case SYN_MT_REPORT: { // 一次SYN_MT_REPORT表示一个手指的触摸数据已经接收完毕,包括X,Y,PRESSURE等
- // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
- uint32_t pointerIndex = mAccumulator.pointerCount;
- LOGE("-ONE-");
- if (mAccumulator.pointers[pointerIndex].fields) {
- if (pointerIndex == MAX_POINTERS) {
- LOGW("MultiTouch device driver returned more than maximum of %d pointers.",
- MAX_POINTERS);
- } else {
- pointerIndex += 1;
- mAccumulator.pointerCount = pointerIndex;
- }
- }
- mAccumulator.pointers[pointerIndex].clear();
- break;
- }
- // 当多点的数据都齐全之后会收到SYN_REPORT事件,这时可以向dispatcher发送了
- case SYN_REPORT:
- LOGE("-SYN MT-");
- sync(rawEvent->when);
- break;
- }
- break;
- }
- }
- void MultiTouchInputMapper::sync(nsecs_t when) {
- static const uint32_t REQUIRED_FIELDS =
- Accumulator::FIELD_ABS_MT_POSITION_X | Accumulator::FIELD_ABS_MT_POSITION_Y;
- uint32_t inCount = mAccumulator.pointerCount;
- uint32_t outCount = 0;
- bool havePointerIds = true;
- mCurrentTouch.clear();
- for (uint32_t inIndex = 0; inIndex < inCount; inIndex++) {
- const Accumulator::Pointer& inPointer = mAccumulator.pointers[inIndex];
- uint32_t fields = inPointer.fields;
- if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) {
- // Some drivers send empty MT sync packets without X / Y to indicate a pointer up.
- // Drop this finger.
- continue;
- }
- PointerData& outPointer = mCurrentTouch.pointers[outCount];
- outPointer.x = inPointer.absMTPositionX;
- outPointer.y = inPointer.absMTPositionY;
- if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) {
- if (inPointer.absMTPressure <= 0) {
- // Some devices send sync packets with X / Y but with a 0 pressure to indicate
- // a pointer going up. Drop this finger.
- continue;
- }
- outPointer.pressure = inPointer.absMTPressure;
- } else {
- // Default pressure to 0 if absent.
- outPointer.pressure = 0;
- }
- .... // 设置FIELD_ABS_MT_WIDTH_MAJOR等等field
- // Assign pointer id using tracking id if available.
- if (havePointerIds) {
- if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) {
- uint32_t id = uint32_t(inPointer.absMTTrackingId);
- if (id > MAX_POINTER_ID) {
- // 利用id来跟踪多个手指的触摸事件
- havePointerIds = false;
- }
- else {
- outPointer.id = id;
- mCurrentTouch.idToIndex[id] = outCount;
- mCurrentTouch.idBits.markBit(id);
- }
- } else {
- havePointerIds = false;
- }
- }
- outCount += 1;
- }
- mCurrentTouch.pointerCount = outCount;
- syncTouch(when, havePointerIds);
- mAccumulator.clear();
- }
- for (i = 0; i < 10; i++){
- if (stored_size[i]){
- active_touches++;
- input_report_abs(mxt->input,
- ABS_MT_TRACKING_ID,
- i);
- input_report_abs(mxt->input,
- ABS_MT_TOUCH_MAJOR,
- stored_size[i]);
- input_report_abs(mxt->input,
- ABS_MT_POSITION_X,
- stored_x[i]);
- input_report_abs(mxt->input,
- ABS_MT_POSITION_Y,
- stored_y[i]);
- input_mt_sync(mxt->input);
- }
- }
- if (active_touches == 0)
- input_mt_sync(mxt->input);
- input_sync(mxt->input);
- void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
- uint32_t policyFlags = 0;
- // Preprocess pointer data.
- if (mParameters.useBadTouchFilter) {
- if (applyBadTouchFilter()) {
- havePointerIds = false;
- }
- }
- if (mParameters.useJumpyTouchFilter) {
- if (applyJumpyTouchFilter()) {
- havePointerIds = false;
- }
- }
- if (! havePointerIds) {
- calculatePointerIds();
- }
- TouchData temp;
- TouchData* savedTouch;
- if (mParameters.useAveragingTouchFilter) {
- temp.copyFrom(mCurrentTouch);
- savedTouch = & temp;
- applyAveragingTouchFilter();
- } else {
- savedTouch = & mCurrentTouch;
- }
- // Process touches and virtual keys.
- TouchResult touchResult = consumeOffScreenTouches(when, policyFlags);
- if (touchResult == DISPATCH_TOUCH) {
- detectGestures(when);
- dispatchTouches(when, policyFlags);
- }
- // Copy current touch to last touch in preparation for the next cycle.
- if (touchResult == DROP_STROKE) {
- mLastTouch.clear();
- } else {
- mLastTouch.copyFrom(*savedTouch);
- }
- }
getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
通知dispatcher有事件来了,dispatcher的分析在下篇开始。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++