Merge "minui: Managed FDs with smart pointers."
diff --git a/minui/events.cpp b/minui/events.cpp
index c958610..7d0250e 100644
--- a/minui/events.cpp
+++ b/minui/events.cpp
@@ -23,144 +23,148 @@
 #include <string.h>
 #include <sys/epoll.h>
 #include <sys/ioctl.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include <functional>
+#include <memory>
+
+#include <android-base/unique_fd.h>
 
 #include "minui/minui.h"
 
-#define MAX_DEVICES 16
-#define MAX_MISC_FDS 16
+constexpr size_t MAX_DEVICES = 16;
+constexpr size_t MAX_MISC_FDS = 16;
 
-#define BITS_PER_LONG (sizeof(unsigned long) * 8)
-#define BITS_TO_LONGS(x) (((x) + BITS_PER_LONG - 1) / BITS_PER_LONG)
+constexpr size_t BITS_PER_LONG = sizeof(unsigned long) * 8;
+constexpr size_t BITS_TO_LONGS(size_t bits) {
+  return ((bits + BITS_PER_LONG - 1) / BITS_PER_LONG);
+}
 
-struct fd_info {
-  int fd;
+struct FdInfo {
+  android::base::unique_fd fd;
   ev_callback cb;
 };
 
-static int g_epoll_fd;
-static epoll_event polledevents[MAX_DEVICES + MAX_MISC_FDS];
-static int npolledevents;
+static android::base::unique_fd g_epoll_fd;
+static epoll_event g_polled_events[MAX_DEVICES + MAX_MISC_FDS];
+static int g_polled_events_count;
 
-static fd_info ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS];
+static FdInfo ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS];
 
-static unsigned ev_count = 0;
-static unsigned ev_dev_count = 0;
-static unsigned ev_misc_count = 0;
+static size_t g_ev_count = 0;
+static size_t g_ev_dev_count = 0;
+static size_t g_ev_misc_count = 0;
 
 static bool test_bit(size_t bit, unsigned long* array) { // NOLINT
-    return (array[bit/BITS_PER_LONG] & (1UL << (bit % BITS_PER_LONG))) != 0;
+  return (array[bit / BITS_PER_LONG] & (1UL << (bit % BITS_PER_LONG))) != 0;
 }
 
 int ev_init(ev_callback input_cb, bool allow_touch_inputs) {
-  g_epoll_fd = epoll_create1(EPOLL_CLOEXEC);
-  if (g_epoll_fd == -1) {
+  g_epoll_fd.reset();
+
+  android::base::unique_fd epoll_fd(epoll_create1(EPOLL_CLOEXEC));
+  if (epoll_fd == -1) {
     return -1;
   }
 
-  bool epollctlfail = false;
-  DIR* dir = opendir("/dev/input");
-  if (dir != nullptr) {
-    dirent* de;
-    while ((de = readdir(dir))) {
-      if (strncmp(de->d_name, "event", 5)) continue;
-      int fd = openat(dirfd(dir), de->d_name, O_RDONLY | O_CLOEXEC);
-      if (fd == -1) continue;
+  std::unique_ptr<DIR, decltype(&closedir)> dir(opendir("/dev/input"), closedir);
+  if (!dir) {
+    return -1;
+  }
 
-      // Use unsigned long to match ioctl's parameter type.
-      unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];  // NOLINT
+  bool epoll_ctl_failed = false;
+  dirent* de;
+  while ((de = readdir(dir.get())) != nullptr) {
+    if (strncmp(de->d_name, "event", 5)) continue;
+    android::base::unique_fd fd(openat(dirfd(dir.get()), de->d_name, O_RDONLY | O_CLOEXEC));
+    if (fd == -1) continue;
 
-      // Read the evbits of the input device.
-      if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
-        close(fd);
-        continue;
-      }
+    // Use unsigned long to match ioctl's parameter type.
+    unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];  // NOLINT
 
-      // We assume that only EV_KEY, EV_REL, and EV_SW event types are ever needed. EV_ABS is also
-      // allowed if allow_touch_inputs is set.
-      if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) {
-        if (!allow_touch_inputs || !test_bit(EV_ABS, ev_bits)) {
-          close(fd);
-          continue;
-        }
-      }
-
-      epoll_event ev;
-      ev.events = EPOLLIN | EPOLLWAKEUP;
-      ev.data.ptr = &ev_fdinfo[ev_count];
-      if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
-        close(fd);
-        epollctlfail = true;
-        continue;
-      }
-
-      ev_fdinfo[ev_count].fd = fd;
-      ev_fdinfo[ev_count].cb = input_cb;
-      ev_count++;
-      ev_dev_count++;
-      if (ev_dev_count == MAX_DEVICES) break;
+    // Read the evbits of the input device.
+    if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
+      continue;
     }
 
-    closedir(dir);
+    // We assume that only EV_KEY, EV_REL, and EV_SW event types are ever needed. EV_ABS is also
+    // allowed if allow_touch_inputs is set.
+    if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) {
+      if (!allow_touch_inputs || !test_bit(EV_ABS, ev_bits)) {
+        continue;
+      }
+    }
+
+    epoll_event ev;
+    ev.events = EPOLLIN | EPOLLWAKEUP;
+    ev.data.ptr = &ev_fdinfo[g_ev_count];
+    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+      epoll_ctl_failed = true;
+      continue;
+    }
+
+    ev_fdinfo[g_ev_count].fd.reset(fd.release());
+    ev_fdinfo[g_ev_count].cb = input_cb;
+    g_ev_count++;
+    g_ev_dev_count++;
+    if (g_ev_dev_count == MAX_DEVICES) break;
   }
 
-  if (epollctlfail && !ev_count) {
-    close(g_epoll_fd);
-    g_epoll_fd = -1;
+  if (epoll_ctl_failed && !g_ev_count) {
     return -1;
   }
 
+  g_epoll_fd.reset(epoll_fd.release());
   return 0;
 }
 
 int ev_get_epollfd(void) {
-    return g_epoll_fd;
+  return g_epoll_fd.get();
 }
 
-int ev_add_fd(int fd, ev_callback cb) {
-  if (ev_misc_count == MAX_MISC_FDS || cb == NULL) {
+int ev_add_fd(android::base::unique_fd&& fd, ev_callback cb) {
+  if (g_ev_misc_count == MAX_MISC_FDS || cb == nullptr) {
     return -1;
   }
 
   epoll_event ev;
   ev.events = EPOLLIN | EPOLLWAKEUP;
-  ev.data.ptr = static_cast<void*>(&ev_fdinfo[ev_count]);
+  ev.data.ptr = static_cast<void*>(&ev_fdinfo[g_ev_count]);
   int ret = epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev);
   if (!ret) {
-    ev_fdinfo[ev_count].fd = fd;
-    ev_fdinfo[ev_count].cb = std::move(cb);
-    ev_count++;
-    ev_misc_count++;
+    ev_fdinfo[g_ev_count].fd.reset(fd.release());
+    ev_fdinfo[g_ev_count].cb = std::move(cb);
+    g_ev_count++;
+    g_ev_misc_count++;
   }
 
   return ret;
 }
 
 void ev_exit(void) {
-    while (ev_count > 0) {
-        close(ev_fdinfo[--ev_count].fd);
-    }
-    ev_misc_count = 0;
-    ev_dev_count = 0;
-    close(g_epoll_fd);
+  while (g_ev_count > 0) {
+    ev_fdinfo[--g_ev_count].fd.reset();
+  }
+  g_ev_misc_count = 0;
+  g_ev_dev_count = 0;
+  g_epoll_fd.reset();
 }
 
 int ev_wait(int timeout) {
-    npolledevents = epoll_wait(g_epoll_fd, polledevents, ev_count, timeout);
-    if (npolledevents <= 0) {
-        return -1;
-    }
-    return 0;
+  g_polled_events_count = epoll_wait(g_epoll_fd, g_polled_events, g_ev_count, timeout);
+  if (g_polled_events_count <= 0) {
+    return -1;
+  }
+  return 0;
 }
 
 void ev_dispatch(void) {
-  for (int n = 0; n < npolledevents; n++) {
-    fd_info* fdi = static_cast<fd_info*>(polledevents[n].data.ptr);
+  for (int n = 0; n < g_polled_events_count; n++) {
+    FdInfo* fdi = static_cast<FdInfo*>(g_polled_events[n].data.ptr);
     const ev_callback& cb = fdi->cb;
     if (cb) {
-      cb(fdi->fd, polledevents[n].events);
+      cb(fdi->fd, g_polled_events[n].events);
     }
   }
 }
@@ -180,7 +184,7 @@
   unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];    // NOLINT
   unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)];  // NOLINT
 
-  for (size_t i = 0; i < ev_dev_count; ++i) {
+  for (size_t i = 0; i < g_ev_dev_count; ++i) {
     memset(ev_bits, 0, sizeof(ev_bits));
     memset(key_bits, 0, sizeof(key_bits));
 
@@ -205,37 +209,36 @@
 }
 
 void ev_iterate_available_keys(const std::function<void(int)>& f) {
-    // Use unsigned long to match ioctl's parameter type.
-    unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT
-    unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)]; // NOLINT
+  // Use unsigned long to match ioctl's parameter type.
+  unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];    // NOLINT
+  unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)];  // NOLINT
 
-    for (size_t i = 0; i < ev_dev_count; ++i) {
-        memset(ev_bits, 0, sizeof(ev_bits));
-        memset(key_bits, 0, sizeof(key_bits));
+  for (size_t i = 0; i < g_ev_dev_count; ++i) {
+    memset(ev_bits, 0, sizeof(ev_bits));
+    memset(key_bits, 0, sizeof(key_bits));
 
-        // Does this device even have keys?
-        if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
-            continue;
-        }
-        if (!test_bit(EV_KEY, ev_bits)) {
-            continue;
-        }
-
-        int rc = ioctl(ev_fdinfo[i].fd, EVIOCGBIT(EV_KEY, KEY_MAX), key_bits);
-        if (rc == -1) {
-            continue;
-        }
-
-        for (int key_code = 0; key_code <= KEY_MAX; ++key_code) {
-            if (test_bit(key_code, key_bits)) {
-                f(key_code);
-            }
-        }
+    // Does this device even have keys?
+    if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
+      continue;
     }
+    if (!test_bit(EV_KEY, ev_bits)) {
+      continue;
+    }
+
+    if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(EV_KEY, KEY_MAX), key_bits) == -1) {
+      continue;
+    }
+
+    for (int key_code = 0; key_code <= KEY_MAX; ++key_code) {
+      if (test_bit(key_code, key_bits)) {
+        f(key_code);
+      }
+    }
+  }
 }
 
 void ev_iterate_touch_inputs(const std::function<void(int)>& action) {
-  for (size_t i = 0; i < ev_dev_count; ++i) {
+  for (size_t i = 0; i < g_ev_dev_count; ++i) {
     // Use unsigned long to match ioctl's parameter type.
     unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)] = {};  // NOLINT
     if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
diff --git a/minui/include/minui/minui.h b/minui/include/minui/minui.h
index e49c6ac..36bdcf1 100644
--- a/minui/include/minui/minui.h
+++ b/minui/include/minui/minui.h
@@ -26,6 +26,7 @@
 #include <vector>
 
 #include <android-base/macros.h>
+#include <android-base/unique_fd.h>
 
 //
 // Graphics.
@@ -153,7 +154,7 @@
 
 int ev_init(ev_callback input_cb, bool allow_touch_inputs = false);
 void ev_exit();
-int ev_add_fd(int fd, ev_callback cb);
+int ev_add_fd(android::base::unique_fd&& fd, ev_callback cb);
 void ev_iterate_available_keys(const std::function<void(int)>& f);
 void ev_iterate_touch_inputs(const std::function<void(int)>& action);
 int ev_sync_key_state(const ev_set_key_callback& set_key_cb);