1 #include "perfetto/tracing/tracing.h"
2
3 #include <stdio.h>
4 #include <optional>
5
6 #include "perfetto/ext/base/thread_task_runner.h"
7 #include "perfetto/ext/base/waitable_event.h"
8 #include "perfetto/ext/tracing/ipc/service_ipc_host.h"
9 #include "perfetto/tracing/backend_type.h"
10 #include "protos/perfetto/config/trace_config.gen.h"
11 #include "protos/perfetto/trace/trace.gen.h"
12 #include "protos/perfetto/trace/trace_packet.gen.h"
13 #include "protos/perfetto/trace/trigger.gen.h"
14 #include "src/base/test/test_task_runner.h"
15 #include "src/base/test/tmp_dir_tree.h"
16 #include "test/gtest_and_gmock.h"
17
18 namespace perfetto {
19 namespace internal {
20 namespace {
21
22 using ::testing::NiceMock;
23 using ::testing::NotNull;
24 using ::testing::Property;
25
26 class TracingMuxerImplIntegrationTest : public testing::Test {
27 protected:
SetUp()28 void SetUp() override {
29 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
30 GTEST_SKIP() << "Unix sockets not supported on windows";
31 #endif
32 }
33
34 // Sets the environment variable `name` to `value`. Restores it to the
35 // previous value when the test finishes.
SetEnvVar(const char * name,const char * value)36 void SetEnvVar(const char* name, const char* value) {
37 prev_state_.emplace();
38 EnvVar& var = prev_state_.top();
39 var.name = name;
40 const char* prev_value = getenv(name);
41 if (prev_value) {
42 var.value.emplace(prev_value);
43 }
44 base::SetEnv(name, value);
45 }
46
~TracingMuxerImplIntegrationTest()47 ~TracingMuxerImplIntegrationTest() override {
48 perfetto::Tracing::ResetForTesting();
49 while (!prev_state_.empty()) {
50 const EnvVar& var = prev_state_.top();
51 if (var.value) {
52 base::SetEnv(var.name, *var.value);
53 } else {
54 base::UnsetEnv(var.name);
55 }
56 prev_state_.pop();
57 }
58 }
59
60 struct EnvVar {
61 const char* name;
62 std::optional<std::string> value;
63 };
64 // Stores previous values of environment variables overridden by tests. We
65 // need to to this because some android integration tests need to talk to the
66 // real system tracing service and need the PERFETTO_PRODUCER_SOCK_NAME and
67 // PERFETTO_CONSUMER_SOCK_NAME to be set to their original value.
68 std::stack<EnvVar> prev_state_;
69 };
70
71 class TracingServiceThread {
72 public:
TracingServiceThread(const std::string & producer_socket,const std::string & consumer_socket)73 TracingServiceThread(const std::string& producer_socket,
74 const std::string& consumer_socket)
75 : runner_(base::ThreadTaskRunner::CreateAndStart("perfetto.svc")),
76 producer_socket_(producer_socket),
77 consumer_socket_(consumer_socket) {
78 runner_.PostTaskAndWaitForTesting([this]() {
79 svc_ = ServiceIPCHost::CreateInstance(&runner_);
80 bool res =
81 svc_->Start(producer_socket_.c_str(), consumer_socket_.c_str());
82 if (!res) {
83 PERFETTO_FATAL("Failed to start service listening on %s and %s",
84 producer_socket_.c_str(), consumer_socket_.c_str());
85 }
86 });
87 }
88
~TracingServiceThread()89 ~TracingServiceThread() {
90 runner_.PostTaskAndWaitForTesting([this]() { svc_.reset(); });
91 }
92
producer_socket() const93 const std::string& producer_socket() const { return producer_socket_; }
consumer_socket() const94 const std::string& consumer_socket() const { return consumer_socket_; }
95
96 private:
97 base::ThreadTaskRunner runner_;
98
99 std::string producer_socket_;
100 std::string consumer_socket_;
101 std::unique_ptr<ServiceIPCHost> svc_;
102 };
103
TEST_F(TracingMuxerImplIntegrationTest,ActivateTriggers)104 TEST_F(TracingMuxerImplIntegrationTest, ActivateTriggers) {
105 base::TmpDirTree tmpdir_;
106
107 base::TestTaskRunner task_runner;
108
109 ASSERT_FALSE(perfetto::Tracing::IsInitialized());
110
111 tmpdir_.TrackFile("producer2.sock");
112 tmpdir_.TrackFile("consumer.sock");
113 TracingServiceThread tracing_service(tmpdir_.AbsolutePath("producer2.sock"),
114 tmpdir_.AbsolutePath("consumer.sock"));
115 // Instead of being a unix socket, producer.sock is a regular empty file.
116 tmpdir_.AddFile("producer.sock", "");
117
118 // Wrong producer socket: the producer won't connect yet, but the consumer
119 // will.
120 SetEnvVar("PERFETTO_PRODUCER_SOCK_NAME",
121 tmpdir_.AbsolutePath("producer.sock").c_str());
122 SetEnvVar("PERFETTO_CONSUMER_SOCK_NAME",
123 tmpdir_.AbsolutePath("consumer.sock").c_str());
124
125 TracingInitArgs args;
126 args.backends = perfetto::kSystemBackend;
127 perfetto::Tracing::Initialize(args);
128
129 // TracingMuxerImpl::ActivateTriggers will be called without the producer side
130 // of the service being connected. It should store the trigger for 10000ms.
131 perfetto::Tracing::ActivateTriggers({"trigger2", "trigger1"}, 10000);
132
133 perfetto::TraceConfig cfg;
134 cfg.add_buffers()->set_size_kb(1024);
135 perfetto::TraceConfig::TriggerConfig* tr_cfg = cfg.mutable_trigger_config();
136 tr_cfg->set_trigger_mode(perfetto::TraceConfig::TriggerConfig::STOP_TRACING);
137 tr_cfg->set_trigger_timeout_ms(10000);
138 perfetto::TraceConfig::TriggerConfig::Trigger* trigger =
139 tr_cfg->add_triggers();
140 trigger->set_name("trigger1");
141
142 std::unique_ptr<TracingSession> session =
143 perfetto::Tracing::NewTrace(perfetto::kSystemBackend);
144 base::WaitableEvent on_stop;
145 session->SetOnStopCallback([&on_stop] { on_stop.Notify(); });
146 session->Setup(cfg);
147
148 session->StartBlocking();
149
150 // Swap producer.sock and producer2.sock. Now the client should connect to the
151 // tracing service as a producer.
152 ASSERT_EQ(rename(tmpdir_.AbsolutePath("producer2.sock").c_str(),
153 tmpdir_.AbsolutePath("producer3.sock").c_str()),
154 0);
155 ASSERT_EQ(rename(tmpdir_.AbsolutePath("producer.sock").c_str(),
156 tmpdir_.AbsolutePath("producer2.sock").c_str()),
157 0);
158 ASSERT_EQ(rename(tmpdir_.AbsolutePath("producer3.sock").c_str(),
159 tmpdir_.AbsolutePath("producer.sock").c_str()),
160 0);
161
162 on_stop.Wait();
163
164 std::vector<char> bytes = session->ReadTraceBlocking();
165 perfetto::protos::gen::Trace parsed_trace;
166 ASSERT_TRUE(parsed_trace.ParseFromArray(bytes.data(), bytes.size()));
167 EXPECT_THAT(
168 parsed_trace,
169 Property(&perfetto::protos::gen::Trace::packet,
170 Contains(Property(
171 &perfetto::protos::gen::TracePacket::trigger,
172 Property(&perfetto::protos::gen::Trigger::trigger_name,
173 "trigger1")))));
174 }
175
176 } // namespace
177 } // namespace internal
178 } // namespace perfetto
179