Merge "Fix run-buildtools-binary.sh to work on my computer"
diff --git a/Android.bp b/Android.bp
index 429038f..4e32744 100644
--- a/Android.bp
+++ b/Android.bp
@@ -46,6 +46,7 @@
     "src/protozero/protozero_message.cc",
     "src/protozero/protozero_message_handle.cc",
     "src/protozero/scattered_stream_writer.cc",
+    "src/traced/perfetto_cmd/perfetto_cmd.cc",
     "src/traced/probes/probes.cc",
     "src/traced/service/service.cc",
     "src/tracing/core/chunked_protobuf_input_stream.cc",
@@ -63,6 +64,7 @@
     "libandroid",
     "liblog",
     "libprotobuf-cpp-lite",
+    "libutils",
   ],
   static_libs: [
     "libgtest_prod",
@@ -80,6 +82,26 @@
   defaults: [
     "perfetto_defaults",
   ],
+  cflags: [
+    "-DPERFETTO_BUILD_WITH_ANDROID",
+  ],
+}
+
+// GN target: //:perfetto
+cc_binary {
+  name: "perfetto",
+  srcs: [
+    "src/traced/perfetto_cmd/main.cc",
+  ],
+  shared_libs: [
+    "libandroid",
+    "liblog",
+    "libtraced_shared",
+    "libutils",
+  ],
+  defaults: [
+    "perfetto_defaults",
+  ],
 }
 
 cc_defaults {
@@ -876,6 +898,7 @@
     "libandroid",
     "liblog",
     "libtraced_shared",
+    "libutils",
   ],
   defaults: [
     "perfetto_defaults",
@@ -892,6 +915,7 @@
     "libandroid",
     "liblog",
     "libtraced_shared",
+    "libutils",
   ],
   defaults: [
     "perfetto_defaults",
diff --git a/BUILD.gn b/BUILD.gn
index 441d438..1996c66 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -17,7 +17,10 @@
 group("all") {
   testonly = true  # allow to build also test targets
   deps = [
+    ":perfetto",
     ":perfetto_tests",
+    ":traced",
+    ":traced_probes",
     "src/ipc/protoc_plugin:ipc_plugin($host_toolchain)",
     "src/protozero/protoc_plugin($host_toolchain)",
     "src/tracing:consumer_cmd",
@@ -59,11 +62,19 @@
   shared_library("libtraced_shared") {
     deps = [
       "gn:default_deps",
+      "src/traced/perfetto_cmd",
       "src/traced/probes",
       "src/traced/service",
     ]
+    if (build_with_android) {
+      cflags = [ "-DPERFETTO_BUILD_WITH_ANDROID" ]
+      libs = [ "utils" ]
+    }
   }
 
+  # The unprivileged trace daemon that listens for Producer and Consumer
+  # connections, handles the coordination of the tracing sessions and owns the
+  # log buffers.
   executable("traced") {
     deps = [
       ":libtraced_shared",
@@ -74,6 +85,8 @@
     ]
   }
 
+  # The unprivileged daemon that is allowed to access tracefs (for ftrace).
+  # Registers as a Producer on the traced daemon.
   executable("traced_probes") {
     deps = [
       ":libtraced_shared",
@@ -83,4 +96,16 @@
       "src/traced/probes/main.cc",
     ]
   }
+
+  # The command line client for Perfetto. Allows to configure / start / stop
+  # tracing, acting as a Consumer.
+  executable("perfetto") {
+    deps = [
+      ":libtraced_shared",
+      "gn:default_deps",
+    ]
+    sources = [
+      "src/traced/perfetto_cmd/main.cc",
+    ]
+  }
 }
diff --git a/build_overrides/build.gni b/build_overrides/build.gni
index b7a2bab..a89a764 100644
--- a/build_overrides/build.gni
+++ b/build_overrides/build.gni
@@ -12,8 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# When building perfetto in the android tree this variable becomes magically
+# When building perfetto in the Chromium tree this variable becomes magically
 # true by virtue of including //build_overrides by absolute path.
 # When false, instead, the build files can assume this is a Perfetto standalone
 # build.
 build_with_chromium = false
+
+declare_args() {
+  # The Android blueprint file generator overrides this to true.
+  build_with_android = false
+}
diff --git a/gn/BUILD.gn b/gn/BUILD.gn
index 32569d8..a1026b6 100644
--- a/gn/BUILD.gn
+++ b/gn/BUILD.gn
@@ -66,6 +66,8 @@
 }
 
 group("protobuf_full_deps") {
+  testonly = true
+
   if (!build_with_chromium) {
     public_deps = [
       "//buildtools:protobuf_full",
diff --git a/include/perfetto/traced/traced.h b/include/perfetto/traced/traced.h
index 0a6f6e9..a3dfaac 100644
--- a/include/perfetto/traced/traced.h
+++ b/include/perfetto/traced/traced.h
@@ -35,6 +35,7 @@
 
 int ServiceMain(int argc, char** argv);
 int ProbesMain(int argc, char** argv);
+int PerfettoCmdMain(int argc, char** argv);
 
 }  // namespace perfetto
 
diff --git a/src/traced/perfetto_cmd/BUILD.gn b/src/traced/perfetto_cmd/BUILD.gn
new file mode 100644
index 0000000..1f11254
--- /dev/null
+++ b/src/traced/perfetto_cmd/BUILD.gn
@@ -0,0 +1,28 @@
+# Copyright (C) 2018 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.
+
+source_set("perfetto_cmd") {
+  public_deps = [
+    "../../../include/perfetto/traced",
+  ]
+  deps = [
+    "../../../gn:default_deps",
+    "../../../protos:lite",
+    "../../base",
+    "../../tracing:ipc",
+  ]
+  sources = [
+    "perfetto_cmd.cc",
+  ]
+}
diff --git a/src/traced/perfetto_cmd/main.cc b/src/traced/perfetto_cmd/main.cc
new file mode 100644
index 0000000..dc71930
--- /dev/null
+++ b/src/traced/perfetto_cmd/main.cc
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2018 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 <stdio.h>
+#include "perfetto/traced/traced.h"
+
+int main(int argc, char** argv) {
+  return perfetto::PerfettoCmdMain(argc, argv);
+}
diff --git a/src/traced/perfetto_cmd/perfetto_cmd.cc b/src/traced/perfetto_cmd/perfetto_cmd.cc
new file mode 100644
index 0000000..66ce34b
--- /dev/null
+++ b/src/traced/perfetto_cmd/perfetto_cmd.cc
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2018 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 <getopt.h>
+
+#include <fstream>
+#include <iostream>
+#include <iterator>
+#include <string>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/base/scoped_file.h"
+#include "perfetto/base/unix_task_runner.h"
+#include "perfetto/base/utils.h"
+#include "perfetto/traced/traced.h"
+#include "perfetto/tracing/core/consumer.h"
+#include "perfetto/tracing/core/data_source_config.h"
+#include "perfetto/tracing/core/data_source_descriptor.h"
+#include "perfetto/tracing/core/trace_config.h"
+#include "perfetto/tracing/core/trace_packet.h"
+#include "perfetto/tracing/ipc/consumer_ipc_client.h"
+
+#include "protos/tracing_service/trace_config.pb.h"
+
+#if defined(PERFETTO_BUILD_WITH_ANDROID)
+#include "perfetto/base/android_task_runner.h"
+
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+#endif  // defined(PERFETTO_BUILD_WITH_ANDROID)
+
+// TODO(primiano): add the ability to pass the file descriptor directly to the
+// traced service instead of receiving a copy of the chunks and writing them
+// from this process.
+namespace perfetto {
+
+#if defined(PERFETTO_BUILD_WITH_ANDROID)
+using PlatformTaskRunner = base::AndroidTaskRunner;
+#else
+using PlatformTaskRunner = base::UnixTaskRunner;
+#endif
+
+class PerfettoCmd : public Consumer {
+ public:
+  int Main(int argc, char** argv);
+  int PrintUsage(const char* argv0);
+  void OnStopTraceTimer();
+
+  // perfetto::Consumer implementation.
+  void OnConnect() override;
+  void OnDisconnect() override;
+  void OnTraceData(std::vector<TracePacket>, bool has_more) override;
+
+ private:
+  PlatformTaskRunner task_runner_;
+  std::unique_ptr<perfetto::Service::ConsumerEndpoint> consumer_endpoint_;
+  std::unique_ptr<TraceConfig> trace_config_;
+  std::ofstream trace_out_stream_;
+  std::string trace_out_path_;
+  bool did_receive_full_trace_ = false;
+};
+
+int PerfettoCmd::PrintUsage(const char* argv0) {
+  fprintf(stderr, R"(Usage: %s
+  --config  -c : /path/to/trace/config/file or - for stdin
+  --out     -o : /path/to/out/trace/file
+  --help
+)", argv0);
+  return 1;
+}
+
+int PerfettoCmd::Main(int argc, char** argv) {
+  static const struct option long_options[] = {
+      // |option_index| relies on the order of options, don't reshuffle them.
+      {"help", required_argument, 0, 'h'},
+      {"config", required_argument, 0, 'c'},
+      {"out", required_argument, 0, 'o'},
+      {0, 0, 0, 0}};
+
+  int option_index = 0;
+  std::string trace_config_raw;
+  for (;;) {
+    int option = getopt_long(argc, argv, "c:o:", long_options, &option_index);
+
+    if (option == -1)
+      break;  // EOF.
+
+    if (option == 'c') {
+      if (strcmp(optarg, "-") == 0) {
+        std::istreambuf_iterator<char> begin(std::cin), end;
+        trace_config_raw.assign(begin, end);
+      } else if (strcmp(optarg, ":test") == 0) {
+        // TODO(primiano): temporary for testing only.
+        perfetto::protos::TraceConfig test_config;
+        test_config.add_buffers()->set_size_kb(4096 * 10);
+        test_config.set_duration_ms(3000);
+        auto* ds_config = test_config.add_data_sources()->mutable_config();
+        ds_config->set_name("perfetto.test");
+        ds_config->set_target_buffer(0);
+        ds_config->set_trace_category_filters("foo,bar");
+        test_config.SerializeToString(&trace_config_raw);
+      } else {
+        std::ifstream file_stream;
+        file_stream.open(optarg, std::ios_base::in | std::ios_base::binary);
+        if (!file_stream.is_open()) {
+          PERFETTO_ELOG("Could not open %s", optarg);
+          return 1;
+        }
+        std::istreambuf_iterator<char> begin(file_stream), end;
+        trace_config_raw.assign(begin, end);
+      }
+      continue;
+    }
+
+    if (option == 'o') {
+      trace_out_path_ = optarg;
+      trace_out_stream_.open(trace_out_path_ + ".tmp",
+                             std::ios_base::out | std::ios_base::binary);
+      if (!trace_out_stream_.is_open()) {
+        PERFETTO_ELOG("Could not open %s", trace_out_path_.c_str());
+        return 1;
+      }
+      continue;
+    }
+
+    return PrintUsage(argv[0]);
+  }
+
+  if (trace_config_raw.empty())
+    return PrintUsage(argv[0]);
+  perfetto::protos::TraceConfig trace_config_proto;
+  PERFETTO_DLOG("Parsing TraceConfig, %zu bytes", trace_config_raw.size());
+  bool parsed = trace_config_proto.ParseFromString(trace_config_raw);
+  if (!parsed) {
+    PERFETTO_ELOG("Could not parse TraceConfig proto from stdin");
+    return 1;
+  }
+  trace_config_.reset(new TraceConfig());
+  trace_config_->FromProto(trace_config_proto);
+  trace_config_raw.clear();
+
+  consumer_endpoint_ = ConsumerIPCClient::Connect(PERFETTO_CONSUMER_SOCK_NAME,
+                                                  this, &task_runner_);
+
+#if defined(PERFETTO_BUILD_WITH_ANDROID)
+  android::sp<android::Looper> looper(android::Looper::prepare(0 /* opts */));
+  while (true) {
+    looper->pollAll(-1 /* timeoutMillis */);
+  }
+#else  // defined(PERFETTO_BUILD_WITH_ANDROID)
+  task_runner_.Run();
+#endif // defined(PERFETTO_BUILD_WITH_ANDROID)
+  return did_receive_full_trace_ ? 0 : 1;
+}  // namespace perfetto
+
+void PerfettoCmd::OnConnect() {
+  PERFETTO_LOG(
+      "Connected to the Perfetto traced service, starting tracing for %d ms",
+      trace_config_->duration_ms());
+  PERFETTO_DCHECK(trace_config_);
+  consumer_endpoint_->EnableTracing(*trace_config_);
+  task_runner_.PostDelayedTask(std::bind(&PerfettoCmd::OnStopTraceTimer, this),
+                               trace_config_->duration_ms());
+}
+
+void PerfettoCmd::OnDisconnect() {
+  PERFETTO_LOG("Disconnected from the Perfetto traced service");
+  task_runner_.Quit();
+}
+
+void PerfettoCmd::OnStopTraceTimer() {
+  PERFETTO_LOG("Timer expired, disabling tracing and collecting results");
+  consumer_endpoint_->DisableTracing();
+  consumer_endpoint_->ReadBuffers();
+}
+
+void PerfettoCmd::OnTraceData(std::vector<TracePacket> packets, bool has_more) {
+  PERFETTO_LOG("Received packet %d", has_more);
+  for (TracePacket& packet : packets) {
+    for (const Chunk& chunk : packet) {
+      trace_out_stream_.write(reinterpret_cast<const char*>(chunk.start),
+                              chunk.size);
+    }
+  }
+  if (has_more)
+    return;
+
+  // Reached end of trace.
+  long bytes_written = trace_out_stream_.tellp();
+  trace_out_stream_.close();
+  std::string tmp_path = trace_out_path_ + ".tmp";
+  PERFETTO_CHECK(rename(tmp_path.c_str(), trace_out_path_.c_str()) == 0);
+  did_receive_full_trace_ = true;
+  PERFETTO_ILOG("Wrote %ld bytes into %s", bytes_written,
+                trace_out_path_.c_str());
+  consumer_endpoint_->FreeBuffers();
+  task_runner_.Quit();
+}
+
+int __attribute__((visibility("default")))
+PerfettoCmdMain(int argc, char** argv) {
+  perfetto::PerfettoCmd consumer_cmd;
+  return consumer_cmd.Main(argc, argv);
+}
+
+}  // namespace perfetto
diff --git a/tools/gen_android_bp b/tools/gen_android_bp
index 3c7b96b..79416d4 100755
--- a/tools/gen_android_bp
+++ b/tools/gen_android_bp
@@ -26,6 +26,7 @@
 # libraries are also mapped to their Android equivalents -- see |builtin_deps|.
 
 import argparse
+import errno
 import json
 import os
 import re
@@ -35,10 +36,12 @@
 
 # Default targets to translate to the blueprint file.
 default_targets = [
+    '//:libtraced_shared',
+    '//:perfetto',
     '//:perfetto_tests',
+    '//:perfetto',
     '//:traced',
     '//:traced_probes',
-    '//:libtraced_shared',
     '//src/tracing:consumer_cmd',
 ]
 
@@ -47,7 +50,7 @@
 target_initrc = {}  # TODO(primiano): populate in upcoming CLs.
 
 # Arguments for the GN output directory.
-gn_args = 'target_os="android" target_cpu="arm" is_debug=false'
+gn_args = 'target_os="android" target_cpu="arm" is_debug=false build_with_android=true'
 
 # All module names are prefixed with this string to avoid collisions.
 module_prefix = 'perfetto_'
@@ -56,6 +59,7 @@
 library_whitelist = [
     'android',
     'log',
+    'utils',
 ]
 
 # Name of the module which settings such as compiler flags for all other
@@ -65,6 +69,9 @@
 # Location of the project in the Android source tree.
 tree_path = 'external/perfetto'
 
+# Compiler flags which are passed through to the blueprint.
+cflag_whitelist = r'^-DPERFETTO.*$'
+
 
 def enable_gmock(module):
     module.static_libs.append('libgmock')
@@ -436,6 +443,9 @@
         # Don't try to inject library/source dependencies into genrules because
         # they are not compiled in the traditional sense.
         if module.type != 'genrule':
+            for flag in target.get('cflags', []):
+                if re.match(cflag_whitelist, flag):
+                  module.cflags.append(flag)
             module.defaults = [defaults_module]
             apply_module_dependency(blueprint, desc, module, target_name)
             for dep in resolve_dependencies(desc, target_name):