Chinaunix首页 | 论坛 | 博客
  • 博客访问: 231052
  • 博文数量: 27
  • 博客积分: 465
  • 博客等级: 下士
  • 技术积分: 1340
  • 用 户 组: 普通用户
  • 注册时间: 2012-08-23 22:33
文章分类

全部博文(27)

文章存档

2014年(1)

2013年(2)

2012年(24)

分类: LINUX

2012-09-12 20:15:11

    linux内核的iput子系统的驱动被封装成字符设备,目录位于/dev/inpuit,用户控件通过open()、read()读取来自底层驱动的输入事件。那么从最底层一步步来看看android的处理流程。在系统启动后,用户空间会通过读取/dev/inpput文件,而这个文件会通过openPlatformInput的scanDir调用openDevice。

点击(此处)折叠或打开

  1. bool EventHub::openPlatformInput(void)
  2. {
  3.     /*
  4.      * Open platform-specific input device(s).
  5.      */
  6.     int res;

  7.     mFDCount = 1;
  8.     mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
  9.     mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
  10.     mFDs[0].events = POLLIN;
  11.     mFDs[0].revents = 0;
  12.     mDevices[0] = NULL;
  13. #ifdef HAVE_INOTIFY
  14.     mFDs[0].fd = inotify_init();
  15.     res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE);
  16.     if(res < 0) {
  17.         LOGE("could not add watch for %s, %s\n", device_path, strerror(errno));
  18.     }
  19. #else
  20.     /*
  21.      * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd.
  22.      * We allocate space for it and set it to something invalid.
  23.      */
  24.     mFDs[0].fd = -1;
  25. #endif

  26.     res = scanDir(device_path);
  27.     if(res < 0) {
  28.         LOGE("scan dir failed for %s\n", device_path);
  29.     }

  30.     return true;
  31. }
openDevice打开设备的时候,会判断事件类型,打开键盘设备的时候通过ioctl获得设备名称,最终会调用device->layoutMap->load进行映射,调用的是文件keylayoutmap.cpp中的函数:KeyLayoutMap::load(const char* filename)通过解析.kl把按键的映射关系保持在KeyedVector中,当获得按键事件以后调用会转换成andorid上层能够识别的按键。下面来看看EventHub.cpp的重点

点击(此处)折叠或打开

  1. bool EventHub::getEvent(RawEvent* outEvent)
  2. {
  3.     outEvent->deviceId = 0;
  4.     outEvent->type = 0;
  5.     outEvent->scanCode = 0;
  6.     outEvent->keyCode = 0;
  7.     outEvent->flags = 0;
  8.     outEvent->value = 0;
  9.     outEvent->when = 0;

  10.     if (!mOpened) {
  11.         mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
  12.         mOpened = true;
  13.         mNeedToSendFinishedDeviceScan = true;
  14.     }

  15.     for (;;) {
  16.         // Report any devices that had last been added/removed.
  17.         if (mClosingDevices != NULL) {
  18.             device_t* device = mClosingDevices;
  19.             LOGV("Reporting device closed: id=0x%x, name=%s\n",
  20.                  device->id, device->path.string());
  21.             mClosingDevices = device->next;
  22.             if (device->id == mFirstKeyboardId) {
  23.                 outEvent->deviceId = 0;
  24.             } else {
  25.                 outEvent->deviceId = device->id;
  26.             }
  27.             outEvent->type = DEVICE_REMOVED;
  28.             outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
  29.             delete device;
  30.             mNeedToSendFinishedDeviceScan = true;
  31.             return true;
  32.         }

  33.         if (mOpeningDevices != NULL) {
  34.             device_t* device = mOpeningDevices;
  35.             LOGV("Reporting device opened: id=0x%x, name=%s\n",
  36.                  device->id, device->path.string());
  37.             mOpeningDevices = device->next;
  38.             if (device->id == mFirstKeyboardId) {
  39.                 outEvent->deviceId = 0;
  40.             } else {
  41.                 outEvent->deviceId = device->id;
  42.             }
  43.             outEvent->type = DEVICE_ADDED;
  44.             outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
  45.             mNeedToSendFinishedDeviceScan = true;
  46.             return true;
  47.         }

  48.         if (mNeedToSendFinishedDeviceScan) {
  49.             mNeedToSendFinishedDeviceScan = false;
  50.             outEvent->type = FINISHED_DEVICE_SCAN;
  51.             outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
  52.             return true;
  53.         }

  54.         // Grab the next input event.
  55.         for (;;) {
  56.             // Consume buffered input events, if any.
  57.             if (mInputBufferIndex < mInputBufferCount) {
  58.                 const struct input_event& iev = mInputBufferData[mInputBufferIndex++];
  59.                 const device_t* device = mDevices[mInputDeviceIndex];

  60.                 LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(),
  61.                      (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value);
  62.                 if (device->id == mFirstKeyboardId) {
  63.                     outEvent->deviceId = 0;
  64.                 } else {
  65.                     outEvent->deviceId = device->id;
  66.                 }
  67.                 outEvent->type = iev.type;
  68.                 outEvent->scanCode = iev.code;
  69.                 if (iev.type == EV_KEY) {
  70.                     status_t err = device->layoutMap->map(iev.code,
  71.                             & outEvent->keyCode, & outEvent->flags);
  72.                     LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
  73.                         iev.code, outEvent->keyCode, outEvent->flags, err);
  74.                     if (err != 0) {
  75.                         outEvent->keyCode = AKEYCODE_UNKNOWN;
  76.                         outEvent->flags = 0;
  77.                     }
  78.                 } else {
  79.                     outEvent->keyCode = iev.code;
  80.                 }
  81.                 outEvent->value = iev.value;

  82.                 // Use an event timestamp in the same timebase as
  83.                 // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis()
  84.                 // as expected by the rest of the system.
  85.                 outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
  86.                 return true;
  87.             }


  88.             mInputDeviceIndex += 1;
  89.             if (mInputDeviceIndex >= mFDCount) {
  90.                 break;
  91.             }

  92.             const struct pollfd& pfd = mFDs[mInputDeviceIndex];
  93.             if (pfd.revents & POLLIN) {
  94.                 int32_t readSize = read(pfd.fd, mInputBufferData,
  95.                         sizeof(struct input_event) * INPUT_BUFFER_SIZE);
  96.                 if (readSize < 0) {
  97.                     if (errno != EAGAIN && errno != EINTR) {
  98.                         LOGW("could not get event (errno=%d)", errno);
  99.                     }
  100.                 } else if ((readSize % sizeof(struct input_event)) != 0) {
  101.                     LOGE("could not get event (wrong size: %d)", readSize);
  102.                 } else {
  103.                     mInputBufferCount = readSize / sizeof(struct input_event);
  104.                     mInputBufferIndex = 0;
  105.                 }
  106.             }
  107.         }

  108. #if HAVE_INOTIFY
  109.         // readNotify() will modify mFDs and mFDCount, so this must be done after
  110.         // processing all other events.
  111.         if(mFDs[0].revents & POLLIN) {
  112.             readNotify(mFDs[0].fd);
  113.             mFDs[0].revents = 0;
  114.             continue; // report added or removed devices immediately
  115.         }
  116. #endif

  117.         mInputDeviceIndex = 0;


  118.         release_wake_lock(WAKE_LOCK_ID);

  119.         int pollResult = poll(mFDs, mFDCount, -1);

  120.         acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

  121.         if (pollResult <= 0) {
  122.             if (errno != EINTR) {
  123.                 LOGW("poll failed (errno=%d)\n", errno);
  124.                 usleep(100000);
  125.             }
  126.         }
  127.     }
  128. }
如果是第一次进入到这个函数时,并且成员变量mopened的值为false,于是就调用openplatforminput函数来打开系统输入设备,打开这个设备就是用poll对这个输入设备进行监控。如果不是第一次进入到这个函数,那么就会分析当前有没有input事件发生,进而等待下一次input事件的发生,这个函数主要是读取input驱动传过来的事件信息。往下走

点击(此处)折叠或打开

  1. void InputReader::loopOnce() {
  2.     RawEvent rawEvent;
  3.     mEventHub->getEvent(& rawEvent);

  4. #if DEBUG_RAW_EVENTS
  5.     LOGD("Input event: device=0x%x type=0x%x scancode=%d keycode=%d value=%d",
  6.             rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode,
  7.             rawEvent.value);
  8. #endif

  9.     process(& rawEvent);
  10. }
这个函数通过EventHub的getEvent方法来获取input事件。

点击(此处)折叠或打开

  1. InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
  2.         Thread(/*canCallJava*/ true), mReader(reader) {
  3. }

  4. InputReaderThread::~InputReaderThread() {
  5. }

  6. bool InputReaderThread::threadLoop() {
  7.     mReader->loopOnce();
  8.     return true;
  9. }

点击(此处)折叠或打开

  1. void InputManager::initialize() {
  2.     mReaderThread = new InputReaderThread(mReader);
  3.     mDispatcherThread = new InputDispatcherThread(mDispatcher);
  4. }
原来创建了两个线程,InputReaderThread和InputDispatcherThread。 由于是Thread子类,于是继承了它的run方法。 InputReaderThread继承Thread,在执行run的时候会调用threadLoop。 而InputDispatcherThread 

点击(此处)折叠或打开

  1. InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
  2.         Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
  3. }

  4. InputDispatcherThread::~InputDispatcherThread() {
  5. }

  6. bool InputDispatcherThread::threadLoop() {
  7.     mDispatcher->dispatchOnce();
  8.     return true;
  9. }
那么会调用dispatchonce的方法

点击(此处)折叠或打开

  1. void InputDispatcher::dispatchOnce() {
  2.     nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout();
  3.     nsecs_t keyRepeatDelay = mPolicy->getKeyRepeatDelay();

  4.     nsecs_t nextWakeupTime = LONG_LONG_MAX;
  5.     { // acquire lock
  6.         AutoMutex _l(mLock);
  7.         dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime);

  8.         if (runCommandsLockedInterruptible()) {
  9.             nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
  10.         }
  11.     } // release lock

  12.     // Wait for callback or timeout or wake. (make sure we round up, not down)
  13.     nsecs_t currentTime = now();
  14.     int32_t timeoutMillis;
  15.     if (nextWakeupTime > currentTime) {
  16.         uint64_t timeout = uint64_t(nextWakeupTime - currentTime);
  17.         timeout = (timeout + 999999LL) / 1000000LL;
  18.         timeoutMillis = timeout > INT_MAX ? -1 : int32_t(timeout);
  19.     } else {
  20.         timeoutMillis = 0;
  21.     }

  22.     mLooper->pollOnce(timeoutMillis);
  23. }
该函数主要是由dispatchOnceInnerLocked处理input输入消息,mLooper->pollOnce等待下一次输入的事件。看看上面的是怎么被调用的吧!

点击(此处)折叠或打开

  1. status_t InputManager::start() {
  2.     char value[92];
  3.     status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
  4.     if (result) {
  5.         LOGE("Could not start InputDispatcher thread due to error %d.", result);
  6.         return result;
  7.     }

  8.     result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
  9.     if (result) {
  10.         LOGE("Could not start InputReader thread due to error %d.", result);

  11.         mDispatcherThread->requestExit();
  12.         return result;
  13.     }
  14.     
  15.     
  16.     property_get("ro.build.type", value, "usr");
  17.     if(strcmp(value, "eng") == 0){
  18.         LightWeight_KeyDispatchAnr::IS_ENG_BUILD = true;
  19.         LOGD("current build is eng build\n");    
  20.         LightWeight_KeyDispatchAnr::createMonitorThread();
  21.     }
  22.     
  23.     return OK;
  24. }
在NativeInputManager里面调用EventHubh和InputManager,也就是上面回顾的。

点击(此处)折叠或打开

  1. NativeInputManager::NativeInputManager(jobject callbacksObj) :
  2.     mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), mVirtualKeyQuietTime(-1),
  3.     mMaxEventsPerSecond(-1),
  4.     mDisplayWidth(-1), mDisplayHeight(-1), mDisplayOrientation(ROTATION_0) {
  5.     JNIEnv* env = jniEnv();

  6.     mCallbacksObj = env->NewGlobalRef(callbacksObj);
  7.     mDisplayOrientation = getHwRotation();

  8.     sp<EventHub> eventHub = new EventHub();
  9.     mInputManager = new InputManager(eventHub, this, this);
  10. }
那么NativeInputManager这个类是在哪创建的呢?

点击(此处)折叠或打开

  1. static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,
  2.         jobject callbacks) {
  3.     if (gNativeInputManager == NULL) {
  4.         gNativeInputManager = new NativeInputManager(callbacks);
  5.     } else {
  6.         LOGE("Input manager already initialized.");
  7.         jniThrowRuntimeException(env, "Input manager already initialized.");
  8.     }
  9. }

点击(此处)折叠或打开

  1. static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,
  2.         jobject callbacks) {
  3.     if (gNativeInputManager == NULL) {
  4.         gNativeInputManager = new NativeInputManager(callbacks);
  5.     } else {
  6.         LOGE("Input manager already initialized.");
  7.         jniThrowRuntimeException(env, "Input manager already initialized.");
  8.     }
  9. }

点击(此处)折叠或打开

  1. static JNINativeMethod gInputManagerMethods[] = {
  2.     /* name, signature, funcPtr */
  3.     { "nativeInit", "(Lcom/android/server/InputManager$Callbacks;)V",
  4.             (void*) android_server_InputManager_nativeInit },

点击(此处)折叠或打开

  1. public InputManager(Context context, WindowManagerService windowManagerService) {
  2.         this.mContext = context;
  3.         this.mWindowManagerService = windowManagerService;
  4.         
  5.         this.mCallbacks = new Callbacks();
  6.         
  7.         init();
  8.     }
  9.     
  10.     private void init() {
  11.         Slog.i(TAG, "Initializing input manager");
  12.         nativeInit(mCallbacks);
  13.     }

点击(此处)折叠或打开

  1. private WindowManagerService(Context context, PowerManagerService pm,
  2.             boolean haveInputMethods) {

  3.         mLockScreenType = SystemProperties.getInt("curlockscreen",1);

  4.         mContext = context;
  5.         mHaveInputMethods = haveInputMethods;
  6.         mLimitedAlphaCompositing = context.getResources().getBoolean(
  7.                 com.android.internal.R.bool.config_sf_limitedAlpha);

  8.         mPowerManager = pm;
  9.         mPowerManager.setPolicy(mPolicy);
  10.         PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
  11.         mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
  12.                 "SCREEN_FROZEN");
  13.         mScreenFrozenLock.setReferenceCounted(false);

  14.         mActivityManager = ActivityManagerNative.getDefault();
  15.         mBatteryStats = BatteryStatsService.getService();

  16.         // Get persisted window scale setting
  17.         mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(),
  18.                 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
  19.         mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
  20.                 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);

  21.         // Track changes to DevicePolicyManager state so we can enable/disable keyguard.
  22.         IntentFilter filter = new IntentFilter();
  23.         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
  24.         mContext.registerReceiver(mBroadcastReceiver, filter);

  25.         mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
  26.                 "KEEP_SCREEN_ON_FLAG");
  27.         mHoldingScreenWakeLock.setReferenceCounted(false);

  28.         mInputManager = new InputManager(context, this);

  29.         PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
  30.         thr.start();
从上面的流程可以看出
1.Eventhub:主要是管理所有系统中可以识别的输入设备的输入事件,当设备增加或者删去时,EventHub将产生相应的输入事件给系统。
2.InputReader:从EventHub中读取原始事件数据(RawEvent)
3.InputDispater:负责把事件分发给输入目标,在等列等待新的输入事件,并且异步的把这些事件分发给应用程序。
4.InputManager:事件处理的核心,不做具体的事。使用两个线程InputReader和InputDispater
阅读(4760) | 评论(0) | 转发(2) |
0

上一篇:Linux设备之I2C

下一篇:linux之块设备驱动

给主人留下些什么吧!~~