Tracing API: Add FlushFlags

Give a way to producer to tell what's the reason for the flush.
For future-proofing and ease of plumbing the flags are implemented
as a uint64 which overlays different sub-fields.

Test: updated perfetto_unittests & perfetto_integrationtests
Bug: 293429094
Change-Id: I6f8ff60832d8bec8b8b8aa8b7b019ac0b2081748
diff --git a/BUILD b/BUILD
index 078b4df..f47bcc3 100644
--- a/BUILD
+++ b/BUILD
@@ -849,6 +849,7 @@
         "include/perfetto/tracing/core/chrome_config.h",
         "include/perfetto/tracing/core/data_source_config.h",
         "include/perfetto/tracing/core/data_source_descriptor.h",
+        "include/perfetto/tracing/core/flush_flags.h",
         "include/perfetto/tracing/core/trace_config.h",
         "include/perfetto/tracing/core/tracing_service_capabilities.h",
         "include/perfetto/tracing/core/tracing_service_state.h",
diff --git a/include/perfetto/ext/tracing/core/producer.h b/include/perfetto/ext/tracing/core/producer.h
index d1ca85d..234c406 100644
--- a/include/perfetto/ext/tracing/core/producer.h
+++ b/include/perfetto/ext/tracing/core/producer.h
@@ -19,7 +19,9 @@
 
 #include "perfetto/base/export.h"
 #include "perfetto/ext/tracing/core/basic_types.h"
+#include "perfetto/tracing/core/flush_flags.h"
 #include "perfetto/tracing/core/forward_decls.h"
+
 namespace perfetto {
 
 class SharedMemory;
@@ -106,7 +108,8 @@
   // flushes < N have also been committed.
   virtual void Flush(FlushRequestID,
                      const DataSourceInstanceID* data_source_ids,
-                     size_t num_data_sources) = 0;
+                     size_t num_data_sources,
+                     FlushFlags) = 0;
 
   // Called by the service to instruct the given data sources to stop referring
   // to any trace contents emitted so far. The intent is that after processing
diff --git a/include/perfetto/ext/tracing/core/tracing_service.h b/include/perfetto/ext/tracing/core/tracing_service.h
index b82a96a..690795f 100644
--- a/include/perfetto/ext/tracing/core/tracing_service.h
+++ b/include/perfetto/ext/tracing/core/tracing_service.h
@@ -30,6 +30,7 @@
 #include "perfetto/ext/tracing/core/shared_memory.h"
 #include "perfetto/ext/tracing/core/trace_packet.h"
 #include "perfetto/tracing/buffer_exhausted_policy.h"
+#include "perfetto/tracing/core/flush_flags.h"
 #include "perfetto/tracing/core/forward_decls.h"
 
 namespace perfetto {
@@ -203,7 +204,15 @@
   // if that one is not set (or is set to 0), kDefaultFlushTimeoutMs (5s) is
   // used.
   using FlushCallback = std::function<void(bool /*success*/)>;
-  virtual void Flush(uint32_t timeout_ms, FlushCallback) = 0;
+  virtual void Flush(uint32_t timeout_ms, FlushCallback callback, FlushFlags);
+
+  // The only caller of this method is arctraceservice's PerfettoClient.
+  // Everything else in the codebase uses the 3-arg Flush() above.
+  // TODO(primiano): remove the overload without FlushFlags once
+  // arctraceservice moves away from this interface. arctraceservice lives in
+  // the internal repo and changes to this interface require multi-side patches.
+  // Inernally this calls Flush(timeout, callback, FlushFlags(0)).
+  virtual void Flush(uint32_t timeout_ms, FlushCallback callback);
 
   // Tracing data will be delivered invoking Consumer::OnTraceData().
   virtual void ReadBuffers() = 0;
diff --git a/include/perfetto/tracing/core/BUILD.gn b/include/perfetto/tracing/core/BUILD.gn
index c961c2d..9ea0e2c 100644
--- a/include/perfetto/tracing/core/BUILD.gn
+++ b/include/perfetto/tracing/core/BUILD.gn
@@ -22,6 +22,7 @@
     "chrome_config.h",
     "data_source_config.h",
     "data_source_descriptor.h",
+    "flush_flags.h",
     "trace_config.h",
     "tracing_service_capabilities.h",
     "tracing_service_state.h",
diff --git a/include/perfetto/tracing/core/flush_flags.h b/include/perfetto/tracing/core/flush_flags.h
new file mode 100644
index 0000000..12445b5
--- /dev/null
+++ b/include/perfetto/tracing/core/flush_flags.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#ifndef INCLUDE_PERFETTO_TRACING_CORE_FLUSH_FLAGS_H_
+#define INCLUDE_PERFETTO_TRACING_CORE_FLUSH_FLAGS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace perfetto {
+
+// This class is a wrapper around the uint64_t flags that are sent across the
+// tracing protocol whenenver a flush occurs. It helps determining the reason
+// and initiator of the flush.
+// NOTE: the values here are part of the tracing protocol ABI. Do not renumber.
+class FlushFlags {
+ public:
+  enum class Initiator : uint64_t {
+    // DO NOT RENUMBER, ABI.
+    kUnknown = 0,
+    kTraced = 1,
+    kPerfettoCmd = 2,
+    kConsumerSdk = 3,
+    kMax,
+  };
+
+  enum class Reason : uint64_t {
+    // DO NOT RENUMBER, ABI.
+    kUnknown = 0,
+    kPeriodic = 1,
+    kTraceStop = 2,
+    kTraceClone = 3,
+    kExplicit = 4,
+    kMax,
+  };
+
+  enum class CloneTarget : uint64_t {
+    // DO NOT RENUMBER, ABI.
+    kUnknown = 0,
+    kBugreport = 1,
+    kMax,
+  };
+
+  explicit FlushFlags(uint64_t flags = 0) : flags_(flags) {}
+  FlushFlags(Initiator i, Reason r, CloneTarget c = CloneTarget::kUnknown)
+      : flags_((static_cast<uint64_t>(i) << kInitiatorShift) |
+               (static_cast<uint64_t>(r) << kReasonShift) |
+               (static_cast<uint64_t>(c) << kCloneTargetShift)) {}
+
+  bool operator==(const FlushFlags& o) const { return flags_ == o.flags_; }
+  bool operator!=(const FlushFlags& o) const { return !(*this == o); }
+
+  Initiator initiator() const {
+    // Due to version mismatch we might see a value from the future that we
+    // didn't know yet. If that happens, short ciruit to kUnknown.
+    static_assert(
+        uint64_t(Initiator::kMax) - 1 <= (kInitiatorMask >> kInitiatorShift),
+        "enum out of range");
+    const uint64_t value = (flags_ & kInitiatorMask) >> kInitiatorShift;
+    return value < uint64_t(Initiator::kMax) ? Initiator(value)
+                                             : Initiator::kUnknown;
+  }
+
+  Reason reason() const {
+    static_assert(uint64_t(Reason::kMax) - 1 <= (kReasonMask >> kReasonShift),
+                  "enum out of range");
+    const uint64_t value = (flags_ & kReasonMask) >> kReasonShift;
+    return value < uint64_t(Reason::kMax) ? Reason(value) : Reason::kUnknown;
+  }
+
+  CloneTarget clone_target() const {
+    static_assert(uint64_t(CloneTarget::kMax) - 1 <=
+                      (kCloneTargetMask >> kCloneTargetShift),
+                  "enum out of range");
+    const uint64_t value = (flags_ & kCloneTargetMask) >> kCloneTargetShift;
+    return value < uint64_t(CloneTarget::kMax) ? CloneTarget(value)
+                                               : CloneTarget::kUnknown;
+  }
+
+  uint64_t flags() const { return flags_; }
+
+ private:
+  // DO NOT CHANGE, ABI.
+  static constexpr uint64_t kReasonMask = 0xF;
+  static constexpr uint64_t kReasonShift = 0;
+  static constexpr uint64_t kInitiatorMask = 0xF0;
+  static constexpr uint64_t kInitiatorShift = 4;
+  static constexpr uint64_t kCloneTargetMask = 0xF00;
+  static constexpr uint64_t kCloneTargetShift = 8;
+
+  uint64_t flags_ = 0;
+};
+
+}  // namespace perfetto
+
+#endif  // INCLUDE_PERFETTO_TRACING_CORE_FLUSH_FLAGS_H_
diff --git a/include/perfetto/tracing/data_source.h b/include/perfetto/tracing/data_source.h
index 925e4dd..4bcd04e 100644
--- a/include/perfetto/tracing/data_source.h
+++ b/include/perfetto/tracing/data_source.h
@@ -33,6 +33,7 @@
 
 #include "perfetto/protozero/message_handle.h"
 #include "perfetto/tracing/buffer_exhausted_policy.h"
+#include "perfetto/tracing/core/flush_flags.h"
 #include "perfetto/tracing/core/forward_decls.h"
 #include "perfetto/tracing/internal/basic_types.h"
 #include "perfetto/tracing/internal/data_source_internal.h"
@@ -160,6 +161,9 @@
 
     // The index of this data source instance (0..kMaxDataSourceInstances - 1).
     uint32_t internal_instance_index = 0;
+
+    // The reason and initiator of the flush. See flush_flags.h .
+    FlushFlags flush_flags;
   };
   // Called when the tracing service requests a Flush. Users can override this
   // to tell other threads to flush their TraceContext for this data source
diff --git a/protos/perfetto/ipc/consumer_port.proto b/protos/perfetto/ipc/consumer_port.proto
index 2fdc919..b587846 100644
--- a/protos/perfetto/ipc/consumer_port.proto
+++ b/protos/perfetto/ipc/consumer_port.proto
@@ -205,6 +205,10 @@
 // Arguments for rpc Flush().
 message FlushRequest {
   optional uint32 timeout_ms = 1;
+
+  // More details such as flush reason and originator. Introduced in v38 / V.
+  // See FlushFlags in include/perfetto/ext/tracing/core/flush_flags.h.
+  optional uint64 flags = 2;
 }
 
 message FlushResponse {}
diff --git a/protos/perfetto/ipc/producer_port.proto b/protos/perfetto/ipc/producer_port.proto
index 5c204cb..9e3d5d1 100644
--- a/protos/perfetto/ipc/producer_port.proto
+++ b/protos/perfetto/ipc/producer_port.proto
@@ -318,6 +318,10 @@
     // expected to copy this value back into the CommitDataRequest, so the
     // service can tell when the data for this flush has been committed.
     optional uint64 request_id = 2;
+
+    // More details such as flush reason and originator. Introduced in v38 / V.
+    // See FlushFlags in include/perfetto/ext/tracing/core/flush_flags.h.
+    optional uint64 flags = 3;
   }
 
   // Instructs the given data sources to stop referring to any trace contents
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index 3052341..2ddbf04 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -1264,13 +1264,17 @@
       return;
     PERFETTO_LOG("SIGINT/SIGTERM received: disabling tracing.");
     weak_this->ctrl_c_evt_.Clear();
-    weak_this->consumer_endpoint_->Flush(0, [weak_this](bool flush_success) {
-      if (!weak_this)
-        return;
-      if (!flush_success)
-        PERFETTO_ELOG("Final flush unsuccessful.");
-      weak_this->consumer_endpoint_->DisableTracing();
-    });
+    weak_this->consumer_endpoint_->Flush(
+        0,
+        [weak_this](bool flush_success) {
+          if (!weak_this)
+            return;
+          if (!flush_success)
+            PERFETTO_ELOG("Final flush unsuccessful.");
+          weak_this->consumer_endpoint_->DisableTracing();
+        },
+        FlushFlags(FlushFlags::Initiator::kPerfettoCmd,
+                   FlushFlags::Reason::kTraceStop));
   });
 }
 
@@ -1305,13 +1309,17 @@
 
   if (stop_trace_once_attached_) {
     auto weak_this = weak_factory_.GetWeakPtr();
-    consumer_endpoint_->Flush(0, [weak_this](bool flush_success) {
-      if (!weak_this)
-        return;
-      if (!flush_success)
-        PERFETTO_ELOG("Final flush unsuccessful.");
-      weak_this->consumer_endpoint_->DisableTracing();
-    });
+    consumer_endpoint_->Flush(
+        0,
+        [weak_this](bool flush_success) {
+          if (!weak_this)
+            return;
+          if (!flush_success)
+            PERFETTO_ELOG("Final flush unsuccessful.");
+          weak_this->consumer_endpoint_->DisableTracing();
+        },
+        FlushFlags(FlushFlags::Initiator::kPerfettoCmd,
+                   FlushFlags::Reason::kTraceStop));
   }
 }
 
diff --git a/src/perfetto_cmd/trigger_producer.cc b/src/perfetto_cmd/trigger_producer.cc
index 7aefabd..a3abf5a 100644
--- a/src/perfetto_cmd/trigger_producer.cc
+++ b/src/perfetto_cmd/trigger_producer.cc
@@ -81,7 +81,8 @@
 }
 void TriggerProducer::Flush(FlushRequestID,
                             const DataSourceInstanceID*,
-                            size_t) {
+                            size_t,
+                            FlushFlags) {
   PERFETTO_DFATAL("Attempted to Flush() on commandline producer");
 }
 
diff --git a/src/perfetto_cmd/trigger_producer.h b/src/perfetto_cmd/trigger_producer.h
index 0a31bd3..90cd489 100644
--- a/src/perfetto_cmd/trigger_producer.h
+++ b/src/perfetto_cmd/trigger_producer.h
@@ -47,7 +47,10 @@
   void SetupDataSource(DataSourceInstanceID, const DataSourceConfig&) override;
   void StartDataSource(DataSourceInstanceID, const DataSourceConfig&) override;
   void StopDataSource(DataSourceInstanceID) override;
-  void Flush(FlushRequestID, const DataSourceInstanceID*, size_t) override;
+  void Flush(FlushRequestID,
+             const DataSourceInstanceID*,
+             size_t,
+             FlushFlags) override;
   void ClearIncrementalState(const DataSourceInstanceID* data_source_ids,
                              size_t num_data_sources) override;
 
diff --git a/src/profiling/memory/heapprofd_producer.cc b/src/profiling/memory/heapprofd_producer.cc
index d4b8ccc..7490115 100644
--- a/src/profiling/memory/heapprofd_producer.cc
+++ b/src/profiling/memory/heapprofd_producer.cc
@@ -765,7 +765,8 @@
 
 void HeapprofdProducer::Flush(FlushRequestID flush_id,
                               const DataSourceInstanceID* ids,
-                              size_t num_ids) {
+                              size_t num_ids,
+                              FlushFlags) {
   size_t& flush_in_progress = flushes_in_progress_[flush_id];
   PERFETTO_DCHECK(flush_in_progress == 0);
   flush_in_progress = num_ids;
diff --git a/src/profiling/memory/heapprofd_producer.h b/src/profiling/memory/heapprofd_producer.h
index fa1f058..f1473c8 100644
--- a/src/profiling/memory/heapprofd_producer.h
+++ b/src/profiling/memory/heapprofd_producer.h
@@ -119,7 +119,8 @@
   void OnTracingSetup() override;
   void Flush(FlushRequestID,
              const DataSourceInstanceID* data_source_ids,
-             size_t num_data_sources) override;
+             size_t num_data_sources,
+             FlushFlags) override;
   void ClearIncrementalState(const DataSourceInstanceID* /*data_source_ids*/,
                              size_t /*num_data_sources*/) override {}
 
diff --git a/src/profiling/memory/java_hprof_producer.cc b/src/profiling/memory/java_hprof_producer.cc
index 01bd01c..9049bc3 100644
--- a/src/profiling/memory/java_hprof_producer.cc
+++ b/src/profiling/memory/java_hprof_producer.cc
@@ -163,7 +163,8 @@
 
 void JavaHprofProducer::Flush(FlushRequestID flush_id,
                               const DataSourceInstanceID*,
-                              size_t) {
+                              size_t,
+                              FlushFlags) {
   endpoint_->NotifyFlushComplete(flush_id);
 }
 
diff --git a/src/profiling/memory/java_hprof_producer.h b/src/profiling/memory/java_hprof_producer.h
index 4355d96..8591718 100644
--- a/src/profiling/memory/java_hprof_producer.h
+++ b/src/profiling/memory/java_hprof_producer.h
@@ -52,7 +52,8 @@
   void OnTracingSetup() override {}
   void Flush(FlushRequestID,
              const DataSourceInstanceID* data_source_ids,
-             size_t num_data_sources) override;
+             size_t num_data_sources,
+             FlushFlags) override;
   void ClearIncrementalState(const DataSourceInstanceID* /*data_source_ids*/,
                              size_t /*num_data_sources*/) override {}
   // TODO(fmayer): Refactor once/if we have generic reconnect logic.
diff --git a/src/profiling/perf/perf_producer.cc b/src/profiling/perf/perf_producer.cc
index fec5b6d..109b580 100644
--- a/src/profiling/perf/perf_producer.cc
+++ b/src/profiling/perf/perf_producer.cc
@@ -561,7 +561,8 @@
 // the SMB.
 void PerfProducer::Flush(FlushRequestID flush_id,
                          const DataSourceInstanceID* data_source_ids,
-                         size_t num_data_sources) {
+                         size_t num_data_sources,
+                         FlushFlags) {
   // Flush metatracing if requested.
   for (size_t i = 0; i < num_data_sources; i++) {
     auto ds_id = data_source_ids[i];
diff --git a/src/profiling/perf/perf_producer.h b/src/profiling/perf/perf_producer.h
index 83174d3..8cd6eb2 100644
--- a/src/profiling/perf/perf_producer.h
+++ b/src/profiling/perf/perf_producer.h
@@ -78,7 +78,8 @@
   void StopDataSource(DataSourceInstanceID instance_id) override;
   void Flush(FlushRequestID flush_id,
              const DataSourceInstanceID* data_source_ids,
-             size_t num_data_sources) override;
+             size_t num_data_sources,
+             FlushFlags) override;
   void ClearIncrementalState(const DataSourceInstanceID* data_source_ids,
                              size_t num_data_sources) override;
 
diff --git a/src/traced/probes/probes_producer.cc b/src/traced/probes/probes_producer.cc
index f4528ab..0aff1db 100644
--- a/src/traced/probes/probes_producer.cc
+++ b/src/traced/probes/probes_producer.cc
@@ -502,7 +502,8 @@
 
 void ProbesProducer::Flush(FlushRequestID flush_request_id,
                            const DataSourceInstanceID* data_source_ids,
-                           size_t num_data_sources) {
+                           size_t num_data_sources,
+                           FlushFlags) {
   PERFETTO_DLOG("ProbesProducer::Flush(%" PRIu64 ") begin", flush_request_id);
   PERFETTO_DCHECK(flush_request_id);
   auto log_on_exit = base::OnScopeExit([&] {
diff --git a/src/traced/probes/probes_producer.h b/src/traced/probes/probes_producer.h
index b021ee5..e7a4203 100644
--- a/src/traced/probes/probes_producer.h
+++ b/src/traced/probes/probes_producer.h
@@ -56,7 +56,8 @@
   void OnTracingSetup() override;
   void Flush(FlushRequestID,
              const DataSourceInstanceID* data_source_ids,
-             size_t num_data_sources) override;
+             size_t num_data_sources,
+             FlushFlags) override;
   void ClearIncrementalState(const DataSourceInstanceID* data_source_ids,
                              size_t num_data_sources) override;
 
diff --git a/src/traced/service/builtin_producer.cc b/src/traced/service/builtin_producer.cc
index 6516100..b9c5a97 100644
--- a/src/traced/service/builtin_producer.cc
+++ b/src/traced/service/builtin_producer.cc
@@ -284,7 +284,8 @@
 
 void BuiltinProducer::Flush(FlushRequestID flush_id,
                             const DataSourceInstanceID* ds_ids,
-                            size_t num_ds_ids) {
+                            size_t num_ds_ids,
+                            FlushFlags) {
   for (size_t i = 0; i < num_ds_ids; i++) {
     auto meta_it = metatrace_.writers.find(ds_ids[i]);
     if (meta_it != metatrace_.writers.end()) {
diff --git a/src/traced/service/builtin_producer.h b/src/traced/service/builtin_producer.h
index 7f0d892..7eb3f94 100644
--- a/src/traced/service/builtin_producer.h
+++ b/src/traced/service/builtin_producer.h
@@ -43,7 +43,10 @@
   void OnConnect() override;
   void SetupDataSource(DataSourceInstanceID, const DataSourceConfig&) override;
   void StartDataSource(DataSourceInstanceID, const DataSourceConfig&) override;
-  void Flush(FlushRequestID, const DataSourceInstanceID*, size_t) override;
+  void Flush(FlushRequestID,
+             const DataSourceInstanceID*,
+             size_t,
+             FlushFlags) override;
   void StopDataSource(DataSourceInstanceID) override;
 
   // nops:
diff --git a/src/tracing/core/tracing_service_impl.cc b/src/tracing/core/tracing_service_impl.cc
index d7f5634..7b421c3 100644
--- a/src/tracing/core/tracing_service_impl.cc
+++ b/src/tracing/core/tracing_service_impl.cc
@@ -1748,7 +1748,8 @@
 
 void TracingServiceImpl::Flush(TracingSessionID tsid,
                                uint32_t timeout_ms,
-                               ConsumerEndpoint::FlushCallback callback) {
+                               ConsumerEndpoint::FlushCallback callback,
+                               FlushFlags flush_flags) {
   PERFETTO_DCHECK_THREAD(thread_checker_);
   TracingSession* tracing_session = GetTracingSession(tsid);
   if (!tracing_session) {
@@ -1794,7 +1795,7 @@
     ProducerID producer_id = kv.first;
     ProducerEndpointImpl* producer = GetProducer(producer_id);
     const std::vector<DataSourceInstanceID>& data_sources = kv.second;
-    producer->Flush(flush_request_id, data_sources);
+    producer->Flush(flush_request_id, data_sources, flush_flags);
     pending_flush.producers.insert(producer_id);
   }
 
@@ -2001,27 +2002,32 @@
   PERFETTO_DCHECK_THREAD(thread_checker_);
   PERFETTO_DLOG("Triggering final flush for %" PRIu64, tsid);
   auto weak_this = weak_ptr_factory_.GetWeakPtr();
-  Flush(tsid, 0, [weak_this, tsid](bool success) {
-    // This was a DLOG up to Jun 2021 (v16, Android S).
-    PERFETTO_LOG("FlushAndDisableTracing(%" PRIu64 ") done, success=%d", tsid,
-                 success);
-    if (!weak_this)
-      return;
-    TracingSession* session = weak_this->GetTracingSession(tsid);
-    session->final_flush_outcome = success ? TraceStats::FINAL_FLUSH_SUCCEEDED
+  Flush(
+      tsid, 0,
+      [weak_this, tsid](bool success) {
+        // This was a DLOG up to Jun 2021 (v16, Android S).
+        PERFETTO_LOG("FlushAndDisableTracing(%" PRIu64 ") done, success=%d",
+                     tsid, success);
+        if (!weak_this)
+          return;
+        TracingSession* session = weak_this->GetTracingSession(tsid);
+        session->final_flush_outcome = success
+                                           ? TraceStats::FINAL_FLUSH_SUCCEEDED
                                            : TraceStats::FINAL_FLUSH_FAILED;
-    if (session->consumer_maybe_null) {
-      // If the consumer is still attached, just disable the session but give it
-      // a chance to read the contents.
-      weak_this->DisableTracing(tsid);
-    } else {
-      // If the consumer detached, destroy the session. If the consumer did
-      // start the session in long-tracing mode, the service will have saved
-      // the contents to the passed file. If not, the contents will be
-      // destroyed.
-      weak_this->FreeBuffers(tsid);
-    }
-  });
+        if (session->consumer_maybe_null) {
+          // If the consumer is still attached, just disable the session but
+          // give it a chance to read the contents.
+          weak_this->DisableTracing(tsid);
+        } else {
+          // If the consumer detached, destroy the session. If the consumer did
+          // start the session in long-tracing mode, the service will have saved
+          // the contents to the passed file. If not, the contents will be
+          // destroyed.
+          weak_this->FreeBuffers(tsid);
+        }
+      },
+      FlushFlags(FlushFlags::Initiator::kTraced,
+                 FlushFlags::Reason::kTraceStop));
 }
 
 void TracingServiceImpl::PeriodicFlushTask(TracingSessionID tsid,
@@ -2045,10 +2051,14 @@
     return;
 
   PERFETTO_DLOG("Triggering periodic flush for trace session %" PRIu64, tsid);
-  Flush(tsid, 0, [](bool success) {
-    if (!success)
-      PERFETTO_ELOG("Periodic flush timed out");
-  });
+  Flush(
+      tsid, 0,
+      [](bool success) {
+        if (!success)
+          PERFETTO_ELOG("Periodic flush timed out");
+      },
+      FlushFlags(FlushFlags::Initiator::kTraced,
+                 FlushFlags::Reason::kPeriodic));
 }
 
 void TracingServiceImpl::PeriodicClearIncrementalStateTask(
@@ -3591,6 +3601,7 @@
 void TracingServiceImpl::FlushAndCloneSession(ConsumerEndpointImpl* consumer,
                                               TracingSessionID tsid) {
   PERFETTO_DCHECK_THREAD(thread_checker_);
+  auto clone_target = FlushFlags::CloneTarget::kUnknown;
 
   if (tsid == kBugreportSessionId) {
     TracingSession* session = FindTracingSessionWithMaxBugreportScore();
@@ -3600,21 +3611,26 @@
       return;
     }
     tsid = session->id;
+    clone_target = FlushFlags::CloneTarget::kBugreport;
   }
 
   auto weak_this = weak_ptr_factory_.GetWeakPtr();
   auto weak_consumer = consumer->GetWeakPtr();
-  Flush(tsid, 0, [weak_this, tsid, weak_consumer](bool final_flush_outcome) {
-    PERFETTO_LOG("FlushAndCloneSession(%" PRIu64 ") started, success=%d", tsid,
-                 final_flush_outcome);
-    if (!weak_this || !weak_consumer)
-      return;
-    base::Uuid uuid;
-    base::Status result = weak_this->DoCloneSession(&*weak_consumer, tsid,
-                                                    final_flush_outcome, &uuid);
-    weak_consumer->consumer_->OnSessionCloned(
-        {result.ok(), result.message(), uuid});
-  });
+  Flush(
+      tsid, 0,
+      [weak_this, tsid, weak_consumer](bool final_flush_outcome) {
+        PERFETTO_LOG("FlushAndCloneSession(%" PRIu64 ") started, success=%d",
+                     tsid, final_flush_outcome);
+        if (!weak_this || !weak_consumer)
+          return;
+        base::Uuid uuid;
+        base::Status result = weak_this->DoCloneSession(
+            &*weak_consumer, tsid, final_flush_outcome, &uuid);
+        weak_consumer->consumer_->OnSessionCloned(
+            {result.ok(), result.message(), uuid});
+      },
+      FlushFlags(FlushFlags::Initiator::kTraced,
+                 FlushFlags::Reason::kTraceClone, clone_target));
 }
 
 base::Status TracingServiceImpl::DoCloneSession(ConsumerEndpointImpl* consumer,
@@ -3826,13 +3842,14 @@
 }
 
 void TracingServiceImpl::ConsumerEndpointImpl::Flush(uint32_t timeout_ms,
-                                                     FlushCallback callback) {
+                                                     FlushCallback callback,
+                                                     FlushFlags flush_flags) {
   PERFETTO_DCHECK_THREAD(thread_checker_);
   if (!tracing_session_id_) {
     PERFETTO_LOG("Consumer called Flush() but tracing was not active");
     return;
   }
-  service_->Flush(tracing_session_id_, timeout_ms, callback);
+  service_->Flush(tracing_session_id_, timeout_ms, callback, flush_flags);
 }
 
 void TracingServiceImpl::ConsumerEndpointImpl::Detach(const std::string& key) {
@@ -4319,15 +4336,17 @@
 
 void TracingServiceImpl::ProducerEndpointImpl::Flush(
     FlushRequestID flush_request_id,
-    const std::vector<DataSourceInstanceID>& data_sources) {
+    const std::vector<DataSourceInstanceID>& data_sources,
+    FlushFlags flush_flags) {
   PERFETTO_DCHECK_THREAD(thread_checker_);
   auto weak_this = weak_ptr_factory_.GetWeakPtr();
-  task_runner_->PostTask([weak_this, flush_request_id, data_sources] {
-    if (weak_this) {
-      weak_this->producer_->Flush(flush_request_id, data_sources.data(),
-                                  data_sources.size());
-    }
-  });
+  task_runner_->PostTask(
+      [weak_this, flush_request_id, data_sources, flush_flags] {
+        if (weak_this) {
+          weak_this->producer_->Flush(flush_request_id, data_sources.data(),
+                                      data_sources.size(), flush_flags);
+        }
+      });
 }
 
 void TracingServiceImpl::ProducerEndpointImpl::SetupDataSource(
diff --git a/src/tracing/core/tracing_service_impl.h b/src/tracing/core/tracing_service_impl.h
index 1a146c9..e9c85ee 100644
--- a/src/tracing/core/tracing_service_impl.h
+++ b/src/tracing/core/tracing_service_impl.h
@@ -136,7 +136,9 @@
     void SetupDataSource(DataSourceInstanceID, const DataSourceConfig&);
     void StartDataSource(DataSourceInstanceID, const DataSourceConfig&);
     void StopDataSource(DataSourceInstanceID);
-    void Flush(FlushRequestID, const std::vector<DataSourceInstanceID>&);
+    void Flush(FlushRequestID,
+               const std::vector<DataSourceInstanceID>&,
+               FlushFlags);
     void OnFreeBuffers(const std::vector<BufferID>& target_buffers);
     void ClearIncrementalState(const std::vector<DataSourceInstanceID>&);
 
@@ -219,7 +221,7 @@
     void DisableTracing() override;
     void ReadBuffers() override;
     void FreeBuffers() override;
-    void Flush(uint32_t timeout_ms, FlushCallback) override;
+    void Flush(uint32_t timeout_ms, FlushCallback, FlushFlags) override;
     void Detach(const std::string& key) override;
     void Attach(const std::string& key) override;
     void GetTraceStats() override;
@@ -306,7 +308,8 @@
   void DisableTracing(TracingSessionID, bool disable_immediately = false);
   void Flush(TracingSessionID tsid,
              uint32_t timeout_ms,
-             ConsumerEndpoint::FlushCallback);
+             ConsumerEndpoint::FlushCallback,
+             FlushFlags);
   void FlushAndDisableTracing(TracingSessionID);
   void FlushAndCloneSession(ConsumerEndpointImpl*, TracingSessionID);
 
diff --git a/src/tracing/core/tracing_service_impl_unittest.cc b/src/tracing/core/tracing_service_impl_unittest.cc
index 7583d33..3aa050c 100644
--- a/src/tracing/core/tracing_service_impl_unittest.cc
+++ b/src/tracing/core/tracing_service_impl_unittest.cc
@@ -786,7 +786,8 @@
   bool flushed_writer_1 = false;
   bool flushed_writer_2 = false;
   auto flush_correct_writer = [&](FlushRequestID flush_req_id,
-                                  const DataSourceInstanceID* id, size_t) {
+                                  const DataSourceInstanceID* id, size_t,
+                                  FlushFlags) {
     if (*id == id1) {
       flushed_writer_1 = true;
       writer1->Flush();
@@ -797,7 +798,9 @@
       producer->endpoint()->NotifyFlushComplete(flush_req_id);
     }
   };
-  EXPECT_CALL(*producer, Flush(_, _, _))
+  FlushFlags flush_flags(FlushFlags::Initiator::kTraced,
+                         FlushFlags::Reason::kTraceStop);
+  EXPECT_CALL(*producer, Flush(_, _, _, flush_flags))
       .WillOnce(Invoke(flush_correct_writer))
       .WillOnce(Invoke(flush_correct_writer));
 
@@ -2111,7 +2114,9 @@
       }));
   consumer2->CloneSession(1);
   // CloneSession() will implicitly issue a flush. Linearize with that.
-  producer->ExpectFlush(std::vector<TraceWriter*>{writer.get()});
+  FlushFlags expected_flags(FlushFlags::Initiator::kTraced,
+                            FlushFlags::Reason::kTraceClone);
+  producer->ExpectFlush(writer.get(), /*reply=*/true, expected_flags);
   task_runner.RunUntilCheckpoint("clone_done");
 
   // Delete the initial tracing session.
@@ -2454,7 +2459,9 @@
   }
 
   auto flush_request = consumer->Flush();
-  producer->ExpectFlush(writer.get());
+  FlushFlags expected_flags(FlushFlags::Initiator::kConsumerSdk,
+                            FlushFlags::Reason::kExplicit);
+  producer->ExpectFlush(writer.get(), /*reply=*/true, expected_flags);
   ASSERT_TRUE(flush_request.WaitForReply());
 
   consumer->DisableTracing();
@@ -2492,7 +2499,9 @@
     tp->set_for_testing()->set_str("payload");
   }
 
-  producer->ExpectFlush(writer.get());
+  FlushFlags expected_flags(FlushFlags::Initiator::kTraced,
+                            FlushFlags::Reason::kTraceStop);
+  producer->ExpectFlush(writer.get(), /*reply=*/true, expected_flags);
 
   producer->WaitForDataSourceStop("data_source");
   consumer->WaitForTracingDisabled();
@@ -2591,10 +2600,13 @@
   const int kNumFlushes = 3;
   auto checkpoint = task_runner.CreateCheckpoint("all_flushes_done");
   int flushes_seen = 0;
-  EXPECT_CALL(*producer, Flush(_, _, _))
+  FlushFlags flush_flags(FlushFlags::Initiator::kTraced,
+                         FlushFlags::Reason::kPeriodic);
+  EXPECT_CALL(*producer, Flush(_, _, _, flush_flags))
       .WillRepeatedly(Invoke([&producer, &writer, &flushes_seen, checkpoint](
                                  FlushRequestID flush_req_id,
-                                 const DataSourceInstanceID*, size_t) {
+                                 const DataSourceInstanceID*, size_t,
+                                 FlushFlags) {
         {
           auto tp = writer->NewTracePacket();
           char payload[32];
@@ -4709,6 +4721,10 @@
   std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
   consumer->Connect(svc.get());
 
+  std::unique_ptr<MockProducer> producer = CreateMockProducer();
+  producer->Connect(svc.get(), "mock_producer");
+  producer->RegisterDataSource("ds_1");
+
   // The consumer that clones it and reads back the data.
   std::unique_ptr<MockConsumer> consumer2 = CreateMockConsumer();
   consumer2->Connect(svc.get(), 1234);
@@ -4716,9 +4732,18 @@
   TraceConfig trace_config;
   trace_config.add_buffers()->set_size_kb(32);
   trace_config.set_bugreport_score(1);
+  auto* ds_cfg = trace_config.add_data_sources()->mutable_config();
+  ds_cfg->set_name("ds_1");
 
+  EXPECT_CALL(*producer, SetupDataSource(_, _));
+  EXPECT_CALL(*producer, StartDataSource(_, _));
   consumer->EnableTracing(trace_config);
+  producer->WaitForTracingSetup();
+
   auto flush_request = consumer->Flush();
+  FlushFlags flush_flags(FlushFlags::Initiator::kConsumerSdk,
+                         FlushFlags::Reason::kExplicit);
+  producer->ExpectFlush({}, /*reply=*/true, flush_flags);
   ASSERT_TRUE(flush_request.WaitForReply());
 
   auto clone_done = task_runner.CreateCheckpoint("clone_done");
@@ -4727,7 +4752,13 @@
         clone_done();
         ASSERT_TRUE(args.success);
       }));
-  consumer2->CloneSession(1);
+
+  FlushFlags flush_flags2(FlushFlags::Initiator::kTraced,
+                          FlushFlags::Reason::kTraceClone,
+                          FlushFlags::CloneTarget::kBugreport);
+  producer->ExpectFlush({}, /*reply=*/true, flush_flags2);
+
+  consumer2->CloneSession(kBugreportSessionId);
   task_runner.RunUntilCheckpoint("clone_done");
 }
 
diff --git a/src/tracing/core/virtual_destructors.cc b/src/tracing/core/virtual_destructors.cc
index d38a776..6c94741 100644
--- a/src/tracing/core/virtual_destructors.cc
+++ b/src/tracing/core/virtual_destructors.cc
@@ -40,4 +40,18 @@
 void ConsumerEndpoint::CloneSession(TracingSessionID) {}
 void Consumer::OnSessionCloned(const OnSessionClonedArgs&) {}
 
+void ConsumerEndpoint::Flush(uint32_t, FlushCallback, FlushFlags) {
+  // In the perfetto codebase, this 3-arg Flush is always overridden and this
+  // FATAL is never reached. The only case where this is used is in
+  // arctraceservice's PerfettoClient_test.cpp. That test mocks the old
+  // 2-arg version of Flush but doesn't actually invoke the 3-arg version.
+  PERFETTO_FATAL("ConsumerEndpoint::Flush(3) not implemented");
+}
+
+void ConsumerEndpoint::Flush(uint32_t timeout_ms, FlushCallback callback) {
+  // This 2-arg version of Flush() is invoked by arctraceservice's
+  // PerfettoClient::Flush().
+  Flush(timeout_ms, std::move(callback), FlushFlags(0));
+}
+
 }  // namespace perfetto
diff --git a/src/tracing/internal/tracing_backend_fake.cc b/src/tracing/internal/tracing_backend_fake.cc
index 4b0d31e..438da32 100644
--- a/src/tracing/internal/tracing_backend_fake.cc
+++ b/src/tracing/internal/tracing_backend_fake.cc
@@ -115,7 +115,9 @@
   void StartTracing() override {}
   void DisableTracing() override {}
 
-  void Flush(uint32_t /*timeout_ms*/, FlushCallback callback) override {
+  void Flush(uint32_t /*timeout_ms*/,
+             FlushCallback callback,
+             FlushFlags) override {
     callback(/*success=*/false);
   }
 
diff --git a/src/tracing/internal/tracing_muxer_impl.cc b/src/tracing/internal/tracing_muxer_impl.cc
index e953823..738cf31 100644
--- a/src/tracing/internal/tracing_muxer_impl.cc
+++ b/src/tracing/internal/tracing_muxer_impl.cc
@@ -296,14 +296,15 @@
 void TracingMuxerImpl::ProducerImpl::Flush(
     FlushRequestID flush_id,
     const DataSourceInstanceID* instances,
-    size_t instance_count) {
+    size_t instance_count,
+    FlushFlags flush_flags) {
   PERFETTO_DCHECK_THREAD(thread_checker_);
   bool all_handled = true;
   if (muxer_) {
     for (size_t i = 0; i < instance_count; i++) {
       DataSourceInstanceID ds_id = instances[i];
-      bool handled =
-          muxer_->FlushDataSource_AsyncBegin(backend_id_, ds_id, flush_id);
+      bool handled = muxer_->FlushDataSource_AsyncBegin(backend_id_, ds_id,
+                                                        flush_id, flush_flags);
       if (!handled) {
         pending_flushes_[flush_id].insert(ds_id);
         all_handled = false;
@@ -1115,34 +1116,33 @@
     InterceptorFactory factory,
     InterceptorBase::TLSFactory tls_factory,
     InterceptorBase::TracePacketCallback packet_callback) {
-  task_runner_->PostTask(
-      [this, descriptor, factory, tls_factory, packet_callback] {
-        // Ignore repeated registrations.
-        for (const auto& interceptor : interceptors_) {
-          if (interceptor.descriptor.name() == descriptor.name()) {
-            PERFETTO_DCHECK(interceptor.tls_factory == tls_factory);
-            PERFETTO_DCHECK(interceptor.packet_callback == packet_callback);
-            return;
-          }
-        }
-        // Only allow certain interceptors for now.
-        if (descriptor.name() != "test_interceptor" &&
-            descriptor.name() != "console" &&
-            descriptor.name() != "etwexport") {
-          PERFETTO_ELOG(
-              "Interceptors are experimental. If you want to use them, please "
-              "get in touch with the project maintainers "
-              "(https://perfetto.dev/docs/contributing/"
-              "getting-started#community).");
-          return;
-        }
-        interceptors_.emplace_back();
-        RegisteredInterceptor& interceptor = interceptors_.back();
-        interceptor.descriptor = descriptor;
-        interceptor.factory = factory;
-        interceptor.tls_factory = tls_factory;
-        interceptor.packet_callback = packet_callback;
-      });
+  task_runner_->PostTask([this, descriptor, factory, tls_factory,
+                          packet_callback] {
+    // Ignore repeated registrations.
+    for (const auto& interceptor : interceptors_) {
+      if (interceptor.descriptor.name() == descriptor.name()) {
+        PERFETTO_DCHECK(interceptor.tls_factory == tls_factory);
+        PERFETTO_DCHECK(interceptor.packet_callback == packet_callback);
+        return;
+      }
+    }
+    // Only allow certain interceptors for now.
+    if (descriptor.name() != "test_interceptor" &&
+        descriptor.name() != "console" && descriptor.name() != "etwexport") {
+      PERFETTO_ELOG(
+          "Interceptors are experimental. If you want to use them, please "
+          "get in touch with the project maintainers "
+          "(https://perfetto.dev/docs/contributing/"
+          "getting-started#community).");
+      return;
+    }
+    interceptors_.emplace_back();
+    RegisteredInterceptor& interceptor = interceptors_.back();
+    interceptor.descriptor = descriptor;
+    interceptor.factory = factory;
+    interceptor.tls_factory = tls_factory;
+    interceptor.packet_callback = packet_callback;
+  });
 }
 
 void TracingMuxerImpl::ActivateTriggers(
@@ -1629,7 +1629,8 @@
 bool TracingMuxerImpl::FlushDataSource_AsyncBegin(
     TracingBackendId backend_id,
     DataSourceInstanceID instance_id,
-    FlushRequestID flush_id) {
+    FlushRequestID flush_id,
+    FlushFlags flush_flags) {
   PERFETTO_DLOG("Flushing data source %" PRIu64, instance_id);
   auto ds = FindDataSource(backend_id, instance_id);
   if (!ds) {
@@ -1640,6 +1641,7 @@
   uint32_t backend_connection_id = ds.internal_state->backend_connection_id;
 
   FlushArgsImpl flush_args;
+  flush_args.flush_flags = flush_flags;
   flush_args.internal_instance_index = ds.instance_idx;
   flush_args.async_flush_closure = [this, backend_id, backend_connection_id,
                                     instance_id, ds, flush_id] {
@@ -1924,7 +1926,11 @@
     return;
   }
 
-  consumer->service_->Flush(timeout_ms, std::move(callback));
+  // For now we don't want to expose the flush reason to the consumer-side SDK
+  // users to avoid misuses until there is a strong need.
+  consumer->service_->Flush(timeout_ms, std::move(callback),
+                            FlushFlags(FlushFlags::Initiator::kConsumerSdk,
+                                       FlushFlags::Reason::kExplicit));
 }
 
 void TracingMuxerImpl::StopTracingSession(TracingSessionGlobalID session_id) {
diff --git a/src/tracing/internal/tracing_muxer_impl.h b/src/tracing/internal/tracing_muxer_impl.h
index 220f96b..ab132f3 100644
--- a/src/tracing/internal/tracing_muxer_impl.h
+++ b/src/tracing/internal/tracing_muxer_impl.h
@@ -228,7 +228,10 @@
     void StartDataSource(DataSourceInstanceID,
                          const DataSourceConfig&) override;
     void StopDataSource(DataSourceInstanceID) override;
-    void Flush(FlushRequestID, const DataSourceInstanceID*, size_t) override;
+    void Flush(FlushRequestID,
+               const DataSourceInstanceID*,
+               size_t,
+               FlushFlags) override;
     void ClearIncrementalState(const DataSourceInstanceID*, size_t) override;
 
     bool SweepDeadServices();
@@ -511,7 +514,8 @@
                                const FindDataSourceRes&);
   bool FlushDataSource_AsyncBegin(TracingBackendId,
                                   DataSourceInstanceID,
-                                  FlushRequestID);
+                                  FlushRequestID,
+                                  FlushFlags);
   void FlushDataSource_AsyncEnd(TracingBackendId,
                                 uint32_t backend_connection_id,
                                 DataSourceInstanceID,
diff --git a/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc b/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc
index cf34361..a729d3b 100644
--- a/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc
+++ b/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc
@@ -221,7 +221,9 @@
   consumer_port_.FreeBuffers(req, std::move(async_response));
 }
 
-void ConsumerIPCClientImpl::Flush(uint32_t timeout_ms, FlushCallback callback) {
+void ConsumerIPCClientImpl::Flush(uint32_t timeout_ms,
+                                  FlushCallback callback,
+                                  FlushFlags flush_flags) {
   if (!connected_) {
     PERFETTO_DLOG("Cannot Flush(), not connected to tracing service");
     return callback(/*success=*/false);
@@ -229,6 +231,7 @@
 
   protos::gen::FlushRequest req;
   req.set_timeout_ms(static_cast<uint32_t>(timeout_ms));
+  req.set_flags(flush_flags.flags());
   ipc::Deferred<protos::gen::FlushResponse> async_response;
   async_response.Bind(
       [callback](ipc::AsyncResult<protos::gen::FlushResponse> response) {
diff --git a/src/tracing/ipc/consumer/consumer_ipc_client_impl.h b/src/tracing/ipc/consumer/consumer_ipc_client_impl.h
index 71f4968..eba824f 100644
--- a/src/tracing/ipc/consumer/consumer_ipc_client_impl.h
+++ b/src/tracing/ipc/consumer/consumer_ipc_client_impl.h
@@ -66,7 +66,7 @@
   void DisableTracing() override;
   void ReadBuffers() override;
   void FreeBuffers() override;
-  void Flush(uint32_t timeout_ms, FlushCallback) override;
+  void Flush(uint32_t timeout_ms, FlushCallback, FlushFlags) override;
   void Detach(const std::string& key) override;
   void Attach(const std::string& key) override;
   void GetTraceStats() override;
diff --git a/src/tracing/ipc/producer/producer_ipc_client_impl.cc b/src/tracing/ipc/producer/producer_ipc_client_impl.cc
index 6caf224..ea87953 100644
--- a/src/tracing/ipc/producer/producer_ipc_client_impl.cc
+++ b/src/tracing/ipc/producer/producer_ipc_client_impl.cc
@@ -374,10 +374,12 @@
     const auto* data_source_ids = cmd.flush().data_source_ids().data();
     static_assert(sizeof(data_source_ids[0]) == sizeof(DataSourceInstanceID),
                   "data_source_ids should be 64-bit");
+
+    FlushFlags flags(cmd.flush().flags());
     producer_->Flush(
         cmd.flush().request_id(),
         reinterpret_cast<const DataSourceInstanceID*>(data_source_ids),
-        static_cast<size_t>(cmd.flush().data_source_ids().size()));
+        static_cast<size_t>(cmd.flush().data_source_ids().size()), flags);
     return;
   }
 
diff --git a/src/tracing/ipc/service/consumer_ipc_service.cc b/src/tracing/ipc/service/consumer_ipc_service.cc
index ac52864..3e01316 100644
--- a/src/tracing/ipc/service/consumer_ipc_service.cc
+++ b/src/tracing/ipc/service/consumer_ipc_service.cc
@@ -129,8 +129,9 @@
     if (weak_this)
       weak_this->OnFlushCallback(success, std::move(it));
   };
-  GetConsumerForCurrentRequest()->service_endpoint->Flush(req.timeout_ms(),
-                                                          std::move(callback));
+  FlushFlags flags(req.flags());
+  GetConsumerForCurrentRequest()->service_endpoint->Flush(
+      req.timeout_ms(), std::move(callback), flags);
 }
 
 // Called by the IPC layer.
diff --git a/src/tracing/ipc/service/producer_ipc_service.cc b/src/tracing/ipc/service/producer_ipc_service.cc
index d13130a..3208096 100644
--- a/src/tracing/ipc/service/producer_ipc_service.cc
+++ b/src/tracing/ipc/service/producer_ipc_service.cc
@@ -506,7 +506,8 @@
 void ProducerIPCService::RemoteProducer::Flush(
     FlushRequestID flush_request_id,
     const DataSourceInstanceID* data_source_ids,
-    size_t num_data_sources) {
+    size_t num_data_sources,
+    FlushFlags flush_flags) {
   if (!async_producer_commands.IsBound()) {
     PERFETTO_DLOG(
         "The Service tried to request a flush but the remote Producer has not "
@@ -518,6 +519,7 @@
   for (size_t i = 0; i < num_data_sources; i++)
     cmd->mutable_flush()->add_data_source_ids(data_source_ids[i]);
   cmd->mutable_flush()->set_request_id(flush_request_id);
+  cmd->mutable_flush()->set_flags(flush_flags.flags());
   async_producer_commands.Resolve(std::move(cmd));
 }
 
diff --git a/src/tracing/ipc/service/producer_ipc_service.h b/src/tracing/ipc/service/producer_ipc_service.h
index b42ed73..dffba9d 100644
--- a/src/tracing/ipc/service/producer_ipc_service.h
+++ b/src/tracing/ipc/service/producer_ipc_service.h
@@ -93,7 +93,8 @@
     void OnTracingSetup() override;
     void Flush(FlushRequestID,
                const DataSourceInstanceID* data_source_ids,
-               size_t num_data_sources) override;
+               size_t num_data_sources,
+               FlushFlags) override;
 
     void ClearIncrementalState(const DataSourceInstanceID* data_source_ids,
                                size_t num_data_sources) override;
diff --git a/src/tracing/test/api_integrationtest.cc b/src/tracing/test/api_integrationtest.cc
index a363089..3ba6aab 100644
--- a/src/tracing/test/api_integrationtest.cc
+++ b/src/tracing/test/api_integrationtest.cc
@@ -282,7 +282,7 @@
   bool handle_flush_asynchronously = false;
   std::function<void()> on_start_callback;
   std::function<void()> on_stop_callback;
-  std::function<void()> on_flush_callback;
+  std::function<void(perfetto::FlushFlags)> on_flush_callback;
   std::function<void()> async_stop_closure;
   std::function<void()> async_flush_closure;
 };
@@ -949,8 +949,9 @@
   EXPECT_NE(handle_, nullptr);
   if (handle_->handle_flush_asynchronously)
     handle_->async_flush_closure = args.HandleFlushAsynchronously();
-  if (handle_->on_flush_callback)
-    handle_->on_flush_callback();
+  if (handle_->on_flush_callback) {
+    handle_->on_flush_callback(args.flush_flags);
+  }
   handle_->on_flush.Notify();
 }
 
@@ -4224,8 +4225,11 @@
   WaitableTestEvent producer_on_flush;
   WaitableTestEvent consumer_flush_done;
 
-  data_source->on_flush_callback = [&] {
+  data_source->on_flush_callback = [&](perfetto::FlushFlags flush_flags) {
     EXPECT_FALSE(consumer_flush_done.notified());
+    EXPECT_EQ(flush_flags.initiator(),
+              perfetto::FlushFlags::Initiator::kConsumerSdk);
+    EXPECT_EQ(flush_flags.reason(), perfetto::FlushFlags::Reason::kExplicit);
     producer_on_flush.Notify();
     MockDataSource::Trace([](MockDataSource::TraceContext ctx) {
       ctx.NewTracePacket()->set_for_testing()->set_str("on-flush");
@@ -4275,7 +4279,7 @@
   WaitableTestEvent consumer_flush_done;
 
   data_source->handle_flush_asynchronously = true;
-  data_source->on_flush_callback = [&] {
+  data_source->on_flush_callback = [&](perfetto::FlushFlags) {
     EXPECT_FALSE(consumer_flush_done.notified());
   };
 
diff --git a/src/tracing/test/mock_consumer.cc b/src/tracing/test/mock_consumer.cc
index e24ffcc..6601681 100644
--- a/src/tracing/test/mock_consumer.cc
+++ b/src/tracing/test/mock_consumer.cc
@@ -91,15 +91,19 @@
   task_runner_->RunUntilCheckpoint(checkpoint_name, timeout_ms);
 }
 
-MockConsumer::FlushRequest MockConsumer::Flush(uint32_t timeout_ms) {
+MockConsumer::FlushRequest MockConsumer::Flush(uint32_t timeout_ms,
+                                               FlushFlags flush_flags) {
   static int i = 0;
   auto checkpoint_name = "on_consumer_flush_" + std::to_string(i++);
   auto on_flush = task_runner_->CreateCheckpoint(checkpoint_name);
   std::shared_ptr<bool> result(new bool());
-  service_endpoint_->Flush(timeout_ms, [result, on_flush](bool success) {
-    *result = success;
-    on_flush();
-  });
+  service_endpoint_->Flush(
+      timeout_ms,
+      [result, on_flush](bool success) {
+        *result = success;
+        on_flush();
+      },
+      flush_flags);
 
   base::TestTaskRunner* task_runner = task_runner_;
   auto wait_for_flush_completion = [result, task_runner,
diff --git a/src/tracing/test/mock_consumer.h b/src/tracing/test/mock_consumer.h
index 2253d93..b7d8d0a 100644
--- a/src/tracing/test/mock_consumer.h
+++ b/src/tracing/test/mock_consumer.h
@@ -56,7 +56,10 @@
   void DisableTracing();
   void FreeBuffers();
   void WaitForTracingDisabled(uint32_t timeout_ms = 3000);
-  FlushRequest Flush(uint32_t timeout_ms = 10000);
+  FlushRequest Flush(
+      uint32_t timeout_ms = 10000,
+      FlushFlags = FlushFlags(FlushFlags::Initiator::kConsumerSdk,
+                              FlushFlags::Reason::kExplicit));
   std::vector<protos::gen::TracePacket> ReadBuffers();
   void GetTraceStats();
   TraceStats WaitForTraceStats(bool success);
diff --git a/src/tracing/test/mock_producer.cc b/src/tracing/test/mock_producer.cc
index 84ca4ee..ef40dd6 100644
--- a/src/tracing/test/mock_producer.cc
+++ b/src/tracing/test/mock_producer.cc
@@ -192,23 +192,32 @@
   return service_endpoint_->CreateTraceWriter(buf_id);
 }
 
-void MockProducer::ExpectFlush(TraceWriter* writer_to_flush, bool reply) {
+void MockProducer::ExpectFlush(TraceWriter* writer_to_flush,
+                               bool reply,
+                               FlushFlags expected_flags) {
   std::vector<TraceWriter*> writers;
   if (writer_to_flush)
     writers.push_back(writer_to_flush);
-  ExpectFlush(writers, reply);
+  ExpectFlush(writers, reply, expected_flags);
 }
 
 void MockProducer::ExpectFlush(std::vector<TraceWriter*> writers_to_flush,
-                               bool reply) {
-  auto& expected_call = EXPECT_CALL(*this, Flush(_, _, _));
-  expected_call.WillOnce(Invoke(
-      [this, writers_to_flush, reply](FlushRequestID flush_req_id,
-                                      const DataSourceInstanceID*, size_t) {
-        for (auto* writer : writers_to_flush)
+                               bool reply,
+                               FlushFlags expected_flags) {
+  auto& expected_call = EXPECT_CALL(*this, Flush(_, _, _, _));
+  expected_call.WillOnce(
+      Invoke([this, writers_to_flush, reply, expected_flags](
+                 FlushRequestID flush_req_id, const DataSourceInstanceID*,
+                 size_t, FlushFlags actual_flags) {
+        if (expected_flags.flags()) {
+          EXPECT_EQ(actual_flags, expected_flags);
+        }
+        for (auto* writer : writers_to_flush) {
           writer->Flush();
-        if (reply)
+        }
+        if (reply) {
           service_endpoint_->NotifyFlushComplete(flush_req_id);
+        }
       }));
 }
 
diff --git a/src/tracing/test/mock_producer.h b/src/tracing/test/mock_producer.h
index 932bd9c..d259a18 100644
--- a/src/tracing/test/mock_producer.h
+++ b/src/tracing/test/mock_producer.h
@@ -76,10 +76,13 @@
 
   // Expect a flush. Flushes |writer_to_flush| if non-null. If |reply| is true,
   // replies to the flush request, otherwise ignores it and doesn't reply.
-  void ExpectFlush(TraceWriter* writer_to_flush, bool reply = true);
+  void ExpectFlush(TraceWriter* writer_to_flush,
+                   bool reply = true,
+                   FlushFlags expected_flags = FlushFlags());
   // Same as above, but with a vector of writers.
   void ExpectFlush(std::vector<TraceWriter*> writers_to_flush,
-                   bool reply = true);
+                   bool reply = true,
+                   FlushFlags expected_flags = FlushFlags());
 
   TracingService::ProducerEndpoint* endpoint() {
     return service_endpoint_.get();
@@ -100,7 +103,7 @@
   MOCK_METHOD(void, OnTracingSetup, (), (override));
   MOCK_METHOD(void,
               Flush,
-              (FlushRequestID, const DataSourceInstanceID*, size_t),
+              (FlushRequestID, const DataSourceInstanceID*, size_t, FlushFlags),
               (override));
   MOCK_METHOD(void,
               ClearIncrementalState,
diff --git a/src/tracing/test/tracing_integration_test.cc b/src/tracing/test/tracing_integration_test.cc
index 29949a8..3d48453 100644
--- a/src/tracing/test/tracing_integration_test.cc
+++ b/src/tracing/test/tracing_integration_test.cc
@@ -73,7 +73,7 @@
   MOCK_METHOD(void, OnTracingSetup, (), (override));
   MOCK_METHOD(void,
               Flush,
-              (FlushRequestID, const DataSourceInstanceID*, size_t),
+              (FlushRequestID, const DataSourceInstanceID*, size_t, FlushFlags),
               (override));
   MOCK_METHOD(void,
               ClearIncrementalState,
@@ -525,13 +525,18 @@
   // Ask the service to flush, but don't flush our trace writer. This should
   // cause our uncommitted SMB chunk to be scraped.
   auto on_flush_complete = task_runner_->CreateCheckpoint("on_flush_complete");
-  consumer_endpoint_->Flush(5000, [on_flush_complete](bool success) {
-    EXPECT_TRUE(success);
-    on_flush_complete();
-  });
-  EXPECT_CALL(producer_, Flush(_, _, _))
+  FlushFlags flush_flags(FlushFlags::Initiator::kConsumerSdk,
+                         FlushFlags::Reason::kExplicit);
+  consumer_endpoint_->Flush(
+      5000,
+      [on_flush_complete](bool success) {
+        EXPECT_TRUE(success);
+        on_flush_complete();
+      },
+      flush_flags);
+  EXPECT_CALL(producer_, Flush(_, _, _, flush_flags))
       .WillOnce(Invoke([this](FlushRequestID flush_req_id,
-                              const DataSourceInstanceID*, size_t) {
+                              const DataSourceInstanceID*, size_t, FlushFlags) {
         producer_endpoint_->NotifyFlushComplete(flush_req_id);
       }));
   task_runner_->RunUntilCheckpoint("on_flush_complete");
diff --git a/test/end_to_end_shared_memory_fuzzer.cc b/test/end_to_end_shared_memory_fuzzer.cc
index adde520..05f1eab 100644
--- a/test/end_to_end_shared_memory_fuzzer.cc
+++ b/test/end_to_end_shared_memory_fuzzer.cc
@@ -96,7 +96,10 @@
 
   void StopDataSource(DataSourceInstanceID) override {}
   void OnTracingSetup() override {}
-  void Flush(FlushRequestID, const DataSourceInstanceID*, size_t) override {}
+  void Flush(FlushRequestID,
+             const DataSourceInstanceID*,
+             size_t,
+             FlushFlags) override {}
   void ClearIncrementalState(const DataSourceInstanceID*, size_t) override {}
 
  private:
diff --git a/test/fake_producer.cc b/test/fake_producer.cc
index 90c3932..46308f5 100644
--- a/test/fake_producer.cc
+++ b/test/fake_producer.cc
@@ -160,7 +160,8 @@
 
 void FakeProducer::Flush(FlushRequestID flush_request_id,
                          const DataSourceInstanceID*,
-                         size_t num_data_sources) {
+                         size_t num_data_sources,
+                         FlushFlags) {
   PERFETTO_DCHECK(num_data_sources > 0);
   if (trace_writer_)
     trace_writer_->Flush();
diff --git a/test/fake_producer.h b/test/fake_producer.h
index 5922165..0b16590 100644
--- a/test/fake_producer.h
+++ b/test/fake_producer.h
@@ -79,7 +79,10 @@
                        const DataSourceConfig& source_config) override;
   void StopDataSource(DataSourceInstanceID) override;
   void OnTracingSetup() override;
-  void Flush(FlushRequestID, const DataSourceInstanceID*, size_t) override;
+  void Flush(FlushRequestID,
+             const DataSourceInstanceID*,
+             size_t,
+             FlushFlags) override;
   void ClearIncrementalState(const DataSourceInstanceID* /*data_source_ids*/,
                              size_t /*num_data_sources*/) override {}
 
diff --git a/test/test_helper.cc b/test/test_helper.cc
index 6054f3f..f991837 100644
--- a/test/test_helper.cc
+++ b/test/test_helper.cc
@@ -209,11 +209,12 @@
   endpoint_->DisableTracing();
 }
 
-void TestHelper::FlushAndWait(uint32_t timeout_ms) {
+void TestHelper::FlushAndWait(uint32_t timeout_ms, FlushFlags flush_flags) {
   static int flush_num = 0;
   std::string checkpoint_name = "flush." + std::to_string(flush_num++);
   auto checkpoint = CreateCheckpoint(checkpoint_name);
-  endpoint_->Flush(timeout_ms, [checkpoint](bool) { checkpoint(); });
+  endpoint_->Flush(
+      timeout_ms, [checkpoint](bool) { checkpoint(); }, flush_flags);
   RunUntilCheckpoint(checkpoint_name, timeout_ms + 1000);
 }
 
diff --git a/test/test_helper.h b/test/test_helper.h
index ba00422..91b955d 100644
--- a/test/test_helper.h
+++ b/test/test_helper.h
@@ -314,7 +314,7 @@
   void StartTracing(const TraceConfig& config,
                     base::ScopedFile = base::ScopedFile());
   void DisableTracing();
-  void FlushAndWait(uint32_t timeout_ms);
+  void FlushAndWait(uint32_t timeout_ms, FlushFlags = FlushFlags());
   void ReadData(uint32_t read_count = 0);
   void FreeBuffers();
   void DetachConsumer(const std::string& key);