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