Android6.0 按键流程(一)读取设备事件
2016-01-29 16:19
507 查看
之前我们整理过一篇按键流程,但是不是太详细有的细节的地方有遗漏,今天在Android6.0上重新总结下,先从读取按键值作为第一篇。
nativeInit在com_android_server_input_InputManagerService.cpp中,实现如下:
新建了一个NativeInputManager对象,并且把这个对象返回了保存在了InputManagerService的mPtr对象中,这只是保存了c层对象的地址,所以只要使用long保存地址就行了。
下面我们看下其构造函数:
新建了一个InputManager和EventHub。
InputManager对象是在InputManager.cpp文件中
InputManager中新建了一个InputDispatcher和InputReader两个对象,然后调用了initialize函数:
这两个变量就是两个线程我们就不看其构造函数了。
接着在InputManagerService中又调了start函数:
我们主要看下nativeStart函数:
我们先把InputManagerService保存的mPtr传下来的变量强制转成NativeInputManager,调用调用器getInputManager函数,也就是其InputManager的start函数
在上一节中,在NativeInputManager构造函数中,还新建了一个EventHub对象,下面我们就来介绍下:
我们先来分析下其构造函数:
在构造函数中,使用了INotify机制(在之前的博客中介绍过)监控dev/input下文件的创建和删除动作,并且将INotify的fd加入epoll机制。还创建了一个pipe,将read端的fd加入了epoll,用来唤醒epoll。
下面我们先来提下会在InputReaderThread这个线程中,不断调用InputReader的loopOnce函数,这个函数会调用EventHub的getEvents函数,我们先来分析下这个函数,其他的我们后续再分析,这个函数写的非常经典。
scanDevicesLocked函数调用了scanDirLocked函数
调用了scanDirLocked函数扫描dev/input下的所有设备,然后调用openDeviceLocked函数
openDeviceLocked函数,使用ioctrl获取设备的各种参数,将设备加入epoll,其data.u32设为deviceId,然后将设备入mDevices
继续分析我们的getEvents函数,分析while循环
下面分析循环中的最后一段,这边是各种设备的事件
上面就是各种设备的事件处理,将event填充。
继续分析:
当读取到内容或者需要唤醒时,直接退出。epoll将内容放入mPendingEventItems,等下次循环处理。
这样EventHub就分析结束了。
我们先来分析InputReaderThread,在一直调用InputReader的loopOnce函数
我们这边主要分析两个函数,先从EventHub中获取事件,然后调用processEventsLocked函数:
我们来看看EventHub->getDeviceClasses函数
就是每个device的classed成员变量,那么我们还是要分析EventHub的openDeviceLocked函数:肯定是在ioctl获取各种参数的时候设置的这个成员变量:
那我们继续分析createDeviceLocked函数:
当我们在InputReader增加设备后,再来分析下processEventsForDeviceLocked函数,处理设备事件的:
这个函数是获取相对应的device执行process函数:
一、初始化
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函数。
相关文章推荐
- Android 获取以太网Mac地址和IP地址
- Android:inputType参数类型说明
- Android Learning:数据存储方案归纳与总结
- Android-开发工具及测试工具
- android的窗口机制分析------事件处理
- Android自定义属性时TypedArray的使用方法
- android studio内存分析初探
- Android权限 uses-permission
- Android重写onConfigurationChanged规避横竖屏切换时候重新进入onCreate生命周期
- android应用中去掉标题栏的方法
- Android:图片大小缩放drawable
- Android反射机制实现与原理
- charter2 Android项目目录结构
- Android 自定义Button按钮显示样式(正常、按下、获取焦点)
- Android 快速开发系列 打造万能的ListView GridView 适配器
- 如何理解android中的上下文对象(Context对象)?
- Android客户端程序Gradle如何打包
- Android中CursorLoader的使用、原理及注意事项
- Android中AlertDialog用法实例分析
- Android ImageView的显示方式 (scaleType属性与adjustViewBounds属性)