InputManagerService源码分析二:初始化


前言

android系统服务很多实现都是在C端实现的,Input也不例外。Input系统java层主要类是InputManagerService, C层实现类为NativeInputManager。

其中NativeInputManager中有两个类:InputReader和InputDispatcher。InputReader故名思议,主要负责input事件的监听,也负责input设备的监听(添加、删除)。InputDispatcher主要负责输入事件的分发。


一、InputManagerService

InputManagerService是在系统进程system_process进程中创建的,SystemServer类是system_process启动后,从C++层调用创建的。InputManagerService是在SystemServer.java中startOtherServices()内创建的,代码如下所示(本章事例代码为Android 10,为了便于理解,本章节展示的均为精简后的代码)。

startOtherServices(){
  ...
  InputManagerService inputManager = null;
  WindowManagerService wm = null; 
  traceBeginAndSlog("StartInputManagerService");
  inputManager = new InputManagerService(context);
  ...
  wm = WindowManagerService.main(context, inputManager,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore, new PhoneWindowManager());
  ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
  ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
                    /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
  ...   
  inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
  inputManager.start();
}

从上图可以看出InputManagerService与WindowManagerService有不少联系,android事件分发主要是基于window的,window是WindowManagerService管理的,这就很容易理解了。这里暂不做赘述,后续章节会从功能、流程上介绍两者之间关系。
InputManagerServie构造方法如下所示:

public InputManagerService(Context context) {
        this.mContext = context;
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
        LocalServices.addService(InputManagerInternal.class, new LocalService());
    }
private static native long nativeInit(InputManagerService service,
            Context context, MessageQueue messageQueue);

可以看出nativeInit()方法是一个native方法。我们接着看下native层的实现。

二、NativeInputManager

native层nativeinit()方法代码如下:

static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == nullptr) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }

    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}

从代码可以看出C++层创建了一个NativeInputManager实例。NativeInputManager类声明如下,我们截取部分代码。

class NativeInputManager : public virtual RefBase,
    public virtual InputReaderPolicyInterface,
    public virtual InputDispatcherPolicyInterface,
    public virtual PointerControllerPolicyInterface {
    void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray, int32_t displayId);
    void setFocusedApplication(JNIEnv* env, int32_t displayId, jobject applicationHandleObj);
    virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
            const sp<IBinder>& token,
            const std::string& reason);
    virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
    
    }

可以猜测NativeInputManager的部分功能包括:焦点变更Input层处理、ANR识别、按键前处理等。接下来我们分析下NativeInputManager。
NativeInputManager初始化代码如下所示,可以看出在NativeInputManager内部创建了一个InputManager实例,并把它添加到ServiceManager中,可以看出InputManager是一个C层的BinderService。接下来我们看一下InputManager的创建。

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();

    mServiceObj = env->NewGlobalRef(serviceObj);
    ...
    mInputManager = new InputManager(this, this);
    defaultServiceManager()->addService(String16("inputflinger"),
            mInputManager, false);
}

2.1 InputManager

InputManager的头文件和Cpp文件的目录frameworks\native\services\inputflinger。
InputManager类申明如下:

frameworks\native\services\inputflinger\InputManager.cpp
class InputManager : public InputManagerInterface, public BnInputFlinger {
protected:
    virtual ~InputManager();
public:
    InputManager(
            const sp<InputReaderPolicyInterface>& readerPolicy,
            const sp<InputDispatcherPolicyInterface>& dispatcherPolicy);
    virtual status_t start();
    virtual status_t stop();
    virtual sp<InputReaderInterface> getReader();
    virtual sp<InputClassifierInterface> getClassifier();
    virtual sp<InputDispatcherInterface> getDispatcher();
    virtual void setInputWindows(const std::vector<InputWindowInfo>& handles,
            const sp<ISetInputWindowsListener>& setInputWindowsListener);
    virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
    virtual void registerInputChannel(const sp<InputChannel>& channel);
    virtual void unregisterInputChannel(const sp<InputChannel>& channel);
private:
    sp<InputReaderInterface> mReader;
    sp<InputReaderThread> mReaderThread;
    sp<InputClassifierInterface> mClassifier;
    sp<InputDispatcherInterface> mDispatcher;
    sp<InputDispatcherThread> mDispatcher;
    void initialize();
};

我们可以看出
1)InputManager继承了BnInputFlinger ,可以看出他的确是一个Binder服务。后续章节我们会结合Surface系统,通过一个简单的程序,可以更加清晰的理解这两个系统。
2)InputManager内部成员变量属性 InputReaderInterfaceInputReaderThreadInputDispatcherInterfaceInputDispatcherThread。他们 是Input系统的工作类和工作线程。下面我会详细的介绍这几个类。为了便于理解本章暂不介绍mClassifier

2.1.1 InputReader、InputDispatcher创建

从InputManager的构造函数,可以看出它内部创建了InputReader、InputDispatcher。创建InputReader构造方法中有一个形参EventHub,它负责监听外部设备的挂载、删除和输入设备输入监听。

frameworks\native\services\inputflinger\InputManager.cpp
InputManager::InputManager(
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    mClassifier = new InputClassifier(mDispatcher);
    mReader = createInputReader(readerPolicy, mClassifier);
    initialize();
}

frameworks\native\services\inputflinger\InputReaderFactory.cpp
sp<InputReaderInterface> createInputReader(
        const sp<InputReaderPolicyInterface>& policy,
        const sp<InputListenerInterface>& listener) {
    return new InputReader(new EventHub(), policy, listener);
}

2.1.2 InputReaderThread、InputReaderThread线程创建

InputManager工作线程mReaderThread、mDispatcherThread是在InputManager构造方法中创建,如下代码所示。

frameworks\native\services\inputflinger\InputManager.cpp
void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputReaderThread(mDispatcher);
}

InputReaderThread实现代码如下:

frameworks\native\services\inputflinger\include\InputReaderBase.h
class InputReaderThread : public Thread {
public:
    explicit InputReaderThread(const sp<InputReaderInterface>& reader);
    virtual ~InputReaderThread();

private:
    sp<InputReaderInterface> mReader;

    virtual bool threadLoop();
};

frameworks\native\services\inputflinger\InputReaderBase.cpp
bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}

InputDispatcherThread实现代码如下:

frameworks\native\services\inputflinger\InputDispatcher.h
class InputDispatcherThread : public Thread {
public:
    explicit InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher);
    ~InputDispatcherThread();

private:
    virtual bool threadLoop();

    sp<InputDispatcherInterface> mDispatcher;
}

frameworks\native\services\inputflinger\InputDispatcher.cpp
bool InputDispatcherThread::threadLoop() {
    mDispatcher->dispatchOnce();
    return true;
}

InputReaderThread 和InputDispatcherThread都继承自android自定义Thread,threadLoop中返回true,代表着他们方法结束了会继续执行,即轮询。

2.1.3 InputReaderThread、InputReaderThread线程启动

上一节介绍了Input C层工作线程的创建,下面介绍工作线程的启动。
Setp 1: SystemServer中调用inputManager.start():
Setp 2: InputManagerService中调用native方法nativeStart()进入native层:

frameworks\base\services\java\com\android\server\SystemServer.java
startOtherServices(){
  ...
  inputManager.start();
  ...
}
frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
 public void start() {
        Slog.i(TAG, "Starting input manager");
        nativeStart(mPtr);
        ....
 }

Setp 3: C层获取InputManager实例,调用start()方法:
Setp 4: InputManager中开启read和dispatcher线程,进入循环。

frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}
frameworks\native\services\inputflinger\InputManager.cpp
status_t InputManager::start() {
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    if (result) {
        ALOGE("Could not start InputDispatcher thread due to error %d.", result);
        return result;
    }

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

        mDispatcherThread->requestExit();
        return result;
    }

    return OK;
}

2.1.4 InputManagerService初始化时序图

InputManagerService初始化流程

2.2 EventHub

上一节介绍InputReader构造方法的时候,提及了EventHub。这一节我们介绍EventHub。EventHub,可以翻译成事件中心。之所以把EventHub单独成一小节介绍,主要是EventHub在Input系统中起着至关重要的作用。它的主要职责就是:
1)输入设备的添加、删除。
2)输入设备的监听。

2.2.1 EventHub若干方法

Eventhub的头文件和cpp文件在目录frameworks\native\services\inputflinger\下。EventHub.h部分代码如下:

class EventHub : public EventHubInterface
{
public:
    EventHub();

    virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize);
    virtual void monitor();

protected:
    virtual ~EventHub();

private:
    struct Device {
        Device* next;

        int fd; // may be -1 if device is closed
        const int32_t id;
        const std::string path;
        const InputDeviceIdentifier identifier;
        uint32_t classes;
  
        Device(int fd, int32_t id, const std::string& path,
                const InputDeviceIdentifier& identifier);
        ~Device();

        void close();
        status_t enable();
        status_t disable();
    };

    status_t openDeviceLocked(const char* devicePath);
  
    void addDeviceLocked(Device* device);
    void configureFd(Device* device);
  
    status_t registerFdForEpoll(int fd);
    status_t unregisterFdFromEpoll(int fd);

    status_t scanDirLocked(const char *dirname);
    void scanDevicesLocked();
    status_t readNotifyLocked();


    // Protect all internal state.
    mutable Mutex mLock;;

    int mEpollFd;
    int mINotifyFd;
    int mWakeReadPipeFd;
    int mWakeWritePipeFd;

    int mInputWd;
};

这里简要介绍几个方法,后面会详细介绍各个方法:
1)getEvents(): 主要是做事件识别;
2)processEventsLocked():主要是做事件处理;
2 ) scanDirLocked():检索/dev/input目录下的挂载输入设备,系统初始化的时候读取后,将输入设备封装成Device,存储在EventHub中;
3) readNotifyLocked():设备添加、删除后的处理方法,接受到iNotify事件后调用的方法。主要是做新挂载、删除设备的监听与删除;
4)processEventsForDeviceLocked():输入设备操作数据处理类,下一章事件分发的时候我们再来分析这个类。

2.2.2 EventHub初始化

这一节我们阅读EventHub的构造方法,代码如下:

EventHub::EventHub(void) :
        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
        mOpeningDevices(nullptr), mClosingDevices(nullptr),
        mNeedToSendFinishedDeviceScan(false),
        mNeedToReopenDevices(false), mNeedToScanDevices(true),
        mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

    mEpollFd = epoll_create1(EPOLL_CLOEXEC);
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
    
    mINotifyFd = inotify_init();
    mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
    LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s",
            DEVICE_PATH, strerror(errno));
    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
    eventItem.data.fd = mINotifyFd;
    //添加文件创建、删除监听
    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance.  errno=%d", errno);
     ...
}

上面的代码主要是实现了挂载设备的监听、和Looper的唤醒,使用了Linux epoll和iNotify机制。对这两种机制不了解的,可以看下我之前的博客InputManagerService源码分析一

2.3 InputReader

InputManager开启工作线程后,InputReaderThread进入轮询,从上节可以知道InputReaderThread会调用InputReader的loopOnce方法。

2.3.1 loopOnce方法

InputReader的loopOnce()方法代码如下。

void InputReader::loopOnce() {
    ...
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
    ...
    { // acquire lock
        AutoMutex _l(mLock);
        if (count) {
            processEventsLocked(mEventBuffer, count);
        }
    } // release lock
    ...
 }

其中有两个关键方法
1)getEvents() :读取事件、封装事件 。
2)processEventsLocked():处理事件。

2.3.2 事件处理

这一章我们分析Input系统的事件读取处理流程。事件读取的部分代码如下所示。

frameworks\native\services\inputflinger\EventHub.cpp
size_t EventHub::getEvents(int timeoutMills,RawEvent* buffer,size_t bufferSize)
 for (;;) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

        //流程一:设备检索,开始
        if (mNeedToScanDevices) {
            mNeedToScanDevices = false;
            scanDevicesLocked();
            mNeedToSendFinishedDeviceScan = true;
        }

        while (mOpeningDevices != nullptr) {
            Device* device = mOpeningDevices;
            ALOGV("Reporting device opened: id=%d, name=%s\n",
                 device->id, device->path.c_str());
            mOpeningDevices = device->next;
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            event->type = DEVICE_ADDED;
            event += 1;
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) {
                break;
            }
        }

        if (mNeedToSendFinishedDeviceScan) {
            mNeedToSendFinishedDeviceScan = false;
            event->when = now;
            event->type = FINISHED_DEVICE_SCAN;
            event += 1;
            if (--capacity == 0) {
                break;
            }
        }
        //流程一:设备检索结束
        // Grab the next input event.
        bool deviceChanged = false;
        while (mPendingEventIndex < mPendingEventCount) {
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            //流程二,输入设备添加删除
            if (eventItem.data.fd == mINotifyFd) {
                if (eventItem.events & EPOLLIN) {
                    mPendingINotify = true;
                } else {
                    ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
                }
                continue;
            }
  
            Device* device = getDeviceByFdLocked(eventItem.data.fd);
            if (!device) {
                ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.",
                        eventItem.events, eventItem.data.fd);
                ALOG_ASSERT(!DEBUG);
                continue;
            }

            // This must be an input event
            //流程三:输入设备输入事件
            if (eventItem.events & EPOLLIN) {
                int32_t readSize = read(device->fd, readBuffer,
                        sizeof(struct input_event) * capacity);
                if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
                    // Device was removed before INotify noticed.
                    ALOGW("could not get event, removed? (fd: %d size: %" PRId32
                            " bufferSize: %zu capacity: %zu errno: %d)\n",
                            device->fd, readSize, bufferSize, capacity, errno);
                    deviceChanged = true;
                    closeDeviceLocked(device);
                } else if (readSize < 0) {
                    if (errno != EAGAIN && errno != EINTR) {
                        ALOGW("could not get event (errno=%d)", errno);
                    }
                } else if ((readSize % sizeof(struct input_event)) != 0) {
                    ALOGE("could not get event (wrong size: %d)", readSize);
                } else {
                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;

                    size_t count = size_t(readSize) / sizeof(struct input_event);
                    for (size_t i = 0; i < count; i++) {
                        struct input_event& iev = readBuffer[i];
                        event->when = processEventTimestamp(iev);
                        event->deviceId = deviceId;
                        event->type = iev.type;
                        event->code = iev.code;
                        event->value = iev.value;
                        event += 1;
                        capacity -= 1;
                    }
                    if (capacity == 0) {
                        // The result buffer is full.  Reset the pending event index
                        // so we will try to read the device again on the next iteration.
                        mPendingEventIndex -= 1;
                        break;
                    }
                }
            } else if (eventItem.events & EPOLLHUP) {
                ALOGI("Removing device %s due to epoll hang-up event.",
                        device->identifier.name.c_str());
                deviceChanged = true;
                closeDeviceLocked(device);
            } else {
                ALOGW("Received unexpected epoll event 0x%08x for device %s.",
                        eventItem.events, device->identifier.name.c_str());
            }
        }

        // readNotify() will modify the list of devices so this must be done after
        // processing all other events to ensure that we read all remaining events
        // before closing the devices.
        if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
            mPendingINotify = false;
            readNotifyLocked();
            deviceChanged = true;
        }

        // Report added or removed devices immediately.
        if (deviceChanged) {
            continue;
        }

        // Return now if we have collected any events or if we were explicitly awoken.
        if (event != buffer || awoken) {
            break;
        }
        
        mPendingEventIndex = 0;

        mLock.unlock(); // release lock before poll, must be before release_wake_lock
        release_wake_lock(WAKE_LOCK_ID);

        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);

        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
        mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock

        if (pollResult == 0) {
            // Timed out.
            mPendingEventCount = 0;
            break;
        }

        if (pollResult < 0) {
            // An error occurred.
            mPendingEventCount = 0;

            // Sleep after errors to avoid locking up the system.
            // Hopefully the error is transient.
            if (errno != EINTR) {
                ALOGW("poll failed (errno=%d)\n", errno);
                usleep(100000);
            }
        } else {
            // Some events occurred.
            mPendingEventCount = size_t(pollResult);
        }
    }

    // All done, return the number of events we read.
    return event - buffer;
}

代码中我们标注了三种事件流程:流程一:设备检索流程; 流程二:设备添加、删除流程; 流程三:输入设备输入事件。接下来我们介绍下这三种不同的事件处理了流程。

2.3.2.1 设备检索

我们首先看下流程一的第一部分代码:

frameworks\native\services\inputflinger\EventHub.cpp
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
  ...
   for (;;) {
        ...
		if (mNeedToScanDevices) {
		      mNeedToScanDevices = false;
		      scanDevicesLocked();
		      mNeedToSendFinishedDeviceScan = true;
		}
 }

从代码中可以看出mNeedToScanDevices为true时,会进入设备检索流程。mNeedToScanDevices在构造方法中设置为ture;所以线程启动后必然会调用检索设备流程。

frameworks\native\services\inputflinger\EventHub.cpp
EventHub::EventHub(void) :
        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
        mOpeningDevices(nullptr), mClosingDevices(nullptr),
        mNeedToSendFinishedDeviceScan(false),
        mNeedToReopenDevices(false), mNeedToScanDevices(true),
        mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false)

**step 1:**遍历/dev/input下的挂载文件:

frameworks\native\services\inputflinger\EventHub.cpp
//scanDevicesLocked方法最终调用scanDirLocked方法检索input目录
status_t EventHub::scanDirLocked(const char *dirname)
{
    char devname[PATH_MAX];
    char *filename;
    DIR *dir;
    struct dirent *de;
    dir = opendir(dirname);
    if(dir == nullptr)
        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);
        openDeviceLocked(devname);
    }
    closedir(dir);
    return 0;
}

step 2: 读取、分析挂载设备信息,将数据封成Device,存储在EventHub中。因为这个过程涉及代码量比较大,我们这边截取部分关键代码,帮助我们分析这个流程。
1)读取设备信息封装成identifier,封装成Device对象:

frameworks\native\services\inputflinger\EventHub.cpp
status_t EventHub::openDeviceLocked(const char* devicePath) {
    //获取检索到的挂载设备句柄
    int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);
   ...
	InputDeviceIdentifier identifier;
	...
	// Get device name.
	if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
	    ALOGE("Could not get device name for %s: %s", devicePath, strerror(errno));
	} else {
	    buffer[sizeof(buffer) - 1] = '\0';
	    identifier.name = buffer;
	}
	...
	if(ioctl(fd, EVIOCGID, &inputId)) {
	    ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
	    close(fd);
	    return -1;
	}
	identifier.bus = inputId.bustype;
	identifier.product = inputId.product;
	identifier.vendor = inputId.vendor;
	identifier.version = inputId.version;
	Device* device = new Device(fd, deviceId, devicePath, identifier);
	...
}

2)通过ioctl(fd, EVIOCGBIT(0, EV_MAX), buf),获取设备支持哪些事件(EV_KEY、EV_REL和EV_ABS等):

frameworks\native\services\inputflinger\EventHub.cpp
status_t EventHub::openDeviceLocked(const char* devicePath) {
   ...
	ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);
	ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);
	ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
	ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
	ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
	ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);
	ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
}

3)设备掩码分析,判断设备支持哪些类型:
根据absBitmask判断设备是否支持屏幕输入。Device的成员变量classes 比较重要,后续介绍processEventsLocked方法的时候会介绍。其他设备的判断这里暂不做介绍。

frameworks\native\services\inputflinger\EventHub.cpp
status_t EventHub::openDeviceLocked(const char* devicePath) {
   ...
	if (test_bit(ABS_MT_POSITION_X, device->absBitmask)
	            && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {
	        // Some joysticks such as the PS3 controller report axes that conflict
	        // with the ABS_MT range.  Try to confirm that the device really is
	        // a touch screen.
	        if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) {
	            device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
	        }
	    // Is this an old style single-touch driver?
	    }
	...
}

4)挂载设备监听:
registerFdForEpoll方法内通过epoll_ctl方法将文件fd添加到mEpollFd监听。

frameworks\native\services\inputflinger\EventHub.cpp
status_t EventHub::openDeviceLocked(const char* devicePath) {
...
	if (registerDeviceForEpollLocked(device) != OK) {
	       delete device;
	       return -1;
	}
...
}
//registerDeviceForEpollLocked方法最终调用了registerFdForEpoll方法
status_t EventHub::registerFdForEpoll(int fd) {
    // TODO(b/121395353) - consider adding EPOLLRDHUP
    struct epoll_event eventItem = {};
    eventItem.events = EPOLLIN | EPOLLWAKEUP;
    eventItem.data.fd = fd;
    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
        ALOGE("Could not add fd to epoll instance: %s", strerror(errno));
        return -errno;
    }
    return OK;
}

5 )将封装的Device实例,保存到EventHub中,并将device赋值给mOpeningDevice。这样做的目的是为了将数据封装成RawEvent(Setp 3),为了后续的事件处理。

frameworks\native\services\inputflinger\EventHub.cpp
void EventHub::addDeviceLocked(Device* device) {
    mDevices.add(device->id, device);
    device->next = mOpeningDevices;
    mOpeningDevices = device;
}

step 3: 将封装后Device数据转换成RawEvent数据,代码如下:

frameworks\native\services\inputflinger\EventHub.cpp
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
	while (mOpeningDevices != nullptr) {
	            Device* device = mOpeningDevices;
	            ALOGV("Reporting device opened: id=%d, name=%s\n",
	                 device->id, device->path.c_str());
	            mOpeningDevices = device->next;
	            event->when = now;
	            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
	            event->type = DEVICE_ADDED;
	            event += 1;
	            mNeedToSendFinishedDeviceScan = true;
	            if (--capacity == 0) {
	                break;
	            }
	 }
	
     if (mNeedToSendFinishedDeviceScan) {
         mNeedToSendFinishedDeviceScan = false;
         event->when = now;
         event->type = FINISHED_DEVICE_SCAN;
         event += 1;
         if (--capacity == 0) {
             break;
         }
     }	     
     ...
}

留意下event的成员变量type,后续step 5会以type为依据执行不同的操作。
step 5: 事件分析(判断、处理):

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    for (const RawEvent* rawEvent = rawEvents; count;) {
        int32_t type = rawEvent->type;
        size_t batchSize = 1;
        //输入设备事件,在后面一章会做分析
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
            int32_t deviceId = rawEvent->deviceId;
            while (batchSize < count) {
                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
                        || rawEvent[batchSize].deviceId != deviceId) {
                    break;
                }
                batchSize += 1;
            }
#if DEBUG_RAW_EVENTS
            ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {
            switch (rawEvent->type) {
            //设备添加
            case EventHubInterface::DEVICE_ADDED:
                addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            //设备删除
            case EventHubInterface::DEVICE_REMOVED:
                removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            设备检索完成
            case EventHubInterface::FINISHED_DEVICE_SCAN:
                handleConfigurationChangedLocked(rawEvent->when);
                break;
            default:
                ALOG_ASSERT(false); // can't happen
                break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}

Step 6: 封装输入设备处理实体InputDevice,将其存储在InputReader中。
本章暂不分析removeDeviceLocked,他的处理逻辑可以参照设备添加逻辑。这里用到了classes这个类型,这里可以看出根据不同的类型,创建了各种映射对象。下一章事件分发我们会详细的介绍各个Mapper的实现。

frameworks\native\services\inputflinger\InputReader.cpp
//addDeviceLocked内部的主要方法为createDeviceLocked
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
        const InputDeviceIdentifier& identifier, uint32_t classes) {
    InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
            controllerNumber, identifier, classes);
    ...

    // Switch-like devices.
    if (classes & INPUT_DEVICE_CLASS_SWITCH) {
        device->addMapper(new SwitchInputMapper(device));
    }
    ...
    // Keyboard-like devices.
    uint32_t keyboardSource = 0;
    ...

    if (keyboardSource != 0) {
        device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
    }
    ...
    // Touchscreens and touchpad devices.
    if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
        device->addMapper(new MultiTouchInputMapper(device));
    } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
        device->addMapper(new SingleTouchInputMapper(device));
    }

    return device;
}

设备检索流程图如下所示:
设备检索

2.3.2.2 设备添加、删除

有了上一节分析设备检索的基础,分析设备删除就会显得比较简单。添加与删除与检索不同之处在于:输入源不同。检索的数据源是通过遍历目录获取的,添加与删除的数据源是通过epoll获取到的。
我们可以分 三步分析它:代码中可以标注了它们的位置
Step 1:事件读取;
Step 2:事件识别;
Step 3:事件处理。

frameworks\native\services\inputflinger\EventHub.cpp
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
   ...
    for (;;) {
       ...
        while (mPendingEventIndex < mPendingEventCount) {
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            //Step 2 添加、删除事件识别
            if (eventItem.data.fd == mINotifyFd) {
                if (eventItem.events & EPOLLIN) {
                    mPendingINotify = true;
                } else {
                    ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
                }
                continue;
            }

            ...

        //Step 3 添加、删除事件处理
        if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
            mPendingINotify = false;
            readNotifyLocked();
            deviceChanged = true;
        }
        ...
        //Step 1 添加、删除事件读取
        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
    }
    ...
}
status_t EventHub::readNotifyLocked() {
    int res;
    char event_buf[512];
    int event_size;
    int event_pos = 0;
    struct inotify_event *event;

    ALOGV("EventHub::readNotify nfd: %d\n", mINotifyFd);
    //读取inotify fd中数据
    res = read(mINotifyFd, event_buf, sizeof(event_buf));
   ...

    while(res >= (int)sizeof(*event)) {
        event = (struct inotify_event *)(event_buf + event_pos);
        if(event->len) {
            if (event->wd == mInputWd) {
               //挂载、删除设备名称拼接
                std::string filename = StringPrintf("%s/%s", DEVICE_PATH, event->name);
                if(event->mask & IN_CREATE) {
                     //添加设备处理:解析、监听
                    openDeviceLocked(filename.c_str());
                } else {
                    ALOGI("Removing device '%s' due to inotify event\n", filename.c_str());
                    //删除设备事件处理
                    closeDeviceByPathLocked(filename.c_str());
                }
            }
            ...
        }
        event_size = sizeof(*event) + event->len;
        res -= event_size;
        event_pos += event_size;
    }
    return 0;
}

readNotifyLocked会根据事件类型对设备进行两种操作:
1)事件类型为创建:调用openDeviceLocked进行设备的解析与监听(详见2.3.2.1 Step1);
2)事件类型为非创建:做设备删除操作(删除EventHub中对应的Device对象,移除设备文件监听,这里暂不分析)。
后续流程可以参考2.3.2.1。添加、删除事件处理流程图如下所示。
设备添加删除

2.3.2.3 设备输入数据

设备输入事件的分析我们在下一章,InputManagerService事件分发中介绍。

2.4 InputDispatcher

事件分发在下一章,InputManagerService事件分发中介绍。

总结

InputManagerService的初始化工作到这里就介绍完毕了,下一节我们介绍InputManagerService事件的分发。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值