1 // Copyright 2012 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 "net/log/net_log.h"
6
7 #include "base/check_op.h"
8 #include "base/containers/contains.h"
9 #include "base/no_destructor.h"
10 #include "base/not_fatal_until.h"
11 #include "base/notreached.h"
12 #include "base/ranges/algorithm.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/values.h"
15 #include "net/log/net_log_values.h"
16
17 namespace net {
18
19 NetLog::ThreadSafeObserver::ThreadSafeObserver() = default;
20
~ThreadSafeObserver()21 NetLog::ThreadSafeObserver::~ThreadSafeObserver() {
22 // Make sure we aren't watching a NetLog on destruction. Because the NetLog
23 // may pass events to each observer on multiple threads, we cannot safely
24 // stop watching a NetLog automatically from a parent class.
25 DCHECK(!net_log_);
26 }
27
capture_mode() const28 NetLogCaptureMode NetLog::ThreadSafeObserver::capture_mode() const {
29 DCHECK(net_log_);
30 return capture_mode_;
31 }
32
net_log() const33 NetLog* NetLog::ThreadSafeObserver::net_log() const {
34 return net_log_;
35 }
36
37 NetLog::ThreadSafeCaptureModeObserver::ThreadSafeCaptureModeObserver() =
38 default;
39 NetLog::ThreadSafeCaptureModeObserver::~ThreadSafeCaptureModeObserver() =
40 default;
41
42 NetLogCaptureModeSet
GetObserverCaptureModes() const43 NetLog::ThreadSafeCaptureModeObserver::GetObserverCaptureModes() const {
44 DCHECK(net_log_);
45 return net_log_->GetObserverCaptureModes();
46 }
47
48 void NetLog::ThreadSafeCaptureModeObserver::
AddEntryAtTimeWithMaterializedParams(NetLogEventType type,const NetLogSource & source,NetLogEventPhase phase,base::TimeTicks time,base::Value::Dict params)49 AddEntryAtTimeWithMaterializedParams(NetLogEventType type,
50 const NetLogSource& source,
51 NetLogEventPhase phase,
52 base::TimeTicks time,
53 base::Value::Dict params) {
54 DCHECK(net_log_);
55 net_log_->AddEntryAtTimeWithMaterializedParams(type, source, phase, time,
56 std::move(params));
57 }
58
59 // static
Get()60 NetLog* NetLog::Get() {
61 static base::NoDestructor<NetLog> instance{base::PassKey<NetLog>()};
62 return instance.get();
63 }
64
NetLog(base::PassKey<NetLog>)65 NetLog::NetLog(base::PassKey<NetLog>) {}
NetLog(base::PassKey<NetLogWithSource>)66 NetLog::NetLog(base::PassKey<NetLogWithSource>) {}
67
AddEntry(NetLogEventType type,const NetLogSource & source,NetLogEventPhase phase)68 void NetLog::AddEntry(NetLogEventType type,
69 const NetLogSource& source,
70 NetLogEventPhase phase) {
71 AddEntry(type, source, phase, [] { return base::Value::Dict(); });
72 }
73
AddGlobalEntry(NetLogEventType type)74 void NetLog::AddGlobalEntry(NetLogEventType type) {
75 AddEntry(type, NetLogSource(NetLogSourceType::NONE, NextID()),
76 NetLogEventPhase::NONE);
77 }
78
AddGlobalEntryWithStringParams(NetLogEventType type,std::string_view name,std::string_view value)79 void NetLog::AddGlobalEntryWithStringParams(NetLogEventType type,
80 std::string_view name,
81 std::string_view value) {
82 AddGlobalEntry(type, [&] { return NetLogParamsWithString(name, value); });
83 }
84
NextID()85 uint32_t NetLog::NextID() {
86 return base::subtle::NoBarrier_AtomicIncrement(&last_id_, 1);
87 }
88
AddObserver(NetLog::ThreadSafeObserver * observer,NetLogCaptureMode capture_mode)89 void NetLog::AddObserver(NetLog::ThreadSafeObserver* observer,
90 NetLogCaptureMode capture_mode) {
91 base::AutoLock lock(lock_);
92
93 DCHECK(!observer->net_log_);
94 DCHECK(!HasObserver(observer));
95 DCHECK_LT(observers_.size(), 20u); // Performance sanity check.
96
97 observers_.push_back(observer);
98
99 observer->net_log_ = this;
100 observer->capture_mode_ = capture_mode;
101 UpdateObserverCaptureModes();
102 }
103
RemoveObserver(NetLog::ThreadSafeObserver * observer)104 void NetLog::RemoveObserver(NetLog::ThreadSafeObserver* observer) {
105 base::AutoLock lock(lock_);
106
107 DCHECK_EQ(this, observer->net_log_);
108
109 auto it = base::ranges::find(observers_, observer);
110 CHECK(it != observers_.end(), base::NotFatalUntil::M130);
111 observers_.erase(it);
112
113 observer->net_log_ = nullptr;
114 observer->capture_mode_ = NetLogCaptureMode::kDefault;
115 UpdateObserverCaptureModes();
116 }
117
AddCaptureModeObserver(NetLog::ThreadSafeCaptureModeObserver * observer)118 void NetLog::AddCaptureModeObserver(
119 NetLog::ThreadSafeCaptureModeObserver* observer) {
120 base::AutoLock lock(lock_);
121
122 DCHECK(!observer->net_log_);
123 DCHECK(!HasCaptureModeObserver(observer));
124 DCHECK_LT(capture_mode_observers_.size(), 20u); // Performance sanity check.
125
126 observer->net_log_ = this;
127 capture_mode_observers_.push_back(observer);
128 }
129
RemoveCaptureModeObserver(NetLog::ThreadSafeCaptureModeObserver * observer)130 void NetLog::RemoveCaptureModeObserver(
131 NetLog::ThreadSafeCaptureModeObserver* observer) {
132 base::AutoLock lock(lock_);
133
134 DCHECK_EQ(this, observer->net_log_);
135 DCHECK(HasCaptureModeObserver(observer));
136
137 auto it = base::ranges::find(capture_mode_observers_, observer);
138 CHECK(it != capture_mode_observers_.end(), base::NotFatalUntil::M130);
139 capture_mode_observers_.erase(it);
140
141 observer->net_log_ = nullptr;
142 }
143
UpdateObserverCaptureModes()144 void NetLog::UpdateObserverCaptureModes() {
145 lock_.AssertAcquired();
146
147 NetLogCaptureModeSet capture_mode_set = 0;
148 for (const net::NetLog::ThreadSafeObserver* observer : observers_) {
149 NetLogCaptureModeSetAdd(observer->capture_mode_, &capture_mode_set);
150 }
151
152 base::subtle::NoBarrier_Store(&observer_capture_modes_, capture_mode_set);
153
154 // Notify any capture mode observers with the new |capture_mode_set|.
155 for (net::NetLog::ThreadSafeCaptureModeObserver* capture_mode_observer :
156 capture_mode_observers_) {
157 capture_mode_observer->OnCaptureModeUpdated(capture_mode_set);
158 }
159 }
160
HasObserver(ThreadSafeObserver * observer)161 bool NetLog::HasObserver(ThreadSafeObserver* observer) {
162 lock_.AssertAcquired();
163 return base::Contains(observers_, observer);
164 }
165
HasCaptureModeObserver(ThreadSafeCaptureModeObserver * observer)166 bool NetLog::HasCaptureModeObserver(ThreadSafeCaptureModeObserver* observer) {
167 lock_.AssertAcquired();
168 return base::Contains(capture_mode_observers_, observer);
169 }
170
171 // static
TickCountToString(const base::TimeTicks & time)172 std::string NetLog::TickCountToString(const base::TimeTicks& time) {
173 int64_t delta_time = time.since_origin().InMilliseconds();
174 // TODO(crbug.com/40606676): Use NetLogNumberValue().
175 return base::NumberToString(delta_time);
176 }
177
178 // static
TimeToString(const base::Time & time)179 std::string NetLog::TimeToString(const base::Time& time) {
180 // Convert the base::Time to its (approximate) equivalent in base::TimeTicks.
181 base::TimeTicks time_ticks =
182 base::TimeTicks::UnixEpoch() + (time - base::Time::UnixEpoch());
183 return TickCountToString(time_ticks);
184 }
185
186 // static
GetEventTypesAsValue()187 base::Value NetLog::GetEventTypesAsValue() {
188 base::Value::Dict dict;
189 for (int i = 0; i < static_cast<int>(NetLogEventType::COUNT); ++i) {
190 dict.Set(NetLogEventTypeToString(static_cast<NetLogEventType>(i)), i);
191 }
192 return base::Value(std::move(dict));
193 }
194
195 // static
SourceTypeToString(NetLogSourceType source)196 const char* NetLog::SourceTypeToString(NetLogSourceType source) {
197 switch (source) {
198 #define SOURCE_TYPE(label) \
199 case NetLogSourceType::label: \
200 return #label;
201 #include "net/log/net_log_source_type_list.h"
202 #undef SOURCE_TYPE
203 default:
204 NOTREACHED();
205 }
206 }
207
208 // static
GetSourceTypesAsValue()209 base::Value NetLog::GetSourceTypesAsValue() {
210 base::Value::Dict dict;
211 for (int i = 0; i < static_cast<int>(NetLogSourceType::COUNT); ++i) {
212 dict.Set(SourceTypeToString(static_cast<NetLogSourceType>(i)), i);
213 }
214 return base::Value(std::move(dict));
215 }
216
217 // static
EventPhaseToString(NetLogEventPhase phase)218 const char* NetLog::EventPhaseToString(NetLogEventPhase phase) {
219 switch (phase) {
220 case NetLogEventPhase::BEGIN:
221 return "PHASE_BEGIN";
222 case NetLogEventPhase::END:
223 return "PHASE_END";
224 case NetLogEventPhase::NONE:
225 return "PHASE_NONE";
226 }
227 NOTREACHED();
228 }
229
InitializeSourceIdPartition()230 void NetLog::InitializeSourceIdPartition() {
231 int32_t old_value = base::subtle::NoBarrier_AtomicExchange(
232 &last_id_, std::numeric_limits<base::subtle::Atomic32>::min());
233 DCHECK_EQ(old_value, 0) << " NetLog::InitializeSourceIdPartition() called "
234 "after NextID() or called multiple times";
235 }
236
AddEntryInternal(NetLogEventType type,const NetLogSource & source,NetLogEventPhase phase,const GetParamsInterface * get_params)237 void NetLog::AddEntryInternal(NetLogEventType type,
238 const NetLogSource& source,
239 NetLogEventPhase phase,
240 const GetParamsInterface* get_params) {
241 NetLogCaptureModeSet observer_capture_modes = GetObserverCaptureModes();
242
243 for (int i = 0; i <= static_cast<int>(NetLogCaptureMode::kLast); ++i) {
244 NetLogCaptureMode capture_mode = static_cast<NetLogCaptureMode>(i);
245 if (!NetLogCaptureModeSetContains(capture_mode, observer_capture_modes))
246 continue;
247
248 NetLogEntry entry(type, source, phase, base::TimeTicks::Now(),
249 get_params->GetParams(capture_mode));
250
251 // Notify all of the log observers with |capture_mode|.
252 base::AutoLock lock(lock_);
253 for (net::NetLog::ThreadSafeObserver* observer : observers_) {
254 if (observer->capture_mode() == capture_mode)
255 observer->OnAddEntry(entry);
256 }
257 }
258 }
259
AddEntryWithMaterializedParams(NetLogEventType type,const NetLogSource & source,NetLogEventPhase phase,base::Value::Dict params)260 void NetLog::AddEntryWithMaterializedParams(NetLogEventType type,
261 const NetLogSource& source,
262 NetLogEventPhase phase,
263 base::Value::Dict params) {
264 AddEntryAtTimeWithMaterializedParams(
265 type, source, phase, base::TimeTicks::Now(), std::move(params));
266 }
267
AddEntryAtTimeWithMaterializedParams(NetLogEventType type,const NetLogSource & source,NetLogEventPhase phase,base::TimeTicks time,base::Value::Dict params)268 void NetLog::AddEntryAtTimeWithMaterializedParams(NetLogEventType type,
269 const NetLogSource& source,
270 NetLogEventPhase phase,
271 base::TimeTicks time,
272 base::Value::Dict params) {
273 NetLogEntry entry(type, source, phase, time, std::move(params));
274
275 // Notify all of the log observers, regardless of capture mode.
276 base::AutoLock lock(lock_);
277 for (net::NetLog::ThreadSafeObserver* observer : observers_) {
278 observer->OnAddEntry(entry);
279 }
280 }
281
282 } // namespace net
283