"track-app" service showing debuggable/profileable apps

Add a "track-app" service in adbd. For every debuggable or
profileable-from-shell process, ART sends related info to
adbd and adbd surfaces the info through the "track-app"
service.

The output format of "track-app" is a line summarizing
the number of reported processes, followed by a protobuf
message in human readable form. For example,

Process count: 2
process {
  pid: 3307
  profileable: true
  architecture: "arm64"
}
process {
  pid: 3341
  debuggable: true
  profileable: true
  architecture: "arm64"
}

Bug: 149050485
Test: manually unplugged/replugged, "adb track-app",
      "adb track-jdwp"
Change-Id: Id1f1a920e1afc148c7e4d2add790baab796178e1
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 081bac4..1186060 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -50,6 +50,8 @@
 #include <unistd.h>
 #endif
 
+#include <google/protobuf/text_format.h>
+
 #include "adb.h"
 #include "adb_auth.h"
 #include "adb_client.h"
@@ -57,6 +59,7 @@
 #include "adb_io.h"
 #include "adb_unique_fd.h"
 #include "adb_utils.h"
+#include "app_processes.pb.h"
 #include "bugreport.h"
 #include "client/file_sync_client.h"
 #include "commandline.h"
@@ -1354,17 +1357,49 @@
     }
 }
 
-static int adb_connect_command(const std::string& command, TransportId* transport = nullptr) {
+static int adb_connect_command(const std::string& command, TransportId* transport,
+                               StandardStreamsCallbackInterface* callback) {
     std::string error;
     unique_fd fd(adb_connect(transport, command, &error));
     if (fd < 0) {
         fprintf(stderr, "error: %s\n", error.c_str());
         return 1;
     }
-    read_and_dump(fd);
+    read_and_dump(fd, false, callback);
     return 0;
 }
 
+static int adb_connect_command(const std::string& command, TransportId* transport = nullptr) {
+    return adb_connect_command(command, transport, &DEFAULT_STANDARD_STREAMS_CALLBACK);
+}
+
+// A class that prints out human readable form of the protobuf message for "track-app" service
+// (received in binary format).
+class TrackAppStreamsCallback : public DefaultStandardStreamsCallback {
+  public:
+    TrackAppStreamsCallback() : DefaultStandardStreamsCallback(nullptr, nullptr) {}
+
+    // Assume the buffer contains at least 4 bytes of valid data.
+    void OnStdout(const char* buffer, int length) override {
+        if (length < 4) return;  // Unexpected length received. Do nothing.
+
+        adb::proto::AppProcesses binary_proto;
+        // The first 4 bytes are the length of remaining content in hexadecimal format.
+        binary_proto.ParseFromString(std::string(buffer + 4, length - 4));
+        char summary[24];  // The following string includes digits and 16 fixed characters.
+        int written = snprintf(summary, sizeof(summary), "Process count: %d\n",
+                               binary_proto.process_size());
+        OnStream(nullptr, stdout, summary, written);
+
+        std::string string_proto;
+        google::protobuf::TextFormat::PrintToString(binary_proto, &string_proto);
+        OnStream(nullptr, stdout, string_proto.data(), string_proto.length());
+    }
+
+  private:
+    DISALLOW_COPY_AND_ASSIGN(TrackAppStreamsCallback);
+};
+
 static int adb_connect_command_bidirectional(const std::string& command) {
     std::string error;
     unique_fd fd(adb_connect(command, &error));
@@ -1925,6 +1960,18 @@
         return adb_connect_command("jdwp");
     } else if (!strcmp(argv[0], "track-jdwp")) {
         return adb_connect_command("track-jdwp");
+    } else if (!strcmp(argv[0], "track-app")) {
+        FeatureSet features;
+        std::string error;
+        if (!adb_get_feature_set(&features, &error)) {
+            fprintf(stderr, "error: %s\n", error.c_str());
+            return 1;
+        }
+        if (!CanUseFeature(features, kFeatureTrackApp)) {
+            error_exit("track-app is not supported by the device");
+        }
+        TrackAppStreamsCallback callback;
+        return adb_connect_command("track-app", nullptr, &callback);
     } else if (!strcmp(argv[0], "track-devices")) {
         if (argc > 2 || (argc == 2 && strcmp(argv[1], "-l"))) {
             error_exit("usage: adb track-devices [-l]");