Merge "Link directly with libm due to libpng dependency." into jb-mr1-dev
diff --git a/adb/Android.mk b/adb/Android.mk
index 1a25106..681c7c7 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -17,32 +17,34 @@
   USB_SRCS := usb_linux.c
   EXTRA_SRCS := get_my_path_linux.c
   LOCAL_LDLIBS += -lrt -lncurses -lpthread
+  LOCAL_SHARED_LIBRARIES := libcrypto
 endif
 
 ifeq ($(HOST_OS),darwin)
   USB_SRCS := usb_osx.c
   EXTRA_SRCS := get_my_path_darwin.c
-  LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
+  LOCAL_LDLIBS += -lpthread -lcrypto -framework CoreFoundation -framework IOKit -framework Carbon
 endif
 
 ifeq ($(HOST_OS),freebsd)
   USB_SRCS := usb_libusb.c
   EXTRA_SRCS := get_my_path_freebsd.c
   LOCAL_LDLIBS += -lpthread -lusb
+  LOCAL_SHARED_LIBRARIES := libcrypto
 endif
 
 ifeq ($(HOST_OS),windows)
   USB_SRCS := usb_windows.c
-  EXTRA_SRCS := get_my_path_windows.c
-  EXTRA_STATIC_LIBS := AdbWinApi
+  EXTRA_SRCS := get_my_path_windows.c ../libcutils/list.c
+  EXTRA_STATIC_LIBS := AdbWinApi libcrypto_static
   ifneq ($(strip $(USE_CYGWIN)),)
     # Pure cygwin case
-    LOCAL_LDLIBS += -lpthread
+    LOCAL_LDLIBS += -lpthread -lgdi32
     LOCAL_C_INCLUDES += /usr/include/w32api/ddk
   endif
   ifneq ($(strip $(USE_MINGW)),)
     # MinGW under Linux case
-    LOCAL_LDLIBS += -lws2_32
+    LOCAL_LDLIBS += -lws2_32 -lgdi32
     USE_SYSDEPS_WIN32 := 1
     LOCAL_C_INCLUDES += /usr/i586-mingw32msvc/include/ddk
   endif
@@ -57,6 +59,7 @@
 	transport_usb.c \
 	commandline.c \
 	adb_client.c \
+	adb_auth_host.c \
 	sockets.c \
 	services.c \
 	file_sync_client.c \
@@ -65,6 +68,7 @@
 	utils.c \
 	usb_vendors.c
 
+LOCAL_C_INCLUDES += external/openssl/include
 
 ifneq ($(USE_SYSDEPS_WIN32),)
   LOCAL_SRC_FILES += sysdeps_win32.c
@@ -104,6 +108,7 @@
 	transport.c \
 	transport_local.c \
 	transport_usb.c \
+	adb_auth_client.c \
 	sockets.c \
 	services.c \
 	file_sync_service.c \
@@ -127,7 +132,7 @@
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
 
-LOCAL_STATIC_LIBRARIES := libcutils libc
+LOCAL_STATIC_LIBRARIES := libcutils libc libmincrypt
 include $(BUILD_EXECUTABLE)
 
 
@@ -146,6 +151,7 @@
 	transport_usb.c \
 	commandline.c \
 	adb_client.c \
+	adb_auth_host.c \
 	sockets.c \
 	services.c \
 	file_sync_client.c \
@@ -165,9 +171,13 @@
 	-D_XOPEN_SOURCE \
 	-D_GNU_SOURCE
 
+LOCAL_C_INCLUDES += external/openssl/include
+
 LOCAL_MODULE := adb
 
 LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils
 
+LOCAL_SHARED_LIBRARIES := libcrypto
+
 include $(BUILD_EXECUTABLE)
 endif
diff --git a/adb/adb.c b/adb/adb.c
index f3251fe..e7d9485 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -28,6 +28,7 @@
 
 #include "sysdeps.h"
 #include "adb.h"
+#include "adb_auth.h"
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
@@ -46,6 +47,8 @@
 
 int HOST = 0;
 
+static int auth_enabled = 0;
+
 #if !ADB_HOST
 static const char *adb_device_banner = "device";
 #endif
@@ -100,6 +103,7 @@
         { "transport", TRACE_TRANSPORT },
         { "jdwp", TRACE_JDWP },
         { "services", TRACE_SERVICES },
+        { "auth", TRACE_AUTH },
         { NULL, 0 }
     };
 
@@ -203,19 +207,21 @@
     free(p);
 }
 
-void handle_online(void)
+void handle_online(atransport *t)
 {
     D("adb: online\n");
+    t->online = 1;
 }
 
 void handle_offline(atransport *t)
 {
     D("adb: offline\n");
     //Close the associated usb
+    t->online = 0;
     run_transport_disconnects(t);
 }
 
-#if TRACE_PACKETS
+#if DEBUG_PACKETS
 #define DUMPMAX 32
 void print_packet(const char *label, apacket *p)
 {
@@ -230,6 +236,7 @@
     case A_OKAY: tag = "OKAY"; break;
     case A_CLSE: tag = "CLSE"; break;
     case A_WRTE: tag = "WRTE"; break;
+    case A_AUTH: tag = "AUTH"; break;
     default: tag = "????"; break;
     }
 
@@ -251,7 +258,7 @@
         }
         x++;
     }
-    fprintf(stderr, tag);
+    fputs(tag, stderr);
 }
 #endif
 
@@ -315,11 +322,70 @@
     cp->msg.data_length = fill_connect_data((char *)cp->data,
                                             sizeof(cp->data));
     send_packet(cp, t);
-#if ADB_HOST
-        /* XXX why sleep here? */
-    // allow the device some time to respond to the connect message
-    adb_sleep_ms(1000);
-#endif
+}
+
+static void send_auth_request(atransport *t)
+{
+    D("Calling send_auth_request\n");
+    apacket *p;
+    int ret;
+
+    ret = adb_auth_generate_token(t->token, sizeof(t->token));
+    if (ret != sizeof(t->token)) {
+        D("Error generating token ret=%d\n", ret);
+        return;
+    }
+
+    p = get_apacket();
+    memcpy(p->data, t->token, ret);
+    p->msg.command = A_AUTH;
+    p->msg.arg0 = ADB_AUTH_TOKEN;
+    p->msg.data_length = ret;
+    send_packet(p, t);
+}
+
+static void send_auth_response(uint8_t *token, size_t token_size, atransport *t)
+{
+    D("Calling send_auth_response\n");
+    apacket *p = get_apacket();
+    int ret;
+
+    ret = adb_auth_sign(t->key, token, token_size, p->data);
+    if (!ret) {
+        D("Error signing the token\n");
+        put_apacket(p);
+        return;
+    }
+
+    p->msg.command = A_AUTH;
+    p->msg.arg0 = ADB_AUTH_SIGNATURE;
+    p->msg.data_length = ret;
+    send_packet(p, t);
+}
+
+static void send_auth_publickey(atransport *t)
+{
+    D("Calling send_auth_publickey\n");
+    apacket *p = get_apacket();
+    int ret;
+
+    ret = adb_auth_get_userkey(p->data, sizeof(p->data));
+    if (!ret) {
+        D("Failed to get user public key\n");
+        put_apacket(p);
+        return;
+    }
+
+    p->msg.command = A_AUTH;
+    p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
+    p->msg.data_length = ret;
+    send_packet(p, t);
+}
+
+void adb_auth_verified(atransport *t)
+{
+    handle_online(t);
+    send_connect(t);
 }
 
 static char *connection_state_name(atransport *t)
@@ -451,13 +517,42 @@
             t->connection_state = CS_OFFLINE;
             handle_offline(t);
         }
+
         parse_banner((char*) p->data, t);
-        handle_online();
-        if(!HOST) send_connect(t);
+
+        if (HOST || !auth_enabled) {
+            handle_online(t);
+            if(!HOST) send_connect(t);
+        } else {
+            send_auth_request(t);
+        }
+        break;
+
+    case A_AUTH:
+        if (p->msg.arg0 == ADB_AUTH_TOKEN) {
+            t->key = adb_auth_nextkey(t->key);
+            if (t->key) {
+                send_auth_response(p->data, p->msg.data_length, t);
+            } else {
+                /* No more private keys to try, send the public key */
+                send_auth_publickey(t);
+            }
+        } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
+            if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
+                adb_auth_verified(t);
+                t->failed_auth_attempts = 0;
+            } else {
+                if (t->failed_auth_attempts++ > 10)
+                    adb_sleep_ms(1000);
+                send_auth_request(t);
+            }
+        } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
+            adb_auth_confirm_key(p->data, p->msg.data_length, t);
+        }
         break;
 
     case A_OPEN: /* OPEN(local-id, 0, "destination") */
-        if(t->connection_state != CS_OFFLINE) {
+        if (t->online) {
             char *name = (char*) p->data;
             name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
             s = create_local_service_socket(name);
@@ -473,7 +568,7 @@
         break;
 
     case A_OKAY: /* READY(local-id, remote-id, "") */
-        if(t->connection_state != CS_OFFLINE) {
+        if (t->online) {
             if((s = find_local_socket(p->msg.arg1))) {
                 if(s->peer == 0) {
                     s->peer = create_remote_socket(p->msg.arg0, t);
@@ -485,7 +580,7 @@
         break;
 
     case A_CLSE: /* CLOSE(local-id, remote-id, "") */
-        if(t->connection_state != CS_OFFLINE) {
+        if (t->online) {
             if((s = find_local_socket(p->msg.arg1))) {
                 s->close(s);
             }
@@ -493,7 +588,7 @@
         break;
 
     case A_WRTE:
-        if(t->connection_state != CS_OFFLINE) {
+        if (t->online) {
             if((s = find_local_socket(p->msg.arg1))) {
                 unsigned rid = p->msg.arg0;
                 p->len = p->msg.data_length;
@@ -1014,6 +1109,7 @@
     usb_vendors_init();
     usb_init();
     local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+    adb_auth_init();
 
     char local_name[30];
     build_local_name(local_name, sizeof(local_name), server_port);
@@ -1021,16 +1117,10 @@
         exit(1);
     }
 #else
-
-    // Our external storage path may be different than apps, since
-    // we aren't able to bind mount after dropping root.
-    const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
-    if (NULL != adb_external_storage) {
-        setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
-    } else {
-        D("Warning: ADB_EXTERNAL_STORAGE is not set.  Leaving EXTERNAL_STORAGE"
-          " unchanged.\n");
-    }
+    property_get("ro.adb.secure", value, "0");
+    auth_enabled = !strcmp(value, "1");
+    if (auth_enabled)
+        adb_auth_init();
 
     /* don't listen on a port (default 5037) if running in secure mode */
     /* don't run as root if we are running in secure mode */
diff --git a/adb/adb.h b/adb/adb.h
index df88896..5e9a0fb 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -29,13 +29,14 @@
 #define A_OKAY 0x59414b4f
 #define A_CLSE 0x45534c43
 #define A_WRTE 0x45545257
+#define A_AUTH 0x48545541
 
 #define A_VERSION 0x01000000        // ADB protocol version
 
 #define ADB_VERSION_MAJOR 1         // Used for help/version information
 #define ADB_VERSION_MINOR 0         // Used for help/version information
 
-#define ADB_SERVER_VERSION    29    // Increment this when we want to force users to start a new adb server
+#define ADB_SERVER_VERSION    30    // Increment this when we want to force users to start a new adb server
 
 typedef struct amessage amessage;
 typedef struct apacket apacket;
@@ -165,6 +166,8 @@
         kTransportHost,
 } transport_type;
 
+#define TOKEN_SIZE 20
+
 struct atransport
 {
     atransport *next;
@@ -181,6 +184,7 @@
     int ref_count;
     unsigned sync_token;
     int connection_state;
+    int online;
     transport_type type;
 
         /* usb handle or socket fd as needed */
@@ -198,6 +202,11 @@
         /* a list of adisconnect callbacks called when the transport is kicked */
     int          kicked;
     adisconnect  disconnects;
+
+    void *key;
+    unsigned char token[TOKEN_SIZE];
+    fdevent auth_fde;
+    unsigned failed_auth_attempts;
 };
 
 
@@ -349,6 +358,7 @@
     TRACE_SYSDEPS,
     TRACE_JDWP,      /* 0x100 */
     TRACE_SERVICES,
+    TRACE_AUTH,
 } AdbTrace;
 
 #if ADB_TRACE
@@ -408,7 +418,7 @@
 #endif
 
 
-#if !TRACE_PACKETS
+#if !DEBUG_PACKETS
 #define print_packet(tag,p) do {} while (0)
 #endif
 
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
new file mode 100644
index 0000000..1fffa49
--- /dev/null
+++ b/adb/adb_auth.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012 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 __ADB_AUTH_H
+#define __ADB_AUTH_H
+
+void adb_auth_init(void);
+void adb_auth_verified(atransport *t);
+
+/* AUTH packets first argument */
+/* Request */
+#define ADB_AUTH_TOKEN         1
+/* Response */
+#define ADB_AUTH_SIGNATURE     2
+#define ADB_AUTH_RSAPUBLICKEY  3
+
+#if ADB_HOST
+
+int adb_auth_sign(void *key, void *token, size_t token_size, void *sig);
+void *adb_auth_nextkey(void *current);
+int adb_auth_get_userkey(unsigned char *data, size_t len);
+
+static inline int adb_auth_generate_token(void *token, size_t token_size) { return 0; }
+static inline int adb_auth_verify(void *token, void *sig, int siglen) { return 0; }
+static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t) { }
+static inline void adb_auth_reload_keys(void) { }
+
+#else // !ADB_HOST
+
+static inline int adb_auth_sign(void* key, void *token, size_t token_size, void *sig) { return 0; }
+static inline void *adb_auth_nextkey(void *current) { return NULL; }
+static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return 0; }
+
+int adb_auth_generate_token(void *token, size_t token_size);
+int adb_auth_verify(void *token, void *sig, int siglen);
+void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t);
+void adb_auth_reload_keys(void);
+
+#endif // ADB_HOST
+
+#endif // __ADB_AUTH_H
diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.c
new file mode 100644
index 0000000..0b4913e
--- /dev/null
+++ b/adb/adb_auth_client.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2012 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 <stdio.h>
+#include <string.h>
+#include <resolv.h>
+#include <cutils/list.h>
+#include <cutils/sockets.h>
+
+#include "sysdeps.h"
+#include "adb.h"
+#include "adb_auth.h"
+#include "fdevent.h"
+#include "mincrypt/rsa.h"
+
+#define TRACE_TAG TRACE_AUTH
+
+
+struct adb_public_key {
+    struct listnode node;
+    RSAPublicKey key;
+};
+
+static struct listnode key_list;
+
+static char *key_paths[] = {
+    "/adb_keys",
+    "/data/misc/adb/adb_keys",
+    NULL
+};
+
+static fdevent listener_fde;
+static int framework_fd = -1;
+
+
+static void read_keys(const char *file, struct listnode *list)
+{
+    struct adb_public_key *key;
+    FILE *f;
+    char buf[MAX_PAYLOAD];
+    char *sep;
+    int ret;
+
+    f = fopen(file, "r");
+    if (!f) {
+        D("Can't open '%s'\n", file);
+        return;
+    }
+
+    while (fgets(buf, sizeof(buf), f)) {
+        /* Allocate 4 extra bytes to decode the base64 data in-place */
+        key = calloc(1, sizeof(*key) + 4);
+        if (!key) {
+            D("Can't malloc key\n");
+            break;
+        }
+
+        sep = strpbrk(buf, " \t");
+        if (sep)
+            *sep = '\0';
+
+        ret = __b64_pton(buf, (u_char *)&key->key, sizeof(key->key) + 4);
+        if (ret != sizeof(key->key)) {
+            D("%s: Invalid base64 data ret=%d\n", file, ret);
+            free(key);
+            continue;
+        }
+
+        if (key->key.len != RSANUMWORDS) {
+            D("%s: Invalid key len %d\n", file, key->key.len);
+            free(key);
+            continue;
+        }
+
+        list_add_tail(list, &key->node);
+    }
+
+    fclose(f);
+}
+
+static void free_keys(struct listnode *list)
+{
+    struct listnode *item;
+
+    while (!list_empty(list)) {
+        item = list_head(list);
+        list_remove(item);
+        free(node_to_item(item, struct adb_public_key, node));
+    }
+}
+
+void adb_auth_reload_keys(void)
+{
+    char *path;
+    char **paths = key_paths;
+    struct stat buf;
+
+    free_keys(&key_list);
+
+    while ((path = *paths++)) {
+        if (!stat(path, &buf)) {
+            D("Loading keys from '%s'\n", path);
+            read_keys(path, &key_list);
+        }
+    }
+}
+
+int adb_auth_generate_token(void *token, size_t token_size)
+{
+    FILE *f;
+    int ret;
+
+    f = fopen("/dev/urandom", "r");
+    if (!f)
+        return 0;
+
+    ret = fread(token, token_size, 1, f);
+
+    fclose(f);
+    return ret * token_size;
+}
+
+int adb_auth_verify(void *token, void *sig, int siglen)
+{
+    struct listnode *item;
+    struct adb_public_key *key;
+    int ret;
+
+    if (siglen != RSANUMBYTES)
+        return 0;
+
+    list_for_each(item, &key_list) {
+        key = node_to_item(item, struct adb_public_key, node);
+        ret = RSA_verify(&key->key, sig, siglen, token);
+        if (ret)
+            return 1;
+    }
+
+    return 0;
+}
+
+static void adb_auth_event(int fd, unsigned events, void *data)
+{
+    atransport *t = data;
+    char response[2];
+    int ret;
+
+    if (events & FDE_READ) {
+        ret = unix_read(fd, response, sizeof(response));
+        if (ret < 0) {
+            D("Disconnect");
+            fdevent_remove(&t->auth_fde);
+            framework_fd = -1;
+        }
+        else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
+            adb_auth_reload_keys();
+            adb_auth_verified(t);
+        }
+    }
+}
+
+void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t)
+{
+    char msg[MAX_PAYLOAD];
+    int ret;
+
+    if (framework_fd < 0) {
+        D("Client not connected\n");
+        return;
+    }
+
+    if (key[len - 1] != '\0') {
+        D("Key must be a null-terminated string\n");
+        return;
+    }
+
+    ret = snprintf(msg, sizeof(msg), "PK%s", key);
+    if (ret >= (signed)sizeof(msg)) {
+        D("Key too long. ret=%d", ret);
+        return;
+    }
+    D("Sending '%s'\n", msg);
+
+    ret = unix_write(framework_fd, msg, ret);
+    if (ret < 0) {
+        D("Failed to write PK, errno=%d\n", errno);
+        return;
+    }
+
+    fdevent_install(&t->auth_fde, framework_fd, adb_auth_event, t);
+    fdevent_add(&t->auth_fde, FDE_READ);
+}
+
+static void adb_auth_listener(int fd, unsigned events, void *data)
+{
+    struct sockaddr addr;
+    socklen_t alen;
+    int s;
+
+    alen = sizeof(addr);
+
+    s = adb_socket_accept(fd, &addr, &alen);
+    if (s < 0) {
+        D("Failed to accept: errno=%d\n", errno);
+        return;
+    }
+
+    framework_fd = s;
+}
+
+void adb_auth_init(void)
+{
+    int fd, ret;
+
+    list_init(&key_list);
+    adb_auth_reload_keys();
+
+    fd = android_get_control_socket("adbd");
+    if (fd < 0) {
+        D("Failed to get adbd socket\n");
+        return;
+    }
+
+    ret = listen(fd, 4);
+    if (ret < 0) {
+        D("Failed to listen on '%d'\n", fd);
+        return;
+    }
+
+    fdevent_install(&listener_fde, fd, adb_auth_listener, NULL);
+    fdevent_add(&listener_fde, FDE_READ);
+}
diff --git a/adb/adb_auth_host.c b/adb/adb_auth_host.c
new file mode 100644
index 0000000..99dcfcb
--- /dev/null
+++ b/adb/adb_auth_host.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2012 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 <stdio.h>
+
+#ifdef _WIN32
+#  define WIN32_LEAN_AND_MEAN
+#  include "windows.h"
+#  include "shlobj.h"
+#else
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#  include <unistd.h>
+#endif
+#include <string.h>
+
+#include "sysdeps.h"
+#include "adb.h"
+#include "adb_auth.h"
+
+/* HACK: we need the RSAPublicKey struct
+ * but RSA_verify conflits with openssl */
+#define RSA_verify RSA_verify_mincrypt
+#include "mincrypt/rsa.h"
+#undef RSA_verify
+
+#include <cutils/list.h>
+
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+
+#define TRACE_TAG TRACE_AUTH
+
+#define ANDROID_PATH   ".android"
+#define ADB_KEY_FILE   "adb_key"
+
+
+struct adb_private_key {
+    struct listnode node;
+    RSA *rsa;
+};
+
+static struct listnode key_list;
+
+
+/* Convert OpenSSL RSA private key to android pre-computed RSAPublicKey format */
+static int RSA_to_RSAPublicKey(RSA *rsa, RSAPublicKey *pkey)
+{
+    int ret = 1;
+    unsigned int i;
+
+    BN_CTX* ctx = BN_CTX_new();
+    BIGNUM* r32 = BN_new();
+    BIGNUM* rr = BN_new();
+    BIGNUM* r = BN_new();
+    BIGNUM* rem = BN_new();
+    BIGNUM* n = BN_new();
+    BIGNUM* n0inv = BN_new();
+
+    if (RSA_size(rsa) != RSANUMBYTES) {
+        ret = 0;
+        goto out;
+    }
+
+    BN_set_bit(r32, 32);
+    BN_copy(n, rsa->n);
+    BN_set_bit(r, RSANUMWORDS * 32);
+    BN_mod_sqr(rr, r, n, ctx);
+    BN_div(NULL, rem, n, r32, ctx);
+    BN_mod_inverse(n0inv, rem, r32, ctx);
+
+    pkey->len = RSANUMWORDS;
+    pkey->n0inv = 0 - BN_get_word(n0inv);
+    for (i = 0; i < RSANUMWORDS; i++) {
+        BN_div(rr, rem, rr, r32, ctx);
+        pkey->rr[i] = BN_get_word(rem);
+        BN_div(n, rem, n, r32, ctx);
+        pkey->n[i] = BN_get_word(rem);
+    }
+    pkey->exponent = BN_get_word(rsa->e);
+
+out:
+    BN_free(n0inv);
+    BN_free(n);
+    BN_free(rem);
+    BN_free(r);
+    BN_free(rr);
+    BN_free(r32);
+    BN_CTX_free(ctx);
+
+    return ret;
+}
+
+static void get_user_info(char *buf, size_t len)
+{
+    char hostname[1024], username[1024];
+    int ret;
+
+#ifndef _WIN32
+    ret = gethostname(hostname, sizeof(hostname));
+    if (ret < 0)
+#endif
+        strcpy(hostname, "unknown");
+
+#if !defined _WIN32 && !defined ADB_HOST_ON_TARGET
+    ret = getlogin_r(username, sizeof(username));
+    if (ret < 0)
+#endif
+        strcpy(username, "unknown");
+
+    ret = snprintf(buf, len, " %s@%s", username, hostname);
+    if (ret >= (signed)len)
+        buf[len - 1] = '\0';
+}
+
+static int write_public_keyfile(RSA *private_key, const char *private_key_path)
+{
+    RSAPublicKey pkey;
+    BIO *bio, *b64, *bfile;
+    char path[PATH_MAX], info[MAX_PAYLOAD];
+    int ret;
+
+    ret = snprintf(path, sizeof(path), "%s.pub", private_key_path);
+    if (ret >= (signed)sizeof(path))
+        return 0;
+
+    ret = RSA_to_RSAPublicKey(private_key, &pkey);
+    if (!ret) {
+        D("Failed to convert to publickey\n");
+        return 0;
+    }
+
+    bfile = BIO_new_file(path, "w");
+    if (!bfile) {
+        D("Failed to open '%s'\n", path);
+        return 0;
+    }
+
+    D("Writing public key to '%s'\n", path);
+
+    b64 = BIO_new(BIO_f_base64());
+    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+
+    bio = BIO_push(b64, bfile);
+    BIO_write(bio, &pkey, sizeof(pkey));
+    BIO_flush(bio);
+    BIO_pop(b64);
+    BIO_free(b64);
+
+    get_user_info(info, sizeof(info));
+    BIO_write(bfile, info, strlen(info));
+    BIO_flush(bfile);
+    BIO_free_all(bfile);
+
+    return 1;
+}
+
+static int generate_key(const char *file)
+{
+    EVP_PKEY* pkey = EVP_PKEY_new();
+    BIGNUM* exponent = BN_new();
+    RSA* rsa = RSA_new();
+    FILE *f = NULL;
+    int ret = 0;
+
+    D("generate_key '%s'\n", file);
+
+    if (!pkey || !exponent || !rsa) {
+        D("Failed to allocate key\n");
+        goto out;
+    }
+
+    BN_set_word(exponent, RSA_F4);
+    RSA_generate_key_ex(rsa, 2048, exponent, NULL);
+    EVP_PKEY_set1_RSA(pkey, rsa);
+
+    f = fopen(file, "w");
+    if (!f) {
+        D("Failed to open '%s'\n", file);
+        goto out;
+    }
+
+    if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
+        D("Failed to write key\n");
+        goto out;
+    }
+
+    if (!write_public_keyfile(rsa, file)) {
+        D("Failed to write public key\n");
+        goto out;
+    }
+
+    ret = 1;
+
+out:
+    if (f)
+        fclose(f);
+    EVP_PKEY_free(pkey);
+    RSA_free(rsa);
+    BN_free(exponent);
+    return ret;
+}
+
+static int read_key(const char *file, struct listnode *list)
+{
+    struct adb_private_key *key;
+    FILE *f;
+
+    D("read_key '%s'\n", file);
+
+    f = fopen(file, "r");
+    if (!f) {
+        D("Failed to open '%s'\n", file);
+        return 0;
+    }
+
+    key = malloc(sizeof(*key));
+    if (!key) {
+        D("Failed to alloc key\n");
+        fclose(f);
+        return 0;
+    }
+    key->rsa = RSA_new();
+
+    if (!PEM_read_RSAPrivateKey(f, &key->rsa, NULL, NULL)) {
+        D("Failed to read key\n");
+        fclose(f);
+        RSA_free(key->rsa);
+        free(key);
+        return 0;
+    }
+
+    fclose(f);
+    list_add_tail(list, &key->node);
+    return 1;
+}
+
+static int get_user_keyfilepath(char *filename, size_t len)
+{
+    const char *format, *home;
+    char android_dir[PATH_MAX];
+    struct stat buf;
+#ifdef _WIN32
+    char path[PATH_MAX];
+    home = getenv("ANDROID_SDK_HOME");
+    if (!home) {
+        SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, path);
+        home = path;
+    }
+    format = "%s\\%s";
+#else
+    home = getenv("HOME");
+    if (!home)
+        return -1;
+    format = "%s/%s";
+#endif
+
+    D("home '%s'\n", home);
+
+    if (snprintf(android_dir, sizeof(android_dir), format, home,
+                        ANDROID_PATH) >= (int)sizeof(android_dir))
+        return -1;
+
+    if (stat(android_dir, &buf)) {
+        if (adb_mkdir(android_dir, 0750) < 0) {
+            D("Cannot mkdir '%s'", android_dir);
+            return -1;
+        }
+    }
+
+    return snprintf(filename, len, format, android_dir, ADB_KEY_FILE);
+}
+
+static int get_user_key(struct listnode *list)
+{
+    struct stat buf;
+    char path[PATH_MAX];
+    int ret;
+
+    ret = get_user_keyfilepath(path, sizeof(path));
+    if (ret < 0 || ret >= (signed)sizeof(path)) {
+        D("Error getting user key filename");
+        return 0;
+    }
+
+    D("user key '%s'\n", path);
+
+    if (stat(path, &buf) == -1) {
+        if (!generate_key(path)) {
+            D("Failed to generate new key\n");
+            return 0;
+        }
+    }
+
+    return read_key(path, list);
+}
+
+static void get_vendor_keys(struct listnode *list)
+{
+    const char *adb_keys_path;
+    char keys_path[MAX_PAYLOAD];
+    char *path;
+    char *save;
+    struct stat buf;
+
+    adb_keys_path = getenv("ADB_VENDOR_KEYS");
+    if (!adb_keys_path)
+        return;
+    strncpy(keys_path, adb_keys_path, sizeof(keys_path));
+
+    path = adb_strtok_r(keys_path, ENV_PATH_SEPARATOR_STR, &save);
+    while (path) {
+        D("Reading: '%s'\n", path);
+
+        if (stat(path, &buf))
+            D("Can't read '%s'\n", path);
+        else if (!read_key(path, list))
+            D("Failed to read '%s'\n", path);
+
+        path = adb_strtok_r(NULL, ENV_PATH_SEPARATOR_STR, &save);
+    }
+}
+
+int adb_auth_sign(void *node, void *token, size_t token_size, void *sig)
+{
+    unsigned int len;
+    struct adb_private_key *key = node_to_item(node, struct adb_private_key, node);
+
+    if (!RSA_sign(NID_sha1, token, token_size, sig, &len, key->rsa)) {
+        return 0;
+    }
+
+    D("adb_auth_sign len=%d\n", len);
+    return (int)len;
+}
+
+void *adb_auth_nextkey(void *current)
+{
+    struct listnode *item;
+
+    if (list_empty(&key_list))
+        return NULL;
+
+    if (!current)
+        return list_head(&key_list);
+
+    list_for_each(item, &key_list) {
+        if (item == current) {
+            /* current is the last item, we tried all the keys */
+            if (item->next == &key_list)
+                return NULL;
+            return item->next;
+        }
+    }
+
+    return NULL;
+}
+
+int adb_auth_get_userkey(unsigned char *data, size_t len)
+{
+    char path[PATH_MAX];
+    char *file;
+    int ret;
+
+    ret = get_user_keyfilepath(path, sizeof(path) - 4);
+    if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) {
+        D("Error getting user key filename");
+        return 0;
+    }
+    strcat(path, ".pub");
+
+    file = load_file(path, (unsigned*)&ret);
+    if (!file) {
+        D("Can't load '%s'\n", path);
+        return 0;
+    }
+
+    if (len < (size_t)(ret + 1)) {
+        D("%s: Content too large ret=%d\n", path, ret);
+        return 0;
+    }
+
+    memcpy(data, file, ret);
+    data[ret] = '\0';
+
+    return ret + 1;
+}
+
+void adb_auth_init(void)
+{
+    int ret;
+
+    D("adb_auth_init\n");
+
+    list_init(&key_list);
+
+    ret = get_user_key(&key_list);
+    if (!ret) {
+        D("Failed to get user key\n");
+        return;
+    }
+
+    get_vendor_keys(&key_list);
+}
diff --git a/adb/protocol.txt b/adb/protocol.txt
index abd63f9..c9d3c24 100644
--- a/adb/protocol.txt
+++ b/adb/protocol.txt
@@ -75,6 +75,24 @@
 or identifier string.  The banner is used to transmit useful properties.
 
 
+--- AUTH(type, 0, "data") ----------------------------------------------
+
+The AUTH message informs the recipient that authentication is required to
+connect to the sender. If type is TOKEN(1), data is a random token that
+the recipient can sign with a private key. The recipient replies with an
+AUTH packet where type is SIGNATURE(2) and data is the signature. If the
+signature verification succeeds, the sender replies with a CONNECT packet.
+
+If the signature verification fails, the sender replies with a new AUTH
+packet and a new random token, so that the recipient can retry signing
+with a different private key.
+
+Once the recipient has tried all its private keys, it can reply with an
+AUTH packet where type is RSAPUBLICKEY(3) and data is the public key. If
+possible, an on-screen confirmation may be displayed for the user to
+confirm they want to install the public key on the device.
+
+
 --- OPEN(local-id, 0, "destination") -----------------------------------
 
 The OPEN message informs the recipient that the sender has a stream
@@ -166,6 +184,7 @@
 
 #define A_SYNC 0x434e5953
 #define A_CNXN 0x4e584e43
+#define A_AUTH 0x48545541
 #define A_OPEN 0x4e45504f
 #define A_OKAY 0x59414b4f
 #define A_CLSE 0x45534c43
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 605fa17..66b60cc 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -38,6 +38,7 @@
 
 #define OS_PATH_SEPARATOR '\\'
 #define OS_PATH_SEPARATOR_STR "\\"
+#define ENV_PATH_SEPARATOR_STR ";"
 
 typedef CRITICAL_SECTION          adb_mutex_t;
 
@@ -277,6 +278,7 @@
 
 #define OS_PATH_SEPARATOR '/'
 #define OS_PATH_SEPARATOR_STR "/"
+#define ENV_PATH_SEPARATOR_STR ":"
 
 typedef  pthread_mutex_t          adb_mutex_t;
 
diff --git a/include/cutils/mspace.h b/include/cutils/mspace.h
new file mode 100644
index 0000000..93fe48e
--- /dev/null
+++ b/include/cutils/mspace.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+/* A wrapper file for dlmalloc.h that defines prototypes for the
+ * mspace_*() functions, which provide an interface for creating
+ * multiple heaps.
+ */
+
+#ifndef MSPACE_H_
+#define MSPACE_H_
+
+/* It's a pain getting the mallinfo stuff to work
+ * with Linux, OSX, and klibc, so just turn it off
+ * for now.
+ * TODO: make mallinfo work
+ */
+#define NO_MALLINFO 1
+
+/* Allow setting the maximum heap footprint.
+ */
+#define USE_MAX_ALLOWED_FOOTPRINT 1
+
+#define USE_CONTIGUOUS_MSPACES 1
+#if USE_CONTIGUOUS_MSPACES
+#define HAVE_MMAP 0
+#define HAVE_MORECORE 1
+#define MORECORE_CONTIGUOUS 0
+#endif
+
+#define MSPACES 1
+#define ONLY_MSPACES 1
+#include "../../../../bionic/libc/bionic/dlmalloc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+  mspace_usable_size(void* p);
+
+  Returns the number of bytes you can actually use in
+  an allocated chunk, which may be more than you requested (although
+  often not) due to alignment and minimum size constraints.
+  You can use this many bytes without worrying about
+  overwriting other allocated objects. This is not a particularly great
+  programming practice. mspace_usable_size can be more useful in
+  debugging and assertions, for example:
+
+  p = mspace_malloc(msp, n);
+  assert(mspace_usable_size(msp, p) >= 256);
+*/
+size_t mspace_usable_size(mspace, const void*);
+
+#if USE_CONTIGUOUS_MSPACES
+/*
+  Similar to create_mspace(), but the underlying memory is
+  guaranteed to be contiguous.  No more than max_capacity
+  bytes is ever allocated to the mspace.
+ */
+mspace create_contiguous_mspace(size_t starting_capacity, size_t max_capacity,
+    int locked);
+
+/*
+   Identical to create_contiguous_mspace, but labels the mapping 'mspace/name'
+   instead of 'mspace'
+*/
+mspace create_contiguous_mspace_with_name(size_t starting_capacity,
+    size_t max_capacity, int locked, const char *name);
+
+/*
+   Identical to create_contiguous_mspace, but uses previously mapped memory.
+*/
+mspace create_contiguous_mspace_with_base(size_t starting_capacity,
+    size_t max_capacity, int locked, void *base);
+
+size_t destroy_contiguous_mspace(mspace msp);
+
+/*
+   Returns the position of the "break" within the given mspace.
+*/
+void *contiguous_mspace_sbrk0(mspace msp);
+#endif
+
+/*
+  Call the handler for each block in the specified mspace.
+  chunkptr and chunklen refer to the heap-level chunk including
+  the chunk overhead, and userptr and userlen refer to the
+  user-usable part of the chunk.  If the chunk is free, userptr
+  will be NULL and userlen will be 0.  userlen is not guaranteed
+  to be the same value passed into malloc() for a given chunk;
+  it is >= the requested size.
+ */
+void mspace_walk_heap(mspace msp,
+    void(*handler)(const void *chunkptr, size_t chunklen,
+        const void *userptr, size_t userlen, void *arg), void *harg);
+
+/*
+  mspace_walk_free_pages(handler, harg)
+
+  Calls the provided handler on each free region in the specified
+  mspace.  The memory between start and end are guaranteed not to
+  contain any important data, so the handler is free to alter the
+  contents in any way.  This can be used to advise the OS that large
+  free regions may be swapped out.
+
+  The value in harg will be passed to each call of the handler.
+ */
+void mspace_walk_free_pages(mspace msp,
+    void(*handler)(void *start, void *end, void *arg), void *harg);
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+#endif /* MSPACE_H_ */
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index db9efbb..6521cbe 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -229,9 +229,6 @@
     { 00644, AID_ROOT,      AID_ROOT,       0 },
 };
 
-#define EXTERNAL_STORAGE_SYSTEM "/mnt/shell/sdcard0"
-#define EXTERNAL_STORAGE_APP "/storage/sdcard0"
-
 static inline void fs_config(const char *path, int dir,
                              unsigned *uid, unsigned *gid, unsigned *mode)
 {
diff --git a/include/sync/sync.h b/include/sync/sync.h
index f015fa1..918acf6 100644
--- a/include/sync/sync.h
+++ b/include/sync/sync.h
@@ -42,7 +42,7 @@
 };
 
 /* timeout in msecs */
-int sync_wait(int fd, unsigned int timeout);
+int sync_wait(int fd, int timeout);
 int sync_merge(const char *name, int fd1, int fd2);
 struct sync_fence_info_data *sync_fence_info(int fd);
 struct sync_pt_info *sync_pt_info(struct sync_fence_info_data *info,
diff --git a/libcorkscrew/arch-arm/backtrace-arm.c b/libcorkscrew/arch-arm/backtrace-arm.c
index 5b91164..ff6c192 100644
--- a/libcorkscrew/arch-arm/backtrace-arm.c
+++ b/libcorkscrew/arch-arm/backtrace-arm.c
@@ -62,21 +62,19 @@
 #include <sys/exec_elf.h>
 #include <cutils/log.h>
 
+#if !defined(__BIONIC_HAVE_UCONTEXT_T)
+/* Old versions of the Android <signal.h> didn't define ucontext_t. */
+#include <asm/sigcontext.h> /* Ensure 'struct sigcontext' is defined. */
+
 /* Machine context at the time a signal was raised. */
 typedef struct ucontext {
     uint32_t uc_flags;
     struct ucontext* uc_link;
     stack_t uc_stack;
-    struct sigcontext {
-        uint32_t trap_no;
-        uint32_t error_code;
-        uint32_t oldmask;
-        uint32_t gregs[16];
-        uint32_t arm_cpsr;
-        uint32_t fault_address;
-    } uc_mcontext;
+    struct sigcontext uc_mcontext;
     uint32_t uc_sigmask;
 } ucontext_t;
+#endif /* !__BIONIC_HAVE_UCONTEXT_T */
 
 /* Unwind state. */
 typedef struct {
@@ -560,9 +558,23 @@
     const ucontext_t* uc = (const ucontext_t*)sigcontext;
 
     unwind_state_t state;
-    for (int i = 0; i < 16; i++) {
-        state.gregs[i] = uc->uc_mcontext.gregs[i];
-    }
+
+    state.gregs[0] = uc->uc_mcontext.arm_r0;
+    state.gregs[1] = uc->uc_mcontext.arm_r1;
+    state.gregs[2] = uc->uc_mcontext.arm_r2;
+    state.gregs[3] = uc->uc_mcontext.arm_r3;
+    state.gregs[4] = uc->uc_mcontext.arm_r4;
+    state.gregs[5] = uc->uc_mcontext.arm_r5;
+    state.gregs[6] = uc->uc_mcontext.arm_r6;
+    state.gregs[7] = uc->uc_mcontext.arm_r7;
+    state.gregs[8] = uc->uc_mcontext.arm_r8;
+    state.gregs[9] = uc->uc_mcontext.arm_r9;
+    state.gregs[10] = uc->uc_mcontext.arm_r10;
+    state.gregs[11] = uc->uc_mcontext.arm_fp;
+    state.gregs[12] = uc->uc_mcontext.arm_ip;
+    state.gregs[13] = uc->uc_mcontext.arm_sp;
+    state.gregs[14] = uc->uc_mcontext.arm_lr;
+    state.gregs[15] = uc->uc_mcontext.arm_pc;
 
     memory_t memory;
     init_memory(&memory, map_info_list);
diff --git a/libcorkscrew/arch-x86/backtrace-x86.c b/libcorkscrew/arch-x86/backtrace-x86.c
index 6cdb0c8..fb79a0c 100644
--- a/libcorkscrew/arch-x86/backtrace-x86.c
+++ b/libcorkscrew/arch-x86/backtrace-x86.c
@@ -35,18 +35,50 @@
 
 #if defined(__BIONIC__)
 
+#if defined(__BIONIC_HAVE_UCONTEXT_T)
+
 // Bionic offers the Linux kernel headers.
 #include <asm/sigcontext.h>
 #include <asm/ucontext.h>
 typedef struct ucontext ucontext_t;
 
-#else
+#else /* __BIONIC_HAVE_UCONTEXT_T */
+
+/* Old versions of the Android <signal.h> didn't define ucontext_t. */
+
+typedef struct {
+  uint32_t  gregs[32];
+  void*     fpregs;
+  uint32_t  oldmask;
+  uint32_t  cr2;
+} mcontext_t;
+
+enum {
+  REG_GS = 0, REG_FS, REG_ES, REG_DS,
+  REG_EDI, REG_ESI, REG_EBP, REG_ESP,
+  REG_EBX, REG_EDX, REG_ECX, REG_EAX,
+  REG_TRAPNO, REG_ERR, REG_EIP, REG_CS,
+  REG_EFL, REG_UESP, REG_SS
+};
+
+/* Machine context at the time a signal was raised. */
+typedef struct ucontext {
+    uint32_t uc_flags;
+    struct ucontext* uc_link;
+    stack_t uc_stack;
+    mcontext_t uc_mcontext;
+    uint32_t uc_sigmask;
+} ucontext_t;
+
+#endif /* __BIONIC_HAVE_UCONTEXT_T */
+
+#else /* __BIONIC__ */
 
 // glibc has its own renaming of the Linux kernel's structures.
 #define __USE_GNU // For REG_EBP, REG_ESP, and REG_EIP.
 #include <ucontext.h>
 
-#endif
+#endif /* __ BIONIC__ */
 
 /* Unwind state. */
 typedef struct {
@@ -96,15 +128,9 @@
     const ucontext_t* uc = (const ucontext_t*)sigcontext;
 
     unwind_state_t state;
-#if defined(__BIONIC__)
-    state.ebp = uc->uc_mcontext.ebp;
-    state.esp = uc->uc_mcontext.esp;
-    state.eip = uc->uc_mcontext.eip;
-#else
     state.ebp = uc->uc_mcontext.gregs[REG_EBP];
     state.esp = uc->uc_mcontext.gregs[REG_ESP];
     state.eip = uc->uc_mcontext.gregs[REG_EIP];
-#endif
 
     memory_t memory;
     init_memory(&memory, map_info_list);
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 9c48ad2..78bae8a 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -75,6 +75,7 @@
 else
     commonSources += \
         abort_socket.c \
+        mspace.c \
         selector.c \
         tztime.c \
         multiuser.c \
diff --git a/libcutils/dlmalloc_stubs.c b/libcutils/dlmalloc_stubs.c
index c327a55..1ced147 100644
--- a/libcutils/dlmalloc_stubs.c
+++ b/libcutils/dlmalloc_stubs.c
@@ -14,22 +14,16 @@
  * limitations under the License.
  */
 
-#include "../../../bionic/libc/bionic/dlmalloc.h"
-#include "cutils/log.h"
-
-/*
- * Stubs for functions defined in bionic/libc/bionic/dlmalloc.c. These
- * are used in host builds, as the host libc will not contain these
- * functions.
+/* No-op stubs for functions defined in system/bionic/bionic/dlmalloc.c.
  */
-void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),
-                          void* arg)
+void dlmalloc_walk_free_pages()
 {
-  ALOGW("Called host unimplemented stub: dlmalloc_inspect_all");
 }
 
-int dlmalloc_trim(size_t unused)
+void dlmalloc_walk_heap()
 {
-  ALOGW("Called host unimplemented stub: dlmalloc_trim");
-  return 0;
+}
+
+void dlmalloc_trim()
+{
 }
diff --git a/libcutils/mspace.c b/libcutils/mspace.c
new file mode 100644
index 0000000..6d3b35c
--- /dev/null
+++ b/libcutils/mspace.c
@@ -0,0 +1,286 @@
+/* Copyright 2006 The Android Open Source Project */
+
+/* A wrapper file for dlmalloc.c that compiles in the
+ * mspace_*() functions, which provide an interface for
+ * creating multiple heaps.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+
+#include <cutils/ashmem.h>
+
+/* It's a pain getting the mallinfo stuff to work
+ * with Linux, OSX, and klibc, so just turn it off
+ * for now.
+ * TODO: make mallinfo work
+ */
+#define NO_MALLINFO 1
+
+/* Allow setting the maximum heap footprint.
+ */
+#define USE_MAX_ALLOWED_FOOTPRINT 1
+
+/* Don't try to trim memory.
+ * TODO: support this.
+ */
+#define MORECORE_CANNOT_TRIM 1
+
+/* Use mmap()d anonymous memory to guarantee
+ * that an mspace is contiguous.
+ *
+ * create_mspace() won't work right if this is
+ * defined, so hide the definition of it and
+ * break any users at build time.
+ */
+#define USE_CONTIGUOUS_MSPACES 1
+#if USE_CONTIGUOUS_MSPACES
+/* This combination of settings forces sys_alloc()
+ * to always use MORECORE().  It won't expect the
+ * results to be contiguous, but we'll guarantee
+ * that they are.
+ */
+#define HAVE_MMAP 0
+#define HAVE_MORECORE 1
+#define MORECORE_CONTIGUOUS 0
+/* m is always the appropriate local when MORECORE() is called. */
+#define MORECORE(S) contiguous_mspace_morecore(m, S)
+#define create_mspace   HIDDEN_create_mspace_HIDDEN
+#define destroy_mspace   HIDDEN_destroy_mspace_HIDDEN
+typedef struct malloc_state *mstate0;
+static void *contiguous_mspace_morecore(mstate0 m, ssize_t nb);
+#endif
+
+#define MSPACES 1
+#define ONLY_MSPACES 1
+#include "../../../bionic/libc/bionic/dlmalloc.c"
+
+#ifndef PAGESIZE
+#define PAGESIZE  mparams.page_size
+#endif
+
+#define ALIGN_UP(p, alignment) \
+    (((uintptr_t)(p) + (alignment)-1) & ~((alignment)-1))
+
+/* A direct copy of dlmalloc_usable_size(),
+ * which isn't compiled in when ONLY_MSPACES is set.
+ * The mspace parameter isn't actually necessary,
+ * but we include it to be consistent with the
+ * rest of the mspace_*() functions.
+ */
+size_t mspace_usable_size(mspace _unused, const void* mem) {
+  if (mem != 0) {
+    const mchunkptr p = mem2chunk(mem);
+    if (cinuse(p))
+      return chunksize(p) - overhead_for(p);
+  }
+  return 0;
+}
+
+#if USE_CONTIGUOUS_MSPACES
+#include <sys/mman.h>
+#include <limits.h>
+
+#define CONTIG_STATE_MAGIC  0xf00dd00d
+struct mspace_contig_state {
+  unsigned int magic;
+  char *brk;
+  char *top;
+  mspace m;
+};
+
+static void *contiguous_mspace_morecore(mstate m, ssize_t nb) {
+  struct mspace_contig_state *cs;
+  char *oldbrk;
+  const unsigned int pagesize = PAGESIZE;
+
+  cs = (struct mspace_contig_state *)((uintptr_t)m & ~(pagesize-1));
+  assert(cs->magic == CONTIG_STATE_MAGIC);
+  assert(cs->m == m);
+assert(nb >= 0);  //xxx deal with the trim case
+
+  oldbrk = cs->brk;
+  if (nb > 0) {
+    /* Break to the first page boundary that satisfies the request.
+     */
+    char *newbrk = (char *)ALIGN_UP(oldbrk + nb, pagesize);
+    if (newbrk > cs->top)
+      return CMFAIL;
+
+    /* Update the protection on the underlying memory.
+     * Pages we've given to dlmalloc are read/write, and
+     * pages we haven't are not accessable (read or write
+     * will cause a seg fault).
+     */
+    if (mprotect(cs, newbrk - (char *)cs, PROT_READ | PROT_WRITE) < 0)
+      return CMFAIL;
+    if (newbrk != cs->top) {
+      if (mprotect(newbrk, cs->top - newbrk, PROT_NONE) < 0)
+        return CMFAIL;
+    }
+
+    cs->brk = newbrk;
+
+    /* Make sure that dlmalloc will merge this block with the
+     * initial block that was passed to create_mspace_with_base().
+     * We don't care about extern vs. non-extern, so just clear it.
+     */
+    m->seg.sflags &= ~EXTERN_BIT;
+  }
+
+  return oldbrk;
+}
+
+mspace create_contiguous_mspace_with_base(size_t starting_capacity,
+    size_t max_capacity, int locked, void *base) {
+  struct mspace_contig_state *cs;
+  unsigned int pagesize;
+  mstate m;
+
+  init_mparams();
+  pagesize = PAGESIZE;
+  assert(starting_capacity <= max_capacity);
+  assert(((uintptr_t)base & (pagesize-1)) == 0);
+  assert(((uintptr_t)max_capacity & (pagesize-1)) == 0);
+  starting_capacity = (size_t)ALIGN_UP(starting_capacity, pagesize);
+
+  /* Make the first page read/write. dlmalloc needs to use that page.
+   */
+  if (mprotect(base, starting_capacity, PROT_READ | PROT_WRITE) < 0) {
+    goto error;
+  }
+
+  /* Create the mspace, pointing to the memory given.
+   */
+  m = create_mspace_with_base((char *)base + sizeof(*cs), starting_capacity,
+                              locked);
+  if (m == (mspace)0) {
+    goto error;
+  }
+  /* Make sure that m is in the same page as base.
+   */
+  assert(((uintptr_t)m & (uintptr_t)~(pagesize-1)) == (uintptr_t)base);
+  /* Use some space for the information that our MORECORE needs.
+   */
+  cs = (struct mspace_contig_state *)base;
+
+  /* Find out exactly how much of the memory the mspace
+   * is using.
+   */
+  cs->brk = m->seg.base + m->seg.size;
+  cs->top = (char *)base + max_capacity;
+
+  assert((char *)base <= cs->brk);
+  assert(cs->brk <= cs->top);
+  /* Prevent access to the memory we haven't handed out yet.
+   */
+  if (cs->brk != cs->top) {
+    /* mprotect() requires page-aligned arguments, but it's possible
+     * for cs->brk not to be page-aligned at this point.
+     */
+    char *prot_brk = (char *)ALIGN_UP(cs->brk, pagesize);
+    if ((mprotect(base, prot_brk - (char *)base, PROT_READ | PROT_WRITE) < 0) ||
+        (mprotect(prot_brk, cs->top - prot_brk, PROT_NONE) < 0)) {
+      goto error;
+    }
+  }
+
+  cs->m = m;
+  cs->magic = CONTIG_STATE_MAGIC;
+
+  return (mspace)m;
+
+error:
+  return (mspace)0;
+}
+
+
+mspace create_contiguous_mspace_with_name(size_t starting_capacity,
+    size_t max_capacity, int locked, char const *name) {
+  int fd, ret;
+  char buf[ASHMEM_NAME_LEN] = "mspace";
+  void *base;
+  unsigned int pagesize;
+  mstate m;
+
+  if (starting_capacity > max_capacity)
+    return (mspace)0;
+
+  init_mparams();
+  pagesize = PAGESIZE;
+
+  /* Create the anonymous memory that will back the mspace.
+   * This reserves all of the virtual address space we could
+   * ever need.  Physical pages will be mapped as the memory
+   * is touched.
+   *
+   * Align max_capacity to a whole page.
+   */
+  max_capacity = (size_t)ALIGN_UP(max_capacity, pagesize);
+
+  if (name)
+    snprintf(buf, sizeof(buf), "mspace/%s", name);
+  fd = ashmem_create_region(buf, max_capacity);
+  if (fd < 0)
+    return (mspace)0;
+
+  base = mmap(NULL, max_capacity, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+  close(fd);
+  if (base == MAP_FAILED)
+    return (mspace)0;
+
+  /* Make sure that base is at the beginning of a page.
+   */
+  assert(((uintptr_t)base & (pagesize-1)) == 0);
+
+  m = create_contiguous_mspace_with_base(starting_capacity, max_capacity,
+                                         locked, base);
+  if (m == 0) {
+    munmap(base, max_capacity);
+  }
+  return m;
+}
+
+mspace create_contiguous_mspace(size_t starting_capacity,
+    size_t max_capacity, int locked) {
+  return create_contiguous_mspace_with_name(starting_capacity,
+      max_capacity, locked, NULL);
+}
+
+size_t destroy_contiguous_mspace(mspace msp) {
+  mstate ms = (mstate)msp;
+
+  if (ok_magic(ms)) {
+    struct mspace_contig_state *cs;
+    size_t length;
+    const unsigned int pagesize = PAGESIZE;
+
+    cs = (struct mspace_contig_state *)((uintptr_t)ms & ~(pagesize-1));
+    assert(cs->magic == CONTIG_STATE_MAGIC);
+    assert(cs->m == ms);
+
+    length = cs->top - (char *)cs;
+    if (munmap((char *)cs, length) != 0)
+      return length;
+  }
+  else {
+    USAGE_ERROR_ACTION(ms, ms);
+  }
+  return 0;
+}
+
+void *contiguous_mspace_sbrk0(mspace msp) {
+    struct mspace_contig_state *cs;
+    mstate ms;
+    const unsigned int pagesize = PAGESIZE;
+
+    ms = (mstate)msp;
+    cs = (struct mspace_contig_state *)((uintptr_t)ms & ~(pagesize-1));
+    assert(cs->magic == CONTIG_STATE_MAGIC);
+    assert(cs->m == ms);
+    return cs->brk;
+}
+#endif
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
index 60fc771..a713feb 100644
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -23,13 +23,10 @@
 #include <sys/mman.h>
 
 #include <cutils/log.h>
-#include <cutils/ashmem.h>
 #include <cutils/atomic.h>
 
 #include "codeflinger/CodeCache.h"
 
-#define LOG_TAG "CodeCache"
-
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -41,72 +38,12 @@
 
 // ----------------------------------------------------------------------------
 
-// A dlmalloc mspace is used to manage the code cache over a mmaped region.
-#define HAVE_MMAP 0
-#define HAVE_MREMAP 0
-#define HAVE_MORECORE 0
-#define MALLOC_ALIGNMENT 16
-#define MSPACES 1
-#define NO_MALLINFO 1
-#define ONLY_MSPACES 1
-// Custom heap error handling.
-#define PROCEED_ON_ERROR 0
-static void heap_error(const char* msg, const char* function, void* p);
-#define CORRUPTION_ERROR_ACTION(m) \
-    heap_error("HEAP MEMORY CORRUPTION", __FUNCTION__, NULL)
-#define USAGE_ERROR_ACTION(m,p) \
-    heap_error("ARGUMENT IS INVALID HEAP ADDRESS", __FUNCTION__, p)
-
-
-#pragma GCC diagnostic ignored "-Wstrict-aliasing"
-#pragma GCC diagnostic ignored "-Wempty-body"
-#include "../../../../bionic/libc/upstream-dlmalloc/malloc.c"
-#pragma GCC diagnostic warning "-Wstrict-aliasing"
-#pragma GCC diagnostic warning "-Wempty-body"
-
-static void heap_error(const char* msg, const char* function, void* p) {
-    ALOG(LOG_FATAL, LOG_TAG, "@@@ ABORTING: CODE FLINGER: %s IN %s addr=%p",
-         msg, function, p);
-    /* So that we can get a memory dump around p */
-    *((int **) 0xdeadbaad) = (int *) p;
-}
-
-// ----------------------------------------------------------------------------
-
-static void* gExecutableStore = NULL;
-static mspace gMspace = NULL;
-const size_t kMaxCodeCacheCapacity = 1024 * 1024;
-
-static mspace getMspace()
-{
-    if (gExecutableStore == NULL) {
-        int fd = ashmem_create_region("CodeFlinger code cache",
-                                      kMaxCodeCacheCapacity);
-        LOG_ALWAYS_FATAL_IF(fd < 0,
-                            "Creating code cache, ashmem_create_region "
-                            "failed with error '%s'", strerror(errno));
-        gExecutableStore = mmap(NULL, kMaxCodeCacheCapacity,
-                                PROT_READ | PROT_WRITE | PROT_EXEC,
-                                MAP_PRIVATE, fd, 0);
-        LOG_ALWAYS_FATAL_IF(gExecutableStore == NULL,
-                            "Creating code cache, mmap failed with error "
-                            "'%s'", strerror(errno));
-        close(fd);
-        gMspace = create_mspace_with_base(gExecutableStore, kMaxCodeCacheCapacity,
-                                          /*locked=*/ false);
-        mspace_set_footprint_limit(gMspace, kMaxCodeCacheCapacity);
-    }
-    return gMspace;
-}
-
 Assembly::Assembly(size_t size)
     : mCount(1), mSize(0)
 {
     mBase = (uint32_t*)mspace_malloc(getMspace(), size);
-    LOG_ALWAYS_FATAL_IF(mBase == NULL,
-                        "Failed to create Assembly of size %zd in executable "
-                        "store of size %zd", size, kMaxCodeCacheCapacity);
     mSize = size;
+    ensureMbaseExecutable();
 }
 
 Assembly::~Assembly()
@@ -140,13 +77,31 @@
 ssize_t Assembly::resize(size_t newSize)
 {
     mBase = (uint32_t*)mspace_realloc(getMspace(), mBase, newSize);
-    LOG_ALWAYS_FATAL_IF(mBase == NULL,
-                        "Failed to resize Assembly to %zd in code cache "
-                        "of size %zd", newSize, kMaxCodeCacheCapacity);
     mSize = newSize;
+    ensureMbaseExecutable();
     return size();
 }
 
+mspace Assembly::getMspace()
+{
+    static mspace msp = create_contiguous_mspace(2 * 1024, 1024 * 1024, /*locked=*/ false);
+    return msp;
+}
+
+void Assembly::ensureMbaseExecutable()
+{
+    long pagesize = sysconf(_SC_PAGESIZE);
+    long pagemask = ~(pagesize - 1);  // assumes pagesize is a power of 2
+
+    uint32_t* pageStart = (uint32_t*) (((uintptr_t) mBase) & pagemask);
+    size_t adjustedLength = (mBase - pageStart) * sizeof(uint32_t) + mSize;
+
+    if (mBase && mprotect(pageStart, adjustedLength, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
+        mspace_free(getMspace(), mBase);
+        mBase = NULL;
+    }
+}
+
 // ----------------------------------------------------------------------------
 
 CodeCache::CodeCache(size_t size)
diff --git a/libpixelflinger/codeflinger/CodeCache.h b/libpixelflinger/codeflinger/CodeCache.h
index 54fd69b..aaafd26 100644
--- a/libpixelflinger/codeflinger/CodeCache.h
+++ b/libpixelflinger/codeflinger/CodeCache.h
@@ -22,6 +22,7 @@
 #include <stdint.h>
 #include <pthread.h>
 #include <sys/types.h>
+#include <cutils/mspace.h>
 
 #include "tinyutils/KeyedVector.h"
 #include "tinyutils/smartpointer.h"
@@ -67,6 +68,9 @@
     typedef void    weakref_type;
 
 private:
+    static  mspace  getMspace();
+            void    ensureMbaseExecutable();
+
     mutable int32_t     mCount;
             uint32_t*   mBase;
             size_t      mSize;
diff --git a/libsync/sync.c b/libsync/sync.c
index c20f15e..4892866 100644
--- a/libsync/sync.c
+++ b/libsync/sync.c
@@ -27,9 +27,9 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
-int sync_wait(int fd, unsigned int timeout)
+int sync_wait(int fd, int timeout)
 {
-    __u32 to = timeout;
+    __s32 to = timeout;
 
     return ioctl(fd, SYNC_IOC_WAIT, &to);
 }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1ed1323..ac36ff5 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -34,6 +34,7 @@
     export ANDROID_ROOT /system
     export ANDROID_ASSETS /system/app
     export ANDROID_DATA /data
+    export ANDROID_STORAGE /storage
     export ASEC_MOUNTPOINT /mnt/asec
     export LOOP_MOUNTPOINT /mnt/obb
     export BOOTCLASSPATH /system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar
@@ -56,8 +57,9 @@
     mkdir /cache 0770 system cache
     mkdir /config 0500 root root
 
-    # Directory for shell-visible mount points, like external storage
+    # See storage config details at http://source.android.com/tech/storage/
     mkdir /mnt/shell 0700 shell shell
+    mkdir /storage 0050 root sdcard_r
 
     # Directory for putting things only root should see.
     mkdir /mnt/secure 0700 root root
@@ -322,8 +324,12 @@
     setprop net.tcp.buffersize.lte     524288,1048576,2097152,262144,524288,1048576
     setprop net.tcp.buffersize.umts    4094,87380,110208,4096,16384,110208
     setprop net.tcp.buffersize.hspa    4094,87380,262144,4096,16384,262144
+    setprop net.tcp.buffersize.hsupa   4094,87380,262144,4096,16384,262144
+    setprop net.tcp.buffersize.hsdpa   4094,87380,262144,4096,16384,262144
+    setprop net.tcp.buffersize.hspap   4094,87380,1220608,4096,16384,1220608
     setprop net.tcp.buffersize.edge    4093,26280,35040,4096,16384,35040
     setprop net.tcp.buffersize.gprs    4092,8760,11680,4096,8760,11680
+    setprop net.tcp.buffersize.evdo    4094,87380,262144,4096,16384,262144
 
 # Set this property so surfaceflinger is not started by system_init
     setprop system_init.startsurfaceflinger 0
@@ -418,7 +424,7 @@
     socket rild stream 660 root radio
     socket rild-debug stream 660 radio system
     user root
-    group radio cache inet misc audio sdcard_r sdcard_rw log
+    group radio cache inet misc audio log
 
 service surfaceflinger /system/bin/surfaceflinger
     class main
@@ -437,7 +443,7 @@
 service drm /system/bin/drmserver
     class main
     user drm
-    group drm system inet drmrpc sdcard_r
+    group drm system inet drmrpc
 
 service media /system/bin/mediaserver
     class main
diff --git a/toolbox/mount.c b/toolbox/mount.c
index 27cf3c9..b7adce2 100644
--- a/toolbox/mount.c
+++ b/toolbox/mount.c
@@ -49,12 +49,17 @@
 	{ "exec",	MS_NOEXEC,	0,		MS_NOEXEC	},
 	{ "move",	MS_TYPE,	MS_MOVE,	0		},
 	{ "recurse",	MS_REC,		MS_REC,		0		},
+	{ "rec",	MS_REC,		MS_REC,		0		},
 	{ "remount",	MS_TYPE,	MS_REMOUNT,	0		},
 	{ "ro",		MS_RDONLY,	MS_RDONLY,	0		},
 	{ "rw",		MS_RDONLY,	0,		MS_RDONLY	},
 	{ "suid",	MS_NOSUID,	0,		MS_NOSUID	},
 	{ "sync",	MS_SYNCHRONOUS,	MS_SYNCHRONOUS,	0		},
 	{ "verbose",	MS_VERBOSE,	MS_VERBOSE,	0		},
+	{ "unbindable",	MS_UNBINDABLE,	MS_UNBINDABLE,	0		},
+	{ "private",	MS_PRIVATE,	MS_PRIVATE,	0		},
+	{ "slave",	MS_SLAVE,	MS_SLAVE,	0		},
+	{ "shared",	MS_SHARED,	MS_SHARED,	0		},
 };
 
 static void add_extra_option(struct extra_opts *extra, char *s)