Merge "adb: fix deadlock between transport_unref and usb_close." into oc-dr1-dev
am: 38eb25e157  -s ours

Change-Id: I029ddf455138b68118aa5eeb4178031c81f0a35f
diff --git a/adb_client.cpp b/adb_client.cpp
index f5d0f02..e533a00 100644
--- a/adb_client.cpp
+++ b/adb_client.cpp
@@ -125,7 +125,7 @@
 
 static int _adb_connect(const std::string& service, std::string* error) {
     D("_adb_connect: %s", service.c_str());
-    if (service.empty() || service.size() > MAX_PAYLOAD_V1) {
+    if (service.empty() || service.size() > MAX_PAYLOAD) {
         *error = android::base::StringPrintf("bad service name length (%zd)",
                                              service.size());
         return -1;
diff --git a/adb_io.cpp b/adb_io.cpp
index ca8729e..38e3116 100644
--- a/adb_io.cpp
+++ b/adb_io.cpp
@@ -31,7 +31,7 @@
 
 bool SendProtocolString(int fd, const std::string& s) {
     unsigned int length = s.size();
-    if (length > MAX_PAYLOAD_V1 - 4) {
+    if (length > MAX_PAYLOAD - 4) {
         errno = EMSGSIZE;
         return false;
     }
diff --git a/commandline.cpp b/commandline.cpp
index 68ae4af..c9f1ee9 100644
--- a/commandline.cpp
+++ b/commandline.cpp
@@ -599,6 +599,13 @@
     std::string service_string = ShellServiceString(use_shell_protocol,
                                                     type_arg, command);
 
+    // Old devices can't handle a service string that's longer than MAX_PAYLOAD_V1.
+    // Use |use_shell_protocol| to determine whether to allow a command longer than that.
+    if (service_string.size() > MAX_PAYLOAD_V1 && !use_shell_protocol) {
+        fprintf(stderr, "error: shell command too long\n");
+        return 1;
+    }
+
     // Make local stdin raw if the device allocates a PTY, which happens if:
     //   1. We are explicitly asking for a PTY shell, or
     //   2. We don't specify shell type and are starting an interactive session.
diff --git a/sockets.cpp b/sockets.cpp
index 14ad1ff..e0143c6 100644
--- a/sockets.cpp
+++ b/sockets.cpp
@@ -686,7 +686,7 @@
     }
 
     len = unhex(p->data, 4);
-    if ((len < 1) || (len > MAX_PAYLOAD_V1)) {
+    if ((len < 1) || (len > MAX_PAYLOAD)) {
         D("SS(%d): bad size (%d)", s->id, len);
         goto fail;
     }
diff --git a/test_device.py b/test_device.py
index 737d0c2..9e1a2ec 100644
--- a/test_device.py
+++ b/test_device.py
@@ -342,6 +342,13 @@
         out = self.device.shell(['echo', 'foo'])[0]
         self.assertEqual(out, 'foo' + self.device.linesep)
 
+    def test_shell_command_length(self):
+        # Devices that have shell_v2 should be able to handle long commands.
+        if self.device.has_shell_protocol():
+            rc, out, err = self.device.shell_nocheck(['echo', 'x' * 16384])
+            self.assertEqual(rc, 0)
+            self.assertTrue(out == ('x' * 16384 + '\n'))
+
     def test_shell_nocheck_failure(self):
         rc, out, _ = self.device.shell_nocheck(['false'])
         self.assertNotEqual(rc, 0)
diff --git a/transport_local.cpp b/transport_local.cpp
index 809ed89..9cd378c 100644
--- a/transport_local.cpp
+++ b/transport_local.cpp
@@ -388,6 +388,25 @@
     D("transport: qemu_socket_thread() exiting");
     return;
 }
+
+// If adbd is running inside the emulator, it will normally use QEMUD pipe (aka
+// goldfish) as the transport. This can either be explicitly set by the
+// service.adb.transport property, or be inferred from ro.kernel.qemu that is
+// set to "1" for ranchu/goldfish.
+static bool use_qemu_goldfish() {
+    // Legacy way to detect if adbd should use the goldfish pipe is to check for
+    // ro.kernel.qemu, keep that behaviour for backward compatibility.
+    if (android::base::GetBoolProperty("ro.kernel.qemu", false)) {
+        return true;
+    }
+    // If service.adb.transport is present and is set to "goldfish", use the
+    // QEMUD pipe.
+    if (android::base::GetProperty("service.adb.transport", "") == "goldfish") {
+        return true;
+    }
+    return false;
+}
+
 #endif  // !ADB_HOST
 
 void local_init(int port)
@@ -401,13 +420,7 @@
 #else
     // For the adbd daemon in the system image we need to distinguish
     // between the device, and the emulator.
-    if (android::base::GetBoolProperty("ro.kernel.qemu", false)) {
-        // Running inside the emulator: use QEMUD pipe as the transport.
-        func = qemu_socket_thread;
-    } else {
-        // Running inside the device: use TCP socket as the transport.
-        func = server_socket_thread;
-    }
+    func = use_qemu_goldfish() ? qemu_socket_thread : server_socket_thread;
     debug_name = "server";
 #endif // !ADB_HOST