connglli / blog-notes

My personal notes ✍️
MIT License
32 stars 2 forks source link

IMS: Input Manager Service #54

Open connglli opened 4 years ago

connglli commented 4 years ago

Input System

Android is an event-driven system, so goals and tasks of the input system is

  1. WATCH task: watch meta events (e.g., x, y, gps) comming from environment (system, user, or sensors),
  2. PARSE task: parses these meta events to RawEvent with type and arguments, and,
  3. DISPATCH task: convert the typed RawEvent to specific typed DispatchEntry, and then dispatches them to correct connections (event consumers)

Work of the input system is a result of cooperations coming from the lower-lever device/kernel, to higher-level framework; and components involved in this process include:

ims

Above figure shows the relationship of these components.

One can see the overall link that the touch experienced is

Driver -> Kernel -> IMS(InputReader -> InputDispatcher) -> WMS -> ViewRootImpl

References

Start Process

IMS is created as an other server of system server, while creating (ims = InputManagerService()),

After created, IMS is started (ims.start()),

As one can see, there are at least 2 process and 4 threads that are involed in input system:

InputReader

InputReader is a component and a thread that connects top to InputDispatcher and bottom to EventHub; InputReader works like the following pseudo-code

while (true) {
  RawEvent next = mEventHub.getEventsOrBlock();
  switch (next.type) {
    case Motion: mDispatcher.notifyMotion(toNotifyMotionArgs.fromRawEvent(next)); break;
    case Key: mDispatcher.notifyKey(toNotifyKeyArgs.fromRawEvent(next)); break;
    ...
  }
}

EventHub

Actually there are at least 3 events that need to be watched:

Since each device has a device file under /dev/input/, the addition and deletion of devices can be told by file creation and deletion. And thereby EventHub enforces the inotify mechanism of linux of watch such event

Since events happended on devices can be told by content changes of their files, EventHub opens the device files and wait for their changes

For better performance, EventHub then enforces epoll on all of them, specifically,

For better performance a further step, the devices ain't opened until the first EventHub#getEvents() is invoked

The following pseudo-code shows the workflow of EventHub

EventHub() : mEpollFd(epoll_create(EPOLL_SIZE_HINT)) {
  // register inotify
  mINotifyFd = inotify_init();
  inotify_add_watch(mINotifyFd, "/dev/input/", IN_DELETE | IN_CREATE);

  // add to mEpollFd
  struct epoll_event eventItem;
  memset(eventItem, 0, sizeof(eventItem));
  eventItem.events = EPOLLIN;
  eventItem.data.u32 = EPOLL_ID_INOTIFY;
  epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
}

RawEvent* getEvents() {
  if (!mDevicesOpened) {
    DIR* dir = opendir("/dev/input");
    struct dirent *de = NULL;
    while((de = readdir(dir))) {
      string devname = "/dev/input/" + de->d_name;

      // open device, and set to non-block
      int fd = open(devname, O_RDWR | O_CLOEXEC);
      fcntl(fd, F_SETFL, O_NONBLOCK);

      // add to mEpollFd
      struct epoll_event eventItem;
      memset(&eventItem, 0, sizeof(eventItem));
      eventItem.events = EPOLLIN;
      if (mUsingEpollWakeup) {
          eventItem.events |= EPOLLWAKEUP;
      }
      eventItem.data.u32 = deviceId;
      epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem);
    }

    mDevicesOpened = true;
  }
  ...
}

References

InputDispatcher

:warning: TO BE ADDED

IPC, WMS and InputDispatcher

:warning: TO BE ADDED