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