android input system(frameworks) analysis -- InputManager (1)


Inputシステムのframeworkレイヤでの解析は、デバイスノード/dev/input/input 0が存在し、geteventがタッチスクリーンの動作に応答できるため、EventHubとInputManagerのレイヤに問題を特定します.
InputManagerの構造は簡単で、外部に開放されています
    virtual status_t start();
    virtual status_t stop();
    virtual sp<InputReaderInterface> getReader();
    virtual sp<InputDispatcherInterface> getDispatcher();

プライベートメンバーを含む4つのメンバー関数
    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
}
InputManagerのstartは主にこの2つのスレッドを走らせます.
status_t InputManager::start() {
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
               ...
    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
               ...
    return OK;
}

====================================================================================================================
次にInputReaderを分析します.
InputReader Thread 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;
}

次にscanDir()に回ります.この関数は/dev/inputというディレクトリの各ファイルに対してopenDevice()を実行することにほかならません.後者は本当に働いています.
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'
", 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; }

初期化が振り回された後、getEventに戻り、getEventは最初にデバイスを追加する必要があるほか、その主体は大きなサイクルです.
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
", 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のデバイスに対してgetEvent()呼び出しは、読み込みごとにすぐにDEVICE_に報告されるADDEDイベントを返します.したがって、システムにkeypadとtouchscreenがある場合、スキャンフェーズでgetEvent()が3回返されます.キーボードのDEVICE_ADDED、タッチパネルのDEVICE_ADDEDとスキャン完了を示すFINISHED_DEVICE_SCAN.