0

[tracing] Fix process type for cloned sessions.

When a session is cloned, OnStop isn't called and thus
process descriptor doesn't have process type if it was set
after the tracing session started.
This brings back logic similar to https://chromium-review.googlesource.com/c/chromium/src/+/6163823
with a few difference:
- process type is updated (whereas only the process name was previously set)
- The descriptor is written by TrackNameRecorder
- process labels are kept and emitted in TrackNameRecorder

Change-Id: I65907390d8da74a34359cd2ff5d054a2d20d1be5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6298800
Commit-Queue: Etienne Pierre-Doray <etiennep@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1425303}
This commit is contained in:
Etienne Pierre-doray
2025-02-26 11:42:16 -08:00
committed by Chromium LUCI CQ
parent 93049ba857
commit 2a39a4e38e
7 changed files with 192 additions and 127 deletions

@ -12,7 +12,6 @@
#include "build/build_config.h"
#include "services/tracing/public/cpp/perfetto/trace_string_lookup.h"
#include "third_party/perfetto/include/perfetto/tracing/internal/track_event_internal.h"
#include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_process_descriptor.gen.h"
#include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_thread_descriptor.gen.h"
#include "third_party/perfetto/protos/perfetto/trace/track_event/process_descriptor.gen.h"
#include "third_party/perfetto/protos/perfetto/trace/track_event/thread_descriptor.gen.h"
@ -23,71 +22,27 @@
namespace tracing {
// Set the track descriptor for the current process.
void SetProcessTrackDescriptor(int64_t process_start_timestamp) {
using perfetto::protos::gen::ChromeProcessDescriptor;
const auto* trace_log = base::trace_event::TraceLog::GetInstance();
int process_id = trace_log->process_id();
std::string process_name = base::CurrentProcess::GetInstance().GetName({});
auto process_type = static_cast<ChromeProcessDescriptor::ProcessType>(
base::CurrentProcess::GetInstance().GetType({}));
// We record a few (string) fields here that are stripped for background
// tracing. We rely on the post-process privacy filtering to remove them.
auto process_track = perfetto::ProcessTrack::Current();
auto process_track_desc = process_track.Serialize();
auto* process = process_track_desc.mutable_process();
process->set_pid(process_id);
process->set_process_name(process_name);
process->set_start_timestamp_ns(process_start_timestamp);
for (const auto& label : trace_log->process_labels()) {
process->add_process_labels(label.second);
}
auto* chrome_process = process_track_desc.mutable_chrome_process();
if (process_type != ChromeProcessDescriptor::PROCESS_UNSPECIFIED) {
chrome_process->set_process_type(process_type);
}
// Add the crash trace ID to all the traces uploaded. If there are crashes
// during this tracing session, then the crash will contain the process's
// trace ID as "chrome-trace-id" crash key. This should be emitted
// periodically to ensure it is present in the traces when the process
// crashes. Metadata can go missing if process crashes. So, record this in
// process descriptor.
static const std::optional<uint64_t> crash_trace_id = GetTraceCrashId();
if (crash_trace_id) {
chrome_process->set_crash_trace_id(*crash_trace_id);
}
#if BUILDFLAG(IS_ANDROID)
// Host app package name is only recorded if the corresponding TraceLog
// setting is set to true.
if (trace_log->ShouldRecordHostAppPackageName()) {
// Host app package name is used to group information from different
// processes that "belong" to the same WebView app.
if (process_type == ChromeProcessDescriptor::PROCESS_RENDERER ||
process_type == ChromeProcessDescriptor::PROCESS_BROWSER) {
chrome_process->set_host_app_package_name(
base::android::BuildInfo::GetInstance()->host_package_name());
}
}
#endif // BUILDFLAG(IS_ANDROID)
base::TrackEvent::SetTrackDescriptor(process_track,
std::move(process_track_desc));
}
using perfetto::protos::gen::ChromeProcessDescriptor;
namespace {
std::optional<uint64_t> GetTraceCrashId() {
static base::debug::CrashKeyString* key = base::debug::AllocateCrashKeyString(
"chrome-trace-id", base::debug::CrashKeySize::Size32);
if (!key) {
return std::nullopt;
}
uint64_t id = base::RandUint64();
base::debug::SetCrashKeyString(key, base::NumberToString(id));
return id;
}
void FillThreadTrack(const perfetto::ThreadTrack& track, const char* name) {
using perfetto::protos::gen::ChromeThreadDescriptor;
int process_id = static_cast<int>(
base::trace_event::TraceLog::GetInstance()->process_id());
auto desc = track.Serialize();
desc.mutable_thread()->set_pid(process_id);
desc.mutable_thread()->set_pid(static_cast<int>(
base::trace_event::TraceLog::GetInstance()->process_id()));
desc.mutable_thread()->set_thread_name(name);
auto thread_type =
static_cast<ChromeThreadDescriptor::ThreadType>(GetThreadType(name));
@ -117,23 +72,64 @@ void SetThreadTrackDescriptors() {
auto thread_track = perfetto::ThreadTrack::Current();
FillThreadTrack(thread_track, thread_name);
}
} // namespace
std::optional<uint64_t> GetTraceCrashId() {
static base::debug::CrashKeyString* key = base::debug::AllocateCrashKeyString(
"chrome-trace-id", base::debug::CrashKeySize::Size32);
if (!key) {
return std::nullopt;
void TrackNameRecorder::SetProcessTrackDescriptor(
const std::string& process_name,
ChromeProcessDescriptor::ProcessType process_type) {
// We record a few (string) fields here that are stripped for background
// tracing. We rely on the post-process privacy filtering to remove them.
auto process_track = perfetto::ProcessTrack::Current();
auto process_track_desc = process_track.Serialize();
auto* process = process_track_desc.mutable_process();
process->set_pid(base::trace_event::TraceLog::GetInstance()->process_id());
process->set_process_name(process_name);
process->set_start_timestamp_ns(process_start_timestamp_);
for (const auto& label : process_labels()) {
process->add_process_labels(label.second);
}
uint64_t id = base::RandUint64();
base::debug::SetCrashKeyString(key, base::NumberToString(id));
return id;
auto* chrome_process = process_track_desc.mutable_chrome_process();
if (process_type != ChromeProcessDescriptor::PROCESS_UNSPECIFIED) {
chrome_process->set_process_type(process_type);
}
// Add the crash trace ID to all the traces uploaded. If there are crashes
// during this tracing session, then the crash will contain the process's
// trace ID as "chrome-trace-id" crash key. This should be emitted
// periodically to ensure it is present in the traces when the process
// crashes. Metadata can go missing if process crashes. So, record this in
// process descriptor.
static const std::optional<uint64_t> crash_trace_id = GetTraceCrashId();
if (crash_trace_id) {
chrome_process->set_crash_trace_id(*crash_trace_id);
}
#if BUILDFLAG(IS_ANDROID)
// Host app package name is only recorded if the corresponding TraceLog
// setting is set to true.
if (base::trace_event::TraceLog::GetInstance()
->ShouldRecordHostAppPackageName()) {
// Host app package name is used to group information from different
// processes that "belong" to the same WebView app.
if (process_type == ChromeProcessDescriptor::PROCESS_RENDERER ||
process_type == ChromeProcessDescriptor::PROCESS_BROWSER) {
chrome_process->set_host_app_package_name(
base::android::BuildInfo::GetInstance()->host_package_name());
}
}
#endif // BUILDFLAG(IS_ANDROID)
base::TrackEvent::SetTrackDescriptor(process_track,
std::move(process_track_desc));
}
TrackNameRecorder::TrackNameRecorder()
: process_start_timestamp_(
TRACE_TIME_TICKS_NOW().since_origin().InNanoseconds()) {
base::ThreadIdNameManager::GetInstance()->AddObserver(this);
base::CurrentProcess::GetInstance().SetDelegate(this, {});
base::TrackEvent::AddSessionObserver(this);
SetThreadTrackDescriptors();
}
@ -147,11 +143,11 @@ TrackNameRecorder* TrackNameRecorder::GetInstance() {
}
void TrackNameRecorder::OnSetup(const perfetto::DataSourceBase::SetupArgs&) {
SetProcessTrackDescriptor(process_start_timestamp_);
SetProcessTrackDescriptor();
}
void TrackNameRecorder::OnStop(const perfetto::DataSourceBase::StopArgs&) {
SetProcessTrackDescriptor(process_start_timestamp_);
SetProcessTrackDescriptor();
}
void TrackNameRecorder::OnThreadNameChanged(const char* name) {
@ -159,4 +155,49 @@ void TrackNameRecorder::OnThreadNameChanged(const char* name) {
// never happen outside of tests.
FillThreadTrack(perfetto::ThreadTrack::Current(), name);
}
void TrackNameRecorder::OnProcessNameChanged(
const std::string& process_name,
base::CurrentProcessType process_type) {
if (perfetto::Tracing::IsInitialized()) {
SetProcessTrackDescriptor(
process_name,
static_cast<ChromeProcessDescriptor::ProcessType>(process_type));
}
}
int TrackNameRecorder::GetNewProcessLabelId() {
base::AutoLock lock(lock_);
return next_process_label_id_++;
}
void TrackNameRecorder::UpdateProcessLabel(int label_id,
const std::string& current_label) {
if (!current_label.length()) {
return RemoveProcessLabel(label_id);
}
if (perfetto::Tracing::IsInitialized()) {
auto track = perfetto::ProcessTrack::Current();
auto desc = track.Serialize();
desc.mutable_process()->add_process_labels(current_label);
base::TrackEvent::SetTrackDescriptor(track, std::move(desc));
}
base::AutoLock lock(lock_);
process_labels_[label_id] = current_label;
}
void TrackNameRecorder::RemoveProcessLabel(int label_id) {
base::AutoLock lock(lock_);
process_labels_.erase(label_id);
}
void TrackNameRecorder::SetProcessTrackDescriptor() {
std::string process_name = base::CurrentProcess::GetInstance().GetName({});
auto process_type = static_cast<ChromeProcessDescriptor::ProcessType>(
base::CurrentProcess::GetInstance().GetType({}));
SetProcessTrackDescriptor(process_name, process_type);
}
} // namespace tracing

@ -6,20 +6,23 @@
#define SERVICES_TRACING_PUBLIC_CPP_PERFETTO_TRACK_NAME_RECORDER_H_
#include "base/component_export.h"
#include "base/process/current_process.h"
#include "base/process/process_handle.h"
#include "base/sequence_checker.h"
#include "base/threading/thread_id_name_manager.h"
#include "base/trace_event/trace_config.h"
#include "base/trace_event/typed_macros.h"
#include "third_party/abseil-cpp/absl/container/flat_hash_map.h"
#include "third_party/perfetto/include/perfetto/tracing/internal/track_event_internal.h"
#include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_process_descriptor.gen.h"
namespace tracing {
std::optional<uint64_t> GetTraceCrashId();
// A class that emits track descriptors for Chrome processes and threads.
class COMPONENT_EXPORT(TRACING_CPP) TrackNameRecorder
: public perfetto::TrackEventSessionObserver,
base::ThreadIdNameManager::Observer {
base::ThreadIdNameManager::Observer,
base::CurrentProcess::Delegate {
public:
static TrackNameRecorder* GetInstance();
@ -33,13 +36,42 @@ class COMPONENT_EXPORT(TRACING_CPP) TrackNameRecorder
// base::ThreadIdNameManager::Observer implementation.
void OnThreadNameChanged(const char* name) override;
// base::CurrentProcess::Delegate implementation.
void OnProcessNameChanged(const std::string& process_name,
base::CurrentProcessType process_type) override;
// Processes can have labels in addition to their names. Use labels, for
// instance, to list out the web page titles that a process is handling.
int GetNewProcessLabelId();
void UpdateProcessLabel(int label_id, const std::string& current_label);
void RemoveProcessLabel(int label_id);
private:
friend class base::NoDestructor<TrackNameRecorder>;
using ChromeProcessDescriptor =
perfetto::protos::gen::ChromeProcessDescriptor;
TrackNameRecorder();
~TrackNameRecorder() override;
uint64_t process_start_timestamp_;
// Set the track descriptor for the current process.
void SetProcessTrackDescriptor(
const std::string& process_name,
ChromeProcessDescriptor::ProcessType process_type);
void SetProcessTrackDescriptor();
absl::flat_hash_map<int, std::string> process_labels() const {
base::AutoLock lock(lock_);
return process_labels_;
}
int64_t process_start_timestamp_;
// This lock protects `process_labels_` member accesses from arbitrary
// threads.
mutable base::Lock lock_;
int next_process_label_id_ GUARDED_BY(lock_) = 0;
absl::flat_hash_map<int, std::string> process_labels_ GUARDED_BY(lock_);
};
} // namespace tracing