android input system(frameworks) analysis -- InputManager (1)
来源:互联网 发布:网络40大禁书海岸线 编辑:程序博客网 时间:2024/04/30 01:21
http://blog.csdn.net/darkengine/article/details/6956802
对input系统在framework层的分析从一次触摸屏丢失上报事件开始:由于设备节点/dev/input/input0存在,而且getevent能响应点触摸屏的动作,所以把问题定位到了EventHub和InputManager这一层。
InputManager的结构很简单,对外开放
- virtual status_t start();
- virtual status_t stop();
- virtual sp<InputReaderInterface> getReader();
- virtual sp<InputDispatcherInterface> getDispatcher();
四个成员函数,内部带有私有成员
- sp<InputReaderInterface> mReader;
- sp<InputReaderThread> mReaderThread;
- sp<InputDispatcherInterface> mDispatcher;
- sp<InputDispatcherThread> mDispatcherThread;
- mDispatcher = new InputDispatcher(dispatcherPolicy); -- 根据输入的参数构造一个dispatcher
- mReader = new InputReader(eventHub, readerPolicy, mDispatcher); -- 根据参数构造一个inputreader
- initialize();
- void InputManager::initialize() {
- mReaderThread = new InputReaderThread(mReader); -- 产生reader线程用于从设备节点读取input event
- mDispatcherThread = new InputDispatcherThread(mDispatcher); -- 产生dispachter线程分发event
- }
- status_t InputManager::start() {
- status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
- ...
- result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
- ...
- return OK;
- }
====================================================================================================================
接着先来分析InputReader:
InputReaderThread run之后会重复的调用
- bool InputReaderThread::threadLoop() {
- mReader->loopOnce();
- return true;
- }
亦即mReader->loopOnce();
- void InputReader::loopOnce() {
- RawEvent rawEvent;
- mEventHub->getEvent(& rawEvent);
- process(& rawEvent);
- }
InputReader上来就找EventHub要数据(getEvent()),所以我们要先看看EventHub的getEvent都做了些什么工作:
- bool EventHub::getEvent(RawEvent* outEvent)
- {
- outEvent->deviceId = 0;
- ...
- // 第一次调用getEvent的时候,需要调用openPlatformInput来搜索输入系统来查找可用的设备
- if (!mOpened) {
- mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
- mOpened = true;
- mNeedToSendFinishedDeviceScan = true;
- }
- }
- bool EventHub::openPlatformInput(void)
- {
- // 为poll()调用作准备
- 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;
- ...
- // 上面有赋值device_path = "/dev/input"
- res = scanDir(device_path);
- ...
- return true;
- }
- int EventHub::openDevice(const char *deviceName) {
- int version;
- int fd;
- struct pollfd *new_mFDs;
- device_t **new_devices;
- char **new_device_names;
- char name[80];
- char location[80];
- char idstr[80];
- struct input_id id;
- LOGV("Opening device: %s", deviceName);
- AutoMutex _l(mLock);
- // 根据路径打开文件获取version, id, name等信息
- fd = open(deviceName, O_RDWR);
- if(fd < 0) ...
- if(ioctl(fd, EVIOCGVERSION, &version))
- ...
- if(ioctl(fd, EVIOCGID, &id))
- ...
- if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1)
- ...
- // check to see if the device is on our excluded list - 如果此设备在排除名单内,忽略它
- List<String8>::iterator iter = mExcludedDevices.begin();
- List<String8>::iterator end = mExcludedDevices.end();
- for ( ; iter != end; iter++) {
- ...
- }
- // 读取location, idstr等信息
- if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1)
- ...
- if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1)
- ...
- // 将设备文件设置为非阻塞
- if (fcntl(fd, F_SETFL, O_NONBLOCK))
- ...
- // 在mDeviceById数组中寻找“空位”,扩充mDeviceById的空间并把新device加到尾部
- int devid = 0;
- while (devid < mNumDevicesById) {
- if (mDevicesById[devid].device == NULL) {
- break;
- }
- devid++;
- }
- if (devid >= mNumDevicesById) {
- device_ent* new_devids = (device_ent*)realloc(mDevicesById,
- sizeof(mDevicesById[0]) * (devid + 1));
- if (new_devids == NULL) {
- LOGE("out of memory");
- return -1;
- }
- mDevicesById = new_devids;
- mNumDevicesById = devid+1;
- mDevicesById[devid].device = NULL;
- mDevicesById[devid].seq = 0;
- }
- mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK;
- if (mDevicesById[devid].seq == 0) {
- mDevicesById[devid].seq = 1<<SEQ_SHIFT;
- }
- // 为后面用poll()来获取kernel层上报的input event作准备
- new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1));
- new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1));
- if (new_mFDs == NULL || new_devices == NULL) {
- LOGE("out of memory");
- return -1;
- }
- mFDs = new_mFDs;
- mDevices = new_devices;
- device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name);
- if (device == NULL) {
- LOGE("out of memory");
- return -1;
- }
- device->fd = fd;
- mFDs[mFDCount].fd = fd;
- mFDs[mFDCount].events = POLLIN;
- mFDs[mFDCount].revents = 0;
- // Figure out the kinds of events the device reports.
- // 分辨本device的输入类型: keypad? touchscreen? gamepad?
- uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
- memset(key_bitmask, 0, sizeof(key_bitmask));
- // 测试本device是否为键盘,是的话把key_bitmask保存下来
- LOGV("Getting keys...");
- if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
- ...
- }
- // 是否为轨迹球或鼠标
- // See if this is a trackball (or mouse).
- if (test_bit(BTN_MOUSE, key_bitmask)) {
- ...
- }
- // 是否为touchscreen,是否支持多点触摸
- // See if this is a touch pad.
- uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)];
- memset(abs_bitmask, 0, sizeof(abs_bitmask));
- LOGV("Getting absolute controllers...");
- if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) {
- ...
- }
- #ifdef EV_SW
- // 是否为switch设备,这个宏没有打开
- #endif
- // 如果是键盘的话,加载keypad-layout,即/usr/keylayout/中的xxx.kl文件
- if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
- ...
- status_t status = device->layoutMap->load(keylayoutFilename);
- if (status) {
- LOGE("Error %d loading key layout.", status);
- }
- ...
- // tell the world about the devname (the descriptive name) - 找一个首选keyboard出来
- if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) {
- // the built-in keyboard has a well-known device ID of 0,
- // this device better not go away.
- mHaveFirstKeyboard = true;
- mFirstKeyboardId = device->id;
- property_set("hw.keyboards.0.devname", name);
- } else {
- // ensure mFirstKeyboardId is set to -something-.
- if (mFirstKeyboardId == 0) {
- mFirstKeyboardId = device->id;
- }
- }
- // 如果键盘有数字键,方向键,游戏控制键等特殊按钮,都一一标记到classes中
- if (hasKeycodeLocked(device, AKEYCODE_Q))
- ...
- if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
- hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
- hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&
- hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&
- hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {
- device->classes |= INPUT_DEVICE_CLASS_DPAD;
- }
- // See if this device has a gamepad.
- for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {
- if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
- device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
- break;
- }
- }
- LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
- device->id, name, propName, keylayoutFilename);
- }
- // 如果不知道这个device是啥类型,忽略之
- if (device->classes == 0) {
- ...
- }
- // 加到mDevicesById和mOpeningDevices中,回头getEvent()会处理mOpenningDevices链表中的新增device
- mDevicesById[devid].device = device;
- device->next = mOpeningDevices;
- mOpeningDevices = device;
- mDevices[mFDCount] = device;
- mFDCount++;
- return 0;
- }
- bool EventHub::getEvent(RawEvent* outEvent)
- {
- ....
- // main loop here - 主循环体
- for (;;) {
- // Report any devices that had last been removed. - 当有设备从系统中移除时
- if (mClosingDevices != NULL) {
- ...
- }
- // Report any devices that had last been added - 当有设备加入到系统中时
- 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; // 一个设备上报一个DEVICE_ADDED事件
- }
- // After finish scanning all input devices in system, send finished siganal at boot time
- if (mNeedToSendFinishedDeviceScan) {
- mNeedToSendFinishedDeviceScan = false;
- outEvent->type = FINISHED_DEVICE_SCAN;
- outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
- return true;
- }
- // 下面为普通event获取和上报过程
- ... ...
- }
- }
从上面的代码段可知,对于mOpeningDevices中的device,getEvent()调用都是每读取一个马上上报DEVICE_ADDED事件并返回。所以如果我们的系统中有一个keypad和一个touchscreen,则在扫描阶段就会有3次getEvent()返回:键盘的DEVICE_ADDED,触摸屏的DEVICE_ADDED和表示扫描完成的FINISHED_DEVICE_SCAN。
- android input system(frameworks) analysis -- InputManager (1)
- android input system(frameworks) analysis -- InputManager (1)
- android input system(frameworks) analysis -- InputManager (2)
- android input system(frameworks) analysis -- InputManager (2)
- android input system(frameworks) analysis -- InputManager
- android input 按键分发(inputManager)
- Android 4.2 Input Event事件处理流程<一>---inputManager启动
- Android JB 4.2 中InputManager 启动过程解析 -- 1
- Android Input System
- 实时数据分析Real-time data analysis frameworks (or stream system)
- Android Input Method Sample Code Analysis
- Android的Event Input System
- android frameworks
- Android Binder Analysis(1)
- Conditional Linking to System Frameworks
- android中的/system/bin/input工具
- android中的/system/bin/input工具
- Android事件输入系统(Input System)
- HDU 3555 我的第一道数位DP
- 6174问题
- hdu 1022
- poj 1753 Flip Game (bfs+bit位运算 ---好题!)
- 纸上谈兵: 拓扑排序强攻“科技树”
- android input system(frameworks) analysis -- InputManager (1)
- linux守护进程
- hive中UDF和UDAF使用说明
- linux进程关系
- 【读书笔记】Lucene+nutch搜索引擎开发
- Linux IP别名和多网卡绑定
- oracle数据库约束
- LeetCode-Jump Game II
- SQL Server 2012 不允许保存更改,您所做的更改要求删除并重新创建以下表