am 1306a7ef: am cc2958fd: fix secure adb in recovery

* commit '1306a7effafab77cf2769091619518c2ab263ee8':
  fix secure adb in recovery
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/minzip/DirUtil.c b/minzip/DirUtil.c
index 8dd5da1..fe2c880 100644
--- a/minzip/DirUtil.c
+++ b/minzip/DirUtil.c
@@ -234,61 +234,3 @@
     /* delete target directory */
     return rmdir(path);
 }
-
-int
-dirSetHierarchyPermissions(const char *path,
-        int uid, int gid, int dirMode, int fileMode)
-{
-    struct stat st;
-    if (lstat(path, &st)) {
-        return -1;
-    }
-
-    /* ignore symlinks */
-    if (S_ISLNK(st.st_mode)) {
-        return 0;
-    }
-
-    /* directories and files get different permissions */
-    if (chown(path, uid, gid) ||
-        chmod(path, S_ISDIR(st.st_mode) ? dirMode : fileMode)) {
-        return -1;
-    }
-
-    /* recurse over directory components */
-    if (S_ISDIR(st.st_mode)) {
-        DIR *dir = opendir(path);
-        if (dir == NULL) {
-            return -1;
-        }
-
-        errno = 0;
-        const struct dirent *de;
-        while (errno == 0 && (de = readdir(dir)) != NULL) {
-            if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) {
-                continue;
-            }
-
-            char dn[PATH_MAX];
-            snprintf(dn, sizeof(dn), "%s/%s", path, de->d_name);
-            if (!dirSetHierarchyPermissions(dn, uid, gid, dirMode, fileMode)) {
-                errno = 0;
-            } else if (errno == 0) {
-                errno = -1;
-            }
-        }
-
-        if (errno != 0) {
-            int save = errno;
-            closedir(dir);
-            errno = save;
-            return -1;
-        }
-
-        if (closedir(dir)) {
-            return -1;
-        }
-    }
-
-    return 0;
-}
diff --git a/minzip/DirUtil.h b/minzip/DirUtil.h
index a5cfa76..85a0012 100644
--- a/minzip/DirUtil.h
+++ b/minzip/DirUtil.h
@@ -48,14 +48,6 @@
  */
 int dirUnlinkHierarchy(const char *path);
 
-/* chown -R <uid>:<gid> <path>
- * chmod -R <mode> <path>
- *
- * Sets directories to <dirMode> and files to <fileMode>.  Skips symlinks.
- */
-int dirSetHierarchyPermissions(const char *path,
-         int uid, int gid, int dirMode, int fileMode);
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/ui.cpp b/ui.cpp
index cece02d..5043ee5 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;
@@ -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..d85fc65 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;
diff --git a/updater/install.c b/updater/install.c
index 0a85945..061aa7b 100644
--- a/updater/install.c
+++ b/updater/install.c
@@ -524,88 +524,6 @@
     return StringValue(strdup(""));
 }
 
-
-Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
-    char* result = NULL;
-    bool recursive = (strcmp(name, "set_perm_recursive") == 0);
-
-    int min_args = 4 + (recursive ? 1 : 0);
-    if (argc < min_args) {
-        return ErrorAbort(state, "%s() expects %d+ args, got %d",
-                          name, min_args, argc);
-    }
-
-    char** args = ReadVarArgs(state, argc, argv);
-    if (args == NULL) return NULL;
-
-    char* end;
-    int i;
-    int bad = 0;
-
-    int uid = strtoul(args[0], &end, 0);
-    if (*end != '\0' || args[0][0] == 0) {
-        ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]);
-        goto done;
-    }
-
-    int gid = strtoul(args[1], &end, 0);
-    if (*end != '\0' || args[1][0] == 0) {
-        ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]);
-        goto done;
-    }
-
-    if (recursive) {
-        int dir_mode = strtoul(args[2], &end, 0);
-        if (*end != '\0' || args[2][0] == 0) {
-            ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]);
-            goto done;
-        }
-
-        int file_mode = strtoul(args[3], &end, 0);
-        if (*end != '\0' || args[3][0] == 0) {
-            ErrorAbort(state, "%s: \"%s\" not a valid filemode",
-                       name, args[3]);
-            goto done;
-        }
-
-        for (i = 4; i < argc; ++i) {
-            dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
-        }
-    } else {
-        int mode = strtoul(args[2], &end, 0);
-        if (*end != '\0' || args[2][0] == 0) {
-            ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]);
-            goto done;
-        }
-
-        for (i = 3; i < argc; ++i) {
-            if (chown(args[i], uid, gid) < 0) {
-                printf("%s: chown of %s to %d %d failed: %s\n",
-                        name, args[i], uid, gid, strerror(errno));
-                ++bad;
-            }
-            if (chmod(args[i], mode) < 0) {
-                printf("%s: chmod of %s to %o failed: %s\n",
-                        name, args[i], mode, strerror(errno));
-                ++bad;
-            }
-        }
-    }
-    result = strdup("");
-
-done:
-    for (i = 0; i < argc; ++i) {
-        free(args[i]);
-    }
-    free(args);
-
-    if (bad) {
-        free(result);
-        return ErrorAbort(state, "%s: some changes failed", name);
-    }
-    return StringValue(result);
-}
-
 struct perm_parsed_args {
     bool has_uid;
     uid_t uid;
@@ -1398,11 +1316,6 @@
     RegisterFunction("package_extract_file", PackageExtractFileFn);
     RegisterFunction("symlink", SymlinkFn);
 
-    // Maybe, at some future point, we can delete these functions? They have been
-    // replaced by perm_set and perm_set_recursive.
-    RegisterFunction("set_perm", SetPermFn);
-    RegisterFunction("set_perm_recursive", SetPermFn);
-
     // Usage:
     //   set_metadata("filename", "key1", "value1", "key2", "value2", ...)
     // Example: