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/client_impl.h"
18*6dbdd20aSAndroid Build Coastguard Worker
19*6dbdd20aSAndroid Build Coastguard Worker #include <fcntl.h>
20*6dbdd20aSAndroid Build Coastguard Worker
21*6dbdd20aSAndroid Build Coastguard Worker #include <cinttypes>
22*6dbdd20aSAndroid Build Coastguard Worker #include <utility>
23*6dbdd20aSAndroid Build Coastguard Worker
24*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/task_runner.h"
25*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/unix_socket.h"
26*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/utils.h"
27*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/ipc/service_descriptor.h"
28*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/ipc/service_proxy.h"
29*6dbdd20aSAndroid Build Coastguard Worker
30*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/ipc/wire_protocol.gen.h"
31*6dbdd20aSAndroid Build Coastguard Worker
32*6dbdd20aSAndroid Build Coastguard Worker // TODO(primiano): Add ThreadChecker everywhere.
33*6dbdd20aSAndroid Build Coastguard Worker
34*6dbdd20aSAndroid Build Coastguard Worker // TODO(primiano): Add timeouts.
35*6dbdd20aSAndroid Build Coastguard Worker
36*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
37*6dbdd20aSAndroid Build Coastguard Worker namespace ipc {
38*6dbdd20aSAndroid Build Coastguard Worker
39*6dbdd20aSAndroid Build Coastguard Worker namespace {
40*6dbdd20aSAndroid Build Coastguard Worker constexpr base::SockFamily kClientSockFamily =
41*6dbdd20aSAndroid Build Coastguard Worker kUseTCPSocket ? base::SockFamily::kInet : base::SockFamily::kUnix;
42*6dbdd20aSAndroid Build Coastguard Worker } // namespace
43*6dbdd20aSAndroid Build Coastguard Worker
44*6dbdd20aSAndroid Build Coastguard Worker // static
CreateInstance(ConnArgs conn_args,base::TaskRunner * task_runner)45*6dbdd20aSAndroid Build Coastguard Worker std::unique_ptr<Client> Client::CreateInstance(ConnArgs conn_args,
46*6dbdd20aSAndroid Build Coastguard Worker base::TaskRunner* task_runner) {
47*6dbdd20aSAndroid Build Coastguard Worker std::unique_ptr<Client> client(
48*6dbdd20aSAndroid Build Coastguard Worker new ClientImpl(std::move(conn_args), task_runner));
49*6dbdd20aSAndroid Build Coastguard Worker return client;
50*6dbdd20aSAndroid Build Coastguard Worker }
51*6dbdd20aSAndroid Build Coastguard Worker
ClientImpl(ConnArgs conn_args,base::TaskRunner * task_runner)52*6dbdd20aSAndroid Build Coastguard Worker ClientImpl::ClientImpl(ConnArgs conn_args, base::TaskRunner* task_runner)
53*6dbdd20aSAndroid Build Coastguard Worker : socket_name_(conn_args.socket_name),
54*6dbdd20aSAndroid Build Coastguard Worker socket_retry_(conn_args.retry),
55*6dbdd20aSAndroid Build Coastguard Worker task_runner_(task_runner),
56*6dbdd20aSAndroid Build Coastguard Worker weak_ptr_factory_(this) {
57*6dbdd20aSAndroid Build Coastguard Worker if (conn_args.socket_fd) {
58*6dbdd20aSAndroid Build Coastguard Worker // Create the client using a connected socket. This code path will never hit
59*6dbdd20aSAndroid Build Coastguard Worker // OnConnect().
60*6dbdd20aSAndroid Build Coastguard Worker sock_ = base::UnixSocket::AdoptConnected(
61*6dbdd20aSAndroid Build Coastguard Worker std::move(conn_args.socket_fd), this, task_runner_, kClientSockFamily,
62*6dbdd20aSAndroid Build Coastguard Worker base::SockType::kStream, base::SockPeerCredMode::kIgnore);
63*6dbdd20aSAndroid Build Coastguard Worker } else {
64*6dbdd20aSAndroid Build Coastguard Worker // Connect using the socket name.
65*6dbdd20aSAndroid Build Coastguard Worker TryConnect();
66*6dbdd20aSAndroid Build Coastguard Worker }
67*6dbdd20aSAndroid Build Coastguard Worker }
68*6dbdd20aSAndroid Build Coastguard Worker
~ClientImpl()69*6dbdd20aSAndroid Build Coastguard Worker ClientImpl::~ClientImpl() {
70*6dbdd20aSAndroid Build Coastguard Worker // Ensure we are not destroyed in the middle of invoking a reply.
71*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(!invoking_method_reply_);
72*6dbdd20aSAndroid Build Coastguard Worker OnDisconnect(
73*6dbdd20aSAndroid Build Coastguard Worker nullptr); // The base::UnixSocket* ptr is not used in OnDisconnect().
74*6dbdd20aSAndroid Build Coastguard Worker }
75*6dbdd20aSAndroid Build Coastguard Worker
TryConnect()76*6dbdd20aSAndroid Build Coastguard Worker void ClientImpl::TryConnect() {
77*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(socket_name_);
78*6dbdd20aSAndroid Build Coastguard Worker sock_ = base::UnixSocket::Connect(
79*6dbdd20aSAndroid Build Coastguard Worker socket_name_, this, task_runner_, base::GetSockFamily(socket_name_),
80*6dbdd20aSAndroid Build Coastguard Worker base::SockType::kStream, base::SockPeerCredMode::kIgnore);
81*6dbdd20aSAndroid Build Coastguard Worker }
82*6dbdd20aSAndroid Build Coastguard Worker
BindService(base::WeakPtr<ServiceProxy> service_proxy)83*6dbdd20aSAndroid Build Coastguard Worker void ClientImpl::BindService(base::WeakPtr<ServiceProxy> service_proxy) {
84*6dbdd20aSAndroid Build Coastguard Worker if (!service_proxy)
85*6dbdd20aSAndroid Build Coastguard Worker return;
86*6dbdd20aSAndroid Build Coastguard Worker if (!sock_->is_connected()) {
87*6dbdd20aSAndroid Build Coastguard Worker queued_bindings_.emplace_back(service_proxy);
88*6dbdd20aSAndroid Build Coastguard Worker return;
89*6dbdd20aSAndroid Build Coastguard Worker }
90*6dbdd20aSAndroid Build Coastguard Worker RequestID request_id = ++last_request_id_;
91*6dbdd20aSAndroid Build Coastguard Worker Frame frame;
92*6dbdd20aSAndroid Build Coastguard Worker frame.set_request_id(request_id);
93*6dbdd20aSAndroid Build Coastguard Worker Frame::BindService* req = frame.mutable_msg_bind_service();
94*6dbdd20aSAndroid Build Coastguard Worker const char* const service_name = service_proxy->GetDescriptor().service_name;
95*6dbdd20aSAndroid Build Coastguard Worker req->set_service_name(service_name);
96*6dbdd20aSAndroid Build Coastguard Worker if (!SendFrame(frame)) {
97*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DLOG("BindService(%s) failed", service_name);
98*6dbdd20aSAndroid Build Coastguard Worker return service_proxy->OnConnect(false /* success */);
99*6dbdd20aSAndroid Build Coastguard Worker }
100*6dbdd20aSAndroid Build Coastguard Worker QueuedRequest qr;
101*6dbdd20aSAndroid Build Coastguard Worker qr.type = Frame::kMsgBindServiceFieldNumber;
102*6dbdd20aSAndroid Build Coastguard Worker qr.request_id = request_id;
103*6dbdd20aSAndroid Build Coastguard Worker qr.service_proxy = service_proxy;
104*6dbdd20aSAndroid Build Coastguard Worker queued_requests_.emplace(request_id, std::move(qr));
105*6dbdd20aSAndroid Build Coastguard Worker }
106*6dbdd20aSAndroid Build Coastguard Worker
UnbindService(ServiceID service_id)107*6dbdd20aSAndroid Build Coastguard Worker void ClientImpl::UnbindService(ServiceID service_id) {
108*6dbdd20aSAndroid Build Coastguard Worker service_bindings_.erase(service_id);
109*6dbdd20aSAndroid Build Coastguard Worker }
110*6dbdd20aSAndroid Build Coastguard Worker
BeginInvoke(ServiceID service_id,const std::string & method_name,MethodID remote_method_id,const ProtoMessage & method_args,bool drop_reply,base::WeakPtr<ServiceProxy> service_proxy,int fd)111*6dbdd20aSAndroid Build Coastguard Worker RequestID ClientImpl::BeginInvoke(ServiceID service_id,
112*6dbdd20aSAndroid Build Coastguard Worker const std::string& method_name,
113*6dbdd20aSAndroid Build Coastguard Worker MethodID remote_method_id,
114*6dbdd20aSAndroid Build Coastguard Worker const ProtoMessage& method_args,
115*6dbdd20aSAndroid Build Coastguard Worker bool drop_reply,
116*6dbdd20aSAndroid Build Coastguard Worker base::WeakPtr<ServiceProxy> service_proxy,
117*6dbdd20aSAndroid Build Coastguard Worker int fd) {
118*6dbdd20aSAndroid Build Coastguard Worker RequestID request_id = ++last_request_id_;
119*6dbdd20aSAndroid Build Coastguard Worker Frame frame;
120*6dbdd20aSAndroid Build Coastguard Worker frame.set_request_id(request_id);
121*6dbdd20aSAndroid Build Coastguard Worker Frame::InvokeMethod* req = frame.mutable_msg_invoke_method();
122*6dbdd20aSAndroid Build Coastguard Worker req->set_service_id(service_id);
123*6dbdd20aSAndroid Build Coastguard Worker req->set_method_id(remote_method_id);
124*6dbdd20aSAndroid Build Coastguard Worker req->set_drop_reply(drop_reply);
125*6dbdd20aSAndroid Build Coastguard Worker req->set_args_proto(method_args.SerializeAsString());
126*6dbdd20aSAndroid Build Coastguard Worker if (!SendFrame(frame, fd)) {
127*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DLOG("BeginInvoke() failed while sending the frame");
128*6dbdd20aSAndroid Build Coastguard Worker return 0;
129*6dbdd20aSAndroid Build Coastguard Worker }
130*6dbdd20aSAndroid Build Coastguard Worker if (drop_reply)
131*6dbdd20aSAndroid Build Coastguard Worker return 0;
132*6dbdd20aSAndroid Build Coastguard Worker QueuedRequest qr;
133*6dbdd20aSAndroid Build Coastguard Worker qr.type = Frame::kMsgInvokeMethodFieldNumber;
134*6dbdd20aSAndroid Build Coastguard Worker qr.request_id = request_id;
135*6dbdd20aSAndroid Build Coastguard Worker qr.method_name = method_name;
136*6dbdd20aSAndroid Build Coastguard Worker qr.service_proxy = std::move(service_proxy);
137*6dbdd20aSAndroid Build Coastguard Worker queued_requests_.emplace(request_id, std::move(qr));
138*6dbdd20aSAndroid Build Coastguard Worker return request_id;
139*6dbdd20aSAndroid Build Coastguard Worker }
140*6dbdd20aSAndroid Build Coastguard Worker
SendFrame(const Frame & frame,int fd)141*6dbdd20aSAndroid Build Coastguard Worker bool ClientImpl::SendFrame(const Frame& frame, int fd) {
142*6dbdd20aSAndroid Build Coastguard Worker // Serialize the frame into protobuf, add the size header, and send it.
143*6dbdd20aSAndroid Build Coastguard Worker std::string buf = BufferedFrameDeserializer::Serialize(frame);
144*6dbdd20aSAndroid Build Coastguard Worker
145*6dbdd20aSAndroid Build Coastguard Worker // TODO(primiano): this should do non-blocking I/O. But then what if the
146*6dbdd20aSAndroid Build Coastguard Worker // socket buffer is full? We might want to either drop the request or throttle
147*6dbdd20aSAndroid Build Coastguard Worker // the send and PostTask the reply later? Right now we are making Send()
148*6dbdd20aSAndroid Build Coastguard Worker // blocking as a workaround. Propagate bakpressure to the caller instead.
149*6dbdd20aSAndroid Build Coastguard Worker bool res = sock_->Send(buf.data(), buf.size(), fd);
150*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(res || !sock_->is_connected());
151*6dbdd20aSAndroid Build Coastguard Worker return res;
152*6dbdd20aSAndroid Build Coastguard Worker }
153*6dbdd20aSAndroid Build Coastguard Worker
OnConnect(base::UnixSocket *,bool connected)154*6dbdd20aSAndroid Build Coastguard Worker void ClientImpl::OnConnect(base::UnixSocket*, bool connected) {
155*6dbdd20aSAndroid Build Coastguard Worker if (!connected && socket_retry_) {
156*6dbdd20aSAndroid Build Coastguard Worker socket_backoff_ms_ =
157*6dbdd20aSAndroid Build Coastguard Worker (socket_backoff_ms_ < 10000) ? socket_backoff_ms_ + 1000 : 30000;
158*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DLOG(
159*6dbdd20aSAndroid Build Coastguard Worker "Connection to traced's UNIX socket failed, retrying in %u seconds",
160*6dbdd20aSAndroid Build Coastguard Worker socket_backoff_ms_ / 1000);
161*6dbdd20aSAndroid Build Coastguard Worker auto weak_this = weak_ptr_factory_.GetWeakPtr();
162*6dbdd20aSAndroid Build Coastguard Worker task_runner_->PostDelayedTask(
163*6dbdd20aSAndroid Build Coastguard Worker [weak_this] {
164*6dbdd20aSAndroid Build Coastguard Worker if (weak_this)
165*6dbdd20aSAndroid Build Coastguard Worker static_cast<ClientImpl&>(*weak_this).TryConnect();
166*6dbdd20aSAndroid Build Coastguard Worker },
167*6dbdd20aSAndroid Build Coastguard Worker socket_backoff_ms_);
168*6dbdd20aSAndroid Build Coastguard Worker return;
169*6dbdd20aSAndroid Build Coastguard Worker }
170*6dbdd20aSAndroid Build Coastguard Worker
171*6dbdd20aSAndroid Build Coastguard Worker // Drain the BindService() calls that were queued before establishing the
172*6dbdd20aSAndroid Build Coastguard Worker // connection with the host. Note that if we got disconnected, the call to
173*6dbdd20aSAndroid Build Coastguard Worker // OnConnect below might delete |this|, so move everything on the stack first.
174*6dbdd20aSAndroid Build Coastguard Worker auto queued_bindings = std::move(queued_bindings_);
175*6dbdd20aSAndroid Build Coastguard Worker queued_bindings_.clear();
176*6dbdd20aSAndroid Build Coastguard Worker for (base::WeakPtr<ServiceProxy>& service_proxy : queued_bindings) {
177*6dbdd20aSAndroid Build Coastguard Worker if (connected) {
178*6dbdd20aSAndroid Build Coastguard Worker BindService(service_proxy);
179*6dbdd20aSAndroid Build Coastguard Worker } else if (service_proxy) {
180*6dbdd20aSAndroid Build Coastguard Worker service_proxy->OnConnect(false /* success */);
181*6dbdd20aSAndroid Build Coastguard Worker }
182*6dbdd20aSAndroid Build Coastguard Worker }
183*6dbdd20aSAndroid Build Coastguard Worker // Don't access |this| below here.
184*6dbdd20aSAndroid Build Coastguard Worker }
185*6dbdd20aSAndroid Build Coastguard Worker
OnDisconnect(base::UnixSocket *)186*6dbdd20aSAndroid Build Coastguard Worker void ClientImpl::OnDisconnect(base::UnixSocket*) {
187*6dbdd20aSAndroid Build Coastguard Worker for (const auto& it : service_bindings_) {
188*6dbdd20aSAndroid Build Coastguard Worker base::WeakPtr<ServiceProxy> service_proxy = it.second;
189*6dbdd20aSAndroid Build Coastguard Worker task_runner_->PostTask([service_proxy] {
190*6dbdd20aSAndroid Build Coastguard Worker if (service_proxy)
191*6dbdd20aSAndroid Build Coastguard Worker service_proxy->OnDisconnect();
192*6dbdd20aSAndroid Build Coastguard Worker });
193*6dbdd20aSAndroid Build Coastguard Worker }
194*6dbdd20aSAndroid Build Coastguard Worker for (const auto& it : queued_requests_) {
195*6dbdd20aSAndroid Build Coastguard Worker const QueuedRequest& queued_request = it.second;
196*6dbdd20aSAndroid Build Coastguard Worker if (queued_request.type != Frame::kMsgBindServiceFieldNumber) {
197*6dbdd20aSAndroid Build Coastguard Worker continue;
198*6dbdd20aSAndroid Build Coastguard Worker }
199*6dbdd20aSAndroid Build Coastguard Worker base::WeakPtr<ServiceProxy> service_proxy = queued_request.service_proxy;
200*6dbdd20aSAndroid Build Coastguard Worker task_runner_->PostTask([service_proxy] {
201*6dbdd20aSAndroid Build Coastguard Worker if (service_proxy)
202*6dbdd20aSAndroid Build Coastguard Worker service_proxy->OnConnect(false);
203*6dbdd20aSAndroid Build Coastguard Worker });
204*6dbdd20aSAndroid Build Coastguard Worker }
205*6dbdd20aSAndroid Build Coastguard Worker service_bindings_.clear();
206*6dbdd20aSAndroid Build Coastguard Worker queued_bindings_.clear();
207*6dbdd20aSAndroid Build Coastguard Worker }
208*6dbdd20aSAndroid Build Coastguard Worker
OnDataAvailable(base::UnixSocket *)209*6dbdd20aSAndroid Build Coastguard Worker void ClientImpl::OnDataAvailable(base::UnixSocket*) {
210*6dbdd20aSAndroid Build Coastguard Worker size_t rsize;
211*6dbdd20aSAndroid Build Coastguard Worker do {
212*6dbdd20aSAndroid Build Coastguard Worker auto buf = frame_deserializer_.BeginReceive();
213*6dbdd20aSAndroid Build Coastguard Worker base::ScopedFile fd;
214*6dbdd20aSAndroid Build Coastguard Worker rsize = sock_->Receive(buf.data, buf.size, &fd);
215*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
216*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(!fd);
217*6dbdd20aSAndroid Build Coastguard Worker #else
218*6dbdd20aSAndroid Build Coastguard Worker if (fd) {
219*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(!received_fd_);
220*6dbdd20aSAndroid Build Coastguard Worker int res = fcntl(*fd, F_SETFD, FD_CLOEXEC);
221*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(res == 0);
222*6dbdd20aSAndroid Build Coastguard Worker received_fd_ = std::move(fd);
223*6dbdd20aSAndroid Build Coastguard Worker }
224*6dbdd20aSAndroid Build Coastguard Worker #endif
225*6dbdd20aSAndroid Build Coastguard Worker if (!frame_deserializer_.EndReceive(rsize)) {
226*6dbdd20aSAndroid Build Coastguard Worker // The endpoint tried to send a frame that is way too large.
227*6dbdd20aSAndroid Build Coastguard Worker return sock_->Shutdown(true); // In turn will trigger an OnDisconnect().
228*6dbdd20aSAndroid Build Coastguard Worker // TODO(fmayer): check this.
229*6dbdd20aSAndroid Build Coastguard Worker }
230*6dbdd20aSAndroid Build Coastguard Worker } while (rsize > 0);
231*6dbdd20aSAndroid Build Coastguard Worker
232*6dbdd20aSAndroid Build Coastguard Worker while (std::unique_ptr<Frame> frame = frame_deserializer_.PopNextFrame())
233*6dbdd20aSAndroid Build Coastguard Worker OnFrameReceived(*frame);
234*6dbdd20aSAndroid Build Coastguard Worker }
235*6dbdd20aSAndroid Build Coastguard Worker
OnFrameReceived(const Frame & frame)236*6dbdd20aSAndroid Build Coastguard Worker void ClientImpl::OnFrameReceived(const Frame& frame) {
237*6dbdd20aSAndroid Build Coastguard Worker auto queued_requests_it = queued_requests_.find(frame.request_id());
238*6dbdd20aSAndroid Build Coastguard Worker if (queued_requests_it == queued_requests_.end()) {
239*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DLOG("OnFrameReceived(): got invalid request_id=%" PRIu64,
240*6dbdd20aSAndroid Build Coastguard Worker static_cast<uint64_t>(frame.request_id()));
241*6dbdd20aSAndroid Build Coastguard Worker return;
242*6dbdd20aSAndroid Build Coastguard Worker }
243*6dbdd20aSAndroid Build Coastguard Worker QueuedRequest req = std::move(queued_requests_it->second);
244*6dbdd20aSAndroid Build Coastguard Worker queued_requests_.erase(queued_requests_it);
245*6dbdd20aSAndroid Build Coastguard Worker
246*6dbdd20aSAndroid Build Coastguard Worker if (req.type == Frame::kMsgBindServiceFieldNumber &&
247*6dbdd20aSAndroid Build Coastguard Worker frame.has_msg_bind_service_reply()) {
248*6dbdd20aSAndroid Build Coastguard Worker return OnBindServiceReply(std::move(req), frame.msg_bind_service_reply());
249*6dbdd20aSAndroid Build Coastguard Worker }
250*6dbdd20aSAndroid Build Coastguard Worker if (req.type == Frame::kMsgInvokeMethodFieldNumber &&
251*6dbdd20aSAndroid Build Coastguard Worker frame.has_msg_invoke_method_reply()) {
252*6dbdd20aSAndroid Build Coastguard Worker return OnInvokeMethodReply(std::move(req), frame.msg_invoke_method_reply());
253*6dbdd20aSAndroid Build Coastguard Worker }
254*6dbdd20aSAndroid Build Coastguard Worker if (frame.has_msg_request_error()) {
255*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DLOG("Host error: %s", frame.msg_request_error().error().c_str());
256*6dbdd20aSAndroid Build Coastguard Worker return;
257*6dbdd20aSAndroid Build Coastguard Worker }
258*6dbdd20aSAndroid Build Coastguard Worker
259*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DLOG(
260*6dbdd20aSAndroid Build Coastguard Worker "OnFrameReceived() request type=%d, received unknown frame in reply to "
261*6dbdd20aSAndroid Build Coastguard Worker "request_id=%" PRIu64,
262*6dbdd20aSAndroid Build Coastguard Worker req.type, static_cast<uint64_t>(frame.request_id()));
263*6dbdd20aSAndroid Build Coastguard Worker }
264*6dbdd20aSAndroid Build Coastguard Worker
OnBindServiceReply(QueuedRequest req,const Frame::BindServiceReply & reply)265*6dbdd20aSAndroid Build Coastguard Worker void ClientImpl::OnBindServiceReply(QueuedRequest req,
266*6dbdd20aSAndroid Build Coastguard Worker const Frame::BindServiceReply& reply) {
267*6dbdd20aSAndroid Build Coastguard Worker base::WeakPtr<ServiceProxy>& service_proxy = req.service_proxy;
268*6dbdd20aSAndroid Build Coastguard Worker if (!service_proxy)
269*6dbdd20aSAndroid Build Coastguard Worker return;
270*6dbdd20aSAndroid Build Coastguard Worker const char* svc_name = service_proxy->GetDescriptor().service_name;
271*6dbdd20aSAndroid Build Coastguard Worker if (!reply.success()) {
272*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DLOG("BindService(): unknown service_name=\"%s\"", svc_name);
273*6dbdd20aSAndroid Build Coastguard Worker return service_proxy->OnConnect(false /* success */);
274*6dbdd20aSAndroid Build Coastguard Worker }
275*6dbdd20aSAndroid Build Coastguard Worker
276*6dbdd20aSAndroid Build Coastguard Worker auto prev_service = service_bindings_.find(reply.service_id());
277*6dbdd20aSAndroid Build Coastguard Worker if (prev_service != service_bindings_.end() && prev_service->second.get()) {
278*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DLOG(
279*6dbdd20aSAndroid Build Coastguard Worker "BindService(): Trying to bind service \"%s\" but another service "
280*6dbdd20aSAndroid Build Coastguard Worker "named \"%s\" is already bound with the same ID.",
281*6dbdd20aSAndroid Build Coastguard Worker svc_name, prev_service->second->GetDescriptor().service_name);
282*6dbdd20aSAndroid Build Coastguard Worker return service_proxy->OnConnect(false /* success */);
283*6dbdd20aSAndroid Build Coastguard Worker }
284*6dbdd20aSAndroid Build Coastguard Worker
285*6dbdd20aSAndroid Build Coastguard Worker // Build the method [name] -> [remote_id] map.
286*6dbdd20aSAndroid Build Coastguard Worker std::map<std::string, MethodID> methods;
287*6dbdd20aSAndroid Build Coastguard Worker for (const auto& method : reply.methods()) {
288*6dbdd20aSAndroid Build Coastguard Worker if (method.name().empty() || method.id() <= 0) {
289*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DLOG("OnBindServiceReply(): invalid method \"%s\" -> %" PRIu64,
290*6dbdd20aSAndroid Build Coastguard Worker method.name().c_str(), static_cast<uint64_t>(method.id()));
291*6dbdd20aSAndroid Build Coastguard Worker continue;
292*6dbdd20aSAndroid Build Coastguard Worker }
293*6dbdd20aSAndroid Build Coastguard Worker methods[method.name()] = method.id();
294*6dbdd20aSAndroid Build Coastguard Worker }
295*6dbdd20aSAndroid Build Coastguard Worker service_proxy->InitializeBinding(weak_ptr_factory_.GetWeakPtr(),
296*6dbdd20aSAndroid Build Coastguard Worker reply.service_id(), std::move(methods));
297*6dbdd20aSAndroid Build Coastguard Worker service_bindings_[reply.service_id()] = service_proxy;
298*6dbdd20aSAndroid Build Coastguard Worker service_proxy->OnConnect(true /* success */);
299*6dbdd20aSAndroid Build Coastguard Worker }
300*6dbdd20aSAndroid Build Coastguard Worker
OnInvokeMethodReply(QueuedRequest req,const Frame::InvokeMethodReply & reply)301*6dbdd20aSAndroid Build Coastguard Worker void ClientImpl::OnInvokeMethodReply(QueuedRequest req,
302*6dbdd20aSAndroid Build Coastguard Worker const Frame::InvokeMethodReply& reply) {
303*6dbdd20aSAndroid Build Coastguard Worker base::WeakPtr<ServiceProxy> service_proxy = req.service_proxy;
304*6dbdd20aSAndroid Build Coastguard Worker if (!service_proxy)
305*6dbdd20aSAndroid Build Coastguard Worker return;
306*6dbdd20aSAndroid Build Coastguard Worker std::unique_ptr<ProtoMessage> decoded_reply;
307*6dbdd20aSAndroid Build Coastguard Worker if (reply.success()) {
308*6dbdd20aSAndroid Build Coastguard Worker // If this becomes a hotspot, optimize by maintaining a dedicated hashtable.
309*6dbdd20aSAndroid Build Coastguard Worker for (const auto& method : service_proxy->GetDescriptor().methods) {
310*6dbdd20aSAndroid Build Coastguard Worker if (req.method_name == method.name) {
311*6dbdd20aSAndroid Build Coastguard Worker decoded_reply = method.reply_proto_decoder(reply.reply_proto());
312*6dbdd20aSAndroid Build Coastguard Worker break;
313*6dbdd20aSAndroid Build Coastguard Worker }
314*6dbdd20aSAndroid Build Coastguard Worker }
315*6dbdd20aSAndroid Build Coastguard Worker }
316*6dbdd20aSAndroid Build Coastguard Worker const RequestID request_id = req.request_id;
317*6dbdd20aSAndroid Build Coastguard Worker invoking_method_reply_ = true;
318*6dbdd20aSAndroid Build Coastguard Worker service_proxy->EndInvoke(request_id, std::move(decoded_reply),
319*6dbdd20aSAndroid Build Coastguard Worker reply.has_more());
320*6dbdd20aSAndroid Build Coastguard Worker invoking_method_reply_ = false;
321*6dbdd20aSAndroid Build Coastguard Worker
322*6dbdd20aSAndroid Build Coastguard Worker // If this is a streaming method and future replies will be resolved, put back
323*6dbdd20aSAndroid Build Coastguard Worker // the |req| with the callback into the set of active requests.
324*6dbdd20aSAndroid Build Coastguard Worker if (reply.has_more())
325*6dbdd20aSAndroid Build Coastguard Worker queued_requests_.emplace(request_id, std::move(req));
326*6dbdd20aSAndroid Build Coastguard Worker }
327*6dbdd20aSAndroid Build Coastguard Worker
328*6dbdd20aSAndroid Build Coastguard Worker ClientImpl::QueuedRequest::QueuedRequest() = default;
329*6dbdd20aSAndroid Build Coastguard Worker
TakeReceivedFD()330*6dbdd20aSAndroid Build Coastguard Worker base::ScopedFile ClientImpl::TakeReceivedFD() {
331*6dbdd20aSAndroid Build Coastguard Worker return std::move(received_fd_);
332*6dbdd20aSAndroid Build Coastguard Worker }
333*6dbdd20aSAndroid Build Coastguard Worker
334*6dbdd20aSAndroid Build Coastguard Worker } // namespace ipc
335*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto
336