|  | /* | 
|  | * 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 <functional> | 
|  | #include <initializer_list> | 
|  | #include <thread> | 
|  |  | 
|  | #include "perfetto/base/build_config.h" | 
|  | #include "perfetto/base/logging.h" | 
|  | #include "perfetto/ext/base/pipe.h" | 
|  | #include "perfetto/ext/base/string_utils.h" | 
|  | #include "perfetto/ext/base/utils.h" | 
|  | #include "perfetto/ext/traced/traced.h" | 
|  | #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" | 
|  |  | 
|  | #include "protos/perfetto/config/test_config.gen.h" | 
|  | #include "protos/perfetto/config/trace_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" | 
|  | #include "protos/perfetto/trace/trace_packet.pbzero.h" | 
|  | #include "protos/perfetto/trace/trigger.gen.h" | 
|  |  | 
|  | namespace perfetto { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | using ::testing::ContainsRegex; | 
|  | using ::testing::Each; | 
|  | using ::testing::ElementsAreArray; | 
|  | using ::testing::Eq; | 
|  | using ::testing::HasSubstr; | 
|  | using ::testing::Property; | 
|  | using ::testing::SizeIs; | 
|  |  | 
|  | std::string RandomTraceFileName() { | 
|  | #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) | 
|  | constexpr char kSysTmpPath[] = "/data/misc/perfetto-traces"; | 
|  | #else | 
|  | constexpr char kSysTmpPath[] = "/tmp"; | 
|  | #endif | 
|  | static int suffix = 0; | 
|  |  | 
|  | std::string path; | 
|  | path.assign(kSysTmpPath); | 
|  | path.append("/trace-"); | 
|  | path.append(std::to_string(base::GetBootTimeNs().count())); | 
|  | path.append("-"); | 
|  | path.append(std::to_string(suffix++)); | 
|  | 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 ScopedFileRemove { | 
|  | public: | 
|  | explicit ScopedFileRemove(const std::string& path) : path_(path) {} | 
|  | ~ScopedFileRemove() { remove(path_.c_str()); } | 
|  | std::string path_; | 
|  | }; | 
|  |  | 
|  | class PerfettoCmdlineTest : public ::testing::Test { | 
|  | public: | 
|  | void SetUp() override { | 
|  | #if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \ | 
|  | defined(MEMORY_SANITIZER) || defined(LEAK_SANITIZER) | 
|  | // Disable cmdline tests on sanitizets because they use fork() and that | 
|  | // messes up leak / races detections, which has been fixed only recently | 
|  | // (see https://github.com/google/sanitizers/issues/836 ). | 
|  | PERFETTO_LOG("Skipping cmdline integration tests on sanitizers"); | 
|  | GTEST_SKIP(); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | void TearDown() override {} | 
|  |  | 
|  | void StartServiceIfRequiredNoNewExecsAfterThis() { | 
|  | exec_allowed_ = false; | 
|  | test_helper_.StartServiceIfRequired(); | 
|  | } | 
|  |  | 
|  | FakeProducer* ConnectFakeProducer() { | 
|  | return test_helper_.ConnectFakeProducer(); | 
|  | } | 
|  |  | 
|  | std::function<void()> WrapTask(const std::function<void()>& function) { | 
|  | return test_helper_.WrapTask(function); | 
|  | } | 
|  |  | 
|  | void WaitForProducerSetup() { test_helper_.WaitForProducerSetup(); } | 
|  |  | 
|  | void WaitForProducerEnabled() { test_helper_.WaitForProducerEnabled(); } | 
|  |  | 
|  | // Creates a process that represents the perfetto binary that will | 
|  | // start when Run() is called. |args| will be passed as part of | 
|  | // the command line and |std_in| will be piped into std::cin. | 
|  | Exec ExecPerfetto(std::initializer_list<std::string> args, | 
|  | std::string std_in = "") { | 
|  | // You can not fork after you've started the service due to risk of | 
|  | // deadlocks. | 
|  | PERFETTO_CHECK(exec_allowed_); | 
|  | return Exec("perfetto", std::move(args), std::move(std_in)); | 
|  | } | 
|  |  | 
|  | // Creates a process that represents the trigger_perfetto binary that will | 
|  | // start when Run() is called. |args| will be passed as part of | 
|  | // the command line and |std_in| will be piped into std::cin. | 
|  | Exec ExecTrigger(std::initializer_list<std::string> args, | 
|  | std::string std_in = "") { | 
|  | // You can not fork after you've started the service due to risk of | 
|  | // deadlocks. | 
|  | PERFETTO_CHECK(exec_allowed_); | 
|  | 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, | 
|  | bool use_explicit_clone = false) { | 
|  | const std::string path = RandomTraceFileName(); | 
|  | ScopedFileRemove remove_on_test_exit(path); | 
|  |  | 
|  | auto perfetto_proc = ExecPerfetto( | 
|  | { | 
|  | "-o", | 
|  | path, | 
|  | "-c", | 
|  | "-", | 
|  | }, | 
|  | trace_config.SerializeAsString()); | 
|  |  | 
|  | Exec perfetto_br_proc = | 
|  | use_explicit_clone | 
|  | ? ExecPerfetto({"--out", GetBugreportTracePath(), "--clone", "-1"}) | 
|  | : 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_; | 
|  |  | 
|  | private: | 
|  | bool exec_allowed_ = true; | 
|  | TestHelper test_helper_{&task_runner_}; | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) | 
|  | #define AndroidOnly(x) x | 
|  | #else | 
|  | #define AndroidOnly(x) DISABLED_##x | 
|  | #endif | 
|  |  | 
|  | TEST_F(PerfettoCmdlineTest, InvalidCases) { | 
|  | std::string cfg("duration_ms: 100"); | 
|  |  | 
|  | auto invalid_arg = ExecPerfetto({"--invalid-arg"}); | 
|  | auto empty_config = ExecPerfetto({"-c", "-", "-o", "-"}, ""); | 
|  |  | 
|  | // Cannot make assertions on --dropbox because on standalone builds it fails | 
|  | // prematurely due to lack of dropbox. | 
|  | auto missing_dropbox = | 
|  | ExecPerfetto({"-c", "-", "--txt", "-o", "-", "--dropbox=foo"}, cfg); | 
|  | auto either_out_or_dropbox = ExecPerfetto({"-c", "-", "--txt"}, cfg); | 
|  |  | 
|  | // Disallow mixing simple and file config. | 
|  | auto simple_and_file_1 = | 
|  | ExecPerfetto({"-o", "-", "-c", "-", "-t", "2s"}, cfg); | 
|  | auto simple_and_file_2 = | 
|  | ExecPerfetto({"-o", "-", "-c", "-", "-b", "2m"}, cfg); | 
|  | auto simple_and_file_3 = | 
|  | ExecPerfetto({"-o", "-", "-c", "-", "-s", "2m"}, cfg); | 
|  |  | 
|  | // Invalid --attach / --detach cases. | 
|  | auto invalid_stop = | 
|  | ExecPerfetto({"-c", "-", "--txt", "-o", "-", "--stop"}, cfg); | 
|  | auto attach_and_config_1 = | 
|  | ExecPerfetto({"-c", "-", "--txt", "-o", "-", "--attach=foo"}, cfg); | 
|  | auto attach_and_config_2 = | 
|  | ExecPerfetto({"-t", "2s", "-o", "-", "--attach=foo"}, cfg); | 
|  | auto attach_needs_argument = ExecPerfetto({"--attach"}, cfg); | 
|  | auto detach_needs_argument = | 
|  | ExecPerfetto({"-t", "2s", "-o", "-", "--detach"}, cfg); | 
|  | auto detach_without_out_or_dropbox = | 
|  | ExecPerfetto({"-t", "2s", "--detach=foo"}, cfg); | 
|  |  | 
|  | // Cannot trace and use --query. | 
|  | auto trace_and_query_1 = ExecPerfetto({"-t", "2s", "--query"}, cfg); | 
|  | auto trace_and_query_2 = ExecPerfetto({"-c", "-", "--query"}, cfg); | 
|  |  | 
|  | // Ensure all Exec:: calls have been saved to prevent deadlocks. | 
|  | StartServiceIfRequiredNoNewExecsAfterThis(); | 
|  |  | 
|  | EXPECT_EQ(1, invalid_arg.Run(&stderr_)); | 
|  |  | 
|  | EXPECT_EQ(1, empty_config.Run(&stderr_)); | 
|  | EXPECT_THAT(stderr_, HasSubstr("TraceConfig is empty")); | 
|  |  | 
|  | // Cannot make assertions on --upload because on standalone builds it fails | 
|  | // prematurely due to lack of dropbox. | 
|  | EXPECT_EQ(1, missing_dropbox.Run(&stderr_)); | 
|  |  | 
|  | EXPECT_EQ(1, either_out_or_dropbox.Run(&stderr_)); | 
|  | EXPECT_THAT(stderr_, HasSubstr("Either --out or --upload")); | 
|  |  | 
|  | // Disallow mixing simple and file config. | 
|  | EXPECT_EQ(1, simple_and_file_1.Run(&stderr_)); | 
|  | EXPECT_THAT(stderr_, HasSubstr("Cannot specify both -c")); | 
|  |  | 
|  | EXPECT_EQ(1, simple_and_file_2.Run(&stderr_)); | 
|  | EXPECT_THAT(stderr_, HasSubstr("Cannot specify both -c")); | 
|  |  | 
|  | EXPECT_EQ(1, simple_and_file_3.Run(&stderr_)); | 
|  | EXPECT_THAT(stderr_, HasSubstr("Cannot specify both -c")); | 
|  |  | 
|  | // Invalid --attach / --detach cases. | 
|  | EXPECT_EQ(1, invalid_stop.Run(&stderr_)); | 
|  | EXPECT_THAT(stderr_, HasSubstr("--stop is supported only in combination")); | 
|  |  | 
|  | EXPECT_EQ(1, attach_and_config_1.Run(&stderr_)); | 
|  | EXPECT_THAT(stderr_, HasSubstr("Cannot specify a trace config")); | 
|  |  | 
|  | EXPECT_EQ(1, attach_and_config_2.Run(&stderr_)); | 
|  | EXPECT_THAT(stderr_, HasSubstr("Cannot specify a trace config")); | 
|  |  | 
|  | EXPECT_EQ(1, attach_needs_argument.Run(&stderr_)); | 
|  | EXPECT_THAT(stderr_, ContainsRegex("option.*--attach.*requires an argument")); | 
|  |  | 
|  | EXPECT_EQ(1, detach_needs_argument.Run(&stderr_)); | 
|  | EXPECT_THAT(stderr_, ContainsRegex("option.*--detach.*requires an argument")); | 
|  |  | 
|  | EXPECT_EQ(1, detach_without_out_or_dropbox.Run(&stderr_)); | 
|  | EXPECT_THAT(stderr_, HasSubstr("--out or --upload is required")); | 
|  |  | 
|  | // Cannot trace and use --query. | 
|  | EXPECT_EQ(1, trace_and_query_1.Run(&stderr_)); | 
|  | EXPECT_THAT(stderr_, HasSubstr("Cannot specify a trace config")); | 
|  |  | 
|  | EXPECT_EQ(1, trace_and_query_2.Run(&stderr_)); | 
|  | EXPECT_THAT(stderr_, HasSubstr("Cannot specify a trace config")); | 
|  | } | 
|  |  | 
|  | TEST_F(PerfettoCmdlineTest, Version) { | 
|  | auto perfetto = ExecPerfetto({"--version"}); | 
|  | EXPECT_EQ(0, perfetto.Run(&stderr_)) << stderr_; | 
|  | } | 
|  |  | 
|  | TEST_F(PerfettoCmdlineTest, TxtConfig) { | 
|  | std::string cfg("duration_ms: 100"); | 
|  | auto perfetto = ExecPerfetto({"-c", "-", "--txt", "-o", "-"}, cfg); | 
|  | StartServiceIfRequiredNoNewExecsAfterThis(); | 
|  | EXPECT_EQ(0, perfetto.Run(&stderr_)) << stderr_; | 
|  | } | 
|  |  | 
|  | TEST_F(PerfettoCmdlineTest, SimpleConfig) { | 
|  | auto perfetto = ExecPerfetto({"-o", "-", "-c", "-", "-t", "100ms"}); | 
|  | StartServiceIfRequiredNoNewExecsAfterThis(); | 
|  | EXPECT_EQ(0, perfetto.Run(&stderr_)) << stderr_; | 
|  | } | 
|  |  | 
|  | TEST_F(PerfettoCmdlineTest, DetachAndAttach) { | 
|  | auto attach_to_not_existing = ExecPerfetto({"--attach=not_existent"}); | 
|  |  | 
|  | std::string cfg("duration_ms: 10000; write_into_file: true"); | 
|  | auto detach_valid_stop = | 
|  | ExecPerfetto({"-o", "-", "-c", "-", "--txt", "--detach=valid_stop"}, cfg); | 
|  | auto stop_valid_stop = ExecPerfetto({"--attach=valid_stop", "--stop"}); | 
|  |  | 
|  | StartServiceIfRequiredNoNewExecsAfterThis(); | 
|  |  | 
|  | EXPECT_NE(0, attach_to_not_existing.Run(&stderr_)); | 
|  | EXPECT_THAT(stderr_, HasSubstr("Session re-attach failed")); | 
|  |  | 
|  | EXPECT_EQ(0, detach_valid_stop.Run(&stderr_)) << stderr_; | 
|  | EXPECT_EQ(0, stop_valid_stop.Run(&stderr_)); | 
|  | } | 
|  |  | 
|  | TEST_F(PerfettoCmdlineTest, StartTracingTrigger) { | 
|  | // See |message_count| and |message_size| in the TraceConfig above. | 
|  | constexpr size_t kMessageCount = 11; | 
|  | constexpr size_t kMessageSize = 32; | 
|  | protos::gen::TraceConfig trace_config; | 
|  | trace_config.add_buffers()->set_size_kb(1024); | 
|  | 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(kMessageCount); | 
|  | ds_config->mutable_for_testing()->set_message_size(kMessageSize); | 
|  | auto* trigger_cfg = trace_config.mutable_trigger_config(); | 
|  | trigger_cfg->set_trigger_mode( | 
|  | protos::gen::TraceConfig::TriggerConfig::START_TRACING); | 
|  | trigger_cfg->set_trigger_timeout_ms(15000); | 
|  | auto* trigger = trigger_cfg->add_triggers(); | 
|  | trigger->set_name("trigger_name"); | 
|  | // |stop_delay_ms| must be long enough that we can write the packets in | 
|  | // before the trace finishes. This has to be long enough for the slowest | 
|  | // emulator. But as short as possible to prevent the test running a long | 
|  | // time. | 
|  | trigger->set_stop_delay_ms(500); | 
|  |  | 
|  | // 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). | 
|  | const std::string path = RandomTraceFileName(); | 
|  | ScopedFileRemove remove_on_test_exit(path); | 
|  | auto perfetto_proc = ExecPerfetto( | 
|  | { | 
|  | "-o", | 
|  | path, | 
|  | "-c", | 
|  | "-", | 
|  | }, | 
|  | trace_config.SerializeAsString()); | 
|  |  | 
|  | auto trigger_proc = ExecTrigger({"trigger_name"}); | 
|  |  | 
|  | // Start the service and connect a simple fake producer. | 
|  | StartServiceIfRequiredNoNewExecsAfterThis(); | 
|  |  | 
|  | auto* fake_producer = ConnectFakeProducer(); | 
|  | EXPECT_TRUE(fake_producer); | 
|  |  | 
|  | // Start a background thread that will deliver the config now that we've | 
|  | // started the service. See |perfetto_proc| above for the args passed. | 
|  | std::thread background_trace([&perfetto_proc]() { | 
|  | std::string stderr_str; | 
|  | EXPECT_EQ(0, perfetto_proc.Run(&stderr_str)) << stderr_str; | 
|  | }); | 
|  |  | 
|  | WaitForProducerSetup(); | 
|  | EXPECT_EQ(0, trigger_proc.Run(&stderr_)); | 
|  |  | 
|  | // Wait for the producer to start, and then write out 11 packets. | 
|  | WaitForProducerEnabled(); | 
|  | auto on_data_written = task_runner_.CreateCheckpoint("data_written"); | 
|  | fake_producer->ProduceEventBatch(WrapTask(on_data_written)); | 
|  | task_runner_.RunUntilCheckpoint("data_written"); | 
|  | background_trace.join(); | 
|  |  | 
|  | std::string trace_str; | 
|  | base::ReadFile(path, &trace_str); | 
|  | protos::gen::Trace trace; | 
|  | ASSERT_TRUE(trace.ParseFromString(trace_str)); | 
|  | size_t for_testing_packets = 0; | 
|  | size_t trigger_packets = 0; | 
|  | size_t trace_config_packets = 0; | 
|  | for (const auto& packet : trace.packet()) { | 
|  | if (packet.has_trace_config()) { | 
|  | // Ensure the trace config properly includes the trigger mode we set. | 
|  | auto kStartTrig = protos::gen::TraceConfig::TriggerConfig::START_TRACING; | 
|  | EXPECT_EQ(kStartTrig, | 
|  | packet.trace_config().trigger_config().trigger_mode()); | 
|  | ++trace_config_packets; | 
|  | } else if (packet.has_trigger()) { | 
|  | // validate that the triggers are properly added to the trace. | 
|  | EXPECT_EQ("trigger_name", packet.trigger().trigger_name()); | 
|  | ++trigger_packets; | 
|  | } else if (packet.has_for_testing()) { | 
|  | // Make sure that the data size is correctly set based on what we | 
|  | // requested. | 
|  | EXPECT_EQ(kMessageSize, packet.for_testing().str().size()); | 
|  | ++for_testing_packets; | 
|  | } | 
|  | } | 
|  | EXPECT_EQ(trace_config_packets, 1u); | 
|  | EXPECT_EQ(trigger_packets, 1u); | 
|  | EXPECT_EQ(for_testing_packets, kMessageCount); | 
|  | } | 
|  |  | 
|  | TEST_F(PerfettoCmdlineTest, StopTracingTrigger) { | 
|  | // See |message_count| and |message_size| in the TraceConfig above. | 
|  | constexpr size_t kMessageCount = 11; | 
|  | constexpr size_t kMessageSize = 32; | 
|  | protos::gen::TraceConfig trace_config; | 
|  | trace_config.add_buffers()->set_size_kb(1024); | 
|  | 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(kMessageCount); | 
|  | ds_config->mutable_for_testing()->set_message_size(kMessageSize); | 
|  | auto* trigger_cfg = trace_config.mutable_trigger_config(); | 
|  | trigger_cfg->set_trigger_mode( | 
|  | protos::gen::TraceConfig::TriggerConfig::STOP_TRACING); | 
|  | trigger_cfg->set_trigger_timeout_ms(15000); | 
|  | auto* trigger = trigger_cfg->add_triggers(); | 
|  | trigger->set_name("trigger_name"); | 
|  | // |stop_delay_ms| must be long enough that we can write the packets in | 
|  | // before the trace finishes. This has to be long enough for the slowest | 
|  | // emulator. But as short as possible to prevent the test running a long | 
|  | // time. | 
|  | trigger->set_stop_delay_ms(500); | 
|  | trigger = trigger_cfg->add_triggers(); | 
|  | trigger->set_name("trigger_name_3"); | 
|  | trigger->set_stop_delay_ms(60000); | 
|  |  | 
|  | // 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). | 
|  | const std::string path = RandomTraceFileName(); | 
|  | ScopedFileRemove remove_on_test_exit(path); | 
|  | auto perfetto_proc = ExecPerfetto( | 
|  | { | 
|  | "-o", | 
|  | path, | 
|  | "-c", | 
|  | "-", | 
|  | }, | 
|  | trace_config.SerializeAsString()); | 
|  |  | 
|  | auto trigger_proc = | 
|  | ExecTrigger({"trigger_name_2", "trigger_name", "trigger_name_3"}); | 
|  |  | 
|  | // Start the service and connect a simple fake producer. | 
|  | StartServiceIfRequiredNoNewExecsAfterThis(); | 
|  | auto* fake_producer = ConnectFakeProducer(); | 
|  | EXPECT_TRUE(fake_producer); | 
|  |  | 
|  | // Start a background thread that will deliver the config now that we've | 
|  | // started the service. See |perfetto_proc| above for the args passed. | 
|  | std::thread background_trace([&perfetto_proc]() { | 
|  | std::string stderr_str; | 
|  | EXPECT_EQ(0, perfetto_proc.Run(&stderr_str)) << stderr_str; | 
|  | }); | 
|  |  | 
|  | WaitForProducerEnabled(); | 
|  | // Wait for the producer to start, and then write out 11 packets, before the | 
|  | // trace actually starts (the trigger is seen). | 
|  | auto on_data_written = task_runner_.CreateCheckpoint("data_written_1"); | 
|  | fake_producer->ProduceEventBatch(WrapTask(on_data_written)); | 
|  | task_runner_.RunUntilCheckpoint("data_written_1"); | 
|  |  | 
|  | EXPECT_EQ(0, trigger_proc.Run(&stderr_)) << "stderr: " << stderr_; | 
|  |  | 
|  | background_trace.join(); | 
|  |  | 
|  | std::string trace_str; | 
|  | base::ReadFile(path, &trace_str); | 
|  | protos::gen::Trace trace; | 
|  | ASSERT_TRUE(trace.ParseFromString(trace_str)); | 
|  | bool seen_first_trigger = false; | 
|  | size_t for_testing_packets = 0; | 
|  | size_t trigger_packets = 0; | 
|  | size_t trace_config_packets = 0; | 
|  | for (const auto& packet : trace.packet()) { | 
|  | if (packet.has_trace_config()) { | 
|  | // Ensure the trace config properly includes the trigger mode we set. | 
|  | auto kStopTrig = protos::gen::TraceConfig::TriggerConfig::STOP_TRACING; | 
|  | EXPECT_EQ(kStopTrig, | 
|  | packet.trace_config().trigger_config().trigger_mode()); | 
|  | ++trace_config_packets; | 
|  | } else if (packet.has_trigger()) { | 
|  | // validate that the triggers are properly added to the trace. | 
|  | if (!seen_first_trigger) { | 
|  | EXPECT_EQ("trigger_name", packet.trigger().trigger_name()); | 
|  | seen_first_trigger = true; | 
|  | } else { | 
|  | EXPECT_EQ("trigger_name_3", packet.trigger().trigger_name()); | 
|  | } | 
|  | ++trigger_packets; | 
|  | } else if (packet.has_for_testing()) { | 
|  | // Make sure that the data size is correctly set based on what we | 
|  | // requested. | 
|  | EXPECT_EQ(kMessageSize, packet.for_testing().str().size()); | 
|  | ++for_testing_packets; | 
|  | } | 
|  | } | 
|  | EXPECT_EQ(trace_config_packets, 1u); | 
|  | EXPECT_EQ(trigger_packets, 2u); | 
|  | EXPECT_EQ(for_testing_packets, kMessageCount); | 
|  | } | 
|  |  | 
|  | // Dropbox on the commandline client only works on android builds. So disable | 
|  | // this test on all other builds. | 
|  | TEST_F(PerfettoCmdlineTest, AndroidOnly(NoDataNoFileWithoutTrigger)) { | 
|  | // See |message_count| and |message_size| in the TraceConfig above. | 
|  | constexpr size_t kMessageCount = 11; | 
|  | constexpr size_t kMessageSize = 32; | 
|  | protos::gen::TraceConfig trace_config; | 
|  | trace_config.add_buffers()->set_size_kb(1024); | 
|  | trace_config.set_allow_user_build_tracing(true); | 
|  | auto* incident_config = trace_config.mutable_incident_report_config(); | 
|  | incident_config->set_destination_package("foo.bar.baz"); | 
|  | 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(kMessageCount); | 
|  | ds_config->mutable_for_testing()->set_message_size(kMessageSize); | 
|  | auto* trigger_cfg = trace_config.mutable_trigger_config(); | 
|  | trigger_cfg->set_trigger_mode( | 
|  | protos::gen::TraceConfig::TriggerConfig::STOP_TRACING); | 
|  | trigger_cfg->set_trigger_timeout_ms(1000); | 
|  | auto* trigger = trigger_cfg->add_triggers(); | 
|  | trigger->set_name("trigger_name"); | 
|  | // |stop_delay_ms| must be long enough that we can write the packets in | 
|  | // before the trace finishes. This has to be long enough for the slowest | 
|  | // emulator. But as short as possible to prevent the test running a long | 
|  | // time. | 
|  | trigger->set_stop_delay_ms(500); | 
|  | trigger = trigger_cfg->add_triggers(); | 
|  |  | 
|  | // 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). | 
|  | const std::string path = RandomTraceFileName(); | 
|  | ScopedFileRemove remove_on_test_exit(path); | 
|  | auto perfetto_proc = ExecPerfetto( | 
|  | { | 
|  | "--dropbox", | 
|  | "TAG", | 
|  | "--no-guardrails", | 
|  | "-c", | 
|  | "-", | 
|  | }, | 
|  | trace_config.SerializeAsString()); | 
|  |  | 
|  | StartServiceIfRequiredNoNewExecsAfterThis(); | 
|  | auto* fake_producer = ConnectFakeProducer(); | 
|  | EXPECT_TRUE(fake_producer); | 
|  |  | 
|  | std::string stderr_str; | 
|  | std::thread background_trace([&perfetto_proc, &stderr_str]() { | 
|  | EXPECT_EQ(0, perfetto_proc.Run(&stderr_str)); | 
|  | }); | 
|  | background_trace.join(); | 
|  |  | 
|  | EXPECT_THAT(stderr_str, | 
|  | ::testing::HasSubstr("Skipping write to incident. Empty trace.")); | 
|  | } | 
|  |  | 
|  | TEST_F(PerfettoCmdlineTest, StopTracingTriggerFromConfig) { | 
|  | // See |message_count| and |message_size| in the TraceConfig above. | 
|  | constexpr size_t kMessageCount = 11; | 
|  | constexpr size_t kMessageSize = 32; | 
|  | protos::gen::TraceConfig trace_config; | 
|  | trace_config.add_buffers()->set_size_kb(1024); | 
|  | 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(kMessageCount); | 
|  | ds_config->mutable_for_testing()->set_message_size(kMessageSize); | 
|  | auto* trigger_cfg = trace_config.mutable_trigger_config(); | 
|  | trigger_cfg->set_trigger_mode( | 
|  | protos::gen::TraceConfig::TriggerConfig::STOP_TRACING); | 
|  | trigger_cfg->set_trigger_timeout_ms(15000); | 
|  | auto* trigger = trigger_cfg->add_triggers(); | 
|  | trigger->set_name("trigger_name"); | 
|  | // |stop_delay_ms| must be long enough that we can write the packets in | 
|  | // before the trace finishes. This has to be long enough for the slowest | 
|  | // emulator. But as short as possible to prevent the test running a long | 
|  | // time. | 
|  | trigger->set_stop_delay_ms(500); | 
|  | trigger = trigger_cfg->add_triggers(); | 
|  | trigger->set_name("trigger_name_3"); | 
|  | trigger->set_stop_delay_ms(60000); | 
|  |  | 
|  | // 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). | 
|  | const std::string path = RandomTraceFileName(); | 
|  | ScopedFileRemove remove_on_test_exit(path); | 
|  | auto perfetto_proc = ExecPerfetto( | 
|  | { | 
|  | "-o", | 
|  | path, | 
|  | "-c", | 
|  | "-", | 
|  | }, | 
|  | trace_config.SerializeAsString()); | 
|  |  | 
|  | std::string triggers = R"( | 
|  | activate_triggers: "trigger_name_2" | 
|  | activate_triggers: "trigger_name" | 
|  | activate_triggers: "trigger_name_3" | 
|  | )"; | 
|  | auto perfetto_proc_2 = ExecPerfetto( | 
|  | { | 
|  | "-o", | 
|  | path, | 
|  | "-c", | 
|  | "-", | 
|  | "--txt", | 
|  | }, | 
|  | triggers); | 
|  |  | 
|  | // Start the service and connect a simple fake producer. | 
|  | StartServiceIfRequiredNoNewExecsAfterThis(); | 
|  | auto* fake_producer = ConnectFakeProducer(); | 
|  | EXPECT_TRUE(fake_producer); | 
|  |  | 
|  | std::thread background_trace([&perfetto_proc]() { | 
|  | std::string stderr_str; | 
|  | EXPECT_EQ(0, perfetto_proc.Run(&stderr_str)) << stderr_str; | 
|  | }); | 
|  |  | 
|  | WaitForProducerEnabled(); | 
|  | // Wait for the producer to start, and then write out 11 packets, before the | 
|  | // trace actually starts (the trigger is seen). | 
|  | auto on_data_written = task_runner_.CreateCheckpoint("data_written_1"); | 
|  | fake_producer->ProduceEventBatch(WrapTask(on_data_written)); | 
|  | task_runner_.RunUntilCheckpoint("data_written_1"); | 
|  |  | 
|  | EXPECT_EQ(0, perfetto_proc_2.Run(&stderr_)) << "stderr: " << stderr_; | 
|  |  | 
|  | background_trace.join(); | 
|  |  | 
|  | std::string trace_str; | 
|  | base::ReadFile(path, &trace_str); | 
|  | protos::gen::Trace trace; | 
|  | ASSERT_TRUE(trace.ParseFromString(trace_str)); | 
|  | EXPECT_LT(static_cast<int>(kMessageCount), trace.packet_size()); | 
|  | bool seen_first_trigger = false; | 
|  | for (const auto& packet : trace.packet()) { | 
|  | if (packet.has_trace_config()) { | 
|  | // Ensure the trace config properly includes the trigger mode we set. | 
|  | auto kStopTrig = protos::gen::TraceConfig::TriggerConfig::STOP_TRACING; | 
|  | EXPECT_EQ(kStopTrig, | 
|  | packet.trace_config().trigger_config().trigger_mode()); | 
|  | } else if (packet.has_trigger()) { | 
|  | // validate that the triggers are properly added to the trace. | 
|  | if (!seen_first_trigger) { | 
|  | EXPECT_EQ("trigger_name", packet.trigger().trigger_name()); | 
|  | seen_first_trigger = true; | 
|  | } else { | 
|  | EXPECT_EQ("trigger_name_3", packet.trigger().trigger_name()); | 
|  | } | 
|  | } else if (packet.has_for_testing()) { | 
|  | // Make sure that the data size is correctly set based on what we | 
|  | // requested. | 
|  | EXPECT_EQ(kMessageSize, packet.for_testing().str().size()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(PerfettoCmdlineTest, TriggerFromConfigStopsFileOpening) { | 
|  | // See |message_count| and |message_size| in the TraceConfig above. | 
|  | constexpr size_t kMessageCount = 11; | 
|  | constexpr size_t kMessageSize = 32; | 
|  | protos::gen::TraceConfig trace_config; | 
|  | trace_config.add_buffers()->set_size_kb(1024); | 
|  | 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(kMessageCount); | 
|  | ds_config->mutable_for_testing()->set_message_size(kMessageSize); | 
|  | auto* trigger_cfg = trace_config.mutable_trigger_config(); | 
|  | trigger_cfg->set_trigger_mode( | 
|  | protos::gen::TraceConfig::TriggerConfig::STOP_TRACING); | 
|  | trigger_cfg->set_trigger_timeout_ms(15000); | 
|  | auto* trigger = trigger_cfg->add_triggers(); | 
|  | trigger->set_name("trigger_name"); | 
|  | // |stop_delay_ms| must be long enough that we can write the packets in | 
|  | // before the trace finishes. This has to be long enough for the slowest | 
|  | // emulator. But as short as possible to prevent the test running a long | 
|  | // time. | 
|  | trigger->set_stop_delay_ms(500); | 
|  | trigger = trigger_cfg->add_triggers(); | 
|  | trigger->set_name("trigger_name_3"); | 
|  | trigger->set_stop_delay_ms(60000); | 
|  |  | 
|  | // 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). | 
|  | const std::string path = RandomTraceFileName(); | 
|  | ScopedFileRemove remove_on_test_exit(path); | 
|  | std::string triggers = R"( | 
|  | activate_triggers: "trigger_name_2" | 
|  | activate_triggers: "trigger_name" | 
|  | activate_triggers: "trigger_name_3" | 
|  | )"; | 
|  | auto perfetto_proc = ExecPerfetto( | 
|  | { | 
|  | "-o", | 
|  | path, | 
|  | "-c", | 
|  | "-", | 
|  | "--txt", | 
|  | }, | 
|  | triggers); | 
|  |  | 
|  | // Start the service and connect a simple fake producer. | 
|  | StartServiceIfRequiredNoNewExecsAfterThis(); | 
|  | auto* fake_producer = ConnectFakeProducer(); | 
|  | EXPECT_TRUE(fake_producer); | 
|  |  | 
|  | std::string trace_str; | 
|  | EXPECT_FALSE(base::ReadFile(path, &trace_str)); | 
|  |  | 
|  | EXPECT_EQ(0, perfetto_proc.Run(&stderr_)) << "stderr: " << stderr_; | 
|  |  | 
|  | EXPECT_FALSE(base::ReadFile(path, &trace_str)); | 
|  | } | 
|  |  | 
|  | TEST_F(PerfettoCmdlineTest, Query) { | 
|  | auto query = ExecPerfetto({"--query"}); | 
|  | auto query_raw = ExecPerfetto({"--query-raw"}); | 
|  | StartServiceIfRequiredNoNewExecsAfterThis(); | 
|  | EXPECT_EQ(0, query.Run(&stderr_)) << stderr_; | 
|  | EXPECT_EQ(0, query_raw.Run(&stderr_)) << stderr_; | 
|  | } | 
|  |  | 
|  | TEST_F(PerfettoCmdlineTest, AndroidOnly(CmdTriggerWithUploadFlag)) { | 
|  | // See |message_count| and |message_size| in the TraceConfig above. | 
|  | constexpr size_t kMessageCount = 2; | 
|  | constexpr size_t kMessageSize = 2; | 
|  | protos::gen::TraceConfig trace_config; | 
|  | trace_config.add_buffers()->set_size_kb(1024); | 
|  | 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(kMessageCount); | 
|  | ds_config->mutable_for_testing()->set_message_size(kMessageSize); | 
|  | auto* trigger_cfg = trace_config.mutable_trigger_config(); | 
|  | trigger_cfg->set_trigger_mode( | 
|  | protos::gen::TraceConfig::TriggerConfig::STOP_TRACING); | 
|  | trigger_cfg->set_trigger_timeout_ms(15000); | 
|  | auto* trigger = trigger_cfg->add_triggers(); | 
|  | trigger->set_name("trigger_name"); | 
|  | // |stop_delay_ms| must be long enough that we can write the packets in | 
|  | // before the trace finishes. This has to be long enough for the slowest | 
|  | // emulator. But as short as possible to prevent the test running a long | 
|  | // time. | 
|  | trigger->set_stop_delay_ms(500); | 
|  |  | 
|  | // 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). | 
|  | const std::string path = RandomTraceFileName(); | 
|  | ScopedFileRemove remove_on_test_exit(path); | 
|  | auto perfetto_proc = ExecPerfetto( | 
|  | { | 
|  | "-o", | 
|  | path, | 
|  | "-c", | 
|  | "-", | 
|  | }, | 
|  | trace_config.SerializeAsString()); | 
|  |  | 
|  | std::string triggers = R"( | 
|  | activate_triggers: "trigger_name" | 
|  | )"; | 
|  | auto perfetto_proc_2 = ExecPerfetto( | 
|  | { | 
|  | "--upload", | 
|  | "-c", | 
|  | "-", | 
|  | "--txt", | 
|  | }, | 
|  | triggers); | 
|  |  | 
|  | // Start the service and connect a simple fake producer. | 
|  | StartServiceIfRequiredNoNewExecsAfterThis(); | 
|  | auto* fake_producer = ConnectFakeProducer(); | 
|  | EXPECT_TRUE(fake_producer); | 
|  |  | 
|  | std::thread background_trace([&perfetto_proc]() { | 
|  | std::string stderr_str; | 
|  | EXPECT_EQ(0, perfetto_proc.Run(&stderr_str)) << stderr_str; | 
|  | }); | 
|  |  | 
|  | WaitForProducerEnabled(); | 
|  | // Wait for the producer to start, and then write out 11 packets, before the | 
|  | // trace actually starts (the trigger is seen). | 
|  | auto on_data_written = task_runner_.CreateCheckpoint("data_written_1"); | 
|  | fake_producer->ProduceEventBatch(WrapTask(on_data_written)); | 
|  | task_runner_.RunUntilCheckpoint("data_written_1"); | 
|  |  | 
|  | EXPECT_EQ(0, perfetto_proc_2.Run(&stderr_)) << "stderr: " << stderr_; | 
|  |  | 
|  | background_trace.join(); | 
|  |  | 
|  | std::string trace_str; | 
|  | base::ReadFile(path, &trace_str); | 
|  | protos::gen::Trace trace; | 
|  | ASSERT_TRUE(trace.ParseFromString(trace_str)); | 
|  | EXPECT_LT(static_cast<int>(kMessageCount), trace.packet_size()); | 
|  | EXPECT_THAT(trace.packet(), | 
|  | Contains(Property(&protos::gen::TracePacket::trigger, | 
|  | Property(&protos::gen::Trigger::trigger_name, | 
|  | Eq("trigger_name"))))); | 
|  | } | 
|  |  | 
|  | TEST_F(PerfettoCmdlineTest, TriggerCloneSnapshot) { | 
|  | constexpr size_t kMessageCount = 2; | 
|  | constexpr size_t kMessageSize = 2; | 
|  | protos::gen::TraceConfig trace_config; | 
|  | trace_config.add_buffers()->set_size_kb(1024); | 
|  | 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(kMessageCount); | 
|  | ds_config->mutable_for_testing()->set_message_size(kMessageSize); | 
|  | auto* trigger_cfg = trace_config.mutable_trigger_config(); | 
|  | trigger_cfg->set_trigger_mode( | 
|  | protos::gen::TraceConfig::TriggerConfig::CLONE_SNAPSHOT); | 
|  | trigger_cfg->set_trigger_timeout_ms(600000); | 
|  | auto* trigger = trigger_cfg->add_triggers(); | 
|  | trigger->set_name("trigger_name"); | 
|  | // |stop_delay_ms| must be long enough that we can write the packets in | 
|  | // before the trace finishes. This has to be long enough for the slowest | 
|  | // emulator. But as short as possible to prevent the test running a long | 
|  | // time. | 
|  | trigger->set_stop_delay_ms(500); | 
|  |  | 
|  | // 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). | 
|  | const std::string path = RandomTraceFileName(); | 
|  | ScopedFileRemove remove_on_test_exit(path); | 
|  | auto perfetto_proc = ExecPerfetto( | 
|  | { | 
|  | "-o", | 
|  | path, | 
|  | "-c", | 
|  | "-", | 
|  | }, | 
|  | trace_config.SerializeAsString()); | 
|  |  | 
|  | std::string triggers = R"( | 
|  | activate_triggers: "trigger_name" | 
|  | )"; | 
|  | auto trigger_proc = ExecPerfetto( | 
|  | { | 
|  | "-c", | 
|  | "-", | 
|  | "--txt", | 
|  | }, | 
|  | triggers); | 
|  |  | 
|  | // Start the service and connect a simple fake producer. | 
|  | StartServiceIfRequiredNoNewExecsAfterThis(); | 
|  | auto* fake_producer = ConnectFakeProducer(); | 
|  | EXPECT_TRUE(fake_producer); | 
|  |  | 
|  | std::thread background_trace([&perfetto_proc]() { | 
|  | std::string stderr_str; | 
|  | EXPECT_EQ(0, perfetto_proc.Run(&stderr_str)) << stderr_str; | 
|  | }); | 
|  |  | 
|  | WaitForProducerEnabled(); | 
|  | // Wait for the producer to start, and then write out 11 packets, before the | 
|  | // trace actually starts (the trigger is seen). | 
|  | auto on_data_written = task_runner_.CreateCheckpoint("data_written_1"); | 
|  | fake_producer->ProduceEventBatch(WrapTask(on_data_written)); | 
|  | task_runner_.RunUntilCheckpoint("data_written_1"); | 
|  |  | 
|  | EXPECT_EQ(0, trigger_proc.Run(&stderr_)) << "stderr: " << stderr_; | 
|  |  | 
|  | // Now we need to wait that the `perfetto_proc` creates the snapshot trace | 
|  | // file in the trace/path.0 file (appending .0). Once that is done we can | 
|  | // kill the perfetto cmd (otherwise it will keep running for the whole | 
|  | // trigger_timeout_ms, unlike the case of STOP_TRACING. | 
|  | std::string snapshot_path = path + ".0"; | 
|  | for (int i = 0; i < 100 && !base::FileExists(snapshot_path); i++) { | 
|  | std::this_thread::sleep_for(std::chrono::milliseconds(100)); | 
|  | } | 
|  | ASSERT_TRUE(base::FileExists(snapshot_path)); | 
|  |  | 
|  | perfetto_proc.SendSigterm(); | 
|  | background_trace.join(); | 
|  |  | 
|  | std::string trace_str; | 
|  | base::ReadFile(snapshot_path, &trace_str); | 
|  | protos::gen::Trace trace; | 
|  | ASSERT_TRUE(trace.ParseFromString(trace_str)); | 
|  | EXPECT_LT(static_cast<int>(kMessageCount), trace.packet_size()); | 
|  | EXPECT_THAT(trace.packet(), | 
|  | Contains(Property(&protos::gen::TracePacket::trigger, | 
|  | Property(&protos::gen::Trigger::trigger_name, | 
|  | Eq("trigger_name"))))); | 
|  | } | 
|  |  | 
|  | 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)); | 
|  | } | 
|  |  | 
|  | TEST_F(PerfettoCmdlineTest, Clone) { | 
|  | TraceConfig trace_config = CreateTraceConfigForBugreportTest(); | 
|  | RunBugreportTest(std::move(trace_config), /*check_original_trace=*/true, | 
|  | /*use_explicit_clone=*/true); | 
|  | } | 
|  |  | 
|  | // Regression test for b/279753347 . | 
|  | TEST_F(PerfettoCmdlineTest, UnavailableBugreportLeavesNoEmptyFiles) { | 
|  | ScopedFileRemove remove_on_test_exit(GetBugreportTracePath()); | 
|  | Exec perfetto_br_proc = ExecPerfetto({"--save-for-bugreport"}); | 
|  | StartServiceIfRequiredNoNewExecsAfterThis(); | 
|  | perfetto_br_proc.Run(&stderr_); | 
|  | ASSERT_FALSE(base::FileExists(GetBugreportTracePath())); | 
|  | } | 
|  |  | 
|  | // 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 |