#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "base/trace_event/trace_log.h"
#include <algorithm>
#include <cmath>
#include <memory>
#include <string_view>
#include <utility>
#include "build/build_config.h"
#include "arkweb/build/features/features.h"
#include "arkweb/chromium_ext/base/process/process_handle_posix_ex.h"
#include "base/containers/contains.h"
#include "base/debug/leak_annotations.h"
#include "base/format_macros.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/stack_allocated.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/process/process.h"
#include "base/process/process_metrics.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/trace_event/perfetto_proto_appender.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "third_party/perfetto/include/perfetto/ext/trace_processor/export_json.h"
#include "third_party/perfetto/include/perfetto/trace_processor/trace_processor_storage.h"
#include "third_party/perfetto/include/perfetto/tracing/console_interceptor.h"
#include "third_party/perfetto/protos/perfetto/config/chrome/chrome_config.gen.h"
#include "third_party/perfetto/protos/perfetto/config/interceptor_config.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"
#if BUILDFLAG(IS_ANDROID)
#include "base/debug/elf_reader.h"
extern char __executable_start;
#endif
namespace base::trace_event {
namespace {
TraceLog* g_trace_log_for_testing = nullptr;
ThreadTicks ThreadNow() {
return ThreadTicks::IsSupported()
? base::subtle::ThreadTicksNowIgnoringOverride()
: ThreadTicks();
}
void AddConvertableToTraceFormat(
base::trace_event::ConvertableToTraceFormat* value,
perfetto::protos::pbzero::DebugAnnotation* annotation) {
PerfettoProtoAppender proto_appender(annotation);
if (value->AppendToProto(&proto_appender)) {
return;
}
std::string json;
value->AppendAsTraceFormat(&json);
annotation->set_legacy_json_value(json.c_str());
}
void WriteDebugAnnotations(base::trace_event::TraceEvent* trace_event,
perfetto::protos::pbzero::TrackEvent* track_event) {
for (size_t i = 0; i < trace_event->arg_size() && trace_event->arg_name(i);
++i) {
auto type = trace_event->arg_type(i);
auto* annotation = track_event->add_debug_annotations();
annotation->set_name(trace_event->arg_name(i));
if (type == TRACE_VALUE_TYPE_CONVERTABLE) {
AddConvertableToTraceFormat(trace_event->arg_convertible_value(i),
annotation);
continue;
}
auto& value = trace_event->arg_value(i);
switch (type) {
case TRACE_VALUE_TYPE_BOOL:
annotation->set_bool_value(value.as_bool);
break;
case TRACE_VALUE_TYPE_UINT:
annotation->set_uint_value(value.as_uint);
break;
case TRACE_VALUE_TYPE_INT:
annotation->set_int_value(value.as_int);
break;
case TRACE_VALUE_TYPE_DOUBLE:
annotation->set_double_value(value.as_double);
break;
case TRACE_VALUE_TYPE_POINTER:
annotation->set_pointer_value(static_cast<uint64_t>(
reinterpret_cast<uintptr_t>(value.as_pointer)));
break;
case TRACE_VALUE_TYPE_STRING:
case TRACE_VALUE_TYPE_COPY_STRING:
annotation->set_string_value(value.as_string ? value.as_string
: "NULL");
break;
case TRACE_VALUE_TYPE_PROTO: {
auto data = value.as_proto->SerializeAsArray();
annotation->AppendRawProtoBytes(data.data(), data.size());
} break;
default:
NOTREACHED() << "Don't know how to serialize this value";
}
}
}
void OnAddLegacyTraceEvent(TraceEvent* trace_event) {
perfetto::DynamicCategory category(TRACE_EVENT_API_GET_CATEGORY_GROUP_NAME(
trace_event->category_group_enabled()));
auto phase = trace_event->phase();
if (phase == TRACE_EVENT_PHASE_COMPLETE) {
phase = TRACE_EVENT_PHASE_BEGIN;
}
auto write_args = [trace_event, phase](perfetto::EventContext ctx) {
WriteDebugAnnotations(trace_event, ctx.event());
uint32_t id_flags = trace_event->flags() & (TRACE_EVENT_FLAG_HAS_ID |
TRACE_EVENT_FLAG_HAS_LOCAL_ID |
TRACE_EVENT_FLAG_HAS_GLOBAL_ID);
if (!id_flags &&
perfetto::internal::TrackEventLegacy::PhaseToType(phase) !=
perfetto::protos::pbzero::TrackEvent::TYPE_UNSPECIFIED) {
return;
}
auto* legacy_event = ctx.event()->set_legacy_event();
legacy_event->set_phase(phase);
switch (id_flags) {
case TRACE_EVENT_FLAG_HAS_ID:
legacy_event->set_unscoped_id(trace_event->id());
break;
case TRACE_EVENT_FLAG_HAS_LOCAL_ID:
legacy_event->set_local_id(trace_event->id());
break;
case TRACE_EVENT_FLAG_HAS_GLOBAL_ID:
legacy_event->set_global_id(trace_event->id());
break;
default:
break;
}
if (trace_event->flags() & TRACE_EVENT_FLAG_HAS_PROCESS_ID) {
legacy_event->set_pid_override(
trace_event->thread_id().truncate_to_int32_for_display_only());
legacy_event->set_tid_override(static_cast<int32_t>(-1));
}
};
auto flags = trace_event->flags();
base::TimeTicks timestamp = trace_event->timestamp().is_null()
? TRACE_TIME_TICKS_NOW()
: trace_event->timestamp();
if (phase == TRACE_EVENT_PHASE_INSTANT) {
auto scope = flags & TRACE_EVENT_FLAG_SCOPE_MASK;
switch (scope) {
case TRACE_EVENT_SCOPE_GLOBAL:
PERFETTO_INTERNAL_LEGACY_EVENT_ON_TRACK(
phase, category, trace_event->name(), ::perfetto::Track::Global(0),
timestamp, write_args);
return;
case TRACE_EVENT_SCOPE_PROCESS:
PERFETTO_INTERNAL_LEGACY_EVENT_ON_TRACK(
phase, category, trace_event->name(),
::perfetto::ProcessTrack::Current(), timestamp, write_args);
return;
default:
case TRACE_EVENT_SCOPE_THREAD:
break;
}
}
if (trace_event->thread_id() != kInvalidThreadId &&
trace_event->thread_id() != base::PlatformThread::CurrentId() &&
!(trace_event->flags() & TRACE_EVENT_FLAG_HAS_PROCESS_ID)) {
PERFETTO_INTERNAL_LEGACY_EVENT_ON_TRACK(
phase, category, trace_event->name(),
perfetto::ThreadTrack::ForThread(trace_event->thread_id().raw()),
timestamp, write_args);
return;
}
PERFETTO_INTERNAL_LEGACY_EVENT_ON_TRACK(
phase, category, trace_event->name(),
perfetto::internal::TrackEventInternal::kDefaultTrack, timestamp,
write_args);
}
void OnUpdateLegacyTraceEventDuration(
const unsigned char* category_group_enabled,
const char* name,
PlatformThreadId thread_id,
bool explicit_timestamps,
const TimeTicks& now,
const ThreadTicks& thread_now) {
perfetto::DynamicCategory category(
TRACE_EVENT_API_GET_CATEGORY_GROUP_NAME(category_group_enabled));
auto phase = TRACE_EVENT_PHASE_END;
base::TimeTicks timestamp =
explicit_timestamps ? now : TRACE_TIME_TICKS_NOW();
if (thread_id != kInvalidThreadId &&
thread_id != base::PlatformThread::CurrentId()) {
PERFETTO_INTERNAL_LEGACY_EVENT_ON_TRACK(
phase, category, name,
perfetto::ThreadTrack::ForThread(thread_id.raw()), timestamp);
return;
}
PERFETTO_INTERNAL_LEGACY_EVENT_ON_TRACK(
phase, category, name,
perfetto::internal::TrackEventInternal::kDefaultTrack, timestamp);
}
base::trace_event::TraceEventHandle AddTraceEventWithThreadIdAndTimestamps(
char phase,
const unsigned char* category_group_enabled,
const char* name,
uint64_t id,
base::PlatformThreadId thread_id,
const base::TimeTicks& timestamp,
base::trace_event::TraceArguments* args,
unsigned int flags) {
base::trace_event::TraceEventHandle handle = {};
if (!*category_group_enabled) {
return handle;
}
DCHECK(!timestamp.is_null());
base::trace_event::TraceEvent new_trace_event(thread_id, timestamp, phase,
category_group_enabled, name,
id, args, flags);
base::trace_event::OnAddLegacyTraceEvent(&new_trace_event);
return handle;
}
}
#if BUILDFLAG(USE_PERFETTO_TRACE_PROCESSOR)
namespace {
static constexpr char kJsonPrefix[] = "{\"traceEvents\":[\n";
static constexpr char kJsonJoiner[] = ",\n";
static constexpr char kJsonSuffix[] = "],\"metadata\":";
}
class JsonStringOutputWriter
: public perfetto::trace_processor::json::OutputWriter {
public:
JsonStringOutputWriter(scoped_refptr<SequencedTaskRunner> flush_task_runner,
TraceLog::OutputCallback flush_callback)
: flush_task_runner_(flush_task_runner),
flush_callback_(std::move(flush_callback)) {
buffer_->as_string().reserve(kBufferReserveCapacity);
}
~JsonStringOutputWriter() override { Flush(false); }
perfetto::trace_processor::util::Status AppendString(
const std::string& string) override {
if (!did_strip_prefix_) {
DCHECK_EQ(string, kJsonPrefix);
did_strip_prefix_ = true;
return perfetto::trace_processor::util::OkStatus();
} else if (buffer_->as_string().empty() &&
!strncmp(string.c_str(), kJsonJoiner, strlen(kJsonJoiner))) {
buffer_->as_string() += string.substr(strlen(kJsonJoiner));
} else if (!strncmp(string.c_str(), kJsonSuffix, strlen(kJsonSuffix))) {
return perfetto::trace_processor::util::OkStatus();
} else {
buffer_->as_string() += string;
}
if (buffer_->as_string().size() > kBufferLimitInBytes) {
Flush(true);
buffer_ = new RefCountedString();
buffer_->as_string().reserve(kBufferReserveCapacity);
}
return perfetto::trace_processor::util::OkStatus();
}
private:
void Flush(bool has_more) {
if (flush_task_runner_) {
flush_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(flush_callback_, std::move(buffer_), has_more));
} else {
flush_callback_.Run(std::move(buffer_), has_more);
}
}
static constexpr size_t kBufferLimitInBytes = 100 * 1024;
static constexpr size_t kBufferReserveCapacity = kBufferLimitInBytes * 5 / 4;
scoped_refptr<SequencedTaskRunner> flush_task_runner_;
TraceLog::OutputCallback flush_callback_;
scoped_refptr<RefCountedString> buffer_ = new RefCountedString();
bool did_strip_prefix_ = false;
};
#endif
struct TraceLog::RegisteredAsyncObserver {
explicit RegisteredAsyncObserver(WeakPtr<AsyncEnabledStateObserver> observer)
: observer(observer),
task_runner(SequencedTaskRunner::GetCurrentDefault()) {}
~RegisteredAsyncObserver() = default;
WeakPtr<AsyncEnabledStateObserver> observer;
scoped_refptr<SequencedTaskRunner> task_runner;
};
TraceLog* TraceLog::GetInstance() {
static base::NoDestructor<TraceLog> instance{};
return instance.get();
}
void TraceLog::ResetForTesting() {
auto* self = GetInstance();
AutoLock lock(self->observers_lock_);
self->tracing_session_.reset();
self->enabled_state_observers_.clear();
self->owned_enabled_state_observer_copy_.clear();
self->async_observers_.clear();
}
TraceLog::TraceLog() : process_id_(base::kNullProcessId) {
#if BUILDFLAG(ARKWEB_USE_UNIQUE_RENDERER_PROCESS_ID)
SetProcessID(GetCurrentRealPid());
#else
SetProcessID(GetCurrentProcId());
#endif
TrackEvent::AddSessionObserver(this);
g_trace_log_for_testing = this;
}
TraceLog::~TraceLog() {
TrackEvent::RemoveSessionObserver(this);
}
void TraceLog::SetEnabled(const TraceConfig& trace_config) {
DCHECK(trace_config.process_filter_config().IsEnabled(process_id_));
AutoLock lock(lock_);
for (const auto& excluded :
trace_config.category_filter().excluded_categories()) {
DCHECK(excluded.find("?") == std::string::npos);
DCHECK(excluded.find("*") == std::string::npos ||
excluded.find("*") == excluded.size() - 1);
}
for (const auto& included :
trace_config.category_filter().included_categories()) {
DCHECK(included.find("?") == std::string::npos);
DCHECK(included.find("*") == std::string::npos ||
included.find("*") == included.size() - 1);
}
for (const auto& disabled :
trace_config.category_filter().disabled_categories()) {
DCHECK(disabled.find("?") == std::string::npos);
DCHECK(disabled.find("*") == std::string::npos ||
disabled.find("*") == disabled.size() - 1);
}
DCHECK(!trace_config.IsArgumentFilterEnabled());
perfetto::TraceConfig perfetto_config;
ByteCount size_limit = trace_config.GetTraceBufferSizeInBytes();
if (size_limit.is_zero()) {
size_limit = MiB(200);
}
auto* buffer_config = perfetto_config.add_buffers();
buffer_config->set_size_kb(checked_cast<uint32_t>(size_limit.InKiB()));
switch (trace_config.GetTraceRecordMode()) {
case base::trace_event::RECORD_UNTIL_FULL:
case base::trace_event::RECORD_AS_MUCH_AS_POSSIBLE:
buffer_config->set_fill_policy(
perfetto::TraceConfig::BufferConfig::DISCARD);
break;
case base::trace_event::RECORD_CONTINUOUSLY:
buffer_config->set_fill_policy(
perfetto::TraceConfig::BufferConfig::RING_BUFFER);
break;
case base::trace_event::ECHO_TO_CONSOLE:
break;
}
auto* data_source = perfetto_config.add_data_sources();
auto* source_config = data_source->mutable_config();
source_config->set_name("track_event");
source_config->set_target_buffer(0);
auto* source_chrome_config = source_config->mutable_chrome_config();
source_chrome_config->set_trace_config(trace_config.ToString());
source_chrome_config->set_convert_to_legacy_json(true);
if (trace_config.GetTraceRecordMode() == base::trace_event::ECHO_TO_CONSOLE) {
perfetto::ConsoleInterceptor::Register();
source_config->mutable_interceptor_config()->set_name("console");
}
source_config->set_track_event_config_raw(
trace_config.ToPerfettoTrackEventConfigRaw(
false));
if (trace_config.IsCategoryGroupEnabled("disabled-by-default-memory-infra")) {
data_source = perfetto_config.add_data_sources();
source_config = data_source->mutable_config();
source_config->set_name("org.chromium.memory_instrumentation");
source_config->set_target_buffer(0);
source_chrome_config = source_config->mutable_chrome_config();
source_chrome_config->set_trace_config(trace_config.ToString());
source_chrome_config->set_convert_to_legacy_json(true);
}
perfetto_config.mutable_incremental_state_config()->set_clear_period_ms(500);
SetEnabledImpl(trace_config, perfetto_config);
}
std::vector<TraceLog::TrackEventSession> TraceLog::GetTrackEventSessions()
const {
AutoLock lock(track_event_lock_);
return track_event_sessions_;
}
void TraceLog::SetEnabled(const TraceConfig& trace_config,
const perfetto::TraceConfig& perfetto_config) {
AutoLock lock(lock_);
SetEnabledImpl(trace_config, perfetto_config);
}
void TraceLog::SetEnabledImpl(const TraceConfig& trace_config,
const perfetto::TraceConfig& perfetto_config) {
DCHECK(!TrackEvent::IsEnabled());
CHECK(perfetto::Tracing::IsInitialized());
CHECK(IsPerfettoInitializedForTesting())
<< "Don't use TraceLog for recording traces from non-test code. Use "
"perfetto::Tracing::NewTrace() instead.";
lock_.AssertAcquired();
perfetto_config_ = perfetto_config;
tracing_session_ = perfetto::Tracing::NewTrace();
AutoUnlock unlock(lock_);
tracing_session_->Setup(perfetto_config);
tracing_session_->StartBlocking();
}
void TraceLog::SetArgumentFilterPredicate(
const ArgumentFilterPredicate& argument_filter_predicate) {
AutoLock lock(lock_);
DCHECK(!argument_filter_predicate.is_null());
argument_filter_predicate_ = argument_filter_predicate;
}
ArgumentFilterPredicate TraceLog::GetArgumentFilterPredicate() const {
AutoLock lock(lock_);
return argument_filter_predicate_;
}
void TraceLog::SetMetadataFilterPredicate(
const MetadataFilterPredicate& metadata_filter_predicate) {
AutoLock lock(lock_);
DCHECK(!metadata_filter_predicate.is_null());
metadata_filter_predicate_ = metadata_filter_predicate;
}
MetadataFilterPredicate TraceLog::GetMetadataFilterPredicate() const {
AutoLock lock(lock_);
return metadata_filter_predicate_;
}
void TraceLog::SetDisabled() {
AutoLock lock(lock_);
SetDisabledWhileLocked();
}
void TraceLog::SetDisabledWhileLocked() {
if (!tracing_session_) {
return;
}
TrackEvent::Flush();
if (SingleThreadTaskRunner::HasCurrentDefault()) {
RunLoop stop_loop(RunLoop::Type::kNestableTasksAllowed);
auto quit_closure = stop_loop.QuitClosure();
tracing_session_->SetOnStopCallback(
[&quit_closure] { quit_closure.Run(); });
tracing_session_->Stop();
AutoUnlock unlock(lock_);
stop_loop.Run();
} else {
tracing_session_->StopBlocking();
}
}
void TraceLog::AddEnabledStateObserver(EnabledStateObserver* listener) {
AutoLock lock(observers_lock_);
enabled_state_observers_.push_back(listener);
}
void TraceLog::RemoveEnabledStateObserver(EnabledStateObserver* listener) {
AutoLock lock(observers_lock_);
auto removed = std::ranges::remove(enabled_state_observers_, listener);
enabled_state_observers_.erase(removed.begin(), removed.end());
}
void TraceLog::AddOwnedEnabledStateObserver(
std::unique_ptr<EnabledStateObserver> listener) {
AutoLock lock(observers_lock_);
enabled_state_observers_.push_back(listener.get());
owned_enabled_state_observer_copy_.push_back(std::move(listener));
}
bool TraceLog::HasEnabledStateObserver(EnabledStateObserver* listener) const {
AutoLock lock(observers_lock_);
return Contains(enabled_state_observers_, listener);
}
void TraceLog::AddAsyncEnabledStateObserver(
WeakPtr<AsyncEnabledStateObserver> listener) {
AutoLock lock(observers_lock_);
async_observers_.emplace(listener.get(), RegisteredAsyncObserver(listener));
}
void TraceLog::RemoveAsyncEnabledStateObserver(
AsyncEnabledStateObserver* listener) {
AutoLock lock(observers_lock_);
async_observers_.erase(listener);
}
bool TraceLog::HasAsyncEnabledStateObserver(
AsyncEnabledStateObserver* listener) const {
AutoLock lock(observers_lock_);
return Contains(async_observers_, listener);
}
void TraceLog::Flush(const TraceLog::OutputCallback& cb,
bool use_worker_thread) {
FlushInternal(cb, use_worker_thread, false);
}
void TraceLog::CancelTracing(const OutputCallback& cb) {
SetDisabled();
FlushInternal(cb, false, true);
}
void TraceLog::FlushInternal(const TraceLog::OutputCallback& cb,
bool use_worker_thread,
bool discard_events) {
#if BUILDFLAG(USE_PERFETTO_TRACE_PROCESSOR)
TrackEvent::Flush();
if (!tracing_session_ || discard_events) {
tracing_session_.reset();
scoped_refptr<RefCountedString> empty_result = new RefCountedString;
cb.Run(empty_result, false);
return;
}
bool convert_to_json = true;
for (const auto& data_source : perfetto_config_.data_sources()) {
if (data_source.config().has_chrome_config() &&
data_source.config().chrome_config().has_convert_to_legacy_json()) {
convert_to_json =
data_source.config().chrome_config().convert_to_legacy_json();
break;
}
}
if (convert_to_json) {
perfetto::trace_processor::Config processor_config;
trace_processor_ =
perfetto::trace_processor::TraceProcessorStorage::CreateInstance(
processor_config);
json_output_writer_ = std::make_unique<JsonStringOutputWriter>(
use_worker_thread ? SingleThreadTaskRunner::GetCurrentDefault()
: nullptr,
cb);
} else {
proto_output_callback_ = std::move(cb);
}
if (use_worker_thread) {
tracing_session_->ReadTrace(
[this](perfetto::TracingSession::ReadTraceCallbackArgs args) {
OnTraceData(args.data, args.size, args.has_more);
});
} else {
auto data = tracing_session_->ReadTraceBlocking();
OnTraceData(data.data(), data.size(), false);
}
#else
NOTREACHED() << "JSON tracing isn't supported";
#endif
}
#if BUILDFLAG(USE_PERFETTO_TRACE_PROCESSOR)
void TraceLog::OnTraceData(const char* data, size_t size, bool has_more) {
if (proto_output_callback_) {
scoped_refptr<RefCountedString> chunk = new RefCountedString();
if (size) {
chunk->as_string().assign(data, size);
}
proto_output_callback_.Run(std::move(chunk), has_more);
if (!has_more) {
proto_output_callback_.Reset();
tracing_session_.reset();
}
return;
}
if (size) {
auto data_copy = std::make_unique<uint8_t[]>(size);
memcpy(&data_copy[0], data, size);
auto status = trace_processor_->Parse(std::move(data_copy), size);
DCHECK(status.ok()) << status.message();
}
if (has_more) {
return;
}
auto status = trace_processor_->NotifyEndOfFile();
DCHECK(status.ok()) << status.message();
status = perfetto::trace_processor::json::ExportJson(
trace_processor_.get(), json_output_writer_.get());
DCHECK(status.ok()) << status.message();
trace_processor_.reset();
tracing_session_.reset();
json_output_writer_.reset();
}
#endif
void TraceLog::SetProcessID(ProcessId process_id) {
process_id_ = process_id;
}
size_t TraceLog::GetObserverCountForTest() const {
AutoLock lock(observers_lock_);
return enabled_state_observers_.size();
}
void TraceLog::OnSetup(const perfetto::DataSourceBase::SetupArgs& args) {
AutoLock lock(track_event_lock_);
track_event_sessions_.emplace_back(args.internal_instance_index, *args.config,
args.backend_type);
}
void TraceLog::OnStart(const perfetto::DataSourceBase::StartArgs&) {
{
AutoLock lock(track_event_lock_);
++active_track_event_sessions_;
if (active_track_event_sessions_ > 1) {
return;
}
}
AutoLock lock(observers_lock_);
for (EnabledStateObserver* observer : enabled_state_observers_) {
observer->OnTraceLogEnabled();
}
for (const auto& it : async_observers_) {
it.second.task_runner->PostTask(
FROM_HERE, BindOnce(&AsyncEnabledStateObserver::OnTraceLogEnabled,
it.second.observer));
}
}
void TraceLog::OnStop(const perfetto::DataSourceBase::StopArgs& args) {
{
AutoLock track_event_lock(track_event_lock_);
std::erase_if(track_event_sessions_, [&args](
const TrackEventSession& session) {
return session.internal_instance_index == args.internal_instance_index;
});
}
{
AutoLock lock(track_event_lock_);
--active_track_event_sessions_;
if (active_track_event_sessions_ > 0) {
return;
}
}
AutoLock lock(observers_lock_);
for (base::trace_event::TraceLog::EnabledStateObserver* it :
enabled_state_observers_) {
it->OnTraceLogDisabled();
}
for (const auto& it : async_observers_) {
it.second.task_runner->PostTask(
FROM_HERE, BindOnce(&AsyncEnabledStateObserver::OnTraceLogDisabled,
it.second.observer));
}
}
}
namespace trace_event_internal {
base::trace_event::TraceEventHandle AddTraceEvent(
char phase,
const unsigned char* category_group_enabled,
const char* name,
uint64_t id,
base::trace_event::TraceArguments* args,
unsigned int flags) {
auto thread_id = base::PlatformThread::CurrentId();
base::TimeTicks now = TRACE_TIME_TICKS_NOW();
return AddTraceEventWithThreadIdAndTimestamp(
phase, category_group_enabled, name, id, thread_id, now, args, flags);
}
base::trace_event::TraceEventHandle AddTraceEventWithProcessId(
char phase,
const unsigned char* category_group_enabled,
const char* name,
uint64_t id,
base::ProcessId process_id,
base::trace_event::TraceArguments* args,
unsigned int flags) {
static_assert(sizeof(base::PlatformThreadId::UnderlyingType) >=
sizeof(base::ProcessId));
base::TimeTicks now = TRACE_TIME_TICKS_NOW();
return AddTraceEventWithThreadIdAndTimestamp(
phase, category_group_enabled, name, id,
base::PlatformThreadId(
static_cast<base::PlatformThreadId::UnderlyingType>(process_id)),
now, args, flags | TRACE_EVENT_FLAG_HAS_PROCESS_ID);
}
base::trace_event::TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
char phase,
const unsigned char* category_group_enabled,
const char* name,
uint64_t id,
base::PlatformThreadId thread_id,
const base::TimeTicks& timestamp,
base::trace_event::TraceArguments* args,
unsigned int flags) {
return base::trace_event::AddTraceEventWithThreadIdAndTimestamps(
phase, category_group_enabled, name, id, thread_id, timestamp, args,
flags);
}
base::trace_event::TraceEventHandle AddTraceEventWithThreadIdAndTimestamps(
char phase,
const unsigned char* category_group_enabled,
const char* name,
uint64_t id,
base::PlatformThreadId thread_id,
const base::TimeTicks& timestamp,
unsigned int flags) {
return base::trace_event::AddTraceEventWithThreadIdAndTimestamps(
phase, category_group_enabled, name, id, thread_id, timestamp, nullptr,
flags);
}
void UpdateTraceEventDuration(const unsigned char* category_group_enabled,
const char* name,
base::trace_event::TraceEventHandle handle) {
if (!*category_group_enabled) {
return;
}
base::trace_event::OnUpdateLegacyTraceEventDuration(
category_group_enabled, name, base::PlatformThread::CurrentId(),
false,
base::subtle::TimeTicksNowIgnoringOverride(),
base::trace_event::ThreadNow());
}
}