xref: /aosp_15_r20/external/perfetto/src/traced_relay/relay_service.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 "src/traced_relay/relay_service.h"
18 
19 #include <functional>
20 #include <memory>
21 
22 #include "perfetto/base/build_config.h"
23 #include "perfetto/base/logging.h"
24 #include "perfetto/base/task_runner.h"
25 #include "perfetto/ext/base/clock_snapshots.h"
26 #include "perfetto/ext/base/file_utils.h"
27 #include "perfetto/ext/base/hash.h"
28 #include "perfetto/ext/base/string_utils.h"
29 #include "perfetto/ext/base/unix_socket.h"
30 #include "perfetto/ext/base/utils.h"
31 #include "perfetto/ext/ipc/client.h"
32 #include "perfetto/tracing/core/forward_decls.h"
33 #include "protos/perfetto/ipc/wire_protocol.gen.h"
34 #include "src/ipc/buffered_frame_deserializer.h"
35 #include "src/traced_relay/socket_relay_handler.h"
36 #include "src/tracing/ipc/producer/relay_ipc_client.h"
37 
38 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
39     PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
40     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
41 #include <fcntl.h>
42 #include <sys/stat.h>
43 #include <sys/syscall.h>
44 #include <sys/utsname.h>
45 #include <unistd.h>
46 #endif
47 
48 using ::perfetto::protos::gen::IPCFrame;
49 
50 namespace perfetto {
51 namespace {
52 
GenerateSetPeerIdentityRequest(int32_t pid,int32_t uid,const std::string & machine_id_hint)53 std::string GenerateSetPeerIdentityRequest(int32_t pid,
54                                            int32_t uid,
55                                            const std::string& machine_id_hint) {
56   IPCFrame ipc_frame;
57   ipc_frame.set_request_id(0);
58 
59   auto* set_peer_identity = ipc_frame.mutable_set_peer_identity();
60 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
61     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
62   set_peer_identity->set_pid(pid);
63 #else
64   base::ignore_result(pid);
65 #endif
66   set_peer_identity->set_uid(uid);
67   set_peer_identity->set_machine_id_hint(machine_id_hint);
68 
69   return ipc::BufferedFrameDeserializer::Serialize(ipc_frame);
70 }
71 
72 }  // Anonymous namespace.
73 
74 RelayClient::~RelayClient() = default;
RelayClient(const std::string & client_sock_name,const std::string & machine_id_hint,base::TaskRunner * task_runner,OnErrorCallback on_error_callback)75 RelayClient::RelayClient(const std::string& client_sock_name,
76                          const std::string& machine_id_hint,
77                          base::TaskRunner* task_runner,
78                          OnErrorCallback on_error_callback)
79     : task_runner_(task_runner),
80       on_error_callback_(on_error_callback),
81       client_sock_name_(client_sock_name),
82       machine_id_hint_(machine_id_hint) {
83   Connect();
84 }
85 
Connect()86 void RelayClient::Connect() {
87   auto sock_family = base::GetSockFamily(client_sock_name_.c_str());
88   client_sock_ =
89       base::UnixSocket::Connect(client_sock_name_, this, task_runner_,
90                                 sock_family, base::SockType::kStream);
91 }
92 
NotifyError()93 void RelayClient::NotifyError() {
94   if (!on_error_callback_)
95     return;
96 
97   // Can only notify once.
98   on_error_callback_();
99   on_error_callback_ = nullptr;
100 }
101 
OnConnect(base::UnixSocket * self,bool connected)102 void RelayClient::OnConnect(base::UnixSocket* self, bool connected) {
103   if (!connected) {
104     return NotifyError();
105   }
106 
107   // The RelayClient needs to send its peer identity to the host.
108   auto req = GenerateSetPeerIdentityRequest(
109       getpid(), static_cast<int32_t>(geteuid()), machine_id_hint_);
110   if (!self->SendStr(req)) {
111     return NotifyError();
112   }
113 
114   // Create the IPC client with a connected socket.
115   PERFETTO_DCHECK(self == client_sock_.get());
116   auto sock_fd = client_sock_->ReleaseSocket().ReleaseFd();
117   client_sock_ = nullptr;
118   relay_ipc_client_ = std::make_unique<RelayIPCClient>(
119       ipc::Client::ConnArgs(std::move(sock_fd)),
120       weak_factory_for_ipc_client.GetWeakPtr(), task_runner_);
121 }
122 
OnServiceConnected()123 void RelayClient::OnServiceConnected() {
124   phase_ = Phase::PING;
125   SendSyncClockRequest();
126 }
127 
OnServiceDisconnected()128 void RelayClient::OnServiceDisconnected() {
129   NotifyError();
130 }
131 
SendSyncClockRequest()132 void RelayClient::SendSyncClockRequest() {
133   protos::gen::SyncClockRequest request;
134   switch (phase_) {
135     case Phase::CONNECTING:
136       PERFETTO_DFATAL("Should be unreachable.");
137       return;
138     case Phase::PING:
139       request.set_phase(SyncClockRequest::PING);
140       break;
141     case Phase::UPDATE:
142       request.set_phase(SyncClockRequest::UPDATE);
143       break;
144   }
145 
146   base::ClockSnapshotVector snapshot_data = base::CaptureClockSnapshots();
147   for (auto& clock : snapshot_data) {
148     auto* clock_proto = request.add_clocks();
149     clock_proto->set_clock_id(clock.clock_id);
150     clock_proto->set_timestamp(clock.timestamp);
151   }
152 
153   relay_ipc_client_->SyncClock(request);
154 }
155 
OnSyncClockResponse(const protos::gen::SyncClockResponse &)156 void RelayClient::OnSyncClockResponse(const protos::gen::SyncClockResponse&) {
157   static constexpr uint32_t kSyncClockIntervalMs = 30000;  // 30 Sec.
158   switch (phase_) {
159     case Phase::CONNECTING:
160       PERFETTO_DFATAL("Should be unreachable.");
161       break;
162     case Phase::PING:
163       phase_ = Phase::UPDATE;
164       SendSyncClockRequest();
165       break;
166     case Phase::UPDATE:
167       // The client finished one run of clock sync. Schedule for next sync after
168       // 30 sec.
169       clock_synced_with_service_for_testing_ = true;
170       task_runner_->PostDelayedTask(
171           [self = weak_factory_.GetWeakPtr()]() {
172             if (!self)
173               return;
174 
175             self->phase_ = Phase::PING;
176             self->SendSyncClockRequest();
177           },
178           kSyncClockIntervalMs);
179       break;
180   }
181 }
182 
RelayService(base::TaskRunner * task_runner)183 RelayService::RelayService(base::TaskRunner* task_runner)
184     : task_runner_(task_runner), machine_id_hint_(GetMachineIdHint()) {}
185 
Start(const char * listening_socket_name,const char * client_socket_name)186 void RelayService::Start(const char* listening_socket_name,
187                          const char* client_socket_name) {
188   auto sock_family = base::GetSockFamily(listening_socket_name);
189   listening_socket_ =
190       base::UnixSocket::Listen(listening_socket_name, this, task_runner_,
191                                sock_family, base::SockType::kStream);
192   bool producer_socket_listening =
193       listening_socket_ && listening_socket_->is_listening();
194   if (!producer_socket_listening) {
195     PERFETTO_FATAL("Failed to listen to socket %s", listening_socket_name);
196   }
197 
198   // Save |client_socket_name| for opening new client connection to remote
199   // service when a local producer connects.
200   client_socket_name_ = client_socket_name;
201 
202   ConnectRelayClient();
203 }
204 
Start(base::ScopedSocketHandle server_socket_handle,const char * client_socket_name)205 void RelayService::Start(base::ScopedSocketHandle server_socket_handle,
206                          const char* client_socket_name) {
207   // Called when the service is started by Android init, where
208   // |server_socket_handle| is a unix socket.
209   listening_socket_ = base::UnixSocket::Listen(
210       std::move(server_socket_handle), this, task_runner_,
211       base::SockFamily::kUnix, base::SockType::kStream);
212   bool producer_socket_listening =
213       listening_socket_ && listening_socket_->is_listening();
214   if (!producer_socket_listening) {
215     PERFETTO_FATAL("Failed to listen to the server socket");
216   }
217 
218   // Save |client_socket_name| for opening new client connection to remote
219   // service when a local producer connects.
220   client_socket_name_ = client_socket_name;
221 
222   ConnectRelayClient();
223 }
224 
OnNewIncomingConnection(base::UnixSocket * listen_socket,std::unique_ptr<base::UnixSocket> server_conn)225 void RelayService::OnNewIncomingConnection(
226     base::UnixSocket* listen_socket,
227     std::unique_ptr<base::UnixSocket> server_conn) {
228   PERFETTO_DCHECK(listen_socket == listening_socket_.get());
229 
230   // Create a connection to the host to pair with |listen_conn|.
231   auto sock_family = base::GetSockFamily(client_socket_name_.c_str());
232   auto client_conn =
233       base::UnixSocket::Connect(client_socket_name_, this, task_runner_,
234                                 sock_family, base::SockType::kStream);
235 
236   // Pre-queue the SetPeerIdentity request. By enqueueing it into the buffer,
237   // this will be sent out as first frame as soon as we connect to the real
238   // traced.
239   //
240   // This code pretends that we received a SetPeerIdentity frame from the
241   // connecting producer (while instead we are just forging it). The host traced
242   // will only accept only one SetPeerIdentity request pre-queued here.
243   int32_t pid = base::kInvalidPid;
244 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
245     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
246   pid = server_conn->peer_pid_linux();
247 #endif
248   auto req = GenerateSetPeerIdentityRequest(
249       pid, static_cast<int32_t>(server_conn->peer_uid_posix()),
250       machine_id_hint_);
251   // Buffer the SetPeerIdentity request.
252   SocketWithBuffer server, client;
253   PERFETTO_CHECK(server.available_bytes() >= req.size());
254   memcpy(server.buffer(), req.data(), req.size());
255   server.EnqueueData(req.size());
256 
257   // Shut down all callbacks associated with the socket in preparation for the
258   // transfer to |socket_relay_handler_|.
259   server.sock = server_conn->ReleaseSocket();
260   auto new_socket_pair =
261       std::make_unique<SocketPair>(std::move(server), std::move(client));
262   pending_connections_.push_back(
263       {std::move(new_socket_pair), std::move(client_conn)});
264 }
265 
OnConnect(base::UnixSocket * self,bool connected)266 void RelayService::OnConnect(base::UnixSocket* self, bool connected) {
267   // This only happens when the client connection is connected or has failed.
268   auto it =
269       std::find_if(pending_connections_.begin(), pending_connections_.end(),
270                    [&](const PendingConnection& pending_conn) {
271                      return pending_conn.connecting_client_conn.get() == self;
272                    });
273   PERFETTO_CHECK(it != pending_connections_.end());
274   // Need to remove the element in |pending_connections_| regardless of
275   // |connected|.
276   auto remover = base::OnScopeExit([&]() { pending_connections_.erase(it); });
277 
278   if (!connected)
279     return;  // This closes both sockets in PendingConnection.
280 
281   // Shut down event handlers and pair with a server connection.
282   it->socket_pair->second.sock = self->ReleaseSocket();
283 
284   // Transfer the socket pair to SocketRelayHandler.
285   socket_relay_handler_.AddSocketPair(std::move(it->socket_pair));
286 }
287 
OnDisconnect(base::UnixSocket *)288 void RelayService::OnDisconnect(base::UnixSocket*) {
289   PERFETTO_DFATAL("Should be unreachable.");
290 }
291 
OnDataAvailable(base::UnixSocket *)292 void RelayService::OnDataAvailable(base::UnixSocket*) {
293   PERFETTO_DFATAL("Should be unreachable.");
294 }
295 
ReconnectRelayClient()296 void RelayService::ReconnectRelayClient() {
297   static constexpr uint32_t kMaxRelayClientRetryDelayMs = 30000;
298   task_runner_->PostDelayedTask([this]() { this->ConnectRelayClient(); },
299                                 relay_client_retry_delay_ms_);
300   relay_client_retry_delay_ms_ =
301       relay_client_->ipc_client_connected()
302           ? kDefaultRelayClientRetryDelayMs
303           : std::min(kMaxRelayClientRetryDelayMs,
304                      relay_client_retry_delay_ms_ * 2);
305 }
306 
ConnectRelayClient()307 void RelayService::ConnectRelayClient() {
308   if (relay_client_disabled_for_testing_)
309     return;
310 
311   relay_client_ = std::make_unique<RelayClient>(
312       client_socket_name_, machine_id_hint_, task_runner_,
313       [this]() { this->ReconnectRelayClient(); });
314 }
315 
GetMachineIdHint(bool use_pseudo_boot_id_for_testing)316 std::string RelayService::GetMachineIdHint(
317     bool use_pseudo_boot_id_for_testing) {
318   // Gets kernel boot ID if available.
319   std::string boot_id;
320   if (!use_pseudo_boot_id_for_testing &&
321       base::ReadFile("/proc/sys/kernel/random/boot_id", &boot_id)) {
322     return base::StripSuffix(boot_id, "\n");
323   }
324 
325 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
326     PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
327     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
328   auto get_pseudo_boot_id = []() -> std::string {
329     base::Hasher hasher;
330     const char* dev_path = "/dev";
331     // Generate a pseudo-unique identifier for the current machine.
332     // Source 1: system boot timestamp from the creation time of /dev inode.
333 #if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
334     // Mac or iOS, just use stat(2).
335     struct stat stat_buf {};
336     int rc = PERFETTO_EINTR(stat(dev_path, &stat_buf));
337     if (rc == -1)
338       return std::string();
339     hasher.Update(reinterpret_cast<const char*>(&stat_buf.st_birthtimespec),
340                   sizeof(stat_buf.st_birthtimespec));
341 #else
342     // Android or Linux, use statx(2)
343     struct statx stat_buf {};
344     auto rc = PERFETTO_EINTR(syscall(__NR_statx, /*dirfd=*/-1, dev_path,
345                                      /*flags=*/0, STATX_BTIME, &stat_buf));
346     if (rc == -1)
347       return std::string();
348     hasher.Update(reinterpret_cast<const char*>(&stat_buf.stx_btime),
349                   sizeof(stat_buf.stx_btime));
350 #endif
351 
352     // Source 2: uname(2).
353     utsname kernel_info{};
354     if (uname(&kernel_info) == -1)
355       return std::string();
356 
357     // Create a non-cryptographic digest of bootup timestamp and everything in
358     // utsname.
359     hasher.Update(reinterpret_cast<const char*>(&kernel_info),
360                   sizeof(kernel_info));
361     return base::Uint64ToHexStringNoPrefix(hasher.digest());
362   };
363 
364   auto pseudo_boot_id = get_pseudo_boot_id();
365   if (!pseudo_boot_id.empty())
366     return pseudo_boot_id;
367 #endif
368 
369   // If all above failed, return nothing.
370   return std::string();
371 }
372 
373 }  // namespace perfetto
374