Home | History | Annotate | Download | only in debuggerd
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <stdio.h>
     18 #include <stdlib.h>
     19 #include <string.h>
     20 #include <stdint.h>
     21 #include <dirent.h>
     22 #include <fcntl.h>
     23 #include <sys/ioctl.h>
     24 #include <sys/inotify.h>
     25 #include <sys/limits.h>
     26 #include <sys/poll.h>
     27 #include <linux/input.h>
     28 #include <errno.h>
     29 #include <cutils/log.h>
     30 
     31 static struct pollfd* ufds;
     32 static char** device_names;
     33 static int nfds;
     34 
     35 static int open_device(const char* device) {
     36   int version;
     37   int fd;
     38   struct pollfd* new_ufds;
     39   char** new_device_names;
     40   char name[80];
     41   char location[80];
     42   char idstr[80];
     43   struct input_id id;
     44 
     45   fd = open(device, O_RDWR);
     46   if (fd < 0) {
     47     return -1;
     48   }
     49 
     50   if (ioctl(fd, EVIOCGVERSION, &version)) {
     51     return -1;
     52   }
     53   if (ioctl(fd, EVIOCGID, &id)) {
     54     return -1;
     55   }
     56   name[sizeof(name) - 1] = '\0';
     57   location[sizeof(location) - 1] = '\0';
     58   idstr[sizeof(idstr) - 1] = '\0';
     59   if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
     60     name[0] = '\0';
     61   }
     62   if (ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
     63     location[0] = '\0';
     64   }
     65   if (ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
     66     idstr[0] = '\0';
     67   }
     68 
     69   new_ufds = reinterpret_cast<pollfd*>(realloc(ufds, sizeof(ufds[0]) * (nfds + 1)));
     70   if (new_ufds == NULL) {
     71     fprintf(stderr, "out of memory\n");
     72     return -1;
     73   }
     74   ufds = new_ufds;
     75   new_device_names = reinterpret_cast<char**>(realloc(
     76       device_names, sizeof(device_names[0]) * (nfds + 1)));
     77   if (new_device_names == NULL) {
     78     fprintf(stderr, "out of memory\n");
     79     return -1;
     80   }
     81   device_names = new_device_names;
     82   ufds[nfds].fd = fd;
     83   ufds[nfds].events = POLLIN;
     84   device_names[nfds] = strdup(device);
     85   nfds++;
     86 
     87   return 0;
     88 }
     89 
     90 int close_device(const char* device) {
     91   int i;
     92   for (i = 1; i < nfds; i++) {
     93     if (strcmp(device_names[i], device) == 0) {
     94       int count = nfds - i - 1;
     95       free(device_names[i]);
     96       memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
     97       memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
     98       nfds--;
     99       return 0;
    100     }
    101   }
    102   return -1;
    103 }
    104 
    105 static int read_notify(const char* dirname, int nfd) {
    106   int res;
    107   char devname[PATH_MAX];
    108   char* filename;
    109   char event_buf[512];
    110   int event_size;
    111   int event_pos = 0;
    112   struct inotify_event *event;
    113 
    114   res = read(nfd, event_buf, sizeof(event_buf));
    115   if (res < (int)sizeof(*event)) {
    116     if (errno == EINTR)
    117       return 0;
    118     fprintf(stderr, "could not get event, %s\n", strerror(errno));
    119     return 1;
    120   }
    121 
    122   strcpy(devname, dirname);
    123   filename = devname + strlen(devname);
    124   *filename++ = '/';
    125 
    126   while (res >= (int)sizeof(*event)) {
    127     event = reinterpret_cast<struct inotify_event*>(event_buf + event_pos);
    128     if (event->len) {
    129       strcpy(filename, event->name);
    130       if (event->mask & IN_CREATE) {
    131         open_device(devname);
    132       } else {
    133         close_device(devname);
    134       }
    135     }
    136     event_size = sizeof(*event) + event->len;
    137     res -= event_size;
    138     event_pos += event_size;
    139   }
    140   return 0;
    141 }
    142 
    143 static int scan_dir(const char* dirname) {
    144   char devname[PATH_MAX];
    145   char* filename;
    146   DIR* dir;
    147   struct dirent* de;
    148   dir = opendir(dirname);
    149   if (dir == NULL)
    150     return -1;
    151   strcpy(devname, dirname);
    152   filename = devname + strlen(devname);
    153   *filename++ = '/';
    154   while ((de = readdir(dir))) {
    155     if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
    156         (de->d_name[1] == '.' && de->d_name[2] == '\0'))
    157       continue;
    158     strcpy(filename, de->d_name);
    159     open_device(devname);
    160   }
    161   closedir(dir);
    162   return 0;
    163 }
    164 
    165 int init_getevent() {
    166   int res;
    167   const char* device_path = "/dev/input";
    168 
    169   nfds = 1;
    170   ufds = reinterpret_cast<pollfd*>(calloc(1, sizeof(ufds[0])));
    171   ufds[0].fd = inotify_init();
    172   ufds[0].events = POLLIN;
    173 
    174   res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
    175   if (res < 0) {
    176     return 1;
    177   }
    178   res = scan_dir(device_path);
    179   if (res < 0) {
    180     return 1;
    181   }
    182   return 0;
    183 }
    184 
    185 void uninit_getevent() {
    186   int i;
    187   for (i = 0; i < nfds; i++) {
    188     close(ufds[i].fd);
    189   }
    190   free(ufds);
    191   ufds = 0;
    192   nfds = 0;
    193 }
    194 
    195 int get_event(struct input_event* event, int timeout) {
    196   int res;
    197   int i;
    198   int pollres;
    199   const char* device_path = "/dev/input";
    200   while (1) {
    201     pollres = poll(ufds, nfds, timeout);
    202     if (pollres == 0) {
    203       return 1;
    204     }
    205     if (ufds[0].revents & POLLIN) {
    206       read_notify(device_path, ufds[0].fd);
    207     }
    208     for (i = 1; i < nfds; i++) {
    209       if (ufds[i].revents) {
    210         if (ufds[i].revents & POLLIN) {
    211           res = read(ufds[i].fd, event, sizeof(*event));
    212           if (res < static_cast<int>(sizeof(event))) {
    213             fprintf(stderr, "could not get event\n");
    214             return -1;
    215           }
    216           return 0;
    217         }
    218       }
    219     }
    220   }
    221   return 0;
    222 }
    223