• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/tracing/ipc/consumer/consumer_ipc_client_impl.h"
18 
19 #include <inttypes.h>
20 #include <string.h>
21 
22 #include "perfetto/base/task_runner.h"
23 #include "perfetto/ipc/client.h"
24 #include "perfetto/tracing/core/consumer.h"
25 #include "perfetto/tracing/core/trace_config.h"
26 
27 // TODO(fmayer): Add a test to check to what happens when ConsumerIPCClientImpl
28 // gets destroyed w.r.t. the Consumer pointer. Also think to lifetime of the
29 // Consumer* during the callbacks.
30 
31 namespace perfetto {
32 
33 // static. (Declared in include/tracing/ipc/consumer_ipc_client.h).
Connect(const char * service_sock_name,Consumer * consumer,base::TaskRunner * task_runner)34 std::unique_ptr<Service::ConsumerEndpoint> ConsumerIPCClient::Connect(
35     const char* service_sock_name,
36     Consumer* consumer,
37     base::TaskRunner* task_runner) {
38   return std::unique_ptr<Service::ConsumerEndpoint>(
39       new ConsumerIPCClientImpl(service_sock_name, consumer, task_runner));
40 }
41 
ConsumerIPCClientImpl(const char * service_sock_name,Consumer * consumer,base::TaskRunner * task_runner)42 ConsumerIPCClientImpl::ConsumerIPCClientImpl(const char* service_sock_name,
43                                              Consumer* consumer,
44                                              base::TaskRunner* task_runner)
45     : consumer_(consumer),
46       ipc_channel_(ipc::Client::CreateInstance(service_sock_name, task_runner)),
47       consumer_port_(this /* event_listener */),
48       weak_ptr_factory_(this) {
49   ipc_channel_->BindService(consumer_port_.GetWeakPtr());
50 }
51 
52 ConsumerIPCClientImpl::~ConsumerIPCClientImpl() = default;
53 
54 // Called by the IPC layer if the BindService() succeeds.
OnConnect()55 void ConsumerIPCClientImpl::OnConnect() {
56   connected_ = true;
57   consumer_->OnConnect();
58 }
59 
OnDisconnect()60 void ConsumerIPCClientImpl::OnDisconnect() {
61   PERFETTO_DLOG("Tracing service connection failure");
62   connected_ = false;
63   consumer_->OnDisconnect();
64 }
65 
EnableTracing(const TraceConfig & trace_config,base::ScopedFile fd)66 void ConsumerIPCClientImpl::EnableTracing(const TraceConfig& trace_config,
67                                           base::ScopedFile fd) {
68   if (!connected_) {
69     PERFETTO_DLOG("Cannot EnableTracing(), not connected to tracing service");
70     return;
71   }
72 
73   protos::EnableTracingRequest req;
74   trace_config.ToProto(req.mutable_trace_config());
75   ipc::Deferred<protos::EnableTracingResponse> async_response;
76   auto weak_this = weak_ptr_factory_.GetWeakPtr();
77   async_response.Bind(
78       [weak_this](ipc::AsyncResult<protos::EnableTracingResponse> response) {
79         if (!weak_this)
80           return;
81         if (!response || response->disabled())
82           weak_this->consumer_->OnTracingDisabled();
83       });
84 
85   // |fd| will be closed when this function returns, but it's fine because the
86   // IPC layer dup()'s it when sending the IPC.
87   consumer_port_.EnableTracing(req, std::move(async_response), *fd);
88 }
89 
DisableTracing()90 void ConsumerIPCClientImpl::DisableTracing() {
91   if (!connected_) {
92     PERFETTO_DLOG("Cannot DisableTracing(), not connected to tracing service");
93     return;
94   }
95 
96   ipc::Deferred<protos::DisableTracingResponse> async_response;
97   async_response.Bind(
98       [](ipc::AsyncResult<protos::DisableTracingResponse> response) {
99         if (!response)
100           PERFETTO_DLOG("DisableTracing() failed");
101       });
102   consumer_port_.DisableTracing(protos::DisableTracingRequest(),
103                                 std::move(async_response));
104 }
105 
ReadBuffers()106 void ConsumerIPCClientImpl::ReadBuffers() {
107   if (!connected_) {
108     PERFETTO_DLOG("Cannot ReadBuffers(), not connected to tracing service");
109     return;
110   }
111 
112   ipc::Deferred<protos::ReadBuffersResponse> async_response;
113 
114   // The IPC layer guarantees that callbacks are destroyed after this object
115   // is destroyed (by virtue of destroying the |consumer_port_|). In turn the
116   // contract of this class expects the caller to not destroy the Consumer class
117   // before having destroyed this class. Hence binding |this| here is safe.
118   async_response.Bind(
119       [this](ipc::AsyncResult<protos::ReadBuffersResponse> response) {
120         OnReadBuffersResponse(std::move(response));
121       });
122   consumer_port_.ReadBuffers(protos::ReadBuffersRequest(),
123                              std::move(async_response));
124 }
125 
OnReadBuffersResponse(ipc::AsyncResult<protos::ReadBuffersResponse> response)126 void ConsumerIPCClientImpl::OnReadBuffersResponse(
127     ipc::AsyncResult<protos::ReadBuffersResponse> response) {
128   if (!response) {
129     PERFETTO_DLOG("ReadBuffers() failed");
130     return;
131   }
132   std::vector<TracePacket> trace_packets;
133   for (auto& resp_slice : *response->mutable_slices()) {
134     partial_packet_.AddSlice(
135         Slice(std::unique_ptr<std::string>(resp_slice.release_data())));
136     if (resp_slice.last_slice_for_packet())
137       trace_packets.emplace_back(std::move(partial_packet_));
138   }
139   if (!trace_packets.empty() || !response.has_more())
140     consumer_->OnTraceData(std::move(trace_packets), response.has_more());
141 }
142 
FreeBuffers()143 void ConsumerIPCClientImpl::FreeBuffers() {
144   if (!connected_) {
145     PERFETTO_DLOG("Cannot FreeBuffers(), not connected to tracing service");
146     return;
147   }
148 
149   protos::FreeBuffersRequest req;
150   ipc::Deferred<protos::FreeBuffersResponse> async_response;
151   async_response.Bind(
152       [](ipc::AsyncResult<protos::FreeBuffersResponse> response) {
153         if (!response)
154           PERFETTO_DLOG("FreeBuffers() failed");
155       });
156   consumer_port_.FreeBuffers(req, std::move(async_response));
157 }
158 
Flush(uint32_t timeout_ms,FlushCallback callback)159 void ConsumerIPCClientImpl::Flush(uint32_t timeout_ms, FlushCallback callback) {
160   if (!connected_) {
161     PERFETTO_DLOG("Cannot Flush(), not connected to tracing service");
162     return callback(/*success=*/false);
163   }
164 
165   protos::FlushRequest req;
166   req.set_timeout_ms(static_cast<uint32_t>(timeout_ms));
167   ipc::Deferred<protos::FlushResponse> async_response;
168   async_response.Bind(
169       [callback](ipc::AsyncResult<protos::FlushResponse> response) {
170         callback(!!response);
171       });
172   consumer_port_.Flush(req, std::move(async_response));
173 }
174 
175 }  // namespace perfetto
176