http://www.kaixinwenda.com/article-jiangshitian-12508223.html
对input系统在framework层的分析从一次触摸屏丢失上报事件开始:由于设备节点/dev/input/input0存在,而且getevent能响应点触摸屏的动作,所以把问题定位到了EventHub和InputManager这一层。
InputManager的结构很简单,对外开放
[plain] view plaincopy
- virtual status_t start();
- virtual status_t stop();
- virtual sp<InputReaderInterface> getReader();
- virtual sp<InputDispatcherInterface> getDispatcher();
四个成员函数,内部带有私有成员
[plain] view plaincopy
- sp<InputReaderInterface> mReader;
- sp<InputReaderThread> mReaderThread;
- sp<InputDispatcherInterface> mDispatcher;
- sp<InputDispatcherThread> mDispatcherThread;
其构造过程也很简单:
[plain] view plaincopy
- mDispatcher = new InputDispatcher(dispatcherPolicy); -- 根据输入的参数构造一个dispatcher
- mReader = new InputReader(eventHub, readerPolicy, mDispatcher); -- 根据参数构造一个inputreader
- initialize();
[plain] view plaincopy
- void InputManager::initialize() {
- mReaderThread = new InputReaderThread(mReader); -- 产生reader线程用于从设备节点读取input event
- mDispatcherThread = new InputDispatcherThread(mDispatcher); -- 产生dispachter线程分发event
- }
InputManager的start主要就是让这两个线程跑起来:
[plain] view plaincopy
- 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之后会重复的调用
[plain] view plaincopy
- bool InputReaderThread::threadLoop() {
- mReader->loopOnce();
- return true;
- }
亦即mReader->loopOnce();
[plain] view plaincopy
- void InputReader::loopOnce() {
- RawEvent rawEvent;
- mEventHub->getEvent(& rawEvent);
- process(& rawEvent);
- }
InputReader上来就找EventHub要数据(getEvent()),所以我们要先看看EventHub的getEvent都做了些什么工作:
[cpp] view plaincopy
- bool EventHub::getEvent(RawEvent* outEvent)
- {
- outEvent->deviceId = 0;
- ...
-
-
- if (!mOpened) {
- mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
- mOpened = true;
- mNeedToSendFinishedDeviceScan = true;
- }
- }
[cpp] view plaincopy
- bool EventHub::openPlatformInput(void)
- {
-
- 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;
- ...
-
- res = scanDir(device_path);
- ...
- return true;
- }
接着又绕到scanDir()里面,这个函数无非就是对/dev/input这个目录的每个文件执行openDevice(),后者才是真正干活的:
[cpp] view plaincopy
- 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);
-
- 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)
- ...
-
- List<String8>::iterator iter = mExcludedDevices.begin();
- List<String8>::iterator end = mExcludedDevices.end();
- for ( ; iter != end; iter++) {
- ...
- }
-
- 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))
- ...
-
- 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;
- }
-
- 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;
-
-
-
- uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
- memset(key_bitmask, 0, sizeof(key_bitmask));
-
- LOGV("Getting keys...");
- if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
- ...
- }
-
-
- if (test_bit(BTN_MOUSE, key_bitmask)) {
- ...
- }
-
-
- 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
-
- #endif
-
- if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
- ...
- status_t status = device->layoutMap->load(keylayoutFilename);
- if (status) {
- LOGE("Error %d loading key layout.", status);
- }
- ...
-
- if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) {
-
-
- mHaveFirstKeyboard = true;
- mFirstKeyboardId = device->id;
- property_set("hw.keyboards.0.devname", name);
- } else {
-
- if (mFirstKeyboardId == 0) {
- mFirstKeyboardId = device->id;
- }
- }
-
- 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;
- }
-
-
- 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);
- }
-
-
- if (device->classes == 0) {
- ...
- }
-
-
-
- mDevicesById[devid].device = device;
- device->next = mOpeningDevices;
- mOpeningDevices = device;
- mDevices[mFDCount] = device;
-
- mFDCount++;
- return 0;
- }
初始化折腾一番后,又回到了getEvent中来,getEvent除了在第一此进入需要加设备外,其主体就是一个大循环:
[cpp] view plaincopy
- bool EventHub::getEvent(RawEvent* outEvent)
- {
- ....
-
-
- for (;;) {
-
- if (mClosingDevices != NULL) {
- ...
- }
-
-
- 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;
- }
-
-
- if (mNeedToSendFinishedDeviceScan) {
- mNeedToSendFinishedDeviceScan = false;
- outEvent->type = FINISHED_DEVICE_SCAN;
- outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
- return true;
- }
-
-
- ... ...
- }
- }
从上面的代码段可知,对于mOpeningDevices中的device,getEvent()调用都是每读取一个马上上报DEVICE_ADDED事件并返回。所以如果我们的系统中有一个keypad和一个touchscreen,则在扫描阶段就会有3次getEvent()返回:键盘的DEVICE_ADDED,触摸屏的DEVICE_ADDED和表示扫描完成的FINISHED_DEVICE_SCAN。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
接上文对EventHub getEvent()的分析,InputReader::loopOnce()在getEvent()成功返回直接,就调用process(& rawEvent);开始分析报上来的rawEvent:
[cpp] view plaincopy
- 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);
- break;
- }
- }
rawEvent的type对应着getEvent里面上报的几种类型,下面根据不同的分支看看inputReader如何处理这样事件。先看看一些关键数据结构:
[cpp] view plaincopy
- struct RawEvent {
- nsecs_t when;
- int32_t deviceId;
- int32_t type;
- int32_t scanCode;
- int32_t keyCode;
- int32_t value;
- uint32_t flags;
- };
DEVICE_ADD事件的处理:
[cpp] view plaincopy
- void InputReader::addDevice(int32_t deviceId) {
- String8 name = mEventHub->getDeviceName(deviceId);
- uint32_t classes = mEventHub->getDeviceClasses(deviceId);
-
- InputDevice* device = createDevice(deviceId, name, classes);
- device->configure();
- ...
- bool added = false;
- {
- RWLock::AutoWLock _wl(mDeviceRegistryLock);
-
- ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
- if (deviceIndex < 0) {
- mDevices.add(deviceId, device);
- added = true;
- }
- }
- ....
- }
createDevice()函数中先new InputDevice创建对象,然后根据device的classes调用device->addMapper加入mapper,这些mapper对后面分析的普通event的处理有重要的作用。device->configure()函数做一些配置工作,如果device有校准数据的话会调用getInputDeviceCalibration进行校准,还会调用上述mapper的configure函数配置mapper,不过mapper的这个函数一般直接置空,只有TouchInputMapper::configure()会针对触摸屏校准做些工作:
[cpp] view plaincopy
- void InputDevice::configure() {
- if (! isIgnored()) {
- mContext->getPolicy()->getInputDeviceCalibration(mName, mCalibration);
- }
-
- mSources = 0;
-
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
- mapper->configure();
- mSources |= mapper->getSources();
- }
- }
DEVICE_REMOVED事件的处理:
[cpp] view plaincopy
- void InputReader::removeDevice(int32_t deviceId) {
- bool removed = false;
- InputDevice* device = NULL;
- {
- RWLock::AutoWLock _wl(mDeviceRegistryLock);
-
- ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
- if (deviceIndex >= 0) {
- device = mDevices.valueAt(deviceIndex);
- mDevices.removeItemsAt(deviceIndex, 1);
- removed = true;
- }
- }
- ...
- device->reset();
-
- delete device;
- }
FINISHED_DEVICE_SCAN事件的处理:
[cpp] view plaincopy
- void InputReader::handleConfigurationChanged(nsecs_t when) {
-
- updateGlobalMetaState();
-
-
- updateInputConfiguration();
-
-
- mDispatcher->notifyConfigurationChanged(when);
- }
普通输入事件的处理:
在函数consumeEvent中会根据rawEvent的deviceId从mDevices中选择上报事件的device然后调用device->process(rawEvent)来处理,device再调用自己mapper的process来处理,因此对于不同的mapper就有了不同的process具体实现。下面选择MultiTouchInputMapper的process函数分析:
[cpp] view plaincopy
- 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) {
- case SYN_MT_REPORT: {
-
- 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;
- }
-
- case SYN_REPORT:
- LOGE("-SYN MT-");
- sync(rawEvent->when);
- break;
- }
- break;
- }
- }
MultiTouchInputMapper::sync的主要作用是,把process中接收到的多个pointer数据做审核,例如屏蔽掉不合要求的点,对缺失的参数设置成默认等。
[cpp] view plaincopy
- 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) {
-
-
- 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) {
-
-
- continue;
- }
- outPointer.pressure = inPointer.absMTPressure;
- } else {
-
- outPointer.pressure = 0;
- }
- ....
-
-
- if (havePointerIds) {
- if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) {
- uint32_t id = uint32_t(inPointer.absMTTrackingId);
-
- if (id > MAX_POINTER_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();
- }
贴一段kernel的触摸屏driver上报事件的代码:
[cpp] view plaincopy
- 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);
可以看到,这个触摸屏也是最多支持10点触摸的,其中的ABS_MT_TRACKING_ID就是追踪每个手指的移动轨迹标示,具体哪个点属于哪个手指的轨迹则是由电容屏的IC确定的,怪不得电容屏成本比较高。经过sync函数的处理后,mCurrentTouch里面就带有整个多点触摸事件的所有数据,可以调用基类TouchInputMapper的syncTouch了:
[cpp] view plaincopy
- void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
- uint32_t policyFlags = 0;
-
-
-
- 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;
- }
-
-
-
- TouchResult touchResult = consumeOffScreenTouches(when, policyFlags);
- if (touchResult == DISPATCH_TOUCH) {
- detectGestures(when);
- dispatchTouches(when, policyFlags);
- }
-
-
-
- if (touchResult == DROP_STROKE) {
- mLastTouch.clear();
- } else {
- mLastTouch.copyFrom(*savedTouch);
- }
- }
在syncTouch里,多点触摸的数据(单点触摸事件也会经过这里)还得通过applyBadTouchFilter,applyJumpyTouchFilter,applyAveragingTouchFilter(视情况)的处理才能到consumeOffScreenTouches这步,这个函数中在处理完一些policy的东西之后就会调
getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
通知dispatcher有事件来了,dispatcher的分析在下篇开始。