am dd92a4d6: am 58c60900: Merge "verifier: update to support certificates using SHA-256"

* commit 'dd92a4d625a6735651efeb12a5707620bc5c6339':
  verifier: update to support certificates using SHA-256
diff --git a/Android.mk b/Android.mk
index 075fa2c..645a835 100644
--- a/Android.mk
+++ b/Android.mk
@@ -82,6 +82,7 @@
 LOCAL_MODULE := verifier_test
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_TAGS := tests
+LOCAL_CFLAGS += -DNO_RECOVERY_MOUNT
 LOCAL_SRC_FILES := \
     verifier_test.cpp \
     verifier.cpp \
diff --git a/etc/init.rc b/etc/init.rc
index 1754890..9b2a991 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -44,7 +44,7 @@
 service ueventd /sbin/ueventd
     critical
 
-service healthd /sbin/healthd -n
+service healthd /sbin/healthd -r
     critical
 
 service recovery /sbin/recovery
diff --git a/minui/events.c b/minui/events.c
index 2918afa..df7dad4 100644
--- a/minui/events.c
+++ b/minui/events.c
@@ -18,7 +18,7 @@
 #include <stdlib.h>
 #include <fcntl.h>
 #include <dirent.h>
-#include <sys/poll.h>
+#include <sys/epoll.h>
 
 #include <linux/input.h>
 
@@ -34,11 +34,15 @@
     ((array)[(bit)/BITS_PER_LONG] & (1 << ((bit) % BITS_PER_LONG)))
 
 struct fd_info {
+    int fd;
     ev_callback cb;
     void *data;
 };
 
-static struct pollfd ev_fds[MAX_DEVICES + MAX_MISC_FDS];
+static int epollfd;
+static struct epoll_event polledevents[MAX_DEVICES + MAX_MISC_FDS];
+static int npolledevents;
+
 static struct fd_info ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS];
 
 static unsigned ev_count = 0;
@@ -50,6 +54,12 @@
     DIR *dir;
     struct dirent *de;
     int fd;
+    struct epoll_event ev;
+    bool epollctlfail = false;
+
+    epollfd = epoll_create(MAX_DEVICES + MAX_MISC_FDS);
+    if (epollfd == -1)
+        return -1;
 
     dir = opendir("/dev/input");
     if(dir != 0) {
@@ -74,8 +84,15 @@
                 continue;
             }
 
-            ev_fds[ev_count].fd = fd;
-            ev_fds[ev_count].events = POLLIN;
+            ev.events = EPOLLIN | EPOLLWAKEUP;
+            ev.data.ptr = (void *)&ev_fdinfo[ev_count];
+            if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev)) {
+                close(fd);
+                epollctlfail = true;
+                continue;
+            }
+
+            ev_fdinfo[ev_count].fd = fd;
             ev_fdinfo[ev_count].cb = input_cb;
             ev_fdinfo[ev_count].data = data;
             ev_count++;
@@ -84,59 +101,78 @@
         }
     }
 
+    if (epollctlfail && !ev_count) {
+        close(epollfd);
+        epollfd = -1;
+        return -1;
+    }
+
     return 0;
 }
 
 int ev_add_fd(int fd, ev_callback cb, void *data)
 {
+    struct epoll_event ev;
+    int ret;
+
     if (ev_misc_count == MAX_MISC_FDS || cb == NULL)
         return -1;
 
-    ev_fds[ev_count].fd = fd;
-    ev_fds[ev_count].events = POLLIN;
-    ev_fdinfo[ev_count].cb = cb;
-    ev_fdinfo[ev_count].data = data;
-    ev_count++;
-    ev_misc_count++;
-    return 0;
+    ev.events = EPOLLIN | EPOLLWAKEUP;
+    ev.data.ptr = (void *)&ev_fdinfo[ev_count];
+    ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
+    if (!ret) {
+        ev_fdinfo[ev_count].fd = fd;
+        ev_fdinfo[ev_count].cb = cb;
+        ev_fdinfo[ev_count].data = data;
+        ev_count++;
+        ev_misc_count++;
+    }
+
+    return ret;
+}
+
+int ev_get_epollfd(void)
+{
+    return epollfd;
 }
 
 void ev_exit(void)
 {
     while (ev_count > 0) {
-        close(ev_fds[--ev_count].fd);
+        close(ev_fdinfo[--ev_count].fd);
     }
     ev_misc_count = 0;
     ev_dev_count = 0;
+    close(epollfd);
 }
 
 int ev_wait(int timeout)
 {
-    int r;
-
-    r = poll(ev_fds, ev_count, timeout);
-    if (r <= 0)
+    npolledevents = epoll_wait(epollfd, polledevents, ev_count, timeout);
+    if (npolledevents <= 0)
         return -1;
     return 0;
 }
 
 void ev_dispatch(void)
 {
-    unsigned n;
+    int n;
     int ret;
 
-    for (n = 0; n < ev_count; n++) {
-        ev_callback cb = ev_fdinfo[n].cb;
-        if (cb && (ev_fds[n].revents & ev_fds[n].events))
-            cb(ev_fds[n].fd, ev_fds[n].revents, ev_fdinfo[n].data);
+    for (n = 0; n < npolledevents; n++) {
+        struct fd_info *fdi = polledevents[n].data.ptr;
+        ev_callback cb = fdi->cb;
+        if (cb)
+            cb(fdi->fd, polledevents[n].events, fdi->data);
     }
 }
 
-int ev_get_input(int fd, short revents, struct input_event *ev)
+int ev_get_input(int fd, uint32_t epevents, struct input_event *ev)
 {
     int r;
 
-    if (revents & POLLIN) {
+    if (epevents & EPOLLIN) {
         r = read(fd, ev, sizeof(*ev));
         if (r == sizeof(*ev))
             return 0;
@@ -157,11 +193,11 @@
         memset(key_bits, 0, sizeof(key_bits));
         memset(ev_bits, 0, sizeof(ev_bits));
 
-        ret = ioctl(ev_fds[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits);
+        ret = ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits);
         if (ret < 0 || !test_bit(EV_KEY, ev_bits))
             continue;
 
-        ret = ioctl(ev_fds[i].fd, EVIOCGKEY(sizeof(key_bits)), key_bits);
+        ret = ioctl(ev_fdinfo[i].fd, EVIOCGKEY(sizeof(key_bits)), key_bits);
         if (ret < 0)
             continue;
 
diff --git a/minui/minui.h b/minui/minui.h
index 1b8dd05..573dd71 100644
--- a/minui/minui.h
+++ b/minui/minui.h
@@ -50,7 +50,7 @@
 // see http://www.mjmwired.net/kernel/Documentation/input/ for info.
 struct input_event;
 
-typedef int (*ev_callback)(int fd, short revents, void *data);
+typedef int (*ev_callback)(int fd, uint32_t epevents, void *data);
 typedef int (*ev_set_key_callback)(int code, int value, void *data);
 
 int ev_init(ev_callback input_cb, void *data);
@@ -65,8 +65,9 @@
  */
 int ev_wait(int timeout);
 
-int ev_get_input(int fd, short revents, struct input_event *ev);
+int ev_get_input(int fd, uint32_t epevents, struct input_event *ev);
 void ev_dispatch(void);
+int ev_get_epollfd(void);
 
 // Resources
 
diff --git a/ui.cpp b/ui.cpp
index cece02d..67a2500 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -31,6 +31,7 @@
 #include <cutils/android_reboot.h>
 
 #include "common.h"
+#include "roots.h"
 #include "device.h"
 #include "minui/minui.h"
 #include "screen_ui.h"
@@ -47,7 +48,10 @@
     key_queue_len(0),
     key_last_down(-1),
     key_long_press(false),
-    key_down_count(0) {
+    key_down_count(0),
+    consecutive_power_keys(0),
+    consecutive_alternate_keys(0),
+    last_key(-1) {
     pthread_mutex_init(&key_queue_mutex, NULL);
     pthread_cond_init(&key_queue_cond, NULL);
     self = this;
@@ -59,12 +63,12 @@
 }
 
 
-int RecoveryUI::input_callback(int fd, short revents, void* data)
+int RecoveryUI::input_callback(int fd, uint32_t epevents, void* data)
 {
     struct input_event ev;
     int ret;
 
-    ret = ev_get_input(fd, revents, &ev);
+    ret = ev_get_input(fd, epevents, &ev);
     if (ret)
         return -1;
 
@@ -152,6 +156,13 @@
           case RecoveryUI::ENQUEUE:
             EnqueueKey(key_code);
             break;
+
+          case RecoveryUI::MOUNT_SYSTEM:
+#ifndef NO_RECOVERY_MOUNT
+            ensure_path_mounted("/system");
+            Print("Mounted /system.");
+#endif
+            break;
         }
     }
 }
@@ -258,8 +269,41 @@
     pthread_mutex_unlock(&key_queue_mutex);
 }
 
+// The default CheckKey implementation assumes the device has power,
+// volume up, and volume down keys.
+//
+// - Hold power and press vol-up to toggle display.
+// - Press power seven times in a row to reboot.
+// - Alternate vol-up and vol-down seven times to mount /system.
 RecoveryUI::KeyAction RecoveryUI::CheckKey(int key) {
-    return RecoveryUI::ENQUEUE;
+    if (IsKeyPressed(KEY_POWER) && key == KEY_VOLUMEUP) {
+        return TOGGLE;
+    }
+
+    if (key == KEY_POWER) {
+        ++consecutive_power_keys;
+        if (consecutive_power_keys >= 7) {
+            return REBOOT;
+        }
+    } else {
+        consecutive_power_keys = 0;
+    }
+
+    if ((key == KEY_VOLUMEUP &&
+         (last_key == KEY_VOLUMEDOWN || last_key == -1)) ||
+        (key == KEY_VOLUMEDOWN &&
+         (last_key == KEY_VOLUMEUP || last_key == -1))) {
+        ++consecutive_alternate_keys;
+        if (consecutive_alternate_keys >= 7) {
+            consecutive_alternate_keys = 0;
+            return MOUNT_SYSTEM;
+        }
+    } else {
+        consecutive_alternate_keys = 0;
+    }
+    last_key = key;
+
+    return ENQUEUE;
 }
 
 void RecoveryUI::NextCheckKeyIsLong(bool is_long_press) {
diff --git a/ui.h b/ui.h
index 6c8987a..8cc1da1 100644
--- a/ui.h
+++ b/ui.h
@@ -77,7 +77,7 @@
     // Return value indicates whether an immediate operation should be
     // triggered (toggling the display, rebooting the device), or if
     // the key should be enqueued for use by the main thread.
-    enum KeyAction { ENQUEUE, TOGGLE, REBOOT, IGNORE };
+    enum KeyAction { ENQUEUE, TOGGLE, REBOOT, IGNORE, MOUNT_SYSTEM };
     virtual KeyAction CheckKey(int key);
 
     // Called immediately before each call to CheckKey(), tell you if
@@ -121,6 +121,10 @@
     int key_down_count;                // under key_queue_mutex
     int rel_sum;
 
+    int consecutive_power_keys;
+    int consecutive_alternate_keys;
+    int last_key;
+
     typedef struct {
         RecoveryUI* ui;
         int key_code;
@@ -130,7 +134,7 @@
     pthread_t input_t;
 
     static void* input_thread(void* cookie);
-    static int input_callback(int fd, short revents, void* data);
+    static int input_callback(int fd, uint32_t epevents, void* data);
     void process_key(int key_code, int updown);
     bool usb_connected();