android学习笔记6 eventhub

来源:互联网 发布:淘宝刷流量 猎流 编辑:程序博客网 时间:2024/04/30 03:21

Eventhub是在Native 的inputmanager创建的时候被创建的,inputreadthread就通过eventhub的getevent方法来源源不断的获取driver上报的input事件。

 

 

bool EventHub::getEvent(RawEvent* outEvent)

{

 

   if (!mOpened) {

       mError = openPlatformInput() ? NO_ERROR :UNKNOWN_ERROR;

       mOpened = true;

       mNeedToSendFinishedDeviceScan = true;

}

//省略

如果是第一次进入getevent,则会去调用openplatforminput来获取input设备,加载对应的kl,将device加入eventhub的特定的结构体中。

 

bool EventHub::openPlatformInput(void)

{

 

 //省略

   res = scanDir(device_path);

   if(res < 0) {

       LOGE("scan dir failed for %s\n", device_path);

    }

 

   return true;

}

直接调用scandir来处理/dev/input/文件夹

int EventHub::scanDir(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);

       openDevice(devname);

    }

   closedir(dir);

   return 0;

}

通过readdir来得到子文件的名字,拼成完整的设备路径后调用opendevice来打开他,如/dev/input/event0 (可以在adb shell进入手机后cd/dev/inputls下,就可以看到了)

 

int EventHub::openDevice(const char*deviceName) {

 //省略,主要是将新发现的设备增加到mDevicesByIdmFDs数组中。

//接下来是对设备类型的判断,我们以键盘为例:

   LOGV("Getting keys...");

   if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >=0) {

       //LOGI("MAP\n");

       //for (int i = 0; i < sizeof(key_bitmask); i++) {

       //    LOGI("%d:0x%02x\n", i, key_bitmask[i]);

       //}

 

       // See if this is a keyboard.  Ignoreeverything in the button range except for

       // gamepads which are also considered keyboards.

       if (containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC))

                ||containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_GAMEPAD),

                       sizeof_bit_array(BTN_DIGI))

                ||containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK),

                       sizeof_bit_array(KEY_MAX + 1))) {

           device->classes |=INPUT_DEVICE_CLASS_KEYBOARD;

 

            device->keyBitmask = newuint8_t[sizeof(key_bitmask)];

           if (device->keyBitmask != NULL) {

                memcpy(device->keyBitmask,key_bitmask, sizeof(key_bitmask));

           } else {

                delete device;

                LOGE("out of memory allocating keybitmask");

                return -1;

           }

       }

    }

//具体的ioctl还没搞明白,从字面意思上看,就是判断当前设备是否是键盘,如果是则将其类型或上INPUT_DEVICE_CLASS_KEYBOARD

//其他的设备的处理也很类似,接下来是加载kl

 

 

if((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {

//如果是键盘

       char tmpfn[sizeof(name)];

       char keylayoutFilename[300];

 

       // a more descriptive name

       device->name = name;

 

       // replace all the spaces with underscores

       strcpy(tmpfn, name);

       for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ''))

           *p = '_';

 

       // find the .kl file we need for this device

       const char* root = getenv("ANDROID_ROOT");

      //此处的root即是/system/

       snprintf(keylayoutFilename, sizeof(keylayoutFilename),

                "%s/usr/keylayout/%s.kl", root, tmpfn);

       bool defaultKeymap = false;

       if (access(keylayoutFilename, R_OK)) {

           snprintf(keylayoutFilename, sizeof(keylayoutFilename),

                     "%s/usr/keylayout/%s",root, "qwerty.kl");

           defaultKeymap = true;

       }

       status_t status = device->layoutMap->load(keylayoutFilename);

       if (status) {

           LOGE("Error %d loading key layout.", status);

       }

   device->next = mOpeningDevices;

mOpeningDevices = device;

    mDevices[mFDCount] = device

    mFDCount++;

      //首先尝试去查找是否存在特定的keylayoutfile,如我们的键盘对应的kl应该是:

       /system/usr/keylayout/sprd-keypad.kl

      如果kl不存在,则尝试去打开默认的kl,即qwerty.kl,然后加载对应的kl

//如果加载成功,则通知大家设备名(将hw.keyboards.0.devname赋值为对应的设备名,如sprd-keypad),并将其声明为mOpeningDevices到这里,一个input设备就打开成功可以为eventhub所用了。

接下来我们看下keylayoutMapLoad函数来了解下kl文件的解析。

Kl文件也比较简单,截取一部分:

Key  116     POWER             WAKE

Key是起始标志, 116是硬件扫描码,POWER是对应的KEYCODEWAKE是按键对应的FLAG

 

KeyLayoutMap::load(const char* filename){

//省略无关。

 

 

enum { BEGIN,SCANCODE, KEYCODE, FLAG } state = BEGIN;

//state初始为BEGIN

   while (true) {

       String8 token = next_token(&p, &line);

       if (*p == '\0') {

           break;

       }

       switch (state)

       {

           case BEGIN:

                if (token == "key") {

                    state = SCANCODE;

                   //如果读取到key,状态置为SCANCODE

                } else {

                    LOGE("%s:%d: expectedkey, got '%s'\n", filename, line,

                            token.string());

                    err = BAD_VALUE;

                    goto done;

                }

                break;

           case SCANCODE:

                scancode = strtol(token.string(),&end, 0);

                if (*end != '\0') {

                    LOGE("%s:%d: expectedscancode (a number), got '%s'\n",

                            filename, line,token.string());

                    goto done;

                }

                //LOGI("%s:%d: gotscancode %d\n", filename, line, scancode );

//

                state = KEYCODE;

                //读取扫描码成功后继续读取keycode

                break;

           case KEYCODE:

                keycode =token_to_value(token.string(), KEYCODES);

                //通过在KEYCODES中查找得到对应的按键码,如POWER

               staticconst KeycodeLabel KEYCODES[] = {

    {"SOFT_LEFT", 1 },

    {"SOFT_RIGHT", 2 },

    {"HOME", 3 },

{"BACK", 4 },

    { "POWER", 26 },

}对应的是KEYCODE_POWER

此处的keycode就是上层的使用的keycode。通过kl,就将硬件扫描码转换成了keycode

                //LOGI("%s:%d: got keycode%d for %s\n", filename, line, keycode, token.string() );

                if (keycode == 0) {

                    LOGE("%s:%d: expectedkeycode, got '%s'\n",

                            filename, line,token.string());

                    goto done;

                }

                state = FLAG;

                break;

           case FLAG:

                if (token == "key") {

                    if (scancode != -1) {

                        //LOGI("got keydecl scancode=%d keycode=%d"

                        //       " flags=0x%08x\n", scancode,keycode, flags);

                        Key k = { keycode,flags };

                        m_keys.add(scancode,k);

                        state = SCANCODE;

                        scancode = -1;

                        keycode = -1;

                        flags = 0;

                        break;

                    }

                }

                tmp = token_to_value(token.string(),FLAGS);

                  //类似的,查FLAGS数组,找到对应的FLAGS

static const KeycodeLabel FLAGS[] = {

{"WAKE", 0x00000001 },

WAKE,就是0x00000001,对应的是    POLICY_FLAG_WAKE =0x00000001,input.h

                //LOGI("%s:%d: got flags%x for %s\n", filename, line, tmp, token.string() );

                if (tmp == 0) {

                    LOGE("%s:%d: expectedflag, got '%s'\n",

                            filename, line,token.string());

                    goto done;

                }

               flags |= tmp;

                break;

       }

    }

   if (state == FLAG && scancode != -1 ) {

       //LOGI("got key decl scancode=%d keycode=%d"

       //       "flags=0x%08x\n", scancode, keycode, flags);

       Key k = { keycode, flags };

        m_keys.add(scancode, k);

}

done:

    free(buf);

    close(fd);

 

    m_status = err;

    return err;

}

这样,对应的keycode scancodeflag,都保存在了m_keys中。

接下来继续看getevent:这个神一样的函数

boolEventHub::getEvent(RawEvent* outEvent)

{  

 

    if (!mOpened) {

        mError = openPlatformInput() ? NO_ERROR: UNKNOWN_ERROR;

        mOpened = true;

        mNeedToSendFinishedDeviceScan = true;

     //如果发现了新设备,mNeedToSendFinishedDeviceScan被置为true,在下面会用到

    }

 for (;;) {

        // Report any devices that had lastbeen added/removed.

        if (mClosingDevices != NULL) {

        //closeDevice函数中被赋值,如果有设备需要关闭,则会走进来,返回一个DEVICE_REMOVED事件。

            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) {

 // 在上文中的opendevice中的末尾,会将其置为对应的device,也就是说如果发现了新设备,会返回一个DEVICE_ADDED的事件。在inputreader中会处理

            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) {

//ADD完成设备后,会发出一个FINISHD_DEVICE_SCAN,标志着所有的input设备都已经SCAN完成。

            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) {

               //如果当前存在需要处理的按键事件,则通过map返回对应的outevent

                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;

                   //keypad的设备id0

                } 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);

                    //将扫描码转换成按键码,并给出按键的flag

                    通过对应devicelayoutMap中的m_keys中存储的信息(上文中的load中可以看到),返回对应的按键码,FLAG

                    LOGV("iev.code=%dkeyCode=%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 inthe 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;

            }

// 如果读取完了所有存在buffer里的按键事件,或者因为设备刚初始化,不存在等待读取的按键事件,则去读。

            mInputDeviceIndex += 1;

            if (mInputDeviceIndex >= mFDCount) {

                break;

            }

 

            const struct pollfd& pfd =mFDs[mInputDeviceIndex];

            if (pfd.revents & POLLIN) {

                int32_t readSize = read(pfd.fd, mInputBufferData,

                        sizeof(structinput_event) * INPUT_BUFFER_SIZE);

                if (readSize < 0) {

                    if (errno != EAGAIN&& errno != EINTR) {

                        LOGW("could notget event (errno=%d)", errno);

                    }

                } else if ((readSize %sizeof(struct input_event)) != 0) {

                    LOGE("could not getevent (wrong size: %d)", readSize);

                } else {

                    mInputBufferCountreadSize / sizeof(struct input_event);

                 //input事件存到buffer中,并计算出count,且将index赋值为0

                    mInputBufferIndex = 0;

                }

            }

这样,inputreadthread不停的调用getevent,不停的可以获取到当前的input事件,并上报处理。

Eventhub的部分就看到这里,下一篇看kernel和上层是怎么对应上的。