Merge changes I7c27ae03,I5a8b068e

* changes:
  tp: support multiple queries being passed to ExecuteQuery
  tp: remove time queued
diff --git a/Android.bp b/Android.bp
index 3a2bdee..5d40cca 100644
--- a/Android.bp
+++ b/Android.bp
@@ -4175,6 +4175,7 @@
         "protos/perfetto/trace/ftrace/scm.proto",
         "protos/perfetto/trace/ftrace/sde.proto",
         "protos/perfetto/trace/ftrace/signal.proto",
+        "protos/perfetto/trace/ftrace/sock.proto",
         "protos/perfetto/trace/ftrace/sync.proto",
         "protos/perfetto/trace/ftrace/synthetic.proto",
         "protos/perfetto/trace/ftrace/systrace.proto",
@@ -4394,6 +4395,7 @@
         "protos/perfetto/trace/ftrace/scm.proto",
         "protos/perfetto/trace/ftrace/sde.proto",
         "protos/perfetto/trace/ftrace/signal.proto",
+        "protos/perfetto/trace/ftrace/sock.proto",
         "protos/perfetto/trace/ftrace/sync.proto",
         "protos/perfetto/trace/ftrace/synthetic.proto",
         "protos/perfetto/trace/ftrace/systrace.proto",
@@ -4447,6 +4449,7 @@
         "external/perfetto/protos/perfetto/trace/ftrace/scm.gen.cc",
         "external/perfetto/protos/perfetto/trace/ftrace/sde.gen.cc",
         "external/perfetto/protos/perfetto/trace/ftrace/signal.gen.cc",
+        "external/perfetto/protos/perfetto/trace/ftrace/sock.gen.cc",
         "external/perfetto/protos/perfetto/trace/ftrace/sync.gen.cc",
         "external/perfetto/protos/perfetto/trace/ftrace/synthetic.gen.cc",
         "external/perfetto/protos/perfetto/trace/ftrace/systrace.gen.cc",
@@ -4500,6 +4503,7 @@
         "protos/perfetto/trace/ftrace/scm.proto",
         "protos/perfetto/trace/ftrace/sde.proto",
         "protos/perfetto/trace/ftrace/signal.proto",
+        "protos/perfetto/trace/ftrace/sock.proto",
         "protos/perfetto/trace/ftrace/sync.proto",
         "protos/perfetto/trace/ftrace/synthetic.proto",
         "protos/perfetto/trace/ftrace/systrace.proto",
@@ -4553,6 +4557,7 @@
         "external/perfetto/protos/perfetto/trace/ftrace/scm.gen.h",
         "external/perfetto/protos/perfetto/trace/ftrace/sde.gen.h",
         "external/perfetto/protos/perfetto/trace/ftrace/signal.gen.h",
+        "external/perfetto/protos/perfetto/trace/ftrace/sock.gen.h",
         "external/perfetto/protos/perfetto/trace/ftrace/sync.gen.h",
         "external/perfetto/protos/perfetto/trace/ftrace/synthetic.gen.h",
         "external/perfetto/protos/perfetto/trace/ftrace/systrace.gen.h",
@@ -4610,6 +4615,7 @@
         "protos/perfetto/trace/ftrace/scm.proto",
         "protos/perfetto/trace/ftrace/sde.proto",
         "protos/perfetto/trace/ftrace/signal.proto",
+        "protos/perfetto/trace/ftrace/sock.proto",
         "protos/perfetto/trace/ftrace/sync.proto",
         "protos/perfetto/trace/ftrace/synthetic.proto",
         "protos/perfetto/trace/ftrace/systrace.proto",
@@ -4662,6 +4668,7 @@
         "external/perfetto/protos/perfetto/trace/ftrace/scm.pb.cc",
         "external/perfetto/protos/perfetto/trace/ftrace/sde.pb.cc",
         "external/perfetto/protos/perfetto/trace/ftrace/signal.pb.cc",
+        "external/perfetto/protos/perfetto/trace/ftrace/sock.pb.cc",
         "external/perfetto/protos/perfetto/trace/ftrace/sync.pb.cc",
         "external/perfetto/protos/perfetto/trace/ftrace/synthetic.pb.cc",
         "external/perfetto/protos/perfetto/trace/ftrace/systrace.pb.cc",
@@ -4715,6 +4722,7 @@
         "protos/perfetto/trace/ftrace/scm.proto",
         "protos/perfetto/trace/ftrace/sde.proto",
         "protos/perfetto/trace/ftrace/signal.proto",
+        "protos/perfetto/trace/ftrace/sock.proto",
         "protos/perfetto/trace/ftrace/sync.proto",
         "protos/perfetto/trace/ftrace/synthetic.proto",
         "protos/perfetto/trace/ftrace/systrace.proto",
@@ -4767,6 +4775,7 @@
         "external/perfetto/protos/perfetto/trace/ftrace/scm.pb.h",
         "external/perfetto/protos/perfetto/trace/ftrace/sde.pb.h",
         "external/perfetto/protos/perfetto/trace/ftrace/signal.pb.h",
+        "external/perfetto/protos/perfetto/trace/ftrace/sock.pb.h",
         "external/perfetto/protos/perfetto/trace/ftrace/sync.pb.h",
         "external/perfetto/protos/perfetto/trace/ftrace/synthetic.pb.h",
         "external/perfetto/protos/perfetto/trace/ftrace/systrace.pb.h",
@@ -4824,6 +4833,7 @@
         "protos/perfetto/trace/ftrace/scm.proto",
         "protos/perfetto/trace/ftrace/sde.proto",
         "protos/perfetto/trace/ftrace/signal.proto",
+        "protos/perfetto/trace/ftrace/sock.proto",
         "protos/perfetto/trace/ftrace/sync.proto",
         "protos/perfetto/trace/ftrace/synthetic.proto",
         "protos/perfetto/trace/ftrace/systrace.proto",
@@ -4877,6 +4887,7 @@
         "external/perfetto/protos/perfetto/trace/ftrace/scm.pbzero.cc",
         "external/perfetto/protos/perfetto/trace/ftrace/sde.pbzero.cc",
         "external/perfetto/protos/perfetto/trace/ftrace/signal.pbzero.cc",
+        "external/perfetto/protos/perfetto/trace/ftrace/sock.pbzero.cc",
         "external/perfetto/protos/perfetto/trace/ftrace/sync.pbzero.cc",
         "external/perfetto/protos/perfetto/trace/ftrace/synthetic.pbzero.cc",
         "external/perfetto/protos/perfetto/trace/ftrace/systrace.pbzero.cc",
@@ -4930,6 +4941,7 @@
         "protos/perfetto/trace/ftrace/scm.proto",
         "protos/perfetto/trace/ftrace/sde.proto",
         "protos/perfetto/trace/ftrace/signal.proto",
+        "protos/perfetto/trace/ftrace/sock.proto",
         "protos/perfetto/trace/ftrace/sync.proto",
         "protos/perfetto/trace/ftrace/synthetic.proto",
         "protos/perfetto/trace/ftrace/systrace.proto",
@@ -4983,6 +4995,7 @@
         "external/perfetto/protos/perfetto/trace/ftrace/scm.pbzero.h",
         "external/perfetto/protos/perfetto/trace/ftrace/sde.pbzero.h",
         "external/perfetto/protos/perfetto/trace/ftrace/signal.pbzero.h",
+        "external/perfetto/protos/perfetto/trace/ftrace/sock.pbzero.h",
         "external/perfetto/protos/perfetto/trace/ftrace/sync.pbzero.h",
         "external/perfetto/protos/perfetto/trace/ftrace/synthetic.pbzero.h",
         "external/perfetto/protos/perfetto/trace/ftrace/systrace.pbzero.h",
diff --git a/BUILD b/BUILD
index c5a3241..081c6f2 100644
--- a/BUILD
+++ b/BUILD
@@ -1264,6 +1264,7 @@
         "src/trace_processor/types/softirq_action.h",
         "src/trace_processor/types/task_state.cc",
         "src/trace_processor/types/task_state.h",
+        "src/trace_processor/types/tcp_state.h",
         "src/trace_processor/types/trace_processor_context.h",
         "src/trace_processor/types/variadic.cc",
         "src/trace_processor/types/variadic.h",
@@ -2880,6 +2881,7 @@
         "protos/perfetto/trace/ftrace/scm.proto",
         "protos/perfetto/trace/ftrace/sde.proto",
         "protos/perfetto/trace/ftrace/signal.proto",
+        "protos/perfetto/trace/ftrace/sock.proto",
         "protos/perfetto/trace/ftrace/sync.proto",
         "protos/perfetto/trace/ftrace/synthetic.proto",
         "protos/perfetto/trace/ftrace/systrace.proto",
diff --git a/protos/perfetto/config/perfetto_config.proto b/protos/perfetto/config/perfetto_config.proto
index b023de2..f420205 100644
--- a/protos/perfetto/config/perfetto_config.proto
+++ b/protos/perfetto/config/perfetto_config.proto
@@ -1596,7 +1596,7 @@
 // It contains the general config for the logging buffer(s) and the configs for
 // all the data source being enabled.
 //
-// Next id: 34.
+// Next id: 35.
 message TraceConfig {
   message BufferConfig {
     optional uint32 size_kb = 1;
@@ -2007,6 +2007,54 @@
   // old field number for trace_filter
   reserved 32;
   optional TraceFilter trace_filter = 33;
+
+  // Android-only. Not for general use. If set, reports the trace to the
+  // Android framework. This field is read by perfetto_cmd, rather than the
+  // tracing service. This field must be set when passing the --upload flag to
+  // perfetto_cmd.
+  message AndroidReportConfig {
+    // In this message, either:
+    //  * |reporter_service_package| and |reporter_service_class| must be set.
+    //  * |skip_reporting| must be explicitly set to true.
+
+    optional string reporter_service_package = 1;
+    optional string reporter_service_class = 2;
+
+    // If true, then skips reporting the trace to Android framework.
+    //
+    // This flag is useful in testing (e.g. Perfetto-statsd integration tests)
+    // or when we explicitly don't want to report traces to the framework even
+    // when they usually would (e.g. configs deployed using statsd but only
+    // used for inclusion in bugreports using |bugreport_score|).
+    //
+    // The motivation for having this flag, instead of just not setting
+    // |framework_report_config|, is prevent accidents where
+    // |framework_report_config| is omitted by mistake.
+    optional bool skip_report = 3;
+
+    // If true, will direct the Android framework to read the data in trace
+    // file and pass it to the reporter class over a pipe instead of passing
+    // the file descriptor directly.
+    //
+    // This flag is needed because the Android test framework does not
+    // currently support priv-app helper apps (in terms of SELinux) and we
+    // really don't want to add an allow rule for untrusted_app to receive
+    // trace fds.
+    //
+    // Because of this, we instead will direct the framework to create a new
+    // pipe and pass this to the reporter process instead. As the pipe is
+    // created by the framework, we won't have any problems with SELinux
+    // (system_server is already allowed to pass pipe fds, even
+    // to untrusted apps).
+    //
+    // As the name suggests this option *MUST* only be used for testing.
+    // Note that the framework will reject (and drop) files which are too
+    // large both for simplicity and to be minimize the amount of data we
+    // pass to a non-priv app (note that the framework will still check
+    // manifest permissions even though SELinux permissions are worked around).
+    optional bool use_pipe_in_framework_for_testing = 4;
+  }
+  optional AndroidReportConfig android_report_config = 34;
 }
 
 // End of protos/perfetto/config/trace_config.proto
diff --git a/protos/perfetto/config/trace_config.proto b/protos/perfetto/config/trace_config.proto
index e845f17..d58239f 100644
--- a/protos/perfetto/config/trace_config.proto
+++ b/protos/perfetto/config/trace_config.proto
@@ -26,7 +26,7 @@
 // It contains the general config for the logging buffer(s) and the configs for
 // all the data source being enabled.
 //
-// Next id: 34.
+// Next id: 35.
 message TraceConfig {
   message BufferConfig {
     optional uint32 size_kb = 1;
@@ -437,4 +437,52 @@
   // old field number for trace_filter
   reserved 32;
   optional TraceFilter trace_filter = 33;
+
+  // Android-only. Not for general use. If set, reports the trace to the
+  // Android framework. This field is read by perfetto_cmd, rather than the
+  // tracing service. This field must be set when passing the --upload flag to
+  // perfetto_cmd.
+  message AndroidReportConfig {
+    // In this message, either:
+    //  * |reporter_service_package| and |reporter_service_class| must be set.
+    //  * |skip_reporting| must be explicitly set to true.
+
+    optional string reporter_service_package = 1;
+    optional string reporter_service_class = 2;
+
+    // If true, then skips reporting the trace to Android framework.
+    //
+    // This flag is useful in testing (e.g. Perfetto-statsd integration tests)
+    // or when we explicitly don't want to report traces to the framework even
+    // when they usually would (e.g. configs deployed using statsd but only
+    // used for inclusion in bugreports using |bugreport_score|).
+    //
+    // The motivation for having this flag, instead of just not setting
+    // |framework_report_config|, is prevent accidents where
+    // |framework_report_config| is omitted by mistake.
+    optional bool skip_report = 3;
+
+    // If true, will direct the Android framework to read the data in trace
+    // file and pass it to the reporter class over a pipe instead of passing
+    // the file descriptor directly.
+    //
+    // This flag is needed because the Android test framework does not
+    // currently support priv-app helper apps (in terms of SELinux) and we
+    // really don't want to add an allow rule for untrusted_app to receive
+    // trace fds.
+    //
+    // Because of this, we instead will direct the framework to create a new
+    // pipe and pass this to the reporter process instead. As the pipe is
+    // created by the framework, we won't have any problems with SELinux
+    // (system_server is already allowed to pass pipe fds, even
+    // to untrusted apps).
+    //
+    // As the name suggests this option *MUST* only be used for testing.
+    // Note that the framework will reject (and drop) files which are too
+    // large both for simplicity and to be minimize the amount of data we
+    // pass to a non-priv app (note that the framework will still check
+    // manifest permissions even though SELinux permissions are worked around).
+    optional bool use_pipe_in_framework_for_testing = 4;
+  }
+  optional AndroidReportConfig android_report_config = 34;
 }
diff --git a/protos/perfetto/trace/ftrace/all_protos.gni b/protos/perfetto/trace/ftrace/all_protos.gni
index 55655f8..8c2ed1f 100644
--- a/protos/perfetto/trace/ftrace/all_protos.gni
+++ b/protos/perfetto/trace/ftrace/all_protos.gni
@@ -54,6 +54,7 @@
   "scm.proto",
   "sde.proto",
   "signal.proto",
+  "sock.proto",
   "sync.proto",
   "synthetic.proto",
   "systrace.proto",
diff --git a/protos/perfetto/trace/ftrace/ftrace_event.proto b/protos/perfetto/trace/ftrace/ftrace_event.proto
index dd718ef..0338cb6 100644
--- a/protos/perfetto/trace/ftrace/ftrace_event.proto
+++ b/protos/perfetto/trace/ftrace/ftrace_event.proto
@@ -54,6 +54,7 @@
 import "protos/perfetto/trace/ftrace/scm.proto";
 import "protos/perfetto/trace/ftrace/sde.proto";
 import "protos/perfetto/trace/ftrace/signal.proto";
+import "protos/perfetto/trace/ftrace/sock.proto";
 import "protos/perfetto/trace/ftrace/sync.proto";
 import "protos/perfetto/trace/ftrace/synthetic.proto";
 import "protos/perfetto/trace/ftrace/systrace.proto";
@@ -452,5 +453,6 @@
     RssStatThrottledFtraceEvent rss_stat_throttled = 359;
     NetifReceiveSkbFtraceEvent netif_receive_skb = 360;
     NetDevXmitFtraceEvent net_dev_xmit = 361;
+    InetSockSetStateFtraceEvent inet_sock_set_state = 362;
   }
 }
diff --git a/protos/perfetto/trace/ftrace/sock.proto b/protos/perfetto/trace/ftrace/sock.proto
new file mode 100644
index 0000000..9607117
--- /dev/null
+++ b/protos/perfetto/trace/ftrace/sock.proto
@@ -0,0 +1,18 @@
+// Autogenerated by:
+// ../../tools/ftrace_proto_gen/ftrace_proto_gen.cc
+// Do not edit.
+
+syntax = "proto2";
+package perfetto.protos;
+
+message InetSockSetStateFtraceEvent {
+  optional uint32 daddr = 1;
+  optional uint32 dport = 2;
+  optional uint32 family = 3;
+  optional int32 newstate = 4;
+  optional int32 oldstate = 5;
+  optional uint32 protocol = 6;
+  optional uint32 saddr = 7;
+  optional uint64 skaddr = 8;
+  optional uint32 sport = 9;
+}
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index e3a75e1..1448043 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -1596,7 +1596,7 @@
 // It contains the general config for the logging buffer(s) and the configs for
 // all the data source being enabled.
 //
-// Next id: 34.
+// Next id: 35.
 message TraceConfig {
   message BufferConfig {
     optional uint32 size_kb = 1;
@@ -2007,6 +2007,54 @@
   // old field number for trace_filter
   reserved 32;
   optional TraceFilter trace_filter = 33;
+
+  // Android-only. Not for general use. If set, reports the trace to the
+  // Android framework. This field is read by perfetto_cmd, rather than the
+  // tracing service. This field must be set when passing the --upload flag to
+  // perfetto_cmd.
+  message AndroidReportConfig {
+    // In this message, either:
+    //  * |reporter_service_package| and |reporter_service_class| must be set.
+    //  * |skip_reporting| must be explicitly set to true.
+
+    optional string reporter_service_package = 1;
+    optional string reporter_service_class = 2;
+
+    // If true, then skips reporting the trace to Android framework.
+    //
+    // This flag is useful in testing (e.g. Perfetto-statsd integration tests)
+    // or when we explicitly don't want to report traces to the framework even
+    // when they usually would (e.g. configs deployed using statsd but only
+    // used for inclusion in bugreports using |bugreport_score|).
+    //
+    // The motivation for having this flag, instead of just not setting
+    // |framework_report_config|, is prevent accidents where
+    // |framework_report_config| is omitted by mistake.
+    optional bool skip_report = 3;
+
+    // If true, will direct the Android framework to read the data in trace
+    // file and pass it to the reporter class over a pipe instead of passing
+    // the file descriptor directly.
+    //
+    // This flag is needed because the Android test framework does not
+    // currently support priv-app helper apps (in terms of SELinux) and we
+    // really don't want to add an allow rule for untrusted_app to receive
+    // trace fds.
+    //
+    // Because of this, we instead will direct the framework to create a new
+    // pipe and pass this to the reporter process instead. As the pipe is
+    // created by the framework, we won't have any problems with SELinux
+    // (system_server is already allowed to pass pipe fds, even
+    // to untrusted apps).
+    //
+    // As the name suggests this option *MUST* only be used for testing.
+    // Note that the framework will reject (and drop) files which are too
+    // large both for simplicity and to be minimize the amount of data we
+    // pass to a non-priv app (note that the framework will still check
+    // manifest permissions even though SELinux permissions are worked around).
+    optional bool use_pipe_in_framework_for_testing = 4;
+  }
+  optional AndroidReportConfig android_report_config = 34;
 }
 
 // End of protos/perfetto/config/trace_config.proto
@@ -5303,6 +5351,22 @@
 
 // End of protos/perfetto/trace/ftrace/signal.proto
 
+// Begin of protos/perfetto/trace/ftrace/sock.proto
+
+message InetSockSetStateFtraceEvent {
+  optional uint32 daddr = 1;
+  optional uint32 dport = 2;
+  optional uint32 family = 3;
+  optional int32 newstate = 4;
+  optional int32 oldstate = 5;
+  optional uint32 protocol = 6;
+  optional uint32 saddr = 7;
+  optional uint64 skaddr = 8;
+  optional uint32 sport = 9;
+}
+
+// End of protos/perfetto/trace/ftrace/sock.proto
+
 // Begin of protos/perfetto/trace/ftrace/sync.proto
 
 message SyncPtFtraceEvent {
@@ -5806,6 +5870,7 @@
     RssStatThrottledFtraceEvent rss_stat_throttled = 359;
     NetifReceiveSkbFtraceEvent netif_receive_skb = 360;
     NetDevXmitFtraceEvent net_dev_xmit = 361;
+    InetSockSetStateFtraceEvent inet_sock_set_state = 362;
   }
 }
 
diff --git a/src/android_internal/health_hal.cc b/src/android_internal/health_hal.cc
index d3e0de0..f21af80 100644
--- a/src/android_internal/health_hal.cc
+++ b/src/android_internal/health_hal.cc
@@ -16,8 +16,8 @@
 
 #include "src/android_internal/health_hal.h"
 
-#include <android/binder_manager.h>
 #include <aidl/android/hardware/health/IHealth.h>
+#include <android/binder_manager.h>
 #include <android/hardware/health/2.0/IHealth.h>
 #include <healthhalutils/HealthHalUtils.h>
 
diff --git a/src/android_internal/tracing_service_proxy.cc b/src/android_internal/tracing_service_proxy.cc
index e297b75..a886689 100644
--- a/src/android_internal/tracing_service_proxy.cc
+++ b/src/android_internal/tracing_service_proxy.cc
@@ -17,21 +17,29 @@
 #include "src/android_internal/tracing_service_proxy.h"
 
 #include <android/tracing/ITracingServiceProxy.h>
+#include <android/tracing/TraceReportParams.h>
 #include <binder/IBinder.h>
 #include <binder/IServiceManager.h>
+#include <binder/ParcelFileDescriptor.h>
 #include <binder/Status.h>
+#include <utils/String16.h>
 
 namespace perfetto {
 namespace android_internal {
 
 using android::sp;
 using android::binder::Status;
+using android::os::ParcelFileDescriptor;
 using android::tracing::ITracingServiceProxy;
+using android::tracing::TraceReportParams;
+
+namespace {
+static constexpr char kServiceName[] = "tracing.proxy";
+}
 
 bool NotifyTraceSessionEnded(bool session_stolen) {
-  sp<ITracingServiceProxy> service = android::interface_cast<ITracingServiceProxy>(
-      android::defaultServiceManager()->getService(android::String16("tracing.proxy")));
-
+  auto service = android::waitForService<ITracingServiceProxy>(
+      android::String16(kServiceName));
   if (service == nullptr) {
     return false;
   }
@@ -40,5 +48,38 @@
   return s.isOk();
 }
 
-} // namespace android_internal
-} // namespace perfetto
+bool ReportTrace(const char* reporter_package_name,
+                 const char* reporter_class_name,
+                 int owned_trace_fd,
+                 int64_t uuid_lsb,
+                 int64_t uuid_msb,
+                 bool use_pipe_in_framework_for_testing) {
+  // Keep this first so we recapture the raw fd in a RAII type as soon as
+  // possible.
+  android::base::unique_fd fd(owned_trace_fd);
+
+  auto service = android::waitForService<ITracingServiceProxy>(
+      android::String16(kServiceName));
+  if (service == nullptr) {
+    return false;
+  }
+
+  TraceReportParams params{};
+  params.reporterPackageName = android::String16(reporter_package_name);
+  params.reporterClassName = android::String16(reporter_class_name);
+  params.fd = ParcelFileDescriptor(std::move(fd));
+  params.uuidLsb = uuid_lsb;
+  params.uuidMsb = uuid_msb;
+  params.usePipeForTesting = use_pipe_in_framework_for_testing;
+
+  Status s = service->reportTrace(std::move(params));
+  if (!s.isOk()) {
+    __android_log_print(ANDROID_LOG_ERROR, "perfetto", "reportTrace failed: %s",
+                        s.toString8().c_str());
+  }
+
+  return s.isOk();
+}
+
+}  // namespace android_internal
+}  // namespace perfetto
diff --git a/src/android_internal/tracing_service_proxy.h b/src/android_internal/tracing_service_proxy.h
index 0b045e2..5c45934 100644
--- a/src/android_internal/tracing_service_proxy.h
+++ b/src/android_internal/tracing_service_proxy.h
@@ -17,6 +17,8 @@
 #ifndef SRC_ANDROID_INTERNAL_TRACING_SERVICE_PROXY_H_
 #define SRC_ANDROID_INTERNAL_TRACING_SERVICE_PROXY_H_
 
+#include <stdint.h>
+
 namespace perfetto {
 namespace android_internal {
 
@@ -25,6 +27,14 @@
 bool __attribute__((visibility("default")))
 NotifyTraceSessionEnded(bool session_stolen);
 
+bool __attribute__((visibility("default")))
+ReportTrace(const char* reporter_package_name,
+            const char* reporter_class_name,
+            int owned_trace_fd,
+            int64_t uuid_lsb,
+            int64_t uuid_msb,
+            bool use_pipe_in_framework_for_testing);
+
 } // extern "C"
 
 } // namespace android_internal
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index f0f7f8f..0096719 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -568,29 +568,66 @@
     uuid_ = uuid.ToString();
   }
 
-  if (!trace_config_->incident_report_config().destination_package().empty() &&
-      !upload_flag_) {
+  bool has_incidentd_package =
+      !trace_config_->incident_report_config().destination_package().empty();
+  if (has_incidentd_package && !upload_flag_) {
     PERFETTO_ELOG(
         "Unexpected IncidentReportConfig without --dropbox / --upload.");
     return 1;
   }
 
+  bool has_android_reporter_package = !trace_config_->android_report_config()
+                                           .reporter_service_package()
+                                           .empty();
+  if (has_android_reporter_package && !upload_flag_) {
+    PERFETTO_ELOG(
+        "Unexpected AndroidReportConfig without --dropbox / --upload.");
+    return 1;
+  }
+
+  if (has_incidentd_package && has_android_reporter_package) {
+    PERFETTO_ELOG(
+        "Only one of IncidentReportConfig and AndroidReportConfig "
+        "allowed in the same config.");
+    return 1;
+  }
+
+  // If the upload flag is set, we can only be doing one of three things:
+  // 1. Reporting to either incidentd or Android framework.
+  // 2. Skipping incidentd/Android report because it was explicitly
+  //    specified in the config.
+  // 3. Activating triggers.
+  bool incidentd_valid =
+      has_incidentd_package ||
+      trace_config_->incident_report_config().skip_incidentd();
+  bool android_report_valid =
+      has_android_reporter_package ||
+      trace_config_->android_report_config().skip_report();
+  bool has_triggers = !trace_config_->activate_triggers().empty();
+  if (upload_flag_ && !incidentd_valid && !android_report_valid &&
+      !has_triggers) {
+    PERFETTO_ELOG(
+        "One of IncidentReportConfig, AndroidReportConfig or activate_triggers "
+        "must be specified with --dropbox / --upload.");
+    return 1;
+  }
+
   // Only save to incidentd if:
-  // 1) --upload is set
+  // 1) |destination_package| is set
   // 2) |skip_incidentd| is absent or false.
   // 3) we are not simply activating triggers.
   save_to_incidentd_ =
-      upload_flag_ &&
+      has_incidentd_package &&
       !trace_config_->incident_report_config().skip_incidentd() &&
-      trace_config_->activate_triggers().empty();
+      !has_triggers;
 
-  if (save_to_incidentd_ &&
-      trace_config_->incident_report_config().destination_package().empty()) {
-    PERFETTO_ELOG(
-        "Missing IncidentReportConfig.destination_package with --dropbox / "
-        "--upload.");
-    return 1;
-  }
+  // Only report to the Andorid framework if:
+  // 1) |reporter_service_package| is set
+  // 2) |skip_report| is absent or false.
+  // 3) we are not simply activating triggers.
+  report_to_android_framework_ =
+      has_android_reporter_package &&
+      !trace_config_->android_report_config().skip_report() && !has_triggers;
 
   // Respect the wishes of the config with respect to statsd logging or fall
   // back on the presence of the --upload flag if not set.
@@ -640,7 +677,7 @@
   // In this case we don't intend to send any trace config to the service,
   // rather use that as a signal to the cmdline client to connect as a producer
   // and activate triggers.
-  if (!trace_config_->activate_triggers().empty()) {
+  if (has_triggers) {
     for (const auto& trigger : trace_config_->activate_triggers()) {
       triggers_to_activate_.push_back(trigger);
     }
@@ -698,13 +735,21 @@
     }
   }
 
-  if (save_to_incidentd_ && !ignore_guardrails_ &&
-      (trace_config_->duration_ms() == 0 &&
-       trace_config_->trigger_config().trigger_timeout_ms() == 0)) {
+  bool will_trace_indefinitely =
+      trace_config_->duration_ms() == 0 &&
+      trace_config_->trigger_config().trigger_timeout_ms() == 0;
+  if (will_trace_indefinitely && save_to_incidentd_ && !ignore_guardrails_) {
     PERFETTO_ELOG("Can't trace indefinitely when tracing to Incidentd.");
     return 1;
   }
 
+  if (will_trace_indefinitely && report_to_android_framework_ &&
+      !ignore_guardrails_) {
+    PERFETTO_ELOG(
+        "Can't trace indefinitely when reporting to Android framework.");
+    return 1;
+  }
+
   if (background_) {
     if (background_wait_) {
 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
@@ -817,7 +862,7 @@
 
   RateLimiter::Args args{};
   args.is_user_build = IsUserBuild();
-  args.is_uploading = save_to_incidentd_;
+  args.is_uploading = save_to_incidentd_ || report_to_android_framework_;
   args.current_time = base::GetWallTimeS();
   args.ignore_guardrails = ignore_guardrails_;
   args.allow_user_build_tracing = trace_config_->allow_user_build_tracing();
@@ -1027,7 +1072,11 @@
 
   if (save_to_incidentd_) {
 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-    SaveTraceIntoDropboxAndIncidentOrCrash();
+    SaveTraceIntoIncidentOrCrash();
+#endif
+  } else if (report_to_android_framework_) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+    ReportTraceToAndroidFrameworkOrCrash();
 #endif
   } else {
     trace_out_stream_.reset();
diff --git a/src/perfetto_cmd/perfetto_cmd.h b/src/perfetto_cmd/perfetto_cmd.h
index 9f62f51..28c7733 100644
--- a/src/perfetto_cmd/perfetto_cmd.h
+++ b/src/perfetto_cmd/perfetto_cmd.h
@@ -115,8 +115,9 @@
 
 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
   static base::ScopedFile CreateUnlinkedTmpFile();
-  void SaveTraceIntoDropboxAndIncidentOrCrash();
+  void SaveTraceIntoIncidentOrCrash();
   void SaveOutputToIncidentTraceOrCrash();
+  void ReportTraceToAndroidFrameworkOrCrash();
 #endif
   void LogUploadEvent(PerfettoStatsdAtom atom);
   void LogTriggerEvents(PerfettoTriggerAtom atom,
@@ -135,6 +136,7 @@
   base::EventFd ctrl_c_evt_;
   base::Pipe background_wait_pipe_;
   bool save_to_incidentd_ = false;
+  bool report_to_android_framework_ = false;
   bool statsd_logging_ = false;
   bool update_guardrail_state_ = false;
   uint64_t bytes_written_ = 0;
diff --git a/src/perfetto_cmd/perfetto_cmd_android.cc b/src/perfetto_cmd/perfetto_cmd_android.cc
index c7953b1..6a2d949 100644
--- a/src/perfetto_cmd/perfetto_cmd_android.cc
+++ b/src/perfetto_cmd/perfetto_cmd_android.cc
@@ -23,10 +23,12 @@
 #include "perfetto/base/build_config.h"
 #include "perfetto/base/logging.h"
 #include "perfetto/ext/base/file_utils.h"
+#include "perfetto/ext/base/string_utils.h"
 #include "perfetto/ext/base/uuid.h"
 #include "perfetto/tracing/core/trace_config.h"
 #include "src/android_internal/incident_service.h"
 #include "src/android_internal/lazy_library_loader.h"
+#include "src/android_internal/tracing_service_proxy.h"
 
 namespace perfetto {
 namespace {
@@ -35,10 +37,12 @@
 
 }  // namespace
 
-void PerfettoCmd::SaveTraceIntoDropboxAndIncidentOrCrash() {
+void PerfettoCmd::SaveTraceIntoIncidentOrCrash() {
   PERFETTO_CHECK(save_to_incidentd_);
-  PERFETTO_CHECK(
-      !trace_config_->incident_report_config().destination_package().empty());
+
+  const auto& cfg = trace_config_->incident_report_config();
+  PERFETTO_CHECK(!cfg.destination_package().empty());
+  PERFETTO_CHECK(!cfg.skip_incidentd());
 
   if (bytes_written_ == 0) {
     LogUploadEvent(PerfettoStatsdAtom::kNotUploadingEmptyTrace);
@@ -52,7 +56,7 @@
   // Skip the trace-uuid link for traces that are too small. Realistically those
   // traces contain only a marker (e.g. seized_for_bugreport, or the trace
   // expired without triggers). Those are useless and introduce only noise.
-  if (!uuid_.empty() && bytes_written_ > 4096) {
+  if (bytes_written_ > 4096) {
     base::Uuid uuid(uuid_);
     PERFETTO_LOG("go/trace-uuid/%s name=\"%s\" size=%" PRIu64,
                  uuid.ToPrettyString().c_str(),
@@ -61,13 +65,53 @@
 
   // Ask incidentd to create a report, which will read the file we just
   // wrote.
-  const auto& cfg = trace_config_->incident_report_config();
   PERFETTO_LAZY_LOAD(android_internal::StartIncidentReport, incident_fn);
   PERFETTO_CHECK(incident_fn(cfg.destination_package().c_str(),
                              cfg.destination_class().c_str(),
                              cfg.privacy_level()));
 }
 
+void PerfettoCmd::ReportTraceToAndroidFrameworkOrCrash() {
+  PERFETTO_CHECK(report_to_android_framework_);
+  PERFETTO_CHECK(trace_out_stream_);
+
+  const auto& cfg = trace_config_->android_report_config();
+  PERFETTO_CHECK(!cfg.reporter_service_package().empty());
+  PERFETTO_CHECK(!cfg.skip_report());
+
+  if (bytes_written_ == 0) {
+    // TODO(lalitm): change this to a dedicated atom decoupled from
+    // incidentd.
+    LogUploadEvent(PerfettoStatsdAtom::kNotUploadingEmptyTrace);
+    PERFETTO_LOG("Skipping reporting trace to Android. Empty trace.");
+    return;
+  }
+
+  // TODO(lalitm): add atom for beginning report here.
+  base::StackString<128> self_fd("/proc/self/fd/%d",
+                                 fileno(*trace_out_stream_));
+  base::ScopedFile fd(base::OpenFile(self_fd.c_str(), O_RDONLY | O_CLOEXEC));
+  if (!fd) {
+    PERFETTO_FATAL("Failed to dup fd when reporting to Android");
+  }
+
+  base::Uuid uuid(uuid_);
+  PERFETTO_LAZY_LOAD(android_internal::ReportTrace, report_fn);
+  PERFETTO_CHECK(report_fn(cfg.reporter_service_package().c_str(),
+                           cfg.reporter_service_class().c_str(), fd.release(),
+                           uuid.lsb(), uuid.msb(),
+                           cfg.use_pipe_in_framework_for_testing()));
+
+  // Skip the trace-uuid link for traces that are too small. Realistically those
+  // traces contain only a marker (e.g. seized_for_bugreport, or the trace
+  // expired without triggers). Those are useless and introduce only noise.
+  if (bytes_written_ > 4096) {
+    PERFETTO_LOG("go/trace-uuid/%s name=\"%s\" size=%" PRIu64,
+                 uuid.ToPrettyString().c_str(),
+                 trace_config_->unique_session_name().c_str(), bytes_written_);
+  }
+}
+
 // Open a staging file (unlinking the previous instance), copy the trace
 // contents over, then rename to a final hardcoded path (known to incidentd).
 // Such tracing sessions should not normally overlap. We do not use unique
diff --git a/src/trace_processor/importers/ftrace/ftrace_descriptors.cc b/src/trace_processor/importers/ftrace/ftrace_descriptors.cc
index bf50559..3158248 100644
--- a/src/trace_processor/importers/ftrace/ftrace_descriptors.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_descriptors.cc
@@ -24,7 +24,7 @@
 namespace trace_processor {
 namespace {
 
-std::array<MessageDescriptor, 362> descriptors{{
+std::array<MessageDescriptor, 363> descriptors{{
     {nullptr, 0, {}},
     {nullptr, 0, {}},
     {nullptr, 0, {}},
@@ -3875,6 +3875,22 @@
             {"skbaddr", ProtoSchemaType::kUint64},
         },
     },
+    {
+        "inet_sock_set_state",
+        9,
+        {
+            {},
+            {"daddr", ProtoSchemaType::kUint32},
+            {"dport", ProtoSchemaType::kUint32},
+            {"family", ProtoSchemaType::kUint32},
+            {"newstate", ProtoSchemaType::kInt32},
+            {"oldstate", ProtoSchemaType::kInt32},
+            {"protocol", ProtoSchemaType::kUint32},
+            {"saddr", ProtoSchemaType::kUint32},
+            {"skaddr", ProtoSchemaType::kUint64},
+            {"sport", ProtoSchemaType::kUint32},
+        },
+    },
 }};
 
 }  // namespace
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index 56f7035..052376e 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -27,6 +27,7 @@
 #include "src/trace_processor/storage/stats.h"
 #include "src/trace_processor/storage/trace_storage.h"
 #include "src/trace_processor/types/softirq_action.h"
+#include "src/trace_processor/types/tcp_state.h"
 
 #include "protos/perfetto/common/gpu_counter_descriptor.pbzero.h"
 #include "protos/perfetto/trace/ftrace/binder.pbzero.h"
@@ -54,6 +55,7 @@
 #include "protos/perfetto/trace/ftrace/scm.pbzero.h"
 #include "protos/perfetto/trace/ftrace/sde.pbzero.h"
 #include "protos/perfetto/trace/ftrace/signal.pbzero.h"
+#include "protos/perfetto/trace/ftrace/sock.pbzero.h"
 #include "protos/perfetto/trace/ftrace/systrace.pbzero.h"
 #include "protos/perfetto/trace/ftrace/task.pbzero.h"
 #include "protos/perfetto/trace/ftrace/thermal.pbzero.h"
@@ -127,6 +129,7 @@
       oom_kill_id_(context_->storage->InternString("mem.oom_kill")),
       workqueue_id_(context_->storage->InternString("workqueue")),
       irq_id_(context_->storage->InternString("irq")),
+      tcp_state_id_(context_->storage->InternString("tcp_state")),
       ret_arg_id_(context_->storage->InternString("ret")),
       direct_reclaim_nr_reclaimed_id_(
           context->storage->InternString("direct_reclaim_nr_reclaimed")),
@@ -651,6 +654,10 @@
         ParseNetDevXmit(cpu, ts, data);
         break;
       }
+      case FtraceEvent::kInetSockSetStateFieldNumber: {
+        ParseInetSockSetState(ts, pid, data);
+        break;
+      }
       default:
         break;
     }
@@ -1717,5 +1724,65 @@
       .AddArg(len_key, Variadic::UnsignedInteger(evt.len()));
 }
 
+void FtraceParser::ParseInetSockSetState(int64_t timestamp,
+                                         uint32_t pid,
+                                         protozero::ConstBytes blob) {
+  protos::pbzero::InetSockSetStateFtraceEvent::Decoder evt(blob.data,
+                                                           blob.size);
+
+  // Skip non TCP protocol.
+  if (evt.protocol() != kIpprotoTcp) {
+    PERFETTO_ELOG("skip non tcp protocol");
+    return;
+  }
+
+  // Skip non IP protocol.
+  if (evt.family() != kAfNet && evt.family() != kAfNet6) {
+    PERFETTO_ELOG("skip non IP protocol");
+    return;
+  }
+
+  // Skip invalid TCP state.
+  if (evt.newstate() >= TCP_MAX_STATES || evt.oldstate() >= TCP_MAX_STATES) {
+    PERFETTO_ELOG("skip invalid tcp state");
+    return;
+  }
+
+  auto got = skaddr_to_stream_.find(evt.skaddr());
+  if (got == skaddr_to_stream_.end()) {
+    skaddr_to_stream_[evt.skaddr()] = ++num_of_tcp_stream_;
+  }
+  uint32_t stream = skaddr_to_stream_[evt.skaddr()];
+  char stream_str[64];
+  sprintf(stream_str, "TCP stream#%" PRIu32 "", stream);
+  StringId stream_id = context_->storage->InternString(stream_str);
+
+  StringId slice_name_id;
+  if (evt.newstate() == TCP_SYN_SENT) {
+    base::StackString<32> str("%s(pid=%" PRIu32 ")",
+                              kTcpStateNames[evt.newstate()], pid);
+    slice_name_id = context_->storage->InternString(str.string_view());
+  } else if (evt.newstate() == TCP_ESTABLISHED) {
+    base::StackString<64> str("%s(sport=%" PRIu32 ",dport=%" PRIu32 ")",
+                              kTcpStateNames[evt.newstate()], evt.sport(),
+                              evt.dport());
+    slice_name_id = context_->storage->InternString(str.string_view());
+  } else {
+    base::StringView slice_name = kTcpStateNames[evt.newstate()];
+    slice_name_id = context_->storage->InternString(slice_name);
+  }
+
+  // Push to async task set tracker.
+  auto async_track =
+      context_->async_track_set_tracker->InternGlobalTrackSet(stream_id);
+  TrackId end_id = context_->async_track_set_tracker->End(
+      async_track, static_cast<int64_t>(evt.skaddr()));
+  context_->slice_tracker->End(timestamp, end_id);
+  TrackId start_id = context_->async_track_set_tracker->Begin(
+      async_track, static_cast<int64_t>(evt.skaddr()));
+  context_->slice_tracker->Begin(timestamp, start_id, tcp_state_id_,
+                                 slice_name_id);
+}
+
 }  // namespace trace_processor
 }  // namespace perfetto
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.h b/src/trace_processor/importers/ftrace/ftrace_parser.h
index 792175c..290f8e7 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.h
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.h
@@ -157,6 +157,9 @@
                             int64_t timestamp,
                             protozero::ConstBytes);
   void ParseNetDevXmit(uint32_t cpu, int64_t timestamp, protozero::ConstBytes);
+  void ParseInetSockSetState(int64_t timestamp,
+                             uint32_t pid,
+                             protozero::ConstBytes);
 
   TraceProcessorContext* context_;
   RssStatTracker rss_stat_tracker_;
@@ -184,6 +187,7 @@
   const StringId oom_kill_id_;
   const StringId workqueue_id_;
   const StringId irq_id_;
+  const StringId tcp_state_id_;
   const StringId ret_arg_id_;
   const StringId direct_reclaim_nr_reclaimed_id_;
   const StringId direct_reclaim_order_id_;
@@ -230,6 +234,12 @@
   // Record number of transmitted bytes to the network interface card.
   std::unordered_map<StringId, uint64_t> nic_transmitted_bytes_;
 
+  // Keep sock to stream number mapping.
+  std::unordered_map<uint64_t, uint32_t> skaddr_to_stream_;
+
+  // Record number of tcp steams.
+  uint32_t num_of_tcp_stream_ = 0;
+
   bool has_seen_first_ftrace_packet_ = false;
 
   // Stores information about the timestamp from the metadata table which is
diff --git a/src/trace_processor/types/BUILD.gn b/src/trace_processor/types/BUILD.gn
index 46d16b9..ba26e24 100644
--- a/src/trace_processor/types/BUILD.gn
+++ b/src/trace_processor/types/BUILD.gn
@@ -21,6 +21,7 @@
     "softirq_action.h",
     "task_state.cc",
     "task_state.h",
+    "tcp_state.h",
     "trace_processor_context.h",
     "variadic.cc",
     "variadic.h",
diff --git a/src/trace_processor/types/tcp_state.h b/src/trace_processor/types/tcp_state.h
new file mode 100644
index 0000000..1db06de
--- /dev/null
+++ b/src/trace_processor/types/tcp_state.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 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 SRC_TRACE_PROCESSOR_TYPES_TCP_STATE_H_
+#define SRC_TRACE_PROCESSOR_TYPES_TCP_STATE_H_
+
+namespace perfetto {
+namespace trace_processor {
+
+// IPV4 protocol
+constexpr int kAfNet = 2;
+// IPV6 protocol
+constexpr int kAfNet6 = 10;
+// TCP protocol
+constexpr int kIpprotoTcp = 6;
+// TCP protocol states, from include/net/tcp_states.h.
+enum {
+  TCP_ESTABLISHED = 1,
+  TCP_SYN_SENT,
+  TCP_SYN_RECV,
+  TCP_FIN_WAIT1,
+  TCP_FIN_WAIT2,
+  TCP_TIME_WAIT,
+  TCP_CLOSE,
+  TCP_CLOSE_WAIT,
+  TCP_LAST_ACK,
+  TCP_LISTEN,
+  TCP_CLOSING,
+  TCP_NEW_SYN_RECV,
+  TCP_MAX_STATES
+};
+// TCP protocol state to string mapping.
+static constexpr const char* const kTcpStateNames[] = {
+    "TCP_UNKNOWN", "TCP_ESTABLISHED", "TCP_SYN_SENT", "TCP_SYN_RECV",
+    "TCP_FIN_WAIT1", "TCP_FIN_WAIT2","TCP_TIME_WAIT", "TCP_CLOSE",
+    "TCP_CLOSE_WAIT","TCP_LAST_ACK", "TCP_LISTEN", "TCP_CLOSING",
+    "TCP_NEW_SYN_RECV","TCP_MAX_STATES"};
+
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_TYPES_TCP_STATE_H_
diff --git a/src/traced/probes/ftrace/event_info.cc b/src/traced/probes/ftrace/event_info.cc
index 6234363..0a40e9a 100644
--- a/src/traced/probes/ftrace/event_info.cc
+++ b/src/traced/probes/ftrace/event_info.cc
@@ -6450,6 +6450,40 @@
        kUnsetFtraceId,
        325,
        kUnsetSize},
+      {"inet_sock_set_state",
+       "sock",
+       {
+           {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+            "daddr", 1, ProtoSchemaType::kUint32,
+            TranslationStrategy::kInvalidTranslationStrategy},
+           {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+            "dport", 2, ProtoSchemaType::kUint32,
+            TranslationStrategy::kInvalidTranslationStrategy},
+           {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+            "family", 3, ProtoSchemaType::kUint32,
+            TranslationStrategy::kInvalidTranslationStrategy},
+           {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+            "newstate", 4, ProtoSchemaType::kInt32,
+            TranslationStrategy::kInvalidTranslationStrategy},
+           {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+            "oldstate", 5, ProtoSchemaType::kInt32,
+            TranslationStrategy::kInvalidTranslationStrategy},
+           {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+            "protocol", 6, ProtoSchemaType::kUint32,
+            TranslationStrategy::kInvalidTranslationStrategy},
+           {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+            "saddr", 7, ProtoSchemaType::kUint32,
+            TranslationStrategy::kInvalidTranslationStrategy},
+           {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+            "skaddr", 8, ProtoSchemaType::kUint64,
+            TranslationStrategy::kInvalidTranslationStrategy},
+           {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+            "sport", 9, ProtoSchemaType::kUint32,
+            TranslationStrategy::kInvalidTranslationStrategy},
+       },
+       kUnsetFtraceId,
+       362,
+       kUnsetSize},
       {"sync_pt",
        "sync",
        {
diff --git a/src/traced/probes/ftrace/test/data/synthetic/events/sock/inet_sock_set_state/format b/src/traced/probes/ftrace/test/data/synthetic/events/sock/inet_sock_set_state/format
new file mode 100644
index 0000000..d7c36c7
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/synthetic/events/sock/inet_sock_set_state/format
@@ -0,0 +1,21 @@
+name: inet_sock_set_state
+ID: 924
+format:
+	field:unsigned short common_type;	offset:0;	size:2;	signed:0;
+	field:unsigned char common_flags;	offset:2;	size:1;	signed:0;
+	field:unsigned char common_preempt_count;	offset:3;	size:1;	signed:0;
+	field:int common_pid;	offset:4;	size:4;	signed:1;
+
+	field:const void * skaddr;	offset:8;	size:8;	signed:0;
+	field:int oldstate;	offset:16;	size:4;	signed:1;
+	field:int newstate;	offset:20;	size:4;	signed:1;
+	field:__u16 sport;	offset:24;	size:2;	signed:0;
+	field:__u16 dport;	offset:26;	size:2;	signed:0;
+	field:__u16 family;	offset:28;	size:2;	signed:0;
+	field:__u16 protocol;	offset:30;	size:2;	signed:0;
+	field:__u8 saddr[4];	offset:32;	size:4;	signed:0;
+	field:__u8 daddr[4];	offset:36;	size:4;	signed:0;
+	field:__u8 saddr_v6[16];	offset:40;	size:16;	signed:0;
+	field:__u8 daddr_v6[16];	offset:56;	size:16;	signed:0;
+
+print fmt: "family=%s protocol=%s sport=%hu dport=%hu saddr=%pI4 daddr=%pI4 saddrv6=%pI6c daddrv6=%pI6c oldstate=%s newstate=%s", __print_symbolic(REC->family, { 2, "AF_INET" }, { 10, "AF_INET6" }), __print_symbolic(REC->protocol, { 6, "IPPROTO_TCP" }, { 33, "IPPROTO_DCCP" }, { 132, "IPPROTO_SCTP" }, { 262, "IPPROTO_MPTCP" }), REC->sport, REC->dport, REC->saddr, REC->daddr, REC->saddr_v6, REC->daddr_v6, __print_symbolic(REC->oldstate, { 1, "TCP_ESTABLISHED" }, { 2, "TCP_SYN_SENT" }, { 3, "TCP_SYN_RECV" }, { 4, "TCP_FIN_WAIT1" }, { 5, "TCP_FIN_WAIT2" }, { 6, "TCP_TIME_WAIT" }, { 7, "TCP_CLOSE" }, { 8, "TCP_CLOSE_WAIT" }, { 9, "TCP_LAST_ACK" }, { 10, "TCP_LISTEN" }, { 11, "TCP_CLOSING" }, { 12, "TCP_NEW_SYN_RECV" }), __print_symbolic(REC->newstate, { 1, "TCP_ESTABLISHED" }, { 2, "TCP_SYN_SENT" }, { 3, "TCP_SYN_RECV" }, { 4, "TCP_FIN_WAIT1" }, { 5, "TCP_FIN_WAIT2" }, { 6, "TCP_TIME_WAIT" }, { 7, "TCP_CLOSE" }, { 8, "TCP_CLOSE_WAIT" }, { 9, "TCP_LAST_ACK" }, { 10, "TCP_LISTEN" }, { 11, "TCP_CLOSING" }, { 12, "TCP_NEW_SYN_RECV" })
diff --git a/src/tracing/core/tracing_service_impl.cc b/src/tracing/core/tracing_service_impl.cc
index 0a19da1..fea5ded 100644
--- a/src/tracing/core/tracing_service_impl.cc
+++ b/src/tracing/core/tracing_service_impl.cc
@@ -626,9 +626,10 @@
       cfg.write_into_file()) {
     // We don't support this usecase because there are subtle assumptions which
     // break around TracingServiceEvents and windowed sorting (i.e. if we don't
-    // drain the events in ReadBuffers because we are waiting for STOP_TRACING,
-    // we can end up queueing up a lot of TracingServiceEvents and emitting them
-    // wildy out of order breaking windowed sorting in trace processor).
+    // drain the events in ReadBuffersIntoFile because we are waiting for
+    // STOP_TRACING, we can end up queueing up a lot of TracingServiceEvents and
+    // emitting them wildy out of order breaking windowed sorting in trace
+    // processor).
     MaybeLogUploadEvent(
         cfg, PerfettoStatsdAtom::kTracedEnableTracingStopTracingWriteIntoFile);
     return PERFETTO_SVC_ERR(
@@ -2012,7 +2013,35 @@
   if (IsWaitingForTrigger(tracing_session))
     return false;
 
-  return ReadBuffers(tsid, tracing_session, consumer);
+  // This is a rough threshold to determine how much to read from the buffer in
+  // each task. This is to avoid executing a single huge sending task for too
+  // long and risk to hit the watchdog. This is *not* an upper bound: we just
+  // stop accumulating new packets and PostTask *after* we cross this threshold.
+  // This constant essentially balances the PostTask and IPC overhead vs the
+  // responsiveness of the service. An extremely small value will cause one IPC
+  // and one PostTask for each slice but will keep the service extremely
+  // responsive. An extremely large value will batch the send for the full
+  // buffer in one large task, will hit the blocking send() once the socket
+  // buffers are full and hang the service for a bit (until the consumer
+  // catches up).
+  static constexpr size_t kApproxBytesPerTask = 32768;
+  bool has_more;
+  std::vector<TracePacket> packets =
+      ReadBuffers(tracing_session, kApproxBytesPerTask, &has_more);
+
+  if (has_more) {
+    auto weak_consumer = consumer->weak_ptr_factory_.GetWeakPtr();
+    auto weak_this = weak_ptr_factory_.GetWeakPtr();
+    task_runner_->PostTask([weak_this, weak_consumer, tsid] {
+      if (!weak_this || !weak_consumer)
+        return;
+      weak_this->ReadBuffersIntoConsumer(tsid, weak_consumer.get());
+    });
+  }
+
+  // Keep this as tail call, just in case the consumer re-enters.
+  consumer->consumer_->OnTraceData(std::move(packets), has_more);
+  return true;
 }
 
 bool TracingServiceImpl::ReadBuffersIntoFile(TracingSessionID tsid) {
@@ -2033,7 +2062,36 @@
       IsWaitingForTrigger(tracing_session))
     return false;
 
-  return ReadBuffers(tsid, tracing_session, nullptr);
+  // Speculative fix for the memory watchdog crash in b/195145848. This function
+  // uses the heap extensively and might need a M_PURGE. window.gc() is back.
+  // TODO(primiano): if this fixes the crash we might want to coalesce the purge
+  // and throttle it.
+  auto on_ret = base::OnScopeExit([] { base::MaybeReleaseAllocatorMemToOS(); });
+
+  bool has_more;
+  std::vector<TracePacket> packets = ReadBuffers(
+      tracing_session, std::numeric_limits<size_t>::max(), &has_more);
+
+  bool stop_writing_into_file =
+      WriteIntoFile(tracing_session, std::move(packets));
+  if (stop_writing_into_file || tracing_session->write_period_ms == 0) {
+    // Ensure all data was written to the file before we close it.
+    base::FlushFile(tracing_session->write_into_file.get());
+    tracing_session->write_into_file.reset();
+    tracing_session->write_period_ms = 0;
+    if (tracing_session->state == TracingSession::STARTED)
+      DisableTracing(tsid);
+    return true;
+  }
+
+  auto weak_this = weak_ptr_factory_.GetWeakPtr();
+  task_runner_->PostDelayedTask(
+      [weak_this, tsid] {
+        if (weak_this)
+          weak_this->ReadBuffersIntoFile(tsid);
+      },
+      tracing_session->delay_to_next_write_period_ms());
+  return true;
 }
 
 bool TracingServiceImpl::IsWaitingForTrigger(TracingSession* tracing_session) {
@@ -2051,20 +2109,13 @@
   return false;
 }
 
-// Note: when this is called to write into a file passed when starting tracing
-// |consumer| will be == nullptr (as opposite to the case of a consumer asking
-// to send the trace data back over IPC).
-bool TracingServiceImpl::ReadBuffers(TracingSessionID tsid,
-                                     TracingSession* tracing_session,
-                                     ConsumerEndpointImpl* consumer) {
+std::vector<TracePacket> TracingServiceImpl::ReadBuffers(
+    TracingSession* tracing_session,
+    size_t threshold,
+    bool* has_more) {
   PERFETTO_DCHECK_THREAD(thread_checker_);
   PERFETTO_DCHECK(tracing_session);
-
-  // Speculative fix for the memory watchdog crash in b/195145848. This function
-  // uses the heap extensively and might need a M_PURGE. window.gc() is back.
-  // TODO(primiano): if this fixes the crash we might want to coalesce the purge
-  // and throttle it.
-  auto on_ret = base::OnScopeExit([] { base::MaybeReleaseAllocatorMemToOS(); });
+  *has_more = false;
 
   std::vector<TracePacket> packets;
   packets.reserve(1024);  // Just an educated guess to avoid trivial expansions.
@@ -2106,22 +2157,8 @@
     packets_bytes += packet.size();
   }
 
-  // This is a rough threshold to determine how much to read from the buffer in
-  // each task. This is to avoid executing a single huge sending task for too
-  // long and risk to hit the watchdog. This is *not* an upper bound: we just
-  // stop accumulating new packets and PostTask *after* we cross this threshold.
-  // This constant essentially balances the PostTask and IPC overhead vs the
-  // responsiveness of the service. An extremely small value will cause one IPC
-  // and one PostTask for each slice but will keep the service extremely
-  // responsive. An extremely large value will batch the send for the full
-  // buffer in one large task, will hit the blocking send() once the socket
-  // buffers are full and hang the service for a bit (until the consumer
-  // catches up).
-  static constexpr size_t kApproxBytesPerTask = 32768;
   bool did_hit_threshold = false;
 
-  // TODO(primiano): Extend the ReadBuffers API to allow reading only some
-  // buffers, not all of them in one go.
   for (size_t buf_idx = 0;
        buf_idx < tracing_session->num_buffers() && !did_hit_threshold;
        buf_idx++) {
@@ -2182,13 +2219,12 @@
 
       // Append the packet (inclusive of the trusted uid) to |packets|.
       packets_bytes += packet.size();
-      did_hit_threshold = packets_bytes >= kApproxBytesPerTask &&
-                          !tracing_session->write_into_file;
+      did_hit_threshold = packets_bytes >= threshold;
       packets.emplace_back(std::move(packet));
     }  // for(packets...)
   }    // for(buffers...)
 
-  const bool has_more = did_hit_threshold;
+  *has_more = did_hit_threshold;
 
   if (!tracing_session->config.builtin_data_sources()
            .disable_service_events()) {
@@ -2207,15 +2243,18 @@
   // reflected in the emitted stats. This is particularly important for use
   // cases where ReadBuffers is only ever called after the tracing session is
   // stopped.
-  if (!has_more && tracing_session->should_emit_stats) {
+  if (!*has_more && tracing_session->should_emit_stats) {
     EmitStats(tracing_session, &packets);
     tracing_session->should_emit_stats = false;
   }
 
-  // +-------------------------------------------------------------------------+
-  // | NO MORE CHANGES TO |packets| AFTER THIS POINT.                          |
-  // +-------------------------------------------------------------------------+
+  MaybeFilterPackets(tracing_session, &packets);
 
+  return packets;
+}
+
+void TracingServiceImpl::MaybeFilterPackets(TracingSession* tracing_session,
+                                            std::vector<TracePacket>* packets) {
   // If the tracing session specified a filter, run all packets through the
   // filter and replace them with the filter results.
   // The process below mantains the cardinality of input packets. Even if an
@@ -2228,7 +2267,7 @@
     // by the earlier call to SetFilterRoot() in EnableTracing().
     PERFETTO_DCHECK(trace_filter.root_msg_index() != 0);
     std::vector<protozero::MessageFilter::InputSlice> filter_input;
-    for (auto it = packets.begin(); it != packets.end(); ++it) {
+    for (auto it = packets->begin(); it != packets->end(); ++it) {
       const auto& packet_slices = it->slices();
       filter_input.clear();
       filter_input.resize(packet_slices.size());
@@ -2254,7 +2293,10 @@
 
     }  // for (packet)
   }    // if (trace_filter)
+}
 
+bool TracingServiceImpl::WriteIntoFile(TracingSession* tracing_session,
+                                       std::vector<TracePacket> packets) {
   // If the caller asked us to write into a file by setting
   // |write_into_file| == true in the trace config, drain the packets read
   // (if any) into the given file descriptor.
@@ -2323,39 +2365,10 @@
 
     PERFETTO_DLOG("Draining into file, written: %" PRIu64 " KB, stop: %d",
                   (total_wr_size + 1023) / 1024, stop_writing_into_file);
-    if (stop_writing_into_file || tracing_session->write_period_ms == 0) {
-      // Ensure all data was written to the file before we close it.
-      base::FlushFile(fd);
-      tracing_session->write_into_file.reset();
-      tracing_session->write_period_ms = 0;
-      if (tracing_session->state == TracingSession::STARTED)
-        DisableTracing(tsid);
-      return true;
-    }
-
-    auto weak_this = weak_ptr_factory_.GetWeakPtr();
-    task_runner_->PostDelayedTask(
-        [weak_this, tsid] {
-          if (weak_this)
-            weak_this->ReadBuffersIntoFile(tsid);
-        },
-        tracing_session->delay_to_next_write_period_ms());
-    return true;
+    return stop_writing_into_file;
   }  // if (tracing_session->write_into_file)
 
-  if (has_more) {
-    auto weak_consumer = consumer->weak_ptr_factory_.GetWeakPtr();
-    auto weak_this = weak_ptr_factory_.GetWeakPtr();
-    task_runner_->PostTask([weak_this, weak_consumer, tsid] {
-      if (!weak_this || !weak_consumer)
-        return;
-      weak_this->ReadBuffersIntoConsumer(tsid, weak_consumer.get());
-    });
-  }
-
-  // Keep this as tail call, just in case the consumer re-enters.
-  consumer->consumer_->OnTraceData(std::move(packets), has_more);
-  return true;
+  return false;
 }
 
 void TracingServiceImpl::FreeBuffers(TracingSessionID tsid) {
@@ -3356,7 +3369,7 @@
     // If we are stealing a write_into_file session, add a marker that explains
     // why the trace has been stolen rather than creating an empty file. This is
     // only for write_into_file traces. A similar code path deals with the case
-    // of reading-back a seized trace from IPC in ReadBuffers().
+    // of reading-back a seized trace from IPC in ReadBuffersIntoConsumer().
     if (!max_session->config.builtin_data_sources().disable_service_events()) {
       std::vector<TracePacket> packets;
       EmitSeizedForBugreportLifecycleEvent(&packets);
diff --git a/src/tracing/core/tracing_service_impl.h b/src/tracing/core/tracing_service_impl.h
index e6cafc2..37941f4 100644
--- a/src/tracing/core/tracing_service_impl.h
+++ b/src/tracing/core/tracing_service_impl.h
@@ -682,10 +682,33 @@
   void ScrapeSharedMemoryBuffers(TracingSession*, ProducerEndpointImpl*);
   void PeriodicClearIncrementalStateTask(TracingSessionID, bool post_next_only);
   TraceBuffer* GetBufferByID(BufferID);
-  bool ReadBuffers(TracingSessionID, TracingSession*, ConsumerEndpointImpl*);
+
   // Returns true if `*tracing_session` is waiting for a trigger that hasn't
   // happened.
-  static bool IsWaitingForTrigger(TracingSession*);
+  static bool IsWaitingForTrigger(TracingSession* tracing_session);
+
+  // Reads the buffers from `*tracing_session` and returns them (along with some
+  // metadata packets).
+  //
+  // The function stops when the cumulative size of the return packets exceeds
+  // `threshold` (so it's not a strict upper bound) and sets `*has_more` to
+  // true, or when there are no more packets (and sets `*has_more` to false).
+  std::vector<TracePacket> ReadBuffers(TracingSession* tracing_session,
+                                       size_t threshold,
+                                       bool* has_more);
+
+  // If `*tracing_session` has a filter, applies it to `*packets`. Doesn't
+  // change the number of `*packets`, only their content.
+  void MaybeFilterPackets(TracingSession* tracing_session,
+                          std::vector<TracePacket>* packets);
+
+  // If `*tracing_session` is configured to write into a file, writes `packets`
+  // into the file.
+  //
+  // Returns true if the file should be closed (because it's full or there has
+  // been an error), false otherwise.
+  bool WriteIntoFile(TracingSession* tracing_session,
+                     std::vector<TracePacket> packets);
   void OnStartTriggersTimeout(TracingSessionID tsid);
   void MaybeLogUploadEvent(const TraceConfig&,
                            PerfettoStatsdAtom atom,
diff --git a/test/cmdline_integrationtest.cc b/test/cmdline_integrationtest.cc
index 0fc0520..0747789 100644
--- a/test/cmdline_integrationtest.cc
+++ b/test/cmdline_integrationtest.cc
@@ -20,10 +20,8 @@
 
 #include "perfetto/base/build_config.h"
 #include "perfetto/base/logging.h"
-#include "perfetto/ext/base/file_utils.h"
 #include "perfetto/ext/base/pipe.h"
 #include "perfetto/ext/base/string_utils.h"
-#include "perfetto/ext/base/subprocess.h"
 #include "perfetto/ext/base/utils.h"
 #include "perfetto/ext/traced/traced.h"
 #include "perfetto/protozero/scattered_heap_buffer.h"
@@ -68,103 +66,6 @@
   return path;
 }
 
-// This class is a reference to a child process that has in essence been execv
-// to the requested binary. The process will start and then wait for Run()
-// before proceeding. We use this to fork new processes before starting any
-// additional threads in the parent process (otherwise you would risk
-// deadlocks), but pause the forked processes until remaining setup (including
-// any necessary threads) in the parent process is complete.
-class Exec {
- public:
-  // Starts the forked process that was created. If not null then |stderr_out|
-  // will contain the stderr of the process.
-  int Run(std::string* stderr_out = nullptr) {
-    // We can't be the child process.
-    PERFETTO_CHECK(getpid() != subprocess_.pid());
-    // Will cause the entrypoint to continue.
-    PERFETTO_CHECK(write(*sync_pipe_.wr, "1", 1) == 1);
-    sync_pipe_.wr.reset();
-    subprocess_.Wait();
-
-    if (stderr_out) {
-      *stderr_out = std::move(subprocess_.output());
-    } else {
-      PERFETTO_LOG("Child proc %d exited with stderr: \"%s\"",
-                   subprocess_.pid(), subprocess_.output().c_str());
-    }
-    return subprocess_.returncode();
-  }
-
-  Exec(const std::string& argv0,
-       std::initializer_list<std::string> args,
-       std::string input = "") {
-    subprocess_.args.stderr_mode = base::Subprocess::kBuffer;
-    subprocess_.args.stdout_mode = base::Subprocess::kDevNull;
-    subprocess_.args.input = input;
-
-#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
-    constexpr bool kUseSystemBinaries = false;
-#else
-    constexpr bool kUseSystemBinaries = true;
-#endif
-
-    std::vector<std::string>& cmd = subprocess_.args.exec_cmd;
-    if (kUseSystemBinaries) {
-      PERFETTO_CHECK(TestHelper::kDefaultMode ==
-                     TestHelper::Mode::kUseSystemService);
-      cmd.push_back("/system/bin/" + argv0);
-      cmd.insert(cmd.end(), args.begin(), args.end());
-    } else {
-      PERFETTO_CHECK(TestHelper::kDefaultMode ==
-                     TestHelper::Mode::kStartDaemons);
-      subprocess_.args.env.push_back(
-          std::string("PERFETTO_PRODUCER_SOCK_NAME=") +
-          TestHelper::GetDefaultModeProducerSocketName());
-      subprocess_.args.env.push_back(
-          std::string("PERFETTO_CONSUMER_SOCK_NAME=") +
-          TestHelper::GetDefaultModeConsumerSocketName());
-      cmd.push_back(base::GetCurExecutableDir() + "/" + argv0);
-      cmd.insert(cmd.end(), args.begin(), args.end());
-    }
-
-    if (!base::FileExists(cmd[0])) {
-      PERFETTO_FATAL(
-          "Cannot find %s. Make sure that the target has been built and, on "
-          "Android, pushed to the device.",
-          cmd[0].c_str());
-    }
-
-    // This pipe blocks the execution of the child process until the main test
-    // process calls Run(). There are two conflicting problems here:
-    // 1) We can't fork() subprocesses too late, because the test spawns threads
-    //    for hosting the service. fork+threads = bad (see aosp/1089744).
-    // 2) We can't run the subprocess too early, because we need to wait that
-    //    the service threads are ready before trying to connect from the child
-    //    process.
-    sync_pipe_ = base::Pipe::Create();
-    int sync_pipe_rd = *sync_pipe_.rd;
-    subprocess_.args.preserve_fds.push_back(sync_pipe_rd);
-
-    // This lambda will be called on the forked child process after having
-    // setup pipe redirection and closed all FDs, right before the exec().
-    // The Subprocesss harness will take care of closing also |sync_pipe_.wr|.
-    subprocess_.args.posix_entrypoint_for_testing = [sync_pipe_rd] {
-      // Don't add any logging here, all file descriptors are closed and trying
-      // to log will likely cause undefined behaviors.
-      char ignored = 0;
-      PERFETTO_CHECK(PERFETTO_EINTR(read(sync_pipe_rd, &ignored, 1)) > 0);
-      PERFETTO_CHECK(close(sync_pipe_rd) == 0 || errno == EINTR);
-    };
-
-    subprocess_.Start();
-    sync_pipe_.rd.reset();
-  }
-
- private:
-  base::Subprocess subprocess_;
-  base::Pipe sync_pipe_;
-};
-
 class PerfettoCmdlineTest : public ::testing::Test {
  public:
   void SetUp() override {
diff --git a/test/cts/Android.bp b/test/cts/Android.bp
index 3958566..e8571a6 100644
--- a/test/cts/Android.bp
+++ b/test/cts/Android.bp
@@ -14,6 +14,7 @@
     "end_to_end_integrationtest_cts.cc",
     "heapprofd_java_test_cts.cc",
     "heapprofd_test_cts.cc",
+    "reporter_test_cts.cc",
     "traced_perf_test_cts.cc",
     ":perfetto_protos_perfetto_config_cpp_gen",
   ],
@@ -48,6 +49,9 @@
         suffix: "64",
     },
   },
+  data: [
+    ":CtsPerfettoReporterApp"
+  ],
   stl: "libc++_static",
   defaults: [
     "perfetto_defaults",
diff --git a/test/cts/AndroidTest.xml b/test/cts/AndroidTest.xml
index e9f5a5f..db14fe6 100644
--- a/test/cts/AndroidTest.xml
+++ b/test/cts/AndroidTest.xml
@@ -27,6 +27,7 @@
         <option name="test-file-name" value="CtsPerfettoReleaseApp.apk" />
         <option name="test-file-name" value="CtsPerfettoProfileableApp.apk" />
         <option name="test-file-name" value="CtsPerfettoNonProfileableApp.apk" />
+        <option name="test-file-name" value="CtsPerfettoReporterApp.apk" />
     </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="cleanup" value="true" />
diff --git a/test/cts/reporter/Android.bp b/test/cts/reporter/Android.bp
new file mode 100644
index 0000000..ab2633b
--- /dev/null
+++ b/test/cts/reporter/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2022 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.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "external_perfetto_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["external_perfetto_license"],
+}
+
+android_test_helper_app {
+    name: "CtsPerfettoReporterApp",
+    manifest: "AndroidManifest.xml",
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    privileged: true,
+}
diff --git a/test/cts/reporter/AndroidManifest.xml b/test/cts/reporter/AndroidManifest.xml
new file mode 100755
index 0000000..9a2ef40
--- /dev/null
+++ b/test/cts/reporter/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.perfetto.cts.reporter">
+    <uses-permission android:name="android.permission.DUMP"/>
+    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
+1
+    <application>
+        <service
+            android:name=".PerfettoReportService"
+            android:permission="android.permission.BIND_TRACE_REPORT_SERVICE"/>
+    </application>
+</manifest>
diff --git a/test/cts/reporter/src/android/perfetto/cts/reporter/PerfettoReportService.java b/test/cts/reporter/src/android/perfetto/cts/reporter/PerfettoReportService.java
new file mode 100644
index 0000000..5d0c8af
--- /dev/null
+++ b/test/cts/reporter/src/android/perfetto/cts/reporter/PerfettoReportService.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+package android.perfetto.cts.reporter;
+
+import android.os.ParcelFileDescriptor.AutoCloseInputStream;
+import android.service.tracing.TraceReportService;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.UUID;
+
+public class PerfettoReportService extends TraceReportService {
+    public static final String TAG = "PerfettoReportService";
+
+    @Override
+    public void onReportTrace(TraceParams args) {
+        File f = new File(getExternalFilesDir(null), args.getUuid().toString());
+        try {
+            boolean created = f.createNewFile();
+            if (!created) {
+                throw new IllegalStateException("Failed to create file");
+            }
+            try (AutoCloseInputStream i = new AutoCloseInputStream(args.getFd())) {
+                try (FileOutputStream o = new FileOutputStream((f))) {
+                    o.write(i.readAllBytes());
+                }
+            }
+        } catch (IOException ex) {
+            throw new IllegalStateException("IO Exception", ex);
+        }
+    }
+}
diff --git a/test/cts/reporter_test_cts.cc b/test/cts/reporter_test_cts.cc
new file mode 100644
index 0000000..6b68d66
--- /dev/null
+++ b/test/cts/reporter_test_cts.cc
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/system_properties.h>
+#include <random>
+#include "test/gtest_and_gmock.h"
+
+#include "perfetto/ext/base/android_utils.h"
+#include "perfetto/ext/base/uuid.h"
+#include "perfetto/tracing/core/data_source_config.h"
+#include "src/base/test/test_task_runner.h"
+#include "test/android_test_utils.h"
+#include "test/test_helper.h"
+
+#include "protos/perfetto/config/test_config.gen.h"
+#include "protos/perfetto/trace/test_event.gen.h"
+#include "protos/perfetto/trace/trace.gen.h"
+#include "protos/perfetto/trace/trace_packet.gen.h"
+
+namespace perfetto {
+namespace {
+
+TEST(PerfettoReporterTest, TestEndToEndReport) {
+  base::TestTaskRunner task_runner;
+  TestHelper helper(&task_runner);
+  helper.ConnectFakeProducer();
+
+  TraceConfig trace_config;
+  trace_config.add_buffers()->set_size_kb(1024);
+  trace_config.set_duration_ms(200);
+
+  auto* ds_config = trace_config.add_data_sources()->mutable_config();
+  ds_config->set_name("android.perfetto.FakeProducer");
+  ds_config->set_target_buffer(0);
+
+  base::Uuid uuid = base::Uuidv4();
+  trace_config.set_trace_uuid_lsb(uuid.lsb());
+  trace_config.set_trace_uuid_msb(uuid.msb());
+
+  static constexpr uint32_t kRandomSeed = 42;
+  static constexpr uint32_t kEventCount = 1;
+  static constexpr uint32_t kMessageSizeBytes = 2;
+  ds_config->mutable_for_testing()->set_seed(kRandomSeed);
+  ds_config->mutable_for_testing()->set_message_count(kEventCount);
+  ds_config->mutable_for_testing()->set_message_size(kMessageSizeBytes);
+  ds_config->mutable_for_testing()->set_send_batch_on_register(true);
+
+  auto* report_config = trace_config.mutable_android_report_config();
+  report_config->set_reporter_service_package("android.perfetto.cts.reporter");
+  report_config->set_reporter_service_class(
+      "android.perfetto.cts.reporter.PerfettoReportService");
+  report_config->set_use_pipe_in_framework_for_testing(true);
+
+  // We have to construct all the processes we want to fork before we start the
+  // service with |StartServiceIfRequired()|. this is because it is unsafe
+  // (could deadlock) to fork after we've spawned some threads which might
+  // printf (and thus hold locks).
+  auto perfetto_proc = Exec("perfetto",
+                            {
+                                "--upload",
+                                "-c",
+                                "-",
+                            },
+                            trace_config.SerializeAsString());
+
+  std::string stderr_str;
+  EXPECT_EQ(0, perfetto_proc.Run(&stderr_str)) << stderr_str;
+
+  static constexpr char kPath[] =
+      "/sdcard/Android/data/android.perfetto.cts.reporter/files/";
+  std::string path = kPath + uuid.ToPrettyString();
+  static constexpr uint32_t kIterationSleepMs = 500;
+  static constexpr uint32_t kIterationCount =
+      kDefaultTestTimeoutMs / kIterationSleepMs;
+  for (size_t i = 0; i < kIterationCount; ++i) {
+    if (!base::FileExists(path)) {
+      base::SleepMicroseconds(kIterationSleepMs * 1000);
+      continue;
+    }
+
+    std::string trace_str;
+    ASSERT_TRUE(base::ReadFile(path, &trace_str));
+
+    protos::gen::Trace trace;
+    ASSERT_TRUE(trace.ParseFromString(trace_str));
+    int for_testing = 0;
+    for (const auto& packet : trace.packet()) {
+      for_testing += packet.has_for_testing();
+    }
+    ASSERT_EQ(for_testing, kEventCount);
+    return;
+  }
+  FAIL() << "Timed out waiting for trace file";
+}
+
+}  // namespace
+}  // namespace perfetto
diff --git a/test/test_helper.h b/test/test_helper.h
index 904623f..8407f20 100644
--- a/test/test_helper.h
+++ b/test/test_helper.h
@@ -20,8 +20,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "perfetto/ext/base/file_utils.h"
 #include "perfetto/ext/base/optional.h"
 #include "perfetto/ext/base/scoped_file.h"
+#include "perfetto/ext/base/subprocess.h"
 #include "perfetto/ext/base/thread_task_runner.h"
 #include "perfetto/ext/base/utils.h"
 #include "perfetto/ext/tracing/core/consumer.h"
@@ -315,6 +317,103 @@
   std::unique_ptr<TracingService::ConsumerEndpoint> endpoint_;  // Keep last.
 };
 
+// This class is a reference to a child process that has in essence been execv
+// to the requested binary. The process will start and then wait for Run()
+// before proceeding. We use this to fork new processes before starting any
+// additional threads in the parent process (otherwise you would risk
+// deadlocks), but pause the forked processes until remaining setup (including
+// any necessary threads) in the parent process is complete.
+class Exec {
+ public:
+  // Starts the forked process that was created. If not null then |stderr_out|
+  // will contain the stderr of the process.
+  int Run(std::string* stderr_out = nullptr) {
+    // We can't be the child process.
+    PERFETTO_CHECK(getpid() != subprocess_.pid());
+    // Will cause the entrypoint to continue.
+    PERFETTO_CHECK(write(*sync_pipe_.wr, "1", 1) == 1);
+    sync_pipe_.wr.reset();
+    subprocess_.Wait();
+
+    if (stderr_out) {
+      *stderr_out = std::move(subprocess_.output());
+    } else {
+      PERFETTO_LOG("Child proc %d exited with stderr: \"%s\"",
+                   subprocess_.pid(), subprocess_.output().c_str());
+    }
+    return subprocess_.returncode();
+  }
+
+  Exec(const std::string& argv0,
+       std::initializer_list<std::string> args,
+       std::string input = "") {
+    subprocess_.args.stderr_mode = base::Subprocess::kBuffer;
+    subprocess_.args.stdout_mode = base::Subprocess::kDevNull;
+    subprocess_.args.input = input;
+
+#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
+    constexpr bool kUseSystemBinaries = false;
+#else
+    constexpr bool kUseSystemBinaries = true;
+#endif
+
+    std::vector<std::string>& cmd = subprocess_.args.exec_cmd;
+    if (kUseSystemBinaries) {
+      PERFETTO_CHECK(TestHelper::kDefaultMode ==
+                     TestHelper::Mode::kUseSystemService);
+      cmd.push_back("/system/bin/" + argv0);
+      cmd.insert(cmd.end(), args.begin(), args.end());
+    } else {
+      PERFETTO_CHECK(TestHelper::kDefaultMode ==
+                     TestHelper::Mode::kStartDaemons);
+      subprocess_.args.env.push_back(
+          std::string("PERFETTO_PRODUCER_SOCK_NAME=") +
+          TestHelper::GetDefaultModeProducerSocketName());
+      subprocess_.args.env.push_back(
+          std::string("PERFETTO_CONSUMER_SOCK_NAME=") +
+          TestHelper::GetDefaultModeConsumerSocketName());
+      cmd.push_back(base::GetCurExecutableDir() + "/" + argv0);
+      cmd.insert(cmd.end(), args.begin(), args.end());
+    }
+
+    if (!base::FileExists(cmd[0])) {
+      PERFETTO_FATAL(
+          "Cannot find %s. Make sure that the target has been built and, on "
+          "Android, pushed to the device.",
+          cmd[0].c_str());
+    }
+
+    // This pipe blocks the execution of the child process until the main test
+    // process calls Run(). There are two conflicting problems here:
+    // 1) We can't fork() subprocesses too late, because the test spawns threads
+    //    for hosting the service. fork+threads = bad (see aosp/1089744).
+    // 2) We can't run the subprocess too early, because we need to wait that
+    //    the service threads are ready before trying to connect from the child
+    //    process.
+    sync_pipe_ = base::Pipe::Create();
+    int sync_pipe_rd = *sync_pipe_.rd;
+    subprocess_.args.preserve_fds.push_back(sync_pipe_rd);
+
+    // This lambda will be called on the forked child process after having
+    // setup pipe redirection and closed all FDs, right before the exec().
+    // The Subprocesss harness will take care of closing also |sync_pipe_.wr|.
+    subprocess_.args.posix_entrypoint_for_testing = [sync_pipe_rd] {
+      // Don't add any logging here, all file descriptors are closed and trying
+      // to log will likely cause undefined behaviors.
+      char ignored = 0;
+      PERFETTO_CHECK(PERFETTO_EINTR(read(sync_pipe_rd, &ignored, 1)) > 0);
+      PERFETTO_CHECK(close(sync_pipe_rd) == 0 || errno == EINTR);
+    };
+
+    subprocess_.Start();
+    sync_pipe_.rd.reset();
+  }
+
+ private:
+  base::Subprocess subprocess_;
+  base::Pipe sync_pipe_;
+};
+
 }  // namespace perfetto
 
 #endif  // TEST_TEST_HELPER_H_
diff --git a/test/trace_processor/network/index b/test/trace_processor/network/index
index a21082a..bc563d1 100644
--- a/test/trace_processor/network/index
+++ b/test/trace_processor/network/index
@@ -2,3 +2,4 @@
 netif_receive_skb.textproto netif_receive_skb.sql netif_receive_skb.out
 net_dev_xmit.textproto net_dev_xmit.sql net_dev_xmit.out
 netperf_metric.textproto android_netperf netperf_metric.out
+inet_sock_set_state.textproto inet_sock_set_state.sql inet_sock_set_state.out
diff --git a/test/trace_processor/network/inet_sock_set_state.out b/test/trace_processor/network/inet_sock_set_state.out
new file mode 100644
index 0000000..fd67a19
--- /dev/null
+++ b/test/trace_processor/network/inet_sock_set_state.out
@@ -0,0 +1,7 @@
+"ts","name","dur","name"
+10000000,"TCP_SYN_SENT(pid=123)",100000000,"TCP stream#1"
+110000000,"TCP_ESTABLISHED(sport=56789,dport=5001)",500000000,"TCP stream#1"
+610000000,"TCP_CLOSE_WAIT",-1,"TCP stream#1"
+710000000,"TCP_SYN_SENT(pid=567)",10000000,"TCP stream#2"
+720000000,"TCP_ESTABLISHED(sport=56790,dport=5002)",300000000,"TCP stream#2"
+1020000000,"TCP_CLOSE_WAIT",-1,"TCP stream#2"
diff --git a/test/trace_processor/network/inet_sock_set_state.sql b/test/trace_processor/network/inet_sock_set_state.sql
new file mode 100644
index 0000000..badba1e
--- /dev/null
+++ b/test/trace_processor/network/inet_sock_set_state.sql
@@ -0,0 +1,12 @@
+SELECT
+  ts,
+  s.name,
+  dur,
+  t.name
+FROM
+  slice AS s
+  LEFT JOIN track AS t
+  ON s.track_id = t.id
+WHERE
+  t.name GLOB "TCP stream#*"
+ORDER BY ts;
diff --git a/test/trace_processor/network/inet_sock_set_state.textproto b/test/trace_processor/network/inet_sock_set_state.textproto
new file mode 100644
index 0000000..00362f9
--- /dev/null
+++ b/test/trace_processor/network/inet_sock_set_state.textproto
@@ -0,0 +1,121 @@
+packet {
+  ftrace_events {
+    cpu: 0
+    event {
+      timestamp: 10000000
+      pid: 123
+      inet_sock_set_state {
+        family: 2
+        protocol: 6
+        daddr: 19216801
+        saddr: 127001
+        dport: 5001
+        sport: 0
+        newstate: 2
+        oldstate: 7
+        skaddr: 77889900
+      }
+    }
+  }
+}
+packet {
+  ftrace_events {
+    cpu: 1
+    event {
+      timestamp: 110000000
+      pid: 234
+      inet_sock_set_state {
+        family: 2
+        protocol: 6
+        daddr: 19216801
+        saddr: 127001
+        dport: 5001
+        sport: 56789
+        newstate: 1
+        oldstate: 2
+        skaddr: 77889900
+      }
+    }
+  }
+}
+packet {
+  ftrace_events {
+    cpu: 0
+    event {
+      timestamp: 610000000
+      pid: 456
+      inet_sock_set_state {
+        family: 2
+        protocol: 6
+        daddr: 19216801
+        saddr: 127001
+        dport: 5001
+        sport: 56789
+        newstate: 8
+        oldstate: 1
+        skaddr: 77889900
+      }
+    }
+  }
+}
+packet {
+  ftrace_events {
+    cpu: 0
+    event {
+      timestamp: 710000000
+      pid:567
+      inet_sock_set_state {
+        family: 10
+        protocol: 6
+        daddr: 0
+        saddr: 0
+        dport: 5002
+        sport: 0
+        newstate: 2
+        oldstate: 7
+        skaddr: 33445566
+      }
+    }
+  }
+}
+packet {
+  ftrace_events {
+    cpu: 1
+    event {
+      timestamp: 720000000
+      pid: 234
+      inet_sock_set_state {
+        family: 10
+        protocol: 6
+        daddr: 0
+        saddr: 0
+        dport: 5002
+        sport: 56790
+        newstate: 1
+        oldstate: 2
+        skaddr: 33445566
+      }
+    }
+  }
+}
+packet {
+  ftrace_events {
+    cpu: 0
+    event {
+      timestamp: 1020000000
+      pid: 456
+      inet_sock_set_state {
+        family: 10
+        protocol: 6
+        daddr: 0
+        saddr: 0
+        dport: 5002
+        sport: 567090
+        newstate: 8
+        oldstate: 1
+        skaddr: 33445566
+      }
+    }
+  }
+}
+
diff --git a/tools/ftrace_proto_gen/event_list b/tools/ftrace_proto_gen/event_list
index 5a0f31b..8cd573f 100644
--- a/tools/ftrace_proto_gen/event_list
+++ b/tools/ftrace_proto_gen/event_list
@@ -356,3 +356,4 @@
 synthetic/rss_stat_throttled
 net/netif_receive_skb
 net/net_dev_xmit
+sock/inet_sock_set_state