diff options
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | etc/init.rc | 2 | ||||
-rw-r--r-- | minui/events.c | 86 | ||||
-rw-r--r-- | minui/minui.h | 5 | ||||
-rw-r--r-- | minui/resources.c | 14 | ||||
-rw-r--r-- | ui.cpp | 52 | ||||
-rw-r--r-- | ui.h | 8 |
7 files changed, 131 insertions, 37 deletions
diff --git a/Android.mk b/Android.mk index 075fa2cfe..645a83534 100644 --- a/Android.mk +++ b/Android.mk @@ -82,6 +82,7 @@ include $(CLEAR_VARS) 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 175489066..9b2a99143 100644 --- a/etc/init.rc +++ b/etc/init.rc @@ -44,7 +44,7 @@ on property:sys.powerctl=* 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 2918afaa8..df7dad448 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 @@ int ev_init(ev_callback input_cb, void *data) 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 @@ int ev_init(ev_callback input_cb, void *data) 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 @@ int ev_init(ev_callback input_cb, void *data) } } + 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 @@ int ev_sync_key_state(ev_set_key_callback set_key_cb, void *data) 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 1b8dd059b..573dd71f4 100644 --- a/minui/minui.h +++ b/minui/minui.h @@ -50,7 +50,7 @@ unsigned int gr_get_height(gr_surface surface); // 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_sync_key_state(ev_set_key_callback set_key_cb, void *data); */ 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/minui/resources.c b/minui/resources.c index c0a9ccacb..b20c00abd 100644 --- a/minui/resources.c +++ b/minui/resources.c @@ -123,10 +123,18 @@ int res_create_surface(const char* name, gr_surface* pSurface) { surface->height = height; surface->stride = width; /* Yes, pixels, not bytes */ surface->data = pData; - surface->format = (channels == 3) ? GGL_PIXEL_FORMAT_RGBX_8888 : - ((color_type == PNG_COLOR_TYPE_PALETTE ? GGL_PIXEL_FORMAT_RGBA_8888 : GGL_PIXEL_FORMAT_L_8)); - int alpha = 0; + if (channels == 3) { + surface->format = GGL_PIXEL_FORMAT_RGBX_8888; + } else if (color_type == PNG_COLOR_TYPE_PALETTE) { + surface->format = GGL_PIXEL_FORMAT_RGBA_8888; + } else if (channels == 1) { + surface->format = GGL_PIXEL_FORMAT_L_8; + } else { + surface->format = GGL_PIXEL_FORMAT_RGBA_8888; + } + + int alpha = (channels == 4); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } @@ -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 @@ RecoveryUI::RecoveryUI() : 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 @@ void RecoveryUI::Init() { } -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 @@ void RecoveryUI::process_key(int key_code, int updown) { 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 @@ void RecoveryUI::FlushKeys() { 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) { @@ -77,7 +77,7 @@ class RecoveryUI { // 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 @@ private: 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 @@ private: 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(); |