linux内核的iput子系统的驱动被封装成字符设备,目录位于/dev/inpuit,用户控件通过open()、read()读取来自底层驱动的输入事件。那么从最底层一步步来看看android的处理流程。在系统启动后,用户空间会通过读取/dev/inpput文件,而这个文件会通过openPlatformInput的scanDir调用openDevice。
- bool EventHub::openPlatformInput(void)
- {
- /*
- * Open platform-specific input device(s).
- */
- int res;
- mFDCount = 1;
- mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
- mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
- mFDs[0].events = POLLIN;
- mFDs[0].revents = 0;
- mDevices[0] = NULL;
- #ifdef HAVE_INOTIFY
- mFDs[0].fd = inotify_init();
- res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE);
- if(res < 0) {
- LOGE("could not add watch for %s, %s\n", device_path, strerror(errno));
- }
- #else
- /*
- * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd.
- * We allocate space for it and set it to something invalid.
- */
- mFDs[0].fd = -1;
- #endif
- res = scanDir(device_path);
- if(res < 0) {
- LOGE("scan dir failed for %s\n", device_path);
- }
- return true;
- }
openDevice打开设备的时候,会判断事件类型,打开键盘设备的时候通过ioctl获得设备名称,最终会调用device->layoutMap->load进行映射,调用的是文件keylayoutmap.cpp中的函数:KeyLayoutMap::load(const char* filename)通过解析
.kl把按键的映射关系保持在KeyedVector中,当获得按键事件以后调用会转换成andorid上层能够识别的按键。下面来看看EventHub.cpp的重点- bool EventHub::getEvent(RawEvent* outEvent)
- {
- outEvent->deviceId = 0;
- outEvent->type = 0;
- outEvent->scanCode = 0;
- outEvent->keyCode = 0;
- outEvent->flags = 0;
- outEvent->value = 0;
- outEvent->when = 0;
- if (!mOpened) {
- mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
- mOpened = true;
- mNeedToSendFinishedDeviceScan = true;
- }
- for (;;) {
- // Report any devices that had last been added/removed.
- if (mClosingDevices != NULL) {
- device_t* device = mClosingDevices;
- LOGV("Reporting device closed: id=0x%x, name=%s\n",
- device->id, device->path.string());
- mClosingDevices = device->next;
- if (device->id == mFirstKeyboardId) {
- outEvent->deviceId = 0;
- } else {
- outEvent->deviceId = device->id;
- }
- outEvent->type = DEVICE_REMOVED;
- outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
- delete device;
- mNeedToSendFinishedDeviceScan = true;
- return true;
- }
- if (mOpeningDevices != NULL) {
- device_t* device = mOpeningDevices;
- LOGV("Reporting device opened: id=0x%x, name=%s\n",
- device->id, device->path.string());
- mOpeningDevices = device->next;
- if (device->id == mFirstKeyboardId) {
- outEvent->deviceId = 0;
- } else {
- outEvent->deviceId = device->id;
- }
- outEvent->type = DEVICE_ADDED;
- outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
- mNeedToSendFinishedDeviceScan = true;
- return true;
- }
- if (mNeedToSendFinishedDeviceScan) {
- mNeedToSendFinishedDeviceScan = false;
- outEvent->type = FINISHED_DEVICE_SCAN;
- outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
- return true;
- }
- // Grab the next input event.
- for (;;) {
- // Consume buffered input events, if any.
- if (mInputBufferIndex < mInputBufferCount) {
- const struct input_event& iev = mInputBufferData[mInputBufferIndex++];
- const device_t* device = mDevices[mInputDeviceIndex];
- LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(),
- (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value);
- if (device->id == mFirstKeyboardId) {
- outEvent->deviceId = 0;
- } else {
- outEvent->deviceId = device->id;
- }
- outEvent->type = iev.type;
- outEvent->scanCode = iev.code;
- if (iev.type == EV_KEY) {
- status_t err = device->layoutMap->map(iev.code,
- & outEvent->keyCode, & outEvent->flags);
- LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
- iev.code, outEvent->keyCode, outEvent->flags, err);
- if (err != 0) {
- outEvent->keyCode = AKEYCODE_UNKNOWN;
- outEvent->flags = 0;
- }
- } else {
- outEvent->keyCode = iev.code;
- }
- outEvent->value = iev.value;
- // Use an event timestamp in the same timebase as
- // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis()
- // as expected by the rest of the system.
- outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
- return true;
- }
- mInputDeviceIndex += 1;
- if (mInputDeviceIndex >= mFDCount) {
- break;
- }
- const struct pollfd& pfd = mFDs[mInputDeviceIndex];
- if (pfd.revents & POLLIN) {
- int32_t readSize = read(pfd.fd, mInputBufferData,
- sizeof(struct input_event) * INPUT_BUFFER_SIZE);
- if (readSize < 0) {
- if (errno != EAGAIN && errno != EINTR) {
- LOGW("could not get event (errno=%d)", errno);
- }
- } else if ((readSize % sizeof(struct input_event)) != 0) {
- LOGE("could not get event (wrong size: %d)", readSize);
- } else {
- mInputBufferCount = readSize / sizeof(struct input_event);
- mInputBufferIndex = 0;
- }
- }
- }
- #if HAVE_INOTIFY
- // readNotify() will modify mFDs and mFDCount, so this must be done after
- // processing all other events.
- if(mFDs[0].revents & POLLIN) {
- readNotify(mFDs[0].fd);
- mFDs[0].revents = 0;
- continue; // report added or removed devices immediately
- }
- #endif
- mInputDeviceIndex = 0;
- release_wake_lock(WAKE_LOCK_ID);
- int pollResult = poll(mFDs, mFDCount, -1);
- acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
- if (pollResult <= 0) {
- if (errno != EINTR) {
- LOGW("poll failed (errno=%d)\n", errno);
- usleep(100000);
- }
- }
- }
- }
如果是第一次进入到这个函数时,并且成员变量mopened的值为false,于是就调用openplatforminput函数来打开系统输入设备,打开这个设备就是用poll对这个输入设备进行监控。如果不是第一次进入到这个函数,那么就会分析当前有没有input事件发生,进而等待下一次input事件的发生,这个函数主要是读取input驱动传过来的事件信息。往下走
- void InputReader::loopOnce() {
- RawEvent rawEvent;
- mEventHub->getEvent(& rawEvent);
- #if DEBUG_RAW_EVENTS
- LOGD("Input event: device=0x%x type=0x%x scancode=%d keycode=%d value=%d",
- rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode,
- rawEvent.value);
- #endif
- process(& rawEvent);
- }
这个函数通过EventHub的getEvent方法来获取input事件。
- InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
- Thread(/*canCallJava*/ true), mReader(reader) {
- }
- InputReaderThread::~InputReaderThread() {
- }
- bool InputReaderThread::threadLoop() {
- mReader->loopOnce();
- return true;
- }
- void InputManager::initialize() {
- mReaderThread = new InputReaderThread(mReader);
- mDispatcherThread = new InputDispatcherThread(mDispatcher);
- }
原来创建了两个线程,InputReaderThread和InputDispatcherThread。 由于是Thread子类,于是继承了它的run方法。
InputReaderThread继承Thread,在执行run的时候会调用threadLoop。 而InputDispatcherThread
- InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
- Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
- }
- InputDispatcherThread::~InputDispatcherThread() {
- }
- bool InputDispatcherThread::threadLoop() {
- mDispatcher->dispatchOnce();
- return true;
- }
那么会调用dispatchonce的方法
- void InputDispatcher::dispatchOnce() {
- nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout();
- nsecs_t keyRepeatDelay = mPolicy->getKeyRepeatDelay();
- nsecs_t nextWakeupTime = LONG_LONG_MAX;
- { // acquire lock
- AutoMutex _l(mLock);
- dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime);
- if (runCommandsLockedInterruptible()) {
- nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
- }
- } // release lock
- // Wait for callback or timeout or wake. (make sure we round up, not down)
- nsecs_t currentTime = now();
- int32_t timeoutMillis;
- if (nextWakeupTime > currentTime) {
- uint64_t timeout = uint64_t(nextWakeupTime - currentTime);
- timeout = (timeout + 999999LL) / 1000000LL;
- timeoutMillis = timeout > INT_MAX ? -1 : int32_t(timeout);
- } else {
- timeoutMillis = 0;
- }
- mLooper->pollOnce(timeoutMillis);
- }
该函数主要是由dispatchOnceInnerLocked处理input输入消息,mLooper->pollOnce等待下一次输入的事件。看看上面的是怎么被调用的吧!
- status_t InputManager::start() {
- char value[92];
- status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
- if (result) {
- LOGE("Could not start InputDispatcher thread due to error %d.", result);
- return result;
- }
- result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
- if (result) {
- LOGE("Could not start InputReader thread due to error %d.", result);
- mDispatcherThread->requestExit();
- return result;
- }
-
-
- property_get("ro.build.type", value, "usr");
- if(strcmp(value, "eng") == 0){
- LightWeight_KeyDispatchAnr::IS_ENG_BUILD = true;
- LOGD("current build is eng build\n");
- LightWeight_KeyDispatchAnr::createMonitorThread();
- }
-
- return OK;
- }
在NativeInputManager里面调用EventHubh和InputManager,也就是上面回顾的。
- NativeInputManager::NativeInputManager(jobject callbacksObj) :
- mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), mVirtualKeyQuietTime(-1),
- mMaxEventsPerSecond(-1),
- mDisplayWidth(-1), mDisplayHeight(-1), mDisplayOrientation(ROTATION_0) {
- JNIEnv* env = jniEnv();
- mCallbacksObj = env->NewGlobalRef(callbacksObj);
- mDisplayOrientation = getHwRotation();
- sp<EventHub> eventHub = new EventHub();
- mInputManager = new InputManager(eventHub, this, this);
- }
那么NativeInputManager这个类是在哪创建的呢?
- static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,
- jobject callbacks) {
- if (gNativeInputManager == NULL) {
- gNativeInputManager = new NativeInputManager(callbacks);
- } else {
- LOGE("Input manager already initialized.");
- jniThrowRuntimeException(env, "Input manager already initialized.");
- }
- }
- static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,
- jobject callbacks) {
- if (gNativeInputManager == NULL) {
- gNativeInputManager = new NativeInputManager(callbacks);
- } else {
- LOGE("Input manager already initialized.");
- jniThrowRuntimeException(env, "Input manager already initialized.");
- }
- }
- static JNINativeMethod gInputManagerMethods[] = {
- /* name, signature, funcPtr */
- { "nativeInit", "(Lcom/android/server/InputManager$Callbacks;)V",
- (void*) android_server_InputManager_nativeInit },
- public InputManager(Context context, WindowManagerService windowManagerService) {
- this.mContext = context;
- this.mWindowManagerService = windowManagerService;
-
- this.mCallbacks = new Callbacks();
-
- init();
- }
-
- private void init() {
- Slog.i(TAG, "Initializing input manager");
- nativeInit(mCallbacks);
- }
- private WindowManagerService(Context context, PowerManagerService pm,
- boolean haveInputMethods) {
- mLockScreenType = SystemProperties.getInt("curlockscreen",1);
- mContext = context;
- mHaveInputMethods = haveInputMethods;
- mLimitedAlphaCompositing = context.getResources().getBoolean(
- com.android.internal.R.bool.config_sf_limitedAlpha);
- mPowerManager = pm;
- mPowerManager.setPolicy(mPolicy);
- PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- "SCREEN_FROZEN");
- mScreenFrozenLock.setReferenceCounted(false);
- mActivityManager = ActivityManagerNative.getDefault();
- mBatteryStats = BatteryStatsService.getService();
- // Get persisted window scale setting
- mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(),
- Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
- mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
- Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
- // Track changes to DevicePolicyManager state so we can enable/disable keyguard.
- IntentFilter filter = new IntentFilter();
- filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
- mContext.registerReceiver(mBroadcastReceiver, filter);
- mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
- "KEEP_SCREEN_ON_FLAG");
- mHoldingScreenWakeLock.setReferenceCounted(false);
- mInputManager = new InputManager(context, this);
- PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
- thr.start();
从上面的流程可以看出
1.Eventhub:主要是管理所有系统中可以识别的输入设备的输入事件,当设备增加或者删去时,EventHub将产生相应的输入事件给系统。
2.InputReader:从EventHub中读取原始事件数据(RawEvent)
3.InputDispater:负责把事件分发给输入目标,在等列等待新的输入事件,并且异步的把这些事件分发给应用程序。
4.InputManager:事件处理的核心,不做具体的事。使用两个线程InputReader和InputDispater
阅读(284) | 评论(0) | 转发(0) |