blob: ff3094ee2d71ceb53970d868b034bffe50d52b56 [file] [log] [blame]
Primiano Tucci1d94e7d2017-11-20 14:45:16 +00001/*
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 "tracing/src/ipc/producer/producer_ipc_client_impl.h"
18
19#include <inttypes.h>
20#include <string.h>
21
22#include "base/task_runner.h"
23#include "ipc/client.h"
24#include "tracing/core/data_source_config.h"
25#include "tracing/core/data_source_descriptor.h"
26#include "tracing/core/producer.h"
27#include "tracing/src/ipc/posix_shared_memory.h"
28
29// TODO think to what happens when ProducerIPCClientImpl gets destroyed
30// w.r.t. the Producer pointer. Also think to lifetime of the Producer* during
31// the callbacks.
32
33namespace perfetto {
34
35// static. (Declared in include/tracing/ipc/producer_ipc_client.h).
36std::unique_ptr<Service::ProducerEndpoint> ProducerIPCClient::Connect(
37 const char* service_sock_name,
38 Producer* producer,
39 base::TaskRunner* task_runner) {
40 return std::unique_ptr<Service::ProducerEndpoint>(
41 new ProducerIPCClientImpl(service_sock_name, producer, task_runner));
42}
43
44ProducerIPCClientImpl::ProducerIPCClientImpl(const char* service_sock_name,
45 Producer* producer,
46 base::TaskRunner* task_runner)
47 : producer_(producer),
48 task_runner_(task_runner),
49 ipc_channel_(ipc::Client::CreateInstance(service_sock_name, task_runner)),
50 producer_port_(this /* event_listener */) {
51 ipc_channel_->BindService(producer_port_.GetWeakPtr());
52}
53
54ProducerIPCClientImpl::~ProducerIPCClientImpl() = default;
55
56// Called by the IPC layer if the BindService() succeeds.
57void ProducerIPCClientImpl::OnConnect() {
58 connected_ = true;
59
60 // The IPC layer guarantees that any outstanding callback will be dropped on
61 // the floor if producer_port_ is destroyed between the request and the reply.
62 // Binding |this| is hence safe.
63 ipc::Deferred<InitializeConnectionResponse> on_init;
64 on_init.Bind([this](ipc::AsyncResult<InitializeConnectionResponse> resp) {
65 OnConnectionInitialized(resp.success());
66 });
67 producer_port_.InitializeConnection(InitializeConnectionRequest(),
68 std::move(on_init));
69
70 // Create the back channel to receive commands from the Service.
71 ipc::Deferred<GetAsyncCommandResponse> on_cmd;
72 on_cmd.Bind([this](ipc::AsyncResult<GetAsyncCommandResponse> resp) {
73 if (!resp)
74 return; // The IPC channel was closed and |resp| was auto-rejected.
75 OnServiceRequest(*resp);
76 });
77 producer_port_.GetAsyncCommand(GetAsyncCommandRequest(), std::move(on_cmd));
78}
79
80void ProducerIPCClientImpl::OnDisconnect() {
81 PERFETTO_DLOG("Tracing service connection failure");
82 connected_ = false;
83 producer_->OnDisconnect();
84}
85
86void ProducerIPCClientImpl::OnConnectionInitialized(bool connection_succeeded) {
Primiano Tucci1d94e7d2017-11-20 14:45:16 +000087 // If connection_succeeded == false, the OnDisconnect() call will follow next
88 // and there we'll notify the |producer_|. TODO: add a test for this.
Primiano Tuccif54cae42017-11-21 19:37:13 +000089 if (!connection_succeeded)
90 return;
91
92 base::ScopedFile shmem_fd = ipc_channel_->TakeReceivedFD();
93 PERFETTO_CHECK(shmem_fd);
94 shared_memory_ = PosixSharedMemory::AttachToFd(std::move(shmem_fd));
95 producer_->OnConnect();
Primiano Tucci1d94e7d2017-11-20 14:45:16 +000096}
97
98void ProducerIPCClientImpl::OnServiceRequest(
99 const GetAsyncCommandResponse& cmd) {
100 if (cmd.cmd_case() == GetAsyncCommandResponse::kStartDataSource) {
101 // Keep this in sync with chages in data_source_config.proto.
102 const auto& req = cmd.start_data_source();
103 const DataSourceInstanceID dsid = req.new_instance_id();
104 const proto::DataSourceConfig& proto_cfg = req.config();
105 DataSourceConfig cfg;
106 cfg.trace_category_filters = proto_cfg.trace_category_filters();
107 producer_->CreateDataSourceInstance(dsid, cfg);
108 return;
109 }
110
111 if (cmd.cmd_case() == GetAsyncCommandResponse::kStopDataSource) {
112 const DataSourceInstanceID dsid = cmd.stop_data_source().instance_id();
113 producer_->TearDownDataSourceInstance(dsid);
114 return;
115 }
116
117 PERFETTO_DLOG("Unknown async request %d received from tracing service",
118 cmd.cmd_case());
119}
120
121void ProducerIPCClientImpl::RegisterDataSource(
122 const DataSourceDescriptor& descriptor,
123 RegisterDataSourceCallback callback) {
124 if (!connected_) {
125 PERFETTO_DLOG(
126 "Cannot RegisterDataSource(), not connected to tracing service");
127 return task_runner_->PostTask(std::bind(callback, 0));
128 }
129 // Keep this in sync with changes in data_source_descriptor.proto.
130 RegisterDataSourceRequest req;
131 auto* proto_descriptor = req.mutable_data_source_descriptor();
132 proto_descriptor->set_name(descriptor.name);
133 ipc::Deferred<RegisterDataSourceResponse> async_response;
134 // TODO: add a test that destroys the IPC channel soon after this call and
135 // checks that the callback(0) is invoked.
136 // TODO: add a test that destroyes ProducerIPCClientImpl soon after this call
137 // and checks that the callback is dropped.
138 async_response.Bind(
139 [callback](ipc::AsyncResult<RegisterDataSourceResponse> response) {
140 if (!response) {
141 PERFETTO_DLOG("RegisterDataSource() failed: connection reset");
142 return callback(0);
143 }
144 if (response->data_source_id() == 0) {
145 PERFETTO_DLOG("RegisterDataSource() failed: %s",
146 response->error().c_str());
147 }
148 callback(response->data_source_id());
149 });
150 producer_port_.RegisterDataSource(req, std::move(async_response));
151}
152
153void ProducerIPCClientImpl::UnregisterDataSource(DataSourceID id) {
154 if (!connected_) {
155 PERFETTO_DLOG(
156 "Cannot UnregisterDataSource(), not connected to tracing service");
157 return;
158 }
159 UnregisterDataSourceRequest req;
160 req.set_data_source_id(id);
161 producer_port_.UnregisterDataSource(
162 req, ipc::Deferred<UnregisterDataSourceResponse>());
163}
164
165void ProducerIPCClientImpl::NotifySharedMemoryUpdate(
166 const std::vector<uint32_t>& changed_pages) {
167 if (!connected_) {
168 PERFETTO_DLOG(
169 "Cannot NotifySharedMemoryUpdate(), not connected to tracing service");
170 return;
171 }
172 NotifySharedMemoryUpdateRequest req;
173 for (uint32_t changed_page : changed_pages)
174 req.add_changed_pages(changed_page);
175 producer_port_.NotifySharedMemoryUpdate(
176 req, ipc::Deferred<NotifySharedMemoryUpdateResponse>());
177}
178
Primiano Tuccif54cae42017-11-21 19:37:13 +0000179SharedMemory* ProducerIPCClientImpl::shared_memory() const {
180 return shared_memory_.get();
181}
182
Primiano Tucci1d94e7d2017-11-20 14:45:16 +0000183} // namespace perfetto