am cddb15b8: am b4e74db7: am 3fa71b8e: Merge "Remove sshd."

* commit 'cddb15b8a9057e7efacf2de9c9a6a887fd666663':
  Remove sshd.
diff --git a/adb/Android.mk b/adb/Android.mk
index 50e28a6..80427b8 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -102,7 +102,6 @@
 
 LOCAL_SRC_FILES := \
 	adb.c \
-	backup_service.c \
 	fdevent.c \
 	transport.c \
 	transport_local.c \
diff --git a/adb/adb.h b/adb/adb.h
index 2504f99..707a6e0 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -36,7 +36,7 @@
 #define ADB_VERSION_MAJOR 1         // Used for help/version information
 #define ADB_VERSION_MINOR 0         // Used for help/version information
 
-#define ADB_SERVER_VERSION    31    // Increment this when we want to force users to start a new adb server
+#define ADB_SERVER_VERSION    32    // Increment this when we want to force users to start a new adb server
 
 typedef struct amessage amessage;
 typedef struct apacket apacket;
@@ -326,11 +326,6 @@
 int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd);
 
 #if !ADB_HOST
-typedef enum {
-    BACKUP,
-    RESTORE
-} BackupOperation;
-int backup_service(BackupOperation operation, char* args);
 void framebuffer_service(int fd, void *cookie);
 void remount_service(int fd, void *cookie);
 #endif
@@ -418,7 +413,7 @@
 #  define  D(...)          ((void)0)
 #  define  DR(...)         ((void)0)
 #  define  ADB_TRACING     0
-#endif
+#endif /* ADB_TRACE */
 
 
 #if !DEBUG_PACKETS
@@ -476,6 +471,11 @@
 extern int HOST;
 extern int SHELL_EXIT_NOTIFY_FD;
 
+typedef enum {
+    SUBPROC_PTY = 0,
+    SUBPROC_RAW = 1,
+} subproc_mode;
+
 #define CHUNK_SIZE (64*1024)
 
 #if !ADB_HOST
diff --git a/adb/adb_client.c b/adb/adb_client.c
index 1e47486..eb1720d 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -279,7 +279,7 @@
 
     fd = _adb_connect(service);
     if(fd == -1) {
-        fprintf(stderr,"error: %s\n", __adb_error);
+        D("_adb_connect error: %s\n", __adb_error);
     } else if(fd == -2) {
         fprintf(stderr,"** daemon still not running\n");
     }
@@ -296,6 +296,7 @@
 {
     int fd = adb_connect(service);
     if(fd < 0) {
+        fprintf(stderr, "error: %s\n", adb_error());
         return -1;
     }
 
diff --git a/adb/backup_service.c b/adb/backup_service.c
deleted file mode 100644
index 654e0f3..0000000
--- a/adb/backup_service.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <unistd.h>
-#include <stdio.h>
-
-#include "sysdeps.h"
-
-#define TRACE_TAG  TRACE_ADB
-#include "adb.h"
-
-typedef struct {
-    pid_t pid;
-    int fd;
-} backup_harvest_params;
-
-// socketpair but do *not* mark as close_on_exec
-static int backup_socketpair(int sv[2]) {
-    int rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv );
-    if (rc < 0)
-        return -1;
-
-    return 0;
-}
-
-// harvest the child process then close the read end of the socketpair
-static void* backup_child_waiter(void* args) {
-    int status;
-    backup_harvest_params* params = (backup_harvest_params*) args;
-
-    waitpid(params->pid, &status, 0);
-    adb_close(params->fd);
-    free(params);
-    return NULL;
-}
-
-/* returns the data socket passing the backup data here for forwarding */
-int backup_service(BackupOperation op, char* args) {
-    pid_t pid;
-    int s[2];
-    char* operation;
-
-    // Command string depends on our invocation
-    if (op == BACKUP) {
-        operation = "backup";
-    } else {
-        operation = "restore";
-    }
-
-    D("backup_service(%s, %s)\n", operation, args);
-
-    // set up the pipe from the subprocess to here
-    // parent will read s[0]; child will write s[1]
-    if (backup_socketpair(s)) {
-        D("can't create backup/restore socketpair\n");
-        fprintf(stderr, "unable to create backup/restore socketpair\n");
-        return -1;
-    }
-
-    D("Backup/restore socket pair: (send=%d, receive=%d)\n", s[1], s[0]);
-    close_on_exec(s[0]);    // only the side we hold on to
-
-    // spin off the child process to run the backup command
-    pid = fork();
-    if (pid < 0) {
-        // failure
-        D("can't fork for %s\n", operation);
-        fprintf(stderr, "unable to fork for %s\n", operation);
-        adb_close(s[0]);
-        adb_close(s[1]);
-        return -1;
-    }
-
-    // Great, we're off and running.
-    if (pid == 0) {
-        // child -- actually run the backup here
-        char* p;
-        int argc;
-        char portnum[16];
-        char** bu_args;
-
-        // fixed args:  [0] is 'bu', [1] is the port number, [2] is the 'operation' string
-        argc = 3;
-        for (p = (char*)args; p && *p; ) {
-            argc++;
-            while (*p && *p != ':') p++;
-            if (*p == ':') p++;
-        }
-
-        bu_args = (char**) alloca(argc*sizeof(char*) + 1);
-
-        // run through again to build the argv array
-        argc = 0;
-        bu_args[argc++] = "bu";
-        snprintf(portnum, sizeof(portnum), "%d", s[1]);
-        bu_args[argc++] = portnum;
-        bu_args[argc++] = operation;
-        for (p = (char*)args; p && *p; ) {
-            bu_args[argc++] = p;
-            while (*p && *p != ':') p++;
-            if (*p == ':') {
-                *p = 0;
-                p++;
-            }
-        }
-        bu_args[argc] = NULL;
-
-        // Close the half of the socket that we don't care about, route 'bu's console
-        // to the output socket, and off we go
-        adb_close(s[0]);
-
-        // off we go
-        execvp("/system/bin/bu", (char * const *)bu_args);
-        // oops error - close up shop and go home
-        fprintf(stderr, "Unable to exec 'bu', bailing\n");
-        exit(-1);
-    } else {
-        adb_thread_t t;
-        backup_harvest_params* params;
-
-        // parent, i.e. adbd -- close the sending half of the socket
-        D("fork() returned pid %d\n", pid);
-        adb_close(s[1]);
-
-        // spin a thread to harvest the child process
-        params = (backup_harvest_params*) malloc(sizeof(backup_harvest_params));
-        params->pid = pid;
-        params->fd = s[0];
-        if (adb_thread_create(&t, backup_child_waiter, params)) {
-            adb_close(s[0]);
-            free(params);
-            D("Unable to create child harvester\n");
-            return -1;
-        }
-    }
-
-    // we'll be reading from s[0] as the data is sent by the child process
-    return s[0];
-}
diff --git a/adb/commandline.c b/adb/commandline.c
index 2e4cd37..23722b6 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -41,7 +41,7 @@
 
 void get_my_path(char *s, size_t maxLen);
 int find_sync_dirs(const char *srcarg,
-        char **android_srcdir_out, char **data_srcdir_out);
+        char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out);
 int install_app(transport_type transport, char* serial, int argc, char** argv);
 int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
 
@@ -110,9 +110,10 @@
         "  adb push [-p] <local> <remote>\n"
         "                               - copy file/dir to device\n"
         "                                 ('-p' to display the transfer progress)\n"
-        "  adb pull [-p] <remote> [<local>]\n"
+        "  adb pull [-p] [-a] <remote> [<local>]\n"
         "                               - copy file/dir from device\n"
         "                                 ('-p' to display the transfer progress)\n"
+        "                                 ('-a' means copy timestamp and mode)\n"
         "  adb sync [ <directory> ]     - copy host->device only if changed\n"
         "                                 (-l means list but don't copy)\n"
         "                                 (see 'adb help all')\n"
@@ -195,7 +196,7 @@
         "  adb get-serialno             - prints: <serial-number>\n"
         "  adb get-devpath              - prints: <device-path>\n"
         "  adb status-window            - continuously print device status for a specified device\n"
-        "  adb remount                  - remounts the /system partition on the device read-write\n"
+        "  adb remount                  - remounts the /system and /vendor (if present) partitions on the device read-write\n"
         "  adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
         "  adb reboot-bootloader        - reboots the device into the bootloader\n"
         "  adb root                     - restarts the adbd daemon with root permissions\n"
@@ -211,9 +212,9 @@
         "adb sync notes: adb sync [ <directory> ]\n"
         "  <localdir> can be interpreted in several ways:\n"
         "\n"
-        "  - If <directory> is not specified, both /system and /data partitions will be updated.\n"
+        "  - If <directory> is not specified, /system, /vendor (if present), and /data partitions will be updated.\n"
         "\n"
-        "  - If it is \"system\" or \"data\", only the corresponding partition\n"
+        "  - If it is \"system\", \"vendor\" or \"data\", only the corresponding partition\n"
         "    is updated.\n"
         "\n"
         "environmental variables:\n"
@@ -286,8 +287,17 @@
     long total = 0;
 
     D("copy_to_file(%d -> %d)\n", inFd, outFd);
+#ifdef HAVE_TERMIO_H
+    if (inFd == STDIN_FILENO) {
+        stdin_raw_init(STDIN_FILENO);
+    }
+#endif
     for (;;) {
-        len = adb_read(inFd, buf, BUFSIZE);
+        if (inFd == STDIN_FILENO) {
+            len = unix_read(inFd, buf, BUFSIZE);
+        } else {
+            len = adb_read(inFd, buf, BUFSIZE);
+        }
         if (len == 0) {
             D("copy_to_file() : read 0 bytes; exiting\n");
             break;
@@ -300,9 +310,19 @@
             D("copy_to_file() : error %d\n", errno);
             break;
         }
-        adb_write(outFd, buf, len);
+        if (outFd == STDOUT_FILENO) {
+            fwrite(buf, 1, len, stdout);
+            fflush(stdout);
+        } else {
+            adb_write(outFd, buf, len);
+        }
         total += len;
     }
+#ifdef HAVE_TERMIO_H
+    if (inFd == STDIN_FILENO) {
+        stdin_raw_restore(STDIN_FILENO);
+    }
+#endif
     D("copy_to_file() finished after %lu bytes\n", total);
     free(buf);
 }
@@ -481,6 +501,115 @@
     return status;
 }
 
+#define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE)
+
+/*
+ * The sideload-host protocol serves the data in a file (given on the
+ * command line) to the client, using a simple protocol:
+ *
+ * - The connect message includes the total number of bytes in the
+ *   file and a block size chosen by us.
+ *
+ * - The other side sends the desired block number as eight decimal
+ *   digits (eg "00000023" for block 23).  Blocks are numbered from
+ *   zero.
+ *
+ * - We send back the data of the requested block.  The last block is
+ *   likely to be partial; when the last block is requested we only
+ *   send the part of the block that exists, it's not padded up to the
+ *   block size.
+ *
+ * - When the other side sends "DONEDONE" instead of a block number,
+ *   we hang up.
+ */
+int adb_sideload_host(const char* fn) {
+    uint8_t* data;
+    unsigned sz;
+    size_t xfer = 0;
+    int status;
+
+    printf("loading: '%s'", fn);
+    fflush(stdout);
+    data = load_file(fn, &sz);
+    if (data == 0) {
+        printf("\n");
+        fprintf(stderr, "* cannot read '%s' *\n", fn);
+        return -1;
+    }
+
+    char buf[100];
+    sprintf(buf, "sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
+    int fd = adb_connect(buf);
+    if (fd < 0) {
+        // Try falling back to the older sideload method.  Maybe this
+        // is an older device that doesn't support sideload-host.
+        printf("\n");
+        status = adb_download_buffer("sideload", fn, data, sz, 1);
+        goto done;
+    }
+
+    int opt = SIDELOAD_HOST_BLOCK_SIZE;
+    opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
+
+    int last_percent = -1;
+    for (;;) {
+        if (readx(fd, buf, 8)) {
+            fprintf(stderr, "* failed to read command: %s\n", adb_error());
+            status = -1;
+            goto done;
+        }
+
+        if (strncmp("DONEDONE", buf, 8) == 0) {
+            status = 0;
+            break;
+        }
+
+        buf[8] = '\0';
+        int block = strtol(buf, NULL, 10);
+
+        size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
+        if (offset >= sz) {
+            fprintf(stderr, "* attempt to read past end: %s\n", adb_error());
+            status = -1;
+            goto done;
+        }
+        uint8_t* start = data + offset;
+        size_t offset_end = offset + SIDELOAD_HOST_BLOCK_SIZE;
+        size_t to_write = SIDELOAD_HOST_BLOCK_SIZE;
+        if (offset_end > sz) {
+            to_write = sz - offset;
+        }
+
+        if(writex(fd, start, to_write)) {
+            adb_status(fd);
+            fprintf(stderr,"* failed to write data '%s' *\n", adb_error());
+            status = -1;
+            goto done;
+        }
+        xfer += to_write;
+
+        // For normal OTA packages, we expect to transfer every byte
+        // twice, plus a bit of overhead (one read during
+        // verification, one read of each byte for installation, plus
+        // extra access to things like the zip central directory).
+        // This estimate of the completion becomes 100% when we've
+        // transferred ~2.13 (=100/47) times the package size.
+        int percent = (int)(xfer * 47LL / (sz ? sz : 1));
+        if (percent != last_percent) {
+            printf("\rserving: '%s'  (~%d%%)    ", fn, percent);
+            fflush(stdout);
+            last_percent = percent;
+        }
+    }
+
+    printf("\rTotal xfer: %.2fx%*s\n", (double)xfer / (sz ? sz : 1), (int)strlen(fn)+10, "");
+
+  done:
+    if (fd >= 0) adb_close(fd);
+    free(data);
+    return status;
+}
+
 static void status_window(transport_type ttype, const char* serial)
 {
     char command[4096];
@@ -525,39 +654,40 @@
     }
 }
 
-/** duplicate string and quote all \ " ( ) chars + space character. */
-static char *
-dupAndQuote(const char *s)
+/** Duplicate and escape given argument. */
+static char *escape_arg(const char *s)
 {
     const char *ts;
     size_t alloc_len;
     char *ret;
     char *dest;
 
-    ts = s;
-
     alloc_len = 0;
-
-    for( ;*ts != '\0'; ts++) {
+    for (ts = s; *ts != '\0'; ts++) {
         alloc_len++;
         if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
             alloc_len++;
         }
     }
 
-    ret = (char *)malloc(alloc_len + 1);
+    if (alloc_len == 0) {
+        // Preserve empty arguments
+        ret = (char *) malloc(3);
+        ret[0] = '\"';
+        ret[1] = '\"';
+        ret[2] = '\0';
+        return ret;
+    }
 
-    ts = s;
+    ret = (char *) malloc(alloc_len + 1);
     dest = ret;
 
-    for ( ;*ts != '\0'; ts++) {
+    for (ts = s; *ts != '\0'; ts++) {
         if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
             *dest++ = '\\';
         }
-
         *dest++ = *ts;
     }
-
     *dest++ = '\0';
 
     return ret;
@@ -664,30 +794,24 @@
     char buf[4096];
 
     char *log_tags;
-    char *quoted_log_tags;
+    char *quoted;
 
     log_tags = getenv("ANDROID_LOG_TAGS");
-    quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
-
+    quoted = escape_arg(log_tags == NULL ? "" : log_tags);
     snprintf(buf, sizeof(buf),
-        "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
-        quoted_log_tags);
+            "shell:export ANDROID_LOG_TAGS=\"%s\"; exec logcat", quoted);
+    free(quoted);
 
-    free(quoted_log_tags);
-
-    if (!strcmp(argv[0],"longcat")) {
-        strncat(buf, " -v long", sizeof(buf)-1);
+    if (!strcmp(argv[0], "longcat")) {
+        strncat(buf, " -v long", sizeof(buf) - 1);
     }
 
     argc -= 1;
     argv += 1;
     while(argc-- > 0) {
-        char *quoted;
-
-        quoted = dupAndQuote (*argv++);
-
-        strncat(buf, " ", sizeof(buf)-1);
-        strncat(buf, quoted, sizeof(buf)-1);
+        quoted = escape_arg(*argv++);
+        strncat(buf, " ", sizeof(buf) - 1);
+        strncat(buf, quoted, sizeof(buf) - 1);
         free(quoted);
     }
 
@@ -939,13 +1063,19 @@
     return path_buf;
 }
 
-
-static void parse_push_pull_args(char** arg, int narg, char const** path1, char const** path2,
-                                 int* show_progress) {
+static void parse_push_pull_args(char **arg, int narg, char const **path1, char const **path2,
+                                 int *show_progress, int *copy_attrs) {
     *show_progress = 0;
+    *copy_attrs = 0;
 
-    if ((narg > 0) && !strcmp(*arg, "-p")) {
-        *show_progress = 1;
+    while (narg > 0) {
+        if (!strcmp(*arg, "-p")) {
+            *show_progress = 1;
+        } else if (!strcmp(*arg, "-a")) {
+            *copy_attrs = 1;
+        } else {
+            break;
+        }
         ++arg;
         --narg;
     }
@@ -969,7 +1099,6 @@
     int is_server = 0;
     int persist = 0;
     int r;
-    int quote;
     transport_type ttype = kTransportAny;
     char* serial = NULL;
     char* server_port_str = NULL;
@@ -1190,19 +1319,14 @@
             return r;
         }
 
-        snprintf(buf, sizeof buf, "shell:%s", argv[1]);
+        snprintf(buf, sizeof(buf), "shell:%s", argv[1]);
         argc -= 2;
         argv += 2;
-        while(argc-- > 0) {
-            strcat(buf, " ");
-
-            /* quote empty strings and strings with spaces */
-            quote = (**argv == 0 || strchr(*argv, ' '));
-            if (quote)
-                strcat(buf, "\"");
-            strcat(buf, *argv++);
-            if (quote)
-                strcat(buf, "\"");
+        while (argc-- > 0) {
+            char *quoted = escape_arg(*argv++);
+            strncat(buf, " ", sizeof(buf) - 1);
+            strncat(buf, quoted, sizeof(buf) - 1);
+            free(quoted);
         }
 
         for(;;) {
@@ -1234,6 +1358,36 @@
         }
     }
 
+    if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
+        int exec_in = !strcmp(argv[0], "exec-in");
+        int fd;
+
+        snprintf(buf, sizeof buf, "exec:%s", argv[1]);
+        argc -= 2;
+        argv += 2;
+        while (argc-- > 0) {
+            char *quoted = escape_arg(*argv++);
+            strncat(buf, " ", sizeof(buf) - 1);
+            strncat(buf, quoted, sizeof(buf) - 1);
+            free(quoted);
+        }
+
+        fd = adb_connect(buf);
+        if (fd < 0) {
+            fprintf(stderr, "error: %s\n", adb_error());
+            return -1;
+        }
+
+        if (exec_in) {
+            copy_to_file(STDIN_FILENO, fd);
+        } else {
+            copy_to_file(fd, STDOUT_FILENO);
+        }
+
+        adb_close(fd);
+        return 0;
+    }
+
     if(!strcmp(argv[0], "kill-server")) {
         int fd;
         fd = _adb_connect("host:kill");
@@ -1246,7 +1400,7 @@
 
     if(!strcmp(argv[0], "sideload")) {
         if(argc != 2) return usage();
-        if(adb_download("sideload", argv[1], 1)) {
+        if (adb_sideload_host(argv[1])) {
             return 1;
         } else {
             return 0;
@@ -1416,9 +1570,10 @@
 
     if(!strcmp(argv[0], "push")) {
         int show_progress = 0;
+        int copy_attrs = 0; // unused
         const char* lpath = NULL, *rpath = NULL;
 
-        parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress);
+        parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress, &copy_attrs);
 
         if ((lpath != NULL) && (rpath != NULL)) {
             return do_sync_push(lpath, rpath, 0 /* no verify APK */, show_progress);
@@ -1429,12 +1584,13 @@
 
     if(!strcmp(argv[0], "pull")) {
         int show_progress = 0;
+        int copy_attrs = 0;
         const char* rpath = NULL, *lpath = ".";
 
-        parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress);
+        parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress, &copy_attrs);
 
         if (rpath != NULL) {
-            return do_sync_pull(rpath, lpath, show_progress);
+            return do_sync_pull(rpath, lpath, show_progress, copy_attrs);
         }
 
         return usage();
@@ -1451,7 +1607,7 @@
     }
 
     if(!strcmp(argv[0], "sync")) {
-        char *srcarg, *android_srcpath, *data_srcpath;
+        char *srcarg, *android_srcpath, *data_srcpath, *vendor_srcpath;
         int listonly = 0;
 
         int ret;
@@ -1471,15 +1627,18 @@
         } else {
             return usage();
         }
-        ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
+        ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath, &vendor_srcpath);
         if(ret != 0) return usage();
 
         if(android_srcpath != NULL)
             ret = do_sync_sync(android_srcpath, "/system", listonly);
+        if(ret == 0 && vendor_srcpath != NULL)
+            ret = do_sync_sync(vendor_srcpath, "/vendor", listonly);
         if(ret == 0 && data_srcpath != NULL)
             ret = do_sync_sync(data_srcpath, "/data", listonly);
 
         free(android_srcpath);
+        free(vendor_srcpath);
         free(data_srcpath);
         return ret;
     }
@@ -1590,25 +1749,30 @@
 }
 
 int find_sync_dirs(const char *srcarg,
-        char **android_srcdir_out, char **data_srcdir_out)
+        char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out)
 {
-    char *android_srcdir, *data_srcdir;
+    char *android_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL;
+    struct stat st;
 
     if(srcarg == NULL) {
         android_srcdir = product_file("system");
         data_srcdir = product_file("data");
+        vendor_srcdir = product_file("vendor");
+        /* Check if vendor partition exists */
+        if (lstat(vendor_srcdir, &st) || !S_ISDIR(st.st_mode))
+            vendor_srcdir = NULL;
     } else {
         /* srcarg may be "data", "system" or NULL.
          * if srcarg is NULL, then both data and system are synced
          */
         if(strcmp(srcarg, "system") == 0) {
             android_srcdir = product_file("system");
-            data_srcdir = NULL;
         } else if(strcmp(srcarg, "data") == 0) {
-            android_srcdir = NULL;
             data_srcdir = product_file("data");
+        } else if(strcmp(srcarg, "vendor") == 0) {
+            vendor_srcdir = product_file("vendor");
         } else {
-            /* It's not "system" or "data".
+            /* It's not "system", "vendor", or "data".
              */
             return 1;
         }
@@ -1619,11 +1783,15 @@
     else
         free(android_srcdir);
 
-    if(data_srcdir_out != NULL)
-        *data_srcdir_out = data_srcdir;
+    if(vendor_srcdir_out != NULL)
+        *vendor_srcdir_out = vendor_srcdir;
     else
-        free(data_srcdir);
+        free(vendor_srcdir);
 
+    if(data_srcdir_out != NULL)
+            *data_srcdir_out = data_srcdir;
+        else
+            free(data_srcdir);
     return 0;
 }
 
@@ -1635,12 +1803,9 @@
     snprintf(buf, sizeof(buf), "shell:pm");
 
     while(argc-- > 0) {
-        char *quoted;
-
-        quoted = dupAndQuote(*argv++);
-
-        strncat(buf, " ", sizeof(buf)-1);
-        strncat(buf, quoted, sizeof(buf)-1);
+        char *quoted = escape_arg(*argv++);
+        strncat(buf, " ", sizeof(buf) - 1);
+        strncat(buf, quoted, sizeof(buf) - 1);
         free(quoted);
     }
 
@@ -1672,7 +1837,7 @@
     char* quoted;
 
     snprintf(buf, sizeof(buf), "shell:rm ");
-    quoted = dupAndQuote(filename);
+    quoted = escape_arg(filename);
     strncat(buf, quoted, sizeof(buf)-1);
     free(quoted);
 
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index dc4e77f..c1ab808 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -25,6 +25,7 @@
 #include <limits.h>
 #include <sys/types.h>
 #include <zipfile/zipfile.h>
+#include <utime.h>
 
 #include "sysdeps.h"
 #include "adb.h"
@@ -139,7 +140,8 @@
 
 static syncsendbuf send_buffer;
 
-int sync_readtime(int fd, const char *path, unsigned *timestamp)
+int sync_readtime(int fd, const char *path, unsigned int *timestamp,
+                  unsigned int *mode)
 {
     syncmsg msg;
     int len = strlen(path);
@@ -161,6 +163,7 @@
     }
 
     *timestamp = ltohl(msg.stat.time);
+    *mode = ltohl(msg.stat.mode);
     return 0;
 }
 
@@ -237,7 +240,7 @@
     if (show_progress) {
         // Determine local file size.
         struct stat st;
-        if (lstat(path, &st)) {
+        if (fstat(lfd, &st)) {
             fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
             return -1;
         }
@@ -694,30 +697,33 @@
             continue;
         strcpy(stat_path, lpath);
         strcat(stat_path, de->d_name);
-        stat(stat_path, &st);
 
-        if (S_ISDIR(st.st_mode)) {
-            ci = mkcopyinfo(lpath, rpath, name, 1);
-            ci->next = dirlist;
-            dirlist = ci;
-        } else {
-            ci = mkcopyinfo(lpath, rpath, name, 0);
-            if(lstat(ci->src, &st)) {
-                fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
-                free(ci);
-                closedir(d);
-                return -1;
-            }
-            if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
-                fprintf(stderr, "skipping special file '%s'\n", ci->src);
-                free(ci);
+        if(!lstat(stat_path, &st)) {
+            if (S_ISDIR(st.st_mode)) {
+                ci = mkcopyinfo(lpath, rpath, name, 1);
+                ci->next = dirlist;
+                dirlist = ci;
             } else {
-                ci->time = st.st_mtime;
-                ci->mode = st.st_mode;
-                ci->size = st.st_size;
-                ci->next = *filelist;
-                *filelist = ci;
+                ci = mkcopyinfo(lpath, rpath, name, 0);
+                if(lstat(ci->src, &st)) {
+                    fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
+                    free(ci);
+                    closedir(d);
+                    return -1;
+                }
+                if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
+                    fprintf(stderr, "skipping special file '%s'\n", ci->src);
+                    free(ci);
+                } else {
+                    ci->time = st.st_mtime;
+                    ci->mode = st.st_mode;
+                    ci->size = st.st_size;
+                    ci->next = *filelist;
+                    *filelist = ci;
+                }
             }
+        } else {
+            fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
         }
     }
 
@@ -931,8 +937,21 @@
     return 0;
 }
 
+static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int mode)
+{
+    struct utimbuf times = { time, time };
+    int r1 = utime(lpath, &times);
+
+    /* use umask for permissions */
+    mode_t mask=umask(0000);
+    umask(mask);
+    int r2 = chmod(lpath, mode & ~mask);
+
+    return r1 ? : r2;
+}
+
 static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
-                                 int checktimestamps)
+                                 int copy_attrs)
 {
     copyinfo *filelist = 0;
     copyinfo *ci, *next;
@@ -962,26 +981,6 @@
         return -1;
     }
 
-#if 0
-    if (checktimestamps) {
-        for (ci = filelist; ci != 0; ci = ci->next) {
-            if (sync_start_readtime(fd, ci->dst)) {
-                return 1;
-            }
-        }
-        for (ci = filelist; ci != 0; ci = ci->next) {
-            unsigned int timestamp, mode, size;
-            if (sync_finish_readtime(fd, &timestamp, &mode, &size))
-                return 1;
-            if (size == ci->size) {
-                /* for links, we cannot update the atime/mtime */
-                if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
-                    (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
-                    ci->flag = 1;
-            }
-        }
-    }
-#endif
     for (ci = filelist; ci != 0; ci = next) {
         next = ci->next;
         if (ci->flag == 0) {
@@ -989,6 +988,10 @@
             if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
                 return 1;
             }
+
+            if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
+               return 1;
+            }
             pulled++;
         } else {
             skipped++;
@@ -1003,9 +1006,9 @@
     return 0;
 }
 
-int do_sync_pull(const char *rpath, const char *lpath, int show_progress)
+int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs)
 {
-    unsigned mode;
+    unsigned mode, time;
     struct stat st;
 
     int fd;
@@ -1016,7 +1019,7 @@
         return 1;
     }
 
-    if(sync_readmode(fd, rpath, &mode)) {
+    if(sync_readtime(fd, rpath, &time, &mode)) {
         return 1;
     }
     if(mode == 0) {
@@ -1047,13 +1050,15 @@
         if (sync_recv(fd, rpath, lpath, show_progress)) {
             return 1;
         } else {
+            if (copy_attrs && set_time_and_mode(lpath, time, mode))
+                return 1;
             END();
             sync_quit(fd);
             return 0;
         }
     } else if(S_ISDIR(mode)) {
         BEGIN();
-        if (copy_remote_dir_local(fd, rpath, lpath, 0)) {
+        if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
             return 1;
         } else {
             END();
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index 1d80d26..e6f64bb 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -39,6 +39,11 @@
     return (strncmp(SYSTEM, name, strlen(SYSTEM)) == 0);
 }
 
+static bool is_on_vendor(const char *name) {
+    const char *VENDOR = "/vendor/";
+    return (strncmp(VENDOR, name, strlen(VENDOR)) == 0);
+}
+
 static int mkdirs(char *name)
 {
     int ret;
@@ -54,7 +59,7 @@
         x = adb_dirstart(x);
         if(x == 0) return 0;
         *x = 0;
-        if (is_on_system(name)) {
+        if (is_on_system(name) || is_on_vendor(name)) {
             fs_config(name, 1, &uid, &gid, &mode, &cap);
         }
         ret = adb_mkdir(name, mode);
@@ -369,7 +374,7 @@
         if(*tmp == '/') {
             tmp++;
         }
-        if (is_on_system(path)) {
+        if (is_on_system(path) || is_on_vendor(path)) {
             fs_config(tmp, 0, &uid, &gid, &mode, &cap);
         }
         ret = handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 3e7e096..8ea239e 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -80,7 +80,7 @@
 int do_sync_ls(const char *path);
 int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress);
 int do_sync_sync(const char *lpath, const char *rpath, int listonly);
-int do_sync_pull(const char *rpath, const char *lpath, int show_progress);
+int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime);
 
 #define SYNC_DATA_MAX (64*1024)
 
diff --git a/adb/remount_service.c b/adb/remount_service.c
index d3a649b..fd81e28 100644
--- a/adb/remount_service.c
+++ b/adb/remount_service.c
@@ -29,6 +29,7 @@
 
 
 static int system_ro = 1;
+static int vendor_ro = 1;
 
 /* Returns the device used to mount a directory in /proc/mounts */
 static char *find_mount(const char *dir)
@@ -67,18 +68,27 @@
     return NULL;
 }
 
+static int hasVendorPartition()
+{
+    struct stat info;
+    if (!lstat("/vendor", &info))
+        if ((info.st_mode & S_IFMT) == S_IFDIR)
+          return true;
+    return false;
+}
+
 /* Init mounts /system as read only, remount to enable writes. */
-static int remount_system()
+static int remount(const char* dir, int* dir_ro)
 {
     char *dev;
     int fd;
     int OFF = 0;
 
-    if (system_ro == 0) {
+    if (dir_ro == 0) {
         return 0;
     }
 
-    dev = find_mount("/system");
+    dev = find_mount(dir);
 
     if (!dev)
         return -1;
@@ -90,11 +100,11 @@
     ioctl(fd, BLKROSET, &OFF);
     adb_close(fd);
 
-    system_ro = mount(dev, "/system", "none", MS_REMOUNT, NULL);
+    *dir_ro = mount(dev, dir, "none", MS_REMOUNT, NULL);
 
     free(dev);
 
-    return system_ro;
+    return *dir_ro;
 }
 
 static void write_string(int fd, const char* str)
@@ -104,16 +114,25 @@
 
 void remount_service(int fd, void *cookie)
 {
-    int ret = remount_system();
-
-    if (!ret)
-       write_string(fd, "remount succeeded\n");
-    else {
-        char    buffer[200];
-        snprintf(buffer, sizeof(buffer), "remount failed: %s\n", strerror(errno));
+    char buffer[200];
+    if (remount("/system", &system_ro)) {
+        snprintf(buffer, sizeof(buffer), "remount of system failed: %s\n",strerror(errno));
         write_string(fd, buffer);
     }
 
+    if (hasVendorPartition()) {
+        if (remount("/vendor", &vendor_ro)) {
+            snprintf(buffer, sizeof(buffer), "remount of vendor failed: %s\n",strerror(errno));
+            write_string(fd, buffer);
+        }
+    }
+
+    if (!system_ro && (!vendor_ro || !hasVendorPartition()))
+        write_string(fd, "remount succeeded\n");
+    else {
+        write_string(fd, "remount failed\n");
+    }
+
     adb_close(fd);
 }
 
diff --git a/adb/services.c b/adb/services.c
index 7b809da..e48e460 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -184,11 +184,26 @@
 }
 
 #if !ADB_HOST
-static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+
+static void init_subproc_child()
 {
+    setsid();
+
+    // Set OOM score adjustment to prevent killing
+    int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY);
+    if (fd >= 0) {
+        adb_write(fd, "0", 1);
+        adb_close(fd);
+    } else {
+       D("adb: unable to update oom_score_adj\n");
+    }
+}
+
+static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+{
+    D("create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
 #ifdef HAVE_WIN32_PROC
-    D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
-    fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
+    fprintf(stderr, "error: create_subproc_pty not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
     return -1;
 #else /* !HAVE_WIN32_PROC */
     char *devname;
@@ -215,47 +230,74 @@
         return -1;
     }
 
-    if(*pid == 0){
-        int pts;
+    if (*pid == 0) {
+        init_subproc_child();
 
-        setsid();
-
-        pts = unix_open(devname, O_RDWR);
-        if(pts < 0) {
+        int pts = unix_open(devname, O_RDWR);
+        if (pts < 0) {
             fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
             exit(-1);
         }
 
-        dup2(pts, 0);
-        dup2(pts, 1);
-        dup2(pts, 2);
+        dup2(pts, STDIN_FILENO);
+        dup2(pts, STDOUT_FILENO);
+        dup2(pts, STDERR_FILENO);
 
         adb_close(pts);
         adb_close(ptm);
 
-        // set OOM adjustment to zero
-        char text[64];
-        snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
-        int fd = adb_open(text, O_WRONLY);
-        if (fd >= 0) {
-            adb_write(fd, "0", 1);
-            adb_close(fd);
-        } else {
-           D("adb: unable to open %s\n", text);
-        }
         execl(cmd, cmd, arg0, arg1, NULL);
         fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
                 cmd, strerror(errno), errno);
         exit(-1);
     } else {
-        // Don't set child's OOM adjustment to zero.
-        // Let the child do it itself, as sometimes the parent starts
-        // running before the child has a /proc/pid/oom_adj.
-        // """adb: unable to open /proc/644/oom_adj""" seen in some logs.
         return ptm;
     }
 #endif /* !HAVE_WIN32_PROC */
 }
+
+static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+{
+    D("create_subproc_raw(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
+#ifdef HAVE_WIN32_PROC
+    fprintf(stderr, "error: create_subproc_raw not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
+    return -1;
+#else /* !HAVE_WIN32_PROC */
+
+    // 0 is parent socket, 1 is child socket
+    int sv[2];
+    if (unix_socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
+        printf("[ cannot create socket pair - %s ]\n", strerror(errno));
+        return -1;
+    }
+
+    *pid = fork();
+    if (*pid < 0) {
+        printf("- fork failed: %s -\n", strerror(errno));
+        adb_close(sv[0]);
+        adb_close(sv[1]);
+        return -1;
+    }
+
+    if (*pid == 0) {
+        adb_close(sv[0]);
+        init_subproc_child();
+
+        // Only hook up stdin/stdout; drop stderr
+        dup2(sv[1], STDIN_FILENO);
+        dup2(sv[1], STDOUT_FILENO);
+        adb_close(sv[1]);
+
+        execl(cmd, cmd, arg0, arg1, NULL);
+        fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
+                cmd, strerror(errno), errno);
+        exit(-1);
+    } else {
+        adb_close(sv[1]);
+        return sv[0];
+    }
+#endif /* !HAVE_WIN32_PROC */
+}
 #endif  /* !ABD_HOST */
 
 #if ADB_HOST
@@ -296,18 +338,32 @@
     }
 }
 
-static int create_subproc_thread(const char *name)
+static int create_subproc_thread(const char *name, const subproc_mode mode)
 {
     stinfo *sti;
     adb_thread_t t;
     int ret_fd;
-    pid_t pid;
-    if(name) {
-        ret_fd = create_subprocess(SHELL_COMMAND, "-c", name, &pid);
+    pid_t pid = -1;
+
+    const char *arg0, *arg1;
+    if (name == 0 || *name == 0) {
+        arg0 = "-"; arg1 = 0;
     } else {
-        ret_fd = create_subprocess(SHELL_COMMAND, "-", 0, &pid);
+        arg0 = "-c"; arg1 = name;
     }
-    D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
+
+    switch (mode) {
+    case SUBPROC_PTY:
+        ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid);
+        break;
+    case SUBPROC_RAW:
+        ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid);
+        break;
+    default:
+        fprintf(stderr, "invalid subproc_mode %d\n", mode);
+        return -1;
+    }
+    D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid);
 
     sti = malloc(sizeof(stinfo));
     if(sti == 0) fatal("cannot allocate stinfo");
@@ -315,14 +371,14 @@
     sti->cookie = (void*) (uintptr_t) pid;
     sti->fd = ret_fd;
 
-    if(adb_thread_create( &t, service_bootstrap_func, sti)){
+    if (adb_thread_create(&t, service_bootstrap_func, sti)) {
         free(sti);
         adb_close(ret_fd);
-        printf("cannot create service thread\n");
+        fprintf(stderr, "cannot create service thread\n");
         return -1;
     }
 
-    D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
+    D("service thread started, fd=%d pid=%d\n", ret_fd, pid);
     return ret_fd;
 }
 #endif
@@ -367,27 +423,35 @@
     } else if (!strncmp(name, "jdwp:", 5)) {
         ret = create_jdwp_connection_fd(atoi(name+5));
     } else if(!HOST && !strncmp(name, "shell:", 6)) {
-        if(name[6]) {
-            ret = create_subproc_thread(name + 6);
-        } else {
-            ret = create_subproc_thread(0);
-        }
+        ret = create_subproc_thread(name + 6, SUBPROC_PTY);
+    } else if(!HOST && !strncmp(name, "exec:", 5)) {
+        ret = create_subproc_thread(name + 5, SUBPROC_RAW);
     } else if(!strncmp(name, "sync:", 5)) {
         ret = create_service_thread(file_sync_service, NULL);
     } else if(!strncmp(name, "remount:", 8)) {
         ret = create_service_thread(remount_service, NULL);
     } else if(!strncmp(name, "reboot:", 7)) {
         void* arg = strdup(name + 7);
-        if(arg == 0) return -1;
+        if (arg == NULL) return -1;
         ret = create_service_thread(reboot_service, arg);
     } else if(!strncmp(name, "root:", 5)) {
         ret = create_service_thread(restart_root_service, NULL);
     } else if(!strncmp(name, "backup:", 7)) {
-        char* arg = strdup(name+7);
+        char* arg = strdup(name + 7);
         if (arg == NULL) return -1;
-        ret = backup_service(BACKUP, arg);
+        char* c = arg;
+        for (; *c != '\0'; c++) {
+            if (*c == ':')
+                *c = ' ';
+        }
+        char* cmd;
+        if (asprintf(&cmd, "/system/bin/bu backup %s", arg) != -1) {
+            ret = create_subproc_thread(cmd, SUBPROC_RAW);
+            free(cmd);
+        }
+        free(arg);
     } else if(!strncmp(name, "restore:", 8)) {
-        ret = backup_service(RESTORE, NULL);
+        ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW);
     } else if(!strncmp(name, "tcpip:", 6)) {
         int port;
         if (sscanf(name + 6, "%d", &port) == 0) {
diff --git a/charger/Android.mk b/charger/Android.mk
deleted file mode 100644
index 40c7d78..0000000
--- a/charger/Android.mk
+++ /dev/null
@@ -1,61 +0,0 @@
-# Copyright 2011 The Android Open Source Project
-
-ifneq ($(BUILD_TINY_ANDROID),true)
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	charger.c
-
-ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
-LOCAL_CFLAGS := -DCHARGER_DISABLE_INIT_BLANK
-endif
-
-ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
-LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
-endif
-
-LOCAL_MODULE := charger
-LOCAL_MODULE_TAGS := optional
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
-LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
-
-LOCAL_C_INCLUDES := bootable/recovery
-
-LOCAL_STATIC_LIBRARIES := libminui libpng
-ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
-LOCAL_STATIC_LIBRARIES += libsuspend
-endif
-LOCAL_STATIC_LIBRARIES += libz libstdc++ libcutils liblog libm libc
-
-include $(BUILD_EXECUTABLE)
-
-define _add-charger-image
-include $$(CLEAR_VARS)
-LOCAL_MODULE := system_core_charger_$(notdir $(1))
-LOCAL_MODULE_STEM := $(notdir $(1))
-_img_modules += $$(LOCAL_MODULE)
-LOCAL_SRC_FILES := $1
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $$(TARGET_ROOT_OUT)/res/images/charger
-include $$(BUILD_PREBUILT)
-endef
-
-_img_modules :=
-_images :=
-$(foreach _img, $(call find-subdir-subdir-files, "images", "*.png"), \
-  $(eval $(call _add-charger-image,$(_img))))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := charger_res_images
-LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := $(_img_modules)
-include $(BUILD_PHONY_PACKAGE)
-
-_add-charger-image :=
-_img_modules :=
-
-endif
diff --git a/charger/charger.c b/charger/charger.c
deleted file mode 100644
index 15add87..0000000
--- a/charger/charger.c
+++ /dev/null
@@ -1,1026 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define DEBUG_UEVENTS
-#define CHARGER_KLOG_LEVEL 6
-
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/input.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/poll.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <sys/socket.h>
-#include <linux/netlink.h>
-
-#include <cutils/android_reboot.h>
-#include <cutils/klog.h>
-#include <cutils/list.h>
-#include <cutils/misc.h>
-#include <cutils/uevent.h>
-#include <cutils/properties.h>
-
-#ifdef CHARGER_ENABLE_SUSPEND
-#include <suspend/autosuspend.h>
-#endif
-
-#include "minui/minui.h"
-
-char *locale;
-
-#ifndef max
-#define max(a,b) ((a) > (b) ? (a) : (b))
-#endif
-
-#ifndef min
-#define min(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-#define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))
-
-#define MSEC_PER_SEC            (1000LL)
-#define NSEC_PER_MSEC           (1000000LL)
-
-#define BATTERY_UNKNOWN_TIME    (2 * MSEC_PER_SEC)
-#define POWER_ON_KEY_TIME       (2 * MSEC_PER_SEC)
-#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
-
-#define BATTERY_FULL_THRESH     95
-
-#define LAST_KMSG_PATH          "/proc/last_kmsg"
-#define LAST_KMSG_MAX_SZ        (32 * 1024)
-
-#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
-#define LOGI(x...) do { KLOG_INFO("charger", x); } while (0)
-#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
-
-struct key_state {
-    bool pending;
-    bool down;
-    int64_t timestamp;
-};
-
-struct power_supply {
-    struct listnode list;
-    char name[256];
-    char type[32];
-    bool online;
-    bool valid;
-    char cap_path[PATH_MAX];
-};
-
-struct frame {
-    int disp_time;
-    int min_capacity;
-    bool level_only;
-
-    gr_surface surface;
-};
-
-struct animation {
-    bool run;
-
-    struct frame *frames;
-    int cur_frame;
-    int num_frames;
-
-    int cur_cycle;
-    int num_cycles;
-
-    /* current capacity being animated */
-    int capacity;
-};
-
-struct charger {
-    int64_t next_screen_transition;
-    int64_t next_key_check;
-    int64_t next_pwr_check;
-
-    struct key_state keys[KEY_MAX + 1];
-    int uevent_fd;
-
-    struct listnode supplies;
-    int num_supplies;
-    int num_supplies_online;
-
-    struct animation *batt_anim;
-    gr_surface surf_unknown;
-
-    struct power_supply *battery;
-};
-
-struct uevent {
-    const char *action;
-    const char *path;
-    const char *subsystem;
-    const char *ps_name;
-    const char *ps_type;
-    const char *ps_online;
-};
-
-static struct frame batt_anim_frames[] = {
-    {
-        .disp_time = 750,
-        .min_capacity = 0,
-    },
-    {
-        .disp_time = 750,
-        .min_capacity = 20,
-    },
-    {
-        .disp_time = 750,
-        .min_capacity = 40,
-    },
-    {
-        .disp_time = 750,
-        .min_capacity = 60,
-    },
-    {
-        .disp_time = 750,
-        .min_capacity = 80,
-        .level_only = true,
-    },
-    {
-        .disp_time = 750,
-        .min_capacity = BATTERY_FULL_THRESH,
-    },
-};
-
-static struct animation battery_animation = {
-    .frames = batt_anim_frames,
-    .num_frames = ARRAY_SIZE(batt_anim_frames),
-    .num_cycles = 3,
-};
-
-static struct charger charger_state = {
-    .batt_anim = &battery_animation,
-};
-
-static int char_width;
-static int char_height;
-
-/* current time in milliseconds */
-static int64_t curr_time_ms(void)
-{
-    struct timespec tm;
-    clock_gettime(CLOCK_MONOTONIC, &tm);
-    return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
-}
-
-static void clear_screen(void)
-{
-    gr_color(0, 0, 0, 255);
-    gr_clear();
-}
-
-#define MAX_KLOG_WRITE_BUF_SZ 256
-
-static void dump_last_kmsg(void)
-{
-    char *buf;
-    char *ptr;
-    unsigned sz = 0;
-    int len;
-
-    LOGI("\n");
-    LOGI("*************** LAST KMSG ***************\n");
-    LOGI("\n");
-    buf = load_file(LAST_KMSG_PATH, &sz);
-    if (!buf || !sz) {
-        LOGI("last_kmsg not found. Cold reset?\n");
-        goto out;
-    }
-
-    len = min(sz, LAST_KMSG_MAX_SZ);
-    ptr = buf + (sz - len);
-
-    while (len > 0) {
-        int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
-        char yoink;
-        char *nl;
-
-        nl = memrchr(ptr, '\n', cnt - 1);
-        if (nl)
-            cnt = nl - ptr + 1;
-
-        yoink = ptr[cnt];
-        ptr[cnt] = '\0';
-        klog_write(6, "<6>%s", ptr);
-        ptr[cnt] = yoink;
-
-        len -= cnt;
-        ptr += cnt;
-    }
-
-    free(buf);
-
-out:
-    LOGI("\n");
-    LOGI("************* END LAST KMSG *************\n");
-    LOGI("\n");
-}
-
-static int read_file(const char *path, char *buf, size_t sz)
-{
-    int fd;
-    size_t cnt;
-
-    fd = open(path, O_RDONLY, 0);
-    if (fd < 0)
-        goto err;
-
-    cnt = read(fd, buf, sz - 1);
-    if (cnt <= 0)
-        goto err;
-    buf[cnt] = '\0';
-    if (buf[cnt - 1] == '\n') {
-        cnt--;
-        buf[cnt] = '\0';
-    }
-
-    close(fd);
-    return cnt;
-
-err:
-    if (fd >= 0)
-        close(fd);
-    return -1;
-}
-
-static int read_file_int(const char *path, int *val)
-{
-    char buf[32];
-    int ret;
-    int tmp;
-    char *end;
-
-    ret = read_file(path, buf, sizeof(buf));
-    if (ret < 0)
-        return -1;
-
-    tmp = strtol(buf, &end, 0);
-    if (end == buf ||
-        ((end < buf+sizeof(buf)) && (*end != '\n' && *end != '\0')))
-        goto err;
-
-    *val = tmp;
-    return 0;
-
-err:
-    return -1;
-}
-
-static int get_battery_capacity(struct charger *charger)
-{
-    int ret;
-    int batt_cap = -1;
-
-    if (!charger->battery)
-        return -1;
-
-    ret = read_file_int(charger->battery->cap_path, &batt_cap);
-    if (ret < 0 || batt_cap > 100) {
-        batt_cap = -1;
-    }
-
-    return batt_cap;
-}
-
-static struct power_supply *find_supply(struct charger *charger,
-                                        const char *name)
-{
-    struct listnode *node;
-    struct power_supply *supply;
-
-    list_for_each(node, &charger->supplies) {
-        supply = node_to_item(node, struct power_supply, list);
-        if (!strncmp(name, supply->name, sizeof(supply->name)))
-            return supply;
-    }
-    return NULL;
-}
-
-static struct power_supply *add_supply(struct charger *charger,
-                                       const char *name, const char *type,
-                                       const char *path, bool online)
-{
-    struct power_supply *supply;
-
-    supply = calloc(1, sizeof(struct power_supply));
-    if (!supply)
-        return NULL;
-
-    strlcpy(supply->name, name, sizeof(supply->name));
-    strlcpy(supply->type, type, sizeof(supply->type));
-    snprintf(supply->cap_path, sizeof(supply->cap_path),
-             "/sys/%s/capacity", path);
-    supply->online = online;
-    list_add_tail(&charger->supplies, &supply->list);
-    charger->num_supplies++;
-    LOGV("... added %s %s %d\n", supply->name, supply->type, online);
-    return supply;
-}
-
-static void remove_supply(struct charger *charger, struct power_supply *supply)
-{
-    if (!supply)
-        return;
-    list_remove(&supply->list);
-    charger->num_supplies--;
-    free(supply);
-}
-
-#ifdef CHARGER_ENABLE_SUSPEND
-static int request_suspend(bool enable)
-{
-    if (enable)
-        return autosuspend_enable();
-    else
-        return autosuspend_disable();
-}
-#else
-static int request_suspend(bool enable)
-{
-    return 0;
-}
-#endif
-
-static void parse_uevent(const char *msg, struct uevent *uevent)
-{
-    uevent->action = "";
-    uevent->path = "";
-    uevent->subsystem = "";
-    uevent->ps_name = "";
-    uevent->ps_online = "";
-    uevent->ps_type = "";
-
-    /* currently ignoring SEQNUM */
-    while (*msg) {
-#ifdef DEBUG_UEVENTS
-        LOGV("uevent str: %s\n", msg);
-#endif
-        if (!strncmp(msg, "ACTION=", 7)) {
-            msg += 7;
-            uevent->action = msg;
-        } else if (!strncmp(msg, "DEVPATH=", 8)) {
-            msg += 8;
-            uevent->path = msg;
-        } else if (!strncmp(msg, "SUBSYSTEM=", 10)) {
-            msg += 10;
-            uevent->subsystem = msg;
-        } else if (!strncmp(msg, "POWER_SUPPLY_NAME=", 18)) {
-            msg += 18;
-            uevent->ps_name = msg;
-        } else if (!strncmp(msg, "POWER_SUPPLY_ONLINE=", 20)) {
-            msg += 20;
-            uevent->ps_online = msg;
-        } else if (!strncmp(msg, "POWER_SUPPLY_TYPE=", 18)) {
-            msg += 18;
-            uevent->ps_type = msg;
-        }
-
-        /* advance to after the next \0 */
-        while (*msg++)
-            ;
-    }
-
-    LOGV("event { '%s', '%s', '%s', '%s', '%s', '%s' }\n",
-         uevent->action, uevent->path, uevent->subsystem,
-         uevent->ps_name, uevent->ps_type, uevent->ps_online);
-}
-
-static void process_ps_uevent(struct charger *charger, struct uevent *uevent)
-{
-    int online;
-    char ps_type[32];
-    struct power_supply *supply = NULL;
-    int i;
-    bool was_online = false;
-    bool battery = false;
-
-    if (uevent->ps_type[0] == '\0') {
-        char *path;
-        int ret;
-
-        if (uevent->path[0] == '\0')
-            return;
-        ret = asprintf(&path, "/sys/%s/type", uevent->path);
-        if (ret <= 0)
-            return;
-        ret = read_file(path, ps_type, sizeof(ps_type));
-        free(path);
-        if (ret < 0)
-            return;
-    } else {
-        strlcpy(ps_type, uevent->ps_type, sizeof(ps_type));
-    }
-
-    if (!strncmp(ps_type, "Battery", 7))
-        battery = true;
-
-    online = atoi(uevent->ps_online);
-    supply = find_supply(charger, uevent->ps_name);
-    if (supply) {
-        was_online = supply->online;
-        supply->online = online;
-    }
-
-    if (!strcmp(uevent->action, "add")) {
-        if (!supply) {
-            supply = add_supply(charger, uevent->ps_name, ps_type, uevent->path,
-                                online);
-            if (!supply) {
-                LOGE("cannot add supply '%s' (%s %d)\n", uevent->ps_name,
-                     uevent->ps_type, online);
-                return;
-            }
-            /* only pick up the first battery for now */
-            if (battery && !charger->battery)
-                charger->battery = supply;
-        } else {
-            LOGE("supply '%s' already exists..\n", uevent->ps_name);
-        }
-    } else if (!strcmp(uevent->action, "remove")) {
-        if (supply) {
-            if (charger->battery == supply)
-                charger->battery = NULL;
-            remove_supply(charger, supply);
-            supply = NULL;
-        }
-    } else if (!strcmp(uevent->action, "change")) {
-        if (!supply) {
-            LOGE("power supply '%s' not found ('%s' %d)\n",
-                 uevent->ps_name, ps_type, online);
-            return;
-        }
-    } else {
-        return;
-    }
-
-    /* allow battery to be managed in the supply list but make it not
-     * contribute to online power supplies. */
-    if (!battery) {
-        if (was_online && !online)
-            charger->num_supplies_online--;
-        else if (supply && !was_online && online)
-            charger->num_supplies_online++;
-    }
-
-    LOGI("power supply %s (%s) %s (action=%s num_online=%d num_supplies=%d)\n",
-         uevent->ps_name, ps_type, battery ? "" : online ? "online" : "offline",
-         uevent->action, charger->num_supplies_online, charger->num_supplies);
-}
-
-static void process_uevent(struct charger *charger, struct uevent *uevent)
-{
-    if (!strcmp(uevent->subsystem, "power_supply"))
-        process_ps_uevent(charger, uevent);
-}
-
-#define UEVENT_MSG_LEN  1024
-static int handle_uevent_fd(struct charger *charger, int fd)
-{
-    char msg[UEVENT_MSG_LEN+2];
-    int n;
-
-    if (fd < 0)
-        return -1;
-
-    while (true) {
-        struct uevent uevent;
-
-        n = uevent_kernel_multicast_recv(fd, msg, UEVENT_MSG_LEN);
-        if (n <= 0)
-            break;
-        if (n >= UEVENT_MSG_LEN)   /* overflow -- discard */
-            continue;
-
-        msg[n] = '\0';
-        msg[n+1] = '\0';
-
-        parse_uevent(msg, &uevent);
-        process_uevent(charger, &uevent);
-    }
-
-    return 0;
-}
-
-static int uevent_callback(int fd, short revents, void *data)
-{
-    struct charger *charger = data;
-
-    if (!(revents & POLLIN))
-        return -1;
-    return handle_uevent_fd(charger, fd);
-}
-
-/* force the kernel to regenerate the change events for the existing
- * devices, if valid */
-static void do_coldboot(struct charger *charger, DIR *d, const char *event,
-                        bool follow_links, int max_depth)
-{
-    struct dirent *de;
-    int dfd, fd;
-
-    dfd = dirfd(d);
-
-    fd = openat(dfd, "uevent", O_WRONLY);
-    if (fd >= 0) {
-        write(fd, event, strlen(event));
-        close(fd);
-        handle_uevent_fd(charger, charger->uevent_fd);
-    }
-
-    while ((de = readdir(d)) && max_depth > 0) {
-        DIR *d2;
-
-        LOGV("looking at '%s'\n", de->d_name);
-
-        if ((de->d_type != DT_DIR && !(de->d_type == DT_LNK && follow_links)) ||
-           de->d_name[0] == '.') {
-            LOGV("skipping '%s' type %d (depth=%d follow=%d)\n",
-                 de->d_name, de->d_type, max_depth, follow_links);
-            continue;
-        }
-        LOGV("can descend into '%s'\n", de->d_name);
-
-        fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
-        if (fd < 0) {
-            LOGE("cannot openat %d '%s' (%d: %s)\n", dfd, de->d_name,
-                 errno, strerror(errno));
-            continue;
-        }
-
-        d2 = fdopendir(fd);
-        if (d2 == 0)
-            close(fd);
-        else {
-            LOGV("opened '%s'\n", de->d_name);
-            do_coldboot(charger, d2, event, follow_links, max_depth - 1);
-            closedir(d2);
-        }
-    }
-}
-
-static void coldboot(struct charger *charger, const char *path,
-                     const char *event)
-{
-    char str[256];
-
-    LOGV("doing coldboot '%s' in '%s'\n", event, path);
-    DIR *d = opendir(path);
-    if (d) {
-        snprintf(str, sizeof(str), "%s\n", event);
-        do_coldboot(charger, d, str, true, 1);
-        closedir(d);
-    }
-}
-
-static int draw_text(const char *str, int x, int y)
-{
-    int str_len_px = gr_measure(str);
-
-    if (x < 0)
-        x = (gr_fb_width() - str_len_px) / 2;
-    if (y < 0)
-        y = (gr_fb_height() - char_height) / 2;
-    gr_text(x, y, str, 0);
-
-    return y + char_height;
-}
-
-static void android_green(void)
-{
-    gr_color(0xa4, 0xc6, 0x39, 255);
-}
-
-/* returns the last y-offset of where the surface ends */
-static int draw_surface_centered(struct charger *charger, gr_surface surface)
-{
-    int w;
-    int h;
-    int x;
-    int y;
-
-    w = gr_get_width(surface);
-    h = gr_get_height(surface);
-    x = (gr_fb_width() - w) / 2 ;
-    y = (gr_fb_height() - h) / 2 ;
-
-    LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
-    gr_blit(surface, 0, 0, w, h, x, y);
-    return y + h;
-}
-
-static void draw_unknown(struct charger *charger)
-{
-    int y;
-    if (charger->surf_unknown) {
-        draw_surface_centered(charger, charger->surf_unknown);
-    } else {
-        android_green();
-        y = draw_text("Charging!", -1, -1);
-        draw_text("?\?/100", -1, y + 25);
-    }
-}
-
-static void draw_battery(struct charger *charger)
-{
-    struct animation *batt_anim = charger->batt_anim;
-    struct frame *frame = &batt_anim->frames[batt_anim->cur_frame];
-
-    if (batt_anim->num_frames != 0) {
-        draw_surface_centered(charger, frame->surface);
-        LOGV("drawing frame #%d min_cap=%d time=%d\n",
-             batt_anim->cur_frame, frame->min_capacity,
-             frame->disp_time);
-    }
-}
-
-static void redraw_screen(struct charger *charger)
-{
-    struct animation *batt_anim = charger->batt_anim;
-
-    clear_screen();
-
-    /* try to display *something* */
-    if (batt_anim->capacity < 0 || batt_anim->num_frames == 0)
-        draw_unknown(charger);
-    else
-        draw_battery(charger);
-    gr_flip();
-}
-
-static void kick_animation(struct animation *anim)
-{
-    anim->run = true;
-}
-
-static void reset_animation(struct animation *anim)
-{
-    anim->cur_cycle = 0;
-    anim->cur_frame = 0;
-    anim->run = false;
-}
-
-static void update_screen_state(struct charger *charger, int64_t now)
-{
-    struct animation *batt_anim = charger->batt_anim;
-    int cur_frame;
-    int disp_time;
-
-    if (!batt_anim->run || now < charger->next_screen_transition)
-        return;
-
-    /* animation is over, blank screen and leave */
-    if (batt_anim->cur_cycle == batt_anim->num_cycles) {
-        reset_animation(batt_anim);
-        charger->next_screen_transition = -1;
-        gr_fb_blank(true);
-        LOGV("[%lld] animation done\n", now);
-        if (charger->num_supplies_online > 0)
-            request_suspend(true);
-        return;
-    }
-
-    disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time;
-
-    /* animation starting, set up the animation */
-    if (batt_anim->cur_frame == 0) {
-        int batt_cap;
-        int ret;
-
-        LOGV("[%lld] animation starting\n", now);
-        batt_cap = get_battery_capacity(charger);
-        if (batt_cap >= 0 && batt_anim->num_frames != 0) {
-            int i;
-
-            /* find first frame given current capacity */
-            for (i = 1; i < batt_anim->num_frames; i++) {
-                if (batt_cap < batt_anim->frames[i].min_capacity)
-                    break;
-            }
-            batt_anim->cur_frame = i - 1;
-
-            /* show the first frame for twice as long */
-            disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2;
-        }
-
-        batt_anim->capacity = batt_cap;
-    }
-
-    /* unblank the screen  on first cycle */
-    if (batt_anim->cur_cycle == 0)
-        gr_fb_blank(false);
-
-    /* draw the new frame (@ cur_frame) */
-    redraw_screen(charger);
-
-    /* if we don't have anim frames, we only have one image, so just bump
-     * the cycle counter and exit
-     */
-    if (batt_anim->num_frames == 0 || batt_anim->capacity < 0) {
-        LOGV("[%lld] animation missing or unknown battery status\n", now);
-        charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;
-        batt_anim->cur_cycle++;
-        return;
-    }
-
-    /* schedule next screen transition */
-    charger->next_screen_transition = now + disp_time;
-
-    /* advance frame cntr to the next valid frame
-     * if necessary, advance cycle cntr, and reset frame cntr
-     */
-    batt_anim->cur_frame++;
-
-    /* if the frame is used for level-only, that is only show it when it's
-     * the current level, skip it during the animation.
-     */
-    while (batt_anim->cur_frame < batt_anim->num_frames &&
-           batt_anim->frames[batt_anim->cur_frame].level_only)
-        batt_anim->cur_frame++;
-    if (batt_anim->cur_frame >= batt_anim->num_frames) {
-        batt_anim->cur_cycle++;
-        batt_anim->cur_frame = 0;
-
-        /* don't reset the cycle counter, since we use that as a signal
-         * in a test above to check if animation is over
-         */
-    }
-}
-
-static int set_key_callback(int code, int value, void *data)
-{
-    struct charger *charger = data;
-    int64_t now = curr_time_ms();
-    int down = !!value;
-
-    if (code > KEY_MAX)
-        return -1;
-
-    /* ignore events that don't modify our state */
-    if (charger->keys[code].down == down)
-        return 0;
-
-    /* only record the down even timestamp, as the amount
-     * of time the key spent not being pressed is not useful */
-    if (down)
-        charger->keys[code].timestamp = now;
-    charger->keys[code].down = down;
-    charger->keys[code].pending = true;
-    if (down) {
-        LOGV("[%lld] key[%d] down\n", now, code);
-    } else {
-        int64_t duration = now - charger->keys[code].timestamp;
-        int64_t secs = duration / 1000;
-        int64_t msecs = duration - secs * 1000;
-        LOGV("[%lld] key[%d] up (was down for %lld.%lldsec)\n", now,
-            code, secs, msecs);
-    }
-
-    return 0;
-}
-
-static void update_input_state(struct charger *charger,
-                               struct input_event *ev)
-{
-    if (ev->type != EV_KEY)
-        return;
-    set_key_callback(ev->code, ev->value, charger);
-}
-
-static void set_next_key_check(struct charger *charger,
-                               struct key_state *key,
-                               int64_t timeout)
-{
-    int64_t then = key->timestamp + timeout;
-
-    if (charger->next_key_check == -1 || then < charger->next_key_check)
-        charger->next_key_check = then;
-}
-
-static void process_key(struct charger *charger, int code, int64_t now)
-{
-    struct key_state *key = &charger->keys[code];
-    int64_t next_key_check;
-
-    if (code == KEY_POWER) {
-        if (key->down) {
-            int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
-            if (now >= reboot_timeout) {
-                /* We do not currently support booting from charger mode on
-                   all devices. Check the property and continue booting or reboot
-                   accordingly. */
-                if (property_get_bool("ro.enable_boot_charger_mode", false)) {
-                    LOGI("[%lld] booting from charger mode\n", now);
-                    property_set("sys.boot_from_charger_mode", "1");
-                } else {
-                    LOGI("[%lld] rebooting\n", now);
-                    android_reboot(ANDROID_RB_RESTART, 0, 0);
-                }
-            } else {
-                /* if the key is pressed but timeout hasn't expired,
-                 * make sure we wake up at the right-ish time to check
-                 */
-                set_next_key_check(charger, key, POWER_ON_KEY_TIME);
-            }
-        } else {
-            /* if the power key got released, force screen state cycle */
-            if (key->pending) {
-                request_suspend(false);
-                kick_animation(charger->batt_anim);
-            }
-        }
-    }
-
-    key->pending = false;
-}
-
-static void handle_input_state(struct charger *charger, int64_t now)
-{
-    process_key(charger, KEY_POWER, now);
-
-    if (charger->next_key_check != -1 && now > charger->next_key_check)
-        charger->next_key_check = -1;
-}
-
-static void handle_power_supply_state(struct charger *charger, int64_t now)
-{
-    if (charger->num_supplies_online == 0) {
-        request_suspend(false);
-        if (charger->next_pwr_check == -1) {
-            charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
-            LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld)\n",
-                 now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
-        } else if (now >= charger->next_pwr_check) {
-            LOGI("[%lld] shutting down\n", now);
-            android_reboot(ANDROID_RB_POWEROFF, 0, 0);
-        } else {
-            /* otherwise we already have a shutdown timer scheduled */
-        }
-    } else {
-        /* online supply present, reset shutdown timer if set */
-        if (charger->next_pwr_check != -1) {
-            LOGI("[%lld] device plugged in: shutdown cancelled\n", now);
-            kick_animation(charger->batt_anim);
-        }
-        charger->next_pwr_check = -1;
-    }
-}
-
-static void wait_next_event(struct charger *charger, int64_t now)
-{
-    int64_t next_event = INT64_MAX;
-    int64_t timeout;
-    struct input_event ev;
-    int ret;
-
-    LOGV("[%lld] next screen: %lld next key: %lld next pwr: %lld\n", now,
-         charger->next_screen_transition, charger->next_key_check,
-         charger->next_pwr_check);
-
-    if (charger->next_screen_transition != -1)
-        next_event = charger->next_screen_transition;
-    if (charger->next_key_check != -1 && charger->next_key_check < next_event)
-        next_event = charger->next_key_check;
-    if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
-        next_event = charger->next_pwr_check;
-
-    if (next_event != -1 && next_event != INT64_MAX)
-        timeout = max(0, next_event - now);
-    else
-        timeout = -1;
-    LOGV("[%lld] blocking (%lld)\n", now, timeout);
-    ret = ev_wait((int)timeout);
-    if (!ret)
-        ev_dispatch();
-}
-
-static int input_callback(int fd, short revents, void *data)
-{
-    struct charger *charger = data;
-    struct input_event ev;
-    int ret;
-
-    ret = ev_get_input(fd, revents, &ev);
-    if (ret)
-        return -1;
-    update_input_state(charger, &ev);
-    return 0;
-}
-
-static void event_loop(struct charger *charger)
-{
-    int ret;
-
-    while (true) {
-        int64_t now = curr_time_ms();
-
-        LOGV("[%lld] event_loop()\n", now);
-        handle_input_state(charger, now);
-        handle_power_supply_state(charger, now);
-
-        /* do screen update last in case any of the above want to start
-         * screen transitions (animations, etc)
-         */
-        update_screen_state(charger, now);
-
-        wait_next_event(charger, now);
-    }
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-    struct charger *charger = &charger_state;
-    int64_t now = curr_time_ms() - 1;
-    int fd;
-    int i;
-
-    list_init(&charger->supplies);
-
-    klog_init();
-    klog_set_level(CHARGER_KLOG_LEVEL);
-
-    dump_last_kmsg();
-
-    LOGI("--------------- STARTING CHARGER MODE ---------------\n");
-
-    gr_init();
-    gr_font_size(&char_width, &char_height);
-
-    ev_init(input_callback, charger);
-
-    fd = uevent_open_socket(64*1024, true);
-    if (fd >= 0) {
-        fcntl(fd, F_SETFL, O_NONBLOCK);
-        ev_add_fd(fd, uevent_callback, charger);
-    }
-    charger->uevent_fd = fd;
-    coldboot(charger, "/sys/class/power_supply", "add");
-
-    ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
-    if (ret < 0) {
-        LOGE("Cannot load battery_fail image\n");
-        charger->surf_unknown = NULL;
-    }
-
-    charger->batt_anim = &battery_animation;
-
-    gr_surface* scale_frames;
-    int scale_count;
-    ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames);
-    if (ret < 0) {
-        LOGE("Cannot load battery_scale image\n");
-        charger->batt_anim->num_frames = 0;
-        charger->batt_anim->num_cycles = 1;
-    } else if (scale_count != charger->batt_anim->num_frames) {
-        LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
-             scale_count, charger->batt_anim->num_frames);
-        charger->batt_anim->num_frames = 0;
-        charger->batt_anim->num_cycles = 1;
-    } else {
-        for (i = 0; i < charger->batt_anim->num_frames; i++) {
-            charger->batt_anim->frames[i].surface = scale_frames[i];
-        }
-    }
-
-    ev_sync_key_state(set_key_callback, charger);
-
-#ifndef CHARGER_DISABLE_INIT_BLANK
-    gr_fb_blank(true);
-#endif
-
-    charger->next_screen_transition = now - 1;
-    charger->next_key_check = -1;
-    charger->next_pwr_check = -1;
-    reset_animation(charger->batt_anim);
-    kick_animation(charger->batt_anim);
-
-    event_loop(charger);
-
-    return 0;
-}
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 73794a0..252db6c 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -17,7 +17,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
-  $(LOCAL_PATH)/../../extras/ext4_utils
+  $(LOCAL_PATH)/../../extras/ext4_utils \
+  $(LOCAL_PATH)/../../extras/f2fs_utils
 LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c fs.c
 LOCAL_MODULE := fastboot
 LOCAL_MODULE_TAGS := debug
@@ -62,10 +63,24 @@
 LOCAL_STATIC_LIBRARIES += libselinux
 endif # HOST_OS != windows
 
+ifeq ($(HOST_OS),linux)
+# libf2fs_dlutils_host will dlopen("libf2fs_fmt_host_dyn")
+LOCAL_CFLAGS += -DUSE_F2FS
+LOCAL_LDFLAGS += -ldl -rdynamic -Wl,-rpath,.
+LOCAL_REQUIRED_MODULES := libf2fs_fmt_host_dyn
+# The following libf2fs_* are from system/extras/f2fs_utils,
+# and do not use code in external/f2fs-tools.
+LOCAL_STATIC_LIBRARIES += libf2fs_utils_host libf2fs_ioutils_host libf2fs_dlutils_host
+endif
+
 include $(BUILD_HOST_EXECUTABLE)
 
-
-$(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
+my_dist_files := $(LOCAL_BUILT_MODULE)
+ifeq ($(HOST_OS),linux)
+my_dist_files += $(HOST_LIBRARY_PATH)/libf2fs_fmt_host_dyn$(HOST_SHLIB_SUFFIX)
+endif
+$(call dist-for-goals,dist_files sdk,$(my_dist_files))
+my_dist_files :=
 
 
 ifeq ($(HOST_OS),linux)
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 266d0b5..64a52b5 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -99,10 +99,11 @@
     char sig_name[13];
     char part_name[9];
     bool is_optional;
-} images[4] = {
+} images[] = {
     {"boot.img", "boot.sig", "boot", false},
     {"recovery.img", "recovery.sig", "recovery", true},
     {"system.img", "system.sig", "system", false},
+    {"vendor.img", "vendor.sig", "vendor", true},
     {"tos.img", "tos.sig", "tos", true},
 };
 
@@ -120,6 +121,8 @@
         fn = "recovery.img";
     } else if(!strcmp(item,"system")) {
         fn = "system.img";
+    } else if(!strcmp(item,"vendor")) {
+        fn = "vendor.img";
     } else if(!strcmp(item,"tos")) {
         fn = "tos.img";
     } else if(!strcmp(item,"userdata")) {
@@ -287,7 +290,7 @@
             "\n"
             "commands:\n"
             "  update <filename>                        reflash device from update.zip\n"
-            "  flashall                                 flash boot, system, and if found,\n"
+            "  flashall                                 flash boot, system, vendor and if found,\n"
             "                                           recovery, tos\n"
             "  flash <partition> [ <filename> ]         write a file to a flash partition\n"
             "  erase <partition>                        erase a flash partition\n"
diff --git a/fastboot/fs.c b/fastboot/fs.c
index cd4b880..8a15e6f 100644
--- a/fastboot/fs.c
+++ b/fastboot/fs.c
@@ -1,5 +1,6 @@
 #include "fastboot.h"
 #include "make_ext4fs.h"
+#include "make_f2fs.h"
 #include "fs.h"
 
 #include <errno.h>
@@ -28,15 +29,23 @@
     return 0;
 }
 
+#ifdef USE_F2FS
+static int generate_f2fs_image(int fd, long long partSize)
+{
+    return make_f2fs_sparse_fd(fd, partSize, NULL, NULL);
+}
+#endif
+
 static const struct fs_generator {
 
     char *fs_type;  //must match what fastboot reports for partition type
     int (*generate)(int fd, long long partSize); //returns 0 or error value
 
 } generators[] = {
-
-    { "ext4", generate_ext4_image}
-
+    { "ext4", generate_ext4_image},
+#ifdef USE_F2FS
+    { "f2fs", generate_f2fs_image},
+#endif
 };
 
 const struct fs_generator* fs_get_generator(const char *fs_type)
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index dcda005..3f94af5 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -31,6 +31,7 @@
 
 #include <linux/loop.h>
 #include <private/android_filesystem_config.h>
+#include <cutils/android_reboot.h>
 #include <cutils/partition_utils.h>
 #include <cutils/properties.h>
 #include <logwrap/logwrap.h>
@@ -46,6 +47,7 @@
 #define KEY_IN_FOOTER  "footer"
 
 #define E2FSCK_BIN      "/system/bin/e2fsck"
+#define F2FS_FSCK_BIN  "/system/bin/fsck.f2fs"
 #define MKSWAP_BIN      "/system/bin/mkswap"
 
 #define FSCK_LOG_FILE   "/dev/fscklogs/log"
@@ -112,6 +114,7 @@
          * fix the filesystem.
          */
         ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
+        INFO("%s(): mount(%s,%s,%s)=%d\n", __func__, blk_device, target, fs_type, ret);
         if (!ret) {
             umount(target);
         }
@@ -135,6 +138,20 @@
                 ERROR("Failed trying to run %s\n", E2FSCK_BIN);
             }
         }
+    } else if (!strcmp(fs_type, "f2fs")) {
+            char *f2fs_fsck_argv[] = {
+                    F2FS_FSCK_BIN,
+                    blk_device
+            };
+        INFO("Running %s on %s\n", F2FS_FSCK_BIN, blk_device);
+
+        ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv,
+                                      &status, true, LOG_KLOG | LOG_FILE,
+                                      true, FSCK_LOG_FILE);
+        if (ret < 0) {
+            /* No need to check for error in fork, we can't really handle it now */
+            ERROR("Failed trying to run %s\n", F2FS_FSCK_BIN);
+        }
     }
 
     return;
@@ -175,16 +192,27 @@
  * sets the underlying block device to read-only if the mount is read-only.
  * See "man 2 mount" for return values.
  */
-static int __mount(const char *source, const char *target,
-                   const char *filesystemtype, unsigned long mountflags,
-                   const void *data)
+static int __mount(const char *source, const char *target, const struct fstab_rec *rec)
 {
-    int ret = mount(source, target, filesystemtype, mountflags, data);
+    unsigned long mountflags = rec->flags;
+    int ret;
+    int save_errno;
 
+    /* We need this because sometimes we have legacy symlinks
+     * that are lingering around and need cleaning up.
+     */
+    struct stat info;
+    if (!lstat(target, &info))
+        if ((info.st_mode & S_IFMT) == S_IFLNK)
+            unlink(target);
+    mkdir(target, 0755);
+    ret = mount(source, target, rec->fs_type, mountflags, rec->fs_options);
+    save_errno = errno;
+    INFO("%s(source=%s,target=%s,type=%s)=%d\n", __func__, source, target, rec->fs_type, ret);
     if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
         fs_set_blk_ro(source);
     }
-
+    errno = save_errno;
     return ret;
 }
 
@@ -208,16 +236,101 @@
     return ret;
 }
 
+static int device_is_debuggable() {
+    int ret = -1;
+    char value[PROP_VALUE_MAX];
+    ret = __system_property_get("ro.debuggable", value);
+    if (ret < 0)
+        return ret;
+    return strcmp(value, "1") ? 0 : 1;
+}
+
+/*
+ * Tries to mount any of the consecutive fstab entries that match
+ * the mountpoint of the one given by fstab->recs[start_idx].
+ *
+ * end_idx: On return, will be the last rec that was looked at.
+ * attempted_idx: On return, will indicate which fstab rec
+ *     succeeded. In case of failure, it will be the start_idx.
+ * Returns
+ *   -1 on failure with errno set to match the 1st mount failure.
+ *   0 on success.
+ */
+static int mount_with_alternatives(struct fstab *fstab, int start_idx, int *end_idx, int *attempted_idx)
+{
+    int i;
+    int mount_errno = 0;
+    int mounted = 0;
+
+    if (!end_idx || !attempted_idx || start_idx >= fstab->num_entries) {
+      errno = EINVAL;
+      if (end_idx) *end_idx = start_idx;
+      if (attempted_idx) *end_idx = start_idx;
+      return -1;
+    }
+
+    /* Hunt down an fstab entry for the same mount point that might succeed */
+    for (i = start_idx;
+         /* We required that fstab entries for the same mountpoint be consecutive */
+         i < fstab->num_entries && !strcmp(fstab->recs[start_idx].mount_point, fstab->recs[i].mount_point);
+         i++) {
+            /*
+             * Don't try to mount/encrypt the same mount point again.
+             * Deal with alternate entries for the same point which are required to be all following
+             * each other.
+             */
+            if (mounted) {
+                ERROR("%s(): skipping fstab dup mountpoint=%s rec[%d].fs_type=%s already mounted as %s.\n", __func__,
+                     fstab->recs[i].mount_point, i, fstab->recs[i].fs_type, fstab->recs[*attempted_idx].fs_type);
+                continue;
+            }
+
+            if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
+                check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
+                         fstab->recs[i].mount_point);
+            }
+            if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, &fstab->recs[i])) {
+                *attempted_idx = i;
+                mounted = 1;
+                if (i != start_idx) {
+                    ERROR("%s(): Mounted %s on %s with fs_type=%s instead of %s\n", __func__,
+                         fstab->recs[i].blk_device, fstab->recs[i].mount_point, fstab->recs[i].fs_type,
+                         fstab->recs[start_idx].fs_type);
+                }
+            } else {
+                /* back up errno for crypto decisions */
+                mount_errno = errno;
+            }
+    }
+
+    /* Adjust i for the case where it was still withing the recs[] */
+    if (i < fstab->num_entries) --i;
+
+    *end_idx = i;
+    if (!mounted) {
+        *attempted_idx = start_idx;
+        errno = mount_errno;
+        return -1;
+    }
+    return 0;
+}
+
+/* When multiple fstab records share the same mount_point, it will
+ * try to mount each one in turn, and ignore any duplicates after a
+ * first successful mount.
+ * Returns -1 on error, and  FS_MGR_MNTALL_* otherwise.
+ */
 int fs_mgr_mount_all(struct fstab *fstab)
 {
     int i = 0;
-    int encrypted = 0;
-    int ret = -1;
-    int mret;
-    int mount_errno;
+    int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
+    int error_count = 0;
+    int mret = -1;
+    int mount_errno = 0;
+    int attempted_idx = -1;
 
     if (!fstab) {
-        return ret;
+        return -1;
     }
 
     for (i = 0; i < fstab->num_entries; i++) {
@@ -237,70 +350,92 @@
             wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
         }
 
-        if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
-            check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
-                     fstab->recs[i].mount_point);
-        }
-
-        if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
+        if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) &&
+            !device_is_debuggable()) {
             if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
-                ERROR("Could not set up verified partition, skipping!");
+                ERROR("Could not set up verified partition, skipping!\n");
                 continue;
             }
         }
+        int last_idx_inspected;
+        mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx);
+        i = last_idx_inspected;
+        mount_errno = errno;
 
-        mret = __mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
-                     fstab->recs[i].fs_type, fstab->recs[i].flags,
-                     fstab->recs[i].fs_options);
-
+        /* Deal with encryptability. */
         if (!mret) {
+            /* If this is encryptable, need to trigger encryption */
+            if ((fstab->recs[attempted_idx].fs_mgr_flags & MF_FORCECRYPT)) {
+                if (umount(fstab->recs[attempted_idx].mount_point) == 0) {
+                    if (encryptable == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
+                        ERROR("Will try to encrypt %s %s\n", fstab->recs[attempted_idx].mount_point,
+                              fstab->recs[attempted_idx].fs_type);
+                        encryptable = FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION;
+                    } else {
+                        ERROR("Only one encryptable/encrypted partition supported\n");
+                        encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
+                    }
+                } else {
+                    INFO("Could not umount %s - allow continue unencrypted\n",
+                         fstab->recs[attempted_idx].mount_point);
+                    continue;
+                }
+            }
             /* Success!  Go get the next one */
             continue;
         }
 
-        /* back up errno as partition_wipe clobbers the value */
-        mount_errno = errno;
-
-        /* mount(2) returned an error, check if it's encrypted and deal with it */
-        if ((fstab->recs[i].fs_mgr_flags & MF_CRYPT) &&
-            !partition_wiped(fstab->recs[i].blk_device)) {
-            /* Need to mount a tmpfs at this mountpoint for now, and set
-             * properties that vold will query later for decrypting
-             */
-            if (mount("tmpfs", fstab->recs[i].mount_point, "tmpfs",
-                  MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) {
-                ERROR("Cannot mount tmpfs filesystem for encrypted fs at %s error: %s\n",
-                        fstab->recs[i].mount_point, strerror(errno));
-                goto out;
+        /* mount(2) returned an error, check if it's encryptable and deal with it */
+        if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
+            fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) {
+            if(partition_wiped(fstab->recs[attempted_idx].blk_device)) {
+                ERROR("%s(): %s is wiped and %s %s is encryptable. Suggest recovery...\n", __func__,
+                      fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+                      fstab->recs[attempted_idx].fs_type);
+                encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY;
+                continue;
+            } else {
+                /* Need to mount a tmpfs at this mountpoint for now, and set
+                 * properties that vold will query later for decrypting
+                 */
+                ERROR("%s(): possibly an encryptable blkdev %s for mount %s type %s )\n", __func__,
+                      fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+                      fstab->recs[attempted_idx].fs_type);
+                if (fs_mgr_do_tmpfs_mount(fstab->recs[attempted_idx].mount_point) < 0) {
+                    ++error_count;
+                    continue;
+                }
             }
-            encrypted = 1;
+            encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
         } else {
             ERROR("Failed to mount an un-encryptable or wiped partition on"
-                    "%s at %s options: %s error: %s\n",
-                    fstab->recs[i].blk_device, fstab->recs[i].mount_point,
-                    fstab->recs[i].fs_options, strerror(mount_errno));
-            goto out;
+                   "%s at %s options: %s error: %s\n",
+                   fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+                   fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
+            ++error_count;
+            continue;
         }
     }
 
-    if (encrypted) {
-        ret = 1;
+    if (error_count) {
+        return -1;
     } else {
-        ret = 0;
+        return encryptable;
     }
-
-out:
-    return ret;
 }
 
 /* If tmp_mount_point is non-null, mount the filesystem there.  This is for the
  * tmp mount we do to check the user password
+ * If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
+ * in turn, and stop on 1st success, or no more match.
  */
 int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
                     char *tmp_mount_point)
 {
     int i = 0;
     int ret = -1;
+    int mount_errors = 0;
+    int first_mount_errno = 0;
     char *m;
 
     if (!fstab) {
@@ -332,9 +467,10 @@
                      fstab->recs[i].mount_point);
         }
 
-        if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
+        if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) &&
+            !device_is_debuggable()) {
             if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
-                ERROR("Could not set up verified partition, skipping!");
+                ERROR("Could not set up verified partition, skipping!\n");
                 continue;
             }
         }
@@ -345,19 +481,23 @@
         } else {
             m = fstab->recs[i].mount_point;
         }
-        if (__mount(n_blk_device, m, fstab->recs[i].fs_type,
-                    fstab->recs[i].flags, fstab->recs[i].fs_options)) {
-            ERROR("Cannot mount filesystem on %s at %s options: %s error: %s\n",
-                n_blk_device, m, fstab->recs[i].fs_options, strerror(errno));
-            goto out;
+        if (__mount(n_blk_device, m, &fstab->recs[i])) {
+            if (!first_mount_errno) first_mount_errno = errno;
+            mount_errors++;
+            continue;
         } else {
             ret = 0;
             goto out;
         }
     }
-
-    /* We didn't find a match, say so and return an error */
-    ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
+    if (mount_errors) {
+        ERROR("Cannot mount filesystem on %s at %s. error: %s\n",
+            n_blk_device, m, strerror(first_mount_errno));
+        ret = -1;
+    } else {
+        /* We didn't find a match, say so and return an error */
+        ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
+    }
 
 out:
     return ret;
@@ -437,7 +577,7 @@
 
             zram_fp = fopen(ZRAM_CONF_DEV, "r+");
             if (zram_fp == NULL) {
-                ERROR("Unable to open zram conf device " ZRAM_CONF_DEV);
+                ERROR("Unable to open zram conf device %s\n", ZRAM_CONF_DEV);
                 ret = -1;
                 continue;
             }
@@ -504,7 +644,7 @@
         if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
             continue;
         }
-        if (!(fstab->recs[i].fs_mgr_flags & MF_CRYPT)) {
+        if (!(fstab->recs[i].fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT))) {
             continue;
         }
 
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index f86fc6a..3f84179 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -59,6 +59,7 @@
     { "wait",        MF_WAIT },
     { "check",       MF_CHECK },
     { "encryptable=",MF_CRYPT },
+    { "forceencrypt=",MF_FORCECRYPT },
     { "nonremovable",MF_NONREMOVABLE },
     { "voldmanaged=",MF_VOLDMANAGED},
     { "length=",     MF_LENGTH },
@@ -106,6 +107,11 @@
                      * location of the keys.  Get it and return it.
                      */
                     flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+                } else if ((fl[i].flag == MF_FORCECRYPT) && flag_vals) {
+                    /* The forceencrypt flag is followed by an = and the
+                     * location of the keys.  Get it and return it.
+                     */
+                    flag_vals->key_loc = strdup(strchr(p, '=') + 1);
                 } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
                     /* The length flag is followed by an = and the
                      * size of the partition.  Get it and return it.
@@ -361,25 +367,47 @@
      return 0;
 }
 
-struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
+/*
+ * Returns the 1st matching fstab_rec that follows the start_rec.
+ * start_rec is the result of a previous search or NULL.
+ */
+struct fstab_rec *fs_mgr_get_entry_for_mount_point_after(struct fstab_rec *start_rec, struct fstab *fstab, const char *path)
 {
     int i;
-
     if (!fstab) {
         return NULL;
     }
 
-    for (i = 0; i < fstab->num_entries; i++) {
+    if (start_rec) {
+        for (i = 0; i < fstab->num_entries; i++) {
+            if (&fstab->recs[i] == start_rec) {
+                i++;
+                break;
+            }
+        }
+    } else {
+        i = 0;
+    }
+    for (; i < fstab->num_entries; i++) {
         int len = strlen(fstab->recs[i].mount_point);
         if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
             (path[len] == '\0' || path[len] == '/')) {
             return &fstab->recs[i];
         }
     }
-
     return NULL;
 }
 
+/*
+ * Returns the 1st matching mount point.
+ * There might be more. To look for others, use fs_mgr_get_entry_for_mount_point_after()
+ * and give the fstab_rec from the previous search.
+ */
+struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
+{
+    return fs_mgr_get_entry_for_mount_point_after(NULL, fstab, path);
+}
+
 int fs_mgr_is_voldmanaged(struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & MF_VOLDMANAGED;
@@ -392,7 +420,7 @@
 
 int fs_mgr_is_encryptable(struct fstab_rec *fstab)
 {
-    return fstab->fs_mgr_flags & MF_CRYPT;
+    return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT);
 }
 
 int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 59ffd78..34938fa 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -23,7 +23,7 @@
 #define INFO(x...)    KLOG_INFO("fs_mgr", x)
 #define ERROR(x...)   KLOG_ERROR("fs_mgr", x)
 
-#define CRYPTO_TMPFS_OPTIONS "size=128m,mode=0771,uid=1000,gid=1000"
+#define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000"
 
 #define WAIT_TIMEOUT 20
 
@@ -72,12 +72,9 @@
 #define MF_SWAPPRIO     0x80
 #define MF_ZRAMSIZE     0x100
 #define MF_VERIFY       0x200
-/*
- * There is no emulated sdcard daemon running on /data/media on this device,
- * so treat the physical SD card as the only external storage device,
- * a la the Nexus One.
- */
-#define MF_NOEMULATEDSD 0x400
+#define MF_FORCECRYPT   0x400
+#define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only
+                                 external storage */
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index c9a2a9b..b79a4a8 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -30,6 +30,7 @@
 #include <time.h>
 
 #include <private/android_filesystem_config.h>
+#include <cutils/properties.h>
 #include <logwrap/logwrap.h>
 
 #include "mincrypt/rsa.h"
@@ -334,6 +335,26 @@
     return -1;
 }
 
+static int set_verified_property(char *name) {
+    int ret;
+    char *key;
+    ret = asprintf(&key, "partition.%s.verified", name);
+    if (ret < 0) {
+        ERROR("Error formatting verified property");
+        return ret;
+    }
+    ret = PROP_NAME_MAX - strlen(key);
+    if (ret < 0) {
+        ERROR("Verified property name is too long");
+        return -1;
+    }
+    ret = property_set(key, "1");
+    if (ret < 0)
+        ERROR("Error setting verified property %s: %d", key, ret);
+    free(key);
+    return ret;
+}
+
 int fs_mgr_setup_verity(struct fstab_rec *fstab) {
 
     int retval = -1;
@@ -350,6 +371,13 @@
     io->flags |= 1;
     io->target_count = 1;
 
+    // check to ensure that the verity device is ext4
+    // TODO: support non-ext4 filesystems
+    if (strcmp(fstab->fs_type, "ext4")) {
+        ERROR("Cannot verify non-ext4 device (%s)", fstab->fs_type);
+        return retval;
+    }
+
     // get the device mapper fd
     int fd;
     if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
@@ -402,7 +430,8 @@
         goto out;
     }
 
-    retval = 0;
+    // set the property indicating that the partition is verified
+    retval = set_verified_property(mount_point);
 
 out:
     close(fd);
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 835cf64..d9c58d4 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -24,6 +24,11 @@
 extern "C" {
 #endif
 
+/*
+ * The entries must be kept in the same order as they were seen in the fstab.
+ * Unless explicitly requested, a lookup on mount point should always
+ * return the 1st one.
+ */
 struct fstab {
     int num_entries;
     struct fstab_rec *recs;
@@ -48,6 +53,11 @@
 
 struct fstab *fs_mgr_read_fstab(const char *fstab_path);
 void fs_mgr_free_fstab(struct fstab *fstab);
+
+#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 3
+#define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 2
+#define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 1
+#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 0
 int fs_mgr_mount_all(struct fstab *fstab);
 int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
                     char *tmp_mount_point);
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 473d375..1d238b1 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -7,12 +7,15 @@
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := healthd_board_default.cpp
 LOCAL_MODULE := libhealthd.default
+LOCAL_CFLAGS := -Werror
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
 	healthd.cpp \
+	healthd_mode_android.cpp \
+	healthd_mode_charger.cpp \
 	BatteryMonitor.cpp \
 	BatteryPropertiesRegistrar.cpp
 
@@ -22,9 +25,57 @@
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
 
-LOCAL_STATIC_LIBRARIES :=  libbatteryservice libbinder libz libutils libstdc++ libcutils liblog libm libc
+LOCAL_CFLAGS := -D__STDC_LIMIT_MACROS -Werror
+
+ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
+LOCAL_CFLAGS += -DCHARGER_DISABLE_INIT_BLANK
+endif
+
+ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
+LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
+endif
+
+LOCAL_C_INCLUDES := bootable/recovery
+
+LOCAL_STATIC_LIBRARIES := libbatteryservice libbinder libminui libpng libz libutils libstdc++ libcutils liblog libm libc
+
+ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
+LOCAL_STATIC_LIBRARIES += libsuspend
+endif
+
 LOCAL_HAL_STATIC_LIBRARIES := libhealthd
 
+# Symlink /charger to /sbin/healthd
+LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT) \
+    && ln -sf /sbin/healthd $(TARGET_ROOT_OUT)/charger
+
 include $(BUILD_EXECUTABLE)
 
+
+define _add-charger-image
+include $$(CLEAR_VARS)
+LOCAL_MODULE := system_core_charger_$(notdir $(1))
+LOCAL_MODULE_STEM := $(notdir $(1))
+_img_modules += $$(LOCAL_MODULE)
+LOCAL_SRC_FILES := $1
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $$(TARGET_ROOT_OUT)/res/images/charger
+include $$(BUILD_PREBUILT)
+endef
+
+_img_modules :=
+_images :=
+$(foreach _img, $(call find-subdir-subdir-files, "images", "*.png"), \
+  $(eval $(call _add-charger-image,$(_img))))
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := charger_res_images
+LOCAL_MODULE_TAGS := optional
+LOCAL_REQUIRED_MODULES := $(_img_modules)
+include $(BUILD_PHONY_PACKAGE)
+
+_add-charger-image :=
+_img_modules :=
+
 endif
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 688c7ff..1ee33a1 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -18,7 +18,6 @@
 
 #include "healthd.h"
 #include "BatteryMonitor.h"
-#include "BatteryPropertiesRegistrar.h"
 
 #include <dirent.h>
 #include <errno.h>
@@ -28,6 +27,9 @@
 #include <unistd.h>
 #include <batteryservice/BatteryService.h>
 #include <cutils/klog.h>
+#include <cutils/properties.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
 
@@ -37,7 +39,7 @@
 namespace android {
 
 struct sysfsStringEnumMap {
-    char* s;
+    const char* s;
     int val;
 };
 
@@ -170,7 +172,6 @@
 }
 
 bool BatteryMonitor::update(void) {
-    struct BatteryProperties props;
     bool logthis;
 
     props.chargerAcOnline = false;
@@ -178,24 +179,20 @@
     props.chargerWirelessOnline = false;
     props.batteryStatus = BATTERY_STATUS_UNKNOWN;
     props.batteryHealth = BATTERY_HEALTH_UNKNOWN;
-    props.batteryCurrentNow = INT_MIN;
-    props.batteryChargeCounter = INT_MIN;
 
     if (!mHealthdConfig->batteryPresentPath.isEmpty())
         props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
     else
-        props.batteryPresent = true;
+        props.batteryPresent = mBatteryDevicePresent;
 
-    props.batteryLevel = getIntField(mHealthdConfig->batteryCapacityPath);
+    props.batteryLevel = mBatteryFixedCapacity ?
+        mBatteryFixedCapacity :
+        getIntField(mHealthdConfig->batteryCapacityPath);
     props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
 
-    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
-        props.batteryCurrentNow = getIntField(mHealthdConfig->batteryCurrentNowPath);
-
-    if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
-        props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);
-
-    props.batteryTemperature = getIntField(mHealthdConfig->batteryTemperaturePath);
+    props.batteryTemperature = mBatteryFixedTemperature ?
+        mBatteryFixedTemperature :
+        getIntField(mHealthdConfig->batteryTemperaturePath);
 
     const int SIZE = 128;
     char buf[SIZE];
@@ -244,7 +241,9 @@
 
     if (logthis) {
         char dmesgline[256];
-        snprintf(dmesgline, sizeof(dmesgline),
+
+        if (props.batteryPresent) {
+            snprintf(dmesgline, sizeof(dmesgline),
                  "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
                  props.batteryLevel, props.batteryVoltage,
                  props.batteryTemperature < 0 ? "-" : "",
@@ -252,11 +251,16 @@
                  abs(props.batteryTemperature % 10), props.batteryHealth,
                  props.batteryStatus);
 
-        if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
-            char b[20];
+            if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+                int c = getIntField(mHealthdConfig->batteryCurrentNowPath);
+                char b[20];
 
-            snprintf(b, sizeof(b), " c=%d", props.batteryCurrentNow / 1000);
-            strlcat(dmesgline, b, sizeof(dmesgline));
+                snprintf(b, sizeof(b), " c=%d", c / 1000);
+                strlcat(dmesgline, b, sizeof(dmesgline));
+            }
+        } else {
+            snprintf(dmesgline, sizeof(dmesgline),
+                 "battery none");
         }
 
         KLOG_INFO(LOG_TAG, "%s chg=%s%s%s\n", dmesgline,
@@ -265,15 +269,110 @@
                   props.chargerWirelessOnline ? "w" : "");
     }
 
-    if (mBatteryPropertiesRegistrar != NULL)
-        mBatteryPropertiesRegistrar->notifyListeners(props);
-
+    healthd_mode_ops->battery_update(&props);
     return props.chargerAcOnline | props.chargerUsbOnline |
             props.chargerWirelessOnline;
 }
 
-void BatteryMonitor::init(struct healthd_config *hc, bool nosvcmgr) {
+status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
+    status_t ret = BAD_VALUE;
+
+    val->valueInt64 = LONG_MIN;
+
+    switch(id) {
+    case BATTERY_PROP_CHARGE_COUNTER:
+        if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
+            val->valueInt64 =
+                getIntField(mHealthdConfig->batteryChargeCounterPath);
+            ret = NO_ERROR;
+        } else {
+            ret = NAME_NOT_FOUND;
+        }
+        break;
+
+    case BATTERY_PROP_CURRENT_NOW:
+        if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+            val->valueInt64 =
+                getIntField(mHealthdConfig->batteryCurrentNowPath);
+            ret = NO_ERROR;
+        } else {
+            ret = NAME_NOT_FOUND;
+        }
+        break;
+
+    case BATTERY_PROP_CURRENT_AVG:
+        if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
+            val->valueInt64 =
+                getIntField(mHealthdConfig->batteryCurrentAvgPath);
+            ret = NO_ERROR;
+        } else {
+            ret = NAME_NOT_FOUND;
+        }
+        break;
+
+    case BATTERY_PROP_CAPACITY:
+        if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
+            val->valueInt64 =
+                getIntField(mHealthdConfig->batteryCapacityPath);
+            ret = NO_ERROR;
+        } else {
+            ret = NAME_NOT_FOUND;
+        }
+        break;
+
+    case BATTERY_PROP_ENERGY_COUNTER:
+        if (mHealthdConfig->energyCounter) {
+            ret = mHealthdConfig->energyCounter(&val->valueInt64);
+        } else {
+            ret = NAME_NOT_FOUND;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    return ret;
+}
+
+void BatteryMonitor::dumpState(int fd) {
+    int v;
+    char vs[128];
+
+    snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d\n",
+             props.chargerAcOnline, props.chargerUsbOnline,
+             props.chargerWirelessOnline);
+    write(fd, vs, strlen(vs));
+    snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
+             props.batteryStatus, props.batteryHealth, props.batteryPresent);
+    write(fd, vs, strlen(vs));
+    snprintf(vs, sizeof(vs), "level: %d voltage: %d temp: %d\n",
+             props.batteryLevel, props.batteryVoltage,
+             props.batteryTemperature);
+    write(fd, vs, strlen(vs));
+
+    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+        v = getIntField(mHealthdConfig->batteryCurrentNowPath);
+        snprintf(vs, sizeof(vs), "current now: %d\n", v);
+        write(fd, vs, strlen(vs));
+    }
+
+    if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
+        v = getIntField(mHealthdConfig->batteryCurrentAvgPath);
+        snprintf(vs, sizeof(vs), "current avg: %d\n", v);
+        write(fd, vs, strlen(vs));
+    }
+
+    if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
+        v = getIntField(mHealthdConfig->batteryChargeCounterPath);
+        snprintf(vs, sizeof(vs), "charge counter: %d\n", v);
+        write(fd, vs, strlen(vs));
+    }
+}
+
+void BatteryMonitor::init(struct healthd_config *hc) {
     String8 path;
+    char pval[PROPERTY_VALUE_MAX];
 
     mHealthdConfig = hc;
     DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);
@@ -303,6 +402,8 @@
                 break;
 
             case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
+                mBatteryDevicePresent = true;
+
                 if (mHealthdConfig->batteryStatusPath.isEmpty()) {
                     path.clear();
                     path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
@@ -358,6 +459,14 @@
                         mHealthdConfig->batteryCurrentNowPath = path;
                 }
 
+                if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
+                    path.clear();
+                    path.appendFormat("%s/%s/current_avg",
+                                      POWER_SUPPLY_SYSFS_PATH, name);
+                    if (access(path, R_OK) == 0)
+                        mHealthdConfig->batteryCurrentAvgPath = path;
+                }
+
                 if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
                     path.clear();
                     path.appendFormat("%s/%s/charge_counter",
@@ -400,25 +509,32 @@
 
     if (!mChargerNames.size())
         KLOG_ERROR(LOG_TAG, "No charger supplies found\n");
-    if (mHealthdConfig->batteryStatusPath.isEmpty())
-        KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
-    if (mHealthdConfig->batteryHealthPath.isEmpty())
-        KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
-    if (mHealthdConfig->batteryPresentPath.isEmpty())
-        KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
-    if (mHealthdConfig->batteryCapacityPath.isEmpty())
-        KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
-    if (mHealthdConfig->batteryVoltagePath.isEmpty())
-        KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
-    if (mHealthdConfig->batteryTemperaturePath.isEmpty())
-        KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
-    if (mHealthdConfig->batteryTechnologyPath.isEmpty())
-        KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
-
-    if (nosvcmgr == false) {
-            mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(this);
-            mBatteryPropertiesRegistrar->publish();
+    if (!mBatteryDevicePresent) {
+        KLOG_INFO(LOG_TAG, "No battery devices found\n");
+        hc->periodic_chores_interval_fast = -1;
+        hc->periodic_chores_interval_slow = -1;
+    } else {
+        if (mHealthdConfig->batteryStatusPath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
+        if (mHealthdConfig->batteryHealthPath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
+        if (mHealthdConfig->batteryPresentPath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
+        if (mHealthdConfig->batteryCapacityPath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
+        if (mHealthdConfig->batteryVoltagePath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
+        if (mHealthdConfig->batteryTemperaturePath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
+        if (mHealthdConfig->batteryTechnologyPath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
     }
+
+    if (property_get("persist.sys.battery.capacity", pval, NULL) > 0)
+        mBatteryFixedCapacity = (int) strtol(pval, NULL, 10);
+
+    if (property_get("persist.sys.battery.temperature", pval, NULL) > 0)
+        mBatteryFixedTemperature = (int) strtol(pval, NULL, 10);
 }
 
 }; // namespace android
diff --git a/healthd/BatteryMonitor.h b/healthd/BatteryMonitor.h
index ba291af..3425f27 100644
--- a/healthd/BatteryMonitor.h
+++ b/healthd/BatteryMonitor.h
@@ -17,17 +17,15 @@
 #ifndef HEALTHD_BATTERYMONITOR_H
 #define HEALTHD_BATTERYMONITOR_H
 
+#include <batteryservice/BatteryService.h>
 #include <binder/IInterface.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
 
 #include "healthd.h"
-#include "BatteryPropertiesRegistrar.h"
 
 namespace android {
 
-class BatteryPropertiesRegistrar;
-
 class BatteryMonitor {
   public:
 
@@ -39,14 +37,18 @@
         ANDROID_POWER_SUPPLY_TYPE_BATTERY
     };
 
-    void init(struct healthd_config *hc, bool nosvcmgr);
+    void init(struct healthd_config *hc);
     bool update(void);
+    status_t getProperty(int id, struct BatteryProperty *val);
+    void dumpState(int fd);
 
   private:
     struct healthd_config *mHealthdConfig;
     Vector<String8> mChargerNames;
-
-    sp<BatteryPropertiesRegistrar> mBatteryPropertiesRegistrar;
+    bool mBatteryDevicePresent;
+    int mBatteryFixedCapacity;
+    int mBatteryFixedTemperature;
+    struct BatteryProperties props;
 
     int getBatteryStatus(const char* status);
     int getBatteryHealth(const char* status);
diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp
index 6a33ad8..74bcbfd 100644
--- a/healthd/BatteryPropertiesRegistrar.cpp
+++ b/healthd/BatteryPropertiesRegistrar.cpp
@@ -18,19 +18,20 @@
 #include <batteryservice/BatteryService.h>
 #include <batteryservice/IBatteryPropertiesListener.h>
 #include <batteryservice/IBatteryPropertiesRegistrar.h>
+#include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+#include <private/android_filesystem_config.h>
 #include <utils/Errors.h>
 #include <utils/Mutex.h>
 #include <utils/String16.h>
 
+#include "healthd.h"
+
 namespace android {
 
-BatteryPropertiesRegistrar::BatteryPropertiesRegistrar(BatteryMonitor* monitor) {
-    mBatteryMonitor = monitor;
-}
-
 void BatteryPropertiesRegistrar::publish() {
-    defaultServiceManager()->addService(String16("batterypropreg"), this);
+    defaultServiceManager()->addService(String16("batteryproperties"), this);
 }
 
 void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) {
@@ -42,6 +43,8 @@
 
 void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesListener>& listener) {
     {
+        if (listener == NULL)
+            return;
         Mutex::Autolock _l(mRegistrationLock);
         // check whether this is a duplicate
         for (size_t i = 0; i < mListeners.size(); i++) {
@@ -53,10 +56,12 @@
         mListeners.add(listener);
         listener->asBinder()->linkToDeath(this);
     }
-    mBatteryMonitor->update();
+    healthd_battery_update();
 }
 
 void BatteryPropertiesRegistrar::unregisterListener(const sp<IBatteryPropertiesListener>& listener) {
+    if (listener == NULL)
+        return;
     Mutex::Autolock _l(mRegistrationLock);
     for (size_t i = 0; i < mListeners.size(); i++) {
         if (mListeners[i]->asBinder() == listener->asBinder()) {
@@ -67,6 +72,23 @@
     }
 }
 
+status_t BatteryPropertiesRegistrar::getProperty(int id, struct BatteryProperty *val) {
+    return healthd_get_property(id, val);
+}
+
+status_t BatteryPropertiesRegistrar::dump(int fd, const Vector<String16>& /*args*/) {
+    IPCThreadState* self = IPCThreadState::self();
+    const int pid = self->getCallingPid();
+    const int uid = self->getCallingUid();
+    if ((uid != AID_SHELL) &&
+        !PermissionCache::checkPermission(
+                String16("android.permission.DUMP"), pid, uid))
+        return PERMISSION_DENIED;
+
+    healthd_dump_battery_state(fd);
+    return OK;
+}
+
 void BatteryPropertiesRegistrar::binderDied(const wp<IBinder>& who) {
     Mutex::Autolock _l(mRegistrationLock);
 
diff --git a/healthd/BatteryPropertiesRegistrar.h b/healthd/BatteryPropertiesRegistrar.h
index 793ddad..8853874 100644
--- a/healthd/BatteryPropertiesRegistrar.h
+++ b/healthd/BatteryPropertiesRegistrar.h
@@ -17,10 +17,9 @@
 #ifndef HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
 #define HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
 
-#include "BatteryMonitor.h"
-
 #include <binder/IBinder.h>
 #include <utils/Mutex.h>
+#include <utils/String16.h>
 #include <utils/Vector.h>
 #include <batteryservice/BatteryService.h>
 #include <batteryservice/IBatteryPropertiesListener.h>
@@ -28,22 +27,20 @@
 
 namespace android {
 
-class BatteryMonitor;
-
 class BatteryPropertiesRegistrar : public BnBatteryPropertiesRegistrar,
                                    public IBinder::DeathRecipient {
 public:
-    BatteryPropertiesRegistrar(BatteryMonitor* monitor);
     void publish();
     void notifyListeners(struct BatteryProperties props);
 
 private:
-    BatteryMonitor* mBatteryMonitor;
     Mutex mRegistrationLock;
     Vector<sp<IBatteryPropertiesListener> > mListeners;
 
     void registerListener(const sp<IBatteryPropertiesListener>& listener);
     void unregisterListener(const sp<IBatteryPropertiesListener>& listener);
+    status_t getProperty(int id, struct BatteryProperty *val);
+    status_t dump(int fd, const Vector<String16>& args);
     void binderDied(const wp<IBinder>& who);
 };
 
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index d30e771..30a4b42 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -21,16 +21,17 @@
 #include "BatteryMonitor.h"
 
 #include <errno.h>
+#include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <batteryservice/BatteryService.h>
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
 #include <cutils/klog.h>
 #include <cutils/uevent.h>
 #include <sys/epoll.h>
 #include <sys/timerfd.h>
+#include <utils/Errors.h>
 
 using namespace android;
 
@@ -49,13 +50,18 @@
     .batteryTemperaturePath = String8(String8::kEmptyString),
     .batteryTechnologyPath = String8(String8::kEmptyString),
     .batteryCurrentNowPath = String8(String8::kEmptyString),
+    .batteryCurrentAvgPath = String8(String8::kEmptyString),
     .batteryChargeCounterPath = String8(String8::kEmptyString),
+    .energyCounter = NULL,
 };
 
+static int eventct;
+static int epollfd;
+
 #define POWER_SUPPLY_SUBSYSTEM "power_supply"
 
-// epoll events: uevent, wakealarm, binder
-#define MAX_EPOLL_EVENTS 3
+// epoll_create() parameter is actually unused
+#define MAX_EPOLL_EVENTS 40
 static int uevent_fd;
 static int wakealarm_fd;
 static int binder_fd;
@@ -67,7 +73,80 @@
 
 static BatteryMonitor* gBatteryMonitor;
 
-static bool nosvcmgr;
+struct healthd_mode_ops *healthd_mode_ops;
+
+// Android mode
+
+extern void healthd_mode_android_init(struct healthd_config *config);
+extern int healthd_mode_android_preparetowait(void);
+extern void healthd_mode_android_battery_update(
+    struct android::BatteryProperties *props);
+
+// Charger mode
+
+extern void healthd_mode_charger_init(struct healthd_config *config);
+extern int healthd_mode_charger_preparetowait(void);
+extern void healthd_mode_charger_heartbeat(void);
+extern void healthd_mode_charger_battery_update(
+    struct android::BatteryProperties *props);
+
+// NOPs for modes that need no special action
+
+static void healthd_mode_nop_init(struct healthd_config *config);
+static int healthd_mode_nop_preparetowait(void);
+static void healthd_mode_nop_heartbeat(void);
+static void healthd_mode_nop_battery_update(
+    struct android::BatteryProperties *props);
+
+static struct healthd_mode_ops android_ops = {
+    .init = healthd_mode_android_init,
+    .preparetowait = healthd_mode_android_preparetowait,
+    .heartbeat = healthd_mode_nop_heartbeat,
+    .battery_update = healthd_mode_android_battery_update,
+};
+
+static struct healthd_mode_ops charger_ops = {
+    .init = healthd_mode_charger_init,
+    .preparetowait = healthd_mode_charger_preparetowait,
+    .heartbeat = healthd_mode_charger_heartbeat,
+    .battery_update = healthd_mode_charger_battery_update,
+};
+
+static struct healthd_mode_ops recovery_ops = {
+    .init = healthd_mode_nop_init,
+    .preparetowait = healthd_mode_nop_preparetowait,
+    .heartbeat = healthd_mode_nop_heartbeat,
+    .battery_update = healthd_mode_nop_battery_update,
+};
+
+static void healthd_mode_nop_init(struct healthd_config* /*config*/) {
+}
+
+static int healthd_mode_nop_preparetowait(void) {
+    return -1;
+}
+
+static void healthd_mode_nop_heartbeat(void) {
+}
+
+static void healthd_mode_nop_battery_update(
+    struct android::BatteryProperties* /*props*/) {
+}
+
+int healthd_register_event(int fd, void (*handler)(uint32_t)) {
+    struct epoll_event ev;
+
+    ev.events = EPOLLIN | EPOLLWAKEUP;
+    ev.data.ptr = (void *)handler;
+    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+        KLOG_ERROR(LOG_TAG,
+                   "epoll_ctl failed; errno=%d\n", errno);
+        return -1;
+    }
+
+    eventct++;
+    return 0;
+}
 
 static void wakealarm_set_interval(int interval) {
     struct itimerspec itval;
@@ -89,7 +168,11 @@
         KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
 }
 
-static void battery_update(void) {
+status_t healthd_get_property(int id, struct BatteryProperty *val) {
+    return gBatteryMonitor->getProperty(id, val);
+}
+
+void healthd_battery_update(void) {
     // Fast wake interval when on charger (watch for overheat);
     // slow wake interval when on battery (watch for drained battery).
 
@@ -113,21 +196,17 @@
                 -1 : healthd_config.periodic_chores_interval_fast * 1000;
 }
 
-static void periodic_chores() {
-    battery_update();
+void healthd_dump_battery_state(int fd) {
+    gBatteryMonitor->dumpState(fd);
+    fsync(fd);
 }
 
-static void uevent_init(void) {
-    uevent_fd = uevent_open_socket(64*1024, true);
-
-    if (uevent_fd >= 0)
-        fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
-    else
-        KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+static void periodic_chores() {
+    healthd_battery_update();
 }
 
 #define UEVENT_MSG_LEN 2048
-static void uevent_event(void) {
+static void uevent_event(uint32_t /*epevents*/) {
     char msg[UEVENT_MSG_LEN+2];
     char *cp;
     int n;
@@ -144,7 +223,7 @@
 
     while (*cp) {
         if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
-            battery_update();
+            healthd_battery_update();
             break;
         }
 
@@ -154,6 +233,31 @@
     }
 }
 
+static void uevent_init(void) {
+    uevent_fd = uevent_open_socket(64*1024, true);
+
+    if (uevent_fd < 0) {
+        KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+        return;
+    }
+
+    fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
+    if (healthd_register_event(uevent_fd, uevent_event))
+        KLOG_ERROR(LOG_TAG,
+                   "register for uevent events failed\n");
+}
+
+static void wakealarm_event(uint32_t /*epevents*/) {
+    unsigned long long wakeups;
+
+    if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
+        KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
+        return;
+    }
+
+    periodic_chores();
+}
+
 static void wakealarm_init(void) {
     wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
     if (wakealarm_fd == -1) {
@@ -161,82 +265,24 @@
         return;
     }
 
+    if (healthd_register_event(wakealarm_fd, wakealarm_event))
+        KLOG_ERROR(LOG_TAG,
+                   "Registration of wakealarm event failed\n");
+
     wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
 }
 
-static void wakealarm_event(void) {
-    unsigned long long wakeups;
-
-    if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
-        KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm_fd failed\n");
-        return;
-    }
-
-    periodic_chores();
-}
-
-static void binder_init(void) {
-    ProcessState::self()->setThreadPoolMaxThreadCount(0);
-    IPCThreadState::self()->disableBackgroundScheduling(true);
-    IPCThreadState::self()->setupPolling(&binder_fd);
-}
-
-static void binder_event(void) {
-    IPCThreadState::self()->handlePolledCommands();
-}
-
 static void healthd_mainloop(void) {
-    struct epoll_event ev;
-    int epollfd;
-    int maxevents = 0;
-
-    epollfd = epoll_create(MAX_EPOLL_EVENTS);
-    if (epollfd == -1) {
-        KLOG_ERROR(LOG_TAG,
-                   "healthd_mainloop: epoll_create failed; errno=%d\n",
-                   errno);
-        return;
-    }
-
-    if (uevent_fd >= 0) {
-        ev.events = EPOLLIN | EPOLLWAKEUP;
-        ev.data.ptr = (void *)uevent_event;
-        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1)
-            KLOG_ERROR(LOG_TAG,
-                       "healthd_mainloop: epoll_ctl for uevent_fd failed; errno=%d\n",
-                       errno);
-        else
-            maxevents++;
-    }
-
-    if (wakealarm_fd >= 0) {
-        ev.events = EPOLLIN | EPOLLWAKEUP;
-        ev.data.ptr = (void *)wakealarm_event;
-        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, wakealarm_fd, &ev) == -1)
-            KLOG_ERROR(LOG_TAG,
-                       "healthd_mainloop: epoll_ctl for wakealarm_fd failed; errno=%d\n",
-                       errno);
-        else
-            maxevents++;
-   }
-
-    if (binder_fd >= 0) {
-        ev.events = EPOLLIN | EPOLLWAKEUP;
-        ev.data.ptr= (void *)binder_event;
-        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, binder_fd, &ev) == -1)
-            KLOG_ERROR(LOG_TAG,
-                       "healthd_mainloop: epoll_ctl for binder_fd failed; errno=%d\n",
-                       errno);
-        else
-            maxevents++;
-   }
-
     while (1) {
-        struct epoll_event events[maxevents];
+        struct epoll_event events[eventct];
         int nevents;
+        int timeout = awake_poll_interval;
+        int mode_timeout;
 
-        IPCThreadState::self()->flushCommands();
-        nevents = epoll_wait(epollfd, events, maxevents, awake_poll_interval);
+        mode_timeout = healthd_mode_ops->preparetowait();
+        if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
+            timeout = mode_timeout;
+        nevents = epoll_wait(epollfd, events, eventct, timeout);
 
         if (nevents == -1) {
             if (errno == EINTR)
@@ -247,39 +293,70 @@
 
         for (int n = 0; n < nevents; ++n) {
             if (events[n].data.ptr)
-                (*(void (*)())events[n].data.ptr)();
+                (*(void (*)(int))events[n].data.ptr)(events[n].events);
         }
 
         if (!nevents)
             periodic_chores();
+
+        healthd_mode_ops->heartbeat();
     }
 
     return;
 }
 
-int main(int argc, char **argv) {
-    int ch;
-
-    klog_set_level(KLOG_LEVEL);
-
-    while ((ch = getopt(argc, argv, "n")) != -1) {
-        switch (ch) {
-        case 'n':
-            nosvcmgr = true;
-            break;
-        case '?':
-        default:
-            KLOG_WARNING(LOG_TAG, "Unrecognized healthd option: %c\n", ch);
-        }
+static int healthd_init() {
+    epollfd = epoll_create(MAX_EPOLL_EVENTS);
+    if (epollfd == -1) {
+        KLOG_ERROR(LOG_TAG,
+                   "epoll_create failed; errno=%d\n",
+                   errno);
+        return -1;
     }
 
+    healthd_mode_ops->init(&healthd_config);
     healthd_board_init(&healthd_config);
     wakealarm_init();
     uevent_init();
-    binder_init();
     gBatteryMonitor = new BatteryMonitor();
-    gBatteryMonitor->init(&healthd_config, nosvcmgr);
+    gBatteryMonitor->init(&healthd_config);
+    return 0;
+}
+
+int main(int argc, char **argv) {
+    int ch;
+    int ret;
+
+    klog_set_level(KLOG_LEVEL);
+    healthd_mode_ops = &android_ops;
+
+    if (!strcmp(basename(argv[0]), "charger")) {
+        healthd_mode_ops = &charger_ops;
+    } else {
+        while ((ch = getopt(argc, argv, "cr")) != -1) {
+            switch (ch) {
+            case 'c':
+                healthd_mode_ops = &charger_ops;
+                break;
+            case 'r':
+                healthd_mode_ops = &recovery_ops;
+                break;
+            case '?':
+            default:
+                KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n",
+                           optopt);
+                exit(1);
+            }
+        }
+    }
+
+    ret = healthd_init();
+    if (ret) {
+        KLOG_ERROR("Initialization failed, exiting\n");
+        exit(2);
+    }
 
     healthd_mainloop();
-    return 0;
+    KLOG_ERROR("Main loop terminated, exiting\n");
+    return 3;
 }
diff --git a/healthd/healthd.h b/healthd/healthd.h
index 5374fb1..972e728 100644
--- a/healthd/healthd.h
+++ b/healthd/healthd.h
@@ -18,6 +18,8 @@
 #define _HEALTHD_H_
 
 #include <batteryservice/BatteryService.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
 #include <utils/String8.h>
 
 // periodic_chores_interval_fast, periodic_chores_interval_slow: intervals at
@@ -61,9 +63,37 @@
     android::String8 batteryTemperaturePath;
     android::String8 batteryTechnologyPath;
     android::String8 batteryCurrentNowPath;
+    android::String8 batteryCurrentAvgPath;
     android::String8 batteryChargeCounterPath;
+
+    int (*energyCounter)(int64_t *);
 };
 
+// Global helper functions
+
+int healthd_register_event(int fd, void (*handler)(uint32_t));
+void healthd_battery_update();
+android::status_t healthd_get_property(int id,
+    struct android::BatteryProperty *val);
+void healthd_dump_battery_state(int fd);
+
+struct healthd_mode_ops {
+    void (*init)(struct healthd_config *config);
+    int (*preparetowait)(void);
+    void (*heartbeat)(void);
+    void (*battery_update)(struct android::BatteryProperties *props);
+};
+
+extern struct healthd_mode_ops *healthd_mode_ops;
+
+// Charger mode
+
+void healthd_mode_charger_init(struct healthd_config *config);
+int healthd_mode_charger_preparetowait(void);
+void healthd_mode_charger_heartbeat(void);
+void healthd_mode_charger_battery_update(
+    struct android::BatteryProperties *props);
+
 // The following are implemented in libhealthd_board to handle board-specific
 // behavior.
 //
diff --git a/healthd/healthd_mode_android.cpp b/healthd/healthd_mode_android.cpp
new file mode 100644
index 0000000..fd153a2
--- /dev/null
+++ b/healthd/healthd_mode_android.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "healthd-android"
+
+#include "healthd.h"
+#include "BatteryPropertiesRegistrar.h"
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <cutils/klog.h>
+#include <sys/epoll.h>
+
+using namespace android;
+
+static int gBinderFd;
+static sp<BatteryPropertiesRegistrar> gBatteryPropertiesRegistrar;
+
+void healthd_mode_android_battery_update(
+    struct android::BatteryProperties *props) {
+    if (gBatteryPropertiesRegistrar != NULL)
+        gBatteryPropertiesRegistrar->notifyListeners(*props);
+
+    return;
+}
+
+int healthd_mode_android_preparetowait(void) {
+    IPCThreadState::self()->flushCommands();
+    return -1;
+}
+
+static void binder_event(uint32_t /*epevents*/) {
+    IPCThreadState::self()->handlePolledCommands();
+}
+
+void healthd_mode_android_init(struct healthd_config* /*config*/) {
+    ProcessState::self()->setThreadPoolMaxThreadCount(0);
+    IPCThreadState::self()->disableBackgroundScheduling(true);
+    IPCThreadState::self()->setupPolling(&gBinderFd);
+
+    if (gBinderFd >= 0) {
+        if (healthd_register_event(gBinderFd, binder_event))
+            KLOG_ERROR(LOG_TAG,
+                       "Register for binder events failed\n");
+    }
+
+    gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
+    gBatteryPropertiesRegistrar->publish();
+}
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
new file mode 100644
index 0000000..67d4944
--- /dev/null
+++ b/healthd/healthd_mode_charger.cpp
@@ -0,0 +1,720 @@
+/*
+ * Copyright (C) 2011-2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <linux/input.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <linux/netlink.h>
+
+#include <batteryservice/BatteryService.h>
+#include <cutils/android_reboot.h>
+#include <cutils/klog.h>
+#include <cutils/misc.h>
+#include <cutils/uevent.h>
+#include <cutils/properties.h>
+
+#ifdef CHARGER_ENABLE_SUSPEND
+#include <suspend/autosuspend.h>
+#endif
+
+#include "minui/minui.h"
+
+#include "healthd.h"
+
+char *locale;
+
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))
+
+#define MSEC_PER_SEC            (1000LL)
+#define NSEC_PER_MSEC           (1000000LL)
+
+#define BATTERY_UNKNOWN_TIME    (2 * MSEC_PER_SEC)
+#define POWER_ON_KEY_TIME       (2 * MSEC_PER_SEC)
+#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
+
+#define BATTERY_FULL_THRESH     95
+#define SCREEN_ON_BATTERY_THRESH 1
+
+#define LAST_KMSG_PATH          "/proc/last_kmsg"
+#define LAST_KMSG_PSTORE_PATH   "/sys/fs/pstore/console-ramoops"
+#define LAST_KMSG_MAX_SZ        (32 * 1024)
+
+#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
+#define LOGI(x...) do { KLOG_INFO("charger", x); } while (0)
+#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
+
+struct key_state {
+    bool pending;
+    bool down;
+    int64_t timestamp;
+};
+
+struct frame {
+    int disp_time;
+    int min_capacity;
+    bool level_only;
+
+    gr_surface surface;
+};
+
+struct animation {
+    bool run;
+
+    struct frame *frames;
+    int cur_frame;
+    int num_frames;
+
+    int cur_cycle;
+    int num_cycles;
+
+    /* current capacity being animated */
+    int capacity;
+};
+
+struct charger {
+    bool have_battery_state;
+    bool charger_connected;
+    int capacity;
+    int64_t next_screen_transition;
+    int64_t next_key_check;
+    int64_t next_pwr_check;
+
+    struct key_state keys[KEY_MAX + 1];
+
+    struct animation *batt_anim;
+    gr_surface surf_unknown;
+};
+
+static struct frame batt_anim_frames[] = {
+    {
+        .disp_time = 750,
+        .min_capacity = 0,
+        .level_only = false,
+        .surface = NULL,
+    },
+    {
+        .disp_time = 750,
+        .min_capacity = 20,
+        .level_only = false,
+        .surface = NULL,
+    },
+    {
+        .disp_time = 750,
+        .min_capacity = 40,
+        .level_only = false,
+        .surface = NULL,
+    },
+    {
+        .disp_time = 750,
+        .min_capacity = 60,
+        .level_only = false,
+        .surface = NULL,
+    },
+    {
+        .disp_time = 750,
+        .min_capacity = 80,
+        .level_only = true,
+        .surface = NULL,
+    },
+    {
+        .disp_time = 750,
+        .min_capacity = BATTERY_FULL_THRESH,
+        .level_only = false,
+        .surface = NULL,
+    },
+};
+
+static struct animation battery_animation = {
+    .run = false,
+    .frames = batt_anim_frames,
+    .cur_frame = 0,
+    .num_frames = ARRAY_SIZE(batt_anim_frames),
+    .cur_cycle = 0,
+    .num_cycles = 3,
+    .capacity = 0,
+};
+
+static struct charger charger_state;
+
+static int char_width;
+static int char_height;
+static bool minui_inited;
+
+/* current time in milliseconds */
+static int64_t curr_time_ms(void)
+{
+    struct timespec tm;
+    clock_gettime(CLOCK_MONOTONIC, &tm);
+    return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
+}
+
+static void clear_screen(void)
+{
+    gr_color(0, 0, 0, 255);
+    gr_clear();
+}
+
+#define MAX_KLOG_WRITE_BUF_SZ 256
+
+static void dump_last_kmsg(void)
+{
+    char *buf;
+    char *ptr;
+    unsigned sz = 0;
+    int len;
+
+    LOGI("\n");
+    LOGI("*************** LAST KMSG ***************\n");
+    LOGI("\n");
+    buf = (char *)load_file(LAST_KMSG_PSTORE_PATH, &sz);
+
+    if (!buf || !sz) {
+        buf = (char *)load_file(LAST_KMSG_PATH, &sz);
+        if (!buf || !sz) {
+            LOGI("last_kmsg not found. Cold reset?\n");
+            goto out;
+        }
+    }
+
+    len = min(sz, LAST_KMSG_MAX_SZ);
+    ptr = buf + (sz - len);
+
+    while (len > 0) {
+        int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
+        char yoink;
+        char *nl;
+
+        nl = (char *)memrchr(ptr, '\n', cnt - 1);
+        if (nl)
+            cnt = nl - ptr + 1;
+
+        yoink = ptr[cnt];
+        ptr[cnt] = '\0';
+        klog_write(6, "<6>%s", ptr);
+        ptr[cnt] = yoink;
+
+        len -= cnt;
+        ptr += cnt;
+    }
+
+    free(buf);
+
+out:
+    LOGI("\n");
+    LOGI("************* END LAST KMSG *************\n");
+    LOGI("\n");
+}
+
+static int get_battery_capacity()
+{
+    return charger_state.capacity;
+}
+
+#ifdef CHARGER_ENABLE_SUSPEND
+static int request_suspend(bool enable)
+{
+    if (enable)
+        return autosuspend_enable();
+    else
+        return autosuspend_disable();
+}
+#else
+static int request_suspend(bool /*enable*/)
+{
+    return 0;
+}
+#endif
+
+static int draw_text(const char *str, int x, int y)
+{
+    int str_len_px = gr_measure(str);
+
+    if (x < 0)
+        x = (gr_fb_width() - str_len_px) / 2;
+    if (y < 0)
+        y = (gr_fb_height() - char_height) / 2;
+    gr_text(x, y, str, 0);
+
+    return y + char_height;
+}
+
+static void android_green(void)
+{
+    gr_color(0xa4, 0xc6, 0x39, 255);
+}
+
+/* returns the last y-offset of where the surface ends */
+static int draw_surface_centered(struct charger* /*charger*/, gr_surface surface)
+{
+    int w;
+    int h;
+    int x;
+    int y;
+
+    w = gr_get_width(surface);
+    h = gr_get_height(surface);
+    x = (gr_fb_width() - w) / 2 ;
+    y = (gr_fb_height() - h) / 2 ;
+
+    LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
+    gr_blit(surface, 0, 0, w, h, x, y);
+    return y + h;
+}
+
+static void draw_unknown(struct charger *charger)
+{
+    int y;
+    if (charger->surf_unknown) {
+        draw_surface_centered(charger, charger->surf_unknown);
+    } else {
+        android_green();
+        y = draw_text("Charging!", -1, -1);
+        draw_text("?\?/100", -1, y + 25);
+    }
+}
+
+static void draw_battery(struct charger *charger)
+{
+    struct animation *batt_anim = charger->batt_anim;
+    struct frame *frame = &batt_anim->frames[batt_anim->cur_frame];
+
+    if (batt_anim->num_frames != 0) {
+        draw_surface_centered(charger, frame->surface);
+        LOGV("drawing frame #%d min_cap=%d time=%d\n",
+             batt_anim->cur_frame, frame->min_capacity,
+             frame->disp_time);
+    }
+}
+
+static void redraw_screen(struct charger *charger)
+{
+    struct animation *batt_anim = charger->batt_anim;
+
+    clear_screen();
+
+    /* try to display *something* */
+    if (batt_anim->capacity < 0 || batt_anim->num_frames == 0)
+        draw_unknown(charger);
+    else
+        draw_battery(charger);
+    gr_flip();
+}
+
+static void kick_animation(struct animation *anim)
+{
+    anim->run = true;
+}
+
+static void reset_animation(struct animation *anim)
+{
+    anim->cur_cycle = 0;
+    anim->cur_frame = 0;
+    anim->run = false;
+}
+
+static void update_screen_state(struct charger *charger, int64_t now)
+{
+    struct animation *batt_anim = charger->batt_anim;
+    int cur_frame;
+    int disp_time;
+
+    if (!batt_anim->run || now < charger->next_screen_transition)
+        return;
+
+    if (!minui_inited) {
+        int batt_cap = get_battery_capacity();
+
+        if (batt_cap < SCREEN_ON_BATTERY_THRESH) {
+            LOGV("[%" PRId64 "] level %d, leave screen off\n", now, batt_cap);
+            batt_anim->run = false;
+            charger->next_screen_transition = -1;
+            if (charger->charger_connected)
+                request_suspend(true);
+            return;
+        }
+
+        gr_init();
+        gr_font_size(&char_width, &char_height);
+
+#ifndef CHARGER_DISABLE_INIT_BLANK
+        gr_fb_blank(true);
+#endif
+        minui_inited = true;
+    }
+
+    /* animation is over, blank screen and leave */
+    if (batt_anim->cur_cycle == batt_anim->num_cycles) {
+        reset_animation(batt_anim);
+        charger->next_screen_transition = -1;
+        gr_fb_blank(true);
+        LOGV("[%" PRId64 "] animation done\n", now);
+        if (!charger->charger_connected)
+            request_suspend(true);
+        return;
+    }
+
+    disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time;
+
+    /* animation starting, set up the animation */
+    if (batt_anim->cur_frame == 0) {
+        int batt_cap;
+        int ret;
+
+        LOGV("[%" PRId64 "] animation starting\n", now);
+        batt_cap = get_battery_capacity();
+        if (batt_cap >= 0 && batt_anim->num_frames != 0) {
+            int i;
+
+            /* find first frame given current capacity */
+            for (i = 1; i < batt_anim->num_frames; i++) {
+                if (batt_cap < batt_anim->frames[i].min_capacity)
+                    break;
+            }
+            batt_anim->cur_frame = i - 1;
+
+            /* show the first frame for twice as long */
+            disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2;
+        }
+
+        batt_anim->capacity = batt_cap;
+    }
+
+    /* unblank the screen  on first cycle */
+    if (batt_anim->cur_cycle == 0)
+        gr_fb_blank(false);
+
+    /* draw the new frame (@ cur_frame) */
+    redraw_screen(charger);
+
+    /* if we don't have anim frames, we only have one image, so just bump
+     * the cycle counter and exit
+     */
+    if (batt_anim->num_frames == 0 || batt_anim->capacity < 0) {
+        LOGV("[%" PRId64 "] animation missing or unknown battery status\n", now);
+        charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;
+        batt_anim->cur_cycle++;
+        return;
+    }
+
+    /* schedule next screen transition */
+    charger->next_screen_transition = now + disp_time;
+
+    /* advance frame cntr to the next valid frame only if we are charging
+     * if necessary, advance cycle cntr, and reset frame cntr
+     */
+    if (charger->charger_connected) {
+        batt_anim->cur_frame++;
+
+        /* if the frame is used for level-only, that is only show it when it's
+         * the current level, skip it during the animation.
+         */
+        while (batt_anim->cur_frame < batt_anim->num_frames &&
+               batt_anim->frames[batt_anim->cur_frame].level_only)
+            batt_anim->cur_frame++;
+        if (batt_anim->cur_frame >= batt_anim->num_frames) {
+            batt_anim->cur_cycle++;
+            batt_anim->cur_frame = 0;
+
+            /* don't reset the cycle counter, since we use that as a signal
+             * in a test above to check if animation is over
+             */
+        }
+    } else {
+        /* Stop animating if we're not charging.
+         * If we stop it immediately instead of going through this loop, then
+         * the animation would stop somewhere in the middle.
+         */
+        batt_anim->cur_frame = 0;
+        batt_anim->cur_cycle++;
+    }
+}
+
+static int set_key_callback(int code, int value, void *data)
+{
+    struct charger *charger = (struct charger *)data;
+    int64_t now = curr_time_ms();
+    int down = !!value;
+
+    if (code > KEY_MAX)
+        return -1;
+
+    /* ignore events that don't modify our state */
+    if (charger->keys[code].down == down)
+        return 0;
+
+    /* only record the down even timestamp, as the amount
+     * of time the key spent not being pressed is not useful */
+    if (down)
+        charger->keys[code].timestamp = now;
+    charger->keys[code].down = down;
+    charger->keys[code].pending = true;
+    if (down) {
+        LOGV("[%" PRId64 "] key[%d] down\n", now, code);
+    } else {
+        int64_t duration = now - charger->keys[code].timestamp;
+        int64_t secs = duration / 1000;
+        int64_t msecs = duration - secs * 1000;
+        LOGV("[%" PRId64 "] key[%d] up (was down for %" PRId64 ".%" PRId64 "sec)\n",
+             now, code, secs, msecs);
+    }
+
+    return 0;
+}
+
+static void update_input_state(struct charger *charger,
+                               struct input_event *ev)
+{
+    if (ev->type != EV_KEY)
+        return;
+    set_key_callback(ev->code, ev->value, charger);
+}
+
+static void set_next_key_check(struct charger *charger,
+                               struct key_state *key,
+                               int64_t timeout)
+{
+    int64_t then = key->timestamp + timeout;
+
+    if (charger->next_key_check == -1 || then < charger->next_key_check)
+        charger->next_key_check = then;
+}
+
+static void process_key(struct charger *charger, int code, int64_t now)
+{
+    struct key_state *key = &charger->keys[code];
+    int64_t next_key_check;
+
+    if (code == KEY_POWER) {
+        if (key->down) {
+            int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
+            if (now >= reboot_timeout) {
+                /* We do not currently support booting from charger mode on
+                   all devices. Check the property and continue booting or reboot
+                   accordingly. */
+                if (property_get_bool("ro.enable_boot_charger_mode", false)) {
+                    LOGI("[%" PRId64 "] booting from charger mode\n", now);
+                    property_set("sys.boot_from_charger_mode", "1");
+                } else {
+                    LOGI("[%" PRId64 "] rebooting\n", now);
+                    android_reboot(ANDROID_RB_RESTART, 0, 0);
+                }
+            } else {
+                /* if the key is pressed but timeout hasn't expired,
+                 * make sure we wake up at the right-ish time to check
+                 */
+                set_next_key_check(charger, key, POWER_ON_KEY_TIME);
+            }
+        } else {
+            /* if the power key got released, force screen state cycle */
+            if (key->pending) {
+                request_suspend(false);
+                kick_animation(charger->batt_anim);
+            }
+        }
+    }
+
+    key->pending = false;
+}
+
+static void handle_input_state(struct charger *charger, int64_t now)
+{
+    process_key(charger, KEY_POWER, now);
+
+    if (charger->next_key_check != -1 && now > charger->next_key_check)
+        charger->next_key_check = -1;
+}
+
+static void handle_power_supply_state(struct charger *charger, int64_t now)
+{
+    if (!charger->have_battery_state)
+        return;
+
+    if (!charger->charger_connected) {
+        request_suspend(false);
+        if (charger->next_pwr_check == -1) {
+            charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
+            LOGI("[%" PRId64 "] device unplugged: shutting down in %" PRId64 " (@ %" PRId64 ")\n",
+                 now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
+        } else if (now >= charger->next_pwr_check) {
+            LOGI("[%" PRId64 "] shutting down\n", now);
+            android_reboot(ANDROID_RB_POWEROFF, 0, 0);
+        } else {
+            /* otherwise we already have a shutdown timer scheduled */
+        }
+    } else {
+        /* online supply present, reset shutdown timer if set */
+        if (charger->next_pwr_check != -1) {
+            LOGI("[%" PRId64 "] device plugged in: shutdown cancelled\n", now);
+            kick_animation(charger->batt_anim);
+        }
+        charger->next_pwr_check = -1;
+    }
+}
+
+void healthd_mode_charger_heartbeat()
+{
+    struct charger *charger = &charger_state;
+    int64_t now = curr_time_ms();
+    int ret;
+
+    handle_input_state(charger, now);
+    handle_power_supply_state(charger, now);
+
+    /* do screen update last in case any of the above want to start
+     * screen transitions (animations, etc)
+     */
+    update_screen_state(charger, now);
+}
+
+void healthd_mode_charger_battery_update(
+    struct android::BatteryProperties *props)
+{
+    struct charger *charger = &charger_state;
+
+    charger->charger_connected =
+        props->chargerAcOnline || props->chargerUsbOnline ||
+        props->chargerWirelessOnline;
+    charger->capacity = props->batteryLevel;
+
+    if (!charger->have_battery_state) {
+        charger->have_battery_state = true;
+        charger->next_screen_transition = curr_time_ms() - 1;
+        reset_animation(charger->batt_anim);
+        kick_animation(charger->batt_anim);
+    }
+}
+
+int healthd_mode_charger_preparetowait(void)
+{
+    struct charger *charger = &charger_state;
+    int64_t now = curr_time_ms();
+    int64_t next_event = INT64_MAX;
+    int64_t timeout;
+    struct input_event ev;
+    int ret;
+
+    LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n", now,
+         charger->next_screen_transition, charger->next_key_check,
+         charger->next_pwr_check);
+
+    if (charger->next_screen_transition != -1)
+        next_event = charger->next_screen_transition;
+    if (charger->next_key_check != -1 && charger->next_key_check < next_event)
+        next_event = charger->next_key_check;
+    if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
+        next_event = charger->next_pwr_check;
+
+    if (next_event != -1 && next_event != INT64_MAX)
+        timeout = max(0, next_event - now);
+    else
+        timeout = -1;
+
+   return (int)timeout;
+}
+
+static int input_callback(int fd, unsigned int epevents, void *data)
+{
+    struct charger *charger = (struct charger *)data;
+    struct input_event ev;
+    int ret;
+
+    ret = ev_get_input(fd, epevents, &ev);
+    if (ret)
+        return -1;
+    update_input_state(charger, &ev);
+    return 0;
+}
+
+static void charger_event_handler(uint32_t /*epevents*/)
+{
+    int ret;
+
+    ret = ev_wait(-1);
+    if (!ret)
+        ev_dispatch();
+}
+
+void healthd_mode_charger_init(struct healthd_config* /*config*/)
+{
+    int ret;
+    struct charger *charger = &charger_state;
+    int i;
+    int epollfd;
+
+    dump_last_kmsg();
+
+    LOGI("--------------- STARTING CHARGER MODE ---------------\n");
+
+    ret = ev_init(input_callback, charger);
+    if (!ret) {
+        epollfd = ev_get_epollfd();
+        healthd_register_event(epollfd, charger_event_handler);
+    }
+
+    ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
+    if (ret < 0) {
+        LOGE("Cannot load battery_fail image\n");
+        charger->surf_unknown = NULL;
+    }
+
+    charger->batt_anim = &battery_animation;
+
+    gr_surface* scale_frames;
+    int scale_count;
+    ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames);
+    if (ret < 0) {
+        LOGE("Cannot load battery_scale image\n");
+        charger->batt_anim->num_frames = 0;
+        charger->batt_anim->num_cycles = 1;
+    } else if (scale_count != charger->batt_anim->num_frames) {
+        LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
+             scale_count, charger->batt_anim->num_frames);
+        charger->batt_anim->num_frames = 0;
+        charger->batt_anim->num_cycles = 1;
+    } else {
+        for (i = 0; i < charger->batt_anim->num_frames; i++) {
+            charger->batt_anim->frames[i].surface = scale_frames[i];
+        }
+    }
+
+    ev_sync_key_state(set_key_callback, charger);
+
+    charger->next_screen_transition = -1;
+    charger->next_key_check = -1;
+    charger->next_pwr_check = -1;
+}
diff --git a/charger/images/battery_fail.png b/healthd/images/battery_fail.png
similarity index 100%
rename from charger/images/battery_fail.png
rename to healthd/images/battery_fail.png
Binary files differ
diff --git a/charger/images/battery_scale.png b/healthd/images/battery_scale.png
similarity index 100%
rename from charger/images/battery_scale.png
rename to healthd/images/battery_scale.png
Binary files differ
diff --git a/include/cutils/klog.h b/include/cutils/klog.h
index 3635e89..d5ae6d7 100644
--- a/include/cutils/klog.h
+++ b/include/cutils/klog.h
@@ -25,7 +25,7 @@
 void klog_init(void);
 int  klog_get_level(void);
 void klog_set_level(int level);
-void klog_close(void);
+/* TODO: void klog_close(void); - and make klog_fd users thread safe. */
 void klog_write(int level, const char *fmt, ...)
     __attribute__ ((format(printf, 2, 3)));
 void klog_vwrite(int level, const char *fmt, va_list ap);
diff --git a/include/cutils/str_parms.h b/include/cutils/str_parms.h
index 247c996..66f3637 100644
--- a/include/cutils/str_parms.h
+++ b/include/cutils/str_parms.h
@@ -34,6 +34,12 @@
 int str_parms_add_float(struct str_parms *str_parms, const char *key,
                         float value);
 
+// Returns non-zero if the str_parms contains the specified key.
+int str_parms_has_key(struct str_parms *str_parms, const char *key);
+
+// Gets value associated with the specified key (if present), placing it in the buffer
+// pointed to by the out_val parameter.  Returns the length of the returned string value.
+// If 'key' isn't in the parms, then return -ENOENT (-2) and leave 'out_val' untouched.
 int str_parms_get_str(struct str_parms *str_parms, const char *key,
                       char *out_val, int len);
 int str_parms_get_int(struct str_parms *str_parms, const char *key,
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index d8e938e..eea9e2b 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -254,6 +254,8 @@
     /* the following files have enhanced capabilities and ARE included in user builds. */
     { 00750, AID_ROOT,      AID_SHELL,     (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" },
 
+    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
+    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },
@@ -263,7 +265,6 @@
     { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/*" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "init*" },
-    { 00750, AID_ROOT,      AID_SHELL,     0, "charger*" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/fs_mgr" },
     { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
     { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
diff --git a/include/system/audio.h b/include/system/audio.h
index 8838e71..c7cd109 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -34,11 +34,17 @@
 /* device address used to refer to the standard remote submix */
 #define AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS "0"
 
+/* AudioFlinger and AudioPolicy services use I/O handles to identify audio sources and sinks */
 typedef int audio_io_handle_t;
+#define AUDIO_IO_HANDLE_NONE    0
 
 /* Audio stream types */
 typedef enum {
+    /* These values must kept in sync with
+     * frameworks/base/media/java/android/media/AudioSystem.java
+     */
     AUDIO_STREAM_DEFAULT          = -1,
+    AUDIO_STREAM_MIN              = 0,
     AUDIO_STREAM_VOICE_CALL       = 0,
     AUDIO_STREAM_SYSTEM           = 1,
     AUDIO_STREAM_RING             = 2,
@@ -55,7 +61,58 @@
 } audio_stream_type_t;
 
 /* Do not change these values without updating their counterparts
- * in media/java/android/media/MediaRecorder.java!
+ * in frameworks/base/media/java/android/media/AudioAttributes.java
+ */
+typedef enum {
+    AUDIO_CONTENT_TYPE_UNKNOWN      = 0,
+    AUDIO_CONTENT_TYPE_SPEECH       = 1,
+    AUDIO_CONTENT_TYPE_MUSIC        = 2,
+    AUDIO_CONTENT_TYPE_MOVIE        = 3,
+    AUDIO_CONTENT_TYPE_SONIFICATION = 4,
+
+    AUDIO_CONTENT_TYPE_CNT,
+    AUDIO_CONTENT_TYPE_MAX          = AUDIO_CONTENT_TYPE_CNT - 1,
+} audio_content_type_t;
+
+/* Do not change these values without updating their counterparts
+ * in frameworks/base/media/java/android/media/AudioAttributes.java
+ */
+typedef enum {
+    AUDIO_USAGE_UNKNOWN                            = 0,
+    AUDIO_USAGE_MEDIA                              = 1,
+    AUDIO_USAGE_VOICE_COMMUNICATION                = 2,
+    AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING     = 3,
+    AUDIO_USAGE_ALARM                              = 4,
+    AUDIO_USAGE_NOTIFICATION                       = 5,
+    AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE    = 6,
+    AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7,
+    AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8,
+    AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9,
+    AUDIO_USAGE_NOTIFICATION_EVENT                 = 10,
+    AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY           = 11,
+    AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE     = 12,
+    AUDIO_USAGE_ASSISTANCE_SONIFICATION            = 13,
+    AUDIO_USAGE_GAME                               = 14,
+
+    AUDIO_USAGE_CNT,
+    AUDIO_USAGE_MAX                                = AUDIO_USAGE_CNT - 1,
+} audio_usage_t;
+
+typedef uint32_t audio_flags_mask_t;
+
+/* Do not change these values without updating their counterparts
+ * in frameworks/base/media/java/android/media/AudioAttributes.java
+ */
+enum {
+    AUDIO_FLAG_AUDIBILITY_ENFORCED = 0x1,
+    AUDIO_FLAG_SECURE              = 0x2,
+    AUDIO_FLAG_SCO                 = 0x4,
+};
+
+/* Do not change these values without updating their counterparts
+ * in frameworks/base/media/java/android/media/MediaRecorder.java,
+ * frameworks/av/services/audiopolicy/AudioPolicyService.cpp,
+ * and system/media/audio_effects/include/audio_effects/audio_effects_conf.h!
  */
 typedef enum {
     AUDIO_SOURCE_DEFAULT             = 0,
@@ -79,6 +136,16 @@
                                                 at the audio HAL. */
 } audio_source_t;
 
+/* Audio attributes */
+#define AUDIO_ATTRIBUTES_TAGS_MAX_SIZE 256
+typedef struct {
+    audio_content_type_t content_type;
+    audio_usage_t        usage;
+    audio_source_t       source;
+    audio_flags_mask_t   flags;
+    char                 tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; /* UTF8 */
+} audio_attributes_t;
+
 /* special audio session values
  * (XXX: should this be living in the audio effects land?)
  */
@@ -93,18 +160,30 @@
      * (value must be 0)
      */
     AUDIO_SESSION_OUTPUT_MIX = 0,
+
+    /* application does not specify an explicit session ID to be used,
+     * and requests a new session ID to be allocated
+     * TODO use unique values for AUDIO_SESSION_OUTPUT_MIX and AUDIO_SESSION_ALLOCATE,
+     * after all uses have been updated from 0 to the appropriate symbol, and have been tested.
+     */
+    AUDIO_SESSION_ALLOCATE = 0,
 } audio_session_t;
 
 /* Audio sub formats (see enum audio_format). */
 
 /* PCM sub formats */
 typedef enum {
+    /* All of these are in native byte order */
     AUDIO_FORMAT_PCM_SUB_16_BIT          = 0x1, /* DO NOT CHANGE - PCM signed 16 bits */
     AUDIO_FORMAT_PCM_SUB_8_BIT           = 0x2, /* DO NOT CHANGE - PCM unsigned 8 bits */
     AUDIO_FORMAT_PCM_SUB_32_BIT          = 0x3, /* PCM signed .31 fixed point */
     AUDIO_FORMAT_PCM_SUB_8_24_BIT        = 0x4, /* PCM signed 7.24 fixed point */
+    AUDIO_FORMAT_PCM_SUB_FLOAT           = 0x5, /* PCM single-precision floating point */
+    AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED   = 0x6, /* PCM signed .23 fixed point packed in 3 bytes */
 } audio_format_pcm_sub_fmt_t;
 
+/* The audio_format_*_sub_fmt_t declarations are not currently used */
+
 /* MP3 sub format field definition : can use 11 LSBs in the same way as MP3
  * frame header to specify bit rate, stereo mode, version...
  */
@@ -129,7 +208,7 @@
     AUDIO_FORMAT_VORBIS_SUB_NONE         = 0x0,
 } audio_format_vorbis_sub_fmt_t;
 
-/* Audio format consists in a main format field (upper 8 bits) and a sub format
+/* Audio format consists of a main format field (upper 8 bits) and a sub format
  * field (lower 24 bits).
  *
  * The main format indicates the main codec type. The sub format field
@@ -149,21 +228,31 @@
     AUDIO_FORMAT_HE_AAC_V1           = 0x05000000UL,
     AUDIO_FORMAT_HE_AAC_V2           = 0x06000000UL,
     AUDIO_FORMAT_VORBIS              = 0x07000000UL,
+    AUDIO_FORMAT_OPUS                = 0x08000000UL,
+    AUDIO_FORMAT_AC3                 = 0x09000000UL,
+    AUDIO_FORMAT_E_AC3               = 0x0A000000UL,
     AUDIO_FORMAT_MAIN_MASK           = 0xFF000000UL,
     AUDIO_FORMAT_SUB_MASK            = 0x00FFFFFFUL,
 
     /* Aliases */
+    /* note != AudioFormat.ENCODING_PCM_16BIT */
     AUDIO_FORMAT_PCM_16_BIT          = (AUDIO_FORMAT_PCM |
                                         AUDIO_FORMAT_PCM_SUB_16_BIT),
+    /* note != AudioFormat.ENCODING_PCM_8BIT */
     AUDIO_FORMAT_PCM_8_BIT           = (AUDIO_FORMAT_PCM |
                                         AUDIO_FORMAT_PCM_SUB_8_BIT),
     AUDIO_FORMAT_PCM_32_BIT          = (AUDIO_FORMAT_PCM |
                                         AUDIO_FORMAT_PCM_SUB_32_BIT),
     AUDIO_FORMAT_PCM_8_24_BIT        = (AUDIO_FORMAT_PCM |
                                         AUDIO_FORMAT_PCM_SUB_8_24_BIT),
+    AUDIO_FORMAT_PCM_FLOAT           = (AUDIO_FORMAT_PCM |
+                                        AUDIO_FORMAT_PCM_SUB_FLOAT),
+    AUDIO_FORMAT_PCM_24_BIT_PACKED   = (AUDIO_FORMAT_PCM |
+                                        AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED),
 } audio_format_t;
 
 enum {
+    AUDIO_CHANNEL_NONE                      = 0x0,
     /* output channels */
     AUDIO_CHANNEL_OUT_FRONT_LEFT            = 0x1,
     AUDIO_CHANNEL_OUT_FRONT_RIGHT           = 0x2,
@@ -191,16 +280,26 @@
                                   AUDIO_CHANNEL_OUT_FRONT_RIGHT |
                                   AUDIO_CHANNEL_OUT_BACK_LEFT |
                                   AUDIO_CHANNEL_OUT_BACK_RIGHT),
-    AUDIO_CHANNEL_OUT_SURROUND = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
+    AUDIO_CHANNEL_OUT_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD,
+    /* like AUDIO_CHANNEL_OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */
+    AUDIO_CHANNEL_OUT_QUAD_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
                                   AUDIO_CHANNEL_OUT_FRONT_RIGHT |
-                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
-                                  AUDIO_CHANNEL_OUT_BACK_CENTER),
+                                  AUDIO_CHANNEL_OUT_SIDE_LEFT |
+                                  AUDIO_CHANNEL_OUT_SIDE_RIGHT),
     AUDIO_CHANNEL_OUT_5POINT1  = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
                                   AUDIO_CHANNEL_OUT_FRONT_RIGHT |
                                   AUDIO_CHANNEL_OUT_FRONT_CENTER |
                                   AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
                                   AUDIO_CHANNEL_OUT_BACK_LEFT |
                                   AUDIO_CHANNEL_OUT_BACK_RIGHT),
+    AUDIO_CHANNEL_OUT_5POINT1_BACK = AUDIO_CHANNEL_OUT_5POINT1,
+    /* like AUDIO_CHANNEL_OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */
+    AUDIO_CHANNEL_OUT_5POINT1_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
+                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
+                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
+                                  AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
+                                  AUDIO_CHANNEL_OUT_SIDE_LEFT |
+                                  AUDIO_CHANNEL_OUT_SIDE_RIGHT),
     // matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND definition for 7.1
     AUDIO_CHANNEL_OUT_7POINT1  = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
                                   AUDIO_CHANNEL_OUT_FRONT_RIGHT |
@@ -264,8 +363,25 @@
                                AUDIO_CHANNEL_IN_VOICE_DNLINK),
 };
 
+/* A channel mask per se only defines the presence or absence of a channel, not the order.
+ * But see AUDIO_INTERLEAVE_* below for the platform convention of order.
+ */
 typedef uint32_t audio_channel_mask_t;
 
+/* Expresses the convention when stereo audio samples are stored interleaved
+ * in an array.  This should improve readability by allowing code to use
+ * symbolic indices instead of hard-coded [0] and [1].
+ *
+ * For multi-channel beyond stereo, the platform convention is that channels
+ * are interleaved in order from least significant channel mask bit
+ * to most significant channel mask bit, with unused bits skipped.
+ * Any exceptions to this convention will be noted at the appropriate API.
+ */
+enum {
+    AUDIO_INTERLEAVE_LEFT   = 0,
+    AUDIO_INTERLEAVE_RIGHT  = 1,
+};
+
 typedef enum {
     AUDIO_MODE_INVALID          = -2,
     AUDIO_MODE_CURRENT          = -1,
@@ -278,7 +394,9 @@
     AUDIO_MODE_MAX              = AUDIO_MODE_CNT - 1,
 } audio_mode_t;
 
+/* This enum is deprecated */
 typedef enum {
+    AUDIO_IN_ACOUSTICS_NONE          = 0,
     AUDIO_IN_ACOUSTICS_AGC_ENABLE    = 0x0001,
     AUDIO_IN_ACOUSTICS_AGC_DISABLE   = 0,
     AUDIO_IN_ACOUSTICS_NS_ENABLE     = 0x0002,
@@ -304,11 +422,25 @@
     AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
     AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER    = 0x200,
     AUDIO_DEVICE_OUT_AUX_DIGITAL               = 0x400,
+    AUDIO_DEVICE_OUT_HDMI                      = AUDIO_DEVICE_OUT_AUX_DIGITAL,
+    /* uses an analog connection (multiplexed over the USB connector pins for instance) */
     AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET         = 0x800,
     AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET         = 0x1000,
+    /* USB accessory mode: your Android device is a USB device and the dock is a USB host */
     AUDIO_DEVICE_OUT_USB_ACCESSORY             = 0x2000,
+    /* USB host mode: your Android device is a USB host and the dock is a USB device */
     AUDIO_DEVICE_OUT_USB_DEVICE                = 0x4000,
     AUDIO_DEVICE_OUT_REMOTE_SUBMIX             = 0x8000,
+    /* Telephony voice TX path */
+    AUDIO_DEVICE_OUT_TELEPHONY_TX              = 0x10000,
+    /* Analog jack with line impedance detected */
+    AUDIO_DEVICE_OUT_LINE                      = 0x20000,
+    /* HDMI Audio Return Channel */
+    AUDIO_DEVICE_OUT_HDMI_ARC                  = 0x40000,
+    /* S/PDIF out */
+    AUDIO_DEVICE_OUT_SPDIF                     = 0x80000,
+    /* FM transmitter out */
+    AUDIO_DEVICE_OUT_FM                        = 0x100000,
     AUDIO_DEVICE_OUT_DEFAULT                   = AUDIO_DEVICE_BIT_DEFAULT,
     AUDIO_DEVICE_OUT_ALL      = (AUDIO_DEVICE_OUT_EARPIECE |
                                  AUDIO_DEVICE_OUT_SPEAKER |
@@ -320,12 +452,17 @@
                                  AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
                                  AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
                                  AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
-                                 AUDIO_DEVICE_OUT_AUX_DIGITAL |
+                                 AUDIO_DEVICE_OUT_HDMI |
                                  AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
                                  AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
                                  AUDIO_DEVICE_OUT_USB_ACCESSORY |
                                  AUDIO_DEVICE_OUT_USB_DEVICE |
                                  AUDIO_DEVICE_OUT_REMOTE_SUBMIX |
+                                 AUDIO_DEVICE_OUT_TELEPHONY_TX |
+                                 AUDIO_DEVICE_OUT_LINE |
+                                 AUDIO_DEVICE_OUT_HDMI_ARC |
+                                 AUDIO_DEVICE_OUT_SPDIF |
+                                 AUDIO_DEVICE_OUT_FM |
                                  AUDIO_DEVICE_OUT_DEFAULT),
     AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
                                  AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
@@ -343,13 +480,25 @@
     AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = AUDIO_DEVICE_BIT_IN | 0x8,
     AUDIO_DEVICE_IN_WIRED_HEADSET         = AUDIO_DEVICE_BIT_IN | 0x10,
     AUDIO_DEVICE_IN_AUX_DIGITAL           = AUDIO_DEVICE_BIT_IN | 0x20,
+    AUDIO_DEVICE_IN_HDMI                  = AUDIO_DEVICE_IN_AUX_DIGITAL,
+    /* Telephony voice RX path */
     AUDIO_DEVICE_IN_VOICE_CALL            = AUDIO_DEVICE_BIT_IN | 0x40,
+    AUDIO_DEVICE_IN_TELEPHONY_RX          = AUDIO_DEVICE_IN_VOICE_CALL,
     AUDIO_DEVICE_IN_BACK_MIC              = AUDIO_DEVICE_BIT_IN | 0x80,
     AUDIO_DEVICE_IN_REMOTE_SUBMIX         = AUDIO_DEVICE_BIT_IN | 0x100,
     AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET     = AUDIO_DEVICE_BIT_IN | 0x200,
     AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET     = AUDIO_DEVICE_BIT_IN | 0x400,
     AUDIO_DEVICE_IN_USB_ACCESSORY         = AUDIO_DEVICE_BIT_IN | 0x800,
     AUDIO_DEVICE_IN_USB_DEVICE            = AUDIO_DEVICE_BIT_IN | 0x1000,
+    /* FM tuner input */
+    AUDIO_DEVICE_IN_FM_TUNER              = AUDIO_DEVICE_BIT_IN | 0x2000,
+    /* TV tuner input */
+    AUDIO_DEVICE_IN_TV_TUNER              = AUDIO_DEVICE_BIT_IN | 0x4000,
+    /* Analog jack with line impedance detected */
+    AUDIO_DEVICE_IN_LINE                  = AUDIO_DEVICE_BIT_IN | 0x8000,
+    /* S/PDIF in */
+    AUDIO_DEVICE_IN_SPDIF                 = AUDIO_DEVICE_BIT_IN | 0x10000,
+    AUDIO_DEVICE_IN_BLUETOOTH_A2DP        = AUDIO_DEVICE_BIT_IN | 0x20000,
     AUDIO_DEVICE_IN_DEFAULT               = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT,
 
     AUDIO_DEVICE_IN_ALL     = (AUDIO_DEVICE_IN_COMMUNICATION |
@@ -357,16 +506,23 @@
                                AUDIO_DEVICE_IN_BUILTIN_MIC |
                                AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET |
                                AUDIO_DEVICE_IN_WIRED_HEADSET |
-                               AUDIO_DEVICE_IN_AUX_DIGITAL |
-                               AUDIO_DEVICE_IN_VOICE_CALL |
+                               AUDIO_DEVICE_IN_HDMI |
+                               AUDIO_DEVICE_IN_TELEPHONY_RX |
                                AUDIO_DEVICE_IN_BACK_MIC |
                                AUDIO_DEVICE_IN_REMOTE_SUBMIX |
                                AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET |
                                AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET |
                                AUDIO_DEVICE_IN_USB_ACCESSORY |
                                AUDIO_DEVICE_IN_USB_DEVICE |
+                               AUDIO_DEVICE_IN_FM_TUNER |
+                               AUDIO_DEVICE_IN_TV_TUNER |
+                               AUDIO_DEVICE_IN_LINE |
+                               AUDIO_DEVICE_IN_SPDIF |
+                               AUDIO_DEVICE_IN_BLUETOOTH_A2DP |
                                AUDIO_DEVICE_IN_DEFAULT),
     AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
+    AUDIO_DEVICE_IN_ALL_USB  = (AUDIO_DEVICE_IN_USB_ACCESSORY |
+                                AUDIO_DEVICE_IN_USB_DEVICE),
 };
 
 typedef uint32_t audio_devices_t;
@@ -444,6 +600,225 @@
     is_streaming: false
 };
 
+
+/* audio hw module handle functions or structures referencing a module */
+typedef int audio_module_handle_t;
+
+/******************************
+ *  Volume control
+ *****************************/
+
+/* If the audio hardware supports gain control on some audio paths,
+ * the platform can expose them in the audio_policy.conf file. The audio HAL
+ * will then implement gain control functions that will use the following data
+ * structures. */
+
+/* Type of gain control exposed by an audio port */
+#define AUDIO_GAIN_MODE_JOINT     0x1 /* supports joint channel gain control */
+#define AUDIO_GAIN_MODE_CHANNELS  0x2 /* supports separate channel gain control */
+#define AUDIO_GAIN_MODE_RAMP      0x4 /* supports gain ramps */
+
+typedef uint32_t audio_gain_mode_t;
+
+
+/* An audio_gain struct is a representation of a gain stage.
+ * A gain stage is always attached to an audio port. */
+struct audio_gain  {
+    audio_gain_mode_t    mode;          /* e.g. AUDIO_GAIN_MODE_JOINT */
+    audio_channel_mask_t channel_mask;  /* channels which gain an be controlled.
+                                           N/A if AUDIO_GAIN_MODE_CHANNELS is not supported */
+    int                  min_value;     /* minimum gain value in millibels */
+    int                  max_value;     /* maximum gain value in millibels */
+    int                  default_value; /* default gain value in millibels */
+    unsigned int         step_value;    /* gain step in millibels */
+    unsigned int         min_ramp_ms;   /* minimum ramp duration in ms */
+    unsigned int         max_ramp_ms;   /* maximum ramp duration in ms */
+};
+
+/* The gain configuration structure is used to get or set the gain values of a
+ * given port */
+struct audio_gain_config  {
+    int                  index;             /* index of the corresponding audio_gain in the
+                                               audio_port gains[] table */
+    audio_gain_mode_t    mode;              /* mode requested for this command */
+    audio_channel_mask_t channel_mask;      /* channels which gain value follows.
+                                               N/A in joint mode */
+    int                  values[sizeof(audio_channel_mask_t)]; /* gain values in millibels for each
+                                               channel ordered from LSb to MSb in channel mask.
+                                               The number of values is 1 in joint mode or
+                                               popcount(channel_mask) */
+    unsigned int         ramp_duration_ms; /* ramp duration in ms */
+};
+
+/******************************
+ *  Routing control
+ *****************************/
+
+/* Types defined here are used to describe an audio source or sink at internal
+ * framework interfaces (audio policy, patch panel) or at the audio HAL.
+ * Sink and sources are grouped in a concept of “audio port” representing an
+ * audio end point at the edge of the system managed by the module exposing
+ * the interface. */
+
+/* Audio port role: either source or sink */
+typedef enum {
+    AUDIO_PORT_ROLE_NONE,
+    AUDIO_PORT_ROLE_SOURCE,
+    AUDIO_PORT_ROLE_SINK,
+} audio_port_role_t;
+
+/* Audio port type indicates if it is a session (e.g AudioTrack),
+ * a mix (e.g PlaybackThread output) or a physical device
+ * (e.g AUDIO_DEVICE_OUT_SPEAKER) */
+typedef enum {
+    AUDIO_PORT_TYPE_NONE,
+    AUDIO_PORT_TYPE_DEVICE,
+    AUDIO_PORT_TYPE_MIX,
+    AUDIO_PORT_TYPE_SESSION,
+} audio_port_type_t;
+
+/* Each port has a unique ID or handle allocated by policy manager */
+typedef int audio_port_handle_t;
+#define AUDIO_PORT_HANDLE_NONE 0
+
+
+/* maximum audio device address length */
+#define AUDIO_DEVICE_MAX_ADDRESS_LEN 32
+
+/* extension for audio port configuration structure when the audio port is a
+ * hardware device */
+struct audio_port_config_device_ext {
+    audio_module_handle_t hw_module;                /* module the device is attached to */
+    audio_devices_t       type;                     /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
+    char                  address[AUDIO_DEVICE_MAX_ADDRESS_LEN]; /* device address. "" if N/A */
+};
+
+/* extension for audio port configuration structure when the audio port is a
+ * sub mix */
+struct audio_port_config_mix_ext {
+    audio_module_handle_t hw_module;    /* module the stream is attached to */
+    audio_io_handle_t handle;           /* I/O handle of the input/output stream */
+    union {
+        //TODO: change use case for output streams: use strategy and mixer attributes
+        audio_stream_type_t stream;
+        audio_source_t      source;
+    } usecase;
+};
+
+/* extension for audio port configuration structure when the audio port is an
+ * audio session */
+struct audio_port_config_session_ext {
+    audio_session_t   session; /* audio session */
+};
+
+/* Flags indicating which fields are to be considered in struct audio_port_config */
+#define AUDIO_PORT_CONFIG_SAMPLE_RATE  0x1
+#define AUDIO_PORT_CONFIG_CHANNEL_MASK 0x2
+#define AUDIO_PORT_CONFIG_FORMAT       0x4
+#define AUDIO_PORT_CONFIG_GAIN         0x8
+#define AUDIO_PORT_CONFIG_ALL (AUDIO_PORT_CONFIG_SAMPLE_RATE | \
+                               AUDIO_PORT_CONFIG_CHANNEL_MASK | \
+                               AUDIO_PORT_CONFIG_FORMAT | \
+                               AUDIO_PORT_CONFIG_GAIN)
+
+/* audio port configuration structure used to specify a particular configuration of
+ * an audio port */
+struct audio_port_config {
+    audio_port_handle_t      id;           /* port unique ID */
+    audio_port_role_t        role;         /* sink or source */
+    audio_port_type_t        type;         /* device, mix ... */
+    unsigned int             config_mask;  /* e.g AUDIO_PORT_CONFIG_ALL */
+    unsigned int             sample_rate;  /* sampling rate in Hz */
+    audio_channel_mask_t     channel_mask; /* channel mask if applicable */
+    audio_format_t           format;       /* format if applicable */
+    struct audio_gain_config gain;         /* gain to apply if applicable */
+    union {
+        struct audio_port_config_device_ext  device;  /* device specific info */
+        struct audio_port_config_mix_ext     mix;     /* mix specific info */
+        struct audio_port_config_session_ext session; /* session specific info */
+    } ext;
+};
+
+
+/* max number of sampling rates in audio port */
+#define AUDIO_PORT_MAX_SAMPLING_RATES 16
+/* max number of channel masks in audio port */
+#define AUDIO_PORT_MAX_CHANNEL_MASKS 16
+/* max number of audio formats in audio port */
+#define AUDIO_PORT_MAX_FORMATS 16
+/* max number of gain controls in audio port */
+#define AUDIO_PORT_MAX_GAINS 16
+
+/* extension for audio port structure when the audio port is a hardware device */
+struct audio_port_device_ext {
+    audio_module_handle_t hw_module;    /* module the device is attached to */
+    audio_devices_t       type;         /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
+    char                  address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+};
+
+/* Latency class of the audio mix */
+typedef enum {
+    AUDIO_LATENCY_LOW,
+    AUDIO_LATENCY_NORMAL,
+} audio_mix_latency_class_t;
+
+/* extension for audio port structure when the audio port is a sub mix */
+struct audio_port_mix_ext {
+    audio_module_handle_t     hw_module;     /* module the stream is attached to */
+    audio_io_handle_t         handle;        /* I/O handle of the input.output stream */
+    audio_mix_latency_class_t latency_class; /* latency class */
+    // other attributes: routing strategies
+};
+
+/* extension for audio port structure when the audio port is an audio session */
+struct audio_port_session_ext {
+    audio_session_t   session; /* audio session */
+};
+
+
+struct audio_port {
+    audio_port_handle_t      id;                /* port unique ID */
+    audio_port_role_t        role;              /* sink or source */
+    audio_port_type_t        type;              /* device, mix ... */
+    unsigned int             num_sample_rates;  /* number of sampling rates in following array */
+    unsigned int             sample_rates[AUDIO_PORT_MAX_SAMPLING_RATES];
+    unsigned int             num_channel_masks; /* number of channel masks in following array */
+    audio_channel_mask_t     channel_masks[AUDIO_PORT_MAX_CHANNEL_MASKS];
+    unsigned int             num_formats;       /* number of formats in following array */
+    audio_format_t           formats[AUDIO_PORT_MAX_FORMATS];
+    unsigned int             num_gains;         /* number of gains in following array */
+    struct audio_gain        gains[AUDIO_PORT_MAX_GAINS];
+    struct audio_port_config active_config;     /* current audio port configuration */
+    union {
+        struct audio_port_device_ext  device;
+        struct audio_port_mix_ext     mix;
+        struct audio_port_session_ext session;
+    } ext;
+};
+
+/* An audio patch represents a connection between one or more source ports and
+ * one or more sink ports. Patches are connected and disconnected by audio policy manager or by
+ * applications via framework APIs.
+ * Each patch is identified by a handle at the interface used to create that patch. For instance,
+ * when a patch is created by the audio HAL, the HAL allocates and returns a handle.
+ * This handle is unique to a given audio HAL hardware module.
+ * But the same patch receives another system wide unique handle allocated by the framework.
+ * This unique handle is used for all transactions inside the framework.
+ */
+typedef int audio_patch_handle_t;
+#define AUDIO_PATCH_HANDLE_NONE 0
+
+#define AUDIO_PATCH_PORTS_MAX   16
+
+struct audio_patch {
+    audio_patch_handle_t id;            /* patch unique ID */
+    unsigned int      num_sources;      /* number of sources in following array */
+    struct audio_port_config sources[AUDIO_PATCH_PORTS_MAX];
+    unsigned int      num_sinks;        /* number of sinks in following array */
+    struct audio_port_config sinks[AUDIO_PATCH_PORTS_MAX];
+};
+
+
 static inline bool audio_is_output_device(audio_devices_t device)
 {
     if (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
@@ -468,8 +843,17 @@
     return (device & AUDIO_DEVICE_BIT_IN) == 0;
 }
 
+static inline bool audio_is_a2dp_in_device(audio_devices_t device)
+{
+    if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+        device &= ~AUDIO_DEVICE_BIT_IN;
+        if ((popcount(device) == 1) && (device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP))
+            return true;
+    }
+    return false;
+}
 
-static inline bool audio_is_a2dp_device(audio_devices_t device)
+static inline bool audio_is_a2dp_out_device(audio_devices_t device)
 {
     if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_A2DP))
         return true;
@@ -477,6 +861,12 @@
         return false;
 }
 
+// Deprecated - use audio_is_a2dp_out_device() instead
+static inline bool audio_is_a2dp_device(audio_devices_t device)
+{
+    return audio_is_a2dp_out_device(device);
+}
+
 static inline bool audio_is_bluetooth_sco_device(audio_devices_t device)
 {
     if ((device & AUDIO_DEVICE_BIT_IN) == 0) {
@@ -491,12 +881,25 @@
     return false;
 }
 
+static inline bool audio_is_usb_out_device(audio_devices_t device)
+{
+    return ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_USB));
+}
+
+static inline bool audio_is_usb_in_device(audio_devices_t device)
+{
+    if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+        device &= ~AUDIO_DEVICE_BIT_IN;
+        if (popcount(device) == 1 && (device & AUDIO_DEVICE_IN_ALL_USB) != 0)
+            return true;
+    }
+    return false;
+}
+
+/* OBSOLETE - use audio_is_usb_out_device() instead. */
 static inline bool audio_is_usb_device(audio_devices_t device)
 {
-    if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_USB))
-        return true;
-    else
-        return false;
+    return audio_is_usb_out_device(device);
 }
 
 static inline bool audio_is_remote_submix_device(audio_devices_t device)
@@ -524,6 +927,22 @@
         return false;
 }
 
+/* Returns the number of channels from an input channel mask,
+ * used in the context of audio input or recording.
+ */
+static inline uint32_t audio_channel_count_from_in_mask(audio_channel_mask_t channel)
+{
+    return popcount(channel & AUDIO_CHANNEL_IN_ALL);
+}
+
+/* Returns the number of channels from an output channel mask,
+ * used in the context of audio output or playback.
+ */
+static inline uint32_t audio_channel_count_from_out_mask(audio_channel_mask_t channel)
+{
+    return popcount(channel & AUDIO_CHANNEL_OUT_ALL);
+}
+
 /* Derive an output channel mask from a channel count.
  * This is to be used when the content channel mask is unknown. The 1, 2, 4, 5, 6, 7 and 8 channel
  * cases are mapped to the standard game/home-theater layouts, but note that 4 is mapped to quad,
@@ -534,7 +953,7 @@
  */
 static inline audio_channel_mask_t audio_channel_out_mask_from_count(uint32_t channel_count)
 {
-    switch(channel_count) {
+    switch (channel_count) {
     case 1:
         return AUDIO_CHANNEL_OUT_MONO;
     case 2:
@@ -573,10 +992,18 @@
 {
     switch (format & AUDIO_FORMAT_MAIN_MASK) {
     case AUDIO_FORMAT_PCM:
-        if (format != AUDIO_FORMAT_PCM_16_BIT &&
-                format != AUDIO_FORMAT_PCM_8_BIT) {
+        switch (format) {
+        case AUDIO_FORMAT_PCM_16_BIT:
+        case AUDIO_FORMAT_PCM_8_BIT:
+        case AUDIO_FORMAT_PCM_32_BIT:
+        case AUDIO_FORMAT_PCM_8_24_BIT:
+        case AUDIO_FORMAT_PCM_FLOAT:
+        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+            return true;
+        default:
             return false;
         }
+        /* not reached */
     case AUDIO_FORMAT_MP3:
     case AUDIO_FORMAT_AMR_NB:
     case AUDIO_FORMAT_AMR_WB:
@@ -584,6 +1011,9 @@
     case AUDIO_FORMAT_HE_AAC_V1:
     case AUDIO_FORMAT_HE_AAC_V2:
     case AUDIO_FORMAT_VORBIS:
+    case AUDIO_FORMAT_OPUS:
+    case AUDIO_FORMAT_AC3:
+    case AUDIO_FORMAT_E_AC3:
         return true;
     default:
         return false;
@@ -604,12 +1034,18 @@
     case AUDIO_FORMAT_PCM_8_24_BIT:
         size = sizeof(int32_t);
         break;
+    case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+        size = sizeof(uint8_t) * 3;
+        break;
     case AUDIO_FORMAT_PCM_16_BIT:
         size = sizeof(int16_t);
         break;
     case AUDIO_FORMAT_PCM_8_BIT:
         size = sizeof(uint8_t);
         break;
+    case AUDIO_FORMAT_PCM_FLOAT:
+        size = sizeof(float);
+        break;
     default:
         break;
     }
diff --git a/include/system/audio_policy.h b/include/system/audio_policy.h
index a6554de..3085830 100644
--- a/include/system/audio_policy.h
+++ b/include/system/audio_policy.h
@@ -44,6 +44,9 @@
     AUDIO_POLICY_FORCE_DIGITAL_DOCK,
     AUDIO_POLICY_FORCE_NO_BT_A2DP, /* A2DP sink is not preferred to speaker or wired HS */
     AUDIO_POLICY_FORCE_SYSTEM_ENFORCED,
+    AUDIO_POLICY_FORCE_SYSTEM_AUDIO_HDMI_ARC,
+    AUDIO_POLICY_FORCE_SYSTEM_AUDIO_SPDIF,
+    AUDIO_POLICY_FORCE_SYSTEM_AUDIO_LINE,
 
     AUDIO_POLICY_FORCE_CFG_CNT,
     AUDIO_POLICY_FORCE_CFG_MAX = AUDIO_POLICY_FORCE_CFG_CNT - 1,
diff --git a/include/system/graphics.h b/include/system/graphics.h
index be86ae4..74d790f 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -165,24 +165,99 @@
     /*
      * Android RAW sensor format:
      *
-     * This format is exposed outside of the HAL to applications.
+     * This format is exposed outside of the camera HAL to applications.
      *
-     * RAW_SENSOR is a single-channel 16-bit format, typically representing raw
-     * Bayer-pattern images from an image sensor, with minimal processing.
+     * RAW_SENSOR is a single-channel, 16-bit, little endian  format, typically
+     * representing raw Bayer-pattern images from an image sensor, with minimal
+     * processing.
      *
      * The exact pixel layout of the data in the buffer is sensor-dependent, and
      * needs to be queried from the camera device.
      *
      * Generally, not all 16 bits are used; more common values are 10 or 12
-     * bits. All parameters to interpret the raw data (black and white points,
+     * bits. If not all bits are used, the lower-order bits are filled first.
+     * All parameters to interpret the raw data (black and white points,
      * color space, etc) must be queried from the camera device.
      *
      * This format assumes
      * - an even width
      * - an even height
-     * - a horizontal stride multiple of 16 pixels (32 bytes).
+     * - a horizontal stride multiple of 16 pixels
+     * - a vertical stride equal to the height
+     * - strides are specified in pixels, not in bytes
+     *
+     *   size = stride * height * 2
+     *
+     * This format must be accepted by the gralloc module when used with the
+     * following usage flags:
+     *    - GRALLOC_USAGE_HW_CAMERA_*
+     *    - GRALLOC_USAGE_SW_*
+     *    - GRALLOC_USAGE_RENDERSCRIPT
      */
-    HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20,
+    HAL_PIXEL_FORMAT_RAW16 = 0x20,
+    HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20, // TODO(rubenbrunk): Remove RAW_SENSOR.
+
+    /*
+     * Android RAW10 format:
+     *
+     * This format is exposed outside of the camera HAL to applications.
+     *
+     * RAW10 is a single-channel, 10-bit per pixel, densely packed, unprocessed
+     * format, representing raw Bayer-pattern images coming from an image sensor.
+     *
+     * In an image buffer with this format, starting from the first pixel, each 4
+     * consecutive pixels are packed into 5 bytes (40 bits). Each one of the first
+     * 4 bytes contains the top 8 bits of each pixel, The fifth byte contains the
+     * 2 least significant bits of the 4 pixels, the exact layout data for each 4
+     * consecutive pixels is illustrated below (Pi[j] stands for the jth bit of
+     * the ith pixel):
+     *
+     *          bit 7                                     bit 0
+     *          =====|=====|=====|=====|=====|=====|=====|=====|
+     * Byte 0: |P0[9]|P0[8]|P0[7]|P0[6]|P0[5]|P0[4]|P0[3]|P0[2]|
+     *         |-----|-----|-----|-----|-----|-----|-----|-----|
+     * Byte 1: |P1[9]|P1[8]|P1[7]|P1[6]|P1[5]|P1[4]|P1[3]|P1[2]|
+     *         |-----|-----|-----|-----|-----|-----|-----|-----|
+     * Byte 2: |P2[9]|P2[8]|P2[7]|P2[6]|P2[5]|P2[4]|P2[3]|P2[2]|
+     *         |-----|-----|-----|-----|-----|-----|-----|-----|
+     * Byte 3: |P3[9]|P3[8]|P3[7]|P3[6]|P3[5]|P3[4]|P3[3]|P3[2]|
+     *         |-----|-----|-----|-----|-----|-----|-----|-----|
+     * Byte 4: |P3[1]|P3[0]|P2[1]|P2[0]|P1[1]|P1[0]|P0[1]|P0[0]|
+     *          ===============================================
+     *
+     * This format assumes
+     * - a width multiple of 4 pixels
+     * - an even height
+     * - a horizontal stride equal to the width
+     * - a vertical stride equal to the height
+     * - strides are specified in pixels, not in bytes
+     *
+     *   size = stride * height * 10 / 8
+     *
+     * This format must be accepted by the gralloc module when used with the
+     * following usage flags:
+     *    - GRALLOC_USAGE_HW_CAMERA_*
+     *    - GRALLOC_USAGE_SW_*
+     *    - GRALLOC_USAGE_RENDERSCRIPT
+     */
+    HAL_PIXEL_FORMAT_RAW10 = 0x25,
+
+    /*
+     * Android opaque RAW format:
+     *
+     * This format is exposed outside of the camera HAL to applications.
+     *
+     * RAW_OPAQUE is a format for unprocessed raw image buffers coming from an
+     * image sensor. The actual structure of buffers of this format is
+     * implementation-dependent.
+     *
+     * This format must be accepted by the gralloc module when used with the
+     * following usage flags:
+     *    - GRALLOC_USAGE_HW_CAMERA_*
+     *    - GRALLOC_USAGE_SW_*
+     *    - GRALLOC_USAGE_RENDERSCRIPT
+     */
+    HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24,
 
     /*
      * Android binary blob graphics buffer format:
@@ -297,6 +372,136 @@
     HAL_TRANSFORM_RESERVED  = 0x08,
 };
 
+/**
+ * Colorspace Definitions
+ * ======================
+ *
+ * Colorspace is the definition of how pixel values should be interpreted.
+ * It includes primaries (including white point) and the transfer
+ * characteristic function, which describes both gamma curve and numeric
+ * range (within the bit depth).
+ */
+
+enum {
+    /*
+     * Arbitrary colorspace with manually defined characteristics.
+     * Colorspace definition must be communicated separately.
+     *
+     * This is used when specifying primaries, transfer characteristics,
+     * etc. separately.
+     *
+     * A typical use case is in video encoding parameters (e.g. for H.264),
+     * where a colorspace can have separately defined primaries, transfer
+     * characteristics, etc.
+     */
+    HAL_COLORSPACE_ARBITRARY = 0x1,
+
+    /*
+     * YCbCr Colorspaces
+     * -----------------
+     *
+     * Primaries are given using (x,y) coordinates in the CIE 1931 definition
+     * of x and y specified by ISO 11664-1.
+     *
+     * Transfer characteristics are the opto-electronic transfer characteristic
+     * at the source as a function of linear optical intensity (luminance).
+     */
+
+    /*
+     * JPEG File Interchange Format (JFIF)
+     *
+     * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
+     *
+     * Transfer characteristic curve:
+     *  E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
+     *  E = 4.500 L, 0.018 > L >= 0
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     *
+     * Primaries:       x       y
+     *  green           0.290   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     */
+    HAL_COLORSPACE_JFIF = 0x101,
+
+    /*
+     * ITU-R Recommendation 601 (BT.601) - 625-line
+     *
+     * Standard-definition television, 625 Lines (PAL)
+     *
+     * For 8-bit-depth formats:
+     * Luma (Y) samples should range from 16 to 235, inclusive
+     * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+     *
+     * For 10-bit-depth formats:
+     * Luma (Y) samples should range from 64 to 940, inclusive
+     * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+     *
+     * Transfer characteristic curve:
+     *  E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
+     *  E = 4.500 L, 0.018 > L >= 0
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     *
+     * Primaries:       x       y
+     *  green           0.290   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     */
+    HAL_COLORSPACE_BT601_625 = 0x102,
+
+    /*
+     * ITU-R Recommendation 601 (BT.601) - 525-line
+     *
+     * Standard-definition television, 525 Lines (NTSC)
+     *
+     * For 8-bit-depth formats:
+     * Luma (Y) samples should range from 16 to 235, inclusive
+     * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+     *
+     * For 10-bit-depth formats:
+     * Luma (Y) samples should range from 64 to 940, inclusive
+     * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+     *
+     * Transfer characteristic curve:
+     *  E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
+     *  E = 4.500 L, 0.018 > L >= 0
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     *
+     * Primaries:       x       y
+     *  green           0.310   0.595
+     *  blue            0.155   0.070
+     *  red             0.630   0.340
+     *  white (D65)     0.3127  0.3290
+     */
+    HAL_COLORSPACE_BT601_525 = 0x103,
+
+    /*
+     * ITU-R Recommendation 709 (BT.709)
+     *
+     * High-definition television
+     *
+     * For 8-bit-depth formats:
+     * Luma (Y) samples should range from 16 to 235, inclusive
+     * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+     *
+     * For 10-bit-depth formats:
+     * Luma (Y) samples should range from 64 to 940, inclusive
+     * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+     *
+     * Primaries:       x       y
+     *  green           0.300   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     */
+    HAL_COLORSPACE_BT709 = 0x104,
+};
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/system/sound_trigger.h b/include/system/sound_trigger.h
new file mode 100644
index 0000000..57225e9
--- /dev/null
+++ b/include/system/sound_trigger.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SOUND_TRIGGER_H
+#define ANDROID_SOUND_TRIGGER_H
+
+#include <stdbool.h>
+
+#define SOUND_TRIGGER_MAX_STRING_LEN 64 /* max length of strings in properties or
+                                           descriptor structs */
+#define SOUND_TRIGGER_MAX_LOCALE_LEN 6  /* max length of locale string. e.g en_US */
+#define SOUND_TRIGGER_MAX_USERS 10      /* max number of concurrent users */
+#define SOUND_TRIGGER_MAX_PHRASES 10    /* max number of concurrent phrases */
+
+#define RECOGNITION_MODE_VOICE_TRIGGER 0x1       /* simple voice trigger */
+#define RECOGNITION_MODE_USER_IDENTIFICATION 0x2 /* trigger only if one user in model identified */
+#define RECOGNITION_MODE_USER_AUTHENTICATION 0x4 /* trigger only if one user in mode
+                                                    authenticated */
+
+#define RECOGNITION_STATUS_SUCCESS 0
+#define RECOGNITION_STATUS_ABORT 1
+#define RECOGNITION_STATUS_FAILURE 2
+
+
+typedef enum {
+    SOUND_MODEL_TYPE_UNKNOWN = -1,    /* use for unspecified sound model type */
+    SOUND_MODEL_TYPE_KEYPHRASE = 0    /* use for key phrase sound models */
+} sound_trigger_sound_model_type_t;
+
+
+typedef struct sound_trigger_uuid_s {
+    unsigned int   timeLow;
+    unsigned short timeMid;
+    unsigned short timeHiAndVersion;
+    unsigned short clockSeq;
+    unsigned char  node[6];
+} sound_trigger_uuid_t;
+
+/*
+ * sound trigger implementation descriptor read by the framework via get_properties().
+ * Used by SoundTrigger service to report to applications and manage concurrency and policy.
+ */
+struct sound_trigger_properties {
+    char                 implementor[SOUND_TRIGGER_MAX_STRING_LEN]; /* implementor name */
+    char                 description[SOUND_TRIGGER_MAX_STRING_LEN]; /* implementation description */
+    unsigned int         version;               /* implementation version */
+    sound_trigger_uuid_t uuid;                  /* unique implementation ID.
+                                                   Must change with version each version */
+    unsigned int         max_sound_models;      /* maximum number of concurrent sound models
+                                                   loaded */
+    unsigned int         max_key_phrases;       /* maximum number of key phrases */
+    unsigned int         max_users;             /* maximum number of concurrent users detected */
+    unsigned int         recognition_modes;     /* all supported modes.
+                                                   e.g RECOGNITION_MODE_VOICE_TRIGGER */
+    bool                 capture_transition;    /* supports seamless transition from detection
+                                                   to capture */
+    unsigned int         max_buffer_ms;         /* maximum buffering capacity in ms if
+                                                   capture_transition is true*/
+    bool                 concurrent_capture;    /* supports capture by other use cases while
+                                                   detection is active */
+    unsigned int         power_consumption_mw;  /* Rated power consumption when detection is active
+                                                   with TDB silence/sound/speech ratio */
+};
+
+typedef int sound_trigger_module_handle_t;
+
+struct sound_trigger_module_descriptor {
+    sound_trigger_module_handle_t   handle;
+    struct sound_trigger_properties properties;
+};
+
+typedef int sound_model_handle_t;
+
+/*
+ * Generic sound model descriptor. This struct is the header of a larger block passed to
+ * load_sound_model() and containing the binary data of the sound model.
+ * Proprietary representation of users in binary data must match information indicated
+ * by users field
+ */
+struct sound_trigger_sound_model {
+    sound_trigger_sound_model_type_t type;        /* model type. e.g. SOUND_MODEL_TYPE_KEYPHRASE */
+    sound_trigger_uuid_t             uuid;        /* unique sound model ID. */
+    unsigned int                     data_size;   /* size of opaque model data */
+    unsigned int                     data_offset; /* offset of opaque data start from head of struct
+                                                    (e.g sizeof struct sound_trigger_sound_model) */
+};
+
+/* key phrase descriptor */
+struct sound_trigger_phrase {
+    unsigned int id;                /* keyphrase ID */
+    unsigned int recognition_mode;  /* recognition modes supported by this key phrase */
+    unsigned int num_users;         /* number of users in the key phrase */
+    char         locale[SOUND_TRIGGER_MAX_LOCALE_LEN]; /* locale - JAVA Locale style (e.g. en_US) */
+    char         text[SOUND_TRIGGER_MAX_STRING_LEN];   /* phrase text in UTF-8 format. */
+};
+
+/*
+ * Specialized sound model for key phrase detection.
+ * Proprietary representation of key phrases in binary data must match information indicated
+ * by phrases field
+ */
+struct sound_trigger_phrase_sound_model {
+    struct sound_trigger_sound_model common;
+    unsigned int                     num_phrases;   /* number of key phrases in model */
+    struct sound_trigger_phrase      phrases[SOUND_TRIGGER_MAX_PHRASES];
+};
+
+
+/*
+ * Generic recognition event sent via recognition callback
+ */
+struct sound_trigger_recognition_event {
+    int                              status;            /* recognition status e.g.
+                                                           RECOGNITION_STATUS_SUCCESS */
+    sound_trigger_sound_model_type_t type;              /* event type, same as sound model type.
+                                                           e.g. SOUND_MODEL_TYPE_KEYPHRASE */
+    sound_model_handle_t             model;             /* loaded sound model that triggered the
+                                                           event */
+    bool                             capture_available; /* it is possible to capture audio from this
+                                                           utterance buffered by the
+                                                           implementation */
+    int                              capture_session;   /* audio session ID. framework use */
+    int                              capture_delay_ms;  /* delay in ms between end of model
+                                                           detection and start of audio available
+                                                           for capture. A negative value is possible
+                                                           (e.g. if key phrase is also available for
+                                                           capture */
+    unsigned int                     data_size;         /* size of opaque event data */
+    unsigned int                     data_offset;       /* offset of opaque data start from start of
+                                                          this struct (e.g sizeof struct
+                                                          sound_trigger_phrase_recognition_event) */
+};
+
+/*
+ * Specialized recognition event for key phrase detection
+ */
+struct sound_trigger_phrase_recognition_extra {
+    unsigned int recognition_modes;
+    unsigned int num_users;
+    unsigned int confidence_levels[SOUND_TRIGGER_MAX_USERS];
+};
+
+struct sound_trigger_phrase_recognition_event {
+    struct sound_trigger_recognition_event common;
+    bool                                   key_phrase_in_capture; /* true if the key phrase is
+                                                                     present in audio data available
+                                                                     for capture after recognition
+                                                                     event is fired */
+    unsigned int                           num_phrases;
+    struct sound_trigger_phrase_recognition_extra phrase_extras[SOUND_TRIGGER_MAX_PHRASES];
+};
+
+
+#endif  // ANDROID_SOUND_TRIGGER_H
diff --git a/include/sysutils/NetlinkEvent.h b/include/sysutils/NetlinkEvent.h
index c0a9418..c345cdb 100644
--- a/include/sysutils/NetlinkEvent.h
+++ b/include/sysutils/NetlinkEvent.h
@@ -37,6 +37,8 @@
     const static int NlActionAddressUpdated;
     const static int NlActionAddressRemoved;
     const static int NlActionRdnss;
+    const static int NlActionRouteUpdated;
+    const static int NlActionRouteRemoved;
 
     NetlinkEvent();
     virtual ~NetlinkEvent();
@@ -52,8 +54,11 @@
  protected:
     bool parseBinaryNetlinkMessage(char *buffer, int size);
     bool parseAsciiNetlinkMessage(char *buffer, int size);
-    bool parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr, int rtasize);
-    bool parseNdUserOptMessage(struct nduseroptmsg *msg, int optsize);
+    bool parseIfInfoMessage(const struct nlmsghdr *nh);
+    bool parseIfAddrMessage(const struct nlmsghdr *nh);
+    bool parseUlogPacketMessage(const struct nlmsghdr *nh);
+    bool parseRtMessage(const struct nlmsghdr *nh);
+    bool parseNdUserOptMessage(const struct nlmsghdr *nh);
 };
 
 #endif
diff --git a/include/usbhost/usbhost.h b/include/usbhost/usbhost.h
index 1d67c12..d26e931 100644
--- a/include/usbhost/usbhost.h
+++ b/include/usbhost/usbhost.h
@@ -189,6 +189,13 @@
 int usb_device_connect_kernel_driver(struct usb_device *device,
         unsigned int interface, int connect);
 
+/* Sets the current configuration for the device to the specified configuration */
+int usb_device_set_configuration(struct usb_device *device, int configuration);
+
+/* Sets the specified interface of a USB device */
+int usb_device_set_interface(struct usb_device *device, unsigned int interface,
+                            unsigned int alt_setting);
+
 /* Sends a control message to the specified device on endpoint zero */
 int usb_device_control_transfer(struct usb_device *device,
                             int requestType,
diff --git a/include/utils/BitSet.h b/include/utils/BitSet.h
index f1d68a0..8c61293 100644
--- a/include/utils/BitSet.h
+++ b/include/utils/BitSet.h
@@ -75,19 +75,19 @@
     // Result is undefined if all bits are unmarked.
     inline uint32_t firstMarkedBit() const { return firstMarkedBit(value); }
 
-    static uint32_t firstMarkedBit(uint32_t value) { return __builtin_clzl(value); }
+    static uint32_t firstMarkedBit(uint32_t value) { return clz_checked(value); }
 
     // Finds the first unmarked bit in the set.
     // Result is undefined if all bits are marked.
     inline uint32_t firstUnmarkedBit() const { return firstUnmarkedBit(value); }
 
-    static inline uint32_t firstUnmarkedBit(uint32_t value) { return __builtin_clzl(~ value); }
+    static inline uint32_t firstUnmarkedBit(uint32_t value) { return clz_checked(~ value); }
 
     // Finds the last marked bit in the set.
     // Result is undefined if all bits are unmarked.
     inline uint32_t lastMarkedBit() const { return lastMarkedBit(value); }
 
-    static inline uint32_t lastMarkedBit(uint32_t value) { return 31 - __builtin_ctzl(value); }
+    static inline uint32_t lastMarkedBit(uint32_t value) { return 31 - ctz_checked(value); }
 
     // Finds the first marked bit in the set and clears it.  Returns the bit index.
     // Result is undefined if all bits are unmarked.
@@ -145,6 +145,25 @@
         value |= other.value;
         return *this;
     }
+
+private:
+    // We use these helpers as the signature of __builtin_c{l,t}z has "unsigned int" for the
+    // input, which is only guaranteed to be 16b, not 32. The compiler should optimize this away.
+    static inline uint32_t clz_checked(uint32_t value) {
+        if (sizeof(unsigned int) == sizeof(uint32_t)) {
+            return __builtin_clz(value);
+        } else {
+            return __builtin_clzl(value);
+        }
+    }
+
+    static inline uint32_t ctz_checked(uint32_t value) {
+        if (sizeof(unsigned int) == sizeof(uint32_t)) {
+            return __builtin_ctz(value);
+        } else {
+            return __builtin_ctzl(value);
+        }
+    }
 };
 
 ANDROID_BASIC_TYPES_TRAITS(BitSet32)
diff --git a/include/utils/Condition.h b/include/utils/Condition.h
index e63ba7e..1c99d1a 100644
--- a/include/utils/Condition.h
+++ b/include/utils/Condition.h
@@ -60,7 +60,7 @@
     status_t wait(Mutex& mutex);
     // same with relative timeout
     status_t waitRelative(Mutex& mutex, nsecs_t reltime);
-    // Signal the condition variable, allowing one thread to continue.
+    // Signal the condition variable, allowing exactly one thread to continue.
     void signal();
     // Signal the condition variable, allowing one or all threads to continue.
     void signal(WakeUpType type) {
@@ -132,6 +132,17 @@
 #endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
 }
 inline void Condition::signal() {
+    /*
+     * POSIX says pthread_cond_signal wakes up "one or more" waiting threads.
+     * However bionic follows the glibc guarantee which wakes up "exactly one"
+     * waiting thread.
+     *
+     * man 3 pthread_cond_signal
+     *   pthread_cond_signal restarts one of the threads that are waiting on
+     *   the condition variable cond. If no threads are waiting on cond,
+     *   nothing happens. If several threads are waiting on cond, exactly one
+     *   is restarted, but it is not specified which.
+     */
     pthread_cond_signal(&mCond);
 }
 inline void Condition::broadcast() {
diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h
index 9248ac9..cd9d7f9 100644
--- a/include/utils/LruCache.h
+++ b/include/utils/LruCache.h
@@ -17,8 +17,8 @@
 #ifndef ANDROID_UTILS_LRU_CACHE_H
 #define ANDROID_UTILS_LRU_CACHE_H
 
+#include <UniquePtr.h>
 #include <utils/BasicHashtable.h>
-#include <utils/UniquePtr.h>
 
 namespace android {
 
@@ -48,6 +48,7 @@
     bool remove(const TKey& key);
     bool removeOldest();
     void clear();
+    const TValue& peekOldestValue();
 
     class Iterator {
     public:
@@ -184,6 +185,14 @@
 }
 
 template <typename TKey, typename TValue>
+const TValue& LruCache<TKey, TValue>::peekOldestValue() {
+    if (mOldest) {
+        return mOldest->value;
+    }
+    return mNullValue;
+}
+
+template <typename TKey, typename TValue>
 void LruCache<TKey, TValue>::clear() {
     if (mListener) {
         for (Entry* p = mOldest; p != NULL; p = p->child) {
diff --git a/include/utils/NativeHandle.h b/include/utils/NativeHandle.h
new file mode 100644
index 0000000..b825168
--- /dev/null
+++ b/include/utils/NativeHandle.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_NATIVE_HANDLE_H
+#define ANDROID_NATIVE_HANDLE_H
+
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+
+typedef struct native_handle native_handle_t;
+
+namespace android {
+
+class NativeHandle: public LightRefBase<NativeHandle> {
+public:
+    // Create a refcounted wrapper around a native_handle_t, and declare
+    // whether the wrapper owns the handle (so that it should clean up the
+    // handle upon destruction) or not.
+    // If handle is NULL, no NativeHandle will be created.
+    static sp<NativeHandle> create(native_handle_t* handle, bool ownsHandle);
+
+    const native_handle_t* handle() const {
+        return mHandle;
+    }
+
+private:
+    // for access to the destructor
+    friend class LightRefBase<NativeHandle>;
+
+    NativeHandle(native_handle_t* handle, bool ownsHandle);
+    virtual ~NativeHandle();
+
+    native_handle_t* mHandle;
+    bool mOwnsHandle;
+
+    // non-copyable
+    NativeHandle(const NativeHandle&);
+    NativeHandle& operator=(const NativeHandle&);
+};
+
+} // namespace android
+
+#endif // ANDROID_NATIVE_HANDLE_H
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index cbfe13a..8e15c19 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -203,6 +203,13 @@
     mutable volatile int32_t mCount;
 };
 
+// This is a wrapper around LightRefBase that simply enforces a virtual
+// destructor to eliminate the template requirement of LightRefBase
+class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> {
+public:
+    virtual ~VirtualLightRefBase() {}
+};
+
 // ---------------------------------------------------------------------------
 
 template <typename T>
diff --git a/include/utils/String8.h b/include/utils/String8.h
index ef59470..ecfcf10 100644
--- a/include/utils/String8.h
+++ b/include/utils/String8.h
@@ -130,11 +130,19 @@
             // start, or -1 if not found
             ssize_t             find(const char* other, size_t start = 0) const;
 
+            // return true if this string contains the specified substring
+    inline  bool                contains(const char* other) const;
+
+            // removes all occurrence of the specified substring
+            // returns true if any were found and removed
+            bool                removeAll(const char* other);
+
             void                toLower();
             void                toLower(size_t start, size_t numChars);
             void                toUpper();
             void                toUpper(size_t start, size_t numChars);
 
+
     /*
      * These methods operate on the string as if it were a path name.
      */
@@ -280,6 +288,11 @@
     return SharedBuffer::bufferFromData(mString);
 }
 
+inline bool String8::contains(const char* other) const
+{
+    return find(other) >= 0;
+}
+
 inline String8& String8::operator=(const String8& other)
 {
     setTo(other);
diff --git a/include/utils/UniquePtr.h b/include/utils/UniquePtr.h
deleted file mode 100644
index bc62fe6..0000000
--- a/include/utils/UniquePtr.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE ===
- *
- * THIS IS A COPY OF libcore/include/UniquePtr.h AND AS SUCH THAT IS THE
- * CANONICAL SOURCE OF THIS FILE. PLEASE KEEP THEM IN SYNC.
- *
- * === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE ===
- */
-
-#ifndef UNIQUE_PTR_H_included
-#define UNIQUE_PTR_H_included
-
-#include <cstdlib> // For NULL.
-
-// Default deleter for pointer types.
-template <typename T>
-struct DefaultDelete {
-    enum { type_must_be_complete = sizeof(T) };
-    DefaultDelete() {}
-    void operator()(T* p) const {
-        delete p;
-    }
-};
-
-// Default deleter for array types.
-template <typename T>
-struct DefaultDelete<T[]> {
-    enum { type_must_be_complete = sizeof(T) };
-    void operator()(T* p) const {
-        delete[] p;
-    }
-};
-
-// A smart pointer that deletes the given pointer on destruction.
-// Equivalent to C++0x's std::unique_ptr (a combination of boost::scoped_ptr
-// and boost::scoped_array).
-// Named to be in keeping with Android style but also to avoid
-// collision with any other implementation, until we can switch over
-// to unique_ptr.
-// Use thus:
-//   UniquePtr<C> c(new C);
-template <typename T, typename D = DefaultDelete<T> >
-class UniquePtr {
-public:
-    // Construct a new UniquePtr, taking ownership of the given raw pointer.
-    explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) {
-    }
-
-    ~UniquePtr() {
-        reset();
-    }
-
-    // Accessors.
-    T& operator*() const { return *mPtr; }
-    T* operator->() const { return mPtr; }
-    T* get() const { return mPtr; }
-
-    // Returns the raw pointer and hands over ownership to the caller.
-    // The pointer will not be deleted by UniquePtr.
-    T* release() __attribute__((warn_unused_result)) {
-        T* result = mPtr;
-        mPtr = NULL;
-        return result;
-    }
-
-    // Takes ownership of the given raw pointer.
-    // If this smart pointer previously owned a different raw pointer, that
-    // raw pointer will be freed.
-    void reset(T* ptr = NULL) {
-        if (ptr != mPtr) {
-            D()(mPtr);
-            mPtr = ptr;
-        }
-    }
-
-private:
-    // The raw pointer.
-    T* mPtr;
-
-    // Comparing unique pointers is probably a mistake, since they're unique.
-    template <typename T2> bool operator==(const UniquePtr<T2>& p) const;
-    template <typename T2> bool operator!=(const UniquePtr<T2>& p) const;
-
-    // Disallow copy and assignment.
-    UniquePtr(const UniquePtr&);
-    void operator=(const UniquePtr&);
-};
-
-// Partial specialization for array types. Like std::unique_ptr, this removes
-// operator* and operator-> but adds operator[].
-template <typename T, typename D>
-class UniquePtr<T[], D> {
-public:
-    explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) {
-    }
-
-    ~UniquePtr() {
-        reset();
-    }
-
-    T& operator[](size_t i) const {
-        return mPtr[i];
-    }
-    T* get() const { return mPtr; }
-
-    T* release() __attribute__((warn_unused_result)) {
-        T* result = mPtr;
-        mPtr = NULL;
-        return result;
-    }
-
-    void reset(T* ptr = NULL) {
-        if (ptr != mPtr) {
-            D()(mPtr);
-            mPtr = ptr;
-        }
-    }
-
-private:
-    T* mPtr;
-
-    // Disallow copy and assignment.
-    UniquePtr(const UniquePtr&);
-    void operator=(const UniquePtr&);
-};
-
-#if UNIQUE_PTR_TESTS
-
-// Run these tests with:
-// g++ -g -DUNIQUE_PTR_TESTS -x c++ UniquePtr.h && ./a.out
-
-#include <stdio.h>
-
-static void assert(bool b) {
-    if (!b) {
-        fprintf(stderr, "FAIL\n");
-        abort();
-    }
-    fprintf(stderr, "OK\n");
-}
-static int cCount = 0;
-struct C {
-    C() { ++cCount; }
-    ~C() { --cCount; }
-};
-static bool freed = false;
-struct Freer {
-    void operator()(int* p) {
-        assert(*p == 123);
-        free(p);
-        freed = true;
-    }
-};
-
-int main(int argc, char* argv[]) {
-    //
-    // UniquePtr<T> tests...
-    //
-
-    // Can we free a single object?
-    {
-        UniquePtr<C> c(new C);
-        assert(cCount == 1);
-    }
-    assert(cCount == 0);
-    // Does release work?
-    C* rawC;
-    {
-        UniquePtr<C> c(new C);
-        assert(cCount == 1);
-        rawC = c.release();
-    }
-    assert(cCount == 1);
-    delete rawC;
-    // Does reset work?
-    {
-        UniquePtr<C> c(new C);
-        assert(cCount == 1);
-        c.reset(new C);
-        assert(cCount == 1);
-    }
-    assert(cCount == 0);
-
-    //
-    // UniquePtr<T[]> tests...
-    //
-
-    // Can we free an array?
-    {
-        UniquePtr<C[]> cs(new C[4]);
-        assert(cCount == 4);
-    }
-    assert(cCount == 0);
-    // Does release work?
-    {
-        UniquePtr<C[]> c(new C[4]);
-        assert(cCount == 4);
-        rawC = c.release();
-    }
-    assert(cCount == 4);
-    delete[] rawC;
-    // Does reset work?
-    {
-        UniquePtr<C[]> c(new C[4]);
-        assert(cCount == 4);
-        c.reset(new C[2]);
-        assert(cCount == 2);
-    }
-    assert(cCount == 0);
-
-    //
-    // Custom deleter tests...
-    //
-    assert(!freed);
-    {
-        UniquePtr<int, Freer> i(reinterpret_cast<int*>(malloc(sizeof(int))));
-        *i = 123;
-    }
-    assert(freed);
-    return 0;
-}
-#endif
-
-#endif  // UNIQUE_PTR_H_included
diff --git a/init/builtins.c b/init/builtins.c
index b32981e..f7bd8a9 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -474,6 +474,26 @@
 
 }
 
+static int wipe_data_via_recovery()
+{
+    mkdir("/cache/recovery", 0700);
+    int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC, 0600);
+    if (fd >= 0) {
+        write(fd, "--wipe_data", strlen("--wipe_data") + 1);
+        close(fd);
+    } else {
+        ERROR("could not open /cache/recovery/command\n");
+        return -1;
+    }
+    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+    while (1) { pause(); }  // never reached
+}
+
+
+/*
+ * This function might request a reboot, in which case it will
+ * not return.
+ */
 int do_mount_all(int nargs, char **args)
 {
     pid_t pid;
@@ -511,23 +531,33 @@
         if (child_ret == -1) {
             ERROR("fs_mgr_mount_all returned an error\n");
         }
-        exit(child_ret);
+        _exit(child_ret);
     } else {
         /* fork failed, return an error */
         return -1;
     }
 
-    /* ret is 1 if the device is encrypted, 0 if not, and -1 on error */
-    if (ret == 1) {
+    if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
+        property_set("ro.crypto.state", "unencrypted");
+        property_set("vold.decrypt", "trigger_encryption");
+    } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
         property_set("ro.crypto.state", "encrypted");
-        property_set("vold.decrypt", "1");
-    } else if (ret == 0) {
+        property_set("vold.decrypt", "trigger_default_encryption");
+    } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
         property_set("ro.crypto.state", "unencrypted");
         /* If fs_mgr determined this is an unencrypted device, then trigger
          * that action.
          */
         action_for_each_trigger("nonencrypted", action_add_queue_tail);
+    } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
+        /* Setup a wipe via recovery, and reboot into recovery */
+        ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
+        ret = wipe_data_via_recovery();
+        /* If reboot worked, there is no return. */
+    } else if (ret > 0) {
+        ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
     }
+    /* else ... < 0: error */
 
     return ret;
 }
diff --git a/init/devices.c b/init/devices.c
index e27c311..1012fee 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -942,7 +942,7 @@
     }
 }
 
-#define UEVENT_MSG_LEN  1024
+#define UEVENT_MSG_LEN  2048
 void handle_device_fd()
 {
     char msg[UEVENT_MSG_LEN+2];
diff --git a/init/property_service.c b/init/property_service.c
index d112699..1902b77 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -24,6 +24,7 @@
 #include <dirent.h>
 #include <limits.h>
 #include <errno.h>
+#include <sys/poll.h>
 
 #include <cutils/misc.h>
 #include <cutils/sockets.h>
@@ -181,7 +182,6 @@
 static bool is_legal_property_name(const char* name, size_t namelen)
 {
     size_t i;
-    bool previous_was_dot = false;
     if (namelen >= PROP_NAME_MAX) return false;
     if (namelen < 1) return false;
     if (name[0] == '.') return false;
@@ -191,11 +191,10 @@
     /* Don't allow ".." to appear in a property name */
     for (i = 0; i < namelen; i++) {
         if (name[i] == '.') {
-            if (previous_was_dot == true) return false;
-            previous_was_dot = true;
+            // i=0 is guaranteed to never have a dot. See above.
+            if (name[i-1] == '.') return false;
             continue;
         }
-        previous_was_dot = false;
         if (name[i] == '_' || name[i] == '-') continue;
         if (name[i] >= 'a' && name[i] <= 'z') continue;
         if (name[i] >= 'A' && name[i] <= 'Z') continue;
@@ -268,6 +267,9 @@
     socklen_t addr_size = sizeof(addr);
     socklen_t cr_size = sizeof(cr);
     char * source_ctx = NULL;
+    struct pollfd ufds[1];
+    const int timeout_ms = 2 * 1000;  /* Default 2 sec timeout for caller to send property. */
+    int nr;
 
     if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
         return;
@@ -280,7 +282,21 @@
         return;
     }
 
-    r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));
+    ufds[0].fd = s;
+    ufds[0].events = POLLIN;
+    ufds[0].revents = 0;
+    nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));
+    if (nr == 0) {
+        ERROR("sys_prop: timeout waiting for uid=%d to send property message.\n", cr.uid);
+        close(s);
+        return;
+    } else if (nr < 0) {
+        ERROR("sys_prop: error waiting for uid=%d to send property message. err=%d %s\n", cr.uid, errno, strerror(errno));
+        close(s);
+        return;
+    }
+
+    r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));
     if(r != sizeof(prop_msg)) {
         ERROR("sys_prop: mis-match msg size received: %d expected: %zu errno: %d\n",
               r, sizeof(prop_msg), errno);
diff --git a/libbacktrace/map_info.c b/libbacktrace/map_info.c
new file mode 100644
index 0000000..073b24a
--- /dev/null
+++ b/libbacktrace/map_info.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <log/log.h>
+#include <sys/time.h>
+
+#include <backtrace/backtrace.h>
+
+#if defined(__APPLE__)
+
+// Mac OS vmmap(1) output:
+// __TEXT                 0009f000-000a1000 [    8K     8K] r-x/rwx SM=COW  /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
+// 012345678901234567890123456789012345678901234567890123456789
+// 0         1         2         3         4         5
+static backtrace_map_info_t* parse_vmmap_line(const char* line) {
+  unsigned long int start;
+  unsigned long int end;
+  char permissions[4];
+  int name_pos;
+  if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c  %n",
+             &start, &end, permissions, &name_pos) != 3) {
+    return NULL;
+  }
+
+  const char* name = line + name_pos;
+  size_t name_len = strlen(name);
+
+  backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len);
+  if (mi != NULL) {
+    mi->start = start;
+    mi->end = end;
+    mi->is_readable = permissions[0] == 'r';
+    mi->is_writable = permissions[1] == 'w';
+    mi->is_executable = permissions[2] == 'x';
+    memcpy(mi->name, name, name_len);
+    mi->name[name_len - 1] = '\0';
+    ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
+          "is_readable=%d, is_writable=%d is_executable=%d, name=%s",
+          mi->start, mi->end,
+          mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
+  }
+  return mi;
+}
+
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid) {
+  char cmd[1024];
+  if (pid < 0) {
+    pid = getpid();
+  }
+  snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid);
+  FILE* fp = popen(cmd, "r");
+  if (fp == NULL) {
+    return NULL;
+  }
+
+  char line[1024];
+  backtrace_map_info_t* milist = NULL;
+  while (fgets(line, sizeof(line), fp) != NULL) {
+    backtrace_map_info_t* mi = parse_vmmap_line(line);
+    if (mi != NULL) {
+      mi->next = milist;
+      milist = mi;
+    }
+  }
+  pclose(fp);
+  return milist;
+}
+
+#else
+
+// Linux /proc/<pid>/maps lines:
+// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so\n
+// 012345678901234567890123456789012345678901234567890123456789
+// 0         1         2         3         4         5
+static backtrace_map_info_t* parse_maps_line(const char* line)
+{
+  unsigned long int start;
+  unsigned long int end;
+  char permissions[5];
+  int name_pos;
+  if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d%n", &start, &end,
+             permissions, &name_pos) != 3) {
+    return NULL;
+  }
+
+  while (isspace(line[name_pos])) {
+    name_pos += 1;
+  }
+  const char* name = line + name_pos;
+  size_t name_len = strlen(name);
+  if (name_len && name[name_len - 1] == '\n') {
+    name_len -= 1;
+  }
+
+  backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len + 1);
+  if (mi) {
+    mi->start = start;
+    mi->end = end;
+    mi->is_readable = strlen(permissions) == 4 && permissions[0] == 'r';
+    mi->is_writable = strlen(permissions) == 4 && permissions[1] == 'w';
+    mi->is_executable = strlen(permissions) == 4 && permissions[2] == 'x';
+    memcpy(mi->name, name, name_len);
+    mi->name[name_len] = '\0';
+    ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
+          "is_readable=%d, is_writable=%d, is_executable=%d, name=%s",
+          mi->start, mi->end,
+          mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
+  }
+  return mi;
+}
+
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid) {
+  char path[PATH_MAX];
+  char line[1024];
+  FILE* fp;
+  backtrace_map_info_t* milist = NULL;
+
+  if (tid < 0) {
+    tid = getpid();
+  }
+  snprintf(path, PATH_MAX, "/proc/%d/maps", tid);
+  fp = fopen(path, "r");
+  if (fp) {
+    while(fgets(line, sizeof(line), fp)) {
+      backtrace_map_info_t* mi = parse_maps_line(line);
+      if (mi) {
+        mi->next = milist;
+        milist = mi;
+      }
+    }
+    fclose(fp);
+  }
+  return milist;
+}
+
+#endif
+
+void backtrace_destroy_map_info_list(backtrace_map_info_t* milist) {
+  while (milist) {
+    backtrace_map_info_t* next = milist->next;
+    free(milist);
+    milist = next;
+  }
+}
+
+const backtrace_map_info_t* backtrace_find_map_info(
+    const backtrace_map_info_t* milist, uintptr_t addr) {
+  const backtrace_map_info_t* mi = milist;
+  while (mi && !(addr >= mi->start && addr < mi->end)) {
+    mi = mi->next;
+  }
+  return mi;
+}
diff --git a/libcutils/fs.c b/libcutils/fs.c
index 286a8eb..45c7add 100644
--- a/libcutils/fs.c
+++ b/libcutils/fs.c
@@ -212,7 +212,7 @@
 
             /* Yay, segment is ready for us to step into */
             int next_fd;
-            if ((next_fd = openat(fd, segment, 0)) == -1) {
+            if ((next_fd = openat(fd, segment, O_NOFOLLOW | O_CLOEXEC)) == -1) {
                 ALOGE("Failed to openat(%s): %s", buf, strerror(errno));
                 res = -errno;
                 goto done_close;
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 9f092d6..fa0792f 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -39,6 +39,7 @@
 
 #if defined(HAVE_ANDROID_OS) && defined(HAVE_SCHED_H) && defined(HAVE_PTHREADS)
 
+#include <linux/prctl.h>
 #include <sched.h>
 #include <pthread.h>
 
@@ -54,6 +55,9 @@
 
 #define CAN_SET_SP_SYSTEM 0 // non-zero means to implement set_sched_policy(tid, SP_SYSTEM)
 
+// timer slack value in nS enforced when the thread moves to background
+#define TIMER_SLACK_BG 40000000
+
 static pthread_once_t the_once = PTHREAD_ONCE_INIT;
 
 static int __sys_supports_schedgroups = -1;
@@ -325,6 +329,8 @@
                            &param);
     }
 
+    prctl(PR_SET_TIMERSLACK_PID, policy == SP_BACKGROUND ? TIMER_SLACK_BG : 0, tid);
+
     return 0;
 }
 
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
index 2e3ce9f..dfe8c4b 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.c
@@ -262,6 +262,10 @@
     return ret;
 }
 
+int str_parms_has_key(struct str_parms *str_parms, const char *key) {
+    return hashmapGet(str_parms->map, (void *)key) != NULL;
+}
+
 int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val,
                       int len)
 {
diff --git a/libdiskconfig/config_mbr.c b/libdiskconfig/config_mbr.c
index 7641b29..7b6ca1c 100644
--- a/libdiskconfig/config_mbr.c
+++ b/libdiskconfig/config_mbr.c
@@ -208,6 +208,26 @@
 }
 
 
+static struct write_list *
+mk_mbr_sig()
+{
+    struct write_list *item;
+    if (!(item = alloc_wl(sizeof(uint16_t)))) {
+        ALOGE("Unable to allocate memory for MBR signature.");
+        return NULL;
+    }
+
+    {
+        /* DO NOT DEREFERENCE */
+        struct pc_boot_record *mbr = (void *)PC_MBR_DISK_OFFSET;
+        /* grab the offset in mbr where to write mbr signature. */
+        item->offset = (loff_t)((uintptr_t)((uint8_t *)(&mbr->mbr_sig)));
+    }
+
+    *((uint16_t*)item->data) = PC_BIOS_BOOT_SIG;
+    return item;
+}
+
 struct write_list *
 config_mbr(struct disk_info *dinfo)
 {
@@ -276,6 +296,13 @@
         wlist_add(&wr_list, temp_wr);
     }
 
+    if ((temp_wr = mk_mbr_sig()))
+        wlist_add(&wr_list, temp_wr);
+    else {
+        ALOGE("Cannot set MBR signature");
+        goto fail;
+    }
+
     return wr_list;
 
 nospace:
diff --git a/libnetutils/packet.c b/libnetutils/packet.c
index be4e0db..3cdefb0 100644
--- a/libnetutils/packet.c
+++ b/libnetutils/packet.c
@@ -230,6 +230,8 @@
     packet.udp.check = 0;
     sum = finish_sum(checksum(&packet, nread, 0));
     packet.udp.check = temp;
+    if (!sum)
+        sum = finish_sum(sum);
     if (temp != sum) {
         ALOGW("UDP header checksum failure (0x%x should be 0x%x)", sum, temp);
         return -1;
diff --git a/libsparse/Android.mk b/libsparse/Android.mk
index 02ab412..0abe33d 100644
--- a/libsparse/Android.mk
+++ b/libsparse/Android.mk
@@ -88,15 +88,18 @@
 include $(BUILD_EXECUTABLE)
 
 
+ifneq ($(HOST_OS),windows)
+
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := simg2simg.c
-LOCAL_MODULE := simg2simg
+LOCAL_SRC_FILES := append2simg.c
+LOCAL_MODULE := append2simg
 LOCAL_STATIC_LIBRARIES := \
     libsparse_host \
     libz
 LOCAL_CFLAGS := -Werror
 include $(BUILD_HOST_EXECUTABLE)
 
+endif
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := simg_dump.py
diff --git a/libsparse/append2simg.c b/libsparse/append2simg.c
new file mode 100644
index 0000000..65e6cc2
--- /dev/null
+++ b/libsparse/append2simg.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE 1
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sparse/sparse.h>
+#include "sparse_file.h"
+#include "backed_block.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#if defined(__APPLE__) && defined(__MACH__)
+#define lseek64 lseek
+#endif
+#if defined(__APPLE__) && defined(__MACH__)
+#define lseek64 lseek
+#define off64_t off_t
+#endif
+
+void usage()
+{
+    fprintf(stderr, "Usage: append2simg <output> <input>\n");
+}
+
+int main(int argc, char *argv[])
+{
+    int output;
+    int output_block;
+    char *output_path;
+    struct sparse_file *sparse_output;
+
+    int input;
+    char *input_path;
+    off64_t input_len;
+
+    int tmp_fd;
+    char *tmp_path;
+
+    int ret;
+
+    if (argc == 3) {
+        output_path = argv[1];
+        input_path = argv[2];
+    } else {
+        usage();
+        exit(-1);
+    }
+
+    ret = asprintf(&tmp_path, "%s.append2simg", output_path);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't allocate filename\n");
+        exit(-1);
+    }
+
+    output = open(output_path, O_RDWR | O_BINARY);
+    if (output < 0) {
+        fprintf(stderr, "Couldn't open output file (%s)\n", strerror(errno));
+        exit(-1);
+    }
+
+    sparse_output = sparse_file_import_auto(output, true);
+    if (!sparse_output) {
+        fprintf(stderr, "Couldn't import output file\n");
+        exit(-1);
+    }
+
+    input = open(input_path, O_RDONLY | O_BINARY);
+    if (input < 0) {
+        fprintf(stderr, "Couldn't open input file (%s)\n", strerror(errno));
+        exit(-1);
+    }
+
+    input_len = lseek64(input, 0, SEEK_END);
+    if (input_len < 0) {
+        fprintf(stderr, "Couldn't get input file length (%s)\n", strerror(errno));
+        exit(-1);
+    } else if (input_len % sparse_output->block_size) {
+        fprintf(stderr, "Input file is not a multiple of the output file's block size");
+        exit(-1);
+    }
+    lseek64(input, 0, SEEK_SET);
+
+    output_block = sparse_output->len / sparse_output->block_size;
+    if (sparse_file_add_fd(sparse_output, input, 0, input_len, output_block) < 0) {
+        fprintf(stderr, "Couldn't add input file\n");
+        exit(-1);
+    }
+    sparse_output->len += input_len;
+
+    tmp_fd = open(tmp_path, O_WRONLY | O_CREAT | O_BINARY, 0664);
+    if (tmp_fd < 0) {
+        fprintf(stderr, "Couldn't open temporary file (%s)\n", strerror(errno));
+        exit(-1);
+    }
+
+    lseek64(output, 0, SEEK_SET);
+    if (sparse_file_write(sparse_output, tmp_fd, false, true, false) < 0) {
+        fprintf(stderr, "Failed to write sparse file\n");
+        exit(-1);
+    }
+
+    sparse_file_destroy(sparse_output);
+    close(tmp_fd);
+    close(output);
+    close(input);
+
+    ret = rename(tmp_path, output_path);
+    if (ret < 0) {
+        fprintf(stderr, "Failed to rename temporary file (%s)\n", strerror(errno));
+        exit(-1);
+    }
+
+    free(tmp_path);
+
+    exit(0);
+}
diff --git a/libsuspend/autosuspend.c b/libsuspend/autosuspend.c
index eb1f66e..edd1007 100644
--- a/libsuspend/autosuspend.c
+++ b/libsuspend/autosuspend.c
@@ -38,10 +38,13 @@
         goto out;
     }
 
+/* Remove autosleep so userspace can manager suspend/resume and keep stats */
+#if 0
     autosuspend_ops = autosuspend_autosleep_init();
     if (autosuspend_ops) {
         goto out;
     }
+#endif
 
     autosuspend_ops = autosuspend_wakeup_count_init();
     if (autosuspend_ops) {
diff --git a/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c
index a88e677..7483a8f 100644
--- a/libsuspend/autosuspend_wakeup_count.c
+++ b/libsuspend/autosuspend_wakeup_count.c
@@ -25,6 +25,7 @@
 #include <unistd.h>
 
 #define LOG_TAG "libsuspend"
+//#define LOG_NDEBUG 0
 #include <cutils/log.h>
 
 #include "autosuspend_ops.h"
@@ -37,6 +38,7 @@
 static pthread_t suspend_thread;
 static sem_t suspend_lockout;
 static const char *sleep_state = "mem";
+static void (*wakeup_func)(void) = NULL;
 
 static void *suspend_thread_func(void *arg __attribute__((unused)))
 {
@@ -80,6 +82,11 @@
             if (ret < 0) {
                 strerror_r(errno, buf, sizeof(buf));
                 ALOGE("Error writing to %s: %s\n", SYS_POWER_STATE, buf);
+            } else {
+                void (*func)(void) = wakeup_func;
+                if (func != NULL) {
+                    (*func)();
+                }
             }
         }
 
@@ -131,6 +138,15 @@
     return ret;
 }
 
+void set_wakeup_callback(void (*func)(void))
+{
+    if (wakeup_func != NULL) {
+        ALOGE("Duplicate wakeup callback applied, keeping original");
+        return;
+    }
+    wakeup_func = func;
+}
+
 struct autosuspend_ops autosuspend_wakeup_count_ops = {
         .enable = autosuspend_wakeup_count_enable,
         .disable = autosuspend_wakeup_count_disable,
diff --git a/libsuspend/include/suspend/autosuspend.h b/libsuspend/include/suspend/autosuspend.h
index f56fc6a..10e3d27 100644
--- a/libsuspend/include/suspend/autosuspend.h
+++ b/libsuspend/include/suspend/autosuspend.h
@@ -43,6 +43,13 @@
  */
 int autosuspend_disable(void);
 
+/*
+ * set_wakeup_callback
+ *
+ * Set a function to be called each time the device wakes up from suspend.
+ */
+void set_wakeup_callback(void (*func)(void));
+
 __END_DECLS
 
 #endif
diff --git a/libsync/tests/Android.mk b/libsync/tests/Android.mk
new file mode 100644
index 0000000..ad20e50
--- /dev/null
+++ b/libsync/tests/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+include external/libcxx/libcxx.mk
+LOCAL_CLANG := true
+LOCAL_MODULE := sync-unit-tests
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers -Wno-sign-compare
+LOCAL_SHARED_LIBRARIES += libsync
+LOCAL_STATIC_LIBRARIES += libgtest_main
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/../include
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
+LOCAL_SRC_FILES := \
+    sync_test.cpp
+include $(BUILD_NATIVE_TEST)
diff --git a/libsync/tests/sync_test.cpp b/libsync/tests/sync_test.cpp
new file mode 100644
index 0000000..55cd687
--- /dev/null
+++ b/libsync/tests/sync_test.cpp
@@ -0,0 +1,615 @@
+#include <gtest/gtest.h>
+#include <sync/sync.h>
+#include <sw_sync.h>
+#include <fcntl.h>
+#include <vector>
+#include <string>
+#include <cassert>
+#include <iostream>
+#include <unistd.h>
+#include <thread>
+#include <poll.h>
+#include <mutex>
+#include <algorithm>
+#include <tuple>
+#include <random>
+#include <unordered_map>
+
+// TODO: better stress tests?
+// Handle more than 64 fd's simultaneously, i.e. fix sync_fence_info's 4k limit.
+// Handle wraparound in timelines like nvidia.
+
+using namespace std;
+
+namespace {
+
+// C++ wrapper class for sync timeline.
+class SyncTimeline {
+    int m_fd = -1;
+    bool m_fdInitialized = false;
+public:
+    SyncTimeline(const SyncTimeline &) = delete;
+    SyncTimeline& operator=(SyncTimeline&) = delete;
+    SyncTimeline() noexcept {
+        int fd = sw_sync_timeline_create();
+        if (fd == -1)
+            return;
+        m_fdInitialized = true;
+        m_fd = fd;
+    }
+    void destroy() {
+        if (m_fdInitialized) {
+            close(m_fd);
+            m_fd = -1;
+            m_fdInitialized = false;
+        }
+    }
+    ~SyncTimeline() {
+        destroy();
+    }
+    bool isValid() const {
+        if (m_fdInitialized) {
+            int status = fcntl(m_fd, F_GETFD, 0);
+            if (status == 0)
+                return true;
+            else
+                return false;
+        }
+        else {
+            return false;
+        }
+    }
+    int getFd() const {
+        return m_fd;
+    }
+    int inc(int val = 1) {
+        return sw_sync_timeline_inc(m_fd, val);
+    }
+};
+
+struct SyncPointInfo {
+    std::string driverName;
+    std::string objectName;
+    uint64_t timeStampNs;
+    int status; // 1 sig, 0 active, neg is err
+};
+
+// Wrapper class for sync fence.
+class SyncFence {
+    int m_fd = -1;
+    bool m_fdInitialized = false;
+    static int s_fenceCount;
+
+    void setFd(int fd) {
+        m_fd = fd;
+        m_fdInitialized = true;
+    }
+    void clearFd() {
+        m_fd = -1;
+        m_fdInitialized = false;
+    }
+public:
+    bool isValid() const {
+        if (m_fdInitialized) {
+            int status = fcntl(m_fd, F_GETFD, 0);
+            if (status == 0)
+                return true;
+            else
+                return false;
+        }
+        else {
+            return false;
+        }
+    }
+    SyncFence& operator=(SyncFence &&rhs) noexcept {
+        destroy();
+        if (rhs.isValid()) {
+            setFd(rhs.getFd());
+            rhs.clearFd();
+        }
+        return *this;
+    }
+    SyncFence(SyncFence &&fence) noexcept {
+        if (fence.isValid()) {
+            setFd(fence.getFd());
+            fence.clearFd();
+        }
+    }
+    SyncFence(const SyncFence &fence) noexcept {
+        // This is ok, as sync fences are immutable after construction, so a dup
+        // is basically the same thing as a copy.
+        if (fence.isValid()) {
+            int fd = dup(fence.getFd());
+            if (fd == -1)
+                return;
+            setFd(fd);
+        }
+    }
+    SyncFence(const SyncTimeline &timeline,
+              int value,
+              const char *name = nullptr) noexcept {
+        std::string autoName = "allocFence";
+        autoName += s_fenceCount;
+        s_fenceCount++;
+        int fd = sw_sync_fence_create(timeline.getFd(), name ? name : autoName.c_str(), value);
+        if (fd == -1)
+            return;
+        setFd(fd);
+    }
+    SyncFence(const SyncFence &a, const SyncFence &b, const char *name = nullptr) noexcept {
+        std::string autoName = "mergeFence";
+        autoName += s_fenceCount;
+        s_fenceCount++;
+        int fd = sync_merge(name ? name : autoName.c_str(), a.getFd(), b.getFd());
+        if (fd == -1)
+            return;
+        setFd(fd);
+    }
+    SyncFence(const vector<SyncFence> &sources) noexcept {
+        assert(sources.size());
+        SyncFence temp(*begin(sources));
+        for (auto itr = ++begin(sources); itr != end(sources); ++itr) {
+            temp = SyncFence(*itr, temp);
+        }
+        if (temp.isValid()) {
+            setFd(temp.getFd());
+            temp.clearFd();
+        }
+    }
+    void destroy() {
+        if (isValid()) {
+            close(m_fd);
+            clearFd();
+        }
+    }
+    ~SyncFence() {
+        destroy();
+    }
+    int getFd() const {
+        return m_fd;
+    }
+    int wait(int timeout = -1) {
+        return sync_wait(m_fd, timeout);
+    }
+    vector<SyncPointInfo> getInfo() const {
+        struct sync_pt_info *pointInfo = nullptr;
+        vector<SyncPointInfo> fenceInfo;
+        sync_fence_info_data *info = sync_fence_info(getFd());
+        if (!info) {
+            return fenceInfo;
+        }
+        while ((pointInfo = sync_pt_info(info, pointInfo))) {
+            fenceInfo.push_back(SyncPointInfo{
+                pointInfo->driver_name,
+                pointInfo->obj_name,
+                pointInfo->timestamp_ns,
+                pointInfo->status});
+        }
+        sync_fence_info_free(info);
+        return fenceInfo;
+    }
+    int getSize() const {
+        return getInfo().size();
+    }
+    int getSignaledCount() const {
+        return countWithStatus(1);
+    }
+    int getActiveCount() const {
+        return countWithStatus(0);
+    }
+    int getErrorCount() const {
+        return countWithStatus(-1);
+    }
+private:
+    int countWithStatus(int status) const {
+        int count = 0;
+        for (auto &info : getInfo()) {
+            if (info.status == status) {
+                count++;
+            }
+        }
+        return count;
+    }
+};
+
+int SyncFence::s_fenceCount = 0;
+
+TEST(AllocTest, Timeline) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+}
+
+TEST(AllocTest, Fence) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    SyncFence fence(timeline, 1);
+    ASSERT_TRUE(fence.isValid());
+}
+
+TEST(AllocTest, FenceNegative) {
+    int timeline = sw_sync_timeline_create();
+    ASSERT_GT(timeline, 0);
+
+    // bad fd.
+    ASSERT_LT(sw_sync_fence_create(-1, "fence", 1), 0);
+
+    // No name - segfaults in user space.
+    // Maybe we should be friendlier here?
+    /*
+    ASSERT_LT(sw_sync_fence_create(timeline, nullptr, 1), 0);
+    */
+    close(timeline);
+}
+
+TEST(FenceTest, OneTimelineWait) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    SyncFence fence(timeline, 5);
+    ASSERT_TRUE(fence.isValid());
+
+    // Wait on fence until timeout.
+    ASSERT_EQ(fence.wait(0), -1);
+    ASSERT_EQ(errno, ETIME);
+
+    // Advance timeline from 0 -> 1
+    ASSERT_EQ(timeline.inc(1), 0);
+
+    // Wait on fence until timeout.
+    ASSERT_EQ(fence.wait(0), -1);
+    ASSERT_EQ(errno, ETIME);
+
+    // Signal the fence.
+    ASSERT_EQ(timeline.inc(4), 0);
+
+    // Wait successfully.
+    ASSERT_EQ(fence.wait(0), 0);
+
+    // Go even futher, and confirm wait still succeeds.
+    ASSERT_EQ(timeline.inc(10), 0);
+    ASSERT_EQ(fence.wait(0), 0);
+}
+
+TEST(FenceTest, OneTimelinePoll) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    SyncFence fence(timeline, 100);
+    ASSERT_TRUE(fence.isValid());
+
+    fd_set set;
+    FD_ZERO(&set);
+    FD_SET(fence.getFd(), &set);
+
+    // Poll the fence, and wait till timeout.
+    timeval time = {0};
+    ASSERT_EQ(select(fence.getFd() + 1, &set, nullptr, nullptr, &time), 0);
+
+    // Advance the timeline.
+    timeline.inc(100);
+    timeline.inc(100);
+
+    // Select should return that the fd is read for reading.
+    FD_ZERO(&set);
+    FD_SET(fence.getFd(), &set);
+
+    ASSERT_EQ(select(fence.getFd() + 1, &set, nullptr, nullptr, &time), 1);
+    ASSERT_TRUE(FD_ISSET(fence.getFd(), &set));
+}
+
+TEST(FenceTest, OneTimelineMerge) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    // create fence a,b,c and then merge them all into fence d.
+    SyncFence a(timeline, 1), b(timeline, 2), c(timeline, 3);
+    ASSERT_TRUE(a.isValid());
+    ASSERT_TRUE(b.isValid());
+    ASSERT_TRUE(c.isValid());
+
+    SyncFence d({a,b,c});
+    ASSERT_TRUE(d.isValid());
+
+    // confirm all fences have one active point (even d).
+    ASSERT_EQ(a.getActiveCount(), 1);
+    ASSERT_EQ(b.getActiveCount(), 1);
+    ASSERT_EQ(c.getActiveCount(), 1);
+    ASSERT_EQ(d.getActiveCount(), 1);
+
+    // confirm that d is not signaled until the max of a,b,c
+    timeline.inc(1);
+    ASSERT_EQ(a.getSignaledCount(), 1);
+    ASSERT_EQ(d.getActiveCount(), 1);
+
+    timeline.inc(1);
+    ASSERT_EQ(b.getSignaledCount(), 1);
+    ASSERT_EQ(d.getActiveCount(), 1);
+
+    timeline.inc(1);
+    ASSERT_EQ(c.getSignaledCount(), 1);
+    ASSERT_EQ(d.getActiveCount(), 0);
+    ASSERT_EQ(d.getSignaledCount(), 1);
+}
+
+TEST(FenceTest, MergeSameFence) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    SyncFence fence(timeline, 5);
+    ASSERT_TRUE(fence.isValid());
+
+    SyncFence selfMergeFence(fence, fence);
+    ASSERT_TRUE(selfMergeFence.isValid());
+
+    ASSERT_EQ(selfMergeFence.getSignaledCount(), 0);
+
+    timeline.inc(5);
+    ASSERT_EQ(selfMergeFence.getSignaledCount(), 1);
+}
+
+TEST(FenceTest, WaitOnDestroyedTimeline) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    SyncFence fenceSig(timeline, 100);
+    SyncFence fenceKill(timeline, 200);
+
+    // Spawn a thread to wait on a fence when the timeline is killed.
+    thread waitThread{
+        [&]() {
+            ASSERT_EQ(timeline.inc(100), 0);
+
+            ASSERT_EQ(fenceKill.wait(-1), -1);
+            ASSERT_EQ(errno, ENOENT);
+        }
+    };
+
+    // Wait for the thread to spool up.
+    fenceSig.wait();
+
+    // Kill the timeline.
+    timeline.destroy();
+
+    // wait for the thread to clean up.
+    waitThread.join();
+}
+
+TEST(FenceTest, PollOnDestroyedTimeline) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    SyncFence fenceSig(timeline, 100);
+    SyncFence fenceKill(timeline, 200);
+
+    // Spawn a thread to wait on a fence when the timeline is killed.
+    thread waitThread{
+        [&]() {
+            ASSERT_EQ(timeline.inc(100), 0);
+
+            // Wait on the fd.
+            struct pollfd fds;
+            fds.fd = fenceKill.getFd();
+            fds.events = POLLIN | POLLERR;
+            ASSERT_EQ(poll(&fds, 1, -1), 1);
+            ASSERT_TRUE(fds.revents & POLLERR);
+        }
+    };
+
+    // Wait for the thread to spool up.
+    fenceSig.wait();
+
+    // Kill the timeline.
+    timeline.destroy();
+
+    // wait for the thread to clean up.
+    waitThread.join();
+}
+
+TEST(FenceTest, MultiTimelineWait) {
+    SyncTimeline timelineA, timelineB, timelineC;
+
+    SyncFence fenceA(timelineA, 5);
+    SyncFence fenceB(timelineB, 5);
+    SyncFence fenceC(timelineC, 5);
+
+    // Make a larger fence using 3 other fences from different timelines.
+    SyncFence mergedFence({fenceA, fenceB, fenceC});
+    ASSERT_TRUE(mergedFence.isValid());
+
+    // Confirm fence isn't signaled
+    ASSERT_EQ(mergedFence.getActiveCount(), 3);
+    ASSERT_EQ(mergedFence.wait(0), -1);
+    ASSERT_EQ(errno, ETIME);
+
+    timelineA.inc(5);
+    ASSERT_EQ(mergedFence.getActiveCount(), 2);
+    ASSERT_EQ(mergedFence.getSignaledCount(), 1);
+
+    timelineB.inc(5);
+    ASSERT_EQ(mergedFence.getActiveCount(), 1);
+    ASSERT_EQ(mergedFence.getSignaledCount(), 2);
+
+    timelineC.inc(5);
+    ASSERT_EQ(mergedFence.getActiveCount(), 0);
+    ASSERT_EQ(mergedFence.getSignaledCount(), 3);
+
+    // confirm you can successfully wait.
+    ASSERT_EQ(mergedFence.wait(100), 0);
+}
+
+TEST(StressTest, TwoThreadsSharedTimeline) {
+    const int iterations = 1 << 16;
+    int counter = 0;
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    // Use a single timeline to synchronize two threads
+    // hammmering on the same counter.
+    auto threadMain = [&](int threadId) {
+        for (int i = 0; i < iterations; i++) {
+            SyncFence fence(timeline, i * 2 + threadId);
+            ASSERT_TRUE(fence.isValid());
+
+            // Wait on the prior thread to complete.
+            ASSERT_EQ(fence.wait(), 0);
+
+            // Confirm the previous thread's writes are visible and then inc.
+            ASSERT_EQ(counter, i * 2 + threadId);
+            counter++;
+
+            // Kick off the other thread.
+            ASSERT_EQ(timeline.inc(), 0);
+        }
+    };
+
+    thread a{threadMain, 0};
+    thread b{threadMain, 1};
+    a.join();
+    b.join();
+
+    // make sure the threads did not trample on one another.
+    ASSERT_EQ(counter, iterations * 2);
+}
+
+class ConsumerStressTest : public ::testing::TestWithParam<int> {};
+
+TEST_P(ConsumerStressTest, MultiProducerSingleConsumer) {
+    mutex lock;
+    int counter = 0;
+    int iterations = 1 << 12;
+
+    vector<SyncTimeline> producerTimelines(GetParam());
+    vector<thread> threads;
+    SyncTimeline consumerTimeline;
+
+    // Producer threads run this lambda.
+    auto threadMain = [&](int threadId) {
+        for (int i = 0; i < iterations; i++) {
+            SyncFence fence(consumerTimeline, i);
+            ASSERT_TRUE(fence.isValid());
+
+            // Wait for the consumer to finish. Use alternate
+            // means of waiting on the fence.
+            if ((iterations + threadId) % 8 != 0) {
+                ASSERT_EQ(fence.wait(), 0);
+            }
+            else {
+                while (fence.getSignaledCount() != 1) {
+                    ASSERT_EQ(fence.getErrorCount(), 0);
+                }
+            }
+
+            // Every producer increments the counter, the consumer checks + erases it.
+            lock.lock();
+            counter++;
+            lock.unlock();
+
+            ASSERT_EQ(producerTimelines[threadId].inc(), 0);
+        }
+    };
+
+    for (int i = 0; i < GetParam(); i++) {
+        threads.push_back(thread{threadMain, i});
+    }
+
+    // Consumer thread runs this loop.
+    for (int i = 1; i <= iterations; i++) {
+        // Create a fence representing all producers final timelines.
+        vector<SyncFence> fences;
+        for (auto& timeline : producerTimelines) {
+            fences.push_back(SyncFence(timeline, i));
+        }
+        SyncFence mergeFence(fences);
+        ASSERT_TRUE(mergeFence.isValid());
+
+        // Make sure we see an increment from every producer thread. Vary
+        // the means by which we wait.
+        if (iterations % 8 != 0) {
+            ASSERT_EQ(mergeFence.wait(), 0);
+        }
+        else {
+            while (mergeFence.getSignaledCount() != mergeFence.getSize()) {
+                ASSERT_EQ(mergeFence.getErrorCount(), 0);
+            }
+        }
+        ASSERT_EQ(counter, GetParam()*i);
+
+        // Release the producer threads.
+        ASSERT_EQ(consumerTimeline.inc(), 0);
+    }
+
+    for_each(begin(threads), end(threads), [](thread& thread) { thread.join(); });
+}
+INSTANTIATE_TEST_CASE_P(
+    ParameterizedStressTest,
+    ConsumerStressTest,
+    ::testing::Values(2,4,16));
+
+class MergeStressTest : public ::testing::TestWithParam<tuple<int, int>> {};
+
+template <typename K, typename V> using dict = unordered_map<K,V>;
+
+TEST_P(MergeStressTest, RandomMerge) {
+    int timelineCount = get<0>(GetParam());
+    int mergeCount = get<1>(GetParam());
+
+    vector<SyncTimeline> timelines(timelineCount);
+
+    default_random_engine generator;
+    uniform_int_distribution<int> timelineDist(0, timelines.size()-1);
+    uniform_int_distribution<int> syncPointDist(0, numeric_limits<int>::max());
+
+    SyncFence fence(timelines[0], 0);
+    ASSERT_TRUE(fence.isValid());
+
+    unordered_map<int, int> fenceMap;
+    fenceMap.insert(make_tuple(0, 0));
+
+    // Randomly create syncpoints out of a fixed set of timelines, and merge them together.
+    for (int i = 0; i < mergeCount; i++) {
+
+        // Generate syncpoint.
+        int timelineOffset = timelineDist(generator);
+        const SyncTimeline& timeline = timelines[timelineOffset];
+        int syncPoint = syncPointDist(generator);
+
+        // Keep track of the latest syncpoint in each timeline.
+        auto itr = fenceMap.find(timelineOffset);
+        if (itr == end(fenceMap)) {
+            fenceMap.insert(tie(timelineOffset, syncPoint));
+        }
+        else {
+            int oldSyncPoint = itr->second;
+            fenceMap.erase(itr);
+            fenceMap.insert(tie(timelineOffset, max(syncPoint, oldSyncPoint)));
+        }
+
+        // Merge.
+        fence = SyncFence(fence, SyncFence(timeline, syncPoint));
+        ASSERT_TRUE(fence.isValid());
+    }
+
+    // Confirm our map matches the fence.
+    ASSERT_EQ(fence.getSize(), fenceMap.size());
+
+    // Trigger the merged fence.
+    for (auto& item: fenceMap) {
+        ASSERT_EQ(fence.wait(0), -1);
+        ASSERT_EQ(errno, ETIME);
+
+        // Increment the timeline to the last syncpoint.
+        timelines[item.first].inc(item.second);
+    }
+
+    // Check that the fence is triggered.
+    ASSERT_EQ(fence.wait(0), 0);
+}
+
+INSTANTIATE_TEST_CASE_P(
+    ParameterizedMergeStressTest,
+    MergeStressTest,
+    ::testing::Combine(::testing::Values(16,32), ::testing::Values(32, 1024, 1024*32)));
+
+}
+
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 1c9c70a..9d596ef 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -29,6 +29,8 @@
 #include <net/if.h>
 
 #include <linux/if.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter_ipv4/ipt_ULOG.h>
 /* From kernel's net/netfilter/xt_quota2.c */
@@ -46,6 +48,8 @@
 const int NetlinkEvent::NlActionAddressUpdated = 6;
 const int NetlinkEvent::NlActionAddressRemoved = 7;
 const int NetlinkEvent::NlActionRdnss = 8;
+const int NetlinkEvent::NlActionRouteUpdated = 9;
+const int NetlinkEvent::NlActionRouteRemoved = 10;
 
 NetlinkEvent::NetlinkEvent() {
     mAction = NlActionUnknown;
@@ -78,32 +82,109 @@
 }
 
 /*
+ * Returns the message name for a message in the NETLINK_ROUTE family, or NULL
+ * if parsing that message is not supported.
+ */
+static const char *rtMessageName(int type) {
+#define NL_EVENT_RTM_NAME(rtm) case rtm: return #rtm;
+    switch (type) {
+        NL_EVENT_RTM_NAME(RTM_NEWLINK);
+        NL_EVENT_RTM_NAME(RTM_DELLINK);
+        NL_EVENT_RTM_NAME(RTM_NEWADDR);
+        NL_EVENT_RTM_NAME(RTM_DELADDR);
+        NL_EVENT_RTM_NAME(RTM_NEWROUTE);
+        NL_EVENT_RTM_NAME(RTM_DELROUTE);
+        NL_EVENT_RTM_NAME(RTM_NEWNDUSEROPT);
+        NL_EVENT_RTM_NAME(QLOG_NL_EVENT);
+        default:
+            return NULL;
+    }
+#undef NL_EVENT_RTM_NAME
+}
+
+/*
+ * Checks that a binary NETLINK_ROUTE message is long enough for a payload of
+ * size bytes.
+ */
+static bool checkRtNetlinkLength(const struct nlmsghdr *nh, size_t size) {
+    if (nh->nlmsg_len < NLMSG_LENGTH(size)) {
+        SLOGE("Got a short %s message\n", rtMessageName(nh->nlmsg_type));
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Utility function to log errors.
+ */
+static bool maybeLogDuplicateAttribute(bool isDup,
+                                       const char *attributeName,
+                                       const char *messageName) {
+    if (isDup) {
+        SLOGE("Multiple %s attributes in %s, ignoring\n", attributeName, messageName);
+        return true;
+    }
+    return false;
+}
+
+/*
+ * Parse a RTM_NEWLINK message.
+ */
+bool NetlinkEvent::parseIfInfoMessage(const struct nlmsghdr *nh) {
+    struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(nh);
+    if (!checkRtNetlinkLength(nh, sizeof(*ifi)))
+        return false;
+
+    if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) {
+        return false;
+    }
+
+    int len = IFLA_PAYLOAD(nh);
+    struct rtattr *rta;
+    for (rta = IFLA_RTA(ifi); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
+        switch(rta->rta_type) {
+            case IFLA_IFNAME:
+                asprintf(&mParams[0], "INTERFACE=%s", (char *) RTA_DATA(rta));
+                mAction = (ifi->ifi_flags & IFF_LOWER_UP) ?  NlActionLinkUp :
+                                                             NlActionLinkDown;
+                mSubsystem = strdup("net");
+                return true;
+        }
+    }
+
+    return false;
+}
+
+/*
  * Parse a RTM_NEWADDR or RTM_DELADDR message.
  */
-bool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr,
-                                      int rtasize) {
-    struct rtattr *rta;
+bool NetlinkEvent::parseIfAddrMessage(const struct nlmsghdr *nh) {
+    struct ifaddrmsg *ifaddr = (struct ifaddrmsg *) NLMSG_DATA(nh);
     struct ifa_cacheinfo *cacheinfo = NULL;
     char addrstr[INET6_ADDRSTRLEN] = "";
+    char ifname[IFNAMSIZ];
+
+    if (!checkRtNetlinkLength(nh, sizeof(*ifaddr)))
+        return false;
 
     // Sanity check.
+    int type = nh->nlmsg_type;
     if (type != RTM_NEWADDR && type != RTM_DELADDR) {
         SLOGE("parseIfAddrMessage on incorrect message type 0x%x\n", type);
         return false;
     }
 
     // For log messages.
-    const char *msgtype = (type == RTM_NEWADDR) ? "RTM_NEWADDR" : "RTM_DELADDR";
+    const char *msgtype = rtMessageName(type);
 
-    for (rta = IFA_RTA(ifaddr); RTA_OK(rta, rtasize);
-         rta = RTA_NEXT(rta, rtasize)) {
+    struct rtattr *rta;
+    int len = IFA_PAYLOAD(nh);
+    for (rta = IFA_RTA(ifaddr); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
         if (rta->rta_type == IFA_ADDRESS) {
             // Only look at the first address, because we only support notifying
             // one change at a time.
-            if (*addrstr != '\0') {
-                SLOGE("Multiple IFA_ADDRESSes in %s, ignoring\n", msgtype);
+            if (maybeLogDuplicateAttribute(*addrstr != '\0', "IFA_ADDRESS", msgtype))
                 continue;
-            }
 
             // Convert the IP address to a string.
             if (ifaddr->ifa_family == AF_INET) {
@@ -128,28 +209,15 @@
             }
 
             // Find the interface name.
-            char ifname[IFNAMSIZ + 1];
             if (!if_indextoname(ifaddr->ifa_index, ifname)) {
                 SLOGE("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype);
                 return false;
             }
 
-            // Fill in interface information.
-            mAction = (type == RTM_NEWADDR) ? NlActionAddressUpdated :
-                                              NlActionAddressRemoved;
-            mSubsystem = strdup("net");
-            asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
-                     ifaddr->ifa_prefixlen);
-            asprintf(&mParams[1], "INTERFACE=%s", ifname);
-            asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
-            asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
         } else if (rta->rta_type == IFA_CACHEINFO) {
             // Address lifetime information.
-            if (cacheinfo) {
-                // We only support one address.
-                SLOGE("Multiple IFA_CACHEINFOs in %s, ignoring\n", msgtype);
+            if (maybeLogDuplicateAttribute(cacheinfo, "IFA_CACHEINFO", msgtype))
                 continue;
-            }
 
             if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) {
                 SLOGE("Short IFA_CACHEINFO (%zu vs. %zu bytes) in %s",
@@ -158,10 +226,6 @@
             }
 
             cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta);
-            asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered);
-            asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid);
-            asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp);
-            asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp);
         }
     }
 
@@ -170,14 +234,145 @@
         return false;
     }
 
+    // Fill in netlink event information.
+    mAction = (type == RTM_NEWADDR) ? NlActionAddressUpdated :
+                                      NlActionAddressRemoved;
+    mSubsystem = strdup("net");
+    asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
+             ifaddr->ifa_prefixlen);
+    asprintf(&mParams[1], "INTERFACE=%s", ifname);
+    asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
+    asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
+
+    if (cacheinfo) {
+        asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered);
+        asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid);
+        asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp);
+        asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp);
+    }
+
+    return true;
+}
+
+/*
+ * Parse a QLOG_NL_EVENT message.
+ */
+bool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) {
+    const char *devname;
+    ulog_packet_msg_t *pm = (ulog_packet_msg_t *) NLMSG_DATA(nh);
+    if (!checkRtNetlinkLength(nh, sizeof(*pm)))
+        return false;
+
+    devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;
+    asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
+    asprintf(&mParams[1], "INTERFACE=%s", devname);
+    mSubsystem = strdup("qlog");
+    mAction = NlActionChange;
+    return true;
+}
+
+/*
+ * Parse a RTM_NEWROUTE or RTM_DELROUTE message.
+ */
+bool NetlinkEvent::parseRtMessage(const struct nlmsghdr *nh) {
+    uint8_t type = nh->nlmsg_type;
+    const char *msgname = rtMessageName(type);
+
+    // Sanity check.
+    if (type != RTM_NEWROUTE && type != RTM_DELROUTE) {
+        SLOGE("%s: incorrect message type %d (%s)\n", __func__, type, msgname);
+        return false;
+    }
+
+    struct rtmsg *rtm = (struct rtmsg *) NLMSG_DATA(nh);
+    if (!checkRtNetlinkLength(nh, sizeof(*rtm)))
+        return false;
+
+    if (// Ignore static routes we've set up ourselves.
+        (rtm->rtm_protocol != RTPROT_KERNEL &&
+         rtm->rtm_protocol != RTPROT_RA) ||
+        // We're only interested in global unicast routes.
+        (rtm->rtm_scope != RT_SCOPE_UNIVERSE) ||
+        (rtm->rtm_type != RTN_UNICAST) ||
+        // We don't support source routing.
+        (rtm->rtm_src_len != 0) ||
+        // Cloned routes aren't real routes.
+        (rtm->rtm_flags & RTM_F_CLONED)) {
+        return false;
+    }
+
+    int family = rtm->rtm_family;
+    int prefixLength = rtm->rtm_dst_len;
+
+    // Currently we only support: destination, (one) next hop, ifindex.
+    char dst[INET6_ADDRSTRLEN] = "";
+    char gw[INET6_ADDRSTRLEN] = "";
+    char dev[IFNAMSIZ] = "";
+
+    size_t len = RTM_PAYLOAD(nh);
+    struct rtattr *rta;
+    for (rta = RTM_RTA(rtm); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
+        switch (rta->rta_type) {
+            case RTA_DST:
+                if (maybeLogDuplicateAttribute(*dst, "RTA_DST", msgname))
+                    continue;
+                if (!inet_ntop(family, RTA_DATA(rta), dst, sizeof(dst)))
+                    return false;
+                continue;
+            case RTA_GATEWAY:
+                if (maybeLogDuplicateAttribute(*gw, "RTA_GATEWAY", msgname))
+                    continue;
+                if (!inet_ntop(family, RTA_DATA(rta), gw, sizeof(gw)))
+                    return false;
+                continue;
+            case RTA_OIF:
+                if (maybeLogDuplicateAttribute(*dev, "RTA_OIF", msgname))
+                    continue;
+                if (!if_indextoname(* (int *) RTA_DATA(rta), dev))
+                    return false;
+            default:
+                continue;
+        }
+    }
+
+   // If there's no RTA_DST attribute, then:
+   // - If the prefix length is zero, it's the default route.
+   // - If the prefix length is nonzero, there's something we don't understand.
+   //   Ignore the event.
+   if (!*dst && !prefixLength) {
+        if (family == AF_INET) {
+            strncpy(dst, "0.0.0.0", sizeof(dst));
+        } else if (family == AF_INET6) {
+            strncpy(dst, "::", sizeof(dst));
+        }
+    }
+
+    // A useful route must have a destination and at least either a gateway or
+    // an interface.
+    if (!*dst || (!*gw && !*dev))
+        return false;
+
+    // Fill in netlink event information.
+    mAction = (type == RTM_NEWROUTE) ? NlActionRouteUpdated :
+                                       NlActionRouteRemoved;
+    mSubsystem = strdup("net");
+    asprintf(&mParams[0], "ROUTE=%s/%d", dst, prefixLength);
+    asprintf(&mParams[1], "GATEWAY=%s", (*gw) ? gw : "");
+    asprintf(&mParams[2], "INTERFACE=%s", (*dev) ? dev : "");
+
     return true;
 }
 
 /*
  * Parse a RTM_NEWNDUSEROPT message.
  */
-bool NetlinkEvent::parseNdUserOptMessage(struct nduseroptmsg *msg, int len) {
+bool NetlinkEvent::parseNdUserOptMessage(const struct nlmsghdr *nh) {
+    struct nduseroptmsg *msg = (struct nduseroptmsg *) NLMSG_DATA(nh);
+    if (!checkRtNetlinkLength(nh, sizeof(*msg)))
+        return false;
+
     // Check the length is valid.
+    int len = NLMSG_PAYLOAD(nh, sizeof(*msg));
     if (msg->nduseropt_opts_len > len) {
         SLOGE("RTM_NEWNDUSEROPT invalid length %d > %d\n",
               msg->nduseropt_opts_len, len);
@@ -200,7 +395,7 @@
     }
 
     // Find the interface name.
-    char ifname[IFNAMSIZ + 1];
+    char ifname[IFNAMSIZ];
     if (!if_indextoname(msg->nduseropt_ifindex, ifname)) {
         SLOGE("RTM_NEWNDUSEROPT on unknown ifindex %d\n",
               msg->nduseropt_ifindex);
@@ -273,6 +468,14 @@
 
 /*
  * Parse a binary message from a NETLINK_ROUTE netlink socket.
+ *
+ * Note that this function can only parse one message, because the message's
+ * content has to be stored in the class's member variables (mAction,
+ * mSubsystem, etc.). Invalid or unrecognized messages are skipped, but if
+ * there are multiple valid messages in the buffer, only the first one will be
+ * returned.
+ *
+ * TODO: consider only ever looking at the first message.
  */
 bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
     const struct nlmsghdr *nh;
@@ -281,93 +484,37 @@
          NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE);
          nh = NLMSG_NEXT(nh, size)) {
 
+        if (!rtMessageName(nh->nlmsg_type)) {
+            SLOGD("Unexpected netlink message type %d\n", nh->nlmsg_type);
+            continue;
+        }
+
         if (nh->nlmsg_type == RTM_NEWLINK) {
-            int len = nh->nlmsg_len - sizeof(*nh);
-            struct ifinfomsg *ifi;
-
-            if (sizeof(*ifi) > (size_t) len) {
-                SLOGE("Got a short RTM_NEWLINK message\n");
-                continue;
-            }
-
-            ifi = (ifinfomsg *)NLMSG_DATA(nh);
-            if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) {
-                continue;
-            }
-
-            struct rtattr *rta = (struct rtattr *)
-              ((char *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
-            len = NLMSG_PAYLOAD(nh, sizeof(*ifi));
-
-            while(RTA_OK(rta, len)) {
-                switch(rta->rta_type) {
-                case IFLA_IFNAME:
-                    char buffer[16 + IFNAMSIZ];
-                    snprintf(buffer, sizeof(buffer), "INTERFACE=%s",
-                             (char *) RTA_DATA(rta));
-                    mParams[0] = strdup(buffer);
-                    mAction = (ifi->ifi_flags & IFF_LOWER_UP) ?
-                      NlActionLinkUp : NlActionLinkDown;
-                    mSubsystem = strdup("net");
-                    break;
-                }
-
-                rta = RTA_NEXT(rta, len);
-            }
+            if (parseIfInfoMessage(nh))
+                return true;
 
         } else if (nh->nlmsg_type == QLOG_NL_EVENT) {
-            char *devname;
-            ulog_packet_msg_t *pm;
-            size_t len = nh->nlmsg_len - sizeof(*nh);
-            if (sizeof(*pm) > len) {
-                SLOGE("Got a short QLOG message\n");
-                continue;
-            }
-            pm = (ulog_packet_msg_t *)NLMSG_DATA(nh);
-            devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;
-            asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
-            asprintf(&mParams[1], "INTERFACE=%s", devname);
-            mSubsystem = strdup("qlog");
-            mAction = NlActionChange;
+            if (parseUlogPacketMessage(nh))
+                return true;
 
         } else if (nh->nlmsg_type == RTM_NEWADDR ||
                    nh->nlmsg_type == RTM_DELADDR) {
-            int len = nh->nlmsg_len - sizeof(*nh);
-            struct ifaddrmsg *ifa;
+            if (parseIfAddrMessage(nh))
+                return true;
 
-            if (sizeof(*ifa) > (size_t) len) {
-                SLOGE("Got a short RTM_xxxADDR message\n");
-                continue;
-            }
-
-            ifa = (ifaddrmsg *)NLMSG_DATA(nh);
-            size_t rtasize = IFA_PAYLOAD(nh);
-            if (!parseIfAddrMessage(nh->nlmsg_type, ifa, rtasize)) {
-                continue;
-            }
+        } else if (nh->nlmsg_type == RTM_NEWROUTE ||
+                   nh->nlmsg_type == RTM_DELROUTE) {
+            if (parseRtMessage(nh))
+                return true;
 
         } else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) {
-            int len = nh->nlmsg_len - sizeof(*nh);
-            struct nduseroptmsg *ndmsg = (struct nduseroptmsg *) NLMSG_DATA(nh);
+            if (parseNdUserOptMessage(nh))
+                return true;
 
-            if (sizeof(*ndmsg) > (size_t) len) {
-                SLOGE("Got a short RTM_NEWNDUSEROPT message\n");
-                continue;
-            }
-
-            size_t optsize = NLMSG_PAYLOAD(nh, sizeof(*ndmsg));
-            if (!parseNdUserOptMessage(ndmsg, optsize)) {
-                continue;
-            }
-
-
-        } else {
-                SLOGD("Unexpected netlink message. type=0x%x\n",
-                      nh->nlmsg_type);
         }
     }
 
-    return true;
+    return false;
 }
 
 /* If the string between 'str' and 'end' begins with 'prefixlen' characters
diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp
index 9c447ca..81c5cc2 100644
--- a/libsysutils/src/NetlinkListener.cpp
+++ b/libsysutils/src/NetlinkListener.cpp
@@ -57,10 +57,12 @@
     }
 
     NetlinkEvent *evt = new NetlinkEvent();
-    if (!evt->decode(mBuffer, count, mFormat)) {
-        SLOGE("Error decoding NetlinkEvent");
-    } else {
+    if (evt->decode(mBuffer, count, mFormat)) {
         onEvent(evt);
+    } else if (mFormat != NETLINK_FORMAT_BINARY) {
+        // Don't complain if parseBinaryNetlinkMessage returns false. That can
+        // just mean that the buffer contained no messages we're interested in.
+        SLOGE("Error decoding NetlinkEvent");
     }
 
     delete evt;
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index cd8000a..488dd0e 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -454,6 +454,8 @@
     int i, result;
     int languageCount = 0;
 
+    if (id == 0) return NULL;
+
     string[0] = 0;
     memset(languages, 0, sizeof(languages));
 
@@ -487,31 +489,19 @@
 char* usb_device_get_manufacturer_name(struct usb_device *device)
 {
     struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
-
-    if (desc->iManufacturer)
-        return usb_device_get_string(device, desc->iManufacturer);
-    else
-        return NULL;
+    return usb_device_get_string(device, desc->iManufacturer);
 }
 
 char* usb_device_get_product_name(struct usb_device *device)
 {
     struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
-
-    if (desc->iProduct)
-        return usb_device_get_string(device, desc->iProduct);
-    else
-        return NULL;
+    return usb_device_get_string(device, desc->iProduct);
 }
 
 char* usb_device_get_serial(struct usb_device *device)
 {
     struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
-
-    if (desc->iSerialNumber)
-        return usb_device_get_string(device, desc->iSerialNumber);
-    else
-        return NULL;
+    return usb_device_get_string(device, desc->iSerialNumber);
 }
 
 int usb_device_is_writeable(struct usb_device *device)
@@ -557,6 +547,21 @@
     return ioctl(device->fd, USBDEVFS_IOCTL, &ctl);
 }
 
+int usb_device_set_configuration(struct usb_device *device, int configuration)
+{
+    return ioctl(device->fd, USBDEVFS_SETCONFIGURATION, &configuration);
+}
+
+int usb_device_set_interface(struct usb_device *device, unsigned int interface,
+                            unsigned int alt_setting)
+{
+    struct usbdevfs_setinterface ctl;
+
+    ctl.interface = interface;
+    ctl.altsetting = alt_setting;
+    return ioctl(device->fd, USBDEVFS_SETINTERFACE, &ctl);
+}
+
 int usb_device_control_transfer(struct usb_device *device,
                             int requestType,
                             int request,
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 9a50147..9343f8e 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -26,6 +26,7 @@
 	LinearAllocator.cpp \
 	LinearTransform.cpp \
 	Log.cpp \
+	NativeHandle.cpp \
 	Printer.cpp \
 	ProcessCallStack.cpp \
 	PropertyMap.cpp \
diff --git a/libutils/NativeHandle.cpp b/libutils/NativeHandle.cpp
new file mode 100644
index 0000000..e4daca7
--- /dev/null
+++ b/libutils/NativeHandle.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/NativeHandle.h>
+#include <cutils/native_handle.h>
+
+namespace android {
+
+sp<NativeHandle> NativeHandle::create(
+        native_handle_t* handle, bool ownsHandle) {
+    return handle ? new NativeHandle(handle, ownsHandle) : NULL;
+}
+
+NativeHandle::NativeHandle(native_handle_t* handle, bool ownsHandle)
+:   mHandle(handle), mOwnsHandle(ownsHandle)
+{}
+
+NativeHandle::~NativeHandle() {
+    if (mOwnsHandle) {
+        native_handle_close(mHandle);
+        native_handle_delete(mHandle);
+    }
+}
+
+} // namespace android
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 49340bb..9092cbc 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -408,6 +408,30 @@
     return p ? p-mString : -1;
 }
 
+bool String8::removeAll(const char* other) {
+    ssize_t index = find(other);
+    if (index < 0) return false;
+
+    char* buf = lockBuffer(size());
+    if (!buf) return false; // out of memory
+
+    size_t skip = strlen(other);
+    size_t len = size();
+    size_t tail = index;
+    while (size_t(index) < len) {
+        ssize_t next = find(other, index + skip);
+        if (next < 0) {
+            next = len;
+        }
+
+        memcpy(buf + tail, buf + index + skip, next - index - skip);
+        tail += next - index - skip;
+        index = next;
+    }
+    unlockBuffer(tail);
+    return true;
+}
+
 void String8::toLower()
 {
     toLower(0, size());
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index fe8887d..378d2a7 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -342,7 +342,8 @@
     while (cur_utf16 < end_utf16) {
         char32_t utf32;
         // surrogate pairs
-        if ((*cur_utf16 & 0xFC00) == 0xD800) {
+        if((*cur_utf16 & 0xFC00) == 0xD800 && (cur_utf16 + 1) < end_utf16
+                && (*(cur_utf16 + 1) & 0xFC00) == 0xDC00) {
             utf32 = (*cur_utf16++ - 0xD800) << 10;
             utf32 |= *cur_utf16++ - 0xDC00;
             utf32 += 0x10000;
diff --git a/lmkd/Android.mk b/lmkd/Android.mk
index 5d6d1d2..2dd8af2 100644
--- a/lmkd/Android.mk
+++ b/lmkd/Android.mk
@@ -2,8 +2,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := lmkd.c
-LOCAL_STATIC_LIBRARIES := libcutils liblog libm libc
-LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_SHARED_LIBRARIES := libcutils liblog libm libc
+LOCAL_CFLAGS := -Werror
 
 LOCAL_MODULE := lmkd
 
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 376410b..5caf77d 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -16,20 +16,26 @@
 
 #define LOG_TAG "lowmemorykiller"
 
+#include <arpa/inet.h>
 #include <errno.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
-#include <unistd.h>
-#include <arpa/inet.h>
+#include <sys/cdefs.h>
 #include <sys/epoll.h>
 #include <sys/eventfd.h>
 #include <sys/socket.h>
 #include <sys/types.h>
-#include <cutils/log.h>
+#include <unistd.h>
+
 #include <cutils/sockets.h>
+#include <log/log.h>
+
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
 
 #define MEMCG_SYSFS_PATH "/dev/memcg/"
 #define MEMPRESSURE_WATCH_LEVEL "medium"
@@ -75,6 +81,10 @@
 #define OOM_ADJUST_MIN (-16)
 #define OOM_ADJUST_MAX 15
 
+/* kernel OOM score values */
+#define OOM_SCORE_ADJ_MIN       (-1000)
+#define OOM_SCORE_ADJ_MAX       1000
+
 static int lowmem_adj[MAX_TARGETS];
 static int lowmem_minfree[MAX_TARGETS];
 static int lowmem_targets_size;
@@ -116,6 +126,14 @@
 /* PAGE_SIZE / 1024 */
 static long page_k;
 
+static int lowmem_oom_adj_to_oom_score_adj(int oom_adj)
+{
+    if (oom_adj == OOM_ADJUST_MAX)
+        return OOM_SCORE_ADJ_MAX;
+    else
+        return (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
+}
+
 static struct proc *pid_lookup(int pid) {
     struct proc *procp;
 
@@ -219,8 +237,8 @@
         return;
     }
 
-    snprintf(path, sizeof(path), "/proc/%d/oom_adj", pid);
-    snprintf(val, sizeof(val), "%d", oomadj);
+    snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", pid);
+    snprintf(val, sizeof(val), "%d", lowmem_oom_adj_to_oom_score_adj(oomadj));
     writefilestring(path, val);
 
     if (use_inkernel_interface)
@@ -245,8 +263,6 @@
 }
 
 static void cmd_procremove(int pid) {
-    struct proc *procp;
-
     if (use_inkernel_interface)
         return;
 
@@ -370,7 +386,7 @@
     }
 }
 
-static void ctrl_connect_handler(uint32_t events) {
+static void ctrl_connect_handler(uint32_t events __unused) {
     struct sockaddr addr;
     socklen_t alen;
     struct epoll_event epev;
@@ -412,7 +428,7 @@
             return 0;
         if (zoneval > max)
             max = zoneval;
-    } while (cp = strtok(NULL, " "));
+    } while ((cp = strtok(NULL, " ")));
 
     return max;
 }
@@ -443,7 +459,6 @@
 
 static int zoneinfo_parse(struct sysmeminfo *mip) {
     FILE *f;
-    char *cp;
     char line[LINE_MAX];
 
     memset(mip, 0, sizeof(struct sysmeminfo));
@@ -507,7 +522,7 @@
     return (struct proc *)adjslot_tail(&procadjslot_list[ADJTOSLOT(oomadj)]);
 }
 
-static void mp_event(uint32_t events) {
+static void mp_event(uint32_t events __unused) {
     int i;
     int ret;
     unsigned long long evcount;
@@ -726,7 +741,7 @@
     }
 }
 
-int main(int argc, char **argv) {
+int main(int argc __unused, char **argv __unused) {
     if (!init())
         mainloop();
 
diff --git a/logcat/event.logtags b/logcat/event.logtags
index a325692..1b5c6f4 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -134,5 +134,7 @@
 # libcore failure logging
 90100 exp_det_cert_pin_failure (certs|4)
 
+1397638484 snet_event_log (subtag|3) (uid|1) (message|3)
+
 # NOTE - the range 1000000-2000000 is reserved for partners and others who
 # want to define their own log tags without conflicting with the core platform.
diff --git a/rootdir/init.rc b/rootdir/init.rc
index c487723..b3ccae1 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -12,7 +12,7 @@
 
 on early-init
     # Set init and its forked children's oom_adj.
-    write /proc/1/oom_adj -16
+    write /proc/1/oom_score_adj -1000
 
     # Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
     write /sys/fs/selinux/checkreqprot 0
@@ -264,6 +264,7 @@
     mkdir /data/misc/wifi 0770 wifi wifi
     mkdir /data/misc/wifi/sockets 0770 wifi wifi
     mkdir /data/misc/wifi/wpa_supplicant 0770 wifi wifi
+    mkdir /data/misc/ethernet 0770 system system
     mkdir /data/misc/dhcp 0770 dhcp dhcp
     mkdir /data/misc/user 0771 root root
     # give system access to wpa_supplicant.conf for backup and restore
@@ -334,9 +335,9 @@
     write /proc/sys/vm/overcommit_memory 1
     write /proc/sys/vm/min_free_order_shift 4
     chown root system /sys/module/lowmemorykiller/parameters/adj
-    chmod 0664 /sys/module/lowmemorykiller/parameters/adj
+    chmod 0220 /sys/module/lowmemorykiller/parameters/adj
     chown root system /sys/module/lowmemorykiller/parameters/minfree
-    chmod 0664 /sys/module/lowmemorykiller/parameters/minfree
+    chmod 0220 /sys/module/lowmemorykiller/parameters/minfree
 
     # Tweak background writeout
     write /proc/sys/vm/dirty_expire_centisecs 200
@@ -425,11 +426,19 @@
     setprop net.tcp.default_init_rwnd 60
 
     class_start core
-    class_start main
 
 on nonencrypted
+    class_start main
     class_start late_start
 
+on property:vold.decrypt=trigger_default_encryption
+    start defaultcrypto
+
+on property:vold.decrypt=trigger_encryption
+    start surfaceflinger
+    start encrypt
+    class_start main
+
 on property:sys.init_log_level=*
     loglevel ${sys.init_log_level}
 
@@ -489,11 +498,6 @@
     critical
     seclabel u:r:healthd:s0
 
-service healthd-charger /sbin/healthd -n
-    class charger
-    critical
-    seclabel u:r:healthd:s0
-
 service console /system/bin/sh
     class core
     console
@@ -530,6 +534,7 @@
     onrestart restart zygote
     onrestart restart media
     onrestart restart surfaceflinger
+    onrestart restart inputflinger
     onrestart restart drm
 
 service vold /system/bin/vold
@@ -563,6 +568,12 @@
     group graphics drmrpc
     onrestart restart zygote
 
+service inputflinger /system/bin/inputflinger
+    class main
+    user system
+    group input
+    onrestart restart zygote
+
 service drm /system/bin/drmserver
     class main
     user drm
@@ -574,6 +585,20 @@
     group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
     ioprio rt 4
 
+# One shot invocation to deal with encrypted volume.
+service defaultcrypto /system/bin/vdc --wait cryptfs mountdefaultencrypted
+    disabled
+    oneshot
+    # vold will set vold.decrypt to trigger_restart_framework (default
+    # encryption) or trigger_restart_min_framework (other encryption)
+
+# One shot invocation to encrypt unencrypted volumes
+service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace default
+    disabled
+    oneshot
+    # vold will set vold.decrypt to trigger_restart_framework (default
+    # encryption)
+
 service bootanim /system/bin/bootanimation
     class main
     user graphics
@@ -585,7 +610,7 @@
     class main
     socket installd stream 600 system system
 
-service flash_recovery /system/etc/install-recovery.sh
+service flash_recovery /system/bin/install-recovery.sh
     class main
     oneshot
 
@@ -623,3 +648,8 @@
     socket mdnsd stream 0660 mdnsr inet
     disabled
     oneshot
+
+service pre-recovery /system/bin/uncrypt
+    class main
+    disabled
+    oneshot
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 7baad63..3a164ed 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -139,6 +139,8 @@
     PERM_ANDROID_DATA,
     /* This node is "/Android/obb" */
     PERM_ANDROID_OBB,
+    /* This node is "/Android/media" */
+    PERM_ANDROID_MEDIA,
     /* This node is "/Android/user" */
     PERM_ANDROID_USER,
 } perm_t;
@@ -475,6 +477,10 @@
             /* Single OBB directory is always shared */
             node->graft_path = fuse->obbpath;
             node->graft_pathlen = strlen(fuse->obbpath);
+        } else if (!strcasecmp(node->name, "media")) {
+            /* App-specific directories inside; let anyone traverse */
+            node->perm = PERM_ANDROID_MEDIA;
+            node->mode = 0771;
         } else if (!strcasecmp(node->name, "user")) {
             /* User directories must only be accessible to system, protected
              * by sdcard_all. Zygote will bind mount the appropriate user-
@@ -486,6 +492,7 @@
         break;
     case PERM_ANDROID_DATA:
     case PERM_ANDROID_OBB:
+    case PERM_ANDROID_MEDIA:
         appid = (appid_t) (uintptr_t) hashmapGet(fuse->package_to_appid, node->name);
         if (appid != 0) {
             node->uid = multiuser_get_uid(parent->userid, appid);
diff --git a/toolbox/ioctl.c b/toolbox/ioctl.c
index 17fabff..fd90812 100644
--- a/toolbox/ioctl.c
+++ b/toolbox/ioctl.c
@@ -63,10 +63,14 @@
         exit(1);
     }
 
-    fd = open(argv[optind], O_RDWR | O_SYNC);
-    if (fd < 0) {
-        fprintf(stderr, "cannot open %s\n", argv[optind]);
-        return 1;
+    if (!strcmp(argv[optind], "-")) {
+        fd = STDIN_FILENO;
+    } else {
+        fd = open(argv[optind], read_only ? O_RDONLY : (O_RDWR | O_SYNC));
+        if (fd < 0) {
+            fprintf(stderr, "cannot open %s\n", argv[optind]);
+            return 1;
+        }
     }
     optind++;
     
diff --git a/toolbox/ps.c b/toolbox/ps.c
index 57b4280..5458f6b 100644
--- a/toolbox/ps.c
+++ b/toolbox/ps.c
@@ -28,7 +28,8 @@
 #define SHOW_POLICY 4
 #define SHOW_CPU  8
 #define SHOW_MACLABEL 16
-#define SHOW_ABI 32
+#define SHOW_NUMERIC_UID 32
+#define SHOW_ABI 64
 
 static int display_flags = 0;
 
@@ -48,7 +49,7 @@
     unsigned utime, stime;
     int prio, nice, rtprio, sched, psr;
     struct passwd *pw;
-    
+
     sprintf(statline, "/proc/%d", pid);
     stat(statline, &stats);
 
@@ -70,7 +71,7 @@
         }
         cmdline[r] = 0;
     }
-    
+
     fd = open(statline, O_RDONLY);
     if(fd == 0) return -1;
     r = read(fd, statline, 1023);
@@ -92,7 +93,6 @@
     nexttok(&ptr); // pgrp
     nexttok(&ptr); // sid
     nexttok(&ptr); // tty
-    
     nexttok(&ptr); // tpgid
     nexttok(&ptr); // flags
     nexttok(&ptr); // minflt
@@ -132,21 +132,21 @@
     psr = atoi(nexttok(&ptr)); // processor
     rtprio = atoi(nexttok(&ptr)); // rt_priority
     sched = atoi(nexttok(&ptr)); // scheduling policy
-    
+
     nexttok(&ptr); // tty
-    
+
     if(tid != 0) {
         ppid = pid;
         pid = tid;
     }
 
     pw = getpwuid(stats.st_uid);
-    if(pw == 0) {
+    if(pw == 0 || (display_flags & SHOW_NUMERIC_UID)) {
         sprintf(user,"%d",(int)stats.st_uid);
     } else {
         strcpy(user,pw->pw_name);
     }
-    
+
     if(!namefilter || !strncmp(name, namefilter, strlen(namefilter))) {
         if (display_flags & SHOW_MACLABEL) {
             fd = open(macline, O_RDONLY);
@@ -229,7 +229,7 @@
     sprintf(tmp,"/proc/%d/task",pid);
     d = opendir(tmp);
     if(d == 0) return;
-    
+
     while((de = readdir(d)) != 0){
         if(isdigit(de->d_name[0])){
             int tid = atoi(de->d_name);
@@ -237,7 +237,7 @@
             ps_line(pid, tid, namefilter);
         }
     }
-    closedir(d);    
+    closedir(d);
 }
 
 int ps_main(int argc, char **argv)
@@ -247,13 +247,15 @@
     char *namefilter = 0;
     int pidfilter = 0;
     int threads = 0;
-    
+
     d = opendir("/proc");
     if(d == 0) return -1;
 
     while(argc > 1){
         if(!strcmp(argv[1],"-t")) {
             threads = 1;
+        } else if(!strcmp(argv[1],"-n")) {
+            display_flags |= SHOW_NUMERIC_UID;
         } else if(!strcmp(argv[1],"-x")) {
             display_flags |= SHOW_TIME;
         } else if(!strcmp(argv[1], "-Z")) {