blob: 9a56e62e230b77ece00002713b185da3d1391ed1 [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 "tracing/src/core/service_impl.h"
#include <inttypes.h>
#include <algorithm>
#include "perfetto_base/logging.h"
#include "perfetto_base/task_runner.h"
#include "tracing/core/data_source_config.h"
#include "tracing/core/producer.h"
#include "tracing/core/shared_memory.h"
namespace perfetto {
// TODO add ThreadChecker everywhere.
namespace {
constexpr size_t kPageSize = 4096;
constexpr size_t kDefaultShmSize = kPageSize * 16; // 64 KB.
constexpr size_t kMaxShmSize = kPageSize * 1024; // 4 MB.
} // namespace
// static
std::unique_ptr<Service> Service::CreateInstance(
std::unique_ptr<SharedMemory::Factory> shm_factory,
base::TaskRunner* task_runner) {
return std::unique_ptr<Service>(
new ServiceImpl(std::move(shm_factory), task_runner));
}
ServiceImpl::ServiceImpl(std::unique_ptr<SharedMemory::Factory> shm_factory,
base::TaskRunner* task_runner)
: shm_factory_(std::move(shm_factory)), task_runner_(task_runner) {
PERFETTO_DCHECK(task_runner_);
}
ServiceImpl::~ServiceImpl() {
// TODO handle teardown of all Producer.
}
std::unique_ptr<Service::ProducerEndpoint> ServiceImpl::ConnectProducer(
Producer* producer,
size_t shared_buffer_size_hint_bytes) {
const ProducerID id = ++last_producer_id_;
size_t shm_size = std::min(shared_buffer_size_hint_bytes, kMaxShmSize);
if (shm_size % kPageSize || shm_size < kPageSize)
shm_size = kDefaultShmSize;
// TODO(primiano): right now Create() will suicide in case of OOM if the mmap
// fails. We should instead gracefully fail the request and tell the client
// to go away.
auto shared_memory = shm_factory_->CreateSharedMemory(shm_size);
std::unique_ptr<ProducerEndpointImpl> endpoint(new ProducerEndpointImpl(
id, this, task_runner_, producer, std::move(shared_memory)));
auto it_and_inserted = producers_.emplace(id, endpoint.get());
PERFETTO_DCHECK(it_and_inserted.second);
task_runner_->PostTask(std::bind(&Producer::OnConnect, endpoint->producer()));
if (observer_)
observer_->OnProducerConnected(id);
return std::move(endpoint);
}
void ServiceImpl::DisconnectProducer(ProducerID id) {
PERFETTO_DCHECK(producers_.count(id));
producers_.erase(id);
if (observer_)
observer_->OnProducerDisconnected(id);
}
ServiceImpl::ProducerEndpointImpl* ServiceImpl::GetProducer(
ProducerID id) const {
auto it = producers_.find(id);
if (it == producers_.end())
return nullptr;
return it->second;
}
////////////////////////////////////////////////////////////////////////////////
// ServiceImpl::ProducerEndpointImpl implementation
////////////////////////////////////////////////////////////////////////////////
ServiceImpl::ProducerEndpointImpl::ProducerEndpointImpl(
ProducerID id,
ServiceImpl* service,
base::TaskRunner* task_runner,
Producer* producer,
std::unique_ptr<SharedMemory> shared_memory)
: id_(id),
service_(service),
task_runner_(task_runner),
producer_(std::move(producer)),
shared_memory_(std::move(shared_memory)) {}
ServiceImpl::ProducerEndpointImpl::~ProducerEndpointImpl() {
producer_->OnDisconnect();
service_->DisconnectProducer(id_);
}
void ServiceImpl::ProducerEndpointImpl::RegisterDataSource(
const DataSourceDescriptor&,
RegisterDataSourceCallback callback) {
const DataSourceID dsid = ++last_data_source_id_;
task_runner_->PostTask(std::bind(std::move(callback), dsid));
// TODO implement the bookkeeping logic.
if (service_->observer_)
service_->observer_->OnDataSourceRegistered(id_, dsid);
}
void ServiceImpl::ProducerEndpointImpl::UnregisterDataSource(
DataSourceID dsid) {
PERFETTO_CHECK(dsid);
// TODO implement the bookkeeping logic.
if (service_->observer_)
service_->observer_->OnDataSourceUnregistered(id_, dsid);
}
void ServiceImpl::ProducerEndpointImpl::NotifySharedMemoryUpdate(
const std::vector<uint32_t>& changed_pages) {
// TODO implement the bookkeeping logic.
return;
}
void ServiceImpl::set_observer_for_testing(ObserverForTesting* observer) {
observer_ = observer;
}
SharedMemory* ServiceImpl::ProducerEndpointImpl::shared_memory() const {
return shared_memory_.get();
}
} // namespace perfetto