blob: 9c12a5b3e243b8b016457e3787af218f8143329d [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/tracing/ipc/consumer/consumer_ipc_client_impl.h"
#include <inttypes.h>
#include <string.h>
#include "perfetto/base/task_runner.h"
#include "perfetto/ipc/client.h"
#include "perfetto/tracing/core/consumer.h"
#include "perfetto/tracing/core/trace_config.h"
#include "perfetto/tracing/core/trace_packet.h"
// TODO Add a test to check to what happens when ConsumerIPCClientImpl gets
// destroyed w.r.t. the Consumer pointer. Also think to lifetime of the
// Consumer* during the callbacks.
namespace perfetto {
// static. (Declared in include/tracing/ipc/consumer_ipc_client.h).
std::unique_ptr<Service::ConsumerEndpoint> ConsumerIPCClient::Connect(
const char* service_sock_name,
Consumer* consumer,
base::TaskRunner* task_runner) {
return std::unique_ptr<Service::ConsumerEndpoint>(
new ConsumerIPCClientImpl(service_sock_name, consumer, task_runner));
}
ConsumerIPCClientImpl::ConsumerIPCClientImpl(const char* service_sock_name,
Consumer* consumer,
base::TaskRunner* task_runner)
: consumer_(consumer),
ipc_channel_(ipc::Client::CreateInstance(service_sock_name, task_runner)),
consumer_port_(this /* event_listener */),
weak_ptr_factory_(this) {
ipc_channel_->BindService(consumer_port_.GetWeakPtr());
}
ConsumerIPCClientImpl::~ConsumerIPCClientImpl() = default;
// Called by the IPC layer if the BindService() succeeds.
void ConsumerIPCClientImpl::OnConnect() {
connected_ = true;
consumer_->OnConnect();
}
void ConsumerIPCClientImpl::OnDisconnect() {
PERFETTO_DLOG("Tracing service connection failure");
connected_ = false;
consumer_->OnDisconnect();
}
void ConsumerIPCClientImpl::EnableTracing(const TraceConfig& trace_config) {
if (!connected_) {
PERFETTO_DLOG("Cannot EnableTracing(), not connected to tracing service");
return;
}
// Serialize the |trace_config| into a EnableTracingRequest protobuf.
// Keep this in sync with changes in consumer_port.proto.
EnableTracingRequest req;
trace_config.ToProto(req.mutable_trace_config());
ipc::Deferred<EnableTracingResponse> async_response;
async_response.Bind([](ipc::AsyncResult<EnableTracingResponse> response) {
if (!response)
PERFETTO_DLOG("EnableTracing() failed");
});
consumer_port_.EnableTracing(req, std::move(async_response));
}
void ConsumerIPCClientImpl::DisableTracing() {
if (!connected_) {
PERFETTO_DLOG("Cannot DisableTracing(), not connected to tracing service");
return;
}
ipc::Deferred<DisableTracingResponse> async_response;
async_response.Bind([](ipc::AsyncResult<DisableTracingResponse> response) {
if (!response)
PERFETTO_DLOG("DisableTracing() failed");
});
consumer_port_.DisableTracing(DisableTracingRequest(),
std::move(async_response));
}
void ConsumerIPCClientImpl::ReadBuffers() {
if (!connected_) {
PERFETTO_DLOG("Cannot ReadBuffers(), not connected to tracing service");
return;
}
ipc::Deferred<ReadBuffersResponse> async_response;
// The IPC layer guarantees that callbacks are destroyed after this object
// is destroyed (by virtue of destroying the |consumer_port_|). In turn the
// contract of this class expects the caller to not destroy the Consumer class
// before having destroyed this class. Hence binding |this| here is safe.
async_response.Bind([this](ipc::AsyncResult<ReadBuffersResponse> response) {
OnReadBuffersResponse(std::move(response));
});
consumer_port_.ReadBuffers(ReadBuffersRequest(), std::move(async_response));
}
void ConsumerIPCClientImpl::OnReadBuffersResponse(
ipc::AsyncResult<ReadBuffersResponse> response) {
if (!response) {
PERFETTO_DLOG("ReadBuffers() failed");
return;
}
// TODO(primiano): We have to guarantee that the log buffer stays alive at
// least as long as these requests are on flights.
std::vector<TracePacket> trace_packets;
trace_packets.reserve(response->trace_packets().size());
for (const std::string& bytes : response->trace_packets()) {
trace_packets.emplace_back();
trace_packets.back().AddChunk(
Chunk(reinterpret_cast<const void*>(bytes.data()), bytes.size()));
}
consumer_->OnTraceData(std::move(trace_packets), response.has_more());
}
void ConsumerIPCClientImpl::FreeBuffers() {
if (!connected_) {
PERFETTO_DLOG("Cannot FreeBuffers(), not connected to tracing service");
return;
}
FreeBuffersRequest req;
ipc::Deferred<FreeBuffersResponse> async_response;
async_response.Bind([](ipc::AsyncResult<FreeBuffersResponse> response) {
if (!response)
PERFETTO_DLOG("FreeBuffers() failed");
});
consumer_port_.FreeBuffers(req, std::move(async_response));
}
} // namespace perfetto