Android 5.0输入系统分析之InputReader线程分析

上编分析了InputReader线程和InputDispatcher线程启动过程后,InputReader和InputDispatcher线程可以运行起来了,那么InputReader和InputDispatcher线程是如何工作?首先分析InputReader线程。

InputReader线程启动后,是从InputReader的loopOnce函数开始

void InputReader::loopOnce() {
  size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
  processEventsLocked(mEventBuffer, count);
  mQueuedListener->flush();
}

把loopOnce分3大块来分析,已在代码中注明

size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

调用EventHub.cpp中的

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    for (;;) {
        if (mNeedToReopenDevices) {
            mNeedToReopenDevices = false;
            closeAllDevicesLocked();
            mNeedToScanDevices = true;
            break; 
        }
    if (mNeedToScanDevices) {  
        mNeedToScanDevices=true
        mNeedToScanDevices = false;
        scanDevicesLocked();      
        mNeedToSendFinishedDeviceScan = true;
    }
  while (mPendingEventIndex < mPendingEventCount) { 
      const struct epoll_event& eventItem =          mPendingEventItems[mPendingEventIndex++];
      if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {  
          if (eventItem.events & EPOLLIN) {
              mPendingINotify = true;
           }
          continue;
      }
      if (eventItem.data.u32 == EPOLL_ID_WAKE) {
          if (eventItem.events & EPOLLIN) {
              ALOGV("awoken after wake()");
              awoken = true;
      }

      ssize_t deviceIndex =    mDevices.indexOfKey(eventItem.data.u32);
      Device* device = mDevices.valueAt(deviceIndex);
      if (eventItem.events & EPOLLIN) { 
          int32_t readSize = read(device->fd, readBuffer,
                  sizeof(struct input_event) * capacity);
              int32_t deviceId = device->id ==   mBuiltInKeyboardId ? 0 : device->id;

       }                   
  int  pollResult=epoll_wait(mEpollFd,mPendingEventItems,EPOLL_MAX_EVENTS, timeoutMillis);

    return event - buffer;
    }

进入 for (;;)后,首先调用 scanDevicesLocked(); 是调用EventHub.cpp中的scanDevicesLocked:

void EventHub::scanDevicesLocked() {
    status_t res = scanDirLocked(DEVICE_PATH);
}

scanDevicesLocked函数中调用了EventHub.java中的scanDirLocked

status_t EventHub::scanDirLocked(const char *dirname)
{
    dir = opendir(dirname);
    while((de = readdir(dir))) {
        openDeviceLocked(devname);
    }
    closedir(dir);
    return 0;
}

opendir打开/dev/input目录,用while((de = readdir(dir)))一一读出/dev/input目录下设备节点,然后调用EventHub.cpp中的openDeviceLocked

status_t EventHub::openDeviceLocked{
    int fd = open(devicePath, O_RDWR | O_CLOEXEC);

    if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) 


    // Get device driver version.
    if(ioctl(fd, EVIOCGVERSION, &driverVersion)) 

    // Get device identifier.
    if(ioctl(fd, EVIOCGID, &inputId)) 

    identifier.bus       = inputId.bustype;
    identifier.product = inputId.product;
    identifier.vendor  = inputId.vendor;
    identifier.version  = inputId.version;


    int32_t deviceId = mNextDeviceId++;
    Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
    loadConfigurationLocked(device); //idc

    // Figure out the kinds of events the device reports.
    ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);

    bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC))
            || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK),
                    sizeof_bit_array(KEY_MAX + 1));
    bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC),
                    sizeof_bit_array(BTN_MOUSE))
            || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK),
                    sizeof_bit_array(BTN_DIGI));
    if (haveKeyboardKeys || haveGamepadButtons) {
        device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
    }
    // Check whether this device supports the vibrator.
    if (test_bit(FF_RUMBLE, device->ffBitmask)) {
        device->classes |= INPUT_DEVICE_CLASS_VIBRATOR;
    }

    status_t keyMapStatus = NAME_NOT_FOUND;
    if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {
        // Load the keymap for the device.
        keyMapStatus = loadKeyMapLocked(device); //key
    } 

    // Register with epoll.
    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = mUsingEpollWakeup ? EPOLLIN : EPOLLIN | EPOLLWAKEUP;

    eventItem.data.u32 = deviceId;
    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
        ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);
        delete device;
        return -1;
    }
    addDeviceLocked(device);
    return 0;
}

open打开/dev/input/目录下XX个节点,读取出这个设备的有用信息。比如设备版本号多少,是什么总线,产口id等等信息。然后创建一个new Device();存放fd, deviceId, devicePath, identifier信息。接下来就是调用 loadConfigurationLocked(device); //idc函数,如果是触摸屏,根据Input Driver中的名字找到相应的名字的idc文件,如果不是触摸屏,此函数没有什么作用。然后检查是哪一类设备,进行相应的设置。比如按键keyMapStatus = loadKeyMapLocked(device);完成相应的设备初始化后,调用epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)加入了epoll中,进行数据监听。最后调用addDeviceLocked(device);函数。接下来分析addDeviceLocked函数,即是调用EventHub.cpp中的addDeviceLocked函数:

void EventHub::addDeviceLocked(Device* device) {
    mDevices.add(device->id, device);
    device->next = mOpeningDevices;
    mOpeningDevices = device;
}

把Device加入mDevices中。经过分析,清楚了scanDevicesLocked就是打开/dev/input/*下所有设备,读出相关的信息,创建一个Device存放相关信息,并检查类型设置,然后把所有设备节点的描述符加入epoll中,最后把Device加入mDevices中。
回到getEvents中scanDevicesLocked跑完后epoll_wait监听设备节点的数据,读到数据后进入while (mPendingEventIndex < mPendingEventCount) 中,然后从const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];中一一取出数据进行判断,从 Device* device = mDevices.valueAt(deviceIndex);中取出一个Device,然后把 int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;存在RawEvent中的deviceId中。
完成后返回到loopOnce中,接下来就是loopOnce中
processEventsLocked函数调用了InputReader.cpp中processEventsLocked

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count){
    for (const RawEvent* rawEvent = rawEvents; count;) {
            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;
            }
        }
}

如果 if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) 不是输入事件,执行switch (rawEvent->type) ,很清楚知道是关于设备添加、删除等操作。重点就是if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) 中processEventsForDeviceLocked函数,调用InputReader.cpp中processEventsForDeviceLocked

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

    InputDevice* device = mDevices.valueAt(deviceIndex);

        return;
    }

    device->process(rawEvents, count);
}

根据deviceId从mDevices中打出InputDevice,然后调用InputDevice中process。这个InputDevice中process是哪一个?上面分析scanDevicesLocked中知道,相应类中就的有相对应的keyMap,比如是按键类,那么是调用了InputReader.cpp中的KeyboardInputMapper::process

void KeyboardInputMapper::process(const RawEvent* rawEvent) {
    switch (rawEvent->type) {
    case EV_KEY: {
            processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
    }  
}

调用了InputReader.cpp中KeyboardInputMapper::processKey

void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,

    NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
    getListener()->notifyKey(&args);
}

把keyCode、keyCode等的数据把包成一个args,最后调用getListener()->notifyKey(&args);
getListener()->notifyKey(&args);根据前面分析《 Android 5.0输入系统分析之InputReader和InputDispatcher线程启动过程》的mReader = new InputReader(eventHub, readerPolicy, mDispatcher);其别就是InputDispatcher。所以是调用了notifyKey:

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

创建一个NotifyKeyArgs加入mArgsQueue中。然后回到了loopOnce函数,最后调用了
mQueuedListener->flush();,那么就是调用flush

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

从mArgsQueue取出NotifyArgs,然后调用了NotifyArgs中的notify。就是

void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
    listener->notifyKey(this);
}

然后调用了InputDispatcher.cpp中的notifyKey

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {

    KeyEvent event;
    event.initialize(args->deviceId, args->source, args->action,
            flags, keyCode, args->scanCode, metaState, 0,
            args->downTime, args->eventTime);
    mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); 


    int32_t repeatCount = 0;
     KeyEntry* newEntry = new KeyEntry(args->eventTime,
             args->deviceId, args->source, policyFlags,
             args->action, flags, keyCode, args->scanCode,
             metaState, repeatCount, args->downTime);

     needWake = enqueueInboundEventLocked(newEntry); 

    if (needWake) {
        mLooper->wake();
    }
}

把数据 封成一个KeyEvent,调用了mPolicy->interceptKeyBeforeQueueing(&event, /byref/ policyFlags); 那么mPolicy又是谁?在notifyKey()函数中会新建一个KeyEvent对象并进行初始化,然后调用mPolicy的interceptKeyBeforeQueueing(mPolicy就是NativeInputManagers)

void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
        uint32_t& policyFlags) {

            wmActions = env->CallIntMethod(mServiceObj, 
                  gServiceClassInfo.interceptKeyBeforeQueueing,
                    keyEventObj, policyFlags); 


        handleInterceptActions(wmActions, when, /*byref*/ policyFlags); 
}
调用了PhoneWindowManager.java中的interceptKeyBeforeQueueing函数
对KEYCODE_VOLUME_DOWN:KeyEvent.KEYCODE_VOLUME_UP:KeyEvent.KEYCODE_VOLUME_MUTE等系统按键处理,然后调handleInterceptActions函数
void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
        uint32_t& policyFlags) {
    if (wmActions & WM_ACTION_PASS_TO_USER) {
        policyFlags |= POLICY_FLAG_PASS_TO_USER;
    } 
}

把policyFlags |= POLICY_FLAG_PASS_TO_USER;代表传给用户的。
回到notifyKey中,创建一个KeyEntry,把NotifyKeyArgs的数据初始化了KeyEntry。然后把KeyEntry放入到enqueueInboundEventLocked中。

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
        mInboundQueue.enqueueAtTail(entry);
}

把KeyEntry放入mInboundQueue队例头。数据放好后,mLooper->wake();唤醒InputDispatcher线程。InputReader线程到此分析完。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值