blob: 9776b7cd3050d19d54e5c5566a3748d939dbbd16 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/metrics/structured/recorder.h"
#include <utility>
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/no_destructor.h"
#include "base/task/current_thread.h"
#include "components/metrics/structured/event_base.h"
#include "components/metrics/structured/histogram_util.h"
#include "components/metrics/structured/structured_metrics_features.h"
namespace metrics {
namespace structured {
Recorder::Recorder() = default;
Recorder::~Recorder() = default;
Recorder* Recorder::GetInstance() {
static base::NoDestructor<Recorder> recorder;
return recorder.get();
}
void Recorder::RecordEvent(Event&& event) {
auto event_base = EventBase::FromEvent(std::move(event));
if (event_base.has_value())
Record(std::move(event_base.value()));
}
void Recorder::Record(EventBase&& event) {
// All calls to StructuredMetricsProvider (the observer) must be on the UI
// sequence, so re-call Record if needed. If a UI task runner hasn't been set
// yet, ignore this Record.
if (!ui_task_runner_) {
LogInternalError(StructuredMetricsError::kUninitializedClient);
return;
}
if (!ui_task_runner_->RunsTasksInCurrentSequence()) {
ui_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&Recorder::Record, base::Unretained(this), event));
return;
}
// If the feature is disabled, it means that the event was recorded directly
// and not through the mojo API.
if (!base::FeatureList::IsEnabled(kUseCrosApiInterface)) {
LogIsEventRecordedUsingMojo(false);
}
DCHECK(base::CurrentUIThread::IsSet());
for (auto& observer : observers_)
observer.OnRecord(event);
if (observers_.empty()) {
// Other values of EventRecordingState are recorded in
// StructuredMetricsProvider::OnRecord.
LogEventRecordingState(EventRecordingState::kProviderMissing);
}
}
bool Recorder::IsReadyToRecord() const {
// No initialization needed. Always ready to record.
return true;
}
void Recorder::ProfileAdded(const base::FilePath& profile_path) {
// All calls to the StructuredMetricsProvider (the observer) must be on the UI
// sequence.
DCHECK(base::CurrentUIThread::IsSet());
// TODO(crbug.com/1016655 ): investigate whether we can verify that
// |profile_path| corresponds to a valid (non-guest, non-signin) profile.
for (auto& observer : observers_)
observer.OnProfileAdded(profile_path);
}
absl::optional<int> Recorder::LastKeyRotation(uint64_t project_name_hash) {
absl::optional<int> result;
// |observers_| will contain at most one observer, despite being an
// ObserverList.
for (auto& observer : observers_) {
result = observer.LastKeyRotation(project_name_hash);
}
return result;
}
void Recorder::OnReportingStateChanged(bool enabled) {
for (auto& observer : observers_) {
observer.OnReportingStateChanged(enabled);
}
}
void Recorder::OnHardwareClassInitialized() {
for (auto& observer : observers_) {
observer.OnHardwareClassInitialized();
}
}
void Recorder::SetUiTaskRunner(
const scoped_refptr<base::SequencedTaskRunner> ui_task_runner) {
ui_task_runner_ = ui_task_runner;
}
void Recorder::AddObserver(RecorderImpl* observer) {
observers_.AddObserver(observer);
}
void Recorder::RemoveObserver(RecorderImpl* observer) {
observers_.RemoveObserver(observer);
}
} // namespace structured
} // namespace metrics