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/adb/transport.cpp b/adb/transport.cpp
index db9236e..402546b 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -779,27 +779,37 @@
     return max_payload;
 }
 
-// Do not use any of [:;=,] in feature strings, they have special meaning
-// in the connection banner.
-// TODO(dpursell): add this in once we can pass features through to the client.
-const char kFeatureShell2[] = "shell_2";
+namespace {
 
-// The list of features supported by the current system. Will be sent to the
-// other side of the connection in the banner.
-static const FeatureSet gSupportedFeatures = {
-        kFeatureShell2,
-};
+constexpr char kFeatureStringDelimiter = ',';
+
+}  // namespace
 
 const FeatureSet& supported_features() {
-    return gSupportedFeatures;
+    // Local static allocation to avoid global non-POD variables.
+    static const FeatureSet* features = new FeatureSet{
+        kFeatureShell2
+    };
+
+    return *features;
+}
+
+std::string FeatureSetToString(const FeatureSet& features) {
+    return android::base::Join(features, kFeatureStringDelimiter);
+}
+
+FeatureSet StringToFeatureSet(const std::string& features_string) {
+    auto names = android::base::Split(features_string,
+                                      {kFeatureStringDelimiter});
+    return FeatureSet(names.begin(), names.end());
 }
 
 bool atransport::has_feature(const std::string& feature) const {
     return features_.count(feature) > 0;
 }
 
-void atransport::add_feature(const std::string& feature) {
-    features_.insert(feature);
+void atransport::SetFeatures(const std::string& features_string) {
+    features_ = StringToFeatureSet(features_string);
 }
 
 bool atransport::CanUseFeature(const std::string& feature) const {
@@ -855,9 +865,6 @@
         append_transport_info(result, "product:", t->product, false);
         append_transport_info(result, "model:", t->model, true);
         append_transport_info(result, "device:", t->device, false);
-        append_transport_info(result, "features:",
-                              android::base::Join(t->features(), ',').c_str(),
-                              false);
     }
     *result += '\n';
 }