Merge "Split fstab mount into 2 phases"
diff --git a/adb/Android.mk b/adb/Android.mk
index 0a9c454..b2a0dc4 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -81,12 +81,10 @@
     $(ADB_COMMON_windows_CFLAGS) \
 
 LIBADB_darwin_SRC_FILES := \
-    get_my_path_darwin.cpp \
     sysdeps_unix.cpp \
     usb_osx.cpp \
 
 LIBADB_linux_SRC_FILES := \
-    get_my_path_linux.cpp \
     sysdeps_unix.cpp \
     usb_linux.cpp \
 
diff --git a/adb/adb.cpp b/adb/adb.cpp
index be390d9..056dbef 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -34,6 +34,7 @@
 #include <vector>
 
 #include <android-base/errors.h>
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <android-base/parsenetaddress.h>
@@ -610,8 +611,7 @@
 
 #endif
 
-int launch_server(int server_port)
-{
+int launch_server(const std::string& socket_spec) {
 #if defined(_WIN32)
     /* we need to start the server in the background                    */
     /* we create a PIPE that will be used to wait for the server's "OK" */
@@ -714,9 +714,8 @@
     }
 
     WCHAR   args[64];
-    snwprintf(args, arraysize(args),
-              L"adb -P %d fork-server server --reply-fd %d", server_port,
-              ack_write_as_int);
+    snwprintf(args, arraysize(args), L"adb -L %s fork-server server --reply-fd %d",
+              socket_spec.c_str(), ack_write_as_int);
 
     PROCESS_INFORMATION   pinfo;
     ZeroMemory(&pinfo, sizeof(pinfo));
@@ -843,30 +842,29 @@
         return -1;
     }
 #else /* !defined(_WIN32) */
-    char    path[PATH_MAX];
-    int     fd[2];
-
     // set up a pipe so the child can tell us when it is ready.
     // fd[0] will be parent's end, and the child will write on fd[1]
+    int fd[2];
     if (pipe(fd)) {
         fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
         return -1;
     }
-    get_my_path(path, PATH_MAX);
+
+    std::string path = android::base::GetExecutablePath();
+
     pid_t pid = fork();
-    if(pid < 0) return -1;
+    if (pid < 0) return -1;
 
     if (pid == 0) {
         // child side of the fork
 
         adb_close(fd[0]);
 
-        char str_port[30];
-        snprintf(str_port, sizeof(str_port), "%d", server_port);
         char reply_fd[30];
         snprintf(reply_fd, sizeof(reply_fd), "%d", fd[1]);
         // child process
-        int result = execl(path, "adb", "-P", str_port, "fork-server", "server", "--reply-fd", reply_fd, NULL);
+        int result = execl(path.c_str(), "adb", "-L", socket_spec.c_str(), "fork-server", "server",
+                           "--reply-fd", reply_fd, NULL);
         // this should not return
         fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
     } else  {
diff --git a/adb/adb.h b/adb/adb.h
index cd6b7bd..0b9fe5b 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -126,9 +126,8 @@
 
 void handle_packet(apacket *p, atransport *t);
 
-void get_my_path(char *s, size_t maxLen);
-int launch_server(int server_port);
-int adb_server_main(int is_daemon, int server_port, int ack_reply_fd);
+int launch_server(const std::string& socket_spec);
+int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd);
 
 /* initialize a transport object's func pointers and state */
 #if ADB_HOST
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 4f4f382..8366549 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -246,21 +246,7 @@
 }
 
 static std::string get_user_key_path() {
-    const std::string home = adb_get_homedir_path(true);
-    LOG(DEBUG) << "adb_get_homedir_path returned '" << home << "'";
-
-    const std::string android_dir = android::base::StringPrintf("%s%c.android", home.c_str(),
-                                                                OS_PATH_SEPARATOR);
-
-    struct stat buf;
-    if (stat(android_dir.c_str(), &buf) == -1) {
-        if (adb_mkdir(android_dir.c_str(), 0750) == -1) {
-            PLOG(ERROR) << "Cannot mkdir '" << android_dir << "'";
-            return "";
-        }
-    }
-
-    return android_dir + OS_PATH_SEPARATOR + "adbkey";
+    return adb_get_android_dir_path() + OS_PATH_SEPARATOR + "adbkey";
 }
 
 static bool get_user_key() {
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index a27dd47..919e1c1 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -37,12 +37,12 @@
 
 #include "adb_io.h"
 #include "adb_utils.h"
+#include "socket_spec.h"
 
 static TransportType __adb_transport = kTransportAny;
 static const char* __adb_serial = NULL;
 
-static int __adb_server_port = DEFAULT_ADB_PORT;
-static const char* __adb_server_name = NULL;
+static const char* __adb_server_socket_spec;
 
 void adb_set_transport(TransportType type, const char* serial)
 {
@@ -59,14 +59,11 @@
     }
 }
 
-void adb_set_tcp_specifics(int server_port)
-{
-    __adb_server_port = server_port;
-}
-
-void adb_set_tcp_name(const char* hostname)
-{
-    __adb_server_name = hostname;
+void adb_set_socket_spec(const char* socket_spec) {
+    if (__adb_server_socket_spec) {
+        LOG(FATAL) << "attempted to reinitialize adb_server_socket_spec " << socket_spec << " (was " << __adb_server_socket_spec << ")";
+    }
+    __adb_server_socket_spec = socket_spec;
 }
 
 static int switch_socket_transport(int fd, std::string* error) {
@@ -139,23 +136,12 @@
         return -1;
     }
 
-    int fd;
     std::string reason;
-    if (__adb_server_name) {
-        fd = network_connect(__adb_server_name, __adb_server_port, SOCK_STREAM, 0, &reason);
-        if (fd == -1) {
-            *error = android::base::StringPrintf("can't connect to %s:%d: %s",
-                                                 __adb_server_name, __adb_server_port,
-                                                 reason.c_str());
-            return -2;
-        }
-    } else {
-        fd = network_loopback_client(__adb_server_port, SOCK_STREAM, &reason);
-        if (fd == -1) {
-            *error = android::base::StringPrintf("cannot connect to daemon: %s",
-                                                 reason.c_str());
-            return -2;
-        }
+    int fd = socket_spec_connect(__adb_server_socket_spec, &reason);
+    if (fd < 0) {
+        *error = android::base::StringPrintf("cannot connect to daemon at %s: %s",
+                                             __adb_server_socket_spec, reason.c_str());
+        return -2;
     }
 
     if ((memcmp(&service[0],"host",4) != 0 || service == "host:reconnect") &&
@@ -185,15 +171,14 @@
     int fd = _adb_connect("host:version", error);
 
     D("adb_connect: service %s", service.c_str());
-    if (fd == -2 && __adb_server_name) {
+    if (fd == -2 && !is_local_socket_spec(__adb_server_socket_spec)) {
         fprintf(stderr,"** Cannot start server on remote host\n");
         // error is the original network connection error
         return fd;
     } else if (fd == -2) {
-        fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
-                __adb_server_port);
+        fprintf(stdout, "* daemon not running. starting it now at %s *\n", __adb_server_socket_spec);
     start_server:
-        if (launch_server(__adb_server_port)) {
+        if (launch_server(__adb_server_socket_spec)) {
             fprintf(stderr,"* failed to start daemon *\n");
             // launch_server() has already printed detailed error info, so just
             // return a generic error string about the overall adb_connect()
diff --git a/adb/adb_client.h b/adb/adb_client.h
index 9f9eb1f..d35d705 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -43,11 +43,9 @@
 // Get the preferred transport to connect to.
 void adb_get_transport(TransportType* _Nullable type, const char* _Nullable* _Nullable serial);
 
-// Set TCP specifics of the transport to use.
-void adb_set_tcp_specifics(int server_port);
-
-// Set TCP Hostname of the transport to use.
-void adb_set_tcp_name(const char* _Nullable hostname);
+// Set the socket specification for the adb server.
+// This function can only be called once, and the argument must live to the end of the process.
+void adb_set_socket_spec(const char* _Nonnull socket_spec);
 
 // Send commands to the current emulator instance. Will fail if there is not
 // exactly one emulator connected (or if you use -s <serial> with a <serial>
diff --git a/adb/adb_unique_fd.h b/adb/adb_unique_fd.h
new file mode 100644
index 0000000..34c1bbc
--- /dev/null
+++ b/adb/adb_unique_fd.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+
+// Helper to automatically close an FD when it goes out of scope.
+struct AdbCloser {
+    static void Close(int fd);
+};
+
+using unique_fd = android::base::unique_fd_impl<AdbCloser>;
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 31ec8af..db39ef4 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -17,6 +17,7 @@
 #define TRACE_TAG ADB
 
 #include "adb_utils.h"
+#include "adb_unique_fd.h"
 
 #include <libgen.h>
 #include <stdlib.h>
@@ -25,6 +26,7 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <vector>
 
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
@@ -41,6 +43,8 @@
 #  endif
 #  include "windows.h"
 #  include "shlobj.h"
+#else
+#include <pwd.h>
 #endif
 
 ADB_MUTEX_DEFINE(basename_lock);
@@ -263,14 +267,8 @@
     return true;
 }
 
-std::string adb_get_homedir_path(bool check_env_first) {
+std::string adb_get_homedir_path() {
 #ifdef _WIN32
-    if (check_env_first) {
-        if (const char* const home = getenv("ANDROID_SDK_HOME")) {
-            return home;
-        }
-    }
-
     WCHAR path[MAX_PATH];
     const HRESULT hr = SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path);
     if (FAILED(hr)) {
@@ -286,6 +284,33 @@
     if (const char* const home = getenv("HOME")) {
         return home;
     }
+
+    struct passwd pwent;
+    struct passwd* result;
+    int pwent_max = sysconf(_SC_GETPW_R_SIZE_MAX);
+    std::vector<char> buf(pwent_max);
+    int rc = getpwuid_r(getuid(), &pwent, buf.data(), buf.size(), &result);
+    if (rc == 0 && result) {
+        return result->pw_dir;
+    }
+
+    LOG(FATAL) << "failed to get user home directory";
     return {};
 #endif
 }
+
+std::string adb_get_android_dir_path() {
+    std::string user_dir = adb_get_homedir_path();
+    std::string android_dir = user_dir + OS_PATH_SEPARATOR + ".android";
+    struct stat buf;
+    if (stat(android_dir.c_str(), &buf) == -1) {
+        if (adb_mkdir(android_dir.c_str(), 0750) == -1) {
+            PLOG(FATAL) << "Cannot mkdir '" << android_dir << "'";
+        }
+    }
+    return android_dir;
+}
+
+void AdbCloser::Close(int fd) {
+    adb_close(fd);
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index f6b4b26..16317e0 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -20,7 +20,6 @@
 #include <string>
 
 #include <android-base/macros.h>
-#include <android-base/unique_fd.h>
 
 void close_stdin();
 
@@ -33,10 +32,10 @@
 std::string adb_dirname(const std::string& path);
 
 // Return the user's home directory.
-// |check_env_first| - if true, on Windows check the ANDROID_SDK_HOME
-// environment variable before trying the WinAPI call (useful when looking for
-// the .android directory)
-std::string adb_get_homedir_path(bool check_env_first);
+std::string adb_get_homedir_path();
+
+// Return the adb user directory.
+std::string adb_get_android_dir_path();
 
 bool mkdirs(const std::string& path);
 
@@ -57,13 +56,4 @@
 bool forward_targets_are_valid(const std::string& source, const std::string& dest,
                                std::string* error);
 
-// Helper to automatically close an FD when it goes out of scope.
-struct AdbCloser {
-    static void Close(int fd) {
-        adb_close(fd);
-    }
-};
-
-using unique_fd = android::base::unique_fd_impl<AdbCloser>;
-
 #endif
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 0c85fe5..571c227 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -88,7 +88,7 @@
 }
 #endif
 
-int adb_server_main(int is_daemon, int server_port, int ack_reply_fd) {
+int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd) {
 #if defined(_WIN32)
     // adb start-server starts us up with stdout and stderr hooked up to
     // anonymous pipes. When the C Runtime sees this, it makes stderr and
@@ -113,8 +113,7 @@
     local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
 
     std::string error;
-    std::string local_name = android::base::StringPrintf("tcp:%d", server_port);
-    if (install_listener(local_name, "*smartsocket*", nullptr, 0, nullptr, &error)) {
+    if (install_listener(socket_spec, "*smartsocket*", nullptr, 0, nullptr, &error)) {
         fatal("could not install *smartsocket* listener: %s", error.c_str());
     }
 
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index c69fe19..77c5f96 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -51,6 +51,7 @@
 #include "adb_auth.h"
 #include "adb_client.h"
 #include "adb_io.h"
+#include "adb_unique_fd.h"
 #include "adb_utils.h"
 #include "bugreport.h"
 #include "commandline.h"
@@ -100,6 +101,8 @@
         "                                 be an absolute path.\n"
         " -H                            - Name of adb server host (default: localhost)\n"
         " -P                            - Port of adb server (default: 5037)\n"
+        " -L <socket>                   - listen on socket specifier for the adb server\n"
+        "                                 (default: tcp:localhost:5037)\n"
         " devices [-l]                  - list all connected devices\n"
         "                                 ('-l' will also list device qualifiers)\n"
         " connect <host>[:<port>]       - connect to a device via TCP/IP\n"
@@ -1453,18 +1456,9 @@
     }
     // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
 
-    /* Validate and assign the server port */
-    const char* server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
-    int server_port = DEFAULT_ADB_PORT;
-    if (server_port_str && strlen(server_port_str) > 0) {
-        server_port = strtol(server_port_str, nullptr, 0);
-        if (server_port <= 0 || server_port > 65535) {
-            fprintf(stderr,
-                    "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number less than 65536. Got \"%s\"\n",
-                    server_port_str);
-            return usage();
-        }
-    }
+    const char* server_host_str = nullptr;
+    const char* server_port_str = nullptr;
+    const char* server_socket_str = nullptr;
 
     // We need to check for -d and -e before we look at $ANDROID_SERIAL.
     const char* serial = nullptr;
@@ -1518,17 +1512,14 @@
         } else if (!strcmp(argv[0],"-a")) {
             gListenAll = 1;
         } else if (!strncmp(argv[0], "-H", 2)) {
-            const char *hostname = NULL;
             if (argv[0][2] == '\0') {
                 if (argc < 2) return usage();
-                hostname = argv[1];
+                server_host_str = argv[1];
                 argc--;
                 argv++;
             } else {
-                hostname = argv[0] + 2;
+                server_host_str = argv[0] + 2;
             }
-            adb_set_tcp_name(hostname);
-
         } else if (!strncmp(argv[0], "-P", 2)) {
             if (argv[0][2] == '\0') {
                 if (argc < 2) return usage();
@@ -1538,34 +1529,58 @@
             } else {
                 server_port_str = argv[0] + 2;
             }
-            if (strlen(server_port_str) > 0) {
-                server_port = (int) strtol(server_port_str, NULL, 0);
-                if (server_port <= 0 || server_port > 65535) {
-                    fprintf(stderr,
-                            "adb: port number must be a positive number less than 65536. Got \"%s\"\n",
-                            server_port_str);
-                    return usage();
-                }
-            } else {
-                fprintf(stderr,
-                "adb: port number must be a positive number less than 65536. Got empty string.\n");
-                return usage();
-            }
+        } else if (!strcmp(argv[0], "-L")) {
+            if (argc < 2) return usage();
+            server_socket_str = argv[1];
+            argc--;
+            argv++;
         } else {
-                /* out of recognized modifiers and flags */
+            /* out of recognized modifiers and flags */
             break;
         }
         argc--;
         argv++;
     }
 
+    if ((server_host_str || server_port_str) && server_socket_str) {
+        fprintf(stderr, "adb: -L is incompatible with -H or -P\n");
+        exit(1);
+    }
+
+    // If -L, -H, or -P are specified, ignore environment variables.
+    // Otherwise, prefer ADB_SERVER_SOCKET over ANDROID_ADB_SERVER_ADDRESS/PORT.
+    if (!(server_host_str || server_port_str || server_socket_str)) {
+        server_socket_str = server_socket_str ? server_socket_str : getenv("ADB_SERVER_SOCKET");
+    }
+
+    if (!server_socket_str) {
+        // tcp:1234 and tcp:localhost:1234 are different with -a, so don't default to localhost
+        server_host_str = server_host_str ? server_host_str : getenv("ANDROID_ADB_SERVER_ADDRESS");
+
+        long server_port = DEFAULT_ADB_PORT;
+        server_port_str = server_port_str ? server_port_str : getenv("ANDROID_ADB_SERVER_PORT");
+
+        int rc;
+        char* temp;
+        if (server_host_str) {
+            rc = asprintf(&temp, "tcp:%s:%ld", server_host_str, server_port);
+        } else {
+            rc = asprintf(&temp, "tcp:%ld", server_port);
+        }
+        if (rc < 0) {
+            fatal("failed to allocate server socket specification");
+        }
+        server_socket_str = temp;
+    }
+
+    adb_set_socket_spec(server_socket_str);
+
     // If none of -d, -e, or -s were specified, try $ANDROID_SERIAL.
     if (transport_type == kTransportAny && serial == nullptr) {
         serial = getenv("ANDROID_SERIAL");
     }
 
     adb_set_transport(transport_type, serial);
-    adb_set_tcp_specifics(server_port);
 
     if (is_server) {
         if (no_daemon || is_daemon) {
@@ -1573,9 +1588,9 @@
                 fprintf(stderr, "reply fd for adb server to client communication not specified.\n");
                 return usage();
             }
-            r = adb_server_main(is_daemon, server_port, ack_reply_fd);
+            r = adb_server_main(is_daemon, server_socket_str, ack_reply_fd);
         } else {
-            r = launch_server(server_port);
+            r = launch_server(server_socket_str);
         }
         if (r) {
             fprintf(stderr,"* could not start server *\n");
diff --git a/adb/console.cpp b/adb/console.cpp
index e9b90a5..9563eac 100644
--- a/adb/console.cpp
+++ b/adb/console.cpp
@@ -32,7 +32,7 @@
 static std::string adb_construct_auth_command() {
     static const char auth_token_filename[] = ".emulator_console_auth_token";
 
-    std::string auth_token_path = adb_get_homedir_path(false);
+    std::string auth_token_path = adb_get_homedir_path();
     auth_token_path += OS_PATH_SEPARATOR;
     auth_token_path += auth_token_filename;
 
diff --git a/adb/get_my_path_darwin.cpp b/adb/get_my_path_darwin.cpp
deleted file mode 100644
index b0c962e..0000000
--- a/adb/get_my_path_darwin.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#import <Carbon/Carbon.h>
-#include <unistd.h>
-
-#include "adb.h"
-
-void get_my_path(char *s, size_t maxLen)
-{
-    CFBundleRef mainBundle = CFBundleGetMainBundle();
-    CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle);
-    CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
-    CFRelease(executableURL);
-
-    CFStringGetFileSystemRepresentation(executablePathString, s, maxLen);
-    CFRelease(executablePathString);
-}
-
diff --git a/adb/get_my_path_linux.cpp b/adb/get_my_path_linux.cpp
deleted file mode 100644
index 11c0b21..0000000
--- a/adb/get_my_path_linux.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2007 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 <limits.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "adb.h"
-
-void get_my_path(char *exe, size_t maxLen)
-{
-    char proc[64];
-    snprintf(proc, sizeof proc, "/proc/%d/exe", getpid());
-    int err = readlink(proc, exe, maxLen - 1);
-    if(err > 0) {
-        exe[err] = '\0';
-    } else {
-        exe[0] = '\0';
-    }
-}
-
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index 027821a..3135aa4 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/jdwp_service.cpp
@@ -34,6 +34,7 @@
 
 #include "adb.h"
 #include "adb_io.h"
+#include "adb_unique_fd.h"
 #include "adb_utils.h"
 
 /* here's how these things work.
diff --git a/adb/protocol.txt b/adb/protocol.txt
index 5c7c6ba..55ea87f 100644
--- a/adb/protocol.txt
+++ b/adb/protocol.txt
@@ -29,12 +29,12 @@
 32 bit words which are sent across the wire in little endian format.
 
 struct message {
-    unsigned command;       /* command identifier constant      */
-    unsigned arg0;          /* first argument                   */
-    unsigned arg1;          /* second argument                  */
-    unsigned data_length;   /* length of payload (0 is allowed) */
-    unsigned data_crc32;    /* crc32 of data payload            */
-    unsigned magic;         /* command ^ 0xffffffff             */
+    unsigned command;       /* command identifier constant (A_CNXN, ...) */
+    unsigned arg0;          /* first argument                            */
+    unsigned arg1;          /* second argument                           */
+    unsigned data_length;   /* length of payload (0 is allowed)          */
+    unsigned data_crc32;    /* crc32 of data payload                     */
+    unsigned magic;         /* command ^ 0xffffffff                      */
 };
 
 Receipt of an invalid message header, corrupt message payload, or an
@@ -55,6 +55,8 @@
 
 --- CONNECT(version, maxdata, "system-identity-string") ----------------
 
+Command constant: A_CNXN
+
 The CONNECT message establishes the presence of a remote system.
 The version is used to ensure protocol compatibility and maxdata
 declares the maximum message body size that the remote system
@@ -80,6 +82,8 @@
 
 --- AUTH(type, 0, "data") ----------------------------------------------
 
+Command constant: A_AUTH
+
 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
@@ -98,6 +102,8 @@
 
 --- OPEN(local-id, 0, "destination") -----------------------------------
 
+Command constant: A_OPEN
+
 The OPEN message informs the recipient that the sender has a stream
 identified by local-id that it wishes to connect to the named
 destination in the message payload.  The local-id may not be zero.
@@ -120,11 +126,13 @@
 
 --- READY(local-id, remote-id, "") -------------------------------------
 
+Command constant: A_OKAY
+
 The READY message informs the recipient that the sender's stream
 identified by local-id is ready for write messages and that it is
 connected to the recipient's stream identified by remote-id.
 
-Neither the local-id nor the remote-id may be zero. 
+Neither the local-id nor the remote-id may be zero.
 
 A READY message containing a remote-id which does not map to an open
 stream on the recipient's side is ignored.  The stream may have been
@@ -135,9 +143,10 @@
 not change on later READY messages sent to the same stream.
 
 
-
 --- WRITE(local-id, remote-id, "data") ---------------------------------
 
+Command constant: A_WRTE
+
 The WRITE message sends data to the recipient's stream identified by
 remote-id.  The payload MUST be <= maxdata in length.
 
@@ -154,6 +163,8 @@
 
 --- CLOSE(local-id, remote-id, "") -------------------------------------
 
+Command constant: A_CLSE
+
 The CLOSE message informs recipient that the connection between the
 sender's stream (local-id) and the recipient's stream (remote-id) is
 broken.  The remote-id MUST not be zero, but the local-id MAY be zero
@@ -170,12 +181,14 @@
 
 --- SYNC(online, sequence, "") -----------------------------------------
 
+Command constant: A_SYNC
+
 The SYNC message is used by the io pump to make sure that stale
 outbound messages are discarded when the connection to the remote side
 is broken.  It is only used internally to the bridge and never valid
-to send across the wire.  
+to send across the wire.
 
-* when the connection to the remote side goes offline, the io pump 
+* when the connection to the remote side goes offline, the io pump
   sends a SYNC(0, 0) and starts discarding all messages
 * when the connection to the remote side is established, the io pump
   sends a SYNC(1, token) and continues to discard messages
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index d83622c..01e206a 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -100,6 +100,7 @@
 #include "adb.h"
 #include "adb_io.h"
 #include "adb_trace.h"
+#include "adb_unique_fd.h"
 #include "adb_utils.h"
 #include "security_log_tags.h"
 
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
index f8bbbb3..18e6e6d 100644
--- a/adb/socket_spec.cpp
+++ b/adb/socket_spec.cpp
@@ -131,6 +131,22 @@
     return StartsWith(spec, "tcp:");
 }
 
+bool is_local_socket_spec(const std::string& spec) {
+    for (const auto& it : kLocalSocketTypes) {
+        std::string prefix = it.first + ":";
+        if (StartsWith(spec, prefix.c_str())) {
+            return true;
+        }
+    }
+
+    std::string error;
+    std::string hostname;
+    if (!parse_tcp_spec(spec, &hostname, nullptr, &error)) {
+        return false;
+    }
+    return tcp_host_is_local(hostname);
+}
+
 int socket_spec_connect(const std::string& spec, std::string* error) {
     if (StartsWith(spec, "tcp:")) {
         std::string hostname;
diff --git a/adb/socket_spec.h b/adb/socket_spec.h
index 69efb07..6302da5 100644
--- a/adb/socket_spec.h
+++ b/adb/socket_spec.h
@@ -20,6 +20,7 @@
 
 // Returns true if the argument starts with a plausible socket prefix.
 bool is_socket_spec(const std::string& spec);
+bool is_local_socket_spec(const std::string& spec);
 
 int socket_spec_connect(const std::string& spec, std::string* error);
 int socket_spec_listen(const std::string& spec, std::string* error,
diff --git a/adb/test_adb.py b/adb/test_adb.py
index 0f1b034..cb3e0d8 100644
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -207,6 +207,28 @@
             # reading the response from the adb emu kill command (on Windows).
             self.assertEqual(0, p.returncode)
 
+    def test_connect_ipv4_ipv6(self):
+        """Ensure that `adb connect localhost:1234` will try both IPv4 and IPv6.
+
+        Bug: http://b/30313466
+        """
+        ipv4 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        ipv4.bind(('127.0.0.1', 0))
+        ipv4.listen(1)
+
+        ipv6 = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+        ipv6.bind(('::1', ipv4.getsockname()[1] + 1))
+        ipv6.listen(1)
+
+        for s in (ipv4, ipv6):
+            port = s.getsockname()[1]
+            output = subprocess.check_output(
+                ['adb', 'connect', 'localhost:{}'.format(port)])
+
+            self.assertEqual(
+                output.strip(), 'connected to localhost:{}'.format(port))
+            s.close()
+
 
 def main():
     random.seed(0)
diff --git a/base/file.cpp b/base/file.cpp
index 4e7ac82..721ab2f 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -20,14 +20,24 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <unistd.h>
 
+#include <memory>
 #include <string>
+#include <vector>
 
 #include "android-base/macros.h"  // For TEMP_FAILURE_RETRY on Darwin.
 #include "android-base/logging.h"
 #include "android-base/utf8.h"
 #include "utils/Compat.h"
 
+#if defined(__APPLE__)
+#include <mach-o/dyld.h>
+#endif
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
 namespace android {
 namespace base {
 
@@ -171,5 +181,55 @@
   return true;
 }
 
+#if !defined(_WIN32)
+bool Readlink(const std::string& path, std::string* result) {
+  result->clear();
+
+  // Most Linux file systems (ext2 and ext4, say) limit symbolic links to
+  // 4095 bytes. Since we'll copy out into the string anyway, it doesn't
+  // waste memory to just start there. We add 1 so that we can recognize
+  // whether it actually fit (rather than being truncated to 4095).
+  std::vector<char> buf(4095 + 1);
+  while (true) {
+    ssize_t size = readlink(path.c_str(), &buf[0], buf.size());
+    // Unrecoverable error?
+    if (size == -1) return false;
+    // It fit! (If size == buf.size(), it may have been truncated.)
+    if (static_cast<size_t>(size) < buf.size()) {
+      result->assign(&buf[0], size);
+      return true;
+    }
+    // Double our buffer and try again.
+    buf.resize(buf.size() * 2);
+  }
+}
+#endif
+
+std::string GetExecutablePath() {
+#if defined(__linux__)
+  std::string path;
+  android::base::Readlink("/proc/self/exe", &path);
+  return path;
+#elif defined(__APPLE__)
+  char path[PATH_MAX + 1];
+  uint32_t path_len = sizeof(path);
+  int rc = _NSGetExecutablePath(path, &path_len);
+  if (rc < 0) {
+    std::unique_ptr<char> path_buf(new char[path_len]);
+    _NSGetExecutablePath(path_buf.get(), &path_len);
+    return path_buf.get();
+  }
+  return path;
+#elif defined(_WIN32)
+  char path[PATH_MAX + 1];
+  DWORD result = GetModuleFileName(NULL, path, sizeof(path) - 1);
+  if (result == 0 || result == sizeof(path) - 1) return "";
+  path[PATH_MAX - 1] = 0;
+  return path;
+#else
+#error unknown OS
+#endif
+}
+
 }  // namespace base
 }  // namespace android
diff --git a/base/file_test.cpp b/base/file_test.cpp
index 17755bf..f5d6062 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -110,3 +110,33 @@
   ASSERT_FALSE(android::base::RemoveFileIfExists(td.path, &err));
   ASSERT_EQ("is not a regular or symbol link file", err);
 }
+
+TEST(file, Readlink) {
+#if !defined(_WIN32)
+  // Linux doesn't allow empty symbolic links.
+  std::string min("x");
+  // ext2 and ext4 both have PAGE_SIZE limits.
+  std::string max(static_cast<size_t>(4096 - 1), 'x');
+
+  TemporaryDir td;
+  std::string min_path{std::string(td.path) + "/" + "min"};
+  std::string max_path{std::string(td.path) + "/" + "max"};
+
+  ASSERT_EQ(0, symlink(min.c_str(), min_path.c_str()));
+  ASSERT_EQ(0, symlink(max.c_str(), max_path.c_str()));
+
+  std::string result;
+
+  result = "wrong";
+  ASSERT_TRUE(android::base::Readlink(min_path, &result));
+  ASSERT_EQ(min, result);
+
+  result = "wrong";
+  ASSERT_TRUE(android::base::Readlink(max_path, &result));
+  ASSERT_EQ(max, result);
+#endif
+}
+
+TEST(file, GetExecutablePath) {
+  ASSERT_NE("", android::base::GetExecutablePath());
+}
diff --git a/base/include/android-base/file.h b/base/include/android-base/file.h
index aa18ea7..5b22a65 100644
--- a/base/include/android-base/file.h
+++ b/base/include/android-base/file.h
@@ -43,6 +43,12 @@
 
 bool RemoveFileIfExists(const std::string& path, std::string* err = nullptr);
 
+#if !defined(_WIN32)
+bool Readlink(const std::string& path, std::string* result);
+#endif
+
+std::string GetExecutablePath();
+
 }  // namespace base
 }  // namespace android
 
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index 66d60c9..721ecce 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -265,7 +265,7 @@
 // MakeEagerEvaluator to infer the types of LHS and RHS.
 template <typename LHS, typename RHS>
 struct EagerEvaluator {
-  EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) {
+  constexpr EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) {
   }
   LHS lhs;
   RHS rhs;
@@ -273,7 +273,7 @@
 
 // Helper function for CHECK_xx.
 template <typename LHS, typename RHS>
-static inline EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
+constexpr EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
   return EagerEvaluator<LHS, RHS>(lhs, rhs);
 }
 
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index ee16d02..88bbe8a 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -41,18 +41,9 @@
 // Note, that most uses of DISALLOW_ASSIGN and DISALLOW_COPY are broken
 // semantically, one should either use disallow both or neither. Try to
 // avoid these in new code.
-//
-// When building with C++11 toolchains, just use the language support
-// for explicitly deleted methods.
-#if __cplusplus >= 201103L
 #define DISALLOW_COPY_AND_ASSIGN(TypeName) \
   TypeName(const TypeName&) = delete;      \
   void operator=(const TypeName&) = delete
-#else
-#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
-  TypeName(const TypeName&);               \
-  void operator=(const TypeName&)
-#endif
 
 // A macro to disallow all the implicit constructors, namely the
 // default constructor, copy constructor and operator= functions.
@@ -60,18 +51,9 @@
 // This should be used in the private: declarations for a class
 // that wants to prevent anyone from instantiating it. This is
 // especially useful for classes containing only static methods.
-//
-// When building with C++11 toolchains, just use the language support
-// for explicitly deleted methods.
-#if __cplusplus >= 201103L
 #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
   TypeName() = delete;                           \
   DISALLOW_COPY_AND_ASSIGN(TypeName)
-#else
-#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
-  TypeName();                                    \
-  DISALLOW_COPY_AND_ASSIGN(TypeName)
-#endif
 
 // The arraysize(arr) macro returns the # of elements in an array arr.
 // The expression is a compile-time constant, and therefore can be
@@ -174,10 +156,10 @@
 //  only if there are no statements on the execution path between it and the
 //  next switch label.
 //
-//  When compiled with clang in C++11 mode, the FALLTHROUGH_INTENDED macro is
-//  expanded to [[clang::fallthrough]] attribute, which is analysed when
-//  performing switch labels fall-through diagnostic ('-Wimplicit-fallthrough').
-//  See clang documentation on language extensions for details:
+//  When compiled with clang, the FALLTHROUGH_INTENDED macro is expanded to
+//  [[clang::fallthrough]] attribute, which is analysed when performing switch
+//  labels fall-through diagnostic ('-Wimplicit-fallthrough'). See clang
+//  documentation on language extensions for details:
 //  http://clang.llvm.org/docs/LanguageExtensions.html#clang__fallthrough
 //
 //  When used with unsupported compilers, the FALLTHROUGH_INTENDED macro has no
@@ -185,7 +167,7 @@
 //
 //  In either case this macro has no effect on runtime behavior and performance
 //  of code.
-#if defined(__clang__) && __cplusplus >= 201103L && defined(__has_warning)
+#if defined(__clang__) && defined(__has_warning)
 #if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
 #define FALLTHROUGH_INTENDED [[clang::fallthrough]]  // NOLINT
 #endif
diff --git a/base/include/android-base/thread_annotations.h b/base/include/android-base/thread_annotations.h
index 2422102..fbb5923 100644
--- a/base/include/android-base/thread_annotations.h
+++ b/base/include/android-base/thread_annotations.h
@@ -29,6 +29,9 @@
 #define SCOPED_CAPABILITY \
       THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
 
+#define SHARED_CAPABILITY(...) \
+      THREAD_ANNOTATION_ATTRIBUTE__(shared_capability(__VA_ARGS__))
+
 #define GUARDED_BY(x) \
       THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
 
@@ -77,6 +80,27 @@
 #define RETURN_CAPABILITY(x) \
       THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
 
+#define EXCLUSIVE_LOCK_FUNCTION(...) \
+      THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
+
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
+      THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
+
+#define SHARED_LOCK_FUNCTION(...) \
+      THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
+
+#define SHARED_TRYLOCK_FUNCTION(...) \
+      THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
+
+#define UNLOCK_FUNCTION(...) \
+      THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
+
+#define SCOPED_LOCKABLE \
+      THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+#define LOCK_RETURNED(x) \
+      THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
 #define NO_THREAD_SAFETY_ANALYSIS \
       THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
 
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 869e60f..c323311 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -95,4 +95,14 @@
 }  // namespace base
 }  // namespace android
 
+template <typename T>
+int close(const android::base::unique_fd_impl<T>&)
+#if defined(__clang__)
+  __attribute__((__unavailable__(
+#else
+  __attribute__((__error__(
+#endif
+    "close called on unique_fd"
+  )));
+
 #endif  // ANDROID_BASE_UNIQUE_FD_H
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 28e3d4b..7112d1d 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -43,15 +43,15 @@
 
 LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"'
 
-LOCAL_SRC_FILES_linux := usb_linux.cpp util_linux.cpp
+LOCAL_SRC_FILES_linux := usb_linux.cpp
 LOCAL_STATIC_LIBRARIES_linux := libselinux
 
-LOCAL_SRC_FILES_darwin := usb_osx.cpp util_osx.cpp
+LOCAL_SRC_FILES_darwin := usb_osx.cpp
 LOCAL_STATIC_LIBRARIES_darwin := libselinux
 LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
 LOCAL_CFLAGS_darwin := -Wno-unused-parameter
 
-LOCAL_SRC_FILES_windows := usb_windows.cpp util_windows.cpp
+LOCAL_SRC_FILES_windows := usb_windows.cpp
 LOCAL_STATIC_LIBRARIES_windows := AdbWinApi
 LOCAL_REQUIRED_MODULES_windows := AdbWinApi
 LOCAL_LDLIBS_windows := -lws2_32
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index df0f651..987ba83 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -47,6 +47,7 @@
 #include <utility>
 #include <vector>
 
+#include <android-base/file.h>
 #include <android-base/macros.h>
 #include <android-base/parseint.h>
 #include <android-base/parsenetaddress.h>
@@ -116,7 +117,7 @@
 
 static std::string find_item_given_name(const char* img_name, const char* product) {
     if(product) {
-        std::string path = get_my_path();
+        std::string path = android::base::GetExecutablePath();
         path.erase(path.find_last_of('/'));
         return android::base::StringPrintf("%s/../../../target/product/%s/%s",
                                            path.c_str(), product, img_name);
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index c2ea551..6699b6a 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -72,8 +72,6 @@
 char *mkmsg(const char *fmt, ...);
 __attribute__((__noreturn__)) void die(const char *fmt, ...);
 
-std::string get_my_path();
-
 /* Current product */
 extern char cur_product[FB_RESPONSE_SZ + 1];
 
diff --git a/fastboot/util_linux.cpp b/fastboot/util_linux.cpp
deleted file mode 100644
index 2c6aedb..0000000
--- a/fastboot/util_linux.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "fastboot.h"
-
-#include <unistd.h>
-#include <limits.h>
-
-#include <android-base/stringprintf.h>
-
-std::string get_my_path() {
-    std::string proc = android::base::StringPrintf("/proc/%d/exe", getpid());
-    char path[PATH_MAX + 1];
-    int rc = readlink(proc.c_str(), path, sizeof(path) - 1);
-    if (rc == -1) return "";
-    path[rc] = '\0';
-    return path;
-}
diff --git a/fastboot/util_osx.cpp b/fastboot/util_osx.cpp
deleted file mode 100644
index 4bae7c4..0000000
--- a/fastboot/util_osx.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "fastboot.h"
-
-#import <Carbon/Carbon.h>
-#include <unistd.h>
-
-std::string get_my_path() {
-    CFBundleRef mainBundle = CFBundleGetMainBundle();
-    CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle);
-    CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
-    CFRelease(executableURL);
-
-    char path[PATH_MAX + 1];
-    CFStringGetFileSystemRepresentation(executablePathString, path, sizeof(PATH_MAX)-1);
-    CFRelease(executablePathString);
-
-    return path;
-}
diff --git a/fastboot/util_windows.cpp b/fastboot/util_windows.cpp
deleted file mode 100644
index 3b22c55..0000000
--- a/fastboot/util_windows.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "fastboot.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <limits.h>
-
-#include <windows.h>
-
-std::string get_my_path() {
-    char path[PATH_MAX + 1];
-
-    DWORD result = GetModuleFileName(NULL, path, sizeof(path) - 1);
-    if (result == 0 || result == sizeof(path) - 1) return "";
-    path[PATH_MAX - 1] = 0;
-
-    return path;
-}
diff --git a/init/devices.cpp b/init/devices.cpp
index 830b74c..bad04ae 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -14,21 +14,23 @@
  * limitations under the License.
  */
 
+#include <dirent.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <fnmatch.h>
+#include <libgen.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <fcntl.h>
-#include <dirent.h>
-#include <unistd.h>
 #include <string.h>
-
 #include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
 #include <sys/un.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
 #include <linux/netlink.h>
 
 #include <memory>
@@ -39,8 +41,6 @@
 #include <selinux/avc.h>
 
 #include <private/android_filesystem_config.h>
-#include <sys/time.h>
-#include <sys/wait.h>
 
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
@@ -541,30 +541,49 @@
     return links;
 }
 
+static void make_link_init(const char* oldpath, const char* newpath) {
+  const char* slash = strrchr(newpath, '/');
+  if (!slash) return;
+
+  if (mkdir_recursive(dirname(newpath), 0755)) {
+    PLOG(ERROR) << "Failed to create directory " << dirname(newpath);
+  }
+
+  if (symlink(oldpath, newpath) && errno != EEXIST) {
+    PLOG(ERROR) << "Failed to symlink " << oldpath << " to " << newpath;
+  }
+}
+
+static void remove_link(const char* oldpath, const char* newpath) {
+  std::string path;
+  if (android::base::Readlink(newpath, &path) && path == oldpath) unlink(newpath);
+}
+
 static void handle_device(const char *action, const char *devpath,
         const char *path, int block, int major, int minor, char **links)
 {
-    int i;
-
     if(!strcmp(action, "add")) {
         make_device(devpath, path, block, major, minor, (const char **)links);
         if (links) {
-            for (i = 0; links[i]; i++)
+            for (int i = 0; links[i]; i++) {
                 make_link_init(devpath, links[i]);
+            }
         }
     }
 
     if(!strcmp(action, "remove")) {
         if (links) {
-            for (i = 0; links[i]; i++)
+            for (int i = 0; links[i]; i++) {
                 remove_link(devpath, links[i]);
+            }
         }
         unlink(devpath);
     }
 
     if (links) {
-        for (i = 0; links[i]; i++)
+        for (int i = 0; links[i]; i++) {
             free(links[i]);
+        }
         free(links);
     }
 }
diff --git a/init/readme.txt b/init/readme.txt
index 4fb016b..77e5de2 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -195,6 +195,14 @@
   Scheduling priority of the service process. This value has to be in range
   -20 to 19. Default priority is 0. Priority is set via setpriority().
 
+namespace <pid|mnt>
+  Enter a new PID or mount namespace when forking the service.
+
+oom_score_adjust <value>
+   Sets the child's /proc/self/oom_score_adj to the specified value,
+   which must range from -1000 to 1000.
+
+
 Triggers
 --------
 Triggers are strings which can be used to match certain kinds of
diff --git a/init/service.cpp b/init/service.cpp
index 32aafd6..1caf7c6 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -163,7 +163,7 @@
     : name_(name), classname_(classname), flags_(0), pid_(0), time_started_(0),
       time_crashed_(0), nr_crashed_(0), uid_(0), gid_(0), namespace_flags_(0),
       seclabel_(""), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
-      priority_(0), args_(args) {
+      priority_(0), oom_score_adjust_(-1000), args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
 }
 
@@ -176,7 +176,7 @@
       time_started_(0), time_crashed_(0), nr_crashed_(0), uid_(uid), gid_(gid),
       supp_gids_(supp_gids), namespace_flags_(namespace_flags),
       seclabel_(seclabel), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
-      priority_(0), args_(args) {
+      priority_(0), oom_score_adjust_(-1000), args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
 }
 
@@ -419,6 +419,18 @@
     return true;
 }
 
+bool Service::ParseOomScoreAdjust(const std::vector<std::string>& args, std::string* err) {
+    oom_score_adjust_ = std::stol(args[1], 0, 10);
+
+    if (oom_score_adjust_ < -1000 || oom_score_adjust_ > 1000) {
+        *err = "oom_score_adjust value must be in range -1000 - +1000";
+        return false;
+    }
+
+    return true;
+}
+
+
 bool Service::ParseSeclabel(const std::vector<std::string>& args, std::string* err) {
     seclabel_ = args[1];
     return true;
@@ -476,6 +488,8 @@
         {"keycodes",    {1,     kMax, &Service::ParseKeycodes}},
         {"oneshot",     {0,     0,    &Service::ParseOneshot}},
         {"onrestart",   {1,     kMax, &Service::ParseOnrestart}},
+        {"oom_score_adjust",
+                        {1,     1,    &Service::ParseOomScoreAdjust}},
         {"namespace",   {1,     2,    &Service::ParseNamespace}},
         {"seclabel",    {1,     1,    &Service::ParseSeclabel}},
         {"setenv",      {2,     2,    &Service::ParseSetenv}},
@@ -611,6 +625,14 @@
         return false;
     }
 
+    if (oom_score_adjust_ != -1000) {
+        std::string oom_str = StringPrintf("%d", oom_score_adjust_);
+        std::string oom_file = StringPrintf("/proc/%d/oom_score_adj", pid);
+        if (!WriteStringToFile(oom_str, oom_file)) {
+            PLOG(ERROR) << "couldn't write oom_score_adj: " << strerror(errno);
+        }
+    }
+
     time_started_ = gettime();
     pid_ = pid;
     flags_ |= SVC_RUNNING;
diff --git a/init/service.h b/init/service.h
index fb03a07..4a3412c 100644
--- a/init/service.h
+++ b/init/service.h
@@ -126,6 +126,7 @@
     bool ParseKeycodes(const std::vector<std::string>& args, std::string* err);
     bool ParseOneshot(const std::vector<std::string>& args, std::string* err);
     bool ParseOnrestart(const std::vector<std::string>& args, std::string* err);
+    bool ParseOomScoreAdjust(const std::vector<std::string>& args, std::string* err);
     bool ParseNamespace(const std::vector<std::string>& args, std::string* err);
     bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
     bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
@@ -165,6 +166,8 @@
     int ioprio_pri_;
     int priority_;
 
+    int oom_score_adjust_;
+
     std::vector<std::string> args_;
 };
 
diff --git a/init/util.cpp b/init/util.cpp
index c1750d2..660a66f 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -270,40 +270,6 @@
     }
 }
 
-void make_link_init(const char *oldpath, const char *newpath)
-{
-    int ret;
-    char buf[256];
-    const char *slash;
-    int width;
-
-    slash = strrchr(newpath, '/');
-    if (!slash)
-        return;
-    width = slash - newpath;
-    if (width <= 0 || width > (int)sizeof(buf) - 1)
-        return;
-    memcpy(buf, newpath, width);
-    buf[width] = 0;
-    ret = mkdir_recursive(buf, 0755);
-    if (ret) PLOG(ERROR) << "Failed to create directory " << buf;
-
-    ret = symlink(oldpath, newpath);
-    if (ret && errno != EEXIST) PLOG(ERROR) << "Failed to symlink " << oldpath << " to " << newpath;
-}
-
-void remove_link(const char *oldpath, const char *newpath)
-{
-    char path[256];
-    ssize_t ret;
-    ret = readlink(newpath, path, sizeof(path) - 1);
-    if (ret <= 0)
-        return;
-    path[ret] = 0;
-    if (!strcmp(path, oldpath))
-        unlink(newpath);
-}
-
 int wait_for_file(const char *filename, int timeout)
 {
     struct stat info;
diff --git a/init/util.h b/init/util.h
index 29d0497..b83b9a0 100644
--- a/init/util.h
+++ b/init/util.h
@@ -51,8 +51,6 @@
 
 int mkdir_recursive(const char *pathname, mode_t mode);
 void sanitize(char *p);
-void make_link_init(const char *oldpath, const char *newpath);
-void remove_link(const char *oldpath, const char *newpath);
 int wait_for_file(const char *filename, int timeout);
 void import_kernel_cmdline(bool in_qemu,
                            const std::function<void(const std::string&, const std::string&, bool)>&);
diff --git a/libcutils/socket_network_client_unix.c b/libcutils/socket_network_client_unix.c
index 3300b8f..46818d6 100644
--- a/libcutils/socket_network_client_unix.c
+++ b/libcutils/socket_network_client_unix.c
@@ -59,64 +59,63 @@
         return -1;
     }
 
-    // TODO: try all the addresses if there's more than one?
-    int family = addrs[0].ai_family;
-    int protocol = addrs[0].ai_protocol;
-    socklen_t addr_len = addrs[0].ai_addrlen;
-    struct sockaddr_storage addr;
-    memcpy(&addr, addrs[0].ai_addr, addr_len);
+    int result = -1;
+    for (struct addrinfo* addr = addrs; addr != NULL; addr = addr->ai_next) {
+        // The Mac doesn't have SOCK_NONBLOCK.
+        int s = socket(addr->ai_family, type, addr->ai_protocol);
+        if (s == -1 || toggle_O_NONBLOCK(s) == -1) return -1;
+
+        int rc = connect(s, addr->ai_addr, addr->ai_addrlen);
+        if (rc == 0) {
+            result = toggle_O_NONBLOCK(s);
+            break;
+        } else if (rc == -1 && errno != EINPROGRESS) {
+            close(s);
+            continue;
+        }
+
+        fd_set r_set;
+        FD_ZERO(&r_set);
+        FD_SET(s, &r_set);
+        fd_set w_set = r_set;
+
+        struct timeval ts;
+        ts.tv_sec = timeout;
+        ts.tv_usec = 0;
+        if ((rc = select(s + 1, &r_set, &w_set, NULL, (timeout != 0) ? &ts : NULL)) == -1) {
+            close(s);
+            break;
+        }
+        if (rc == 0) {  // we had a timeout
+            errno = ETIMEDOUT;
+            close(s);
+            break;
+        }
+
+        int error = 0;
+        socklen_t len = sizeof(error);
+        if (FD_ISSET(s, &r_set) || FD_ISSET(s, &w_set)) {
+            if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
+                close(s);
+                break;
+            }
+        } else {
+            close(s);
+            break;
+        }
+
+        if (error) {  // check if we had a socket error
+            // TODO: Update the timeout.
+            errno = error;
+            close(s);
+            continue;
+        }
+
+        result = toggle_O_NONBLOCK(s);
+    }
 
     freeaddrinfo(addrs);
-
-    // The Mac doesn't have SOCK_NONBLOCK.
-    int s = socket(family, type, protocol);
-    if (s == -1 || toggle_O_NONBLOCK(s) == -1) return -1;
-
-    int rc = connect(s, (const struct sockaddr*) &addr, addr_len);
-    if (rc == 0) {
-        return toggle_O_NONBLOCK(s);
-    } else if (rc == -1 && errno != EINPROGRESS) {
-        close(s);
-        return -1;
-    }
-
-    fd_set r_set;
-    FD_ZERO(&r_set);
-    FD_SET(s, &r_set);
-    fd_set w_set = r_set;
-
-    struct timeval ts;
-    ts.tv_sec = timeout;
-    ts.tv_usec = 0;
-    if ((rc = select(s + 1, &r_set, &w_set, NULL, (timeout != 0) ? &ts : NULL)) == -1) {
-        close(s);
-        return -1;
-    }
-    if (rc == 0) {   // we had a timeout
-        errno = ETIMEDOUT;
-        close(s);
-        return -1;
-    }
-
-    int error = 0;
-    socklen_t len = sizeof(error);
-    if (FD_ISSET(s, &r_set) || FD_ISSET(s, &w_set)) {
-        if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
-            close(s);
-            return -1;
-        }
-    } else {
-        close(s);
-        return -1;
-    }
-
-    if (error) {  // check if we had a socket error
-        errno = error;
-        close(s);
-        return -1;
-    }
-
-    return toggle_O_NONBLOCK(s);
+    return result;
 }
 
 int socket_network_client(const char* host, int port, int type) {
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index 3cb04cf..345f0d3 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -99,6 +99,9 @@
     if (processFile(newTagMap) != 0)
         goto fail;
 
+    if (fd >= 0)
+      close(fd);
+
     return newTagMap;
 
 fail:
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index fa95733..1ecf99c 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -508,7 +508,8 @@
     LogBufferElementCollection::iterator it;
 
     if (caller_uid != AID_ROOT) {
-        // Only here if clearAll condition (pruneRows == ULONG_MAX)
+        // Only here if clear all request from non system source, so chatty
+        // filter logistics is not required.
         it = mLastSet[id] ? mLast[id] : mLogElements.begin();
         while (it != mLogElements.end()) {
             LogBufferElement *element = *it;
@@ -534,7 +535,9 @@
             }
 
             it = erase(it);
-            pruneRows--;
+            if (--pruneRows == 0) {
+                break;
+            }
         }
         LogTimeEntry::unlock();
         return busy;
@@ -678,7 +681,7 @@
                         && ((!gc && (element->getPid() == worstPid))
                            || (mLastWorstPidOfSystem[id].find(element->getPid())
                                 == mLastWorstPidOfSystem[id].end()))) {
-                    mLastWorstPidOfSystem[id][key] = it;
+                    mLastWorstPidOfSystem[id][element->getPid()] = it;
                 }
                 if ((!gc && !worstPid && (key == worst))
                         || (mLastWorst[id].find(key) == mLastWorst[id].end())) {
diff --git a/sdcard/fuse.cpp b/sdcard/fuse.cpp
index 6a972ea..f549606 100644
--- a/sdcard/fuse.cpp
+++ b/sdcard/fuse.cpp
@@ -23,9 +23,6 @@
 /* FUSE_CANONICAL_PATH is not currently upstreamed */
 #define FUSE_CANONICAL_PATH 2016
 
-#define PROP_SDCARDFS_DEVICE "ro.sys.sdcardfs"
-#define PROP_SDCARDFS_USER "persist.sys.sdcardfs"
-
 #define FUSE_UNKNOWN_INO 0xffffffff
 
 /* Pseudo-error constant used to indicate that no fuse status is needed
diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp
index 3481ec3..70bbf26 100644
--- a/sdcard/sdcard.cpp
+++ b/sdcard/sdcard.cpp
@@ -28,11 +28,16 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/macros.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 
 #include <cutils/fs.h>
 #include <cutils/multiuser.h>
+#include <cutils/properties.h>
+
 #include <packagelistparser/packagelistparser.h>
 
 #include <libminijail.h>
@@ -73,6 +78,9 @@
 
 #include "fuse.h"
 
+#define PROP_SDCARDFS_DEVICE "ro.sys.sdcardfs"
+#define PROP_SDCARDFS_USER "persist.sys.sdcardfs"
+
 /* Supplementary groups to execute with. */
 static const gid_t kGroups[1] = { AID_PACKAGE_INFO };
 
@@ -307,6 +315,98 @@
     LOG(FATAL) << "terminated prematurely";
 }
 
+static bool sdcardfs_setup(const std::string& source_path, const std::string& dest_path, uid_t fsuid,
+                        gid_t fsgid, bool multi_user, userid_t userid, gid_t gid, mode_t mask) {
+    std::string opts = android::base::StringPrintf("fsuid=%d,fsgid=%d,%smask=%d,userid=%d,gid=%d",
+            fsuid, fsgid, multi_user?"multiuser,":"", mask, userid, gid);
+
+    if (mount(source_path.c_str(), dest_path.c_str(), "sdcardfs",
+                        MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) != 0) {
+        PLOG(ERROR) << "failed to mount sdcardfs filesystem";
+        return false;
+    }
+
+    return true;
+}
+
+static void run_sdcardfs(const std::string& source_path, const std::string& label, uid_t uid,
+        gid_t gid, userid_t userid, bool multi_user, bool full_write) {
+    std::string dest_path_default = "/mnt/runtime/default/" + label;
+    std::string dest_path_read = "/mnt/runtime/read/" + label;
+    std::string dest_path_write = "/mnt/runtime/write/" + label;
+
+    umask(0);
+    if (multi_user) {
+        // Multi-user storage is fully isolated per user, so "other"
+        // permissions are completely masked off.
+        if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
+                                                      AID_SDCARD_RW, 0006)
+                || !sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
+                                                      AID_EVERYBODY, 0027)
+                || !sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
+                                                      AID_EVERYBODY, full_write ? 0007 : 0027)) {
+            LOG(FATAL) << "failed to sdcardfs_setup";
+        }
+    } else {
+        // Physical storage is readable by all users on device, but
+        // the Android directories are masked off to a single user
+        // deep inside attr_from_stat().
+        if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
+                                                      AID_SDCARD_RW, 0006)
+                || !sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
+                                                      AID_EVERYBODY, full_write ? 0027 : 0022)
+                || !sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
+                                                      AID_EVERYBODY, full_write ? 0007 : 0022)) {
+            LOG(FATAL) << "failed to sdcardfs_setup";
+        }
+    }
+
+    // Will abort if priv-dropping fails.
+    drop_privs(uid, gid);
+
+    if (multi_user) {
+        std::string obb_path = source_path + "/obb";
+        fs_prepare_dir(obb_path.c_str(), 0775, uid, gid);
+    }
+
+    exit(0);
+}
+
+static bool supports_sdcardfs(void) {
+    std::string filesystems;
+    if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) {
+        PLOG(ERROR) << "Could not read /proc/filesystems";
+        return false;
+    }
+    for (const auto& fs : android::base::Split(filesystems, "\n")) {
+        if (fs.find("sdcardfs") != std::string::npos) return true;
+    }
+    return false;
+}
+
+static bool should_use_sdcardfs(void) {
+    char property[PROPERTY_VALUE_MAX];
+
+    // Allow user to have a strong opinion about state
+    property_get(PROP_SDCARDFS_USER, property, "");
+    if (!strcmp(property, "force_on")) {
+        LOG(WARNING) << "User explicitly enabled sdcardfs";
+        return supports_sdcardfs();
+    } else if (!strcmp(property, "force_off")) {
+        LOG(WARNING) << "User explicitly disabled sdcardfs";
+        return false;
+    }
+
+    // Fall back to device opinion about state
+    if (property_get_bool(PROP_SDCARDFS_DEVICE, false)) {
+        LOG(WARNING) << "Device explicitly enabled sdcardfs";
+        return supports_sdcardfs();
+    } else {
+        LOG(WARNING) << "Device explicitly disabled sdcardfs";
+        return false;
+    }
+}
+
 static int usage() {
     LOG(ERROR) << "usage: sdcard [OPTIONS] <source_path> <label>"
                << "    -u: specify UID to run as"
@@ -389,6 +489,10 @@
         sleep(1);
     }
 
-    run(source_path, label, uid, gid, userid, multi_user, full_write);
+    if (should_use_sdcardfs()) {
+        run_sdcardfs(source_path, label, uid, gid, userid, multi_user, full_write);
+    } else {
+        run(source_path, label, uid, gid, userid, multi_user, full_write);
+    }
     return 1;
 }