Update EXPORT_JSON to output stack samples in a matching format to the legacy viewer

R=ssid@google.com

Change-Id: I9efdad6b1a8a3d197898c63154787711bc8964ba
diff --git a/src/trace_processor/export_json.cc b/src/trace_processor/export_json.cc
index 15ad611..5d2d0a0 100644
--- a/src/trace_processor/export_json.cc
+++ b/src/trace_processor/export_json.cc
@@ -799,12 +799,22 @@
           static_cast<int32_t>(storage->GetProcess(*thread.upid).pid);
     }
 
-    // Use "I" instead of "i" phase for backwards-compat with old consumers.
-    event["ph"] = "I";
+    event["ph"] = "n";
     event["cat"] = "disabled_by_default-cpu_profiler";
     event["name"] = "StackCpuSampling";
     event["s"] = "t";
 
+    // Add a dummy thread timestamp to this event to match the format of instant
+    // events. Useful in the UI to view args of a selected group of samples.
+    event["tts"] = Json::Int64(1);
+
+    // "n"-phase events are nestable async events which get tied together with
+    // their id, so we need to give each one a unique ID as we only
+    // want the samples to show up on their own track in the trace-viewer but
+    // not nested together.
+    static size_t g_id_counter = 0;
+    event["id"] = PrintUint64(++g_id_counter);
+
     std::vector<std::string> callstack;
     const auto& callsites = storage->stack_profile_callsite_table();
     int64_t maybe_callsite_id = samples.callsite_ids()[i];
@@ -853,6 +863,12 @@
     }
 
     event["args"]["frames"] = merged_callstack;
+
+    // TODO(oysteine): Used for backwards compatibility with the memlog
+    // pipeline, should remove once we've switched to looking directly at the
+    // tid.
+    event["args"]["thread_id"] = thread.tid;
+
     writer->WriteCommonEvent(event);
   }
 
diff --git a/src/trace_processor/export_json_unittest.cc b/src/trace_processor/export_json_unittest.cc
index c5c949a..6b7ad59 100644
--- a/src/trace_processor/export_json_unittest.cc
+++ b/src/trace_processor/export_json_unittest.cc
@@ -1189,7 +1189,8 @@
 
   EXPECT_EQ(result["traceEvents"].size(), 1u);
   Json::Value event = result["traceEvents"][0];
-  EXPECT_EQ(event["ph"].asString(), "I");
+  EXPECT_EQ(event["ph"].asString(), "n");
+  EXPECT_EQ(event["id"].asString(), "0x1");
   EXPECT_EQ(event["ts"].asInt64(), kTimestamp / 1000);
   EXPECT_EQ(event["tid"].asUInt(), kThreadID);
   EXPECT_EQ(event["cat"].asString(), "disabled_by_default-cpu_profiler");