Add a new TrustedPacket for received triggers.

We create a packet with a timestamp matching the time a trigger was received.
In addition we include enough data to determine which trigger and who called
it. This allows us to emit whatever triggers we've received into the trace
and the UI will be able to annotate the trace based on these packets.

Bug: 128966650
Change-Id: Ib751f4f2547cc2c8f68161af7437de29395d342b
diff --git a/Android.bp b/Android.bp
index bfdf51a..a6492fb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1668,6 +1668,7 @@
   srcs: [
     "protos/perfetto/trace/clock_snapshot.proto",
     "protos/perfetto/trace/system_info.proto",
+    "protos/perfetto/trace/trigger.proto",
   ],
   tools: [
     "aprotoc",
@@ -1676,6 +1677,7 @@
   out: [
     "external/perfetto/protos/perfetto/trace/clock_snapshot.pb.cc",
     "external/perfetto/protos/perfetto/trace/system_info.pb.cc",
+    "external/perfetto/protos/perfetto/trace/trigger.pb.cc",
   ],
 }
 
@@ -1685,6 +1687,7 @@
   srcs: [
     "protos/perfetto/trace/clock_snapshot.proto",
     "protos/perfetto/trace/system_info.proto",
+    "protos/perfetto/trace/trigger.proto",
   ],
   tools: [
     "aprotoc",
@@ -1693,6 +1696,7 @@
   out: [
     "external/perfetto/protos/perfetto/trace/clock_snapshot.pb.h",
     "external/perfetto/protos/perfetto/trace/system_info.pb.h",
+    "external/perfetto/protos/perfetto/trace/trigger.pb.h",
   ],
   export_include_dirs: [
     "protos",
@@ -2170,6 +2174,7 @@
     "protos/perfetto/trace/test_event.proto",
     "protos/perfetto/trace/trace.proto",
     "protos/perfetto/trace/trace_packet.proto",
+    "protos/perfetto/trace/trigger.proto",
   ],
   tools: [
     "aprotoc",
@@ -2182,6 +2187,7 @@
     "external/perfetto/protos/perfetto/trace/test_event.pbzero.cc",
     "external/perfetto/protos/perfetto/trace/trace.pbzero.cc",
     "external/perfetto/protos/perfetto/trace/trace_packet.pbzero.cc",
+    "external/perfetto/protos/perfetto/trace/trigger.pbzero.cc",
   ],
 }
 
@@ -2194,6 +2200,7 @@
     "protos/perfetto/trace/test_event.proto",
     "protos/perfetto/trace/trace.proto",
     "protos/perfetto/trace/trace_packet.proto",
+    "protos/perfetto/trace/trigger.proto",
   ],
   tools: [
     "aprotoc",
@@ -2206,6 +2213,7 @@
     "external/perfetto/protos/perfetto/trace/test_event.pbzero.h",
     "external/perfetto/protos/perfetto/trace/trace.pbzero.h",
     "external/perfetto/protos/perfetto/trace/trace_packet.pbzero.h",
+    "external/perfetto/protos/perfetto/trace/trigger.pbzero.h",
   ],
   export_include_dirs: [
     "protos",
diff --git a/protos/BUILD b/protos/BUILD
index 0e486fc..faccfe6 100644
--- a/protos/BUILD
+++ b/protos/BUILD
@@ -693,6 +693,7 @@
     srcs = [
         "perfetto/trace/clock_snapshot.proto",
         "perfetto/trace/system_info.proto",
+        "perfetto/trace/trigger.proto",
     ],
     has_services = 1,
     cc_api_version = 2,
@@ -753,6 +754,7 @@
         "perfetto/trace/test_event.proto",
         "perfetto/trace/trace.proto",
         "perfetto/trace/trace_packet.proto",
+        "perfetto/trace/trigger.proto",
     ],
     deps = [
         "//third_party/perfetto/protos:android_zero",
diff --git a/protos/perfetto/trace/BUILD.gn b/protos/perfetto/trace/BUILD.gn
index 9e05cf1..f79a07c 100644
--- a/protos/perfetto/trace/BUILD.gn
+++ b/protos/perfetto/trace/BUILD.gn
@@ -20,6 +20,7 @@
 # the generic ":lite" target
 proto_sources_minimal = [
   "clock_snapshot.proto",
+  "trigger.proto",
   "system_info.proto",
 ]
 
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 14177fb..5362bbb 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -2652,7 +2652,7 @@
 // TracePacket(s).
 //
 // Next reserved id: 13 (up to 15).
-// Next id: 46.
+// Next id: 47.
 message TracePacket {
   // TODO(primiano): in future we should add a timestamp_clock_domain field to
   // allow mixing timestamps from different clock domains.
@@ -2679,6 +2679,7 @@
     PowerRails power_rails = 40;
     AndroidLogPacket android_log = 39;
     SystemInfo system_info = 45;
+    Trigger trigger = 46;
 
     // Only used by TrackEvent.
     ProcessDescriptor process_descriptor = 43;
@@ -3021,6 +3022,23 @@
 
 // End of protos/perfetto/trace/track_event/track_event.proto
 
+// Begin of protos/perfetto/trace/trigger.proto
+
+// When a TracingSession receives a trigger it records the boot time nanoseconds
+// in the TracePacket's timestamp field as well as the name of the producer that
+// triggered it. We emit this data so filtering can be done on triggers received
+// in the trace.
+message Trigger {
+  // Name of the trigger which was received.
+  optional string trigger_name = 1;
+  // The actual producer that activated |trigger|.
+  optional string producer_name = 2;
+  // The verified UID of the producer.
+  optional int32 trusted_producer_uid = 3;
+}
+
+// End of protos/perfetto/trace/trigger.proto
+
 // Begin of protos/perfetto/config/android/android_log_config.proto
 
 message AndroidLogConfig {
diff --git a/protos/perfetto/trace/trace_packet.proto b/protos/perfetto/trace/trace_packet.proto
index 234f1b6..246cacb 100644
--- a/protos/perfetto/trace/trace_packet.proto
+++ b/protos/perfetto/trace/trace_packet.proto
@@ -33,10 +33,11 @@
 import "perfetto/trace/ps/process_tree.proto";
 import "perfetto/trace/sys_stats/sys_stats.proto";
 import "perfetto/trace/system_info.proto";
-import "perfetto/trace/test_event.proto";
 import "perfetto/trace/track_event/process_descriptor.proto";
 import "perfetto/trace/track_event/thread_descriptor.proto";
 import "perfetto/trace/track_event/track_event.proto";
+import "perfetto/trace/trigger.proto";
+import "perfetto/trace/test_event.proto";
 
 package perfetto.protos;
 
@@ -44,7 +45,7 @@
 // TracePacket(s).
 //
 // Next reserved id: 13 (up to 15).
-// Next id: 46.
+// Next id: 47.
 message TracePacket {
   // TODO(primiano): in future we should add a timestamp_clock_domain field to
   // allow mixing timestamps from different clock domains.
@@ -71,6 +72,7 @@
     PowerRails power_rails = 40;
     AndroidLogPacket android_log = 39;
     SystemInfo system_info = 45;
+    Trigger trigger = 46;
 
     // Only used by TrackEvent.
     ProcessDescriptor process_descriptor = 43;
diff --git a/protos/perfetto/trace/trigger.proto b/protos/perfetto/trace/trigger.proto
new file mode 100644
index 0000000..d895d80
--- /dev/null
+++ b/protos/perfetto/trace/trigger.proto
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package perfetto.protos;
+
+// When a TracingSession receives a trigger it records the boot time nanoseconds
+// in the TracePacket's timestamp field as well as the name of the producer that
+// triggered it. We emit this data so filtering can be done on triggers received
+// in the trace.
+message Trigger {
+  // Name of the trigger which was received.
+  optional string trigger_name = 1;
+  // The actual producer that activated |trigger|.
+  optional string producer_name = 2;
+  // The verified UID of the producer.
+  optional int32 trusted_producer_uid = 3;
+}
diff --git a/protos/perfetto/trace/trusted_packet.proto b/protos/perfetto/trace/trusted_packet.proto
index b1b59ec..516766e 100644
--- a/protos/perfetto/trace/trusted_packet.proto
+++ b/protos/perfetto/trace/trusted_packet.proto
@@ -30,6 +30,7 @@
 import "perfetto/config/trace_config.proto";
 import "perfetto/trace/clock_snapshot.proto";
 import "perfetto/trace/system_info.proto";
+import "perfetto/trace/trigger.proto";
 
 package perfetto.protos;
 
@@ -58,4 +59,5 @@
   bytes synchronization_marker = 36;
   bool previous_packet_dropped = 42;
   SystemInfo system_info = 45;
+  Trigger trigger = 46;
 }
diff --git a/src/tracing/core/tracing_service_impl.cc b/src/tracing/core/tracing_service_impl.cc
index e193477..2a4e907 100644
--- a/src/tracing/core/tracing_service_impl.cc
+++ b/src/tracing/core/tracing_service_impl.cc
@@ -897,14 +897,11 @@
         continue;
       }
 
-      // TODO(nuskos): Currently we store these triggers but don't actually
-      // return them inside ReadBuffers. In a followup CL add this
-      // functionality. Ensure that there is no race condition between
-      // future triggers being added and ReadBuffers processing this vector.
       const bool triggers_already_received =
           !tracing_session.received_triggers.empty();
-      tracing_session.received_triggers.push_back(std::make_pair(
-          static_cast<uint64_t>(base::GetBootTimeNs().count()), *iter));
+      tracing_session.received_triggers.push_back(
+          {static_cast<uint64_t>(base::GetBootTimeNs().count()), iter->name(),
+           producer->name_, producer->uid_});
       auto weak_this = weak_ptr_factory_.GetWeakPtr();
       switch (tracing_session.config.trigger_config().trigger_mode()) {
         case TraceConfig::TriggerConfig::START_TRACING:
@@ -1347,6 +1344,7 @@
   }
   MaybeEmitTraceConfig(tracing_session, &packets);
   MaybeEmitSystemInfo(tracing_session, &packets);
+  MaybeEmitReceivedTriggers(tracing_session, &packets);
 
   size_t packets_bytes = 0;  // SUM(slice.size() for each slice in |packets|).
   size_t total_slices = 0;   // SUM(#slices in |packets|).
@@ -2137,6 +2135,32 @@
   packets->back().AddSlice(std::move(slice));
 }
 
+void TracingServiceImpl::MaybeEmitReceivedTriggers(
+    TracingSession* tracing_session,
+    std::vector<TracePacket>* packets) {
+  PERFETTO_DCHECK(tracing_session->num_triggers_emitted_into_trace <=
+                  tracing_session->received_triggers.size());
+  for (size_t i = tracing_session->num_triggers_emitted_into_trace;
+       i < tracing_session->received_triggers.size(); ++i) {
+    const auto& info = tracing_session->received_triggers[i];
+    protos::TrustedPacket packet;
+
+    protos::Trigger* trigger = packet.mutable_trigger();
+    trigger->set_trigger_name(info.trigger_name);
+    trigger->set_producer_name(info.producer_name);
+    trigger->set_trusted_producer_uid(static_cast<int32_t>(info.producer_uid));
+
+    packet.set_timestamp(info.boot_time_ns);
+    packet.set_trusted_uid(static_cast<int32_t>(uid_));
+    packet.set_trusted_packet_sequence_id(kServicePacketSequenceID);
+    Slice slice = Slice::Allocate(static_cast<size_t>(packet.ByteSize()));
+    PERFETTO_CHECK(packet.SerializeWithCachedSizesToArray(slice.own_data()));
+    packets->emplace_back();
+    packets->back().AddSlice(std::move(slice));
+    ++tracing_session->num_triggers_emitted_into_trace;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // TracingServiceImpl::ConsumerEndpointImpl implementation
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/tracing/core/tracing_service_impl.h b/src/tracing/core/tracing_service_impl.h
index db174ce..bda8c29 100644
--- a/src/tracing/core/tracing_service_impl.h
+++ b/src/tracing/core/tracing_service_impl.h
@@ -398,8 +398,13 @@
     // were received at. This is used to insert 'fake' packets back to the
     // consumer so they can tell when some event happened. The order matches the
     // order they were received.
-    std::vector<std::pair<uint64_t, TraceConfig::TriggerConfig::Trigger>>
-        received_triggers;
+    struct TriggerInfo {
+      uint64_t boot_time_ns;
+      std::string trigger_name;
+      std::string producer_name;
+      uid_t producer_uid;
+    };
+    std::vector<TriggerInfo> received_triggers;
 
     // The trace config provided by the Consumer when calling
     // EnableTracing(), plus any updates performed by ChangeTraceConfig.
@@ -432,6 +437,9 @@
     // Whether we put the system info into the trace output yet.
     bool did_emit_system_info = false;
 
+    // The number of received triggers we've emitted into the trace output.
+    size_t num_triggers_emitted_into_trace = 0;
+
     State state = DISABLED;
 
     // If the consumer detached the session, this variable defines the key used
@@ -480,6 +488,7 @@
   TraceStats GetTraceStats(TracingSession* tracing_session);
   void MaybeEmitTraceConfig(TracingSession*, std::vector<TracePacket>*);
   void MaybeEmitSystemInfo(TracingSession*, std::vector<TracePacket>*);
+  void MaybeEmitReceivedTriggers(TracingSession*, std::vector<TracePacket>*);
   void OnFlushTimeout(TracingSessionID, FlushRequestID);
   void OnDisableTracingTimeout(TracingSessionID);
   void DisableTracingNotifyConsumerAndFlushFile(TracingSession*);
diff --git a/src/tracing/core/tracing_service_impl_unittest.cc b/src/tracing/core/tracing_service_impl_unittest.cc
index c5e8e0d..9af5391 100644
--- a/src/tracing/core/tracing_service_impl_unittest.cc
+++ b/src/tracing/core/tracing_service_impl_unittest.cc
@@ -290,7 +290,7 @@
 
   ASSERT_EQ(1u, tracing_session()->received_triggers.size());
   EXPECT_EQ("trigger_name",
-            tracing_session()->received_triggers[0].second.name());
+            tracing_session()->received_triggers[0].trigger_name);
 
   EXPECT_THAT(
       consumer->ReadBuffers(),
@@ -507,9 +507,6 @@
 
   producer->WaitForDataSourceSetup("ds_1");
 
-  // Make sure we don't get unexpected DataSourceStart() notifications yet.
-  task_runner.RunUntilIdle();
-
   std::vector<std::string> req;
   req.push_back("not_correct_trigger");
   req.push_back("trigger_name");
@@ -559,9 +556,6 @@
 
   producer->WaitForDataSourceSetup("ds_1");
 
-  // Make sure we don't get unexpected DataSourceStart() notifications yet from
-  // consumer_1.
-  task_runner.RunUntilIdle();
   auto tracing_session_1_id = GetTracingSessionID();
 
   (*trace_config.mutable_data_sources())[0].mutable_config()->set_name("ds_2");
@@ -573,9 +567,6 @@
 
   producer->WaitForDataSourceSetup("ds_2");
 
-  // Make sure we don't get unexpected DataSourceStart() notifications yet from
-  // consumer_2.
-  task_runner.RunUntilIdle();
   auto tracing_session_2_id = GetTracingSessionID();
   EXPECT_NE(tracing_session_1_id, tracing_session_2_id);
 
@@ -597,7 +588,7 @@
   auto* tracing_session_1 = GetTracingSession(tracing_session_1_id);
   ASSERT_EQ(1u, tracing_session_1->received_triggers.size());
   EXPECT_EQ("trigger_name",
-            tracing_session_1->received_triggers[0].second.name());
+            tracing_session_1->received_triggers[0].trigger_name);
 
   // This is actually dependent on the order in which the triggers were received
   // but there isn't really a better way than iteration order so probably not to
@@ -606,13 +597,10 @@
   ASSERT_EQ(2u, tracing_session_2->received_triggers.size());
 
   EXPECT_EQ("trigger_name",
-            tracing_session_2->received_triggers[0].second.name());
-  EXPECT_EQ(1u, tracing_session_2->received_triggers[0].second.stop_delay_ms());
+            tracing_session_2->received_triggers[0].trigger_name);
 
   EXPECT_EQ("trigger_name_2",
-            tracing_session_2->received_triggers[1].second.name());
-  EXPECT_EQ(8.64e+7,
-            tracing_session_2->received_triggers[1].second.stop_delay_ms());
+            tracing_session_2->received_triggers[1].trigger_name);
 
   auto writer1 = producer->CreateTraceWriter("ds_1");
   auto writer2 = producer->CreateTraceWriter("ds_2");
@@ -668,6 +656,237 @@
       HasTriggerMode(protos::TraceConfig::TriggerConfig::START_TRACING));
 }
 
+// Creates a tracing session with a START_TRACING trigger and checks that the
+// received_triggers are emitted as packets.
+TEST_F(TracingServiceImplTest, EmitTriggersWithStartTracingTrigger) {
+  std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+  consumer->Connect(svc.get());
+
+  std::unique_ptr<MockProducer> producer = CreateMockProducer();
+  producer->Connect(svc.get(), "mock_producer", /* uid = */ 123u);
+
+  producer->RegisterDataSource("ds_1");
+
+  TraceConfig trace_config;
+  trace_config.add_buffers()->set_size_kb(128);
+  trace_config.add_data_sources()->mutable_config()->set_name("ds_1");
+  auto* trigger_config = trace_config.mutable_trigger_config();
+  trigger_config->set_trigger_mode(TraceConfig::TriggerConfig::START_TRACING);
+  auto* trigger = trigger_config->add_triggers();
+  trigger->set_name("trigger_name");
+  trigger->set_stop_delay_ms(1);
+  trigger->set_producer_name_regex("mock_produc[e-r]+");
+
+  trigger_config->set_trigger_timeout_ms(30000);
+
+  consumer->EnableTracing(trace_config);
+  producer->WaitForTracingSetup();
+  producer->WaitForDataSourceSetup("ds_1");
+
+  // The trace won't start until we send the trigger since we have a
+  // START_TRACING trigger defined.
+  std::vector<std::string> req;
+  req.push_back("trigger_name");
+  req.push_back("trigger_name_2");
+  req.push_back("trigger_name_3");
+  producer->endpoint()->ActivateTriggers(req);
+
+  producer->WaitForDataSourceStart("ds_1");
+  auto writer1 = producer->CreateTraceWriter("ds_1");
+  producer->WaitForFlush(writer1.get());
+  producer->WaitForDataSourceStop("ds_1");
+  consumer->WaitForTracingDisabled();
+
+  ASSERT_EQ(1u, tracing_session()->received_triggers.size());
+  EXPECT_EQ("trigger_name",
+            tracing_session()->received_triggers[0].trigger_name);
+
+  auto packets = consumer->ReadBuffers();
+  EXPECT_THAT(
+      packets,
+      Contains(Property(
+          &protos::TracePacket::trace_config,
+          Property(
+              &protos::TraceConfig::trigger_config,
+              Property(
+                  &protos::TraceConfig::TriggerConfig::trigger_mode,
+                  Eq(protos::TraceConfig::TriggerConfig::START_TRACING))))));
+  auto expect_received_trigger = [&](const std::string& name) {
+    return Contains(AllOf(
+        Property(
+            &protos::TracePacket::trigger,
+            AllOf(Property(&protos::Trigger::trigger_name, Eq(name)),
+                  Property(&protos::Trigger::trusted_producer_uid, Eq(123u)),
+                  Property(&protos::Trigger::producer_name,
+                           Eq("mock_producer")))),
+        Property(&protos::TracePacket::trusted_packet_sequence_id,
+                 Eq(kServicePacketSequenceID))));
+  };
+  EXPECT_THAT(packets, expect_received_trigger("trigger_name"));
+  EXPECT_THAT(packets,
+              ::testing::Not(expect_received_trigger("trigger_name_2")));
+  EXPECT_THAT(packets,
+              ::testing::Not(expect_received_trigger("trigger_name_3")));
+}
+
+// Creates a tracing session with a START_TRACING trigger and checks that the
+// received_triggers are emitted as packets.
+TEST_F(TracingServiceImplTest, EmitTriggersWithStopTracingTrigger) {
+  std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+  consumer->Connect(svc.get());
+
+  std::unique_ptr<MockProducer> producer = CreateMockProducer();
+  producer->Connect(svc.get(), "mock_producer", /* uid = */ 321u);
+
+  producer->RegisterDataSource("ds_1");
+
+  TraceConfig trace_config;
+  trace_config.add_buffers()->set_size_kb(128);
+  trace_config.add_data_sources()->mutable_config()->set_name("ds_1");
+  auto* trigger_config = trace_config.mutable_trigger_config();
+  trigger_config->set_trigger_mode(TraceConfig::TriggerConfig::STOP_TRACING);
+  auto* trigger = trigger_config->add_triggers();
+  trigger->set_name("trigger_name");
+  trigger->set_stop_delay_ms(1);
+  trigger = trigger_config->add_triggers();
+  trigger->set_name("trigger_name_3");
+  trigger->set_stop_delay_ms(30000);
+
+  trigger_config->set_trigger_timeout_ms(30000);
+
+  consumer->EnableTracing(trace_config);
+  producer->WaitForTracingSetup();
+  producer->WaitForDataSourceSetup("ds_1");
+  producer->WaitForDataSourceStart("ds_1");
+
+  // The trace won't start until we send the trigger since we have a
+  // START_TRACING trigger defined.
+  std::vector<std::string> req;
+  req.push_back("trigger_name");
+  req.push_back("trigger_name_2");
+  req.push_back("trigger_name_3");
+  producer->endpoint()->ActivateTriggers(req);
+
+  auto writer1 = producer->CreateTraceWriter("ds_1");
+  producer->WaitForFlush(writer1.get());
+  producer->WaitForDataSourceStop("ds_1");
+  consumer->WaitForTracingDisabled();
+
+  ASSERT_EQ(2u, tracing_session()->received_triggers.size());
+  EXPECT_EQ("trigger_name",
+            tracing_session()->received_triggers[0].trigger_name);
+  EXPECT_EQ("trigger_name_3",
+            tracing_session()->received_triggers[1].trigger_name);
+
+  auto packets = consumer->ReadBuffers();
+  EXPECT_THAT(
+      packets,
+      Contains(Property(
+          &protos::TracePacket::trace_config,
+          Property(
+              &protos::TraceConfig::trigger_config,
+              Property(
+                  &protos::TraceConfig::TriggerConfig::trigger_mode,
+                  Eq(protos::TraceConfig::TriggerConfig::STOP_TRACING))))));
+
+  auto expect_received_trigger = [&](const std::string& name) {
+    return Contains(AllOf(
+        Property(
+            &protos::TracePacket::trigger,
+            AllOf(Property(&protos::Trigger::trigger_name, Eq(name)),
+                  Property(&protos::Trigger::trusted_producer_uid, Eq(321u)),
+                  Property(&protos::Trigger::producer_name,
+                           Eq("mock_producer")))),
+        Property(&protos::TracePacket::trusted_packet_sequence_id,
+                 Eq(kServicePacketSequenceID))));
+  };
+  EXPECT_THAT(packets, expect_received_trigger("trigger_name"));
+  EXPECT_THAT(packets,
+              ::testing::Not(expect_received_trigger("trigger_name_2")));
+  EXPECT_THAT(packets, expect_received_trigger("trigger_name_3"));
+}
+
+// Creates a tracing session with a START_TRACING trigger and checks that the
+// received_triggers are emitted as packets even ones after the initial
+// ReadBuffers() call.
+TEST_F(TracingServiceImplTest, EmitTriggersRepeatedly) {
+  std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+  consumer->Connect(svc.get());
+
+  std::unique_ptr<MockProducer> producer = CreateMockProducer();
+  producer->Connect(svc.get(), "mock_producer");
+
+  // Create two data sources but enable only one of them.
+  producer->RegisterDataSource("ds_1");
+  producer->RegisterDataSource("ds_2");
+
+  TraceConfig trace_config;
+  trace_config.add_buffers()->set_size_kb(128);
+  trace_config.add_data_sources()->mutable_config()->set_name("ds_1");
+  auto* trigger_config = trace_config.mutable_trigger_config();
+  trigger_config->set_trigger_mode(TraceConfig::TriggerConfig::STOP_TRACING);
+  auto* trigger = trigger_config->add_triggers();
+  trigger->set_name("trigger_name");
+  trigger->set_stop_delay_ms(1);
+  trigger = trigger_config->add_triggers();
+  trigger->set_name("trigger_name_2");
+  trigger->set_stop_delay_ms(1);
+
+  trigger_config->set_trigger_timeout_ms(30000);
+
+  auto expect_received_trigger = [&](const std::string& name) {
+    return Contains(
+        AllOf(Property(&protos::TracePacket::trigger,
+                       AllOf(Property(&protos::Trigger::trigger_name, Eq(name)),
+                             Property(&protos::Trigger::producer_name,
+                                      Eq("mock_producer")))),
+              Property(&protos::TracePacket::trusted_packet_sequence_id,
+                       Eq(kServicePacketSequenceID))));
+  };
+
+  consumer->EnableTracing(trace_config);
+  producer->WaitForTracingSetup();
+  producer->WaitForDataSourceSetup("ds_1");
+  producer->WaitForDataSourceStart("ds_1");
+
+  // The trace won't start until we send the trigger. since we have a
+  // START_TRACING trigger defined.
+  producer->endpoint()->ActivateTriggers({"trigger_name"});
+
+  auto packets = consumer->ReadBuffers();
+  EXPECT_THAT(
+      packets,
+      Contains(Property(
+          &protos::TracePacket::trace_config,
+          Property(
+              &protos::TraceConfig::trigger_config,
+              Property(
+                  &protos::TraceConfig::TriggerConfig::trigger_mode,
+                  Eq(protos::TraceConfig::TriggerConfig::STOP_TRACING))))));
+  EXPECT_THAT(packets, expect_received_trigger("trigger_name"));
+  EXPECT_THAT(packets,
+              ::testing::Not(expect_received_trigger("trigger_name_2")));
+
+  // Send a new trigger.
+  producer->endpoint()->ActivateTriggers({"trigger_name_2"});
+
+  auto writer1 = producer->CreateTraceWriter("ds_1");
+  producer->WaitForFlush(writer1.get());
+  producer->WaitForDataSourceStop("ds_1");
+  consumer->WaitForTracingDisabled();
+
+  ASSERT_EQ(2u, tracing_session()->received_triggers.size());
+  EXPECT_EQ("trigger_name",
+            tracing_session()->received_triggers[0].trigger_name);
+  EXPECT_EQ("trigger_name_2",
+            tracing_session()->received_triggers[1].trigger_name);
+
+  packets = consumer->ReadBuffers();
+  // We don't rewrite the old trigger.
+  EXPECT_THAT(packets, ::testing::Not(expect_received_trigger("trigger_name")));
+  EXPECT_THAT(packets, expect_received_trigger("trigger_name_2"));
+}
+
 // Creates a tracing session with a STOP_TRACING trigger and checks that the
 // session is cleaned up after |trigger_timeout_ms|.
 TEST_F(TracingServiceImplTest, StopTracingTriggerTimeout) {
@@ -745,8 +964,6 @@
   producer->WaitForDataSourceSetup("ds_1");
   producer->WaitForDataSourceStart("ds_1");
 
-  task_runner.RunUntilIdle();
-
   // The trace won't return data until unless we send a trigger at this point.
   EXPECT_THAT(consumer->ReadBuffers(), ::testing::IsEmpty());
 
@@ -782,15 +999,13 @@
 
   ASSERT_EQ(1u, tracing_session()->received_triggers.size());
   EXPECT_EQ("trigger_name",
-            tracing_session()->received_triggers[0].second.name());
+            tracing_session()->received_triggers[0].trigger_name);
 
   producer->WaitForDataSourceStop("ds_1");
   consumer->WaitForTracingDisabled();
-  // There are 5 preample packets plus the kNumTestPackets we wrote out. The
-  // large_payload one should be overwritten.
-  static const uint32_t kNumPreamblePackets = 5;
+
   auto packets = consumer->ReadBuffers();
-  EXPECT_EQ(kNumTestPackets + kNumPreamblePackets, packets.size());
+  EXPECT_LT(kNumTestPackets, packets.size());
   // We expect for the TraceConfig preamble packet to be there correctly and
   // then we expect each payload to be there, but not the |large_payload|
   // packet.
@@ -845,8 +1060,6 @@
   producer->WaitForDataSourceSetup("ds_1");
   producer->WaitForDataSourceStart("ds_1");
 
-  task_runner.RunUntilIdle();
-
   // The trace won't return data until unless we send a trigger at this point.
   EXPECT_THAT(consumer->ReadBuffers(), ::testing::IsEmpty());
 
@@ -861,9 +1074,9 @@
 
   ASSERT_EQ(2u, tracing_session()->received_triggers.size());
   EXPECT_EQ("trigger_name",
-            tracing_session()->received_triggers[0].second.name());
+            tracing_session()->received_triggers[0].trigger_name);
   EXPECT_EQ("trigger_name_2",
-            tracing_session()->received_triggers[1].second.name());
+            tracing_session()->received_triggers[1].trigger_name);
 
   producer->WaitForDataSourceStop("ds_1");
   consumer->WaitForTracingDisabled();
diff --git a/tools/gen_merged_protos b/tools/gen_merged_protos
index ee12f10..1696501 100755
--- a/tools/gen_merged_protos
+++ b/tools/gen_merged_protos
@@ -80,6 +80,7 @@
   'protos/perfetto/trace/track_event/task_execution.proto',
   'protos/perfetto/trace/track_event/thread_descriptor.proto',
   'protos/perfetto/trace/track_event/track_event.proto',
+  'protos/perfetto/trace/trigger.proto',
 )
 
 MERGED_TRACE_PROTO = 'protos/perfetto/trace/perfetto_trace.proto'