xref: /aosp_15_r20/external/perfetto/src/ipc/host_impl.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #include "src/ipc/host_impl.h"
18*6dbdd20aSAndroid Build Coastguard Worker 
19*6dbdd20aSAndroid Build Coastguard Worker #include <algorithm>
20*6dbdd20aSAndroid Build Coastguard Worker #include <cinttypes>
21*6dbdd20aSAndroid Build Coastguard Worker #include <utility>
22*6dbdd20aSAndroid Build Coastguard Worker 
23*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/build_config.h"
24*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/compiler.h"
25*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/logging.h"
26*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/task_runner.h"
27*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/time.h"
28*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/crash_keys.h"
29*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/sys_types.h"
30*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/unix_socket.h"
31*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/utils.h"
32*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/ipc/service.h"
33*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/ipc/service_descriptor.h"
34*6dbdd20aSAndroid Build Coastguard Worker 
35*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/ipc/wire_protocol.gen.h"
36*6dbdd20aSAndroid Build Coastguard Worker 
37*6dbdd20aSAndroid Build Coastguard Worker // TODO(primiano): put limits on #connections/uid and req. queue (b/69093705).
38*6dbdd20aSAndroid Build Coastguard Worker 
39*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
40*6dbdd20aSAndroid Build Coastguard Worker namespace ipc {
41*6dbdd20aSAndroid Build Coastguard Worker 
42*6dbdd20aSAndroid Build Coastguard Worker namespace {
43*6dbdd20aSAndroid Build Coastguard Worker 
44*6dbdd20aSAndroid Build Coastguard Worker constexpr base::SockFamily kHostSockFamily =
45*6dbdd20aSAndroid Build Coastguard Worker     kUseTCPSocket ? base::SockFamily::kInet : base::SockFamily::kUnix;
46*6dbdd20aSAndroid Build Coastguard Worker 
47*6dbdd20aSAndroid Build Coastguard Worker base::CrashKey g_crash_key_uid("ipc_uid");
48*6dbdd20aSAndroid Build Coastguard Worker 
GenerateMachineID(base::UnixSocket * sock,const std::string & machine_id_hint)49*6dbdd20aSAndroid Build Coastguard Worker base::MachineID GenerateMachineID(base::UnixSocket* sock,
50*6dbdd20aSAndroid Build Coastguard Worker                                   const std::string& machine_id_hint) {
51*6dbdd20aSAndroid Build Coastguard Worker   // The special value of base::kDefaultMachineID is reserved for local
52*6dbdd20aSAndroid Build Coastguard Worker   // producers.
53*6dbdd20aSAndroid Build Coastguard Worker   if (!sock->is_connected() || sock->family() == base::SockFamily::kUnix)
54*6dbdd20aSAndroid Build Coastguard Worker     return base::kDefaultMachineID;
55*6dbdd20aSAndroid Build Coastguard Worker 
56*6dbdd20aSAndroid Build Coastguard Worker   base::Hasher hasher;
57*6dbdd20aSAndroid Build Coastguard Worker   // Use the hint from the client, or fallback to hostname if the client
58*6dbdd20aSAndroid Build Coastguard Worker   // doesn't provide a hint.
59*6dbdd20aSAndroid Build Coastguard Worker   if (!machine_id_hint.empty()) {
60*6dbdd20aSAndroid Build Coastguard Worker     hasher.Update(machine_id_hint);
61*6dbdd20aSAndroid Build Coastguard Worker   } else {
62*6dbdd20aSAndroid Build Coastguard Worker     // Use the socket address without the port number part as the hint.
63*6dbdd20aSAndroid Build Coastguard Worker     auto host_id = sock->GetSockAddr();
64*6dbdd20aSAndroid Build Coastguard Worker     auto pos = std::string::npos;
65*6dbdd20aSAndroid Build Coastguard Worker     switch (sock->family()) {
66*6dbdd20aSAndroid Build Coastguard Worker       case base::SockFamily::kInet:
67*6dbdd20aSAndroid Build Coastguard Worker         PERFETTO_FALLTHROUGH;
68*6dbdd20aSAndroid Build Coastguard Worker       case base::SockFamily::kInet6:
69*6dbdd20aSAndroid Build Coastguard Worker         PERFETTO_FALLTHROUGH;
70*6dbdd20aSAndroid Build Coastguard Worker       case base::SockFamily::kVsock:
71*6dbdd20aSAndroid Build Coastguard Worker         pos = host_id.rfind(":");
72*6dbdd20aSAndroid Build Coastguard Worker         if (pos != std::string::npos)
73*6dbdd20aSAndroid Build Coastguard Worker           host_id.resize(pos);
74*6dbdd20aSAndroid Build Coastguard Worker         break;
75*6dbdd20aSAndroid Build Coastguard Worker       case base::SockFamily::kUnspec:
76*6dbdd20aSAndroid Build Coastguard Worker         PERFETTO_FALLTHROUGH;
77*6dbdd20aSAndroid Build Coastguard Worker       case base::SockFamily::kUnix:
78*6dbdd20aSAndroid Build Coastguard Worker         PERFETTO_DFATAL("Should be unreachable.");
79*6dbdd20aSAndroid Build Coastguard Worker         return base::kDefaultMachineID;
80*6dbdd20aSAndroid Build Coastguard Worker     }
81*6dbdd20aSAndroid Build Coastguard Worker     hasher.Update(host_id);
82*6dbdd20aSAndroid Build Coastguard Worker   }
83*6dbdd20aSAndroid Build Coastguard Worker 
84*6dbdd20aSAndroid Build Coastguard Worker   // Take the lower 32-bit from the hash.
85*6dbdd20aSAndroid Build Coastguard Worker   uint32_t digest = static_cast<uint32_t>(hasher.digest());
86*6dbdd20aSAndroid Build Coastguard Worker   // Avoid the extremely unlikely case that the hasher digest happens to be 0.
87*6dbdd20aSAndroid Build Coastguard Worker   return digest == base::kDefaultMachineID ? 1 : digest;
88*6dbdd20aSAndroid Build Coastguard Worker }
89*6dbdd20aSAndroid Build Coastguard Worker }  // namespace
90*6dbdd20aSAndroid Build Coastguard Worker 
GetPosixPeerUid() const91*6dbdd20aSAndroid Build Coastguard Worker uid_t HostImpl::ClientConnection::GetPosixPeerUid() const {
92*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
93*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
94*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
95*6dbdd20aSAndroid Build Coastguard Worker   if (sock->family() == base::SockFamily::kUnix)
96*6dbdd20aSAndroid Build Coastguard Worker     return sock->peer_uid_posix();
97*6dbdd20aSAndroid Build Coastguard Worker #endif
98*6dbdd20aSAndroid Build Coastguard Worker 
99*6dbdd20aSAndroid Build Coastguard Worker   // For non-unix sockets, check if the UID is set in OnSetPeerIdentity().
100*6dbdd20aSAndroid Build Coastguard Worker   if (uid_override != base::kInvalidUid)
101*6dbdd20aSAndroid Build Coastguard Worker     return uid_override;
102*6dbdd20aSAndroid Build Coastguard Worker   // Must be != kInvalidUid or the PacketValidator will fail.
103*6dbdd20aSAndroid Build Coastguard Worker   return 0;
104*6dbdd20aSAndroid Build Coastguard Worker }
105*6dbdd20aSAndroid Build Coastguard Worker 
GetLinuxPeerPid() const106*6dbdd20aSAndroid Build Coastguard Worker pid_t HostImpl::ClientConnection::GetLinuxPeerPid() const {
107*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
108*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
109*6dbdd20aSAndroid Build Coastguard Worker   if (sock->family() == base::SockFamily::kUnix)
110*6dbdd20aSAndroid Build Coastguard Worker     return sock->peer_pid_linux();
111*6dbdd20aSAndroid Build Coastguard Worker #endif
112*6dbdd20aSAndroid Build Coastguard Worker 
113*6dbdd20aSAndroid Build Coastguard Worker   // For non-unix sockets, return the PID set in OnSetPeerIdentity().
114*6dbdd20aSAndroid Build Coastguard Worker   return pid_override;
115*6dbdd20aSAndroid Build Coastguard Worker }
116*6dbdd20aSAndroid Build Coastguard Worker 
117*6dbdd20aSAndroid Build Coastguard Worker // static
CreateInstance(const char * socket_name,base::TaskRunner * task_runner)118*6dbdd20aSAndroid Build Coastguard Worker std::unique_ptr<Host> Host::CreateInstance(const char* socket_name,
119*6dbdd20aSAndroid Build Coastguard Worker                                            base::TaskRunner* task_runner) {
120*6dbdd20aSAndroid Build Coastguard Worker   std::unique_ptr<HostImpl> host(new HostImpl(socket_name, task_runner));
121*6dbdd20aSAndroid Build Coastguard Worker   if (!host->sock() || !host->sock()->is_listening())
122*6dbdd20aSAndroid Build Coastguard Worker     return nullptr;
123*6dbdd20aSAndroid Build Coastguard Worker   return std::unique_ptr<Host>(std::move(host));
124*6dbdd20aSAndroid Build Coastguard Worker }
125*6dbdd20aSAndroid Build Coastguard Worker 
126*6dbdd20aSAndroid Build Coastguard Worker // static
CreateInstance(base::ScopedSocketHandle socket_fd,base::TaskRunner * task_runner)127*6dbdd20aSAndroid Build Coastguard Worker std::unique_ptr<Host> Host::CreateInstance(base::ScopedSocketHandle socket_fd,
128*6dbdd20aSAndroid Build Coastguard Worker                                            base::TaskRunner* task_runner) {
129*6dbdd20aSAndroid Build Coastguard Worker   std::unique_ptr<HostImpl> host(
130*6dbdd20aSAndroid Build Coastguard Worker       new HostImpl(std::move(socket_fd), task_runner));
131*6dbdd20aSAndroid Build Coastguard Worker   if (!host->sock() || !host->sock()->is_listening())
132*6dbdd20aSAndroid Build Coastguard Worker     return nullptr;
133*6dbdd20aSAndroid Build Coastguard Worker   return std::unique_ptr<Host>(std::move(host));
134*6dbdd20aSAndroid Build Coastguard Worker }
135*6dbdd20aSAndroid Build Coastguard Worker 
136*6dbdd20aSAndroid Build Coastguard Worker // static
CreateInstance_Fuchsia(base::TaskRunner * task_runner)137*6dbdd20aSAndroid Build Coastguard Worker std::unique_ptr<Host> Host::CreateInstance_Fuchsia(
138*6dbdd20aSAndroid Build Coastguard Worker     base::TaskRunner* task_runner) {
139*6dbdd20aSAndroid Build Coastguard Worker   return std::unique_ptr<HostImpl>(new HostImpl(task_runner));
140*6dbdd20aSAndroid Build Coastguard Worker }
141*6dbdd20aSAndroid Build Coastguard Worker 
HostImpl(base::ScopedSocketHandle socket_fd,base::TaskRunner * task_runner)142*6dbdd20aSAndroid Build Coastguard Worker HostImpl::HostImpl(base::ScopedSocketHandle socket_fd,
143*6dbdd20aSAndroid Build Coastguard Worker                    base::TaskRunner* task_runner)
144*6dbdd20aSAndroid Build Coastguard Worker     : task_runner_(task_runner), weak_ptr_factory_(this) {
145*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
146*6dbdd20aSAndroid Build Coastguard Worker   sock_ = base::UnixSocket::Listen(std::move(socket_fd), this, task_runner_,
147*6dbdd20aSAndroid Build Coastguard Worker                                    kHostSockFamily, base::SockType::kStream);
148*6dbdd20aSAndroid Build Coastguard Worker }
149*6dbdd20aSAndroid Build Coastguard Worker 
HostImpl(const char * socket_name,base::TaskRunner * task_runner)150*6dbdd20aSAndroid Build Coastguard Worker HostImpl::HostImpl(const char* socket_name, base::TaskRunner* task_runner)
151*6dbdd20aSAndroid Build Coastguard Worker     : task_runner_(task_runner), weak_ptr_factory_(this) {
152*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
153*6dbdd20aSAndroid Build Coastguard Worker   sock_ = base::UnixSocket::Listen(socket_name, this, task_runner_,
154*6dbdd20aSAndroid Build Coastguard Worker                                    base::GetSockFamily(socket_name),
155*6dbdd20aSAndroid Build Coastguard Worker                                    base::SockType::kStream);
156*6dbdd20aSAndroid Build Coastguard Worker   if (!sock_) {
157*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_PLOG("Failed to create %s", socket_name);
158*6dbdd20aSAndroid Build Coastguard Worker   }
159*6dbdd20aSAndroid Build Coastguard Worker }
160*6dbdd20aSAndroid Build Coastguard Worker 
HostImpl(base::TaskRunner * task_runner)161*6dbdd20aSAndroid Build Coastguard Worker HostImpl::HostImpl(base::TaskRunner* task_runner)
162*6dbdd20aSAndroid Build Coastguard Worker     : task_runner_(task_runner), weak_ptr_factory_(this) {
163*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
164*6dbdd20aSAndroid Build Coastguard Worker }
165*6dbdd20aSAndroid Build Coastguard Worker 
166*6dbdd20aSAndroid Build Coastguard Worker HostImpl::~HostImpl() = default;
167*6dbdd20aSAndroid Build Coastguard Worker 
ExposeService(std::unique_ptr<Service> service)168*6dbdd20aSAndroid Build Coastguard Worker bool HostImpl::ExposeService(std::unique_ptr<Service> service) {
169*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
170*6dbdd20aSAndroid Build Coastguard Worker   const std::string& service_name = service->GetDescriptor().service_name;
171*6dbdd20aSAndroid Build Coastguard Worker   if (GetServiceByName(service_name)) {
172*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_DLOG("Duplicate ExposeService(): %s", service_name.c_str());
173*6dbdd20aSAndroid Build Coastguard Worker     return false;
174*6dbdd20aSAndroid Build Coastguard Worker   }
175*6dbdd20aSAndroid Build Coastguard Worker   service->use_shmem_emulation_ =
176*6dbdd20aSAndroid Build Coastguard Worker       sock() && !base::SockShmemSupported(sock()->family());
177*6dbdd20aSAndroid Build Coastguard Worker   ServiceID sid = ++last_service_id_;
178*6dbdd20aSAndroid Build Coastguard Worker   ExposedService exposed_service(sid, service_name, std::move(service));
179*6dbdd20aSAndroid Build Coastguard Worker   services_.emplace(sid, std::move(exposed_service));
180*6dbdd20aSAndroid Build Coastguard Worker   return true;
181*6dbdd20aSAndroid Build Coastguard Worker }
182*6dbdd20aSAndroid Build Coastguard Worker 
AdoptConnectedSocket_Fuchsia(base::ScopedSocketHandle connected_socket,std::function<bool (int)> send_fd_cb)183*6dbdd20aSAndroid Build Coastguard Worker void HostImpl::AdoptConnectedSocket_Fuchsia(
184*6dbdd20aSAndroid Build Coastguard Worker     base::ScopedSocketHandle connected_socket,
185*6dbdd20aSAndroid Build Coastguard Worker     std::function<bool(int)> send_fd_cb) {
186*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
187*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK(connected_socket);
188*6dbdd20aSAndroid Build Coastguard Worker   // Should not be used in conjunction with listen sockets.
189*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK(!sock_);
190*6dbdd20aSAndroid Build Coastguard Worker 
191*6dbdd20aSAndroid Build Coastguard Worker   auto unix_socket = base::UnixSocket::AdoptConnected(
192*6dbdd20aSAndroid Build Coastguard Worker       std::move(connected_socket), this, task_runner_, kHostSockFamily,
193*6dbdd20aSAndroid Build Coastguard Worker       base::SockType::kStream);
194*6dbdd20aSAndroid Build Coastguard Worker 
195*6dbdd20aSAndroid Build Coastguard Worker   auto* unix_socket_ptr = unix_socket.get();
196*6dbdd20aSAndroid Build Coastguard Worker   OnNewIncomingConnection(nullptr, std::move(unix_socket));
197*6dbdd20aSAndroid Build Coastguard Worker   ClientConnection* client_connection = clients_by_socket_[unix_socket_ptr];
198*6dbdd20aSAndroid Build Coastguard Worker   client_connection->send_fd_cb_fuchsia = std::move(send_fd_cb);
199*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK(client_connection->send_fd_cb_fuchsia);
200*6dbdd20aSAndroid Build Coastguard Worker }
201*6dbdd20aSAndroid Build Coastguard Worker 
SetSocketSendTimeoutMs(uint32_t timeout_ms)202*6dbdd20aSAndroid Build Coastguard Worker void HostImpl::SetSocketSendTimeoutMs(uint32_t timeout_ms) {
203*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
204*6dbdd20aSAndroid Build Coastguard Worker   // Should be less than the watchdog period (30s).
205*6dbdd20aSAndroid Build Coastguard Worker   socket_tx_timeout_ms_ = timeout_ms;
206*6dbdd20aSAndroid Build Coastguard Worker }
207*6dbdd20aSAndroid Build Coastguard Worker 
OnNewIncomingConnection(base::UnixSocket *,std::unique_ptr<base::UnixSocket> new_conn)208*6dbdd20aSAndroid Build Coastguard Worker void HostImpl::OnNewIncomingConnection(
209*6dbdd20aSAndroid Build Coastguard Worker     base::UnixSocket*,
210*6dbdd20aSAndroid Build Coastguard Worker     std::unique_ptr<base::UnixSocket> new_conn) {
211*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
212*6dbdd20aSAndroid Build Coastguard Worker   std::unique_ptr<ClientConnection> client(new ClientConnection());
213*6dbdd20aSAndroid Build Coastguard Worker   ClientID client_id = ++last_client_id_;
214*6dbdd20aSAndroid Build Coastguard Worker   clients_by_socket_[new_conn.get()] = client.get();
215*6dbdd20aSAndroid Build Coastguard Worker   client->id = client_id;
216*6dbdd20aSAndroid Build Coastguard Worker   client->sock = std::move(new_conn);
217*6dbdd20aSAndroid Build Coastguard Worker   client->sock->SetTxTimeout(socket_tx_timeout_ms_);
218*6dbdd20aSAndroid Build Coastguard Worker   clients_[client_id] = std::move(client);
219*6dbdd20aSAndroid Build Coastguard Worker }
220*6dbdd20aSAndroid Build Coastguard Worker 
OnDataAvailable(base::UnixSocket * sock)221*6dbdd20aSAndroid Build Coastguard Worker void HostImpl::OnDataAvailable(base::UnixSocket* sock) {
222*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
223*6dbdd20aSAndroid Build Coastguard Worker   auto it = clients_by_socket_.find(sock);
224*6dbdd20aSAndroid Build Coastguard Worker   if (it == clients_by_socket_.end())
225*6dbdd20aSAndroid Build Coastguard Worker     return;
226*6dbdd20aSAndroid Build Coastguard Worker   ClientConnection* client = it->second;
227*6dbdd20aSAndroid Build Coastguard Worker   BufferedFrameDeserializer& frame_deserializer = client->frame_deserializer;
228*6dbdd20aSAndroid Build Coastguard Worker 
229*6dbdd20aSAndroid Build Coastguard Worker   auto peer_uid = client->GetPosixPeerUid();
230*6dbdd20aSAndroid Build Coastguard Worker   auto scoped_key = g_crash_key_uid.SetScoped(static_cast<int64_t>(peer_uid));
231*6dbdd20aSAndroid Build Coastguard Worker 
232*6dbdd20aSAndroid Build Coastguard Worker   size_t rsize;
233*6dbdd20aSAndroid Build Coastguard Worker   do {
234*6dbdd20aSAndroid Build Coastguard Worker     auto buf = frame_deserializer.BeginReceive();
235*6dbdd20aSAndroid Build Coastguard Worker     base::ScopedFile fd;
236*6dbdd20aSAndroid Build Coastguard Worker     rsize = client->sock->Receive(buf.data, buf.size, &fd);
237*6dbdd20aSAndroid Build Coastguard Worker     if (fd) {
238*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_DCHECK(!client->received_fd);
239*6dbdd20aSAndroid Build Coastguard Worker       client->received_fd = std::move(fd);
240*6dbdd20aSAndroid Build Coastguard Worker     }
241*6dbdd20aSAndroid Build Coastguard Worker     if (!frame_deserializer.EndReceive(rsize))
242*6dbdd20aSAndroid Build Coastguard Worker       return OnDisconnect(client->sock.get());
243*6dbdd20aSAndroid Build Coastguard Worker   } while (rsize > 0);
244*6dbdd20aSAndroid Build Coastguard Worker 
245*6dbdd20aSAndroid Build Coastguard Worker   for (;;) {
246*6dbdd20aSAndroid Build Coastguard Worker     std::unique_ptr<Frame> frame = frame_deserializer.PopNextFrame();
247*6dbdd20aSAndroid Build Coastguard Worker     if (!frame)
248*6dbdd20aSAndroid Build Coastguard Worker       break;
249*6dbdd20aSAndroid Build Coastguard Worker     OnReceivedFrame(client, *frame);
250*6dbdd20aSAndroid Build Coastguard Worker   }
251*6dbdd20aSAndroid Build Coastguard Worker }
252*6dbdd20aSAndroid Build Coastguard Worker 
OnReceivedFrame(ClientConnection * client,const Frame & req_frame)253*6dbdd20aSAndroid Build Coastguard Worker void HostImpl::OnReceivedFrame(ClientConnection* client,
254*6dbdd20aSAndroid Build Coastguard Worker                                const Frame& req_frame) {
255*6dbdd20aSAndroid Build Coastguard Worker   if (req_frame.has_msg_bind_service())
256*6dbdd20aSAndroid Build Coastguard Worker     return OnBindService(client, req_frame);
257*6dbdd20aSAndroid Build Coastguard Worker   if (req_frame.has_msg_invoke_method())
258*6dbdd20aSAndroid Build Coastguard Worker     return OnInvokeMethod(client, req_frame);
259*6dbdd20aSAndroid Build Coastguard Worker   if (req_frame.has_set_peer_identity())
260*6dbdd20aSAndroid Build Coastguard Worker     return OnSetPeerIdentity(client, req_frame);
261*6dbdd20aSAndroid Build Coastguard Worker 
262*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DLOG("Received invalid RPC frame from client %" PRIu64, client->id);
263*6dbdd20aSAndroid Build Coastguard Worker   Frame reply_frame;
264*6dbdd20aSAndroid Build Coastguard Worker   reply_frame.set_request_id(req_frame.request_id());
265*6dbdd20aSAndroid Build Coastguard Worker   reply_frame.mutable_msg_request_error()->set_error("unknown request");
266*6dbdd20aSAndroid Build Coastguard Worker   SendFrame(client, reply_frame);
267*6dbdd20aSAndroid Build Coastguard Worker }
268*6dbdd20aSAndroid Build Coastguard Worker 
OnBindService(ClientConnection * client,const Frame & req_frame)269*6dbdd20aSAndroid Build Coastguard Worker void HostImpl::OnBindService(ClientConnection* client, const Frame& req_frame) {
270*6dbdd20aSAndroid Build Coastguard Worker   // Binding a service doesn't do anything major. It just returns back the
271*6dbdd20aSAndroid Build Coastguard Worker   // service id and its method map.
272*6dbdd20aSAndroid Build Coastguard Worker   const Frame::BindService& req = req_frame.msg_bind_service();
273*6dbdd20aSAndroid Build Coastguard Worker   Frame reply_frame;
274*6dbdd20aSAndroid Build Coastguard Worker   reply_frame.set_request_id(req_frame.request_id());
275*6dbdd20aSAndroid Build Coastguard Worker   auto* reply = reply_frame.mutable_msg_bind_service_reply();
276*6dbdd20aSAndroid Build Coastguard Worker   const ExposedService* service = GetServiceByName(req.service_name());
277*6dbdd20aSAndroid Build Coastguard Worker   if (service) {
278*6dbdd20aSAndroid Build Coastguard Worker     reply->set_success(true);
279*6dbdd20aSAndroid Build Coastguard Worker     reply->set_service_id(service->id);
280*6dbdd20aSAndroid Build Coastguard Worker     uint32_t method_id = 1;  // method ids start at index 1.
281*6dbdd20aSAndroid Build Coastguard Worker     for (const auto& desc_method : service->instance->GetDescriptor().methods) {
282*6dbdd20aSAndroid Build Coastguard Worker       Frame::BindServiceReply::MethodInfo* method_info = reply->add_methods();
283*6dbdd20aSAndroid Build Coastguard Worker       method_info->set_name(desc_method.name);
284*6dbdd20aSAndroid Build Coastguard Worker       method_info->set_id(method_id++);
285*6dbdd20aSAndroid Build Coastguard Worker     }
286*6dbdd20aSAndroid Build Coastguard Worker   }
287*6dbdd20aSAndroid Build Coastguard Worker   SendFrame(client, reply_frame);
288*6dbdd20aSAndroid Build Coastguard Worker }
289*6dbdd20aSAndroid Build Coastguard Worker 
OnInvokeMethod(ClientConnection * client,const Frame & req_frame)290*6dbdd20aSAndroid Build Coastguard Worker void HostImpl::OnInvokeMethod(ClientConnection* client,
291*6dbdd20aSAndroid Build Coastguard Worker                               const Frame& req_frame) {
292*6dbdd20aSAndroid Build Coastguard Worker   const Frame::InvokeMethod& req = req_frame.msg_invoke_method();
293*6dbdd20aSAndroid Build Coastguard Worker   Frame reply_frame;
294*6dbdd20aSAndroid Build Coastguard Worker   RequestID request_id = req_frame.request_id();
295*6dbdd20aSAndroid Build Coastguard Worker   reply_frame.set_request_id(request_id);
296*6dbdd20aSAndroid Build Coastguard Worker   reply_frame.mutable_msg_invoke_method_reply()->set_success(false);
297*6dbdd20aSAndroid Build Coastguard Worker   auto svc_it = services_.find(req.service_id());
298*6dbdd20aSAndroid Build Coastguard Worker   if (svc_it == services_.end())
299*6dbdd20aSAndroid Build Coastguard Worker     return SendFrame(client, reply_frame);  // |success| == false by default.
300*6dbdd20aSAndroid Build Coastguard Worker 
301*6dbdd20aSAndroid Build Coastguard Worker   Service* service = svc_it->second.instance.get();
302*6dbdd20aSAndroid Build Coastguard Worker   const ServiceDescriptor& svc = service->GetDescriptor();
303*6dbdd20aSAndroid Build Coastguard Worker   const auto& methods = svc.methods;
304*6dbdd20aSAndroid Build Coastguard Worker   const uint32_t method_id = req.method_id();
305*6dbdd20aSAndroid Build Coastguard Worker   if (method_id == 0 || method_id > methods.size())
306*6dbdd20aSAndroid Build Coastguard Worker     return SendFrame(client, reply_frame);
307*6dbdd20aSAndroid Build Coastguard Worker 
308*6dbdd20aSAndroid Build Coastguard Worker   const ServiceDescriptor::Method& method = methods[method_id - 1];
309*6dbdd20aSAndroid Build Coastguard Worker   std::unique_ptr<ProtoMessage> decoded_req_args(
310*6dbdd20aSAndroid Build Coastguard Worker       method.request_proto_decoder(req.args_proto()));
311*6dbdd20aSAndroid Build Coastguard Worker   if (!decoded_req_args)
312*6dbdd20aSAndroid Build Coastguard Worker     return SendFrame(client, reply_frame);
313*6dbdd20aSAndroid Build Coastguard Worker 
314*6dbdd20aSAndroid Build Coastguard Worker   Deferred<ProtoMessage> deferred_reply;
315*6dbdd20aSAndroid Build Coastguard Worker   base::WeakPtr<HostImpl> host_weak_ptr = weak_ptr_factory_.GetWeakPtr();
316*6dbdd20aSAndroid Build Coastguard Worker   ClientID client_id = client->id;
317*6dbdd20aSAndroid Build Coastguard Worker 
318*6dbdd20aSAndroid Build Coastguard Worker   if (!req.drop_reply()) {
319*6dbdd20aSAndroid Build Coastguard Worker     deferred_reply.Bind([host_weak_ptr, client_id,
320*6dbdd20aSAndroid Build Coastguard Worker                          request_id](AsyncResult<ProtoMessage> reply) {
321*6dbdd20aSAndroid Build Coastguard Worker       if (!host_weak_ptr)
322*6dbdd20aSAndroid Build Coastguard Worker         return;  // The reply came too late, the HostImpl has gone.
323*6dbdd20aSAndroid Build Coastguard Worker       host_weak_ptr->ReplyToMethodInvocation(client_id, request_id,
324*6dbdd20aSAndroid Build Coastguard Worker                                              std::move(reply));
325*6dbdd20aSAndroid Build Coastguard Worker     });
326*6dbdd20aSAndroid Build Coastguard Worker   }
327*6dbdd20aSAndroid Build Coastguard Worker 
328*6dbdd20aSAndroid Build Coastguard Worker   auto peer_uid = client->GetPosixPeerUid();
329*6dbdd20aSAndroid Build Coastguard Worker   auto scoped_key = g_crash_key_uid.SetScoped(static_cast<int64_t>(peer_uid));
330*6dbdd20aSAndroid Build Coastguard Worker   service->client_info_ = ClientInfo(
331*6dbdd20aSAndroid Build Coastguard Worker       client->id, peer_uid, client->GetLinuxPeerPid(), client->GetMachineID());
332*6dbdd20aSAndroid Build Coastguard Worker   service->received_fd_ = &client->received_fd;
333*6dbdd20aSAndroid Build Coastguard Worker   method.invoker(service, *decoded_req_args, std::move(deferred_reply));
334*6dbdd20aSAndroid Build Coastguard Worker   service->received_fd_ = nullptr;
335*6dbdd20aSAndroid Build Coastguard Worker   service->client_info_ = ClientInfo();
336*6dbdd20aSAndroid Build Coastguard Worker }
337*6dbdd20aSAndroid Build Coastguard Worker 
OnSetPeerIdentity(ClientConnection * client,const Frame & req_frame)338*6dbdd20aSAndroid Build Coastguard Worker void HostImpl::OnSetPeerIdentity(ClientConnection* client,
339*6dbdd20aSAndroid Build Coastguard Worker                                  const Frame& req_frame) {
340*6dbdd20aSAndroid Build Coastguard Worker   if (client->sock->family() == base::SockFamily::kUnix) {
341*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_DLOG("SetPeerIdentity is ignored for unix socket connections.");
342*6dbdd20aSAndroid Build Coastguard Worker     return;
343*6dbdd20aSAndroid Build Coastguard Worker   }
344*6dbdd20aSAndroid Build Coastguard Worker 
345*6dbdd20aSAndroid Build Coastguard Worker   // This is can only be set once by the relay service.
346*6dbdd20aSAndroid Build Coastguard Worker   if (client->pid_override != base::kInvalidPid ||
347*6dbdd20aSAndroid Build Coastguard Worker       client->uid_override != base::kInvalidUid) {
348*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_DLOG("Already received SetPeerIdentity.");
349*6dbdd20aSAndroid Build Coastguard Worker     return;
350*6dbdd20aSAndroid Build Coastguard Worker   }
351*6dbdd20aSAndroid Build Coastguard Worker 
352*6dbdd20aSAndroid Build Coastguard Worker   const auto& set_peer_identity = req_frame.set_peer_identity();
353*6dbdd20aSAndroid Build Coastguard Worker   client->pid_override = set_peer_identity.pid();
354*6dbdd20aSAndroid Build Coastguard Worker   client->uid_override = static_cast<uid_t>(set_peer_identity.uid());
355*6dbdd20aSAndroid Build Coastguard Worker 
356*6dbdd20aSAndroid Build Coastguard Worker   client->machine_id = GenerateMachineID(client->sock.get(),
357*6dbdd20aSAndroid Build Coastguard Worker                                          set_peer_identity.machine_id_hint());
358*6dbdd20aSAndroid Build Coastguard Worker }
359*6dbdd20aSAndroid Build Coastguard Worker 
ReplyToMethodInvocation(ClientID client_id,RequestID request_id,AsyncResult<ProtoMessage> reply)360*6dbdd20aSAndroid Build Coastguard Worker void HostImpl::ReplyToMethodInvocation(ClientID client_id,
361*6dbdd20aSAndroid Build Coastguard Worker                                        RequestID request_id,
362*6dbdd20aSAndroid Build Coastguard Worker                                        AsyncResult<ProtoMessage> reply) {
363*6dbdd20aSAndroid Build Coastguard Worker   auto client_iter = clients_.find(client_id);
364*6dbdd20aSAndroid Build Coastguard Worker   if (client_iter == clients_.end())
365*6dbdd20aSAndroid Build Coastguard Worker     return;  // client has disconnected by the time we got the async reply.
366*6dbdd20aSAndroid Build Coastguard Worker 
367*6dbdd20aSAndroid Build Coastguard Worker   ClientConnection* client = client_iter->second.get();
368*6dbdd20aSAndroid Build Coastguard Worker   Frame reply_frame;
369*6dbdd20aSAndroid Build Coastguard Worker   reply_frame.set_request_id(request_id);
370*6dbdd20aSAndroid Build Coastguard Worker 
371*6dbdd20aSAndroid Build Coastguard Worker   // TODO(fmayer): add a test to guarantee that the reply is consumed within the
372*6dbdd20aSAndroid Build Coastguard Worker   // same call stack and not kept around. ConsumerIPCService::OnTraceData()
373*6dbdd20aSAndroid Build Coastguard Worker   // relies on this behavior.
374*6dbdd20aSAndroid Build Coastguard Worker   auto* reply_frame_data = reply_frame.mutable_msg_invoke_method_reply();
375*6dbdd20aSAndroid Build Coastguard Worker   reply_frame_data->set_has_more(reply.has_more());
376*6dbdd20aSAndroid Build Coastguard Worker   if (reply.success()) {
377*6dbdd20aSAndroid Build Coastguard Worker     std::string reply_proto = reply->SerializeAsString();
378*6dbdd20aSAndroid Build Coastguard Worker     reply_frame_data->set_reply_proto(reply_proto);
379*6dbdd20aSAndroid Build Coastguard Worker     reply_frame_data->set_success(true);
380*6dbdd20aSAndroid Build Coastguard Worker   }
381*6dbdd20aSAndroid Build Coastguard Worker   SendFrame(client, reply_frame, reply.fd());
382*6dbdd20aSAndroid Build Coastguard Worker }
383*6dbdd20aSAndroid Build Coastguard Worker 
384*6dbdd20aSAndroid Build Coastguard Worker // static
SendFrame(ClientConnection * client,const Frame & frame,int fd)385*6dbdd20aSAndroid Build Coastguard Worker void HostImpl::SendFrame(ClientConnection* client, const Frame& frame, int fd) {
386*6dbdd20aSAndroid Build Coastguard Worker   auto peer_uid = client->GetPosixPeerUid();
387*6dbdd20aSAndroid Build Coastguard Worker   auto scoped_key = g_crash_key_uid.SetScoped(static_cast<int64_t>(peer_uid));
388*6dbdd20aSAndroid Build Coastguard Worker 
389*6dbdd20aSAndroid Build Coastguard Worker   std::string buf = BufferedFrameDeserializer::Serialize(frame);
390*6dbdd20aSAndroid Build Coastguard Worker 
391*6dbdd20aSAndroid Build Coastguard Worker   // On Fuchsia, |send_fd_cb_fuchsia_| is used to send the FD to the client
392*6dbdd20aSAndroid Build Coastguard Worker   // and therefore must be set.
393*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK(!PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA) ||
394*6dbdd20aSAndroid Build Coastguard Worker                   client->send_fd_cb_fuchsia);
395*6dbdd20aSAndroid Build Coastguard Worker   if (client->send_fd_cb_fuchsia && fd != base::ScopedFile::kInvalid) {
396*6dbdd20aSAndroid Build Coastguard Worker     if (!client->send_fd_cb_fuchsia(fd)) {
397*6dbdd20aSAndroid Build Coastguard Worker       client->sock->Shutdown(true);
398*6dbdd20aSAndroid Build Coastguard Worker       return;
399*6dbdd20aSAndroid Build Coastguard Worker     }
400*6dbdd20aSAndroid Build Coastguard Worker     fd = base::ScopedFile::kInvalid;
401*6dbdd20aSAndroid Build Coastguard Worker   }
402*6dbdd20aSAndroid Build Coastguard Worker 
403*6dbdd20aSAndroid Build Coastguard Worker   // When a new Client connects in OnNewClientConnection we set a timeout on
404*6dbdd20aSAndroid Build Coastguard Worker   // Send (see call to SetTxTimeout).
405*6dbdd20aSAndroid Build Coastguard Worker   //
406*6dbdd20aSAndroid Build Coastguard Worker   // The old behaviour was to do a blocking I/O call, which caused crashes from
407*6dbdd20aSAndroid Build Coastguard Worker   // misbehaving producers (see b/169051440).
408*6dbdd20aSAndroid Build Coastguard Worker   bool res = client->sock->Send(buf.data(), buf.size(), fd);
409*6dbdd20aSAndroid Build Coastguard Worker   // If we timeout |res| will be false, but the UnixSocket will have called
410*6dbdd20aSAndroid Build Coastguard Worker   // UnixSocket::ShutDown() and thus |is_connected()| is false.
411*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_CHECK(res || !client->sock->is_connected());
412*6dbdd20aSAndroid Build Coastguard Worker }
413*6dbdd20aSAndroid Build Coastguard Worker 
OnDisconnect(base::UnixSocket * sock)414*6dbdd20aSAndroid Build Coastguard Worker void HostImpl::OnDisconnect(base::UnixSocket* sock) {
415*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
416*6dbdd20aSAndroid Build Coastguard Worker   auto it = clients_by_socket_.find(sock);
417*6dbdd20aSAndroid Build Coastguard Worker   if (it == clients_by_socket_.end())
418*6dbdd20aSAndroid Build Coastguard Worker     return;
419*6dbdd20aSAndroid Build Coastguard Worker   auto* client = it->second;
420*6dbdd20aSAndroid Build Coastguard Worker   ClientID client_id = client->id;
421*6dbdd20aSAndroid Build Coastguard Worker 
422*6dbdd20aSAndroid Build Coastguard Worker   ClientInfo client_info(client_id, client->GetPosixPeerUid(),
423*6dbdd20aSAndroid Build Coastguard Worker                          client->GetLinuxPeerPid(), client->GetMachineID());
424*6dbdd20aSAndroid Build Coastguard Worker 
425*6dbdd20aSAndroid Build Coastguard Worker   clients_by_socket_.erase(it);
426*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK(clients_.count(client_id));
427*6dbdd20aSAndroid Build Coastguard Worker   clients_.erase(client_id);
428*6dbdd20aSAndroid Build Coastguard Worker 
429*6dbdd20aSAndroid Build Coastguard Worker   for (const auto& service_it : services_) {
430*6dbdd20aSAndroid Build Coastguard Worker     Service& service = *service_it.second.instance;
431*6dbdd20aSAndroid Build Coastguard Worker     service.client_info_ = client_info;
432*6dbdd20aSAndroid Build Coastguard Worker     service.OnClientDisconnected();
433*6dbdd20aSAndroid Build Coastguard Worker     service.client_info_ = ClientInfo();
434*6dbdd20aSAndroid Build Coastguard Worker   }
435*6dbdd20aSAndroid Build Coastguard Worker }
436*6dbdd20aSAndroid Build Coastguard Worker 
GetServiceByName(const std::string & name)437*6dbdd20aSAndroid Build Coastguard Worker const HostImpl::ExposedService* HostImpl::GetServiceByName(
438*6dbdd20aSAndroid Build Coastguard Worker     const std::string& name) {
439*6dbdd20aSAndroid Build Coastguard Worker   // This could be optimized by using another map<name,ServiceID>. However this
440*6dbdd20aSAndroid Build Coastguard Worker   // is used only by Bind/ExposeService that are quite rare (once per client
441*6dbdd20aSAndroid Build Coastguard Worker   // connection and once per service instance), not worth it.
442*6dbdd20aSAndroid Build Coastguard Worker   for (const auto& it : services_) {
443*6dbdd20aSAndroid Build Coastguard Worker     if (it.second.name == name)
444*6dbdd20aSAndroid Build Coastguard Worker       return &it.second;
445*6dbdd20aSAndroid Build Coastguard Worker   }
446*6dbdd20aSAndroid Build Coastguard Worker   return nullptr;
447*6dbdd20aSAndroid Build Coastguard Worker }
448*6dbdd20aSAndroid Build Coastguard Worker 
ExposedService(ServiceID id_,const std::string & name_,std::unique_ptr<Service> instance_)449*6dbdd20aSAndroid Build Coastguard Worker HostImpl::ExposedService::ExposedService(ServiceID id_,
450*6dbdd20aSAndroid Build Coastguard Worker                                          const std::string& name_,
451*6dbdd20aSAndroid Build Coastguard Worker                                          std::unique_ptr<Service> instance_)
452*6dbdd20aSAndroid Build Coastguard Worker     : id(id_), name(name_), instance(std::move(instance_)) {}
453*6dbdd20aSAndroid Build Coastguard Worker 
454*6dbdd20aSAndroid Build Coastguard Worker HostImpl::ExposedService::ExposedService(ExposedService&&) noexcept = default;
455*6dbdd20aSAndroid Build Coastguard Worker HostImpl::ExposedService& HostImpl::ExposedService::operator=(
456*6dbdd20aSAndroid Build Coastguard Worker     HostImpl::ExposedService&&) = default;
457*6dbdd20aSAndroid Build Coastguard Worker HostImpl::ExposedService::~ExposedService() = default;
458*6dbdd20aSAndroid Build Coastguard Worker 
459*6dbdd20aSAndroid Build Coastguard Worker HostImpl::ClientConnection::~ClientConnection() = default;
460*6dbdd20aSAndroid Build Coastguard Worker 
461*6dbdd20aSAndroid Build Coastguard Worker }  // namespace ipc
462*6dbdd20aSAndroid Build Coastguard Worker }  // namespace perfetto
463