am 7e0d3066: am fc729512: Merge "Set SELinux security contexts correctly for init and services."

* commit '7e0d30667cf53a182525f87dd0c8cb0e2628a1ed':
  Set SELinux security contexts correctly for init and services.
diff --git a/Android.mk b/Android.mk
index 3d61568..c544db9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -57,7 +57,7 @@
 
 ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
     LOCAL_CFLAGS += -DUSE_EXT4
-    LOCAL_C_INCLUDES += system/extras/ext4_utils
+    LOCAL_C_INCLUDES += system/extras/ext4_utils system/vold
     LOCAL_STATIC_LIBRARIES += libext4_utils_static libz
 endif
 
@@ -89,6 +89,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 \
     asn1_decoder.cpp \
diff --git a/etc/init.rc b/etc/init.rc
index 5f9ce80..554ed7a 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -52,7 +52,7 @@
     critical
     seclabel u:r:ueventd:s0
 
-service healthd /sbin/healthd -n
+service healthd /sbin/healthd -r
     critical
     seclabel u:r:healthd:s0
 
diff --git a/install.cpp b/install.cpp
index 797a525..980830c 100644
--- a/install.cpp
+++ b/install.cpp
@@ -120,6 +120,7 @@
 
     pid_t pid = fork();
     if (pid == 0) {
+        umask(022);
         close(pipefd[0]);
         execv(binary, (char* const*)args);
         fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno));
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/minui/resources.c b/minui/resources.c
index c0a9cca..b20c00a 100644
--- a/minui/resources.c
+++ b/minui/resources.c
@@ -123,10 +123,18 @@
     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);
     }
diff --git a/minzip/SysUtil.c b/minzip/SysUtil.c
index 31c76d6..e6f6506 100644
--- a/minzip/SysUtil.c
+++ b/minzip/SysUtil.c
@@ -16,34 +16,6 @@
 #include "Log.h"
 #include "SysUtil.h"
 
-/*
- * Having trouble finding a portable way to get this.  sysconf(_SC_PAGE_SIZE)
- * seems appropriate, but we don't have that on the device.  Some systems
- * have getpagesize(2), though the linux man page has some odd cautions.
- */
-#define DEFAULT_PAGE_SIZE   4096
-
-
-/*
- * Create an anonymous shared memory segment large enough to hold "length"
- * bytes.  The actual segment may be larger because mmap() operates on
- * page boundaries (usually 4K).
- */
-static void* sysCreateAnonShmem(size_t length)
-{
-    void* ptr;
-
-    ptr = mmap(NULL, length, PROT_READ | PROT_WRITE,
-            MAP_SHARED | MAP_ANON, -1, 0);
-    if (ptr == MAP_FAILED) {
-        LOGW("mmap(%d, RW, SHARED|ANON) failed: %s\n", (int) length,
-            strerror(errno));
-        return NULL;
-    }
-
-    return ptr;
-}
-
 static int getFileStartAndLength(int fd, off_t *start_, size_t *length_)
 {
     off_t start, end;
@@ -74,41 +46,6 @@
 }
 
 /*
- * Pull the contents of a file into an new shared memory segment.  We grab
- * everything from fd's current offset on.
- *
- * We need to know the length ahead of time so we can allocate a segment
- * of sufficient size.
- */
-int sysLoadFileInShmem(int fd, MemMapping* pMap)
-{
-    off_t start;
-    size_t length, actual;
-    void* memPtr;
-
-    assert(pMap != NULL);
-
-    if (getFileStartAndLength(fd, &start, &length) < 0)
-        return -1;
-
-    memPtr = sysCreateAnonShmem(length);
-    if (memPtr == NULL)
-        return -1;
-
-    pMap->baseAddr = pMap->addr = memPtr;
-    pMap->baseLength = pMap->length = length;
-
-    actual = TEMP_FAILURE_RETRY(read(fd, memPtr, length));
-    if (actual != length) {
-        LOGE("only read %d of %d bytes\n", (int) actual, (int) length);
-        sysReleaseShmem(pMap);
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
  * Map a file (from fd's current offset) into a shared, read-only memory
  * segment.  The file offset must be a multiple of the page size.
  *
@@ -140,59 +77,6 @@
 }
 
 /*
- * Map part of a file (from fd's current offset) into a shared, read-only
- * memory segment.
- *
- * On success, returns 0 and fills out "pMap".  On failure, returns a nonzero
- * value and does not disturb "pMap".
- */
-int sysMapFileSegmentInShmem(int fd, off_t start, long length,
-    MemMapping* pMap)
-{
-    off_t dummy;
-    size_t fileLength, actualLength;
-    off_t actualStart;
-    int adjust;
-    void* memPtr;
-
-    assert(pMap != NULL);
-
-    if (getFileStartAndLength(fd, &dummy, &fileLength) < 0)
-        return -1;
-
-    if (start + length > (long)fileLength) {
-        LOGW("bad segment: st=%d len=%ld flen=%d\n",
-            (int) start, length, (int) fileLength);
-        return -1;
-    }
-
-    /* adjust to be page-aligned */
-    adjust = start % DEFAULT_PAGE_SIZE;
-    actualStart = start - adjust;
-    actualLength = length + adjust;
-
-    memPtr = mmap(NULL, actualLength, PROT_READ, MAP_FILE | MAP_SHARED,
-                fd, actualStart);
-    if (memPtr == MAP_FAILED) {
-        LOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s\n",
-            (int) actualLength, fd, (int) actualStart, strerror(errno));
-        return -1;
-    }
-
-    pMap->baseAddr = memPtr;
-    pMap->baseLength = actualLength;
-    pMap->addr = (char*)memPtr + adjust;
-    pMap->length = length;
-
-    LOGVV("mmap seg (st=%d ln=%d): bp=%p bl=%d ad=%p ln=%d\n",
-        (int) start, (int) length,
-        pMap->baseAddr, (int) pMap->baseLength,
-        pMap->addr, (int) pMap->length);
-
-    return 0;
-}
-
-/*
  * Release a memory mapping.
  */
 void sysReleaseShmem(MemMapping* pMap)
@@ -209,4 +93,3 @@
         pMap->baseLength = 0;
     }
 }
-
diff --git a/minzip/SysUtil.h b/minzip/SysUtil.h
index ec3a4bc..55cd0e7 100644
--- a/minzip/SysUtil.h
+++ b/minzip/SysUtil.h
@@ -27,17 +27,6 @@
 }
 
 /*
- * Load a file into a new shared memory segment.  All data from the current
- * offset to the end of the file is pulled in.
- *
- * The segment is read-write, allowing VM fixups.  (It should be modified
- * to support .gz/.zip compressed data.)
- *
- * On success, "pMap" is filled in, and zero is returned.
- */
-int sysLoadFileInShmem(int fd, MemMapping* pMap);
-
-/*
  * Map a file (from fd's current offset) into a shared,
  * read-only memory segment.
  *
@@ -46,12 +35,6 @@
 int sysMapFileInShmem(int fd, MemMapping* pMap);
 
 /*
- * Like sysMapFileInShmem, but on only part of a file.
- */
-int sysMapFileSegmentInShmem(int fd, off_t start, long length,
-    MemMapping* pMap);
-
-/*
  * Release the pages associated with a shared memory segment.
  *
  * This does not free "pMap"; it just releases the memory.
diff --git a/roots.cpp b/roots.cpp
index 113dba1..47cea0b 100644
--- a/roots.cpp
+++ b/roots.cpp
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <ctype.h>
+#include <fcntl.h>
 
 #include <fs_mgr.h>
 #include "mtdutils/mtdutils.h"
@@ -28,6 +29,10 @@
 #include "roots.h"
 #include "common.h"
 #include "make_ext4fs.h"
+extern "C" {
+#include "wipe.h"
+#include "cryptfs.h"
+}
 
 static struct fstab *fstab = NULL;
 
@@ -191,11 +196,31 @@
     }
 
     if (strcmp(v->fs_type, "ext4") == 0) {
-        int result = make_ext4fs(v->blk_device, v->length, volume, sehandle);
+        ssize_t length = 0;
+        if (v->length != 0) {
+            length = v->length;
+        } else if (v->key_loc != NULL && strcmp(v->key_loc, "footer") == 0) {
+            length = -CRYPT_FOOTER_OFFSET;
+        }
+        int result = make_ext4fs(v->blk_device, length, volume, sehandle);
         if (result != 0) {
             LOGE("format_volume: make_extf4fs failed on %s\n", v->blk_device);
             return -1;
         }
+
+        // if there's a key_loc that looks like a path, it should be a
+        // block device for storing encryption metadata.  wipe it too.
+        if (v->key_loc != NULL && v->key_loc[0] == '/') {
+            LOGI("wiping %s\n", v->key_loc);
+            int fd = open(v->key_loc, O_WRONLY | O_CREAT, 0644);
+            if (fd < 0) {
+                LOGE("format_volume: failed to open %s\n", v->key_loc);
+                return -1;
+            }
+            wipe_block_device(fd, get_file_size(fd));
+            close(fd);
+        }
+
         return 0;
     }
 
diff --git a/screen_ui.cpp b/screen_ui.cpp
index 27d0a24..fd1a6c7 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -392,6 +392,7 @@
     text_cols = gr_fb_width() / char_width;
     if (text_cols > kMaxCols - 1) text_cols = kMaxCols - 1;
 
+    backgroundIcon[NONE] = NULL;
     LoadBitmap("icon_installing", &backgroundIcon[INSTALLING_UPDATE]);
     backgroundIcon[ERASING] = backgroundIcon[INSTALLING_UPDATE];
     LoadBitmap("icon_error", &backgroundIcon[ERROR]);
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 0757260..faa0acd 100644
--- a/ui.h
+++ b/ui.h
@@ -79,7 +79,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
@@ -123,6 +123,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;
@@ -132,7 +136,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();