Merge change 10445

* changes:
  added SuperH atomic support to libcutils
diff --git a/adb/Android.mk b/adb/Android.mk
index 9725478..f3eaa6e 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -53,7 +53,7 @@
 	$(USB_SRCS) \
 	shlist.c \
 	utils.c \
-	usb_vendors.c \
+	usb_vendors.c
 
 
 ifneq ($(USE_SYSDEPS_WIN32),)
@@ -76,7 +76,9 @@
 $(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
 
 ifeq ($(HOST_OS),windows)
-$(LOCAL_INSTALLED_MODULE): $(HOST_OUT_EXECUTABLES)/AdbWinApi.dll
+$(LOCAL_INSTALLED_MODULE): \
+    $(HOST_OUT_EXECUTABLES)/AdbWinApi.dll \
+    $(HOST_OUT_EXECUTABLES)/AdbWinUsbApi.dll
 endif
 
 
@@ -91,9 +93,9 @@
 
 # build adbd for the Linux simulator build
 # so we can use it to test the adb USB gadget driver on x86
-ifeq ($(HOST_OS),linux)
-    BUILD_ADBD := true
-endif
+#ifeq ($(HOST_OS),linux)
+#    BUILD_ADBD := true
+#endif
 
 
 ifeq ($(BUILD_ADBD),true)
@@ -113,7 +115,7 @@
 	remount_service.c \
 	usb_linux_client.c \
 	log_service.c \
-	utils.c \
+	utils.c
 
 LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
 LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
diff --git a/adb/adb.c b/adb/adb.c
index 956df54..283ebce 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -30,6 +30,8 @@
 
 #if !ADB_HOST
 #include <private/android_filesystem_config.h>
+#include <linux/capability.h>
+#include <linux/prctl.h>
 #else
 #include "usb_vendors.h"
 #endif
@@ -830,6 +832,7 @@
 {
 #if !ADB_HOST
     int secure = 0;
+    int port;
     char value[PROPERTY_VALUE_MAX];
 #endif
 
@@ -848,7 +851,7 @@
     HOST = 1;
     usb_vendors_init();
     usb_init();
-    local_init();
+    local_init(ADB_LOCAL_TRANSPORT_PORT);
 
     if(install_listener("tcp:5037", "*smartsocket*", NULL)) {
         exit(1);
@@ -879,6 +882,11 @@
     /* don't listen on port 5037 if we are running in secure mode */
     /* don't run as root if we are running in secure mode */
     if (secure) {
+        struct __user_cap_header_struct header;
+        struct __user_cap_data_struct cap;
+
+        prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
         /* add extra groups:
         ** AID_ADB to access the USB driver
         ** AID_LOG to read system logs (adb logcat)
@@ -896,6 +904,13 @@
         setgid(AID_SHELL);
         setuid(AID_SHELL);
 
+        /* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */
+        header.version = _LINUX_CAPABILITY_VERSION;
+        header.pid = 0;
+        cap.effective = cap.permitted = (1 << CAP_SYS_BOOT);
+        cap.inheritable = 0;
+        capset(&header, &cap);
+
         D("Local port 5037 disabled\n");
     } else {
         if(install_listener("tcp:5037", "*smartsocket*", NULL)) {
@@ -904,14 +919,19 @@
     }
 
         /* for the device, start the usb transport if the
-        ** android usb device exists, otherwise start the
-        ** network transport.
+        ** android usb device exists and "service.adb.tcp"
+        ** is not set, otherwise start the network transport.
         */
-    if(access("/dev/android_adb", F_OK) == 0 ||
-       access("/dev/android", F_OK) == 0) {
+    property_get("service.adb.tcp.port", value, "0");
+    if (sscanf(value, "%d", &port) == 1 && port > 0) {
+        // listen on TCP port specified by service.adb.tcp.port property
+        local_init(port);
+    } else if (access("/dev/android_adb", F_OK) == 0) {
+        // listen on USB
         usb_init();
     } else {
-        local_init();
+        // listen on default port
+        local_init(ADB_LOCAL_TRANSPORT_PORT);
     }
     init_jdwp();
 #endif
@@ -992,6 +1012,43 @@
         return 0;
     }
 
+    // add a new TCP transport
+    if (!strncmp(service, "connect:", 8)) {
+        char buffer[4096];
+        int port, fd;
+        char* host = service + 8;
+        char* portstr = strchr(host, ':');
+
+        if (!portstr) {
+            snprintf(buffer, sizeof(buffer), "unable to parse %s as <host>:<port>\n", host);
+            goto done;
+        }
+        // zero terminate host by overwriting the ':'
+        *portstr++ = 0;
+        if (sscanf(portstr, "%d", &port) == 0) {
+            snprintf(buffer, sizeof(buffer), "bad port number %s\n", portstr);
+            goto done;
+        }
+
+        fd = socket_network_client(host, port, SOCK_STREAM);
+        if (fd < 0) {
+            snprintf(buffer, sizeof(buffer), "unable to connect to %s:%d\n", host, port);
+            goto done;
+        }
+
+        D("client: connected on remote on fd %d\n", fd);
+        close_on_exec(fd);
+        disable_tcp_nagle(fd);
+        snprintf(buf, sizeof buf, "%s:%d", host, port);
+        register_socket_transport(fd, buf, port, 0);
+        snprintf(buffer, sizeof(buffer), "connected to %s:%d\n", host, port);
+
+done:
+        snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
+        writex(reply_fd, buf, strlen(buf));
+        return 0;
+    }
+
     // returns our value for ADB_SERVER_VERSION
     if (!strcmp(service, "version")) {
         char version[12];
diff --git a/adb/adb.h b/adb/adb.h
index 95610a7..713666f 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -33,7 +33,7 @@
 #define ADB_VERSION_MAJOR 1         // Used for help/version information
 #define ADB_VERSION_MINOR 0         // Used for help/version information
 
-#define ADB_SERVER_VERSION    21    // Increment this when we want to force users to start a new adb server
+#define ADB_SERVER_VERSION    25    // Increment this when we want to force users to start a new adb server
 
 typedef struct amessage amessage;
 typedef struct apacket apacket;
@@ -262,15 +262,18 @@
 void   kick_transport( atransport*  t );
 
 /* initialize a transport object's func pointers and state */
-int  init_socket_transport(atransport *t, int s, int port);
-void init_usb_transport(atransport *t, usb_handle *usb);
+int  init_socket_transport(atransport *t, int s, int port, int local);
+void init_usb_transport(atransport *t, usb_handle *usb, int state);
 
 /* for MacOS X cleanup */
 void close_usb_devices();
 
 /* cause new transports to be init'd and added to the list */
-void register_socket_transport(int s, const char *serial, int  port);
-void register_usb_transport(usb_handle *h, const char *serial);
+void register_socket_transport(int s, const char *serial, int port, int local);
+void register_usb_transport(usb_handle *h, const char *serial, unsigned writeable);
+
+/* this should only be used for transports with connection_state == CS_NOPERM */
+void unregister_usb_transport(usb_handle *usb);
 
 int service_to_fd(const char *name);
 #if ADB_HOST
@@ -357,7 +360,7 @@
 #define ADB_PROTOCOL           0x1
 
 
-void local_init();
+void local_init(int port);
 int  local_connect(int  port);
 
 /* usb host/client interface */
@@ -384,7 +387,7 @@
 #define CS_DEVICE     2
 #define CS_HOST       3
 #define CS_RECOVERY   4
-#define CS_ERROR      5
+#define CS_NOPERM     5 /* Insufficient permissions to communicate with the device */
 
 extern int HOST;
 
diff --git a/adb/commandline.c b/adb/commandline.c
index 548d362..411bb82 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -96,7 +96,8 @@
         " -e                            - directs command to the only running emulator.\n"
         "                                 returns an error if more than one emulator is running.\n"
         " -s <serial number>            - directs command to the USB device or emulator with\n"
-        "                                 the given serial number\n"
+        "                                 the given serial number. Overrides ANDROID_SERIAL\n"
+        "                                 envivornment variable.\n"
         " -p <product name or path>     - simple product name like 'sooner', or\n"
         "                                 a relative/absolute path to a product\n"
         "                                 out directory like 'out/target/product/sooner'.\n"
@@ -104,6 +105,7 @@
         "                                 environment variable is used, which must\n"
         "                                 be an absolute path.\n"
         " devices                       - list all connected devices\n"
+        " connect <host>:<port>         - connect to a device via TCP/IP"
         "\n"
         "device commands:\n"
         "  adb push <local> <remote>    - copy file/dir to device\n"
@@ -147,7 +149,10 @@
         "  adb get-serialno             - prints: <serial-number>\n"
         "  adb status-window            - continuously print device status for a specified device\n"
         "  adb remount                  - remounts the /system partition on the device read-write\n"
-        "  adb root                     - restarts adb with root permissions\n"
+        "  adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
+        "  adb root                     - restarts the adbd daemon with root permissions\n"
+        "  adb usb                      - restarts the adbd daemon listening on USB"
+        "  adb tcpip <port>             - restarts the adbd daemon listening on TCP on the specified port"
         "\n"
         "networking:\n"
         "  adb ppp <tty> [parameters]   - Run PPP over USB.\n"
@@ -766,6 +771,8 @@
     }
     // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
 
+    serial = getenv("ANDROID_SERIAL");
+
         /* modifiers and flags */
     while(argc > 0) {
         if(!strcmp(argv[0],"nodaemon")) {
@@ -846,6 +853,22 @@
         }
     }
 
+    if(!strcmp(argv[0], "connect")) {
+        char *tmp;
+        if (argc != 2) {
+            fprintf(stderr, "Usage: adb connect <host>:<port>\n");
+            return 1;
+        }
+        snprintf(buf, sizeof buf, "host:%s:%s", argv[0], argv[1]);
+        tmp = adb_query(buf);
+        if(tmp) {
+            printf("%s\n", tmp);
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
     if (!strcmp(argv[0], "emu")) {
         return adb_send_emulator_command(argc, argv);
     }
@@ -904,19 +927,15 @@
         return 0;
     }
 
-    if(!strcmp(argv[0], "remount")) {
-        int fd = adb_connect("remount:");
-        if(fd >= 0) {
-            read_and_dump(fd);
-            adb_close(fd);
-            return 0;
-        }
-        fprintf(stderr,"error: %s\n", adb_error());
-        return 1;
-    }
-
-    if(!strcmp(argv[0], "root")) {
-        int fd = adb_connect("root:");
+    if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
+            || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
+            || !strcmp(argv[0], "root")) {
+        char command[100];
+        if (argc > 1)
+            snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
+        else
+            snprintf(command, sizeof(command), "%s:", argv[0]);
+        int fd = adb_connect(command);
         if(fd >= 0) {
             read_and_dump(fd);
             adb_close(fd);
diff --git a/adb/get_my_path_darwin.c b/adb/get_my_path_darwin.c
index 00dfee4..6125cb4 100644
--- a/adb/get_my_path_darwin.c
+++ b/adb/get_my_path_darwin.c
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <utils/executablepath.h>
 #import <Carbon/Carbon.h>
 #include <unistd.h>
 
diff --git a/adb/services.c b/adb/services.c
index 78d092b..2864ac9 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -33,6 +33,7 @@
 #  endif
 #else
 #include <sys/poll.h>
+#include <sys/reboot.h>
 #endif
 
 typedef struct stinfo stinfo;
@@ -119,6 +120,7 @@
         if (strcmp(value, "1") != 0) {
             snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n");
             writex(fd, buf, strlen(buf));
+            adb_close(fd);
             return;
         }
 
@@ -133,6 +135,59 @@
     }
 }
 
+void restart_tcp_service(int fd, void *cookie)
+{
+    char buf[100];
+    char value[PROPERTY_VALUE_MAX];
+    int port = (int)cookie;
+
+    if (port <= 0) {
+        snprintf(buf, sizeof(buf), "invalid port\n");
+        writex(fd, buf, strlen(buf));
+        adb_close(fd);
+        return;
+    }
+
+    snprintf(value, sizeof(value), "%d", port);
+    property_set("service.adb.tcp.port", value);
+    snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
+    writex(fd, buf, strlen(buf));
+    adb_close(fd);
+
+    // quit, and init will restart us in TCP mode
+    sleep(1);
+    exit(1);
+}
+
+void restart_usb_service(int fd, void *cookie)
+{
+    char buf[100];
+
+    property_set("service.adb.tcp.port", "0");
+    snprintf(buf, sizeof(buf), "restarting in USB mode\n");
+    writex(fd, buf, strlen(buf));
+    adb_close(fd);
+
+    // quit, and init will restart us in USB mode
+    sleep(1);
+    exit(1);
+}
+
+void reboot_service(int fd, void *arg)
+{
+    char buf[100];
+    int ret;
+
+    sync();
+    ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+                    LINUX_REBOOT_CMD_RESTART2, (char *)arg);
+    if (ret < 0) {
+        snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
+        writex(fd, buf, strlen(buf));
+    }
+    adb_close(fd);
+}
+
 #endif
 
 #if 0
@@ -399,8 +454,21 @@
         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)) {
+        const char* arg = name + 7;
+        if (*name == 0)
+            arg = NULL;
+        ret = create_service_thread(reboot_service, (void *)arg);
     } else if(!strncmp(name, "root:", 5)) {
         ret = create_service_thread(restart_root_service, NULL);
+    } else if(!strncmp(name, "tcpip:", 6)) {
+        int port;
+        if (sscanf(name + 6, "%d", &port) == 0) {
+            port = 0;
+        }
+        ret = create_service_thread(restart_tcp_service, (void *)port);
+    } else if(!strncmp(name, "usb:", 4)) {
+        ret = create_service_thread(restart_usb_service, NULL);
 #endif
 #if 0
     } else if(!strncmp(name, "echo:", 5)){
diff --git a/adb/transport.c b/adb/transport.c
index c76f1a5..617dabf 100644
--- a/adb/transport.c
+++ b/adb/transport.c
@@ -584,18 +584,37 @@
         return;
     }
 
+    /* don't create transport threads for inaccessible devices */
+    if (t->connection_state != CS_NOPERM) {
         /* initial references are the two threads */
-    t->ref_count = 2;
+        t->ref_count = 2;
 
-    if(adb_socketpair(s)) {
-        fatal_errno("cannot open transport socketpair");
+        if(adb_socketpair(s)) {
+            fatal_errno("cannot open transport socketpair");
+        }
+
+        D("transport: %p (%d,%d) starting\n", t, s[0], s[1]);
+
+        t->transport_socket = s[0];
+        t->fd = s[1];
+
+        D("transport: %p install %d\n", t, t->transport_socket );
+        fdevent_install(&(t->transport_fde),
+                        t->transport_socket,
+                        transport_socket_events,
+                        t);
+
+        fdevent_set(&(t->transport_fde), FDE_READ);
+
+        if(adb_thread_create(&input_thread_ptr, input_thread, t)){
+            fatal_errno("cannot create input thread");
+        }
+
+        if(adb_thread_create(&output_thread_ptr, output_thread, t)){
+            fatal_errno("cannot create output thread");
+        }
     }
 
-    D("transport: %p (%d,%d) starting\n", t, s[0], s[1]);
-
-    t->transport_socket = s[0];
-    t->fd = s[1];
-
         /* put us on the master device list */
     adb_mutex_lock(&transport_lock);
     t->next = &transport_list;
@@ -604,22 +623,6 @@
     t->prev->next = t;
     adb_mutex_unlock(&transport_lock);
 
-    D("transport: %p install %d\n", t, t->transport_socket );
-    fdevent_install(&(t->transport_fde),
-                    t->transport_socket,
-                    transport_socket_events,
-                    t);
-
-    fdevent_set(&(t->transport_fde), FDE_READ);
-
-    if(adb_thread_create(&input_thread_ptr, input_thread, t)){
-        fatal_errno("cannot create input thread");
-    }
-
-    if(adb_thread_create(&output_thread_ptr, output_thread, t)){
-        fatal_errno("cannot create output thread");
-    }
-
     t->disconnects.next = t->disconnects.prev = &t->disconnects;
 
     update_transports();
@@ -717,6 +720,12 @@
 
     adb_mutex_lock(&transport_lock);
     for (t = transport_list.next; t != &transport_list; t = t->next) {
+        if (t->connection_state == CS_NOPERM) {
+        if (error_out)
+            *error_out = "insufficient permissions for device";
+            continue;
+        }
+
         /* check for matching serial number */
         if (serial) {
             if (t->serial && !strcmp(serial, t->serial)) {
@@ -763,7 +772,6 @@
                 *error_out = "device offline";
             result = NULL;
         }
-
          /* check for required connection state */
         if (result && state != CS_ANY && result->connection_state != state) {
             if (error_out)
@@ -793,6 +801,7 @@
     case CS_DEVICE: return "device";
     case CS_HOST: return "host";
     case CS_RECOVERY: return "recovery";
+    case CS_NOPERM: return "no permissions";
     default: return "unknown";
     }
 }
@@ -807,9 +816,10 @@
         /* XXX OVERRUN PROBLEMS XXX */
     adb_mutex_lock(&transport_lock);
     for(t = transport_list.next; t != &transport_list; t = t->next) {
-        len = snprintf(p, end - p, "%s\t%s\n",
-                t->serial ? t->serial : "",
-                statename(t));
+        const char* serial = t->serial;
+        if (!serial || !serial[0])
+            serial = "????????????";
+        len = snprintf(p, end - p, "%s\t%s\n", serial, statename(t));
 
         if (p + len >= end) {
             /* discard last line if buffer is too short */
@@ -839,11 +849,11 @@
 }
 #endif // ADB_HOST
 
-void register_socket_transport(int s, const char *serial, int  port)
+void register_socket_transport(int s, const char *serial, int port, int local)
 {
     atransport *t = calloc(1, sizeof(atransport));
     D("transport: %p init'ing for socket %d, on port %d\n", t, s, port);
-    if ( init_socket_transport(t, s, port) < 0 ) {
+    if ( init_socket_transport(t, s, port, local) < 0 ) {
         adb_close(s);
         free(t);
         return;
@@ -854,18 +864,32 @@
     register_transport(t);
 }
 
-void register_usb_transport(usb_handle *usb, const char *serial)
+void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable)
 {
     atransport *t = calloc(1, sizeof(atransport));
     D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
       serial ? serial : "");
-    init_usb_transport(t, usb);
+    init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
     if(serial) {
         t->serial = strdup(serial);
     }
     register_transport(t);
 }
 
+/* this should only be used for transports with connection_state == CS_NOPERM */
+void unregister_usb_transport(usb_handle *usb)
+{
+    atransport *t;
+    adb_mutex_lock(&transport_lock);
+    for(t = transport_list.next; t != &transport_list; t = t->next) {
+        if (t->usb == usb && t->connection_state == CS_NOPERM) {
+            t->next->prev = t->prev;
+            t->prev->next = t->next;
+            break;
+        }
+     }
+    adb_mutex_unlock(&transport_lock);
+}
 
 #undef TRACE_TAG
 #define TRACE_TAG  TRACE_RWX
diff --git a/adb/transport_local.c b/adb/transport_local.c
index be01f29..c528d1f 100644
--- a/adb/transport_local.c
+++ b/adb/transport_local.c
@@ -122,7 +122,7 @@
         close_on_exec(fd);
         disable_tcp_nagle(fd);
         snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, port - 1);
-        register_socket_transport(fd, buf, port);
+        register_socket_transport(fd, buf, port, 1);
         return 0;
     }
     return -1;
@@ -147,17 +147,18 @@
     return 0;
 }
 
-static void *server_socket_thread(void *x)
+static void *server_socket_thread(void * arg)
 {
     int serverfd, fd;
     struct sockaddr addr;
     socklen_t alen;
+    int port = (int)arg;
 
     D("transport: server_socket_thread() starting\n");
     serverfd = -1;
     for(;;) {
         if(serverfd == -1) {
-            serverfd = socket_inaddr_any_server(ADB_LOCAL_TRANSPORT_PORT, SOCK_STREAM);
+            serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
             if(serverfd < 0) {
                 D("server: cannot bind socket yet\n");
                 adb_sleep_ms(1000);
@@ -167,20 +168,20 @@
         }
 
         alen = sizeof(addr);
-        D("server: trying to get new connection from %d\n", ADB_LOCAL_TRANSPORT_PORT);
+        D("server: trying to get new connection from %d\n", port);
         fd = adb_socket_accept(serverfd, &addr, &alen);
         if(fd >= 0) {
             D("server: new connection on fd %d\n", fd);
             close_on_exec(fd);
             disable_tcp_nagle(fd);
-            register_socket_transport(fd,"host",ADB_LOCAL_TRANSPORT_PORT);
+            register_socket_transport(fd, "host", port, 1);
         }
     }
     D("transport: server_socket_thread() exiting\n");
     return 0;
 }
 
-void local_init(void)
+void local_init(int port)
 {
     adb_thread_t thr;
     void* (*func)(void *);
@@ -193,7 +194,7 @@
 
     D("transport: local %s init\n", HOST ? "client" : "server");
 
-    if(adb_thread_create(&thr, func, 0)) {
+    if(adb_thread_create(&thr, func, (void *)port)) {
         fatal_errno("cannot create local socket %s thread",
                     HOST ? "client" : "server");
     }
@@ -225,7 +226,7 @@
     adb_close(t->fd);
 }
 
-int init_socket_transport(atransport *t, int s, int  port)
+int init_socket_transport(atransport *t, int s, int port, int local)
 {
     int  fail = 0;
 
@@ -239,7 +240,7 @@
     t->type = kTransportLocal;
 
 #if ADB_HOST
-    if (HOST) {
+    if (HOST && local) {
         adb_mutex_lock( &local_transports_lock );
         {
             int  index = (port - ADB_LOCAL_TRANSPORT_PORT)/2;
diff --git a/adb/transport_usb.c b/adb/transport_usb.c
index 3737c5c..2584163 100644
--- a/adb/transport_usb.c
+++ b/adb/transport_usb.c
@@ -110,7 +110,7 @@
     usb_kick(t->usb);
 }
 
-void init_usb_transport(atransport *t, usb_handle *h)
+void init_usb_transport(atransport *t, usb_handle *h, int state)
 {
     D("transport: usb\n");
     t->close = remote_close;
@@ -118,7 +118,7 @@
     t->read_from_remote = remote_read;
     t->write_to_remote = remote_write;
     t->sync_token = 1;
-    t->connection_state = CS_OFFLINE;
+    t->connection_state = state;
     t->type = kTransportUsb;
     t->usb = h;
 
diff --git a/adb/usb_linux.c b/adb/usb_linux.c
index 537122d..863af1d 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.c
@@ -57,6 +57,7 @@
     unsigned char ep_out;
 
     unsigned zero_mask;
+    unsigned writeable;
 
     struct usbdevfs_urb urb_in;
     struct usbdevfs_urb urb_out;
@@ -115,7 +116,7 @@
 }
 
 static void register_device(const char *dev_name, unsigned char ep_in, unsigned char ep_out,
-                            int ifc, const char *serial, unsigned zero_mask);
+                            int ifc, int serial_index, unsigned zero_mask);
 
 static inline int badname(const char *name)
 {
@@ -125,19 +126,18 @@
     return 0;
 }
 
-static int find_usb_device(const char *base,
-                           void (*register_device_callback) (const char *, unsigned char, unsigned char, int, const char *, unsigned))
+static void find_usb_device(const char *base,
+        void (*register_device_callback)
+                (const char *, unsigned char, unsigned char, int, int, unsigned))
 {
     char busname[32], devname[32];
     unsigned char local_ep_in, local_ep_out;
     DIR *busdir , *devdir ;
     struct dirent *de;
     int fd ;
-    int found_device = 0;
-    char serial[256];
 
     busdir = opendir(base);
-    if(busdir == 0) return 0;
+    if(busdir == 0) return;
 
     while((de = readdir(busdir)) != 0) {
         if(badname(de->d_name)) continue;
@@ -168,7 +168,7 @@
             }
 
 //            DBGX("[ scanning %s ]\n", devname);
-            if((fd = unix_open(devname, O_RDWR)) < 0) {
+            if((fd = unix_open(devname, O_RDONLY)) < 0) {
                 continue;
             }
 
@@ -263,67 +263,13 @@
                         local_ep_out = ep1->bEndpointAddress;
                     }
 
-                        // read the device's serial number
-                    serial[0] = 0;
-                    memset(serial, 0, sizeof(serial));
-                    if (device->iSerialNumber) {
-                        struct usbdevfs_ctrltransfer  ctrl;
-                        __u16 buffer[128];
-                        __u16 languages[128];
-                        int i, result;
-                        int languageCount = 0;
-
-                        memset(languages, 0, sizeof(languages));
-                        memset(&ctrl, 0, sizeof(ctrl));
-
-                            // read list of supported languages
-                        ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
-                        ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
-                        ctrl.wValue = (USB_DT_STRING << 8) | 0;
-                        ctrl.wIndex = 0;
-                        ctrl.wLength = sizeof(languages);
-                        ctrl.data = languages;
-
-                        result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
-                        if (result > 0)
-                            languageCount = (result - 2) / 2;
-
-                        for (i = 1; i <= languageCount; i++) {
-                            memset(buffer, 0, sizeof(buffer));
-                            memset(&ctrl, 0, sizeof(ctrl));
-
-                            ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
-                            ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
-                            ctrl.wValue = (USB_DT_STRING << 8) | device->iSerialNumber;
-                            ctrl.wIndex = languages[i];
-                            ctrl.wLength = sizeof(buffer);
-                            ctrl.data = buffer;
-
-                            result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
-                            if (result > 0) {
-                                int i;
-                                    // skip first word, and copy the rest to the serial string, changing shorts to bytes.
-                                result /= 2;
-                                for (i = 1; i < result; i++)
-                                    serial[i - 1] = buffer[i];
-                                serial[i - 1] = 0;
-                                break;
-                            }
-                        }
-                    }
-
                     register_device_callback(devname, local_ep_in, local_ep_out,
-                            interface->bInterfaceNumber, serial, zero_mask);
+                            interface->bInterfaceNumber, device->iSerialNumber, zero_mask);
 
-                    found_device = 1;
                     break;
                 } else {
                     // seek next interface descriptor
-                    if (i < interfaces - 1) {
-                        while (bufptr[1] != USB_DT_INTERFACE) {
-                            bufptr += bufptr[0];
-                        }
-                    }
+                    bufptr += (USB_DT_ENDPOINT_SIZE * interface->bNumEndpoints);
                  }
             } // end of for
 
@@ -332,8 +278,6 @@
         closedir(devdir);
     } //end of busdir while
     closedir(busdir);
-
-    return found_device;
 }
 
 void usb_cleanup()
@@ -537,26 +481,30 @@
     if(h->dead == 0) {
         h->dead = 1;
 
-        /* HACK ALERT!
-        ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB).
-        ** This is a workaround for that problem.
-        */
-        if (h->reaper_thread) {
-            pthread_kill(h->reaper_thread, SIGALRM);
-        }
+        if (h->writeable) {
+            /* HACK ALERT!
+            ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB).
+            ** This is a workaround for that problem.
+            */
+            if (h->reaper_thread) {
+                pthread_kill(h->reaper_thread, SIGALRM);
+            }
 
-        /* cancel any pending transactions
-        ** these will quietly fail if the txns are not active,
-        ** but this ensures that a reader blocked on REAPURB
-        ** will get unblocked
-        */
-        ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in);
-        ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out);
-        h->urb_in.status = -ENODEV;
-        h->urb_out.status = -ENODEV;
-        h->urb_in_busy = 0;
-        h->urb_out_busy = 0;
-        adb_cond_broadcast(&h->notify);
+            /* cancel any pending transactions
+            ** these will quietly fail if the txns are not active,
+            ** but this ensures that a reader blocked on REAPURB
+            ** will get unblocked
+            */
+            ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in);
+            ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out);
+            h->urb_in.status = -ENODEV;
+            h->urb_out.status = -ENODEV;
+            h->urb_in_busy = 0;
+            h->urb_out_busy = 0;
+            adb_cond_broadcast(&h->notify);
+        } else {
+            unregister_usb_transport(h);
+        }
     }
     adb_mutex_unlock(&h->lock);
 }
@@ -580,11 +528,11 @@
 
 static void register_device(const char *dev_name,
                             unsigned char ep_in, unsigned char ep_out,
-                            int interface,
-                            const char *serial, unsigned zero_mask)
+                            int interface, int serial_index, unsigned zero_mask)
 {
     usb_handle* usb = 0;
     int n = 0;
+    char serial[256];
 
         /* Since Linux will not reassign the device ID (and dev_name)
         ** as long as the device is open, we can add to the list here
@@ -610,6 +558,7 @@
     usb->ep_in = ep_in;
     usb->ep_out = ep_out;
     usb->zero_mask = zero_mask;
+    usb->writeable = 1;
 
     adb_cond_init(&usb->notify, 0);
     adb_mutex_init(&usb->lock, 0);
@@ -618,10 +567,66 @@
     usb->reaper_thread = 0;
 
     usb->desc = unix_open(usb->fname, O_RDWR);
-    if(usb->desc < 0) goto fail;
-    D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
-    n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
-    if(n != 0) goto fail;
+    if(usb->desc < 0) {
+        /* if we fail, see if have read-only access */
+        usb->desc = unix_open(usb->fname, O_RDONLY);
+        if(usb->desc < 0) goto fail;
+        usb->writeable = 0;
+        D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc);
+    } else {
+        D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
+        n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
+        if(n != 0) goto fail;
+    }
+
+        /* read the device's serial number */
+    serial[0] = 0;
+    memset(serial, 0, sizeof(serial));
+    if (serial_index) {
+        struct usbdevfs_ctrltransfer  ctrl;
+        __u16 buffer[128];
+        __u16 languages[128];
+        int i, result;
+        int languageCount = 0;
+
+        memset(languages, 0, sizeof(languages));
+        memset(&ctrl, 0, sizeof(ctrl));
+
+            // read list of supported languages
+        ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
+        ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
+        ctrl.wValue = (USB_DT_STRING << 8) | 0;
+        ctrl.wIndex = 0;
+        ctrl.wLength = sizeof(languages);
+        ctrl.data = languages;
+
+        result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
+        if (result > 0)
+            languageCount = (result - 2) / 2;
+
+        for (i = 1; i <= languageCount; i++) {
+            memset(buffer, 0, sizeof(buffer));
+            memset(&ctrl, 0, sizeof(ctrl));
+
+            ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
+            ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
+            ctrl.wValue = (USB_DT_STRING << 8) | serial_index;
+            ctrl.wIndex = languages[i];
+            ctrl.wLength = sizeof(buffer);
+            ctrl.data = buffer;
+
+            result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
+            if (result > 0) {
+                int i;
+                // skip first word, and copy the rest to the serial string, changing shorts to bytes.
+                result /= 2;
+                for (i = 1; i < result; i++)
+                    serial[i - 1] = buffer[i];
+                serial[i - 1] = 0;
+                break;
+            }
+        }
+    }
 
         /* add to the end of the active handles */
     adb_mutex_lock(&usb_lock);
@@ -631,7 +636,7 @@
     usb->next->prev = usb;
     adb_mutex_unlock(&usb_lock);
 
-    register_usb_transport(usb, serial);
+    register_usb_transport(usb, serial, usb->writeable);
     return;
 
 fail:
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c
index 530bd04..0a21c6f 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.c
@@ -72,7 +72,7 @@
         usb->fd = fd;
 
         D("[ usb_thread - registering device ]\n");
-        register_usb_transport(usb, 0);
+        register_usb_transport(usb, 0, 1);
     }
 
     // never gets here
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index 4892c38..00d02da 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -194,30 +194,54 @@
         kr = (*dev)->GetDeviceProduct(dev, &product);
         kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
 
-        if (serialIndex > 0) {
-            IOUSBDevRequest req;
-            UInt16          buffer[256];
+	if (serialIndex > 0) {
+		IOUSBDevRequest req;
+		UInt16          buffer[256];
+		UInt16          languages[128];
 
-            req.bmRequestType =
-                USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
-            req.bRequest = kUSBRqGetDescriptor;
-            req.wValue = (kUSBStringDesc << 8) | serialIndex;
-            req.wIndex = 0;
-            req.pData = buffer;
-            req.wLength = sizeof(buffer);
-            kr = (*dev)->DeviceRequest(dev, &req);
+		memset(languages, 0, sizeof(languages));
 
-            if (kr == kIOReturnSuccess && req.wLenDone > 0) {
-                int i, count;
+		req.bmRequestType =
+			USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+		req.bRequest = kUSBRqGetDescriptor;
+		req.wValue = (kUSBStringDesc << 8) | 0;
+		req.wIndex = 0;
+		req.pData = languages;
+		req.wLength = sizeof(languages);
+		kr = (*dev)->DeviceRequest(dev, &req);
 
-                // skip first word, and copy the rest to the serial string,
-                // changing shorts to bytes.
-                count = (req.wLenDone - 1) / 2;
-                for (i = 0; i < count; i++)
-                  serial[i] = buffer[i + 1];
-                serial[i] = 0;
-            }
-        }
+		if (kr == kIOReturnSuccess && req.wLenDone > 0) {
+
+			int langCount = (req.wLenDone - 2) / 2, lang;
+
+			for (lang = 1; lang <= langCount; lang++) {
+
+                                memset(buffer, 0, sizeof(buffer));
+                                memset(&req, 0, sizeof(req));
+
+				req.bmRequestType =
+					USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+				req.bRequest = kUSBRqGetDescriptor;
+				req.wValue = (kUSBStringDesc << 8) | serialIndex;
+				req.wIndex = languages[lang];
+				req.pData = buffer;
+				req.wLength = sizeof(buffer);
+				kr = (*dev)->DeviceRequest(dev, &req);
+
+				if (kr == kIOReturnSuccess && req.wLenDone > 0) {
+					int i, count;
+
+					// skip first word, and copy the rest to the serial string,
+					// changing shorts to bytes.
+					count = (req.wLenDone - 1) / 2;
+					for (i = 0; i < count; i++)
+						serial[i] = buffer[i + 1];
+					serial[i] = 0;
+                                        break;
+				}
+			}
+		}
+	}
         (*dev)->Release(dev);
 
         DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product,
@@ -232,7 +256,7 @@
         }
 
         DBG("AndroidDeviceAdded calling register_usb_transport\n");
-        register_usb_transport(handle, (serial[0] ? serial : NULL));
+        register_usb_transport(handle, (serial[0] ? serial : NULL), 1);
 
         // Register for an interest notification of this device being removed.
         // Pass the reference to our private data as the refCon for the
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index 0951f67..38c4cf4 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -488,7 +488,7 @@
                                 true)) {
             // Lets make sure that we don't duplicate this device
             if (register_new_device(handle)) {
-              register_usb_transport(handle, serial_number);
+              register_usb_transport(handle, serial_number, 1);
             } else {
               D("register_new_device failed for %s\n", interf_name);
               usb_cleanup_handle(handle);
diff --git a/fastboot/util_osx.c b/fastboot/util_osx.c
index 068241c..b43e316 100644
--- a/fastboot/util_osx.c
+++ b/fastboot/util_osx.c
@@ -26,7 +26,6 @@
  * SUCH DAMAGE.
  */
 
-#include <utils/executablepath.h>
 #import <Carbon/Carbon.h>
 #include <unistd.h>
 
diff --git a/init/builtins.c b/init/builtins.c
index 93ce6e8..43508ef 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -131,6 +131,18 @@
     }
 }
 
+int do_chdir(int nargs, char **args)
+{
+    chdir(args[1]);
+    return 0;
+}
+
+int do_chroot(int nargs, char **args)
+{
+    chroot(args[1]);
+    return 0;
+}
+
 int do_class_start(int nargs, char **args)
 {
         /* Starting a class does not start services
@@ -206,7 +218,7 @@
 
 int do_import(int nargs, char **args)
 {
-    return -1;
+    return parse_config_file(args[1]);
 }
 
 int do_mkdir(int nargs, char **args)
@@ -400,6 +412,8 @@
 
 int do_trigger(int nargs, char **args)
 {
+    action_for_each_trigger(args[1], action_add_queue_tail);
+    drain_action_queue();
     return 0;
 }
 
diff --git a/init/devices.c b/init/devices.c
index 60f9b9c..c5f681f 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -114,6 +114,7 @@
     { "/dev/pmem_camera",   0660,   AID_SYSTEM,     AID_CAMERA,     1 },
     { "/dev/oncrpc/",       0660,   AID_ROOT,       AID_SYSTEM,     1 },
     { "/dev/adsp/",         0660,   AID_SYSTEM,     AID_AUDIO,      1 },
+    { "/dev/snd/",          0660,   AID_SYSTEM,     AID_AUDIO,      1 },
     { "/dev/mt9t013",       0660,   AID_SYSTEM,     AID_SYSTEM,     0 },
     { "/dev/msm_camera/",   0660,   AID_SYSTEM,     AID_SYSTEM,     1 },
     { "/dev/akm8976_daemon",0640,   AID_COMPASS,    AID_SYSTEM,     0 },
@@ -288,7 +289,7 @@
     chown(path, uid, gid);
 }
 
-#ifdef LOG_UEVENTS
+#if LOG_UEVENTS
 
 static inline suseconds_t get_usecs(void)
 {
diff --git a/init/init.c b/init/init.c
old mode 100644
new mode 100755
index dfc858a..adc4c9f
--- a/init/init.c
+++ b/init/init.c
@@ -65,8 +65,6 @@
 static int keychords_count = 0;
 static int keychords_length = 0;
 
-static void drain_action_queue(void);
-
 static void notify_service_state(const char *name, const char *state)
 {
     char pname[PROP_NAME_MAX];
@@ -391,12 +389,13 @@
         }
     }
 
+    svc->flags |= SVC_RESTARTING;
+
     /* Execute all onrestart commands for this service. */
     list_for_each(node, &svc->onrestart.commands) {
         cmd = node_to_item(node, struct command, clist);
         cmd->func(cmd->nargs, cmd->args);
     }
-    svc->flags |= SVC_RESTARTING;
     notify_service_state(svc->name, "restarting");
     return 0;
 }
@@ -667,7 +666,7 @@
     }
 }
 
-static void drain_action_queue(void)
+void drain_action_queue(void)
 {
     struct listnode *node;
     struct command *cmd;
diff --git a/init/init.h b/init/init.h
index f306b7b..60c3055 100644
--- a/init/init.h
+++ b/init/init.h
@@ -165,6 +165,7 @@
 void service_start(struct service *svc, const char *dynamic_args);
 void property_changed(const char *name, const char *value);
 
+void drain_action_queue(void);
 struct action *action_remove_queue_head(void);
 void action_add_queue_tail(struct action *act);
 void action_for_each_trigger(const char *trigger,
diff --git a/init/keywords.h b/init/keywords.h
index 6f47379..1e2b9c8 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -1,5 +1,7 @@
 
 #ifndef KEYWORD
+int do_chroot(int nargs, char **args);
+int do_chdir(int nargs, char **args);
 int do_class_start(int nargs, char **args);
 int do_class_stop(int nargs, char **args);
 int do_domainname(int nargs, char **args);
@@ -31,6 +33,8 @@
     K_UNKNOWN,
 #endif
     KEYWORD(capability,  OPTION,  0, 0)
+    KEYWORD(chdir,       COMMAND, 1, do_chdir)
+    KEYWORD(chroot,      COMMAND, 1, do_chroot)
     KEYWORD(class,       OPTION,  0, 0)
     KEYWORD(class_start, COMMAND, 1, do_class_start)
     KEYWORD(class_stop,  COMMAND, 1, do_class_stop)
diff --git a/init/parser.c b/init/parser.c
index 33c1a68..0eb078d 100644
--- a/init/parser.c
+++ b/init/parser.c
@@ -128,6 +128,8 @@
     switch (*s++) {
     case 'c':
         if (!strcmp(s, "apability")) return K_capability;
+        if (!strcmp(s, "hdir")) return K_chdir;
+        if (!strcmp(s, "hroot")) return K_chroot;
         if (!strcmp(s, "lass")) return K_class;
         if (!strcmp(s, "lass_start")) return K_class_start;
         if (!strcmp(s, "lass_stop")) return K_class_stop;
diff --git a/init/readme.txt b/init/readme.txt
index 665090b..a185790 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -145,12 +145,18 @@
 hostname <name>
    Set the host name.
 
+chdir <directory>
+   Change working directory.
+
 chmod <octal-mode> <path>
    Change file access permissions.
 
 chown <owner> <group> <path>
    Change file owner and group.
 
+chroot <directory>
+  Change process root directory.
+
 class_start <serviceclass>
    Start all services of the specified class if they are
    not already running.
diff --git a/libcutils/atomic-android-arm.S b/libcutils/atomic-android-arm.S
index c56ec5d..9a24976 100644
--- a/libcutils/atomic-android-arm.S
+++ b/libcutils/atomic-android-arm.S
@@ -17,8 +17,7 @@
 #include <machine/cpu-features.h>
 
 /*
- * NOTE: these atomic operations are SMP safe on all architectures, 
- * except swap(), see below.
+ * NOTE: these atomic operations are SMP safe on all architectures. 
  */
 
 	.text
@@ -228,11 +227,18 @@
  * output: r0 = old value
  */
 
-/* FIXME: this is not safe on SMP systems 
- * a general way to do it is to use kernel_cmpxchg */
-
+/* replaced swp instruction with ldrex/strex for ARMv6 & ARMv7 */
 android_atomic_swap:
+#if defined (_ARM_HAVE_LDREX_STREX)
+1:  ldrex   r2, [r1]
+    strex   r3, r0, [r1]
+    teq     r3, #0
+    bne     1b
+    mov     r0, r2
+    mcr     p15, 0, r0, c7, c10, 5 /* or, use dmb */
+#else
     swp     r0, r0, [r1]
+#endif
     bx      lr
 
 /*
diff --git a/logcat/Android.mk b/logcat/Android.mk
index f9fd2c9..5a9f12d 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -21,5 +21,6 @@
 LOCAL_MODULE_CLASS := ETC
 
 LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_PREBUILT_STRIP_COMMENTS := 1
 
 include $(BUILD_PREBUILT)
diff --git a/rootdir/etc/init.goldfish.sh b/rootdir/etc/init.goldfish.sh
index f1b801d..5ff0a3a 100755
--- a/rootdir/etc/init.goldfish.sh
+++ b/rootdir/etc/init.goldfish.sh
@@ -3,16 +3,20 @@
 ifconfig eth0 10.0.2.15 netmask 255.255.255.0 up
 route add default gw 10.0.2.2 dev eth0
 
-qemud=`getprop.ro.kernel.android.qemud`
-if test -z "$qemud"; then
+qemud=`getprop ro.kernel.android.qemud`
+case "$qemud" in
+    "")
     radio_ril=`getprop ro.kernel.android.ril`
-    if test -z "$radio_ril"; then
+    case "$radio_ril" in
+        "")
         # no need for the radio interface daemon
         # telephony is entirely emulated in Java
         setprop ro.radio.noril yes
         stop ril-daemon
-    fi
-fi
+        ;;
+    esac
+    ;;
+esac
 
 num_dns=`getprop ro.kernel.android.ndns`
 case "$num_dns" in
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a648ad8..9d30518 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -38,7 +38,7 @@
 # Create cgroup mount points for process groups
     mkdir /dev/cpuctl
     mount cgroup none /dev/cpuctl cpu
-    chown sytem system /dev/cpuctl
+    chown system system /dev/cpuctl
     chown system system /dev/cpuctl/tasks
     chmod 0777 /dev/cpuctl/tasks
     write /dev/cpuctl/cpu.shares 1024
@@ -51,7 +51,8 @@
     mkdir /dev/cpuctl/bg_non_interactive
     chown system system /dev/cpuctl/bg_non_interactive/tasks
     chmod 0777 /dev/cpuctl/bg_non_interactive/tasks
-    write /dev/cpuctl/bg_non_interactive/cpu.shares 16
+    # 5.0 %
+    write /dev/cpuctl/bg_non_interactive/cpu.shares 52
 
 # mount mtd partitions
     # Mount /system rw first to give the filesystem a chance to save a checkpoint
diff --git a/vold/blkdev.c b/vold/blkdev.c
index 1482a1a..2c5681a 100644
--- a/vold/blkdev.c
+++ b/vold/blkdev.c
@@ -112,7 +112,7 @@
             goto out;
         }
 
-        for (i = 0; i < 4; i++) {
+        for (i = 0; i < NDOSPART; i++) {
             struct dos_partition part;
 
             dos_partition_dec(block + DOSPARTOFF + i * sizeof(struct dos_partition), &part);
@@ -134,7 +134,7 @@
         struct dos_partition part;
         int part_no = blk->minor -1;
 
-        if (part_no < 4) {
+        if (part_no < NDOSPART) {
             dos_partition_dec(block + DOSPARTOFF + part_no * sizeof(struct dos_partition), &part);
             blk->part_type = part.dp_typ;
         } else {
@@ -219,7 +219,7 @@
 
     /* Create device nodes */
     char nodepath[255];
-    mode_t mode = 0666 | S_IFBLK;
+    mode_t mode = 0660 | S_IFBLK;
     dev_t dev = (major << 8) | minor;
 
     sprintf(nodepath, "%s/vold/%d:%d", DEVPATH, major, minor);
diff --git a/vold/mmc.c b/vold/mmc.c
index cbddb92..6ad97f4 100644
--- a/vold/mmc.c
+++ b/vold/mmc.c
@@ -25,6 +25,7 @@
 #include "vold.h"
 #include "mmc.h"
 #include "media.h"
+#include "diskmbr.h" /* for NDOSPART */
 
 #define DEBUG_BOOTSTRAP 0
 
@@ -157,6 +158,10 @@
 
     sprintf(filename, "/sys%s/name", devpath);
     p = read_file(filename, &sz);
+    if (!p) {
+        LOGE("Unable to read MMC name: %s", filename);
+        return -errno;
+    }
     p[strlen(p) - 1] = '\0';
     sprintf(tmp, "MMC_NAME=%s", p);
     free(p);
@@ -233,7 +238,7 @@
          *mmcblk_devname != '/'; mmcblk_devname--);
     mmcblk_devname++;
 
-    for (part_no = 0; part_no < 4; part_no++) {
+    for (part_no = 1; part_no <= NDOSPART; part_no++) {
         char part_file[255];
         sprintf(part_file, "/sys%s/%sp%d", devpath, mmcblk_devname, part_no);
         if (!access(part_file, F_OK)) {