xref: /aosp_15_r20/external/perfetto/src/traced_relay/relay_service_integrationtest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <memory>
18 #include <string>
19 #include <vector>
20 #include "perfetto/ext/base/unix_socket.h"
21 #include "protos/perfetto/trace/remote_clock_sync.gen.h"
22 #include "src/traced_relay/relay_service.h"
23 
24 #include "src/base/test/test_task_runner.h"
25 #include "test/gtest_and_gmock.h"
26 #include "test/test_helper.h"
27 
28 #include "protos/perfetto/config/test_config.gen.h"
29 #include "protos/perfetto/config/trace_config.gen.h"
30 #include "protos/perfetto/trace/test_event.gen.h"
31 
32 namespace perfetto {
33 namespace {
34 
35 struct TestParams {
36   std::string id;
37   std::string tcp_sock_name;
38   std::string unix_sock_name;
39   std::string producer_name;
40 
41   std::unique_ptr<RelayService> relay_service;
42   std::unique_ptr<base::UnixSocket> server_socket;
43   std::unique_ptr<FakeProducerThread> producer_thread;
44 };
45 
TEST(TracedRelayIntegrationTest,BasicCase)46 TEST(TracedRelayIntegrationTest, BasicCase) {
47   base::TestTaskRunner task_runner;
48 
49   std::string sock_name;
50   {
51     // Set up a server UnixSocket to find an unused TCP port.
52     base::UnixSocket::EventListener event_listener;
53     auto srv = base::UnixSocket::Listen("127.0.0.1:0", &event_listener,
54                                         &task_runner, base::SockFamily::kInet,
55                                         base::SockType::kStream);
56     ASSERT_TRUE(srv->is_listening());
57     sock_name = srv->GetSockAddr();
58     // Shut down |srv| here to free the port. It's unlikely that the port will
59     // be taken by another process so quickly before we reach the code below.
60   }
61 
62   TestHelper helper(&task_runner, TestHelper::Mode::kStartDaemons,
63                     sock_name.c_str(), /*enable_relay_endpoint=*/true);
64   ASSERT_EQ(helper.num_producers(), 1u);
65   helper.StartServiceIfRequired();
66 
67   auto relay_service = std::make_unique<RelayService>(&task_runner);
68   // Don't let RelayClient interfere with the testing of relayed producers.
69   relay_service->SetRelayClientDisabledForTesting(true);
70 
71   relay_service->Start("@traced_relay", sock_name.c_str());
72 
73   auto producer_connected =
74       task_runner.CreateCheckpoint("perfetto.FakeProducer.connected");
75   auto noop = []() {};
76   auto connected = [&]() { task_runner.PostTask(producer_connected); };
77 
78   // We won't use the built-in fake producer and will start our own.
79   auto producer_thread = std::make_unique<FakeProducerThread>(
80       "@traced_relay", connected, noop, noop, "perfetto.FakeProducer");
81   producer_thread->Connect();
82   task_runner.RunUntilCheckpoint("perfetto.FakeProducer.connected");
83 
84   helper.ConnectConsumer();
85   helper.WaitForConsumerConnect();
86 
87   TraceConfig trace_config;
88   trace_config.add_buffers()->set_size_kb(1024);
89   trace_config.set_duration_ms(200);
90 
91   static constexpr uint32_t kMsgSize = 1024;
92   static constexpr uint32_t kRandomSeed = 42;
93   // Enable the producer.
94   auto* ds_config = trace_config.add_data_sources()->mutable_config();
95   ds_config->set_name("perfetto.FakeProducer");
96   ds_config->set_target_buffer(0);
97   ds_config->mutable_for_testing()->set_seed(kRandomSeed);
98   ds_config->mutable_for_testing()->set_message_count(12);
99   ds_config->mutable_for_testing()->set_message_size(kMsgSize);
100   ds_config->mutable_for_testing()->set_send_batch_on_register(true);
101 
102   helper.StartTracing(trace_config);
103   helper.WaitForTracingDisabled();
104 
105   helper.ReadData();
106   helper.WaitForReadData();
107 
108   const auto& packets = helper.trace();
109   ASSERT_EQ(packets.size(), 12u);
110 
111   // The producer is connected from this process. The relay service will inject
112   // the SetPeerIdentity message using the pid and euid of the current process.
113   auto pid = static_cast<int32_t>(getpid());
114   auto uid = static_cast<int32_t>(geteuid());
115 
116   std::minstd_rand0 rnd_engine(kRandomSeed);
117   for (const auto& packet : packets) {
118     ASSERT_TRUE(packet.has_for_testing());
119     ASSERT_EQ(packet.trusted_pid(), pid);
120     ASSERT_EQ(packet.trusted_uid(), uid);
121     ASSERT_EQ(packet.for_testing().seq_value(), rnd_engine());
122     // The tracing service should emit non-default machine ID in trace packets.
123     ASSERT_NE(packet.machine_id(), 0u);
124   }
125 }
126 
TEST(TracedRelayIntegrationTest,MachineID_MultiRelayService)127 TEST(TracedRelayIntegrationTest, MachineID_MultiRelayService) {
128   base::TestTaskRunner task_runner;
129   std::vector<TestParams> test_params(2);
130 
131   base::UnixSocket::EventListener event_listener;
132   for (size_t i = 0; i < test_params.size(); i++) {
133     auto& param = test_params[i];
134     param.id = std::to_string(i + 1);
135     param.server_socket = base::UnixSocket::Listen(
136         "127.0.0.1:0", &event_listener, &task_runner, base::SockFamily::kInet,
137         base::SockType::kStream);
138     ASSERT_TRUE(param.server_socket->is_listening());
139     param.tcp_sock_name = param.server_socket->GetSockAddr();
140     param.relay_service = std::make_unique<RelayService>(&task_runner);
141     param.relay_service->SetMachineIdHintForTesting("test-machine-id-" +
142                                                     param.id);
143     param.unix_sock_name = std::string("@traced_relay_") + param.id;
144     param.producer_name = std::string("perfetto.FakeProducer.") + param.id;
145   }
146   for (auto& param : test_params) {
147     // Shut down listening sockets to free the port. It's unlikely that the port
148     // will be taken by another process so quickly before we reach the code
149     // below.
150     param.server_socket = nullptr;
151   }
152   auto relay_sock_name =
153       test_params[0].tcp_sock_name + "," + test_params[1].tcp_sock_name;
154 
155   for (auto& param : test_params) {
156     param.relay_service->Start(param.unix_sock_name.c_str(),
157                                param.tcp_sock_name.c_str());
158     // Don't let RelayClient interfere with the testing of relayed producers.
159     param.relay_service->SetRelayClientDisabledForTesting(true);
160   }
161 
162   TestHelper helper(&task_runner, TestHelper::Mode::kStartDaemons,
163                     relay_sock_name.c_str(), /*enable_relay_endpoint=*/true);
164   ASSERT_EQ(helper.num_producers(), 2u);
165   helper.StartServiceIfRequired();
166 
167   for (auto& param : test_params) {
168     auto checkpoint_name = "perfetto.FakeProducer.connected." + param.id;
169     auto producer_connected = task_runner.CreateCheckpoint(checkpoint_name);
170     auto noop = []() {};
171     auto connected = std::bind(
172         [&](std::function<void()> checkpoint) {
173           task_runner.PostTask(checkpoint);
174         },
175         producer_connected);
176     // We won't use the built-in fake producer and will start our own.
177     param.producer_thread = std::make_unique<FakeProducerThread>(
178         param.unix_sock_name, connected, noop, noop, param.producer_name);
179     param.producer_thread->Connect();
180     task_runner.RunUntilCheckpoint(checkpoint_name);
181   }
182 
183   helper.ConnectConsumer();
184   helper.WaitForConsumerConnect();
185 
186   TraceConfig trace_config;
187   trace_config.add_buffers()->set_size_kb(1024);
188   trace_config.set_duration_ms(200);
189 
190   static constexpr uint32_t kMsgSize = 1024;
191   static constexpr uint32_t kRandomSeed = 42;
192 
193   // Enable the 1st producer.
194   auto* ds_config = trace_config.add_data_sources()->mutable_config();
195   ds_config->set_name("perfetto.FakeProducer.1");
196   ds_config->set_target_buffer(0);
197   ds_config->mutable_for_testing()->set_message_count(12);
198   ds_config->mutable_for_testing()->set_message_size(kMsgSize);
199   ds_config->mutable_for_testing()->set_send_batch_on_register(true);
200   // Enable the 2nd producer.
201   ds_config = trace_config.add_data_sources()->mutable_config();
202   ds_config->set_name("perfetto.FakeProducer.2");
203   ds_config->set_target_buffer(0);
204   ds_config->mutable_for_testing()->set_message_count(24);
205   ds_config->mutable_for_testing()->set_message_size(kMsgSize);
206   ds_config->mutable_for_testing()->set_send_batch_on_register(true);
207 
208   helper.StartTracing(trace_config);
209   helper.WaitForTracingDisabled();
210 
211   helper.ReadData();
212   helper.WaitForReadData();
213 
214   const auto& packets = helper.trace();
215   ASSERT_EQ(packets.size(), 36u);
216 
217   // The producer is connected from this process. The relay service will inject
218   // the SetPeerIdentity message using the pid and euid of the current process.
219   auto pid = static_cast<int32_t>(getpid());
220   auto uid = static_cast<int32_t>(geteuid());
221 
222   std::minstd_rand0 rnd_engine(kRandomSeed);
223   std::map<uint32_t, size_t> packets_counts;  // machine ID => count.
224 
225   for (const auto& packet : packets) {
226     ASSERT_TRUE(packet.has_for_testing());
227     ASSERT_EQ(packet.trusted_pid(), pid);
228     ASSERT_EQ(packet.trusted_uid(), uid);
229     packets_counts[packet.machine_id()]++;
230   }
231 
232   // Fake producer (1, 2) either gets machine ID (1, 2), or (2, 1), depending on
233   // which on is seen by the tracing service first.
234   ASSERT_EQ(packets_counts.size(), 2u);
235   auto count_1 = packets_counts.begin()->second;
236   auto count_2 = packets_counts.rbegin()->second;
237   ASSERT_TRUE(count_1 == 12u || count_1 == 24u);
238   ASSERT_EQ(count_1 + count_2, 36u);
239 
240   for (auto& param : test_params) {
241     param.producer_thread = nullptr;
242     param.relay_service = nullptr;
243   }
244 }
245 
TEST(TracedRelayIntegrationTest,RelayClient)246 TEST(TracedRelayIntegrationTest, RelayClient) {
247   base::TestTaskRunner task_runner;
248 
249   std::string sock_name;
250   {
251     // Set up a server UnixSocket to find an unused TCP port.
252     base::UnixSocket::EventListener event_listener;
253     auto srv = base::UnixSocket::Listen("127.0.0.1:0", &event_listener,
254                                         &task_runner, base::SockFamily::kInet,
255                                         base::SockType::kStream);
256     ASSERT_TRUE(srv->is_listening());
257     sock_name = srv->GetSockAddr();
258     // Shut down |srv| here to free the port. It's unlikely that the port will
259     // be taken by another process so quickly before we reach the code below.
260   }
261 
262   TestHelper helper(&task_runner, TestHelper::Mode::kStartDaemons,
263                     sock_name.c_str(), /*enable_relay_endpoint=*/true);
264   ASSERT_EQ(helper.num_producers(), 1u);
265   helper.StartServiceIfRequired();
266 
267   auto relay_service = std::make_unique<RelayService>(&task_runner);
268   // This also starts the RelayClient.
269   relay_service->Start("@traced_relay", sock_name.c_str());
270   ASSERT_TRUE(!!relay_service->relay_client_for_testing());
271 
272   auto producer_connected =
273       task_runner.CreateCheckpoint("perfetto.FakeProducer.connected");
274   auto noop = []() {};
275   auto connected = [&]() { task_runner.PostTask(producer_connected); };
276 
277   // We won't use the built-in fake producer and will start our own.
278   auto producer_thread = std::make_unique<FakeProducerThread>(
279       "@traced_relay", connected, noop, noop, "perfetto.FakeProducer");
280   producer_thread->Connect();
281   task_runner.RunUntilCheckpoint("perfetto.FakeProducer.connected");
282 
283   helper.ConnectConsumer();
284   helper.WaitForConsumerConnect();
285 
286   while (!relay_service->relay_client_for_testing()
287               ->clock_synced_with_service_for_testing())
288     task_runner.RunUntilIdle();
289 
290   TraceConfig trace_config;
291   trace_config.add_buffers()->set_size_kb(1024);
292   trace_config.set_duration_ms(200);
293 
294   // // Enable the producer.
295   auto* ds_config = trace_config.add_data_sources()->mutable_config();
296   ds_config->set_name("perfetto.FakeProducer");
297   ds_config->set_target_buffer(0);
298 
299   helper.StartTracing(trace_config);
300   helper.WaitForTracingDisabled();
301 
302   helper.ReadData();
303   helper.WaitForReadData();
304 
305   const auto& packets = helper.trace();
306 
307   bool clock_sync_packet_seen = false;
308   for (auto& packet : packets) {
309     if (!packet.has_remote_clock_sync())
310       continue;
311     clock_sync_packet_seen = true;
312 
313     auto& synced_clocks = packet.remote_clock_sync().synced_clocks();
314     ASSERT_FALSE(synced_clocks.empty());
315     for (auto& clock_offset : synced_clocks) {
316       ASSERT_TRUE(clock_offset.has_client_clocks());
317       ASSERT_TRUE(clock_offset.has_host_clocks());
318     }
319   }
320   ASSERT_TRUE(clock_sync_packet_seen);
321 }
322 
323 }  // namespace
324 }  // namespace perfetto
325