1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/metrics/user_metrics.h"
6
7 #include <stddef.h>
8
9 #include <vector>
10
11 #include "base/functional/bind.h"
12 #include "base/lazy_instance.h"
13 #include "base/location.h"
14 #include "base/ranges/algorithm.h"
15 #include "base/threading/thread_checker.h"
16 #include "base/time/time.h"
17 #include "base/trace_event/base_tracing.h"
18
19 namespace base {
20 namespace {
21
22 LazyInstance<std::vector<ActionCallback>>::DestructorAtExit g_callbacks =
23 LAZY_INSTANCE_INITIALIZER;
24 LazyInstance<scoped_refptr<SingleThreadTaskRunner>>::DestructorAtExit
25 g_task_runner = LAZY_INSTANCE_INITIALIZER;
26
27 } // namespace
28
RecordAction(const UserMetricsAction & action)29 void RecordAction(const UserMetricsAction& action) {
30 RecordComputedAction(action.str_);
31 }
32
RecordComputedAction(const std::string & action)33 void RecordComputedAction(const std::string& action) {
34 RecordComputedActionAt(action, TimeTicks::Now());
35 }
36
RecordComputedActionSince(const std::string & action,TimeDelta time_since)37 void RecordComputedActionSince(const std::string& action,
38 TimeDelta time_since) {
39 RecordComputedActionAt(action, TimeTicks::Now() - time_since);
40 }
41
RecordComputedActionAt(const std::string & action,TimeTicks action_time)42 void RecordComputedActionAt(const std::string& action, TimeTicks action_time) {
43 TRACE_EVENT_INSTANT1("ui", "UserEvent", TRACE_EVENT_SCOPE_GLOBAL, "action",
44 action);
45 if (!g_task_runner.Get()) {
46 DCHECK(g_callbacks.Get().empty());
47 return;
48 }
49
50 if (!g_task_runner.Get()->BelongsToCurrentThread()) {
51 g_task_runner.Get()->PostTask(
52 FROM_HERE, BindOnce(&RecordComputedActionAt, action, action_time));
53 return;
54 }
55
56 for (const ActionCallback& callback : g_callbacks.Get()) {
57 callback.Run(action, action_time);
58 }
59 }
60
AddActionCallback(const ActionCallback & callback)61 void AddActionCallback(const ActionCallback& callback) {
62 // Only allow adding a callback if the task runner is set.
63 DCHECK(g_task_runner.Get());
64 DCHECK(g_task_runner.Get()->BelongsToCurrentThread());
65 g_callbacks.Get().push_back(callback);
66 }
67
RemoveActionCallback(const ActionCallback & callback)68 void RemoveActionCallback(const ActionCallback& callback) {
69 DCHECK(g_task_runner.Get());
70 DCHECK(g_task_runner.Get()->BelongsToCurrentThread());
71 std::vector<ActionCallback>* callbacks = g_callbacks.Pointer();
72 const auto i = ranges::find(*callbacks, callback);
73 if (i != callbacks->end())
74 callbacks->erase(i);
75 }
76
SetRecordActionTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner)77 void SetRecordActionTaskRunner(
78 scoped_refptr<SingleThreadTaskRunner> task_runner) {
79 DCHECK(task_runner->BelongsToCurrentThread());
80 DCHECK(!g_task_runner.Get() || g_task_runner.Get()->BelongsToCurrentThread());
81 g_task_runner.Get() = task_runner;
82 }
83
GetRecordActionTaskRunner()84 scoped_refptr<SingleThreadTaskRunner> GetRecordActionTaskRunner() {
85 if (g_task_runner.IsCreated())
86 return g_task_runner.Get();
87 return nullptr;
88 }
89
90 } // namespace base
91