Merge "perfetto: switch base::Optional to std::optional"
diff --git a/Android.bp b/Android.bp
index 6ce03ca..92728f9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1005,6 +1005,7 @@
":perfetto_src_base_version",
":perfetto_src_ipc_client",
":perfetto_src_ipc_common",
+ ":perfetto_src_perfetto_cmd_bugreport_path",
":perfetto_src_perfetto_cmd_perfetto_cmd",
":perfetto_src_perfetto_cmd_protos_cpp_gen",
":perfetto_src_perfetto_cmd_trigger_producer",
@@ -1191,6 +1192,7 @@
":perfetto_src_ipc_perfetto_ipc",
":perfetto_src_kallsyms_kallsyms",
":perfetto_src_kernel_utils_syscall_table",
+ ":perfetto_src_perfetto_cmd_bugreport_path",
":perfetto_src_protozero_filtering_bytecode_common",
":perfetto_src_protozero_filtering_bytecode_generator",
":perfetto_src_protozero_filtering_bytecode_parser",
@@ -1990,6 +1992,7 @@
":perfetto_src_ipc_perfetto_ipc",
":perfetto_src_kallsyms_kallsyms",
":perfetto_src_kernel_utils_syscall_table",
+ ":perfetto_src_perfetto_cmd_bugreport_path",
":perfetto_src_profiling_common_callstack_trie",
":perfetto_src_profiling_common_interner",
":perfetto_src_profiling_common_interning_output",
@@ -8467,6 +8470,11 @@
],
}
+// GN: //src/perfetto_cmd:bugreport_path
+filegroup {
+ name: "perfetto_src_perfetto_cmd_bugreport_path",
+}
+
// GN: //src/perfetto_cmd:gen_cc_config_descriptor
genrule {
name: "perfetto_src_perfetto_cmd_gen_cc_config_descriptor",
@@ -11625,6 +11633,7 @@
":perfetto_src_kallsyms_kallsyms",
":perfetto_src_kallsyms_unittests",
":perfetto_src_kernel_utils_syscall_table",
+ ":perfetto_src_perfetto_cmd_bugreport_path",
":perfetto_src_perfetto_cmd_perfetto_cmd",
":perfetto_src_perfetto_cmd_protos_cpp_gen",
":perfetto_src_perfetto_cmd_trigger_producer",
diff --git a/BUILD b/BUILD
index 3de28e1..8cc1999 100644
--- a/BUILD
+++ b/BUILD
@@ -905,6 +905,14 @@
],
)
+# GN target: //src/perfetto_cmd:bugreport_path
+perfetto_filegroup(
+ name = "src_perfetto_cmd_bugreport_path",
+ srcs = [
+ "src/perfetto_cmd/bugreport_path.h",
+ ],
+)
+
# GN target: //src/perfetto_cmd:gen_cc_config_descriptor
perfetto_cc_proto_descriptor(
name = "src_perfetto_cmd_gen_cc_config_descriptor",
@@ -4536,6 +4544,7 @@
":include_perfetto_tracing_tracing",
":src_android_stats_android_stats",
":src_android_stats_perfetto_atoms",
+ ":src_perfetto_cmd_bugreport_path",
":src_perfetto_cmd_perfetto_cmd",
":src_perfetto_cmd_trigger_producer",
":src_tracing_common",
diff --git a/include/perfetto/ext/tracing/core/basic_types.h b/include/perfetto/ext/tracing/core/basic_types.h
index ac75b4d..0950fe8 100644
--- a/include/perfetto/ext/tracing/core/basic_types.h
+++ b/include/perfetto/ext/tracing/core/basic_types.h
@@ -76,6 +76,11 @@
constexpr uint32_t kDefaultFlushTimeoutMs = 5000;
+// The special id 0xffff..ffff represents the tracing session with the highest
+// bugreport score. This is used for CloneSession(kBugreportSessionId).
+constexpr TracingSessionID kBugreportSessionId =
+ static_cast<TracingSessionID>(-1);
+
} // namespace perfetto
#endif // INCLUDE_PERFETTO_EXT_TRACING_CORE_BASIC_TYPES_H_
diff --git a/include/perfetto/ext/tracing/core/tracing_service.h b/include/perfetto/ext/tracing/core/tracing_service.h
index 68dc086..82e53f7 100644
--- a/include/perfetto/ext/tracing/core/tracing_service.h
+++ b/include/perfetto/ext/tracing/core/tracing_service.h
@@ -42,9 +42,6 @@
class SharedMemoryArbiter;
class TraceWriter;
-// Exposed for testing.
-std::string GetBugreportPath();
-
// TODO: for the moment this assumes that all the calls happen on the same
// thread/sequence. Not sure this will be the case long term in Chrome.
@@ -192,6 +189,8 @@
// Clones an existing tracing session and attaches to it. The session is
// cloned in read-only mode and can only be used to read a snapshot of an
// existing tracing session. Will invoke Consumer::OnSessionCloned().
+ // If TracingSessionID == kBugreportSessionId (0xff...ff) the session with the
+ // highest bugreport score is cloned (if any exists).
// TODO(primiano): make pure virtual after various 3way patches.
virtual void CloneSession(TracingSessionID);
diff --git a/protos/perfetto/ipc/consumer_port.proto b/protos/perfetto/ipc/consumer_port.proto
index aa7fc93..d5a4025 100644
--- a/protos/perfetto/ipc/consumer_port.proto
+++ b/protos/perfetto/ipc/consumer_port.proto
@@ -270,7 +270,7 @@
// or something failed.
message SaveTraceForBugreportResponse {
// If true, an eligible the trace was saved into a known location (on Android
- // /data/misc/perfetto-traces, see GetBugreportPath()).
+ // /data/misc/perfetto-traces, see GetBugreportTracePath()).
// If false no trace with bugreport_score > 0 was found or an error occurred.
// see |msg| in that case for details about the failure.
optional bool success = 1;
@@ -279,6 +279,8 @@
// Arguments for rpc CloneSession.
message CloneSessionRequest {
+ // The session ID to clone. If session_id == kBugreportSessionId (0xff...ff)
+ // the session with the highest bugreport score is cloned (if any exists).
optional uint64 session_id = 1;
}
diff --git a/protos/perfetto/trace/perfetto/tracing_service_event.proto b/protos/perfetto/trace/perfetto/tracing_service_event.proto
index 04923dc..0573be0 100644
--- a/protos/perfetto/trace/perfetto/tracing_service_event.proto
+++ b/protos/perfetto/trace/perfetto/tracing_service_event.proto
@@ -60,6 +60,8 @@
// the contents are routed onto the bugreport file. This event flags the
// situation explicitly. Traces that contain this marker should be discarded
// by test infrastructures / pipelines.
+ // Deprecated since Android U, where --save-for-bugreport uses
+ // non-destructive cloning.
bool seized_for_bugreport = 6;
}
}
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 3d8b920..3efbb44 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -10372,6 +10372,8 @@
// the contents are routed onto the bugreport file. This event flags the
// situation explicitly. Traces that contain this marker should be discarded
// by test infrastructures / pipelines.
+ // Deprecated since Android U, where --save-for-bugreport uses
+ // non-destructive cloning.
bool seized_for_bugreport = 6;
}
}
diff --git a/src/perfetto_cmd/BUILD.gn b/src/perfetto_cmd/BUILD.gn
index 70c47fc..51486c0 100644
--- a/src/perfetto_cmd/BUILD.gn
+++ b/src/perfetto_cmd/BUILD.gn
@@ -49,6 +49,7 @@
"../../include/perfetto/ext/traced",
]
deps = [
+ ":bugreport_path",
":gen_cc_config_descriptor",
":trigger_producer",
"../../gn:default_deps",
@@ -83,6 +84,15 @@
}
}
+source_set("bugreport_path") {
+ sources = [ "bugreport_path.h" ]
+ deps = [ "../../gn:default_deps" ]
+ public_deps = [
+ "../../include/perfetto/base",
+ "../../include/perfetto/ext/base",
+ ]
+}
+
perfetto_cc_proto_descriptor("gen_cc_config_descriptor") {
descriptor_name = "config.descriptor"
descriptor_target = "../../protos/perfetto/config:descriptor"
diff --git a/src/perfetto_cmd/bugreport_path.h b/src/perfetto_cmd/bugreport_path.h
new file mode 100644
index 0000000..5bc7602
--- /dev/null
+++ b/src/perfetto_cmd/bugreport_path.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_PERFETTO_CMD_BUGREPORT_PATH_H_
+#define SRC_PERFETTO_CMD_BUGREPORT_PATH_H_
+
+#include <string>
+
+#include "perfetto/base/build_config.h"
+#include "perfetto/ext/base/temp_file.h"
+
+namespace perfetto {
+
+// Expose for testing
+inline std::string GetBugreportTracePath() {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
+ PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
+ return "/data/misc/perfetto-traces/bugreport/systrace.pftrace";
+#else
+ // Only for tests, SaveTraceForBugreport is not used on other OSes.
+ return base::GetSysTempDir() + "/bugreport.pftrace";
+#endif
+}
+
+} // namespace perfetto
+
+#endif // SRC_PERFETTO_CMD_BUGREPORT_PATH_H_
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index b6323df..4a2b081 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -51,6 +51,7 @@
#include "perfetto/ext/base/getopt.h"
#include "perfetto/ext/base/pipe.h"
#include "perfetto/ext/base/string_view.h"
+#include "perfetto/ext/base/temp_file.h"
#include "perfetto/ext/base/thread_utils.h"
#include "perfetto/ext/base/utils.h"
#include "perfetto/ext/base/uuid.h"
@@ -64,9 +65,11 @@
#include "perfetto/tracing/core/trace_config.h"
#include "perfetto/tracing/core/tracing_service_state.h"
#include "src/android_stats/statsd_logging_helper.h"
+#include "src/perfetto_cmd/bugreport_path.h"
#include "src/perfetto_cmd/config.h"
#include "src/perfetto_cmd/packet_writer.h"
#include "src/perfetto_cmd/pbtxt_to_pb.h"
+#include "src/perfetto_cmd/rate_limiter.h"
#include "src/perfetto_cmd/trigger_producer.h"
#include "protos/perfetto/common/ftrace_descriptor.gen.h"
@@ -78,7 +81,8 @@
perfetto::PerfettoCmd* g_perfetto_cmd;
-uint32_t kOnTraceDataTimeoutMs = 3000;
+const uint32_t kOnTraceDataTimeoutMs = 3000;
+const uint32_t kCloneTimeoutMs = 10000;
class LoggingErrorReporter : public ErrorReporter {
public:
@@ -552,6 +556,13 @@
return 1;
}
+ // --save-for-bugreport is the equivalent of:
+ // --clone kBugreportSessionId -o /data/misc/perfetto-traces/bugreport/...
+ if (bugreport_ && trace_out_path_.empty()) {
+ clone_tsid_ = kBugreportSessionId;
+ trace_out_path_ = GetBugreportTracePath();
+ }
+
// Parse the trace config. It can be either:
// 1) A proto-encoded file/stdin (-c ...).
// 2) A proto-text file/stdin (-c ... --txt).
@@ -561,8 +572,7 @@
trace_config_.reset(new TraceConfig());
bool parsed = false;
- const bool will_trace_or_trigger =
- !is_attach() && !query_service_ && !bugreport_;
+ const bool will_trace_or_trigger = !is_attach() && !query_service_;
if (!will_trace_or_trigger || clone_tsid_) {
if ((!trace_config_raw.empty() || has_config_options)) {
PERFETTO_ELOG("Cannot specify a trace config with this option");
@@ -904,12 +914,12 @@
return finished_with_success ? 0 : 1;
} // if (triggers_to_activate_)
- if (query_service_ || bugreport_) {
+ if (query_service_) {
consumer_endpoint_ =
ConsumerIPCClient::Connect(GetConsumerSocket(), this, &task_runner_);
task_runner_.Run();
return 1; // We can legitimately get here if the service disconnects.
- } // if (query_service || bugreport_)
+ }
RateLimiter::Args args{};
args.is_user_build = IsUserBuild();
@@ -997,25 +1007,14 @@
return;
}
- if (bugreport_) {
- consumer_endpoint_->SaveTraceForBugreport(
- [](bool success, const std::string& msg) {
- if (success) {
- PERFETTO_ILOG("Trace saved into %s", msg.c_str());
- exit(0);
- }
- PERFETTO_ELOG("%s", msg.c_str());
- exit(1);
- });
- return;
- }
-
if (is_attach()) {
consumer_endpoint_->Attach(attach_key_);
return;
}
if (clone_tsid_.has_value()) {
+ task_runner_.PostDelayedTask(std::bind(&PerfettoCmd::OnTimeout, this),
+ kCloneTimeoutMs);
consumer_endpoint_->CloneSession(*clone_tsid_);
return;
}
diff --git a/src/perfetto_cmd/perfetto_cmd.h b/src/perfetto_cmd/perfetto_cmd.h
index 5806237..9504ca5 100644
--- a/src/perfetto_cmd/perfetto_cmd.h
+++ b/src/perfetto_cmd/perfetto_cmd.h
@@ -33,7 +33,6 @@
#include "perfetto/ext/tracing/core/consumer.h"
#include "perfetto/ext/tracing/ipc/consumer_ipc_client.h"
#include "src/android_stats/perfetto_atoms.h"
-#include "src/perfetto_cmd/rate_limiter.h"
namespace perfetto {
diff --git a/src/tools/proto_merger/proto_file.cc b/src/tools/proto_merger/proto_file.cc
index 65237d7..bf1a715 100644
--- a/src/tools/proto_merger/proto_file.cc
+++ b/src/tools/proto_merger/proto_file.cc
@@ -263,10 +263,10 @@
} // namespace
ProtoFile ProtoFileFromDescriptor(
- std::string premable,
+ std::string preamble,
const google::protobuf::FileDescriptor& desc) {
ProtoFile file;
- file.preamble = std::move(premable);
+ file.preamble = std::move(preamble);
for (int i = 0; i < desc.enum_type_count(); ++i) {
file.enums.push_back(EnumFromDescriptor(*desc.enum_type(i)));
}
diff --git a/src/tools/proto_merger/proto_file.h b/src/tools/proto_merger/proto_file.h
index a7056da..985af47 100644
--- a/src/tools/proto_merger/proto_file.h
+++ b/src/tools/proto_merger/proto_file.h
@@ -27,7 +27,7 @@
namespace perfetto {
namespace proto_merger {
-/// Simplified representation of the coomponents of a .proto file.
+// Simplified representation of the components of a .proto file.
struct ProtoFile {
struct Option {
std::string key;
@@ -85,7 +85,7 @@
};
// Creates a ProtoFile struct from a libprotobuf-full descriptor clas.
-ProtoFile ProtoFileFromDescriptor(std::string premable,
+ProtoFile ProtoFileFromDescriptor(std::string preamble,
const google::protobuf::FileDescriptor&);
} // namespace proto_merger
diff --git a/src/tools/proto_merger/proto_merger.cc b/src/tools/proto_merger/proto_merger.cc
index 6e2304c..ba7a701 100644
--- a/src/tools/proto_merger/proto_merger.cc
+++ b/src/tools/proto_merger/proto_merger.cc
@@ -182,7 +182,7 @@
input.packageless_type.c_str(), upstream.packageless_type.c_str());
}
- // If the packageless type mathces, the type should also match.
+ // If the packageless type matches, the type should also match.
PERFETTO_CHECK(input.type == upstream.type);
// Get the comments, label and the name from the source of truth.
@@ -254,8 +254,8 @@
continue;
// If the input value doesn't exist, create a fake "input" that we can pass
- // to the merge functon. This basically has the effect that the upstream
- // item is taken but *not* recrusively; i.e. any fields which are inside the
+ // to the merge function. This basically has the effect that the upstream
+ // item is taken but *not* recursively; i.e. any fields which are inside the
// message/oneof are checked against the allowlist individually. If we just
// took the whole upstream here, we could add fields which were not
// allowlisted.
diff --git a/src/trace_processor/metrics/sql/android/android_startup.sql b/src/trace_processor/metrics/sql/android/android_startup.sql
index e70385a..50da014 100644
--- a/src/trace_processor/metrics/sql/android/android_startup.sql
+++ b/src/trace_processor/metrics/sql/android/android_startup.sql
@@ -305,22 +305,24 @@
FROM (
SELECT 'dex2oat running during launch' AS slow_cause
WHERE
- DUR_OF_PROCESS_RUNNING_CONCURRENT_TO_LAUNCH(launches.startup_id, '*dex2oat64') > 20e6
+ DUR_OF_PROCESS_RUNNING_CONCURRENT_TO_LAUNCH(launches.startup_id, '*dex2oat64') > 0
UNION ALL
SELECT 'installd running during launch' AS slow_cause
WHERE
- DUR_OF_PROCESS_RUNNING_CONCURRENT_TO_LAUNCH(launches.startup_id, '*installd') > 150e6
+ DUR_OF_PROCESS_RUNNING_CONCURRENT_TO_LAUNCH(launches.startup_id, '*installd') > 0
UNION ALL
SELECT 'Main Thread - Time spent in Running state'
AS slow_cause
- WHERE MAIN_THREAD_TIME_FOR_LAUNCH_AND_STATE(launches.startup_id, 'Running') > 150e6
+ WHERE
+ MAIN_THREAD_TIME_FOR_LAUNCH_AND_STATE(launches.startup_id, 'Running') > launches.dur * 0.8
UNION ALL
SELECT 'Main Thread - Time spent in Runnable state'
AS slow_cause
- WHERE MAIN_THREAD_TIME_FOR_LAUNCH_IN_RUNNABLE_STATE(launches.startup_id) > 100e6
+ WHERE
+ MAIN_THREAD_TIME_FOR_LAUNCH_IN_RUNNABLE_STATE(launches.startup_id) > launches.dur * 0.15
UNION ALL
SELECT 'Main Thread - Time spent in interruptible sleep state'
@@ -334,7 +336,9 @@
UNION ALL
SELECT 'Time spent in OpenDexFilesFromOat*'
AS slow_cause
- WHERE ANDROID_SUM_DUR_FOR_STARTUP_AND_SLICE(launches.startup_id, 'OpenDexFilesFromOat*') > 1e6
+ WHERE
+ ANDROID_SUM_DUR_FOR_STARTUP_AND_SLICE(launches.startup_id, 'OpenDexFilesFromOat*')
+ > launches.dur * 0.2
UNION ALL
SELECT 'Time spent in bindApplication'
@@ -355,7 +359,9 @@
UNION ALL
SELECT 'Time spent verifying classes'
AS slow_cause
- WHERE ANDROID_SUM_DUR_FOR_STARTUP_AND_SLICE(launches.startup_id, 'VerifyClass*') > 10e6
+ WHERE
+ ANDROID_SUM_DUR_FOR_STARTUP_AND_SLICE(launches.startup_id, 'VerifyClass*')
+ > launches.dur * 0.15
UNION ALL
SELECT 'Potential CPU contention with '
@@ -379,7 +385,7 @@
WHERE ANDROID_SUM_DUR_ON_MAIN_THREAD_FOR_STARTUP_AND_SLICE(
launches.startup_id,
'Lock contention on*'
- ) > 25e6
+ ) > launches.dur * 0.2
UNION ALL
SELECT 'Main Thread - Monitor contention'
@@ -387,7 +393,7 @@
WHERE ANDROID_SUM_DUR_ON_MAIN_THREAD_FOR_STARTUP_AND_SLICE(
launches.startup_id,
'Lock contention on a monitor*'
- ) > 40e6
+ ) > launches.dur * 0.15
UNION ALL
SELECT 'GC Activity'
diff --git a/src/tracing/core/tracing_service_impl.cc b/src/tracing/core/tracing_service_impl.cc
index 5bd9693..8299500 100644
--- a/src/tracing/core/tracing_service_impl.cc
+++ b/src/tracing/core/tracing_service_impl.cc
@@ -102,15 +102,6 @@
namespace perfetto {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
- PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
-// These are the only SELinux approved dir for trace files that are created
-// directly by traced.
-const char* kTraceDirBasePath = "/data/misc/perfetto-traces/";
-const char* kAndroidProductionBugreportTracePath =
- "/data/misc/perfetto-traces/bugreport/systrace.pftrace";
-#endif
-
namespace {
constexpr int kMaxBuffersPerConsumer = 128;
constexpr uint32_t kDefaultSnapshotsIntervalMs = 10 * 1000;
@@ -241,9 +232,7 @@
return filter_matches || filter_regex_matches;
}
-// Used when:
-// 1. TraceConfig.write_into_file == true and output_path is not empty.
-// 2. Calling SaveTraceForBugreport(), from perfetto --save-for-bugreport.
+// Used when TraceConfig.write_into_file == true and output_path is not empty.
base::ScopedFile CreateTraceFile(const std::string& path, bool overwrite) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
@@ -251,6 +240,9 @@
// It just improves the actionability of the error when people try to save the
// trace in a location that is not SELinux-allowed (a generic "permission
// denied" vs "don't put it here, put it there").
+ // These are the only SELinux approved dir for trace files that are created
+ // directly by traced.
+ static const char* kTraceDirBasePath = "/data/misc/perfetto-traces/";
if (!base::StartsWith(path, kTraceDirBasePath)) {
PERFETTO_ELOG("Invalid output_path %s. On Android it must be within %s.",
path.c_str(), kTraceDirBasePath);
@@ -271,10 +263,6 @@
return fd;
}
-std::string GetBugreportTmpPath() {
- return GetBugreportPath() + ".tmp";
-}
-
bool ShouldLogEvent(const TraceConfig& cfg) {
switch (cfg.statsd_logging()) {
case TraceConfig::STATSD_LOGGING_ENABLED:
@@ -320,16 +308,6 @@
constexpr uint8_t TracingServiceImpl::kSyncMarker[];
#endif
-std::string GetBugreportPath() {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
- PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
- return kAndroidProductionBugreportTracePath;
-#else
- // Only for tests, SaveTraceForBugreport is not used on other OSes.
- return base::GetSysTempDir() + "/bugreport.pftrace";
-#endif
-}
-
// static
std::unique_ptr<TracingService> TracingService::CreateInstance(
std::unique_ptr<SharedMemory::Factory> shm_factory,
@@ -1692,11 +1670,6 @@
ReadBuffersIntoFile(tracing_session->id);
}
- if (tracing_session->on_disable_callback_for_bugreport) {
- std::move(tracing_session->on_disable_callback_for_bugreport)();
- tracing_session->on_disable_callback_for_bugreport = nullptr;
- }
-
MaybeLogUploadEvent(tracing_session->config, tracing_session->trace_uuid,
PerfettoStatsdAtom::kTracedNotifyTracingDisabled);
@@ -2078,21 +2051,6 @@
return false;
}
- // If a bugreport request happened and the trace was stolen for that, give
- // an empty trace with a clear signal to the consumer. This deals only with
- // the case of readback-from-IPC. A similar code-path deals with the
- // write_into_file case in MaybeSaveTraceForBugreport().
- if (tracing_session->seized_for_bugreport) {
- std::vector<TracePacket> packets;
- if (!tracing_session->config.builtin_data_sources()
- .disable_service_events()) {
- EmitSeizedForBugreportLifecycleEvent(&packets);
- }
- EmitLifecycleEvents(tracing_session, &packets);
- consumer->consumer_->OnTraceData(std::move(packets), /*has_more=*/false);
- return true;
- }
-
if (IsWaitingForTrigger(tracing_session))
return false;
@@ -2141,8 +2099,7 @@
if (!tracing_session->write_into_file)
return false;
- if (!tracing_session->seized_for_bugreport &&
- IsWaitingForTrigger(tracing_session))
+ if (IsWaitingForTrigger(tracing_session))
return false;
// ReadBuffers() can allocate memory internally, for filtering. By limiting
@@ -2501,25 +2458,22 @@
bool is_long_trace =
(tracing_session->config.write_into_file() &&
tracing_session->config.file_write_period_ms() < kMillisPerDay);
- bool seized_for_bugreport = tracing_session->seized_for_bugreport;
tracing_sessions_.erase(tsid);
tracing_session = nullptr;
UpdateMemoryGuardrail();
PERFETTO_LOG("Tracing session %" PRIu64 " ended, total sessions:%zu", tsid,
tracing_sessions_.size());
-
#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) && \
PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- if (notify_traceur && (seized_for_bugreport || is_long_trace)) {
+ if (notify_traceur && is_long_trace) {
PERFETTO_LAZY_LOAD(android_internal::NotifyTraceSessionEnded, notify_fn);
- if (!notify_fn || !notify_fn(seized_for_bugreport))
+ if (!notify_fn || !notify_fn(/*session_stolen=*/false))
PERFETTO_ELOG("Failed to notify Traceur long tracing has ended");
}
#else
base::ignore_result(notify_traceur);
base::ignore_result(is_long_trace);
- base::ignore_result(seized_for_bugreport);
#endif
}
@@ -2983,6 +2937,23 @@
return &it->second;
}
+TracingServiceImpl::TracingSession*
+TracingServiceImpl::FindTracingSessionWithMaxBugreportScore() {
+ TracingSession* max_session = nullptr;
+ for (auto& session_id_and_session : tracing_sessions_) {
+ auto& session = session_id_and_session.second;
+ const int32_t score = session.config.bugreport_score();
+ // Exclude sessions with 0 (or below) score. By default tracing sessions
+ // should NOT be eligible to be attached to bugreports.
+ if (score <= 0 || session.state != TracingSession::STARTED)
+ continue;
+
+ if (!max_session || score > max_session->config.bugreport_score())
+ max_session = &session;
+ }
+ return max_session;
+}
+
ProducerID TracingServiceImpl::GetNextProducerID() {
PERFETTO_DCHECK_THREAD(thread_checker_);
PERFETTO_CHECK(producers_.size() < kMaxProducerID);
@@ -3411,18 +3382,6 @@
SerializeAndAppendPacket(packets, std::move(pair.second));
}
-void TracingServiceImpl::EmitSeizedForBugreportLifecycleEvent(
- std::vector<TracePacket>* packets) {
- protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
- packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
- packet->set_trusted_uid(static_cast<int32_t>(uid_));
- packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
- auto* service_event = packet->set_service_event();
- service_event->AppendVarInt(
- protos::pbzero::TracingServiceEvent::kSeizedForBugreportFieldNumber, 1);
- SerializeAndAppendPacket(packets, packet.SerializeAsArray());
-}
-
void TracingServiceImpl::MaybeEmitReceivedTriggers(
TracingSession* tracing_session,
std::vector<TracePacket>* packets) {
@@ -3445,91 +3404,6 @@
}
}
-bool TracingServiceImpl::MaybeSaveTraceForBugreport(
- std::function<void()> callback) {
- TracingSession* max_session = nullptr;
- TracingSessionID max_tsid = 0;
- for (auto& session_id_and_session : tracing_sessions_) {
- auto& session = session_id_and_session.second;
- const int32_t score = session.config.bugreport_score();
- // Exclude sessions with 0 (or below) score. By default tracing sessions
- // should NOT be eligible to be attached to bugreports.
- if (score <= 0 || session.state != TracingSession::STARTED)
- continue;
-
- // Also don't try to steal long traces with write_into_file if their content
- // has been already partially written into a file, as we would get partial
- // traces on both sides. We can't just copy the original file into the
- // bugreport because the file could be too big (GBs) for bugreports.
- // The only case where it's legit to steal traces with write_into_file, is
- // when the consumer specified a very large write_period_ms (e.g. 24h),
- // meaning that this is effectively a ring-buffer trace. Traceur (the
- // Android System Tracing app), which uses --detach, does this to have a
- // consistent invocation path for long-traces and ring-buffer-mode traces.
- if (session.write_into_file && session.bytes_written_into_file > 0)
- continue;
-
- // If we are already in the process of finalizing another trace for
- // bugreport, don't even start another one, as they would try to write onto
- // the same file.
- if (session.on_disable_callback_for_bugreport)
- return false;
-
- if (!max_session || score > max_session->config.bugreport_score()) {
- max_session = &session;
- max_tsid = session_id_and_session.first;
- }
- }
-
- // No eligible trace found.
- if (!max_session)
- return false;
-
- PERFETTO_LOG("Seizing trace for bugreport. tsid:%" PRIu64
- " state:%d wf:%d score:%d name:\"%s\"",
- max_tsid, max_session->state, !!max_session->write_into_file,
- max_session->config.bugreport_score(),
- max_session->config.unique_session_name().c_str());
-
- auto br_fd = CreateTraceFile(GetBugreportTmpPath(), /*overwrite=*/true);
- if (!br_fd)
- return false;
-
- if (max_session->write_into_file) {
- auto fd = *max_session->write_into_file;
- // 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 ReadBuffersIntoConsumer().
- if (!max_session->config.builtin_data_sources().disable_service_events()) {
- std::vector<TracePacket> packets;
- EmitSeizedForBugreportLifecycleEvent(&packets);
- for (auto& packet : packets) {
- char* preamble;
- size_t preamble_size = 0;
- std::tie(preamble, preamble_size) = packet.GetProtoPreamble();
- base::WriteAll(fd, preamble, preamble_size);
- for (const Slice& slice : packet.slices()) {
- base::WriteAll(fd, slice.start, slice.size);
- }
- } // for (packets)
- } // if (!disable_service_events())
- } // if (max_session->write_into_file)
- max_session->write_into_file = std::move(br_fd);
- max_session->on_disable_callback_for_bugreport = std::move(callback);
- max_session->seized_for_bugreport = true;
-
- // Post a task to avoid that early FlushAndDisableTracing() failures invoke
- // the callback before we return. That would re-enter in a weird way the
- // callstack of the calling ConsumerEndpointImpl::SaveTraceForBugreport().
- auto weak_this = weak_ptr_factory_.GetWeakPtr();
- task_runner_->PostTask([weak_this, max_tsid] {
- if (weak_this)
- weak_this->FlushAndDisableTracing(max_tsid);
- });
- return true;
-}
-
void TracingServiceImpl::MaybeLogUploadEvent(const TraceConfig& cfg,
const base::Uuid& uuid,
PerfettoStatsdAtom atom,
@@ -3571,6 +3445,17 @@
void TracingServiceImpl::FlushAndCloneSession(ConsumerEndpointImpl* consumer,
TracingSessionID tsid) {
PERFETTO_DCHECK_THREAD(thread_checker_);
+
+ if (tsid == kBugreportSessionId) {
+ TracingSession* session = FindTracingSessionWithMaxBugreportScore();
+ if (!session) {
+ consumer->consumer_->OnSessionCloned(
+ false, "No tracing sessions eligible for bugreport found");
+ return;
+ }
+ tsid = session->id;
+ }
+
auto weak_this = weak_ptr_factory_.GetWeakPtr();
auto weak_consumer = consumer->GetWeakPtr();
Flush(tsid, 0, [weak_this, tsid, weak_consumer](bool final_flush_outcome) {
@@ -3589,6 +3474,7 @@
bool final_flush_outcome) {
PERFETTO_DLOG("CloneSession(%" PRIu64 ") started, consumer uid: %d", src_tsid,
static_cast<int>(consumer->uid_));
+
TracingSession* src = GetTracingSession(src_tsid);
// The session might be gone by the time we try to clone it.
@@ -3662,6 +3548,11 @@
new protozero::MessageFilter(*src->trace_filter));
}
+ SnapshotLifecyleEvent(
+ cloned_session,
+ protos::pbzero::TracingServiceEvent::kTracingDisabledFieldNumber,
+ true /* snapshot_clocks */);
+
PERFETTO_DLOG("Consumer (uid:%d) cloned tracing session %" PRIu64
" -> %" PRIu64,
static_cast<int>(consumer->uid_), src_tsid, tsid);
@@ -3982,21 +3873,9 @@
void TracingServiceImpl::ConsumerEndpointImpl::SaveTraceForBugreport(
SaveTraceForBugreportCallback consumer_callback) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- auto on_complete_callback = [consumer_callback] {
- if (rename(GetBugreportTmpPath().c_str(), GetBugreportPath().c_str())) {
- consumer_callback(false, "rename(" + GetBugreportTmpPath() + ", " +
- GetBugreportPath() + ") failed (" +
- strerror(errno) + ")");
- } else {
- consumer_callback(true, GetBugreportPath());
- }
- };
- if (!service_->MaybeSaveTraceForBugreport(std::move(on_complete_callback))) {
- consumer_callback(false,
- "No trace with TraceConfig.bugreport_score > 0 eligible "
- "for bug reporting was found");
- }
+ consumer_callback(false,
+ "SaveTraceForBugreport is deprecated. Use "
+ "CloneSession(kBugreportSessionId) instead.");
}
void TracingServiceImpl::ConsumerEndpointImpl::CloneSession(
diff --git a/src/tracing/core/tracing_service_impl.h b/src/tracing/core/tracing_service_impl.h
index e1da6b5..7cefb9b 100644
--- a/src/tracing/core/tracing_service_impl.h
+++ b/src/tracing/core/tracing_service_impl.h
@@ -632,11 +632,6 @@
uint64_t max_file_size_bytes = 0;
uint64_t bytes_written_into_file = 0;
- // Set when using SaveTraceForBugreport(). This callback will be called
- // when the tracing session ends and the data has been saved into the file.
- std::function<void()> on_disable_callback_for_bugreport;
- bool seized_for_bugreport = false;
-
// Periodic task for snapshotting service events (e.g. clocks, sync markers
// etc)
base::PeriodicTask snapshot_periodic_task;
@@ -680,6 +675,10 @@
// session doesn't exists.
TracingSession* GetTracingSession(TracingSessionID);
+ // Returns a pointer to the tracing session that has the highest
+ // TraceConfig.bugreport_score, if any, or nullptr.
+ TracingSession* FindTracingSessionWithMaxBugreportScore();
+
// Returns a pointer to the |tracing_sessions_| entry, matching the given
// uid and detach key, or nullptr if no such session exists.
TracingSession* GetDetachedSession(uid_t, const std::string& key);
@@ -708,12 +707,10 @@
void EmitStats(TracingSession*, std::vector<TracePacket>*);
TraceStats GetTraceStats(TracingSession*);
void EmitLifecycleEvents(TracingSession*, std::vector<TracePacket>*);
- void EmitSeizedForBugreportLifecycleEvent(std::vector<TracePacket>*);
void MaybeEmitUuidAndTraceConfig(TracingSession*, std::vector<TracePacket>*);
void MaybeEmitSystemInfo(TracingSession*, std::vector<TracePacket>*);
void MaybeEmitReceivedTriggers(TracingSession*, std::vector<TracePacket>*);
void MaybeNotifyAllDataSourcesStarted(TracingSession*);
- bool MaybeSaveTraceForBugreport(std::function<void()> callback);
void OnFlushTimeout(TracingSessionID, FlushRequestID);
void OnDisableTracingTimeout(TracingSessionID);
void DisableTracingNotifyConsumerAndFlushFile(TracingSession*);
diff --git a/test/BUILD.gn b/test/BUILD.gn
index 768b8ad..6b995ed 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -38,6 +38,7 @@
"../protos/perfetto/trace/sys_stats:cpp",
"../src/base:base",
"../src/base:test_support",
+ "../src/perfetto_cmd:bugreport_path",
]
if (enable_perfetto_traced_probes) {
deps += [
diff --git a/test/android_integrationtest.cc b/test/android_integrationtest.cc
index 19e894d..9d4e543 100644
--- a/test/android_integrationtest.cc
+++ b/test/android_integrationtest.cc
@@ -63,33 +63,6 @@
using ::testing::Property;
using ::testing::SizeIs;
-// For the SaveForBugreport* tests.
-void SetTraceConfigForBugreportTest(TraceConfig* trace_config) {
- trace_config->add_buffers()->set_size_kb(4096);
- trace_config->set_duration_ms(60000); // Will never hit this.
- trace_config->set_bugreport_score(10);
- auto* ds_config = trace_config->add_data_sources()->mutable_config();
- ds_config->set_name("android.perfetto.FakeProducer");
- ds_config->mutable_for_testing()->set_message_count(3);
- ds_config->mutable_for_testing()->set_message_size(10);
- ds_config->mutable_for_testing()->set_send_batch_on_register(true);
-}
-
-// For the SaveForBugreport* tests.
-static void VerifyBugreportTraceContents() {
- // Read the trace written in the fixed location (/data/misc/perfetto-traces/
- // on Android, /tmp/ on Linux/Mac) and make sure it has the right contents.
- std::string trace_str;
- base::ReadFile(GetBugreportPath(), &trace_str);
- ASSERT_FALSE(trace_str.empty());
- protos::gen::Trace trace;
- ASSERT_TRUE(trace.ParseFromString(trace_str));
- int test_packets = 0;
- for (const auto& p : trace.packet())
- test_packets += p.has_for_testing() ? 1 : 0;
- ASSERT_EQ(test_packets, 3);
-}
-
} // namespace
TEST(PerfettoAndroidIntegrationTest, TestKmemActivity) {
@@ -283,125 +256,6 @@
ASSERT_TRUE(has_battery_packet);
}
-TEST(PerfettoAndroidIntegrationTest, SaveForBugreport) {
- base::TestTaskRunner task_runner;
-
- TestHelper helper(&task_runner);
- helper.StartServiceIfRequired();
- helper.ConnectFakeProducer();
- helper.ConnectConsumer();
- helper.WaitForConsumerConnect();
-
- TraceConfig trace_config;
- SetTraceConfigForBugreportTest(&trace_config);
-
- helper.StartTracing(trace_config);
- helper.WaitForProducerEnabled();
-
- EXPECT_TRUE(helper.SaveTraceForBugreportAndWait());
- helper.WaitForTracingDisabled();
-
- VerifyBugreportTraceContents();
-
- // Now read the trace returned to the consumer via ReadBuffers. This should
- // be always empty because --save-for-bugreport takes it over and makes the
- // buffers unreadable by the consumer (by virtue of force-setting
- // write_into_file, which is incompatible with ReadBuffers()). The only
- // content should be the |seized_for_bugreport| flag.
- helper.ReadData();
- helper.WaitForReadData();
- const auto& packets = helper.full_trace();
- ASSERT_EQ(packets.size(), 1u);
- for (const auto& p : packets) {
- ASSERT_TRUE(p.has_service_event());
- ASSERT_TRUE(p.service_event().seized_for_bugreport());
- }
-}
-
-// Tests that the SaveForBugreport logic works also for traces with
-// write_into_file = true (with a passed file descriptor).
-TEST(PerfettoAndroidIntegrationTest, SaveForBugreport_WriteIntoFile) {
- base::TestTaskRunner task_runner;
-
- TestHelper helper(&task_runner);
- helper.StartServiceIfRequired();
- helper.ConnectFakeProducer();
- helper.ConnectConsumer();
- helper.WaitForConsumerConnect();
-
- TraceConfig trace_config;
- SetTraceConfigForBugreportTest(&trace_config);
- trace_config.set_file_write_period_ms(60000); // Will never hit this.
- trace_config.set_write_into_file(true);
-
- auto pipe_pair = base::Pipe::Create();
- helper.StartTracing(trace_config, std::move(pipe_pair.wr));
- helper.WaitForProducerEnabled();
-
- EXPECT_TRUE(helper.SaveTraceForBugreportAndWait());
- helper.WaitForTracingDisabled();
-
- VerifyBugreportTraceContents();
-
- // Now read the original file descriptor passed in.
- std::string trace_bytes;
- ASSERT_TRUE(base::ReadPlatformHandle(*pipe_pair.rd, &trace_bytes));
- protos::gen::Trace trace;
- ASSERT_TRUE(trace.ParseFromString(trace_bytes));
- ASSERT_EQ(trace.packet().size(), 1u);
- for (const auto& p : trace.packet()) {
- ASSERT_TRUE(p.has_service_event());
- ASSERT_TRUE(p.service_event().seized_for_bugreport());
- }
-}
-
-// Tests that SaveTraceForBugreport() works also if the trace has triggers
-// defined and those triggers have not been hit. This is a regression test for
-// b/188008375 .
-#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
-// Disabled due to b/191940560
-#define MAYBE_SaveForBugreport_Triggers DISABLED_SaveForBugreport_Triggers
-#else
-#define MAYBE_SaveForBugreport_Triggers SaveForBugreport_Triggers
-#endif
-TEST(PerfettoAndroidIntegrationTest, MAYBE_SaveForBugreport_Triggers) {
- base::TestTaskRunner task_runner;
-
- TestHelper helper(&task_runner);
- helper.StartServiceIfRequired();
- helper.ConnectFakeProducer();
- helper.ConnectConsumer();
- helper.WaitForConsumerConnect();
-
- TraceConfig trace_config;
- SetTraceConfigForBugreportTest(&trace_config);
- trace_config.set_duration_ms(0); // set_trigger_timeout_ms is used instead.
- auto* trigger_config = trace_config.mutable_trigger_config();
- trigger_config->set_trigger_timeout_ms(8.64e+7);
- trigger_config->set_trigger_mode(TraceConfig::TriggerConfig::STOP_TRACING);
- auto* trigger = trigger_config->add_triggers();
- trigger->set_name("trigger_name");
- trigger->set_stop_delay_ms(1);
-
- helper.StartTracing(trace_config);
- helper.WaitForProducerEnabled();
-
- EXPECT_TRUE(helper.SaveTraceForBugreportAndWait());
- helper.WaitForTracingDisabled();
-
- VerifyBugreportTraceContents();
-
- // Now read the original trace.
- helper.ReadData();
- helper.WaitForReadData();
- const auto& packets = helper.full_trace();
- ASSERT_EQ(packets.size(), 1u);
- for (const auto& p : packets) {
- ASSERT_TRUE(p.has_service_event());
- ASSERT_TRUE(p.service_event().seized_for_bugreport());
- }
-}
-
} // namespace perfetto
#endif // PERFETTO_OS_ANDROID
diff --git a/test/cmdline_integrationtest.cc b/test/cmdline_integrationtest.cc
index 0747789..cbc3555 100644
--- a/test/cmdline_integrationtest.cc
+++ b/test/cmdline_integrationtest.cc
@@ -27,6 +27,7 @@
#include "perfetto/protozero/scattered_heap_buffer.h"
#include "src/base/test/test_task_runner.h"
#include "src/base/test/utils.h"
+#include "src/perfetto_cmd/bugreport_path.h"
#include "test/gtest_and_gmock.h"
#include "test/test_helper.h"
@@ -66,6 +67,19 @@
return path;
}
+// For the SaveForBugreport* tests.
+TraceConfig CreateTraceConfigForBugreportTest() {
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(4096);
+ trace_config.set_duration_ms(60000); // Will never hit this.
+ trace_config.set_bugreport_score(10);
+ auto* ds_config = trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("android.perfetto.FakeProducer");
+ ds_config->mutable_for_testing()->set_message_count(3);
+ ds_config->mutable_for_testing()->set_message_size(10);
+ return trace_config;
+}
+
class PerfettoCmdlineTest : public ::testing::Test {
public:
void SetUp() override {
@@ -120,6 +134,68 @@
return Exec("trigger_perfetto", std::move(args), std::move(std_in));
}
+ // This is in common to the 3 TEST_F SaveForBugreport* fixtures, which differ
+ // only in the config, passed here as input.
+ void RunBugreportTest(protos::gen::TraceConfig trace_config,
+ bool check_original_trace = true) {
+ const std::string path = RandomTraceFileName();
+
+ auto perfetto_proc = ExecPerfetto(
+ {
+ "-o",
+ path,
+ "-c",
+ "-",
+ },
+ trace_config.SerializeAsString());
+
+ auto perfetto_br_proc = ExecPerfetto({
+ "--save-for-bugreport",
+ });
+
+ // Start the service and connect a simple fake producer.
+ StartServiceIfRequiredNoNewExecsAfterThis();
+
+ auto* fake_producer = ConnectFakeProducer();
+ ASSERT_TRUE(fake_producer);
+
+ std::thread background_trace([&perfetto_proc]() {
+ std::string stderr_str;
+ ASSERT_EQ(0, perfetto_proc.Run(&stderr_str)) << stderr_str;
+ });
+
+ // Wait for the producer to start, and then write out packets.
+ WaitForProducerEnabled();
+ auto on_data_written = task_runner_.CreateCheckpoint("data_written");
+ fake_producer->ProduceEventBatch(WrapTask(on_data_written));
+ task_runner_.RunUntilCheckpoint("data_written");
+
+ ASSERT_EQ(0, perfetto_br_proc.Run(&stderr_)) << "stderr: " << stderr_;
+ perfetto_proc.SendSigterm();
+ background_trace.join();
+
+ auto check_trace_contents = [](std::string trace_path) {
+ // Read the trace written in the fixed location
+ // (/data/misc/perfetto-traces/ on Android, /tmp/ on Linux/Mac) and make
+ // sure it has the right contents.
+ std::string trace_str;
+ base::ReadFile(trace_path, &trace_str);
+ ASSERT_FALSE(trace_str.empty());
+ protos::gen::Trace trace;
+ ASSERT_TRUE(trace.ParseFromString(trace_str));
+ int test_packets = 0;
+ for (const auto& p : trace.packet())
+ test_packets += p.has_for_testing() ? 1 : 0;
+ ASSERT_EQ(test_packets, 3) << trace_path;
+ };
+
+ // Verify that both the original trace and the cloned bugreport contain
+ // the expected contents.
+ check_trace_contents(GetBugreportTracePath());
+ if (check_original_trace)
+ check_trace_contents(path);
+ }
+
// Tests are allowed to freely use these variables.
std::string stderr_;
base::TestTaskRunner task_runner_;
@@ -760,4 +836,37 @@
}
}
+TEST_F(PerfettoCmdlineTest, SaveForBugreport) {
+ TraceConfig trace_config = CreateTraceConfigForBugreportTest();
+ RunBugreportTest(std::move(trace_config));
+}
+
+TEST_F(PerfettoCmdlineTest, SaveForBugreport_WriteIntoFile) {
+ TraceConfig trace_config = CreateTraceConfigForBugreportTest();
+ trace_config.set_file_write_period_ms(60000); // Will never hit this.
+ trace_config.set_write_into_file(true);
+ RunBugreportTest(std::move(trace_config));
+}
+
+// Tests that SaveTraceForBugreport() works also if the trace has triggers
+// defined and those triggers have not been hit. This is a regression test for
+// b/188008375 .
+#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
+// Disabled due to b/191940560
+#define MAYBE_SaveForBugreport_Triggers DISABLED_SaveForBugreport_Triggers
+#else
+#define MAYBE_SaveForBugreport_Triggers SaveForBugreport_Triggers
+#endif
+TEST_F(PerfettoCmdlineTest, MAYBE_SaveForBugreport_Triggers) {
+ TraceConfig trace_config = CreateTraceConfigForBugreportTest();
+ trace_config.set_duration_ms(0); // set_trigger_timeout_ms is used instead.
+ auto* trigger_config = trace_config.mutable_trigger_config();
+ trigger_config->set_trigger_timeout_ms(8.64e+7);
+ trigger_config->set_trigger_mode(TraceConfig::TriggerConfig::STOP_TRACING);
+ auto* trigger = trigger_config->add_triggers();
+ trigger->set_name("trigger_name");
+ trigger->set_stop_delay_ms(1);
+ RunBugreportTest(std::move(trace_config), /*check_original_trace=*/false);
+}
+
} // namespace perfetto
diff --git a/test/configs/bugreport.cfg b/test/configs/bugreport.cfg
new file mode 100644
index 0000000..d42fd61
--- /dev/null
+++ b/test/configs/bugreport.cfg
@@ -0,0 +1,30 @@
+bugreport_score: 100
+duration_ms: 600000
+
+buffers {
+ size_kb: 32768
+ fill_policy: RING_BUFFER
+}
+
+data_sources {
+ config {
+ name: "linux.ftrace"
+ target_buffer: 0
+ ftrace_config {
+ ftrace_events: "sched/sched_switch"
+ ftrace_events: "power/suspend_resume"
+ ftrace_events: "sched/sched_process_exit"
+ ftrace_events: "sched/sched_process_free"
+ ftrace_events: "task/task_newtask"
+ ftrace_events: "task/task_rename"
+ ftrace_events: "sched/sched_wakeup"
+ }
+ }
+}
+
+data_sources {
+ config {
+ name: "linux.process_stats"
+ target_buffer: 0
+ }
+}
diff --git a/test/test_helper.cc b/test/test_helper.cc
index 2267dc0..cbc3aca 100644
--- a/test/test_helper.cc
+++ b/test/test_helper.cc
@@ -156,18 +156,6 @@
return success;
}
-bool TestHelper::SaveTraceForBugreportAndWait() {
- bool success = false;
- auto checkpoint = CreateCheckpoint("bugreport");
- auto callback = [&success, checkpoint](bool s, const std::string&) {
- success = s;
- checkpoint();
- };
- endpoint_->SaveTraceForBugreport(callback);
- RunUntilCheckpoint("bugreport");
- return success;
-}
-
void TestHelper::CreateProducerProvidedSmb() {
fake_producer_thread_.CreateProducerProvidedSmb();
}
diff --git a/test/test_helper.h b/test/test_helper.h
index c8a8aa5..dd18b4c 100644
--- a/test/test_helper.h
+++ b/test/test_helper.h
@@ -40,6 +40,8 @@
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include "src/tracing/ipc/shared_memory_windows.h"
#else
+#include <signal.h>
+
#include "src/traced/probes/probes_producer.h"
#include "src/tracing/ipc/posix_shared_memory.h"
#endif
@@ -309,7 +311,6 @@
void FreeBuffers();
void DetachConsumer(const std::string& key);
bool AttachConsumer(const std::string& key);
- bool SaveTraceForBugreportAndWait();
void CreateProducerProvidedSmb();
bool IsShmemProvidedByProducer();
void ProduceStartupEventBatch(const protos::gen::TestConfig& config);
@@ -427,6 +428,12 @@
constexpr bool kUseSystemBinaries = true;
#endif
+ auto pass_env = [](const std::string& var, base::Subprocess* proc) {
+ const char* val = getenv(var.c_str());
+ if (val)
+ proc->args.env.push_back(var + "=" + val);
+ };
+
std::vector<std::string>& cmd = subprocess_.args.exec_cmd;
if (kUseSystemBinaries) {
PERFETTO_CHECK(TestHelper::kDefaultMode ==
@@ -442,6 +449,9 @@
subprocess_.args.env.push_back(
std::string("PERFETTO_CONSUMER_SOCK_NAME=") +
TestHelper::GetDefaultModeConsumerSocketName());
+ pass_env("TMPDIR", &subprocess_);
+ pass_env("TMP", &subprocess_);
+ pass_env("TEMP", &subprocess_);
cmd.push_back(base::GetCurExecutableDir() + "/" + argv0);
cmd.insert(cmd.end(), args.begin(), args.end());
}
@@ -479,6 +489,16 @@
sync_pipe_.rd.reset();
}
+ void SendSigterm() {
+#ifdef SIGTERM
+ kill(subprocess_.pid(), SIGTERM);
+#else
+ // This code is never used on Windows tests, not bothering.
+ if (subprocess_.pid()) // Always true, but avoids Wnoreturn compile errors.
+ PERFETTO_FATAL("SendSigterm() not implemented on this platform");
+#endif
+ }
+
private:
base::Subprocess subprocess_;
base::Pipe sync_pipe_;
diff --git a/test/trace_processor/diff_tests/startup/android_startup.out b/test/trace_processor/diff_tests/startup/android_startup.out
index f804a34..48fa752 100644
--- a/test/trace_processor/diff_tests/startup/android_startup.out
+++ b/test/trace_processor/diff_tests/startup/android_startup.out
@@ -62,6 +62,7 @@
installd_dur_ns: 0
dex2oat_dur_ns: 0
}
+ slow_start_reason: "Main Thread - Time spent in Runnable state"
startup_type: "warm"
}
}
diff --git a/test/trace_processor/diff_tests/startup/android_startup_attribution_slow.out b/test/trace_processor/diff_tests/startup/android_startup_attribution_slow.out
index 475edf8..ea33f96 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_attribution_slow.out
+++ b/test/trace_processor/diff_tests/startup/android_startup_attribution_slow.out
@@ -74,8 +74,6 @@
dex2oat_dur_ns: 0
}
startup_type: "hot"
- slow_start_reason: "Time spent in OpenDexFilesFromOat*"
- slow_start_reason: "Time spent verifying classes"
slow_start_reason: "JIT Activity"
slow_start_reason: "GC Activity"
slow_start_reason: "JIT compiled methods"
diff --git a/test/trace_processor/diff_tests/startup/android_startup_breakdown.out b/test/trace_processor/diff_tests/startup/android_startup_breakdown.out
index 132aad8..5baa172 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_breakdown.out
+++ b/test/trace_processor/diff_tests/startup/android_startup_breakdown.out
@@ -102,8 +102,6 @@
installd_dur_ns: 0
dex2oat_dur_ns: 0
}
- slow_start_reason: "Main Thread - Time spent in Running state"
- slow_start_reason: "Main Thread - Time spent in Runnable state"
slow_start_reason: "Time spent in bindApplication"
slow_start_reason: "Time spent in view inflation"
slow_start_reason: "Time spent in ResourcesManager#getResources"
diff --git a/test/trace_processor/diff_tests/startup/android_startup_breakdown_slow.out b/test/trace_processor/diff_tests/startup/android_startup_breakdown_slow.out
index 2974f88..c58d970 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_breakdown_slow.out
+++ b/test/trace_processor/diff_tests/startup/android_startup_breakdown_slow.out
@@ -102,8 +102,6 @@
installd_dur_ns: 0
dex2oat_dur_ns: 0
}
- slow_start_reason: "Main Thread - Time spent in Running state"
- slow_start_reason: "Main Thread - Time spent in Runnable state"
slow_start_reason: "Time spent in bindApplication"
slow_start_reason: "Time spent in view inflation"
slow_start_reason: "Time spent in ResourcesManager#getResources"
diff --git a/test/trace_processor/diff_tests/startup/android_startup_installd_dex2oat.out b/test/trace_processor/diff_tests/startup/android_startup_installd_dex2oat.out
index 48aa205..f2b6285 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_installd_dex2oat.out
+++ b/test/trace_processor/diff_tests/startup/android_startup_installd_dex2oat.out
@@ -61,6 +61,7 @@
installd_dur_ns: 0
dex2oat_dur_ns: 5
}
+ slow_start_reason: "dex2oat running during launch"
}
startup {
startup_id: 3
@@ -93,6 +94,7 @@
installd_dur_ns: 5
dex2oat_dur_ns: 0
}
+ slow_start_reason: "installd running during launch"
}
startup {
startup_id: 4
@@ -126,5 +128,7 @@
installd_dur_ns: 5
dex2oat_dur_ns: 5
}
+ slow_start_reason: "dex2oat running during launch"
+ slow_start_reason: "installd running during launch"
}
}
diff --git a/test/trace_processor/diff_tests/startup/android_startup_lock_contention_slow.out b/test/trace_processor/diff_tests/startup/android_startup_lock_contention_slow.out
index 09a342a..cd5dc6c 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_lock_contention_slow.out
+++ b/test/trace_processor/diff_tests/startup/android_startup_lock_contention_slow.out
@@ -33,12 +33,12 @@
dur_ms: 2000.0
}
time_lock_contention_thread_main {
- dur_ns: 20000000000
- dur_ms: 20000.0
+ dur_ns: 27000000000
+ dur_ms: 27000.0
}
time_monitor_contention_thread_main {
- dur_ns: 10000000000
- dur_ms: 10000.0
+ dur_ns: 17000000000
+ dur_ms: 17000.0
}
}
activity_hosting_process_count: 1
diff --git a/test/trace_processor/diff_tests/startup/android_startup_lock_contention_slow.py b/test/trace_processor/diff_tests/startup/android_startup_lock_contention_slow.py
index c447b08..482549c 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_lock_contention_slow.py
+++ b/test/trace_processor/diff_tests/startup/android_startup_lock_contention_slow.py
@@ -60,7 +60,7 @@
tid=3,
pid=3,
buf='Lock contention on a monitor lock (owner tid: 2)')
-trace.add_atrace_end(ts=to_s(150), tid=3, pid=3)
+trace.add_atrace_end(ts=to_s(157), tid=3, pid=3)
# Lock contention on non-main thread should not be counted.
trace.add_atrace_begin(
diff --git a/test/trace_processor/diff_tests/startup/android_startup_slow.out b/test/trace_processor/diff_tests/startup/android_startup_slow.out
index 22f2d90..3b5d1ab 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_slow.out
+++ b/test/trace_processor/diff_tests/startup/android_startup_slow.out
@@ -63,7 +63,6 @@
dex2oat_dur_ns: 0
}
startup_type: "warm"
- slow_start_reason: "Main Thread - Time spent in Running state"
slow_start_reason: "Main Thread - Time spent in Runnable state"
slow_start_reason: "Main Thread - Time spent in interruptible sleep state"
slow_start_reason: "Main Thread - Time spent in Blocking I/O"