adb: add -Tt options to `adb shell`.

Adds -T (no PTY) and -t (force PTY) options to `adb shell` to mimic
ssh options. Small cleanup to send an entire FeatureSet to the adb
client at once to avoid multiple round-trips when querying multiple
features.

Known issue: humans using `adb shell -T` to start a non-PTY interactive
session may experience problems since neither side will have PTY
features like echoing or newline translation. This is probably OK for
now as the -Tt options are primarily useful for scripting.

Bug: http://b/23825231
Change-Id: I4d0df300db0abd1f7410bab59dd4d5b991babda7
diff --git a/services.cpp b/services.cpp
index d128efc..d0494ec 100644
--- a/services.cpp
+++ b/services.cpp
@@ -194,7 +194,39 @@
     adb_close(fd);
 }
 
-#endif
+// Shell service string can look like:
+//   shell[args]:[command]
+// Currently the only supported args are -T (force raw) and -t (force PTY).
+static int ShellService(const std::string& args, const atransport* transport) {
+    size_t delimiter_index = args.find(':');
+    if (delimiter_index == std::string::npos) {
+        LOG(ERROR) << "No ':' found in shell service arguments: " << args;
+        return -1;
+    }
+    const std::string service_args = args.substr(0, delimiter_index);
+    const std::string command = args.substr(delimiter_index + 1);
+
+    SubprocessType type;
+    if (service_args.empty()) {
+        // Default: use PTY for interactive, raw for non-interactive.
+        type = (command.empty() ? SubprocessType::kPty : SubprocessType::kRaw);
+    } else if (service_args == "-T") {
+        type = SubprocessType::kRaw;
+    } else if (service_args == "-t") {
+        type = SubprocessType::kPty;
+    } else {
+        LOG(ERROR) << "Unsupported shell service arguments: " << args;
+        return -1;
+    }
+
+    SubprocessProtocol protocol =
+            (transport->CanUseFeature(kFeatureShell2) ? SubprocessProtocol::kShell
+                                                      : SubprocessProtocol::kNone);
+
+    return StartSubprocess(command.c_str(), type, protocol);
+}
+
+#endif  // !ADB_HOST
 
 static int create_service_thread(void (*func)(int, void *), void *cookie)
 {
@@ -265,14 +297,8 @@
         ret = create_service_thread(framebuffer_service, 0);
     } else if (!strncmp(name, "jdwp:", 5)) {
         ret = create_jdwp_connection_fd(atoi(name+5));
-    } else if(!strncmp(name, "shell:", 6)) {
-        const char* args = name + 6;
-        // Use raw for non-interactive, PTY for interactive.
-        SubprocessType type = (*args ? SubprocessType::kRaw : SubprocessType::kPty);
-        SubprocessProtocol protocol =
-                (transport->CanUseFeature(kFeatureShell2) ? SubprocessProtocol::kShell
-                                                          : SubprocessProtocol::kNone);
-        ret = StartSubprocess(args, type, protocol);
+    } else if(!strncmp(name, "shell", 5)) {
+        ret = ShellService(name + 5, transport);
     } else if(!strncmp(name, "exec:", 5)) {
         ret = StartSubprocess(name + 5, SubprocessType::kRaw,
                               SubprocessProtocol::kNone);