Only write to data-sources targeting the process.

Bug: 136210868

Test: art/tools/run-gtests.sh -j4
Failed test: /apex/com.android.art/bin/art/arm/instruction_set_features_test
Known issue, see http://b/139425971

Test: art/test/testrunner/testrunner.py --target --64
Concurrency: 7
4140/4305 (96%) tests passed.

Test: art/tools/run-libcore-tests.sh --mode=device --variant=X64
Outcomes: 13781. Passed: 13542, Failed: 0, Skipped: 140, Warnings: 99. Took 28m28s.

Test: art/tools/run-jdwp-tests.sh --mode=device --variant=X64
Outcomes: 401. All successful. Took 7m1s.

Change-Id: I31fb02141630118fc8a039af9d7827dca340a527
diff --git a/perfetto_hprof/perfetto_hprof.cc b/perfetto_hprof/perfetto_hprof.cc
index 078ac76..edff9da 100644
--- a/perfetto_hprof/perfetto_hprof.cc
+++ b/perfetto_hprof/perfetto_hprof.cc
@@ -32,9 +32,11 @@
 #include "gc/scoped_gc_critical_section.h"
 #include "mirror/object-refvisitor-inl.h"
 #include "nativehelper/scoped_local_ref.h"
+#include "perfetto/profiling/normalize.h"
 #include "perfetto/trace/interned_data/interned_data.pbzero.h"
 #include "perfetto/trace/profiling/heap_graph.pbzero.h"
 #include "perfetto/trace/profiling/profile_common.pbzero.h"
+#include "perfetto/config/profiling/java_hprof_config.pbzero.h"
 #include "perfetto/tracing.h"
 #include "runtime-inl.h"
 #include "runtime_callbacks.h"
@@ -104,13 +106,70 @@
   }
 }
 
+constexpr size_t kMaxCmdlineSize = 512;
+
 class JavaHprofDataSource : public perfetto::DataSource<JavaHprofDataSource> {
  public:
-  // TODO(fmayer): Change Client API and reject configs that do not target
-  // this process.
-  void OnSetup(const SetupArgs&) override {}
+  void OnSetup(const SetupArgs& args) override {
+    // This is on the heap as it triggers -Wframe-larger-than.
+    std::unique_ptr<perfetto::protos::pbzero::JavaHprofConfig::Decoder> cfg(
+        new perfetto::protos::pbzero::JavaHprofConfig::Decoder(
+          args.config->java_hprof_config_raw()));
+
+    uint64_t self_pid = static_cast<uint64_t>(getpid());
+    for (auto it = cfg->pid(); it; ++it) {
+      uint64_t pid = it->as_uint64();
+      if (pid == self_pid) {
+        enabled_ = true;
+        return;
+      }
+    }
+
+    if (cfg->has_process_cmdline()) {
+      int fd = open("/proc/self/cmdline", O_RDONLY | O_CLOEXEC);
+      if (fd == -1) {
+        PLOG(ERROR) << "failed to open /proc/self/cmdline";
+        return;
+      }
+      char cmdline[kMaxCmdlineSize];
+      ssize_t rd = read(fd, cmdline, sizeof(cmdline) - 1);
+      if (rd == -1) {
+        PLOG(ERROR) << "failed to read /proc/self/cmdline";
+      }
+      close(fd);
+      if (rd == -1) {
+        return;
+      }
+      cmdline[rd] = '\0';
+      char* cmdline_ptr = cmdline;
+      ssize_t sz = perfetto::profiling::NormalizeCmdLine(&cmdline_ptr, static_cast<size_t>(rd + 1));
+      if (sz == -1) {
+        PLOG(ERROR) << "failed to normalize cmdline";
+      }
+      for (auto it = cfg->process_cmdline(); it; ++it) {
+        std::string other = it->as_std_string();
+        // Append \0 to make this a C string.
+        other.resize(other.size() + 1);
+        char* other_ptr = &(other[0]);
+        ssize_t other_sz = perfetto::profiling::NormalizeCmdLine(&other_ptr, other.size());
+        if (other_sz == -1) {
+          PLOG(ERROR) << "failed to normalize other cmdline";
+          continue;
+        }
+        if (sz == other_sz && strncmp(cmdline_ptr, other_ptr, static_cast<size_t>(sz)) == 0) {
+          enabled_ = true;
+          return;
+        }
+      }
+    }
+  }
+
+  bool enabled() { return enabled_; }
 
   void OnStart(const StartArgs&) override {
+    if (!enabled()) {
+      return;
+    }
     art::MutexLock lk(art_thread(), GetStateMutex());
     if (g_state == State::kWaitForStart) {
       g_state = State::kStart;
@@ -131,6 +190,7 @@
   }
 
  private:
+  bool enabled_ = false;
   static art::Thread* self_;
 };
 
@@ -261,6 +321,13 @@
   JavaHprofDataSource::Trace(
       [parent_pid](JavaHprofDataSource::TraceContext ctx)
           NO_THREAD_SAFETY_ANALYSIS {
+            {
+              auto ds = ctx.GetDataSourceLocked();
+              if (!ds || !ds->enabled()) {
+                LOG(INFO) << "skipping irrelevant data source.";
+                return;
+              }
+            }
             LOG(INFO) << "dumping heap for " << parent_pid;
             Writer writer(parent_pid, &ctx);
             // Make sure that intern ID 0 (default proto value for a uint64_t) always maps to ""