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