Android6.0 按键流程(一)读取设备事件

来源:互联网 发布:在家便知天下事ppt 编辑:程序博客网 时间:2024/05/21 12:47

之前我们整理过一篇按键流程,但是不是太详细有的细节的地方有遗漏,今天在Android6.0上重新总结下,先从读取按键值作为第一篇。


一、初始化

InputManagerService在SystemServer中新建,然后调用了start函数,这里我们就不讲了,从InputManagerService的构造函数讲起。


    public InputManagerService(Context context) {        this.mContext = context;        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());        mUseDevInputEventForAudioJack =                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="                + mUseDevInputEventForAudioJack);        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());        LocalServices.addService(InputManagerInternal.class, new LocalService());    }

nativeInit在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 == NULL) {        jniThrowRuntimeException(env, "MessageQueue is not initialized.");        return 0;    }    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,            messageQueue->getLooper());    im->incStrong(0);    return reinterpret_cast<jlong>(im);}

新建了一个NativeInputManager对象,并且把这个对象返回了保存在了InputManagerService的mPtr对象中,这只是保存了c层对象的地址,所以只要使用long保存地址就行了。

下面我们看下其构造函数:

NativeInputManager::NativeInputManager(jobject contextObj,        jobject serviceObj, const sp<Looper>& looper) :        mLooper(looper), mInteractive(true) {    JNIEnv* env = jniEnv();    mContextObj = env->NewGlobalRef(contextObj);    mServiceObj = env->NewGlobalRef(serviceObj);    {        AutoMutex _l(mLock);        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;        mLocked.pointerSpeed = 0;        mLocked.pointerGesturesEnabled = true;        mLocked.showTouches = false;    }    mInteractive = true;    sp<EventHub> eventHub = new EventHub();    mInputManager = new InputManager(eventHub, this, this);}

新建了一个InputManager和EventHub。


InputManager对象是在InputManager.cpp文件中

InputManager::InputManager(        const sp<EventHubInterface>& eventHub,        const sp<InputReaderPolicyInterface>& readerPolicy,        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {    mDispatcher = new InputDispatcher(dispatcherPolicy);    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);    initialize();}

InputManager中新建了一个InputDispatcher和InputReader两个对象,然后调用了initialize函数:

void InputManager::initialize() {    mReaderThread = new InputReaderThread(mReader);    mDispatcherThread = new InputDispatcherThread(mDispatcher);}

这两个变量就是两个线程我们就不看其构造函数了。


接着在InputManagerService中又调了start函数:

    public void start() {        Slog.i(TAG, "Starting input manager");        nativeStart(mPtr);        // Add ourself to the Watchdog monitors.        Watchdog.getInstance().addMonitor(this);        registerPointerSpeedSettingObserver();        registerShowTouchesSettingObserver();        mContext.registerReceiver(new BroadcastReceiver() {            @Override            public void onReceive(Context context, Intent intent) {                updatePointerSpeedFromSettings();                updateShowTouchesFromSettings();            }        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);        updatePointerSpeedFromSettings();        updateShowTouchesFromSettings();    }

我们主要看下nativeStart函数:

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);    status_t result = im->getInputManager()->start();    if (result) {        jniThrowRuntimeException(env, "Input manager could not be started.");    }}

我们先把InputManagerService保存的mPtr传下来的变量强制转成NativeInputManager,调用调用器getInputManager函数,也就是其InputManager的start函数

status_t InputManager::start() {    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);    if (result) {        ALOGE("Could not start InputDispatcher thread due to error %d.", result);        return result;    }    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);    if (result) {        ALOGE("Could not start InputReader thread due to error %d.", result);        mDispatcherThread->requestExit();        return result;    }    return OK;}


二、EventHub

在上一节中,在NativeInputManager构造函数中,还新建了一个EventHub对象,下面我们就来介绍下:

我们先来分析下其构造函数:

EventHub::EventHub(void) :        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),        mOpeningDevices(0), mClosingDevices(0),        mNeedToSendFinishedDeviceScan(false),        mNeedToReopenDevices(false), mNeedToScanDevices(true),        mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);    mEpollFd = epoll_create(EPOLL_SIZE_HINT);    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);    mINotifyFd = inotify_init();//INotify机制    int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);//监控dev/input目录    LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s.  errno=%d",            DEVICE_PATH, errno);    struct epoll_event eventItem;    memset(&eventItem, 0, sizeof(eventItem));    eventItem.events = EPOLLIN;    eventItem.data.u32 = EPOLL_ID_INOTIFY;    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);//将这个iNotify的fd加入epoll    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance.  errno=%d", errno);    int wakeFds[2];    result = pipe(wakeFds);//创建了管道,用来唤醒epoll    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.u32 = EPOLL_ID_WAKE;    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);    int major, minor;    getLinuxRelease(&major, &minor);    // EPOLLWAKEUP was introduced in kernel 3.5    mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);}

在构造函数中,使用了INotify机制(在之前的博客中介绍过)监控dev/input下文件的创建和删除动作,并且将INotify的fd加入epoll机制。还创建了一个pipe,将read端的fd加入了epoll,用来唤醒epoll。

下面我们先来提下会在InputReaderThread这个线程中,不断调用InputReader的loopOnce函数,这个函数会调用EventHub的getEvents函数,我们先来分析下这个函数,其他的我们后续再分析,这个函数写的非常经典。

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {    ALOG_ASSERT(bufferSize >= 1);    AutoMutex _l(mLock);    struct input_event readBuffer[bufferSize];    RawEvent* event = buffer;    size_t capacity = bufferSize;    bool awoken = false;    for (;;) {......        if (mNeedToScanDevices) {//这个变量第一次传进来为 true            mNeedToScanDevices = false;            scanDevicesLocked();//扫描设备            mNeedToSendFinishedDeviceScan = true;        }

scanDevicesLocked函数调用了scanDirLocked函数

void EventHub::scanDevicesLocked() {    status_t res = scanDirLocked(DEVICE_PATH);//dev/input    if(res < 0) {        ALOGE("scan dir failed for %s\n", DEVICE_PATH);    }    if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {        createVirtualKeyboardLocked();    }}

调用了scanDirLocked函数扫描dev/input下的所有设备,然后调用openDeviceLocked函数

status_t EventHub::scanDirLocked(const char *dirname){    char devname[PATH_MAX];    char *filename;    DIR *dir;    struct dirent *de;    dir = opendir(dirname);    if(dir == NULL)        return -1;    strcpy(devname, dirname);    filename = devname + strlen(devname);    *filename++ = '/';    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);        openDeviceLocked(devname);//打开设备    }    closedir(dir);    return 0;}

openDeviceLocked函数,使用ioctrl获取设备的各种参数,将设备加入epoll,其data.u32设为deviceId,然后将设备入mDevices

status_t EventHub::openDeviceLocked(const char *devicePath) {    char buffer[80];    ALOGV("Opening device: %s", devicePath);    int fd = open(devicePath, O_RDWR | O_CLOEXEC);    if(fd < 0) {        ALOGE("could not open %s, %s\n", devicePath, strerror(errno));        return -1;    }    ......//调用ioctl,获取device的各种参数    eventItem.data.u32 = deviceId;//    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {//加入epoll        ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);        delete device;        return -1;    }......    addDeviceLocked(device);//加入mDevices    return 0;}

继续分析我们的getEvents函数,分析while循环

        bool deviceChanged = false;        while (mPendingEventIndex < mPendingEventCount) {            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];            if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {                if (eventItem.events & EPOLLIN) {//notify监测到有新设备,或者设备拔出                    mPendingINotify = true;                } else {                    ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);                }                continue;//跳出循环            }            if (eventItem.data.u32 == EPOLL_ID_WAKE) {                if (eventItem.events & EPOLLIN) {//唤醒事件                    ALOGV("awoken after wake()");                    awoken = true;//置位                    char buffer[16];                    ssize_t nRead;                    do {                        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));                    } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));                } else {                    ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",                            eventItem.events);                }                continue;            }

下面分析循环中的最后一段,这边是各种设备的事件

            ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);//deviceId            if (deviceIndex < 0) {                ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.",                        eventItem.events, eventItem.data.u32);                continue;            }            Device* device = mDevices.valueAt(deviceIndex);//填充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) {                    ALOGE("could not get event (wrong size: %d)", readSize);                } 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++) {                        struct input_event& iev = readBuffer[i];                        ALOGV("%s got: time=%d.%06d, type=%d, code=%d, value=%d",                                device->path.string(),                                (int) iev.time.tv_sec, (int) iev.time.tv_usec,                                iev.type, iev.code, iev.value);                        // Some input devices may have a better concept of the time                        // when an input event was actually generated than the kernel                        // which simply timestamps all events on entry to evdev.                        // This is a custom Android extension of the input protocol                        // mainly intended for use with uinput based device drivers.                        if (iev.type == EV_MSC) {                            if (iev.code == MSC_ANDROID_TIME_SEC) {                                device->timestampOverrideSec = iev.value;                                continue;                            } else if (iev.code == MSC_ANDROID_TIME_USEC) {                                device->timestampOverrideUsec = iev.value;                                continue;                            }                        }                        if (device->timestampOverrideSec || device->timestampOverrideUsec) {                            iev.time.tv_sec = device->timestampOverrideSec;                            iev.time.tv_usec = device->timestampOverrideUsec;                            if (iev.type == EV_SYN && iev.code == SYN_REPORT) {                                device->timestampOverrideSec = 0;                                device->timestampOverrideUsec = 0;                            }                            ALOGV("applied override time %d.%06d",                                    int(iev.time.tv_sec), int(iev.time.tv_usec));                        }                        // Use the time specified in the event instead of the current time                        // so that downstream code can get more accurate estimates of                        // event dispatch latency from the time the event is enqueued onto                        // the evdev client buffer.                        //                        // The event's timestamp fortuitously uses the same monotonic clock                        // time base as the rest of Android.  The kernel event device driver                        // (drivers/input/evdev.c) obtains timestamps using ktime_get_ts().                        // The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere                        // calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a                        // system call that also queries ktime_get_ts().                        event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL                                + nsecs_t(iev.time.tv_usec) * 1000LL;                        ALOGV("event time %" PRId64 ", now %" PRId64, event->when, now);                        // Bug 7291243: Add a guard in case the kernel generates timestamps                        // that appear to be far into the future because they were generated                        // using the wrong clock source.                        //                        // This can happen because when the input device is initially opened                        // it has a default clock source of CLOCK_REALTIME.  Any input events                        // enqueued right after the device is opened will have timestamps                        // generated using CLOCK_REALTIME.  We later set the clock source                        // to CLOCK_MONOTONIC but it is already too late.                        //                        // Invalid input event timestamps can result in ANRs, crashes and                        // and other issues that are hard to track down.  We must not let them                        // propagate through the system.                        //                        // Log a warning so that we notice the problem and recover gracefully.                        if (event->when >= now + 10 * 1000000000LL) {                            // Double-check.  Time may have moved on.                            nsecs_t time = systemTime(SYSTEM_TIME_MONOTONIC);                            if (event->when > time) {                                ALOGW("An input event from %s has a timestamp that appears to "                                        "have been generated using the wrong clock source "                                        "(expected CLOCK_MONOTONIC): "                                        "event time %" PRId64 ", current time %" PRId64                                        ", call time %" PRId64 ".  "                                        "Using current time instead.",                                        device->path.string(), event->when, time, now);                                event->when = time;                            } else {                                ALOGV("Event time is ok but failed the fast path and required "                                        "an extra call to systemTime: "                                        "event time %" PRId64 ", current time %" PRId64                                        ", call time %" PRId64 ".",                                        event->when, time, now);                            }                        }                        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.string());                deviceChanged = true;                closeDeviceLocked(device);            } else {                ALOGW("Received unexpected epoll event 0x%08x for device %s.",                        eventItem.events, device->identifier.name.string());            }        }

上面就是各种设备的事件处理,将event填充。

继续分析:

        if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {//前面扫描到设备的添加或者删除            mPendingINotify = false;            readNotifyLocked();            deviceChanged = true;        }        // Report added or removed devices immediately.        if (deviceChanged) {//如果设备改变了,添加或者删除设备了,就要重新循环            continue;        }
readNotifyLocked函数,就是读取INotify的内容,然后执行相应的打开设备或者关闭设备。
status_t EventHub::readNotifyLocked() {    int res;    char devname[PATH_MAX];    char *filename;    char event_buf[512];    int event_size;    int event_pos = 0;    struct inotify_event *event;    ALOGV("EventHub::readNotify nfd: %d\n", mINotifyFd);    res = read(mINotifyFd, event_buf, sizeof(event_buf));    if(res < (int)sizeof(*event)) {        if(errno == EINTR)            return 0;        ALOGW("could not get event, %s\n", strerror(errno));        return -1;    }    //printf("got %d bytes of event information\n", res);    strcpy(devname, DEVICE_PATH);    filename = devname + strlen(devname);    *filename++ = '/';    while(res >= (int)sizeof(*event)) {        event = (struct inotify_event *)(event_buf + event_pos);        //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");        if(event->len) {            strcpy(filename, event->name);            if(event->mask & IN_CREATE) {                openDeviceLocked(devname);//打开设备            } else {                ALOGI("Removing device '%s' due to inotify event\n", devname);                closeDeviceByPathLocked(devname);//关闭设备            }        }        event_size = sizeof(*event) + event->len;        res -= event_size;        event_pos += event_size;    }    return 0;}
再分析getEvents的最后一部分

        // Return now if we have collected any events or if we were explicitly awoken.        if (event != buffer || awoken) {//这个event != buffer代表已经读取到内容了,所以event指针向前走了            break;        }        // Poll for events.  Mind the wake lock dance!        // We hold a wake lock at all times except during epoll_wait().  This works due to some        // subtle choreography.  When a device driver has pending (unread) events, it acquires        // a kernel wake lock.  However, once the last pending event has been read, the device        // driver will release the kernel wake lock.  To prevent the system from going to sleep        // when this happens, the EventHub holds onto its own user wake lock while the client        // is processing events.  Thus the system can only sleep if there are no events        // pending or currently being processed.        //        // The timeout is advisory only.  If the device is asleep, it will not wake just to        // service the timeout.        mPendingEventIndex = 0;        mLock.unlock(); // release lock before poll, must be before release_wake_lock        release_wake_lock(WAKE_LOCK_ID);        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);//epoll等待,数据加入mPendingEventItems        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);        mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock        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);        }    }    // All done, return the number of events we read.    return event - buffer;//返回个数

当读取到内容或者需要唤醒时,直接退出。epoll将内容放入mPendingEventItems,等下次循环处理。
这样EventHub就分析结束了。

三、InputReader中的InputMapper

InputReader,前面分析到InputManagerService调用Start函数后,会在InputManager对象中,开启InputReaderThread,和InputDispatcherThread线程。

我们先来分析InputReaderThread,在一直调用InputReader的loopOnce函数

void InputReader::loopOnce() {    ......    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);    { // acquire lock        AutoMutex _l(mLock);        mReaderIsAliveCondition.broadcast();        if (count) {            processEventsLocked(mEventBuffer, count);        }

我们这边主要分析两个函数,先从EventHub中获取事件,然后调用processEventsLocked函数:

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;            }#if DEBUG_RAW_EVENTS            ALOGD("BatchSize: %d Count: %d", 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;    }}
我们先来看下设备增加,会在mDevices中增加一个设备。

void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);    if (deviceIndex >= 0) {        ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId);        return;    }    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);    uint32_t classes = mEventHub->getDeviceClasses(deviceId);    int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);    InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);//创建一个InputDevice    device->configure(when, &mConfig, 0);    device->reset(when);    if (device->isIgnored()) {        ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,                identifier.name.string());    } else {        ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,                identifier.name.string(), device->getSources());    }    mDevices.add(deviceId, device);    bumpGenerationLocked();    if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {        notifyExternalStylusPresenceChanged();    }}

我们来看看EventHub->getDeviceClasses函数

uint32_t EventHub::getDeviceClasses(int32_t deviceId) const {    AutoMutex _l(mLock);    Device* device = getDeviceLocked(deviceId);    if (device == NULL) return 0;    return device->classes;}

就是每个device的classed成员变量,那么我们还是要分析EventHub的openDeviceLocked函数:肯定是在ioctl获取各种参数的时候设置的这个成员变量:

    // joystick and gamepad buttons which are handled like keyboards for the most part.    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;    }    // See if this is a cursor device such as a trackball or mouse.    if (test_bit(BTN_MOUSE, device->keyBitmask)            && test_bit(REL_X, device->relBitmask)            && test_bit(REL_Y, device->relBitmask)) {        device->classes |= INPUT_DEVICE_CLASS_CURSOR;    }    // See if this is a touch pad.    // Is this a new modern multi-touch driver?    if (test_bit(ABS_MT_POSITION_X, device->absBitmask)            && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {        // Some joysticks such as the PS3 controller report axes that conflict        // with the ABS_MT range.  Try to confirm that the device really is        // a touch screen.        if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) {            device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;        }    // Is this an old style single-touch driver?    } else if (test_bit(BTN_TOUCH, device->keyBitmask)            && test_bit(ABS_X, device->absBitmask)            && test_bit(ABS_Y, device->absBitmask)) {        device->classes |= INPUT_DEVICE_CLASS_TOUCH;    // Is this a BT stylus?    } else if ((test_bit(ABS_PRESSURE, device->absBitmask) ||                test_bit(BTN_TOUCH, device->keyBitmask))            && !test_bit(ABS_X, device->absBitmask)            && !test_bit(ABS_Y, device->absBitmask)) {        device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS;        // Keyboard will try to claim some of the buttons but we really want to reserve those so we        // can fuse it with the touch screen data, so just take them back. Note this means an        // external stylus cannot also be a keyboard device.        device->classes &= ~INPUT_DEVICE_CLASS_KEYBOARD;    }    // See if this device is a joystick.    // Assumes that joysticks always have gamepad buttons in order to distinguish them    // from other devices such as accelerometers that also have absolute axes.    if (haveGamepadButtons) {        uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK;        for (int i = 0; i <= ABS_MAX; i++) {            if (test_bit(i, device->absBitmask)                    && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) {                device->classes = assumedClasses;                break;            }        }    }    // Check whether this device has switches.    for (int i = 0; i <= SW_MAX; i++) {        if (test_bit(i, device->swBitmask)) {            device->classes |= INPUT_DEVICE_CLASS_SWITCH;            break;        }    }
结果果然是classes的设置,


那我们继续分析createDeviceLocked函数:

InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,        const InputDeviceIdentifier& identifier, uint32_t classes) {    InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),            controllerNumber, identifier, classes);    // External devices.    if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {        device->setExternal(true);    }    // Devices with mics.    if (classes & INPUT_DEVICE_CLASS_MIC) {        device->setMic(true);    }    // Switch-like devices.    if (classes & INPUT_DEVICE_CLASS_SWITCH) {        device->addMapper(new SwitchInputMapper(device));    }    // Vibrator-like devices.    if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {        device->addMapper(new VibratorInputMapper(device));    }    // Keyboard-like devices.    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;    }    if (keyboardSource != 0) {        device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));    }    // Cursor-like devices.    if (classes & INPUT_DEVICE_CLASS_CURSOR) {        device->addMapper(new CursorInputMapper(device));    }    // Touchscreens and touchpad devices.    if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {        device->addMapper(new MultiTouchInputMapper(device));    } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {        device->addMapper(new SingleTouchInputMapper(device));    }    // Joystick-like devices.    if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {        device->addMapper(new JoystickInputMapper(device));    }    // External stylus-like devices.    if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {        device->addMapper(new ExternalStylusInputMapper(device));    }    return device;}
这个函数又会根据classes不同,增加各种Mapper。


当我们在InputReader增加设备后,再来分析下processEventsForDeviceLocked函数,处理设备事件的:

void InputReader::processEventsForDeviceLocked(int32_t deviceId,        const RawEvent* rawEvents, size_t count) {    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);    if (deviceIndex < 0) {        ALOGW("Discarding event for unknown deviceId %d.", deviceId);        return;    }    InputDevice* device = mDevices.valueAt(deviceIndex);    if (device->isIgnored()) {        //ALOGD("Discarding event for ignored deviceId %d.", deviceId);        return;    }    device->process(rawEvents, count);}

这个函数是获取相对应的device执行process函数:

void InputDevice::process(const RawEvent* rawEvents, size_t count) {    // Process all of the events in order for each mapper.    // We cannot simply ask each mapper to process them in bulk because mappers may    // have side-effects that must be interleaved.  For example, joystick movement events and    // gamepad button presses are handled by different mappers but they should be dispatched    // in the order received.    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 {            }        } 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->process(rawEvent);            }        }    }}
最后遍历各个Event,然后遍历每个Device的InputMapper去执行其process函数。




2 0