am b85c2494: am 03b87b49: Merge "Make host ashmem_create_region seed only once."

* commit 'b85c2494df1e1003b3101e36b29faace3a51dc3f':
  Make host ashmem_create_region seed only once.
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..4704abb 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -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/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..4f2d40f 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -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"
@@ -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);
 }
@@ -939,13 +959,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 +995,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 +1215,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 = dupAndQuote(*argv++);
+            strncat(buf, " ", sizeof(buf) - 1);
+            strncat(buf, quoted, sizeof(buf) - 1);
+            free(quoted);
         }
 
         for(;;) {
@@ -1234,6 +1254,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 = dupAndQuote(*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");
@@ -1416,9 +1466,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 +1480,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();
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index dc4e77f..d3cb113 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;
         }
@@ -931,8 +934,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 +978,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 +985,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 +1003,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 +1016,7 @@
         return 1;
     }
 
-    if(sync_readmode(fd, rpath, &mode)) {
+    if(sync_readtime(fd, rpath, &time, &mode)) {
         return 1;
     }
     if(mode == 0) {
@@ -1047,13 +1047,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.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/services.c b/adb/services.c
index 7b809da..d1e8939 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 adjustment to prevent killing
+    int fd = adb_open("/proc/self/oom_adj", O_WRONLY);
+    if (fd >= 0) {
+        adb_write(fd, "0", 1);
+        adb_close(fd);
+    } else {
+       D("adb: unable to update oom_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 e3cadb1..0000000
--- a/charger/charger.c
+++ /dev/null
@@ -1,1017 +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>
-
-#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) {
-                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/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index cdaa09f..e75367e 100755
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -460,16 +460,16 @@
 // Reads the contents of the specified log device, filters out the entries
 // that don't match the specified pid, and writes them to the tombstone file.
 //
-// If "tail" is set, we only print the last few lines.
+// If "tail" is non-zero, log the last "tail" number of lines.
 static EventTagMap* g_eventTagMap = NULL;
 
-static void dump_log_file(log_t* log, pid_t pid, const char* filename,
-  unsigned int tail) {
+static void dump_log_file(
+    log_t* log, pid_t pid, const char* filename, unsigned int tail) {
   bool first = true;
-  struct logger_list *logger_list;
+  struct logger_list* logger_list;
 
   logger_list = android_logger_list_open(
-    android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid);
+      android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid);
 
   if (!logger_list) {
     XLOG("Unable to open %s: %s\n", filename, strerror(errno));
@@ -480,6 +480,7 @@
 
   while (true) {
     ssize_t actual = android_logger_list_read(logger_list, &log_entry);
+    struct logger_entry* entry;
 
     if (actual < 0) {
       if (actual == -EINTR) {
@@ -489,8 +490,7 @@
         // non-blocking EOF; we're done
         break;
       } else {
-        _LOG(log, 0, "Error while reading log: %s\n",
-          strerror(-actual));
+        _LOG(log, 0, "Error while reading log: %s\n", strerror(-actual));
         break;
       }
     } else if (actual == 0) {
@@ -503,16 +503,11 @@
     // because you will be writing as fast as you're reading.  Any
     // high-frequency debug diagnostics should just be written to
     // the tombstone file.
-    struct logger_entry* entry = &log_entry.entry_v1;
 
-    if (entry->pid != static_cast<int32_t>(pid)) {
-      // wrong pid, ignore
-      continue;
-    }
+    entry = &log_entry.entry_v1;
 
     if (first) {
-      _LOG(log, 0, "--------- %slog %s\n",
-        tail ? "tail end of " : "", filename);
+      _LOG(log, 0, "--------- %slog %s\n", tail ? "tail end of " : "", filename);
       first = false;
     }
 
@@ -554,7 +549,7 @@
     // consume any trailing newlines
     char* nl = msg + strlen(msg) - 1;
     while (nl >= msg && *nl == '\n') {
-        *nl-- = '\0';
+      *nl-- = '\0';
     }
 
     char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
@@ -571,7 +566,6 @@
       _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n",
          timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
          prioChar, tag, msg);
-
     } while ((msg = nl));
   }
 
@@ -580,7 +574,7 @@
 
 // Dumps the logs generated by the specified pid to the tombstone, from both
 // "system" and "main" log devices.  Ideally we'd interleave the output.
-static void dump_logs(log_t* log, pid_t pid, unsigned tail) {
+static void dump_logs(log_t* log, pid_t pid, unsigned int tail) {
   dump_log_file(log, pid, "system", tail);
   dump_log_file(log, pid, "main", tail);
 }
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index dcda005..ee3cbf9 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -208,16 +208,25 @@
     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;
+}
+
 int fs_mgr_mount_all(struct fstab *fstab)
 {
     int i = 0;
-    int encrypted = 0;
-    int ret = -1;
+    int encryptable = 0;
+    int error_count = 0;
     int mret;
     int mount_errno;
 
     if (!fstab) {
-        return ret;
+        return -1;
     }
 
     for (i = 0; i < fstab->num_entries; i++) {
@@ -242,7 +251,8 @@
                      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!");
                 continue;
@@ -250,47 +260,62 @@
         }
 
         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);
+                       fstab->recs[i].fs_type, fstab->recs[i].flags,
+                       fstab->recs[i].fs_options);
 
         if (!mret) {
+            /* If this is encryptable, need to trigger encryption */
+            if ((fstab->recs[i].fs_mgr_flags & MF_FORCECRYPT)) {
+                if (umount(fstab->recs[i].mount_point) == 0) {
+                    if (!encryptable) {
+                        encryptable = 2;
+                    } else {
+                        ERROR("Only one encryptable/encrypted partition supported");
+                        encryptable = 1;
+                    }
+                } else {
+                    INFO("Could not umount %s - allow continue unencrypted",
+                         fstab->recs[i].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) &&
+        /* mount(2) returned an error, check if it's encryptable and deal with it */
+        if (mount_errno != EBUSY && mount_errno != EACCES &&
+            (fstab->recs[i].fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT)) &&
             !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;
+                      MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) {
+                ERROR("Cannot mount tmpfs filesystem for encryptable fs at %s error: %s\n",
+                       fstab->recs[i].mount_point, strerror(errno));
+                ++error_count;
+                continue;
             }
-            encrypted = 1;
+            encryptable = 1;
         } 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[i].blk_device, fstab->recs[i].mount_point,
+                   fstab->recs[i].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
@@ -332,7 +357,8 @@
                      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!");
                 continue;
@@ -504,7 +530,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..6c21425 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.
@@ -392,7 +398,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..6bb568a 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -72,6 +72,7 @@
 #define MF_SWAPPRIO     0x80
 #define MF_ZRAMSIZE     0x100
 #define MF_VERIFY       0x200
+#define MF_FORCECRYPT   0x400
 /*
  * 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,
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/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 9b84c3e..a1912f1 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 1024
-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..cfac312
--- /dev/null
+++ b/healthd/healthd_mode_charger.cpp
@@ -0,0 +1,685 @@
+/*
+ * 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>
+
+#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 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;
+
+/* 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;
+
+    /* 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
+     * 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 = (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) {
+                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");
+
+    gr_init();
+    gr_font_size(&char_width, &char_height);
+
+    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);
+
+#ifndef CHARGER_DISABLE_INIT_BLANK
+    gr_fb_blank(true);
+#endif
+
+    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/properties.h b/include/cutils/properties.h
index 2c70165..798db8b 100644
--- a/include/cutils/properties.h
+++ b/include/cutils/properties.h
@@ -20,6 +20,7 @@
 #include <sys/cdefs.h>
 #include <stddef.h>
 #include <sys/system_properties.h>
+#include <stdint.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -44,6 +45,64 @@
 */
 int property_get(const char *key, char *value, const char *default_value);
 
+/* property_get_bool: returns the value of key coerced into a
+** boolean. If the property is not set, then the default value is returned.
+**
+* The following is considered to be true (1):
+**   "1", "true", "y", "yes", "on"
+**
+** The following is considered to be false (0):
+**   "0", "false", "n", "no", "off"
+**
+** The conversion is whitespace-sensitive (e.g. " off" will not be false).
+**
+** If no property with this key is set (or the key is NULL) or the boolean
+** conversion fails, the default value is returned.
+**/
+int8_t property_get_bool(const char *key, int8_t default_value);
+
+/* property_get_int64: returns the value of key truncated and coerced into a
+** int64_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+**   -- 0 prefix is octal
+**   -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int64_t property_get_int64(const char *key, int64_t default_value);
+
+/* property_get_int32: returns the value of key truncated and coerced into an
+** int32_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+**   -- 0 prefix is octal
+**   -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int32_t property_get_int32(const char *key, int32_t default_value);
+
 /* property_set: returns 0 on success, < 0 on failure
 */
 int property_set(const char *key, const char *value);
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 f5289c1..61ce211 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -252,6 +252,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/*" },
@@ -261,7 +263,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..cc4137e 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,29 @@
     AUDIO_FORMAT_HE_AAC_V1           = 0x05000000UL,
     AUDIO_FORMAT_HE_AAC_V2           = 0x06000000UL,
     AUDIO_FORMAT_VORBIS              = 0x07000000UL,
+    AUDIO_FORMAT_OPUS                = 0x08000000UL,
     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 +278,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 +361,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 +392,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 +420,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 +450,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 +478,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 +504,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 +598,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 +841,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 +859,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 +879,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 +925,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 +951,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 +990,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:
@@ -604,12 +1029,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/graphics.h b/include/system/graphics.h
index be86ae4..82877a0 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -165,24 +165,54 @@
     /*
      * 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 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 +327,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/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/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 d9f7bbe..37bbaa3 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -517,10 +517,14 @@
         return -1;
     }
 
-    /* ret is 1 if the device is encrypted, 0 if not, and -1 on error */
-    if (ret == 1) {
+    /* ret is 2 if device needs encrypted, 1 if the device appears encrypted,
+     * 0 if not, and -1 on error */
+    if (ret == 2) {
+        property_set("ro.crypto.state", "unencrypted");
+        property_set("vold.decrypt", "trigger_encryption");
+    } else if (ret == 1) {
         property_set("ro.crypto.state", "encrypted");
-        property_set("vold.decrypt", "1");
+        property_set("vold.decrypt", "trigger_default_encryption");
     } else if (ret == 0) {
         property_set("ro.crypto.state", "unencrypted");
         /* If fs_mgr determined this is an unencrypted device, then trigger
diff --git a/init/property_service.c b/init/property_service.c
index fb3bc8d..97f281f 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>
@@ -96,6 +97,8 @@
     { "persist.gps.",      AID_GPS,      0 },
     { "persist.service.bdroid.", AID_BLUETOOTH,   0 },
     { "selinux."         , AID_SYSTEM,   0 },
+    { "build.fingerprint", AID_SYSTEM,   0 },
+    { "partition."        , AID_SYSTEM,   0},
     { NULL, 0, 0 }
 };
 
@@ -110,6 +113,7 @@
 } control_perms[] = {
     { "dumpstate",AID_SHELL, AID_LOG },
     { "ril-daemon",AID_RADIO, AID_RADIO },
+    { "pre-recovery", AID_SYSTEM, AID_SYSTEM },
      {NULL, 0, 0 }
 };
 
@@ -282,7 +286,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;
@@ -292,11 +295,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;
@@ -369,6 +371,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;
@@ -381,7 +386,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/properties.c b/libcutils/properties.c
index 28d8b2f..b283658 100644
--- a/libcutils/properties.c
+++ b/libcutils/properties.c
@@ -15,17 +15,95 @@
  */
 
 #define LOG_TAG "properties"
+// #define LOG_NDEBUG 0
 
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include <unistd.h>
 #include <cutils/sockets.h>
 #include <errno.h>
 #include <assert.h>
 
 #include <cutils/properties.h>
+#include <stdbool.h>
+#include <inttypes.h>
 #include "loghack.h"
 
+int8_t property_get_bool(const char *key, int8_t default_value) {
+    if (!key) {
+        return default_value;
+    }
+
+    int8_t result = default_value;
+    char buf[PROPERTY_VALUE_MAX] = {'\0',};
+
+    int len = property_get(key, buf, "");
+    if (len == 1) {
+        char ch = buf[0];
+        if (ch == '0' || ch == 'n') {
+            result = false;
+        } else if (ch == '1' || ch == 'y') {
+            result = true;
+        }
+    } else if (len > 1) {
+         if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
+            result = false;
+        } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
+            result = true;
+        }
+    }
+
+    return result;
+}
+
+// Convert string property to int (default if fails); return default value if out of bounds
+static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound,
+        intmax_t default_value) {
+    if (!key) {
+        return default_value;
+    }
+
+    intmax_t result = default_value;
+    char buf[PROPERTY_VALUE_MAX] = {'\0',};
+    char *end = NULL;
+
+    int len = property_get(key, buf, "");
+    if (len > 0) {
+        int tmp = errno;
+        errno = 0;
+
+        // Infer base automatically
+        result = strtoimax(buf, &end, /*base*/0);
+        if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) {
+            // Over or underflow
+            result = default_value;
+            ALOGV("%s(%s,%" PRIdMAX ") - overflow", __FUNCTION__, key, default_value);
+        } else if (result < lower_bound || result > upper_bound) {
+            // Out of range of requested bounds
+            result = default_value;
+            ALOGV("%s(%s,%" PRIdMAX ") - out of range", __FUNCTION__, key, default_value);
+        } else if (end == buf) {
+            // Numeric conversion failed
+            result = default_value;
+            ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed",
+                    __FUNCTION__, key, default_value);
+        }
+
+        errno = tmp;
+    }
+
+    return result;
+}
+
+int64_t property_get_int64(const char *key, int64_t default_value) {
+    return (int64_t)property_get_imax(key, INT64_MIN, INT64_MAX, default_value);
+}
+
+int32_t property_get_int32(const char *key, int32_t default_value) {
+    return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value);
+}
+
 #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
 
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
@@ -44,10 +122,13 @@
     if(len > 0) {
         return len;
     }
-    
     if(default_value) {
         len = strlen(default_value);
-        memcpy(value, default_value, len + 1);
+        if (len >= PROPERTY_VALUE_MAX) {
+            len = PROPERTY_VALUE_MAX - 1;
+        }
+        memcpy(value, default_value, len);
+        value[len] = '\0';
     }
     return len;
 }
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/libcutils/tests/Android.mk b/libcutils/tests/Android.mk
new file mode 100644
index 0000000..d3e07f8
--- /dev/null
+++ b/libcutils/tests/Android.mk
@@ -0,0 +1,32 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+test_src_files := \
+    PropertiesTest.cpp \
+
+shared_libraries := \
+    libutils \
+    liblog
+
+static_libraries := \
+    libcutils
+
+LOCAL_SHARED_LIBRARIES := $(shared_libraries)
+LOCAL_STATIC_LIBRARIES := $(static_libraries)
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_MODULE := libcutils_test
+include $(BUILD_NATIVE_TEST)
diff --git a/libcutils/tests/PropertiesTest.cpp b/libcutils/tests/PropertiesTest.cpp
new file mode 100644
index 0000000..659821c
--- /dev/null
+++ b/libcutils/tests/PropertiesTest.cpp
@@ -0,0 +1,309 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Properties_test"
+#include <utils/Log.h>
+#include <gtest/gtest.h>
+
+#include <cutils/properties.h>
+#include <limits.h>
+#include <string>
+#include <sstream>
+#include <iostream>
+
+namespace android {
+
+#define STRINGIFY_INNER(x) #x
+#define STRINGIFY(x) STRINGIFY_INNER(x)
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+#define ASSERT_OK(x) ASSERT_EQ(0, (x))
+#define EXPECT_OK(x) EXPECT_EQ(0, (x))
+
+#define PROPERTY_TEST_KEY "libcutils.test.key"
+#define PROPERTY_TEST_VALUE_DEFAULT "<<<default_value>>>"
+
+template <typename T>
+static std::string HexString(T value) {
+    std::stringstream ss;
+    ss << "0x" << std::hex << std::uppercase << value;
+    return ss.str();
+}
+
+template <typename T>
+static ::testing::AssertionResult AssertEqualHex(const char *mExpr,
+        const char *nExpr,
+        T m,
+        T n) {
+    if (m == n) {
+        return ::testing::AssertionSuccess();
+    }
+
+    return ::testing::AssertionFailure()
+        << mExpr << " and " << nExpr << " (expected: " << HexString(m) <<
+        ", actual: " << HexString(n) << ") are not equal";
+}
+
+class PropertiesTest : public testing::Test {
+public:
+    PropertiesTest() : mValue() {}
+protected:
+    virtual void SetUp() {
+        EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
+    }
+
+    virtual void TearDown() {
+        EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
+    }
+
+    char mValue[PROPERTY_VALUE_MAX];
+
+    template <typename T>
+    static std::string ToString(T value) {
+        std::stringstream ss;
+        ss << value;
+
+        return ss.str();
+    }
+
+    // Return length of property read; value is written into mValue
+    int SetAndGetProperty(const char* value, const char* defaultValue = PROPERTY_TEST_VALUE_DEFAULT) {
+        EXPECT_OK(property_set(PROPERTY_TEST_KEY, value)) << "value: '" << value << "'";
+        return property_get(PROPERTY_TEST_KEY, mValue, defaultValue);
+    }
+
+    void ResetValue(unsigned char c = 0xFF) {
+        for (size_t i = 0; i < ARRAY_SIZE(mValue); ++i) {
+            mValue[i] = (char) c;
+        }
+    }
+};
+
+TEST_F(PropertiesTest, SetString) {
+
+    // Null key -> unsuccessful set
+    {
+        // Null key -> fails
+        EXPECT_GT(0, property_set(/*key*/NULL, PROPERTY_TEST_VALUE_DEFAULT));
+    }
+
+    // Null value -> returns default value
+    {
+        // Null value -> OK , and it clears the value
+        EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
+        ResetValue();
+
+        // Since the value is null, default value will be returned
+        int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+        EXPECT_EQ(strlen(PROPERTY_TEST_VALUE_DEFAULT), len);
+        EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue);
+    }
+
+    // Trivial case => get returns what was set
+    {
+        int len = SetAndGetProperty("hello_world");
+        EXPECT_EQ(strlen("hello_world"), len) << "hello_world key";
+        EXPECT_STREQ("hello_world", mValue);
+        ResetValue();
+    }
+
+    // Set to empty string => get returns default always
+    {
+        const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING";
+        int len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
+        EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key";
+        EXPECT_STREQ(EMPTY_STRING_DEFAULT, mValue);
+        ResetValue();
+    }
+
+    // Set to max length => get returns what was set
+    {
+        std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a');
+
+        int len = SetAndGetProperty(maxLengthString.c_str());
+        EXPECT_EQ(PROPERTY_VALUE_MAX-1, len) << "max length key";
+        EXPECT_STREQ(maxLengthString.c_str(), mValue);
+        ResetValue();
+    }
+
+    // Set to max length + 1 => set fails
+    {
+        const char* VALID_TEST_VALUE = "VALID_VALUE";
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, VALID_TEST_VALUE));
+
+        std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
+
+        // Expect that the value set fails since it's too long
+        EXPECT_GT(0, property_set(PROPERTY_TEST_KEY, oneLongerString.c_str()));
+        int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+
+        EXPECT_EQ(strlen(VALID_TEST_VALUE), len) << "set should've failed";
+        EXPECT_STREQ(VALID_TEST_VALUE, mValue);
+        ResetValue();
+    }
+}
+
+TEST_F(PropertiesTest, GetString) {
+
+    // Try to use a default value that's too long => set fails
+    {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+        std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a');
+        std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
+
+        // Expect that the value is truncated since it's too long (by 1)
+        int len = property_get(PROPERTY_TEST_KEY, mValue, oneLongerString.c_str());
+        EXPECT_EQ(PROPERTY_VALUE_MAX-1, len);
+        EXPECT_STREQ(maxLengthString.c_str(), mValue);
+        ResetValue();
+    }
+}
+
+TEST_F(PropertiesTest, GetBool) {
+    /**
+     * TRUE
+     */
+    const char *valuesTrue[] = { "1", "true", "y", "yes", "on", };
+    for (size_t i = 0; i < ARRAY_SIZE(valuesTrue); ++i) {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesTrue[i]));
+        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
+        EXPECT_TRUE(val) << "Property should've been TRUE for value: '" << valuesTrue[i] << "'";
+    }
+
+    /**
+     * FALSE
+     */
+    const char *valuesFalse[] = { "0", "false", "n", "no", "off", };
+    for (size_t i = 0; i < ARRAY_SIZE(valuesFalse); ++i) {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesFalse[i]));
+        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
+        EXPECT_FALSE(val) << "Property shoud've been FALSE For string value: '" << valuesFalse[i] << "'";
+    }
+
+    /**
+     * NEITHER
+     */
+    const char *valuesNeither[] = { "x0", "x1", "2", "-2", "True", "False", "garbage", "", " ",
+            "+1", "  1  ", "  true", "  true  ", "  y  ", "  yes", "yes  ",
+            "+0", "-0", "00", "  00  ", "  false", "false  ",
+    };
+    for (size_t i = 0; i < ARRAY_SIZE(valuesNeither); ++i) {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesNeither[i]));
+
+        // The default value should always be used
+        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
+        EXPECT_TRUE(val) << "Property should've been NEITHER (true) for string value: '" << valuesNeither[i] << "'";
+
+        val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
+        EXPECT_FALSE(val) << "Property should've been NEITHER (false) for string value: '" << valuesNeither[i] << "'";
+    }
+}
+
+TEST_F(PropertiesTest, GetInt64) {
+    const int64_t DEFAULT_VALUE = INT64_C(0xDEADBEEFBEEFDEAD);
+
+    const std::string longMaxString = ToString(INT64_MAX);
+    const std::string longStringOverflow = longMaxString + "0";
+
+    const std::string longMinString = ToString(INT64_MIN);
+    const std::string longStringUnderflow = longMinString + "0";
+
+    const char* setValues[] = {
+        // base 10
+        "1", "2", "12345", "-1", "-2", "-12345",
+        // base 16
+        "0xFF", "0x0FF", "0xC0FFEE",
+        // base 8
+        "0", "01234", "07",
+        // corner cases
+        "       2", "2      ", "+0", "-0", "  +0   ", longMaxString.c_str(), longMinString.c_str(),
+        // failing cases
+        NULL, "", " ", "    ", "hello", "     true     ", "y",
+        longStringOverflow.c_str(), longStringUnderflow.c_str(),
+    };
+
+    int64_t getValues[] = {
+        // base 10
+        1, 2, 12345, -1, -2, -12345,
+        // base 16
+        0xFF, 0x0FF, 0xC0FFEE,
+        // base 8
+        0, 01234, 07,
+        // corner cases
+        2, 2, 0, 0, 0, INT64_MAX, INT64_MIN,
+        // failing cases
+        DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE,
+        DEFAULT_VALUE, DEFAULT_VALUE,
+    };
+
+    ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues));
+
+    for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
+
+        int64_t val = property_get_int64(PROPERTY_TEST_KEY, DEFAULT_VALUE);
+        EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'";
+    }
+}
+
+TEST_F(PropertiesTest, GetInt32) {
+    const int32_t DEFAULT_VALUE = INT32_C(0xDEADBEEF);
+
+    const std::string intMaxString = ToString(INT32_MAX);
+    const std::string intStringOverflow = intMaxString + "0";
+
+    const std::string intMinString = ToString(INT32_MIN);
+    const std::string intStringUnderflow = intMinString + "0";
+
+    const char* setValues[] = {
+        // base 10
+        "1", "2", "12345", "-1", "-2", "-12345",
+        // base 16
+        "0xFF", "0x0FF", "0xC0FFEE", "0Xf00",
+        // base 8
+        "0", "01234", "07",
+        // corner cases
+        "       2", "2      ", "+0", "-0", "  +0   ", intMaxString.c_str(), intMinString.c_str(),
+        // failing cases
+        NULL, "", " ", "    ", "hello", "     true     ", "y",
+        intStringOverflow.c_str(), intStringUnderflow.c_str(),
+    };
+
+    int32_t getValues[] = {
+        // base 10
+        1, 2, 12345, -1, -2, -12345,
+        // base 16
+        0xFF, 0x0FF, 0xC0FFEE, 0Xf00,
+        // base 8
+        0, 01234, 07,
+        // corner cases
+        2, 2, 0, 0, 0, INT32_MAX, INT32_MIN,
+        // failing cases
+        DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE,
+        DEFAULT_VALUE, DEFAULT_VALUE,
+    };
+
+    ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues));
+
+    for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
+
+        int32_t val = property_get_int32(PROPERTY_TEST_KEY, DEFAULT_VALUE);
+        EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'";
+    }
+}
+
+} // namespace android
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/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 1c48619..1fef049 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/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/rootdir/init.rc b/rootdir/init.rc
index b66529f..7d8a4e3 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
@@ -240,6 +240,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
     # give system access to wpa_supplicant.conf for backup and restore
     chmod 0660 /data/misc/wifi/wpa_supplicant.conf
@@ -310,9 +311,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
@@ -401,11 +402,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 charger
     class_start charger
 
@@ -461,11 +470,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
@@ -502,6 +506,7 @@
     onrestart restart zygote
     onrestart restart media
     onrestart restart surfaceflinger
+    onrestart restart inputflinger
     onrestart restart drm
 
 service vold /system/bin/vold
@@ -535,6 +540,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
@@ -546,6 +557,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
@@ -557,7 +582,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
 
@@ -599,3 +624,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/Android.mk b/toolbox/Android.mk
index fddf0a9..78adf1e 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -68,7 +68,9 @@
 	swapon \
 	swapoff \
 	mkswap \
-	readlink
+	readlink \
+	mknod \
+	nohup
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
 TOOLS += r
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index c2256ff..da83ec3 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -295,6 +295,7 @@
 {
     int version;
     int fd;
+    int clkid = CLOCK_MONOTONIC;
     struct pollfd *new_ufds;
     char **new_device_names;
     char name[80];
@@ -335,6 +336,11 @@
         idstr[0] = '\0';
     }
 
+    if (ioctl(fd, EVIOCSCLOCKID, &clkid) != 0) {
+        fprintf(stderr, "Can't enable monotonic clock reporting: %s\n", strerror(errno));
+        // a non-fatal error
+    }
+
     new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
     if(new_ufds == NULL) {
         fprintf(stderr, "out of memory\n");
@@ -470,9 +476,9 @@
     return 0;
 }
 
-static void usage(int argc, char *argv[])
+static void usage(char *name)
 {
-    fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", argv[0]);
+    fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", name);
     fprintf(stderr, "    -t: show time stamps\n");
     fprintf(stderr, "    -n: don't print newlines\n");
     fprintf(stderr, "    -s: print switch states for given bits\n");
@@ -568,7 +574,7 @@
             fprintf(stderr, "%s: invalid option -%c\n",
                 argv[0], optopt);
         case 'h':
-            usage(argc, argv);
+            usage(argv[0]);
             exit(1);
         }
     } while (1);
@@ -580,7 +586,7 @@
         optind++;
     }
     if (optind != argc) {
-        usage(argc, argv);
+        usage(argv[0]);
         exit(1);
     }
     nfds = 1;
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/mknod.c b/toolbox/mknod.c
new file mode 100644
index 0000000..0fedece
--- /dev/null
+++ b/toolbox/mknod.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+static int print_usage() {
+    fprintf(stderr, "mknod <path> [b|c|u|p] <major> <minor>\n");
+    return EXIT_FAILURE;
+}
+
+int mknod_main(int argc, char **argv) {
+    char *path = NULL;
+    int major = 0;
+    int minor = 0;
+    int args = 0;
+    mode_t mode = 0660;
+
+    /* Check correct argument count is 3 or 5 */
+    if (argc != 3 && argc != 5) {
+        fprintf(stderr, "Incorrect argument count\n");
+        return print_usage();
+    }
+
+    path = argv[1];
+
+    const char node_type = *argv[2];
+    switch (node_type) {
+    case 'b':
+        mode |= S_IFBLK;
+        args = 5;
+        break;
+    case 'c':
+    case 'u':
+        mode |= S_IFCHR;
+        args = 5;
+        break;
+    case 'p':
+        mode |= S_IFIFO;
+        args = 3;
+        break;
+    default:
+        fprintf(stderr, "Invalid node type '%c'\n", node_type);
+        return print_usage();
+    }
+
+    if (argc != args) {
+        if (args == 5) {
+            fprintf(stderr, "Node type '%c' requires <major> and <minor>\n", node_type);
+        } else {
+            fprintf(stderr, "Node type '%c' does not require <major> and <minor>\n", node_type);
+        }
+        return print_usage();
+    }
+
+    if (args == 5) {
+        major = atoi(argv[3]);
+        minor = atoi(argv[4]);
+    }
+
+    if (mknod(path, mode, makedev(major, minor))) {
+        perror("Unable to create node");
+        return EXIT_FAILURE;
+    }
+    return 0;
+}
diff --git a/toolbox/nohup.c b/toolbox/nohup.c
new file mode 100644
index 0000000..363999d
--- /dev/null
+++ b/toolbox/nohup.c
@@ -0,0 +1,26 @@
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int nohup_main(int argc, char *argv[])
+{
+    if (argc < 2) {
+        fprintf(stderr, "Usage: %s [-n] program args...\n", argv[0]);
+        return EXIT_FAILURE;
+    }
+    signal(SIGHUP, SIG_IGN);
+    argv++;
+    if (strcmp(argv[0], "-n") == 0) {
+        argv++;
+        signal(SIGINT, SIG_IGN);
+        signal(SIGSTOP, SIG_IGN);
+        signal(SIGTTIN, SIG_IGN);
+        signal(SIGTTOU, SIG_IGN);
+        signal(SIGQUIT, SIG_IGN);
+        signal(SIGTERM, SIG_IGN);
+    }
+    execvp(argv[0], argv);
+    perror(argv[0]);
+    return EXIT_FAILURE;
+}
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")) {