blob: 6246a6b69e8bb970cbe8426cd0e6d67bc926b20f [file] [log] [blame]
/*
* Copyright (C) 2019 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/test/api_test_support.h"
#include "perfetto/base/compiler.h"
#include "perfetto/base/proc_utils.h"
#include "perfetto/base/time.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/temp_file.h"
#include "src/tracing/internal/tracing_muxer_impl.h"
#include <sstream>
#if PERFETTO_BUILDFLAG(PERFETTO_IPC)
#include "test/test_helper.h"
#endif
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <Windows.h>
#endif
namespace perfetto {
namespace test {
using internal::TracingMuxerImpl;
#if PERFETTO_BUILDFLAG(PERFETTO_IPC)
namespace {
class InProcessSystemService {
public:
InProcessSystemService()
: test_helper_(&task_runner_, TestHelper::Mode::kStartDaemons) {
// Will always start service because we explicitly set kStartDaemons.
test_helper_.StartServiceIfRequired();
}
void CleanEnv() { test_helper_.CleanEnv(); }
private:
perfetto::base::TestTaskRunner task_runner_;
perfetto::TestHelper test_helper_;
};
InProcessSystemService* g_system_service = nullptr;
} // namespace
// static
SystemService SystemService::Start() {
// If there already was a system service running, make sure the new one is
// running before tearing down the old one. This avoids a 1 second
// reconnection delay between each test since the connection to the new
// service succeeds immediately.
std::unique_ptr<InProcessSystemService> old_service(g_system_service);
if (old_service) {
old_service->CleanEnv();
}
g_system_service = new InProcessSystemService();
// Tear down the service at process exit to make sure temporary files get
// deleted.
static bool cleanup_registered;
if (!cleanup_registered) {
atexit([] { delete g_system_service; });
cleanup_registered = true;
}
SystemService ret;
ret.valid_ = true;
return ret;
}
void SystemService::Clean() {
if (valid_) {
if (g_system_service) {
// Does not really stop. We want to reuse the service in future tests. It
// is important to clean the environment variables, though.
g_system_service->CleanEnv();
}
}
valid_ = false;
}
#else // !PERFETTO_BUILDFLAG(PERFETTO_IPC)
// static
SystemService SystemService::Start() {
return SystemService();
}
void SystemService::Clean() {
valid_ = false;
}
#endif // !PERFETTO_BUILDFLAG(PERFETTO_IPC)
SystemService& SystemService::operator=(SystemService&& other) noexcept {
PERFETTO_CHECK(!valid_ || !other.valid_);
Clean();
valid_ = other.valid_;
other.valid_ = false;
return *this;
}
int32_t GetCurrentProcessId() {
return static_cast<int32_t>(base::GetProcessId());
}
void SyncProducers() {
auto* muxer = reinterpret_cast<perfetto::internal::TracingMuxerImpl*>(
perfetto::internal::TracingMuxer::Get());
muxer->SyncProducersForTesting();
}
void SetBatchCommitsDuration(uint32_t batch_commits_duration_ms,
BackendType backend_type) {
auto* muxer = reinterpret_cast<perfetto::internal::TracingMuxerImpl*>(
perfetto::internal::TracingMuxer::Get());
muxer->SetBatchCommitsDurationForTesting(batch_commits_duration_ms,
backend_type);
}
void DisableReconnectLimit() {
auto* muxer = reinterpret_cast<perfetto::internal::TracingMuxerImpl*>(
perfetto::internal::TracingMuxer::Get());
muxer->SetMaxProducerReconnectionsForTesting(
std::numeric_limits<uint32_t>::max());
}
bool EnableDirectSMBPatching(BackendType backend_type) {
auto* muxer = reinterpret_cast<perfetto::internal::TracingMuxerImpl*>(
perfetto::internal::TracingMuxer::Get());
return muxer->EnableDirectSMBPatchingForTesting(backend_type);
}
TestTempFile CreateTempFile() {
TestTempFile res{};
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
base::StackString<255> temp_file("%s\\perfetto-XXXXXX", getenv("TMP"));
PERFETTO_CHECK(_mktemp_s(temp_file.mutable_data(), temp_file.len() + 1) == 0);
HANDLE handle =
::CreateFileA(temp_file.c_str(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_DELETE | FILE_SHARE_READ, nullptr, CREATE_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY, nullptr);
PERFETTO_CHECK(handle && handle != INVALID_HANDLE_VALUE);
res.fd = _open_osfhandle(reinterpret_cast<intptr_t>(handle), 0);
res.path = temp_file.ToStdString();
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
char temp_file[] = "/data/local/tmp/perfetto-XXXXXXXX";
res.fd = mkstemp(temp_file);
res.path = temp_file;
#else
char temp_file[] = "/tmp/perfetto-XXXXXXXX";
res.fd = mkstemp(temp_file);
res.path = temp_file;
#endif
PERFETTO_CHECK(res.fd > 0);
return res;
}
// static
bool TracingMuxerImplInternalsForTest::DoesSystemBackendHaveSMB() {
using RegisteredProducerBackend = TracingMuxerImpl::RegisteredProducerBackend;
// Ideally we should be doing dynamic_cast and a DCHECK(muxer != nullptr);
auto* muxer =
reinterpret_cast<TracingMuxerImpl*>(TracingMuxerImpl::instance_);
const auto& backends = muxer->producer_backends_;
const auto& backend =
std::find_if(backends.begin(), backends.end(),
[](const RegisteredProducerBackend& r_backend) {
return r_backend.type == kSystemBackend;
});
if (backend == backends.end())
return false;
const auto& service = backend->producer->service_;
return service && service->shared_memory();
}
// static
void TracingMuxerImplInternalsForTest::ClearIncrementalState() {
auto* muxer =
reinterpret_cast<TracingMuxerImpl*>(TracingMuxerImpl::instance_);
for (const auto& data_source : muxer->data_sources_) {
data_source.static_state->incremental_state_generation.fetch_add(
1, std::memory_order_relaxed);
}
}
} // namespace test
} // namespace perfetto