Merge "Convert to Android.bp"
diff --git a/adb/Android.mk b/adb/Android.mk
index 3512323..1aa3dc1 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -52,6 +52,7 @@
     adb_utils.cpp \
     fdevent.cpp \
     sockets.cpp \
+    socket_spec.cpp \
     transport.cpp \
     transport_local.cpp \
     transport_usb.cpp \
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index 0299be3..18b1492 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -23,12 +23,10 @@
 #include <android-base/strings.h>
 #include <cutils/sockets.h>
 
+#include "socket_spec.h"
 #include "sysdeps.h"
 #include "transport.h"
 
-// Not static because it is used in commandline.c.
-int gListenAll = 0;
-
 // A listener is an entity which binds to a local port and, upon receiving a connection on that
 // port, creates an asocket to connect the new local connection to a specific remote service.
 //
@@ -120,48 +118,6 @@
     }
 }
 
-int local_name_to_fd(alistener* listener, int* resolved_tcp_port, std::string* error) {
-    if (android::base::StartsWith(listener->local_name, "tcp:")) {
-        int requested_port = atoi(&listener->local_name[4]);
-        int sock = -1;
-        if (gListenAll > 0) {
-            sock = network_inaddr_any_server(requested_port, SOCK_STREAM, error);
-        } else {
-            sock = network_loopback_server(requested_port, SOCK_STREAM, error);
-        }
-
-        // If the caller requested port 0, update the listener name with the resolved port.
-        if (sock >= 0 && requested_port == 0) {
-            int local_port = adb_socket_get_local_port(sock);
-            if (local_port > 0) {
-                listener->local_name = android::base::StringPrintf("tcp:%d", local_port);
-                if (resolved_tcp_port != nullptr) {
-                    *resolved_tcp_port = local_port;
-                }
-            }
-        }
-
-        return sock;
-    }
-#if !defined(_WIN32)  // No Unix-domain sockets on Windows.
-    // It's nonsensical to support the "reserved" space on the adb host side.
-    if (android::base::StartsWith(listener->local_name, "local:")) {
-        return network_local_server(&listener->local_name[6], ANDROID_SOCKET_NAMESPACE_ABSTRACT,
-                                    SOCK_STREAM, error);
-    } else if (android::base::StartsWith(listener->local_name, "localabstract:")) {
-        return network_local_server(&listener->local_name[14], ANDROID_SOCKET_NAMESPACE_ABSTRACT,
-                                    SOCK_STREAM, error);
-    } else if (android::base::StartsWith(listener->local_name, "localfilesystem:")) {
-        return network_local_server(&listener->local_name[16], ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
-                                    SOCK_STREAM, error);
-    }
-
-#endif
-    *error = android::base::StringPrintf("unknown local portname '%s'",
-                                         listener->local_name.c_str());
-    return -1;
-}
-
 // Write the list of current listeners (network redirections) into a string.
 std::string format_listeners() {
     std::string result;
@@ -230,11 +186,20 @@
 
     std::unique_ptr<alistener> listener(new alistener(local_name, connect_to));
 
-    listener->fd = local_name_to_fd(listener.get(), resolved_tcp_port, error);
+    int resolved = 0;
+    listener->fd = socket_spec_listen(listener->local_name, error, &resolved);
     if (listener->fd < 0) {
         return INSTALL_STATUS_CANNOT_BIND;
     }
 
+    // If the caller requested port 0, update the listener name with the resolved port.
+    if (resolved != 0) {
+        listener->local_name = android::base::StringPrintf("tcp:%d", resolved);
+        if (resolved_tcp_port) {
+            *resolved_tcp_port = resolved;
+        }
+    }
+
     close_on_exec(listener->fd);
     if (listener->connect_to == "*smartsocket*") {
         fdevent_install(&listener->fde, listener->fd, ss_listener_event_func, listener.get());
diff --git a/adb/services.cpp b/adb/services.cpp
index 3b212e9..2207a3e 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -49,6 +49,7 @@
 #include "remount_service.h"
 #include "services.h"
 #include "shell_service.h"
+#include "socket_spec.h"
 #include "sysdeps.h"
 #include "transport.h"
 
@@ -278,36 +279,12 @@
 int service_to_fd(const char* name, const atransport* transport) {
     int ret = -1;
 
-    if(!strncmp(name, "tcp:", 4)) {
-        int port = atoi(name + 4);
-        name = strchr(name + 4, ':');
-        if(name == 0) {
-            std::string error;
-            ret = network_loopback_client(port, SOCK_STREAM, &error);
-            if (ret >= 0)
-                disable_tcp_nagle(ret);
-        } else {
-#if ADB_HOST
-            std::string error;
-            ret = network_connect(name + 1, port, SOCK_STREAM, 0, &error);
-#else
-            return -1;
-#endif
+    if (is_socket_spec(name)) {
+        std::string error;
+        ret = socket_spec_connect(name, &error);
+        if (ret < 0) {
+            LOG(ERROR) << "failed to connect to socket '" << name << "': " << error;
         }
-#if !defined(_WIN32)   /* winsock doesn't implement unix domain sockets */
-    } else if(!strncmp(name, "local:", 6)) {
-        ret = socket_local_client(name + 6,
-                ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
-    } else if(!strncmp(name, "localreserved:", 14)) {
-        ret = socket_local_client(name + 14,
-                ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
-    } else if(!strncmp(name, "localabstract:", 14)) {
-        ret = socket_local_client(name + 14,
-                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
-    } else if(!strncmp(name, "localfilesystem:", 16)) {
-        ret = socket_local_client(name + 16,
-                ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
-#endif
 #if !ADB_HOST
     } else if(!strncmp("dev:", name, 4)) {
         ret = unix_open(name + 4, O_RDWR | O_CLOEXEC);
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
new file mode 100644
index 0000000..f8bbbb3
--- /dev/null
+++ b/adb/socket_spec.cpp
@@ -0,0 +1,220 @@
+/*
+ * 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.
+ */
+
+#include "socket_spec.h"
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <cutils/sockets.h>
+
+#include "adb.h"
+#include "sysdeps.h"
+
+using android::base::StartsWith;
+using android::base::StringPrintf;
+
+#if defined(__linux__)
+#define ADB_LINUX 1
+#else
+#define ADB_LINUX 0
+#endif
+
+#if defined(_WIN32)
+#define ADB_WINDOWS 1
+#else
+#define ADB_WINDOWS 0
+#endif
+
+// Not static because it is used in commandline.c.
+int gListenAll = 0;
+
+struct LocalSocketType {
+    int socket_namespace;
+    bool available;
+};
+
+static auto& kLocalSocketTypes = *new std::unordered_map<std::string, LocalSocketType>({
+#if ADB_HOST
+    { "local", { ANDROID_SOCKET_NAMESPACE_FILESYSTEM, !ADB_WINDOWS } },
+#else
+    { "local", { ANDROID_SOCKET_NAMESPACE_RESERVED, !ADB_WINDOWS } },
+#endif
+
+    { "localreserved", { ANDROID_SOCKET_NAMESPACE_RESERVED, !ADB_HOST } },
+    { "localabstract", { ANDROID_SOCKET_NAMESPACE_ABSTRACT, ADB_LINUX } },
+    { "localfilesystem", { ANDROID_SOCKET_NAMESPACE_FILESYSTEM, !ADB_WINDOWS } },
+});
+
+static bool parse_tcp_spec(const std::string& spec, std::string* hostname, int* port,
+                           std::string* error) {
+    std::vector<std::string> fragments = android::base::Split(spec, ":");
+    if (fragments.size() == 1 || fragments.size() > 3) {
+        *error = StringPrintf("invalid tcp specification: '%s'", spec.c_str());
+        return false;
+    }
+
+    if (fragments[0] != "tcp") {
+        *error = StringPrintf("specification is not tcp: '%s'", spec.c_str());
+        return false;
+    }
+
+    // strtol accepts leading whitespace.
+    const std::string& port_str = fragments.back();
+    if (port_str.empty() || port_str[0] < '0' || port_str[0] > '9') {
+        *error = StringPrintf("invalid port '%s'", port_str.c_str());
+        return false;
+    }
+
+    char* parsed_end;
+    long parsed_port = strtol(port_str.c_str(), &parsed_end, 10);
+    if (*parsed_end != '\0') {
+        *error = StringPrintf("trailing chars in port: '%s'", port_str.c_str());
+        return false;
+    }
+    if (parsed_port > 65535) {
+        *error = StringPrintf("invalid port %ld", parsed_port);
+        return false;
+    }
+
+    // tcp:123 is valid, tcp::123 isn't.
+    if (fragments.size() == 2) {
+        // Empty hostname.
+        if (hostname) {
+            *hostname = "";
+        }
+    } else {
+        if (fragments[1].empty()) {
+            *error = StringPrintf("empty host in '%s'", spec.c_str());
+            return false;
+        }
+        if (hostname) {
+            *hostname = fragments[1];
+        }
+    }
+
+    if (port) {
+        *port = parsed_port;
+    }
+
+    return true;
+}
+
+static bool tcp_host_is_local(const std::string& hostname) {
+    // FIXME
+    return hostname.empty() || hostname == "localhost";
+}
+
+bool is_socket_spec(const std::string& spec) {
+    for (const auto& it : kLocalSocketTypes) {
+        std::string prefix = it.first + ":";
+        if (StartsWith(spec, prefix.c_str())) {
+            return true;
+        }
+    }
+    return StartsWith(spec, "tcp:");
+}
+
+int socket_spec_connect(const std::string& spec, std::string* error) {
+    if (StartsWith(spec, "tcp:")) {
+        std::string hostname;
+        int port;
+        if (!parse_tcp_spec(spec, &hostname, &port, error)) {
+            return -1;
+        }
+
+        int result;
+        if (tcp_host_is_local(hostname)) {
+            result = network_loopback_client(port, SOCK_STREAM, error);
+        } else {
+#if ADB_HOST
+            result = network_connect(hostname, port, SOCK_STREAM, 0, error);
+#else
+            // Disallow arbitrary connections in adbd.
+            *error = "adbd does not support arbitrary tcp connections";
+            return -1;
+#endif
+        }
+
+        if (result >= 0) {
+            disable_tcp_nagle(result);
+        }
+        return result;
+    }
+
+    for (const auto& it : kLocalSocketTypes) {
+        std::string prefix = it.first + ":";
+        if (StartsWith(spec, prefix.c_str())) {
+            if (!it.second.available) {
+                *error = StringPrintf("socket type %s is unavailable on this platform",
+                                      it.first.c_str());
+                return -1;
+            }
+
+            return network_local_client(&spec[prefix.length()], it.second.socket_namespace,
+                                        SOCK_STREAM, error);
+        }
+    }
+
+    *error = StringPrintf("unknown socket specification '%s'", spec.c_str());
+    return -1;
+}
+
+int socket_spec_listen(const std::string& spec, std::string* error, int* resolved_tcp_port) {
+    if (StartsWith(spec, "tcp:")) {
+        std::string hostname;
+        int port;
+        if (!parse_tcp_spec(spec, &hostname, &port, error)) {
+            return -1;
+        }
+
+        int result;
+        if (hostname.empty() && gListenAll) {
+            result = network_inaddr_any_server(port, SOCK_STREAM, error);
+        } else if (tcp_host_is_local(hostname)) {
+            result = network_loopback_server(port, SOCK_STREAM, error);
+        } else {
+            // TODO: Implement me.
+            *error = "listening on specified hostname currently unsupported";
+            return -1;
+        }
+
+        if (result >= 0 && port == 0 && resolved_tcp_port) {
+            *resolved_tcp_port = adb_socket_get_local_port(result);
+        }
+        return result;
+    }
+
+    for (const auto& it : kLocalSocketTypes) {
+        std::string prefix = it.first + ":";
+        if (StartsWith(spec, prefix.c_str())) {
+            if (!it.second.available) {
+                *error = StringPrintf("attempted to listen on unavailable socket type: '%s'",
+                                      spec.c_str());
+                return -1;
+            }
+
+            return network_local_server(&spec[prefix.length()], it.second.socket_namespace,
+                                        SOCK_STREAM, error);
+        }
+    }
+
+    *error = StringPrintf("unknown socket specification '%s'", spec.c_str());
+    return -1;
+}
diff --git a/adb/socket_spec.h b/adb/socket_spec.h
new file mode 100644
index 0000000..69efb07
--- /dev/null
+++ b/adb/socket_spec.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 <string>
+
+// Returns true if the argument starts with a plausible socket prefix.
+bool is_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,
+                       int* resolved_tcp_port = nullptr);
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 322f992..8d99722 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -277,6 +277,15 @@
 int network_loopback_client(int port, int type, std::string* error);
 int network_loopback_server(int port, int type, std::string* error);
 int network_inaddr_any_server(int port, int type, std::string* error);
+
+inline int network_local_client(const char* name, int namespace_id, int type, std::string* error) {
+    abort();
+}
+
+inline int network_local_server(const char* name, int namespace_id, int type, std::string* error) {
+    abort();
+}
+
 int network_connect(const std::string& host, int port, int type, int timeout,
                     std::string* error);
 
@@ -638,10 +647,12 @@
   return _fd_set_error_str(socket_inaddr_any_server(port, type), error);
 }
 
-inline int network_local_server(const char *name, int namespace_id, int type,
-                                std::string* error) {
-  return _fd_set_error_str(socket_local_server(name, namespace_id, type),
-                           error);
+inline int network_local_client(const char* name, int namespace_id, int type, std::string* error) {
+    return _fd_set_error_str(socket_local_client(name, namespace_id, type), error);
+}
+
+inline int network_local_server(const char* name, int namespace_id, int type, std::string* error) {
+    return _fd_set_error_str(socket_local_server(name, namespace_id, type), error);
 }
 
 inline int network_connect(const std::string& host, int port, int type,
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index 299ec35..ee16d02 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -60,9 +60,18 @@
 // 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
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 3ddd2b0..8506765 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -136,8 +136,13 @@
 #if defined(SEGV_BNDERR)
         case SEGV_BNDERR: return "SEGV_BNDERR";
 #endif
+#if defined(SEGV_PKUERR)
+        case SEGV_PKUERR: return "SEGV_PKUERR";
+#endif
       }
-#if defined(SEGV_BNDERR)
+#if defined(SEGV_PKUERR)
+      static_assert(NSIGSEGV == SEGV_PKUERR, "missing SEGV_* si_code");
+#elif defined(SEGV_BNDERR)
       static_assert(NSIGSEGV == SEGV_BNDERR, "missing SEGV_* si_code");
 #else
       static_assert(NSIGSEGV == SEGV_ACCERR, "missing SEGV_* si_code");
diff --git a/libsync/sync.c b/libsync/sync.c
index d73bb11..169dc36 100644
--- a/libsync/sync.c
+++ b/libsync/sync.c
@@ -21,13 +21,27 @@
 #include <stdint.h>
 #include <string.h>
 
-#include <linux/sync.h>
 #include <linux/sw_sync.h>
 
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <sync/sync.h>
+
+// The sync code is undergoing a major change. Add enough in to get
+// everything to compile wih the latest uapi headers.
+struct sync_merge_data {
+  int32_t fd2;
+  char name[32];
+  int32_t fence;
+};
+
+#define SYNC_IOC_MAGIC '>'
+#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32)
+#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data)
+#define SYNC_IOC_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2, struct sync_fence_info_data)
+
 int sync_wait(int fd, int timeout)
 {
     __s32 to = timeout;