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