Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3056168
  • 博文数量: 396
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4209
  • 用 户 组: 普通用户
  • 注册时间: 2016-07-04 13:04
文章分类

全部博文(396)

文章存档

2022年(1)

2021年(2)

2020年(8)

2019年(24)

2018年(135)

2017年(158)

2016年(68)

我的朋友

分类: Android平台

2020-07-01 15:05:49

一. InputReader起点

上一篇文章,介绍IMS服务的启动过程会创建两个native线程,分别是InputReader,InputDispatcher. 接下来从InputReader线程的执行过程从threadLoop为起点开始分析。

1.1 threadLoop

[-> InputReader.cpp]

bool InputReaderThread::threadLoop() {
    mReader->loopOnce(); //【见小节1.2】 return true;
} 

threadLoop返回值true代表的是会不断地循环调用loopOnce()。另外,如果当返回值为false则会 退出循环。整个过程是不断循环的地调用InputReader的loopOnce()方法,先来回顾一下InputReader对象构造方法。

1.2 loopOnce

[-> InputReader.cpp]

void InputReader::loopOnce() {
    ...
    {
        AutoMutex _l(mLock); uint32_t changes = mConfigurationChangesToRefresh; if (changes) {
            timeoutMillis = 0;
            ...
        } else if (mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
        }
    } //从EventHub读取事件,其中EVENT_BUFFER_SIZE = 256【见小节2.1】 size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { // acquire lock AutoMutex _l(mLock);
         mReaderIsAliveCondition.broadcast(); if (count) { //处理事件【见小节3.1】 processEventsLocked(mEventBuffer, count);
        } if (oldGeneration != mGeneration) {
            inputDevicesChanged = true;
            getInputDevicesLocked(inputDevices);
        }
        ...
    } // release lock if (inputDevicesChanged) { //输入设备发生改变 mPolicy->notifyInputDevicesChanged(inputDevices);
    } //发送事件到nputDispatcher【见小节4.1】 mQueuedListener->flush();
} 

二. EventHub

2.1 getEvents

[-> EventHub.cpp]

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    AutoMutex _l(mLock); //加锁 struct input_event readBuffer[bufferSize];
    RawEvent* event = buffer; //原始事件 size_t capacity = bufferSize; //容量大小为256 bool awoken = false; for (;;) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        ... if (mNeedToScanDevices) {
            mNeedToScanDevices = false;
            scanDevicesLocked(); //扫描设备【见小节2.2】 mNeedToSendFinishedDeviceScan = true;
        } while (mOpeningDevices != NULL) {
            Device* device = mOpeningDevices;
            mOpeningDevices = device->next;
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            event->type = DEVICE_ADDED; //添加设备的事件 event += 1;
            mNeedToSendFinishedDeviceScan = true; if (--capacity == 0) { break;
            }
        }
        ... bool deviceChanged = false; while (mPendingEventIndex < mPendingEventCount) { //从mPendingEventItems读取事件项 const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            ... //获取设备ID所对应的device ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
            Device* device = mDevices.valueAt(deviceIndex); if (eventItem.events & EPOLLIN) { //从设备不断读取事件,放入到readBuffer int32_t readSize = read(device->fd, readBuffer,
                        sizeof(struct input_event) * capacity); if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
                    deviceChanged = true;
                    closeDeviceLocked(device);//设备已被移除则执行关闭操作 } else if (readSize < 0) {
                    ...
                } else if ((readSize % sizeof(struct input_event)) != 0) {
                    ...
                } else { int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; size_t count = size_t(readSize) / sizeof(struct input_event); for (size_t i = 0; i < count; i++) { //获取readBuffer的数据 struct input_event& iev = readBuffer[i]; //将input_event信息, 封装成RawEvent event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
                                + nsecs_t(iev.time.tv_usec) * 1000LL;
                        event->deviceId = deviceId;
                        event->type = iev.type;
                        event->code = iev.code;
                        event->value = iev.value;
                        event += 1;
                        capacity -= 1;
                    } if (capacity == 0) {
                        mPendingEventIndex -= 1; break;
                    }
                }
            }
            ...
        }
        ...
        mLock.unlock(); //poll之前先释放锁 //等待input事件的到来 int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
        ...
        mLock.lock(); //poll之后再次请求锁 if (pollResult < 0) { //出现错误 mPendingEventCount = 0; if (errno != EINTR) {
                usleep(100000); //系统发生错误则休眠1s }
        } else {
            mPendingEventCount = size_t(pollResult);
        }
    }

    return event - buffer; //返回所读取的事件个数 } 

EventHub采用INotify + epoll机制实现监听目录/dev/input下的设备节点,经过EventHub将input_event结构体 + deviceId 转换成RawEvent结构体,如下:

2.1.1 RawEvent

[-> InputEventReader.h]

struct input_event { struct timeval time; //事件发生的时间点 __u16 type;
 __u16 code;
 __s32 value;
}; struct RawEvent { nsecs_t when; //事件发生的时间店 int32_t deviceId; //产生事件的设备Id int32_t type; // 事件类型 int32_t code; int32_t value;
}; 

此处事件类型:

  • DEVICE_ADDED(添加)
  • DEVICE_REMOVED(删除)
  • FINISHED_DEVICE_SCAN(扫描完成)
  • type

getEvents()已完成转换事件转换工作, 接下来,顺便看看设备扫描过程.

2.2 设备扫描

2.2.1 scanDevicesLocked

void EventHub::scanDevicesLocked() { //此处DEVICE_PATH="/dev/input"【见小节2.3】 status_t res = scanDirLocked(DEVICE_PATH);
    ...
} 

2.2.2 scanDirLocked

status_t EventHub::scanDirLocked(const char *dirname)
{ char devname[PATH_MAX]; char *filename;
    DIR *dir; struct dirent *de;
    dir = opendir(dirname); strcpy(devname, dirname);
    filename = devname + strlen(devname);
    *filename++ = '/'; //读取/dev/input/目录下所有的设备节点 while((de = readdir(dir))) { if(de->d_name[0] == '.' &&
           (de->d_name[1] == '\0' ||
            (de->d_name[1] == '.' && de->d_name[2] == '\0'))) continue; strcpy(filename, de->d_name); //打开相应的设备节点【2.2.3】 openDeviceLocked(devname);
    }
    closedir(dir);
    return 0;
} 

2.2.3 openDeviceLocked

status_t EventHub::openDeviceLocked(const char *devicePath) { char buffer[80]; //打开设备文件 int fd = open(devicePath, O_RDWR | O_CLOEXEC);
    InputDeviceIdentifier identifier; //获取设备名 if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1){
    } else {
        buffer[sizeof(buffer) - 1] = '\0';
        identifier.name.setTo(buffer);
    }

    identifier.bus = inputId.bustype;
    identifier.product = inputId.product;
    identifier.vendor = inputId.vendor;
    identifier.version = inputId.version; //获取设备物理地址 if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
    } else {
        buffer[sizeof(buffer) - 1] = '\0';
        identifier.location.setTo(buffer);
    } //获取设备唯一ID if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
    } else {
        buffer[sizeof(buffer) - 1] = '\0';
        identifier.uniqueId.setTo(buffer);
    } //将identifier信息填充到fd assignDescriptorLocked(identifier); //设置fd为非阻塞方式 fcntl(fd, F_SETFL, O_NONBLOCK); //获取设备ID,分配设备对象内存 int32_t deviceId = mNextDeviceId++;
    Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
    ... //注册epoll struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN; if (mUsingEpollWakeup) {
        eventItem.events |= EPOLLWAKEUP;
    }
    eventItem.data.u32 = deviceId; if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
        delete device; //添加失败则删除该设备 return -1;
    }
    ... //【见小节2.2.4】 addDeviceLocked(device);
} 

2.2.4 addDeviceLocked

void EventHub::addDeviceLocked(Device* device) {
    mDevices.add(device->id, device); //添加到mDevices队列 device->next = mOpeningDevices;
    mOpeningDevices = device;
} 

介绍了EventHub从设备节点获取事件的流程,当收到事件后接下里便开始处理事件。

三. InputReader

3.1 processEventsLocked

[-> 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; 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; //同一设备的事件打包处理 } //数据事件的处理【见小节3.3】 processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else { switch (rawEvent->type) { case EventHubInterface::DEVICE_ADDED: //设备添加【见小节3.2】 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);//不会发生 break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
} 

事件处理总共有下几类类型:

  • DEVICE_ADDED(设备增加), [见小节3.2]
  • DEVICE_REMOVED(设备移除)
  • FINISHED_DEVICE_SCAN(设备扫描完成)
  • 数据事件[见小节3.4]

先来说说DEVICE_ADDED设备增加的过程。

3.2 设备增加

3.2.1 addDeviceLocked

void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex >= 0) { return; //已添加的相同设备则不再添加 }

    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
    uint32_t classes = mEventHub->getDeviceClasses(deviceId);
    int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId); //【见小节3.2.2】 InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
    device->configure(when, &mConfig, 0);
    device->reset(when);
    mDevices.add(deviceId, device); //添加设备到mDevices ...
} 

3.2.2 createDeviceLocked

InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) { //创建InputDevice对象 InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
            controllerNumber, identifier, classes);
    ... //获取键盘源类型 uint32_t keyboardSource = 0;
    int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
        keyboardSource |= AINPUT_SOURCE_KEYBOARD;
    } if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
        keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
    } if (classes & INPUT_DEVICE_CLASS_DPAD) {
        keyboardSource |= AINPUT_SOURCE_DPAD;
    } if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
        keyboardSource |= AINPUT_SOURCE_GAMEPAD;
    } //添加键盘类设备InputMapper if (keyboardSource != 0) {
        device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
    } //添加鼠标类设备InputMapper if (classes & INPUT_DEVICE_CLASS_CURSOR) {
        device->addMapper(new CursorInputMapper(device));
    } //添加触摸屏设备InputMapper if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
        device->addMapper(new MultiTouchInputMapper(device));
    } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
        device->addMapper(new SingleTouchInputMapper(device));
    }
    ... return device;
} 

该方法主要功能:

  • 创建InputDevice对象,将InputReader的mContext赋给InputDevice对象所对应的变量
  • 根据设备类型来创建并添加相对应的InputMapper,同时设置mContext.

input设备类型有很多种,以上代码只列举部分常见的设备以及相应的InputMapper:

  • 键盘类设备:KeyboardInputMapper
  • 触摸屏设备:MultiTouchInputMapper或SingleTouchInputMapper
  • 鼠标类设备:CursorInputMapper

介绍完设备增加过程,继续回到[小节3.1]除了设备的增删,更常见事件便是数据事件,那么接下来介绍数据事件的 处理过程。

3.3 事件处理

3.3.1 processEventsForDeviceLocked

void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
    ...

    InputDevice* device = mDevices.valueAt(deviceIndex); if (device->isIgnored()) {
        return; //可忽略则直接返回 } //【见小节3.3.2】 device->process(rawEvents, count);
} 

3.3.2 InputDevice.process

void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    size_t numMappers = mMappers.size(); for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) { if (mDropUntilNextSync) { if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
                mDropUntilNextSync = false;
            }
        } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
            mDropUntilNextSync = true;
            reset(rawEvent->when);
        } else { for (size_t i = 0; i < numMappers; i++) {
                InputMapper* mapper = mMappers[i]; //调用具体mapper来处理【见小节3.4】 mapper->process(rawEvent);
            }
        }
    }
} 

小节[3.2]createDeviceLocked创建设备并添加InputMapper,提到会有多种InputMapper。 这里以KeyboardInputMapper(按键事件)为例来展开说明

3.4 按键事件处理

3.4.1 KeyboardInputMapper.process

[-> InputReader.cpp ::KeyboardInputMapper]

void KeyboardInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_KEY: {
        int32_t scanCode = rawEvent->code;
        int32_t usageCode = mCurrentHidUsage;
        mCurrentHidUsage = 0; if (isKeyboardOrGamepadKey(scanCode)) {
            int32_t keyCode; //获取所对应的KeyCode【见小节3.4.2】 if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) {
                keyCode = AKEYCODE_UNKNOWN;
                flags = 0;
            } //【见小节3.4.4】 processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
        } break;
    } case EV_MSC: ... case EV_SYN: ...
    }
} 

3.4.2 EventHub::mapKey

[-> EventHub.cpp]

status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
    AutoMutex _l(mLock);
    Device* device = getDeviceLocked(deviceId); //获取设备对象 status_t status = NAME_NOT_FOUND; if (device) {
        sp kcm = device->getKeyCharacterMap(); if (kcm != NULL) { //根据scanCode找到keyCode【见小节3.4.3】 if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
                *outFlags = 0;
                status = NO_ERROR;
            }
        }
    }
    ...
    return status;
} 

将事件的扫描码(scanCode)转换成键盘码(Keycode)

3.4.3 KeyCharacterMap::mapKey

[-> KeyCharacterMap.cpp]

status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
    ... if (scanCode) { ssize_t index = mKeysByScanCode.indexOfKey(scanCode); if (index >= 0) { //根据scanCode找到keyCode *outKeyCode = mKeysByScanCode.valueAt(index);
            return OK;
        }
    }
    *outKeyCode = AKEYCODE_UNKNOWN;
    return NAME_NOT_FOUND;
} 

再回到[3.4.1],接下来进入如下过程:

3.4.4 InputMapper.processKey

[-> InputReader.cpp]

void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
        int32_t scanCode, uint32_t policyFlags) { if (down) { if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
            keyCode = rotateKeyCode(keyCode, mOrientation);
        }

        ssize_t keyDownIndex = findKeyDown(scanCode); if (keyDownIndex >= 0) { //mKeyDowns记录着所有按下的键 keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
        } else {
            ...
            mKeyDowns.push(); //压入栈顶 KeyDown& keyDown = mKeyDowns.editTop();
            keyDown.keyCode = keyCode;
            keyDown.scanCode = scanCode;
        }
        mDownTime = when; //记录按下时间点 } else {
        ssize_t keyDownIndex = findKeyDown(scanCode); if (keyDownIndex >= 0) { //键抬起操作,则移除按下事件 keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
            mKeyDowns.removeAt(size_t(keyDownIndex));
        } else { return; //键盘没有按下操作,则直接忽略抬起操作 }
    }
    nsecs_t downTime = mDownTime;
    ... //创建NotifyKeyArgs对象, when记录eventTime, downTime记录按下时间; NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime); //通知key事件【见小节3.4.5】 getListener()->notifyKey(&args);
} 

参数说明:

  • mKeyDowns记录着所有按下的键;
  • mDownTime记录按下时间点;
  • 此处KeyboardInputMapper的mContext指向InputReader,getListener()获取的便是mQueuedListener。 接下来调用该对象的notifyKey.

3.4.5 QueuedInputListener.notifyKey

[-> InputListener.cpp]

void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
    mArgsQueue.push(new NotifyKeyArgs(*args));
} 

mArgsQueue的数据类型为Vector,将该key事件压人该栈顶。 到此,整个事件加工完成, 再然后就是将事件发送给InputDispatcher线程.

接下来,再回调小节[1.2] InputReader的loopOnce过程, 可知当执行完processEventsLocked()过程, 然后便开始执行mQueuedListener->flush()过程, 如下文.

四. QueuedListener

4.1 QueuedInputListener.flush

[-> InputListener.cpp]

void QueuedInputListener::flush() { size_t count = mArgsQueue.size(); for (size_t i = 0; i < count; i++) {
        NotifyArgs* args = mArgsQueue[i]; //【见小节4.2】 args->notify(mInnerListener); delete args;
    }
    mArgsQueue.clear();
} 

遍历整个mArgsQueue数组, 在input架构中NotifyArgs的实现子类主要有以下几类:

  • NotifyConfigurationChangedArgs
  • NotifyKeyArgs
  • NotifyMotionArgs
  • NotifySwitchArgs
  • NotifyDeviceResetArgs

紧接着上述的小节[3.4.5], 可知此处是NotifyKeyArgs对象. 从InputManager对象初始化的过程可知,mInnerListener便是InputDispatcher对象。

4.2 NotifyKeyArgs.notify

[-> InputListener.cpp]

void NotifyKeyArgs::notify(const sp& listener) const {
    listener->notifyKey(this); // this是指NotifyKeyArgs【见小节4.3】 } 

4.3 InputDispatcher.notifyKey

[-> InputDispatcher.cpp]

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { if (!validateKeyEvent(args->action)) { return;
    }
    ...
    int32_t keyCode = args->keyCode; if (keyCode == AKEYCODE_HOME) { if (args->action == AKEY_EVENT_ACTION_DOWN) {
            property_set("sys.domekey.down", "1");
        } else if (args->action == AKEY_EVENT_ACTION_UP) {
            property_set("sys.domekey.down", "0");
        }
    } if (metaState & AMETA_META_ON && args->action == AKEY_EVENT_ACTION_DOWN) {
        ...
    } else if (args->action == AKEY_EVENT_ACTION_UP) {
        ...
    }

    KeyEvent event; //初始化KeyEvent对象 event.initialize(args->deviceId, args->source, args->action,
            flags, keyCode, args->scanCode, metaState, 0,
            args->downTime, args->eventTime); //mPolicy是指NativeInputManager对象。【小节4.3.1】 mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);

    bool needWake;
    {
        mLock.lock(); if (shouldSendKeyToInputFilterLocked(args)) {
            mLock.unlock();
            policyFlags |= POLICY_FLAG_FILTERED; //当inputEventObj不为空, 则事件被filter所拦截【见小节4.3.2】 if (!mPolicy->filterInputEvent(&event, policyFlags)) { return;
            }
            mLock.lock();
        }

        int32_t repeatCount = 0; //创建KeyEntry对象 KeyEntry* newEntry = new KeyEntry(args->eventTime,
                args->deviceId, args->source, policyFlags,
                args->action, flags, keyCode, args->scanCode,
                metaState, repeatCount, args->downTime); //将KeyEntry放入队列【见小节4.3.3】 needWake = enqueueInboundEventLocked(newEntry);
        mLock.unlock();
    } if (needWake) { //唤醒InputDispatcher线程【见小节4.3.5】 mLooper->wake();
    }
} 

该方法的主要功能:

  1. 调用NativeInputManager.interceptKeyBeforeQueueing,加入队列前执行拦截动作,但并不改变流程,调用链:
    • IMS.interceptKeyBeforeQueueing
    • InputMonitor.interceptKeyBeforeQueueing (继承IMS.WindowManagerCallbacks)
    • PhoneWindowManager.interceptKeyBeforeQueueing (继承WindowManagerPolicy)
  2. 当mInputFilterEnabled=true(该值默认为false,可通过setInputFilterEnabled设置),则调用NativeInputManager.filterInputEvent过滤输入事件;
    • 当返回值为false则过滤该事件,不再往下分发;
  3. 生成KeyEvent,并调用enqueueInboundEventLocked,将该事件加入到InputDispatcherd的成员变量mInboundQueue。

4.3.1 interceptKeyBeforeQueueing

void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) {
    ... if ((policyFlags & POLICY_FLAG_TRUSTED)) { nsecs_t when = keyEvent->getEventTime(); //时间 JNIEnv* env = jniEnv();
        jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent); if (keyEventObj) { // 调用Java层的IMS.interceptKeyBeforeQueueing wmActions = env->CallIntMethod(mServiceObj,
                    gServiceClassInfo.interceptKeyBeforeQueueing,
                    keyEventObj, policyFlags);
            ...
        } else {
            ...
        }
        handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
    } else {
        ...
    }
} 

该方法会调用Java层的InputManagerService的interceptKeyBeforeQueueing()方法。

4.3.2 filterInputEvent

bool NativeInputManager::filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
    jobject inputEventObj;

    JNIEnv* env = jniEnv(); switch (inputEvent->getType()) { case AINPUT_EVENT_TYPE_KEY:
        inputEventObj = android_view_KeyEvent_fromNative(env,
                static_cast<const KeyEvent*>(inputEvent)); break; case AINPUT_EVENT_TYPE_MOTION:
        inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
                static_cast<const MotionEvent*>(inputEvent)); break; default: return true; // 走事件正常的分发流程 } if (!inputEventObj) { return true; // 当inputEventObj为空, 则走事件正常的分发流程 } //当inputEventObj不为空,则调用Java层的IMS.filterInputEvent() jboolean pass = env->CallBooleanMethod(mServiceObj, gServiceClassInfo.filterInputEvent,
            inputEventObj, policyFlags); if (checkAndClearExceptionFromCallback(env, "filterInputEvent")) {
        pass = true; //出现Exception,则走事件正常的分发流程 }
    env->DeleteLocalRef(inputEventObj); return pass;
} 

当inputEventObj不为空,则调用Java层的IMS.filterInputEvent(). 经过层层调用后, 最终会再调用InputDispatcher.injectInputEvent(),该基本等效于该方法的后半段:

  • enqueueInboundEventLocked
  • wakeup

4.3.3 enqueueInboundEventLocked

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { bool needWake = mInboundQueue.isEmpty();
    mInboundQueue.enqueueAtTail(entry); //将该事件放入mInboundQueue队列尾部 switch (entry->type) { case EventEntry::TYPE_KEY: {
        KeyEntry* keyEntry = static_cast(entry); if (isAppSwitchKeyEventLocked(keyEntry)) { if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
                mAppSwitchSawKeyDown = true; //按下事件 } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { if (mAppSwitchSawKeyDown) { //其中APP_SWITCH_TIMEOUT=500ms mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
                    mAppSwitchSawKeyDown = false;
                    needWake = true;
                }
            }
        } break;
    } case EventEntry::TYPE_MOTION: { //当前App无响应且用户希望切换到其他应用窗口,则drop该窗口事件,并处理其他窗口事件 MotionEntry* motionEntry = static_cast(entry); if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
                && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
                && mInputTargetWaitApplicationHandle != NULL) { int32_t displayId = motionEntry->displayId; int32_t x = int32_t(motionEntry->pointerCoords[0].
                    getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(motionEntry->pointerCoords[0].
                    getAxisValue(AMOTION_EVENT_AXIS_Y)); //查询可触摸的窗口【见小节4.3.4】 sp touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); if (touchedWindowHandle != NULL && touchedWindowHandle->inputApplicationHandle
                            != mInputTargetWaitApplicationHandle) {
                mNextUnblockedEvent = motionEntry;
                needWake = true;
            }
        } break;
    }
    }

    return needWake;
} 

AppSwitchKeyEvent是指keyCode等于以下值:

  • AKEYCODE_HOME
  • AKEYCODE_ENDCALL
  • AKEYCODE_APP_SWITCH

4.3.4 findTouchedWindowAtLocked

[-> InputDispatcher.cpp]

sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,
        int32_t x, int32_t y) { //从前台到后台来遍历查询可触摸的窗口 size_t numWindows = mWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) {
        sp windowHandle = mWindowHandles.itemAt(i); const InputWindowInfo* windowInfo = windowHandle->getInfo(); if (windowInfo->displayId == displayId) {
            int32_t flags = windowInfo->layoutParamsFlags; if (windowInfo->visible) { if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
                    bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
                            | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { return windowHandle; //找到目标窗口 }
                }
            }
        }
    } return NULL;
} 

此处mWindowHandles的赋值过程是由Java层的InputMonitor.setInputWindows(),经过JNI调用后进入InputDispatcher::setInputWindows()方法完成. 进一步说, 就是WMS执行addWindow()过程或许UI改变等场景,都会触发该方法的修改.

4.3.5 Looper.wake

[-> system/core/libutils/Looper.cpp]

void Looper::wake() { uint64_t inc = 1; ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t))); if (nWrite != sizeof(uint64_t)) { if (errno != EAGAIN) {
            ALOGW("Could not write wake signal, errno=%d", errno);
        }
    }
} 

[小节4.3]的过程会调用enqueueInboundEventLocked()方法来决定是否需要将数字1写入句柄mWakeEventFd来唤醒InputDispatcher线程. 满足唤醒的条件:

  1. 执行enqueueInboundEventLocked方法前,mInboundQueue队列为空,执行完必然不再为空,则需要唤醒分发线程;
  2. 当事件类型为key事件,且发生一对按下和抬起操作,则需要唤醒;
  3. 当事件类型为motion事件,且当前可触摸的窗口属于另一个应用,则需要唤醒.

五. 总结

5.1 核心工作

InputReader整个过程涉及多次事件封装转换,其主要工作核心是以下三大步骤:

  • getEvents:通过EventHub(监听目录/dev/input)读取事件放入mEventBuffer,而mEventBuffer是一个大小为256的数组, 再将事件input_event转换为RawEvent; [见小节2.1]
  • processEventsLocked: 对事件进行加工, 转换RawEvent -> NotifyKeyArgs(NotifyArgs) [见小节3.1]
  • QueuedListener->flush:将事件发送到InputDispatcher线程, 转换NotifyKeyArgs -> KeyEntry(EventEntry) [见小节4.1]

InputReader线程不断循环地执行InputReader.loopOnce(), 每次处理完生成的是EventEntry(比如KeyEntry, MotionEntry), 接下来的工作就交给InputDispatcher线程。

5.2 流程图

点击查看大图:

input_reader_seq

InputReader的核心工作就是从EventHub获取数据后生成EventEntry事件,加入到InputDispatcher的mInboundQueue队列,再唤醒InputDispatcher线程。

input_reader

说明:

  • IMS.filterInputEvent可以过滤无需上报的事件,当该方法返回值为false则代表是需要被过滤掉的事件,无机会交给InputDispatcher来分发。
  • 节点/dev/input的event事件所对应的输入设备信息位于/proc/bus/input/devices,也可以通过getevent来获取事件. 不同的input事件所对应的物理input节点,比如常见的情形:
    • 屏幕触摸和(MENU,HOME,BACK)3按键:对应同一个input设备节点;
    • POWER和音量(下)键:对应同一个input设备节点;
    • 音量(上)键:对应同一个input设备节点;

阅读(2464) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~