1 // Copyright 2013 The Chromium Authors. All rights reserved.
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 "chrome/browser/media/webrtc/webrtc_logging_controller.h"
6
7 #include <string>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/files/file_util.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram_functions.h"
15 #include "base/supports_user_data.h"
16 #include "base/task/post_task.h"
17 #include "base/task_runner_util.h"
18 #include "base/threading/sequenced_task_runner_handle.h"
19 #include "chrome/browser/media/webrtc/webrtc_event_log_manager.h"
20 #include "chrome/browser/media/webrtc/webrtc_log_uploader.h"
21 #include "chrome/browser/media/webrtc/webrtc_rtp_dump_handler.h"
22 #include "components/webrtc_logging/browser/text_log_list.h"
23 #include "content/public/browser/browser_context.h"
24 #include "content/public/browser/render_process_host.h"
25
26 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD)
27 #include "content/public/browser/child_process_security_policy.h"
28 #include "storage/browser/file_system/isolated_context.h"
29 #endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD)
30
31 using webrtc_event_logging::WebRtcEventLogManager;
32
33 namespace {
34
35 // Key used to attach the handler to the RenderProcessHost.
36 constexpr char kRenderProcessHostKey[] = "kWebRtcLoggingControllerKey";
37
38 } // namespace
39
40 // static
AttachToRenderProcessHost(content::RenderProcessHost * host,WebRtcLogUploader * log_uploader)41 void WebRtcLoggingController::AttachToRenderProcessHost(
42 content::RenderProcessHost* host,
43 WebRtcLogUploader* log_uploader) {
44 host->SetUserData(
45 kRenderProcessHostKey,
46 std::make_unique<base::UserDataAdapter<WebRtcLoggingController>>(
47 new WebRtcLoggingController(host->GetID(), host->GetBrowserContext(),
48 log_uploader)));
49 }
50
51 // static
FromRenderProcessHost(content::RenderProcessHost * host)52 WebRtcLoggingController* WebRtcLoggingController::FromRenderProcessHost(
53 content::RenderProcessHost* host) {
54 return base::UserDataAdapter<WebRtcLoggingController>::Get(
55 host, kRenderProcessHostKey);
56 }
57
SetMetaData(std::unique_ptr<WebRtcLogMetaDataMap> meta_data,GenericDoneCallback callback)58 void WebRtcLoggingController::SetMetaData(
59 std::unique_ptr<WebRtcLogMetaDataMap> meta_data,
60 GenericDoneCallback callback) {
61 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
62 DCHECK(!callback.is_null());
63
64 // Set the web app ID if there's a "client" key, otherwise leave it unchanged.
65 for (const auto& it : *meta_data) {
66 if (it.first == "client") {
67 web_app_id_ = static_cast<int>(base::PersistentHash(it.second));
68 text_log_handler_->SetWebAppId(web_app_id_);
69 break;
70 }
71 }
72
73 text_log_handler_->SetMetaData(std::move(meta_data), std::move(callback));
74 }
75
StartLogging(GenericDoneCallback callback)76 void WebRtcLoggingController::StartLogging(GenericDoneCallback callback) {
77 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
78 DCHECK(!callback.is_null());
79
80 // Request a log_slot from the LogUploader and start logging.
81 if (text_log_handler_->StartLogging(log_uploader_, std::move(callback))) {
82 // Start logging in the renderer. The callback has already been fired since
83 // there is no acknowledgement when the renderer actually starts.
84 content::RenderProcessHost* host =
85 content::RenderProcessHost::FromID(render_process_id_);
86
87 // OK to rebind existing |logging_agent_| and |receiver_| connections.
88 logging_agent_.reset();
89 receiver_.reset();
90
91 host->BindReceiver(logging_agent_.BindNewPipeAndPassReceiver());
92 logging_agent_.set_disconnect_handler(
93 base::BindOnce(&WebRtcLoggingController::OnAgentDisconnected, this));
94 logging_agent_->Start(receiver_.BindNewPipeAndPassRemote());
95 }
96 }
97
StopLogging(GenericDoneCallback callback)98 void WebRtcLoggingController::StopLogging(GenericDoneCallback callback) {
99 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
100 DCHECK(!callback.is_null());
101
102 // Change the state to STOPPING and disable logging in the browser.
103 if (text_log_handler_->StopLogging(std::move(callback))) {
104 // Stop logging in the renderer. OnStopped will be called when this is done
105 // to change the state from STOPPING to STOPPED and fire the callback.
106 logging_agent_->Stop();
107 }
108 }
109
UploadLog(UploadDoneCallback callback)110 void WebRtcLoggingController::UploadLog(UploadDoneCallback callback) {
111 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
112 DCHECK(!callback.is_null());
113
114 // This functions uploads both text logs (mandatory) and RTP dumps (optional).
115 // TODO(terelius): If there's no text log available (either because it hasn't
116 // been started or because it hasn't been stopped), the current implementation
117 // will fire an error callback and leave any RTP dumps in a local directory.
118 // Would it be better to upload whatever logs we have, or would the lack of
119 // an error callback make it harder to debug potential errors?
120
121 base::UmaHistogramSparse("WebRtcTextLogging.UploadStarted", web_app_id_);
122
123 base::PostTaskAndReplyWithResult(
124 log_uploader_->background_task_runner().get(), FROM_HERE,
125 base::BindOnce(log_directory_getter_),
126 base::BindOnce(&WebRtcLoggingController::TriggerUpload, this,
127 std::move(callback)));
128 }
129
UploadStoredLog(const std::string & log_id,UploadDoneCallback callback)130 void WebRtcLoggingController::UploadStoredLog(const std::string& log_id,
131 UploadDoneCallback callback) {
132 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
133 DCHECK(!callback.is_null());
134
135 base::UmaHistogramSparse("WebRtcTextLogging.UploadStoredStarted",
136 web_app_id_);
137
138 // Make this a method call on log_uploader_
139
140 WebRtcLogUploader::UploadDoneData upload_data;
141 upload_data.callback = std::move(callback);
142 upload_data.local_log_id = log_id;
143 upload_data.web_app_id = web_app_id_;
144
145 log_uploader_->background_task_runner()->PostTask(
146 FROM_HERE,
147 base::BindOnce(
148 [](WebRtcLogUploader* log_uploader,
149 WebRtcLogUploader::UploadDoneData upload_data,
150 base::RepeatingCallback<base::FilePath(void)>
151 log_directory_getter) {
152 upload_data.paths.directory = log_directory_getter.Run();
153 log_uploader->UploadStoredLog(std::move(upload_data));
154 },
155 log_uploader_, std::move(upload_data), log_directory_getter_));
156 }
157
DiscardLog(GenericDoneCallback callback)158 void WebRtcLoggingController::DiscardLog(GenericDoneCallback callback) {
159 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
160 DCHECK(!callback.is_null());
161
162 if (!text_log_handler_->ExpectLoggingStateStopped(&callback)) {
163 // The callback is fired with an error message by ExpectLoggingStateStopped.
164 return;
165 }
166 log_uploader_->LoggingStoppedDontUpload();
167 text_log_handler_->DiscardLog();
168 rtp_dump_handler_.reset();
169 stop_rtp_dump_callback_.Reset();
170 FireGenericDoneCallback(std::move(callback), true, "");
171 }
172
173 // Stores the log locally using a hash of log_id + security origin.
StoreLog(const std::string & log_id,GenericDoneCallback callback)174 void WebRtcLoggingController::StoreLog(const std::string& log_id,
175 GenericDoneCallback callback) {
176 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
177 DCHECK(!callback.is_null());
178
179 if (!text_log_handler_->ExpectLoggingStateStopped(&callback)) {
180 // The callback is fired with an error message by ExpectLoggingStateStopped.
181 return;
182 }
183
184 if (rtp_dump_handler_) {
185 if (stop_rtp_dump_callback_) {
186 base::SequencedTaskRunnerHandle::Get()->PostTask(
187 FROM_HERE,
188 base::BindOnce(std::move(stop_rtp_dump_callback_), true, true));
189 }
190
191 rtp_dump_handler_->StopOngoingDumps(
192 base::BindOnce(&WebRtcLoggingController::StoreLogContinue, this, log_id,
193 std::move(callback)));
194 return;
195 }
196
197 StoreLogContinue(log_id, std::move(callback));
198 }
199
StoreLogContinue(const std::string & log_id,GenericDoneCallback callback)200 void WebRtcLoggingController::StoreLogContinue(const std::string& log_id,
201 GenericDoneCallback callback) {
202 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
203 DCHECK(!callback.is_null());
204
205 std::unique_ptr<WebRtcLogPaths> log_paths(new WebRtcLogPaths());
206 ReleaseRtpDumps(log_paths.get());
207
208 base::PostTaskAndReplyWithResult(
209 log_uploader_->background_task_runner().get(), FROM_HERE,
210 base::BindOnce(log_directory_getter_),
211 base::BindOnce(&WebRtcLoggingController::StoreLogInDirectory, this,
212 log_id, std::move(log_paths), std::move(callback)));
213 }
214
StartRtpDump(RtpDumpType type,GenericDoneCallback callback)215 void WebRtcLoggingController::StartRtpDump(RtpDumpType type,
216 GenericDoneCallback callback) {
217 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
218 DCHECK(!stop_rtp_dump_callback_);
219
220 content::RenderProcessHost* host =
221 content::RenderProcessHost::FromID(render_process_id_);
222
223 // This call cannot fail.
224 stop_rtp_dump_callback_ = host->StartRtpDump(
225 type == RTP_DUMP_INCOMING || type == RTP_DUMP_BOTH,
226 type == RTP_DUMP_OUTGOING || type == RTP_DUMP_BOTH,
227 base::BindRepeating(&WebRtcLoggingController::OnRtpPacket, this));
228
229 if (!rtp_dump_handler_) {
230 base::PostTaskAndReplyWithResult(
231 log_uploader_->background_task_runner().get(), FROM_HERE,
232 base::BindOnce(log_directory_getter_),
233 base::BindOnce(&WebRtcLoggingController::CreateRtpDumpHandlerAndStart,
234 this, type, std::move(callback)));
235 return;
236 }
237
238 DoStartRtpDump(type, std::move(callback));
239 }
240
StopRtpDump(RtpDumpType type,GenericDoneCallback callback)241 void WebRtcLoggingController::StopRtpDump(RtpDumpType type,
242 GenericDoneCallback callback) {
243 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
244 DCHECK(!callback.is_null());
245
246 if (!rtp_dump_handler_) {
247 FireGenericDoneCallback(std::move(callback), false,
248 "RTP dump has not been started.");
249 return;
250 }
251
252 if (stop_rtp_dump_callback_) {
253 base::SequencedTaskRunnerHandle::Get()->PostTask(
254 FROM_HERE,
255 base::BindOnce(std::move(stop_rtp_dump_callback_),
256 type == RTP_DUMP_INCOMING || type == RTP_DUMP_BOTH,
257 type == RTP_DUMP_OUTGOING || type == RTP_DUMP_BOTH));
258 }
259
260 rtp_dump_handler_->StopDump(type, std::move(callback));
261 }
262
StartEventLogging(const std::string & session_id,size_t max_log_size_bytes,int output_period_ms,size_t web_app_id,const StartEventLoggingCallback & callback)263 void WebRtcLoggingController::StartEventLogging(
264 const std::string& session_id,
265 size_t max_log_size_bytes,
266 int output_period_ms,
267 size_t web_app_id,
268 const StartEventLoggingCallback& callback) {
269 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
270 WebRtcEventLogManager::GetInstance()->StartRemoteLogging(
271 render_process_id_, session_id, max_log_size_bytes, output_period_ms,
272 web_app_id, callback);
273 }
274
275 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD)
GetLogsDirectory(LogsDirectoryCallback callback,LogsDirectoryErrorCallback error_callback)276 void WebRtcLoggingController::GetLogsDirectory(
277 LogsDirectoryCallback callback,
278 LogsDirectoryErrorCallback error_callback) {
279 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
280 DCHECK(!callback.is_null());
281 base::PostTaskAndReplyWithResult(
282 log_uploader_->background_task_runner().get(), FROM_HERE,
283 base::BindOnce(log_directory_getter_),
284 base::BindOnce(&WebRtcLoggingController::GrantLogsDirectoryAccess, this,
285 std::move(callback), std::move(error_callback)));
286 }
287
GrantLogsDirectoryAccess(LogsDirectoryCallback callback,LogsDirectoryErrorCallback error_callback,const base::FilePath & logs_path)288 void WebRtcLoggingController::GrantLogsDirectoryAccess(
289 LogsDirectoryCallback callback,
290 LogsDirectoryErrorCallback error_callback,
291 const base::FilePath& logs_path) {
292 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
293 if (logs_path.empty()) {
294 base::SequencedTaskRunnerHandle::Get()->PostTask(
295 FROM_HERE, base::BindOnce(std::move(error_callback),
296 "Logs directory not available"));
297 return;
298 }
299
300 storage::IsolatedContext* isolated_context =
301 storage::IsolatedContext::GetInstance();
302 DCHECK(isolated_context);
303
304 std::string registered_name;
305 storage::IsolatedContext::ScopedFSHandle file_system =
306 isolated_context->RegisterFileSystemForPath(
307 storage::kFileSystemTypeNativeLocal, std::string(), logs_path,
308 ®istered_name);
309
310 // Only granting read and delete access to reduce contention with
311 // webrtcLogging APIs that modify files in that folder.
312 content::ChildProcessSecurityPolicy* policy =
313 content::ChildProcessSecurityPolicy::GetInstance();
314 policy->GrantReadFileSystem(render_process_id_, file_system.id());
315 // Delete is needed to prevent accumulation of files.
316 policy->GrantDeleteFromFileSystem(render_process_id_, file_system.id());
317 base::SequencedTaskRunnerHandle::Get()->PostTask(
318 FROM_HERE,
319 base::BindOnce(std::move(callback), file_system.id(), registered_name));
320 }
321 #endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD)
322
OnRtpPacket(std::unique_ptr<uint8_t[]> packet_header,size_t header_length,size_t packet_length,bool incoming)323 void WebRtcLoggingController::OnRtpPacket(
324 std::unique_ptr<uint8_t[]> packet_header,
325 size_t header_length,
326 size_t packet_length,
327 bool incoming) {
328 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
329
330 // |rtp_dump_handler_| could be null if we are waiting for the FILE thread to
331 // create/ensure the log directory.
332 if (rtp_dump_handler_) {
333 rtp_dump_handler_->OnRtpPacket(packet_header.get(), header_length,
334 packet_length, incoming);
335 }
336 }
337
OnAddMessages(std::vector<chrome::mojom::WebRtcLoggingMessagePtr> messages)338 void WebRtcLoggingController::OnAddMessages(
339 std::vector<chrome::mojom::WebRtcLoggingMessagePtr> messages) {
340 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
341
342 if (text_log_handler_->GetState() == WebRtcTextLogHandler::STARTED ||
343 text_log_handler_->GetState() == WebRtcTextLogHandler::STOPPING) {
344 for (auto& message : messages)
345 text_log_handler_->LogWebRtcLoggingMessage(message.get());
346 }
347 }
348
OnStopped()349 void WebRtcLoggingController::OnStopped() {
350 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
351
352 if (text_log_handler_->GetState() != WebRtcTextLogHandler::STOPPING) {
353 // If an out-of-order response is received, stop_callback_ may be invalid,
354 // and must not be invoked.
355 DLOG(ERROR) << "OnStopped invoked in state "
356 << text_log_handler_->GetState();
357 mojo::ReportBadMessage("WRLHH: OnStopped invoked in unexpected state.");
358 return;
359 }
360 text_log_handler_->StopDone();
361 }
362
WebRtcLoggingController(int render_process_id,content::BrowserContext * browser_context,WebRtcLogUploader * log_uploader)363 WebRtcLoggingController::WebRtcLoggingController(
364 int render_process_id,
365 content::BrowserContext* browser_context,
366 WebRtcLogUploader* log_uploader)
367 : receiver_(this),
368 render_process_id_(render_process_id),
369 log_directory_getter_(base::BindRepeating(
370 &WebRtcLoggingController::GetLogDirectoryAndEnsureExists,
371 browser_context->GetPath())),
372 upload_log_on_render_close_(false),
373 text_log_handler_(
374 std::make_unique<WebRtcTextLogHandler>(render_process_id)),
375 log_uploader_(log_uploader) {
376 DCHECK(log_uploader_);
377 }
378
~WebRtcLoggingController()379 WebRtcLoggingController::~WebRtcLoggingController() {
380 // If we hit this, then we might be leaking a log reference count (see
381 // ApplyForStartLogging).
382 DCHECK_EQ(WebRtcTextLogHandler::CLOSED, text_log_handler_->GetState());
383 }
384
OnAgentDisconnected()385 void WebRtcLoggingController::OnAgentDisconnected() {
386 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
387
388 if (text_log_handler_->GetChannelIsClosing())
389 return;
390
391 switch (text_log_handler_->GetState()) {
392 case WebRtcTextLogHandler::STARTING:
393 case WebRtcTextLogHandler::STARTED:
394 case WebRtcTextLogHandler::STOPPING:
395 case WebRtcTextLogHandler::STOPPED:
396 text_log_handler_->ChannelClosing();
397 if (upload_log_on_render_close_) {
398 base::PostTaskAndReplyWithResult(
399 log_uploader_->background_task_runner().get(), FROM_HERE,
400 base::BindOnce(log_directory_getter_),
401 base::BindOnce(&WebRtcLoggingController::TriggerUpload, this,
402 UploadDoneCallback()));
403 } else {
404 log_uploader_->LoggingStoppedDontUpload();
405 text_log_handler_->DiscardLog();
406 }
407 break;
408 case WebRtcTextLogHandler::CLOSED:
409 // Do nothing
410 break;
411 default:
412 NOTREACHED();
413 }
414 }
415
TriggerUpload(UploadDoneCallback callback,const base::FilePath & log_directory)416 void WebRtcLoggingController::TriggerUpload(
417 UploadDoneCallback callback,
418 const base::FilePath& log_directory) {
419 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
420
421 if (rtp_dump_handler_) {
422 if (stop_rtp_dump_callback_) {
423 base::SequencedTaskRunnerHandle::Get()->PostTask(
424 FROM_HERE,
425 base::BindOnce(std::move(stop_rtp_dump_callback_), true, true));
426 }
427
428 rtp_dump_handler_->StopOngoingDumps(
429 base::BindOnce(&WebRtcLoggingController::DoUploadLogAndRtpDumps, this,
430 log_directory, std::move(callback)));
431 return;
432 }
433
434 DoUploadLogAndRtpDumps(log_directory, std::move(callback));
435 }
436
StoreLogInDirectory(const std::string & log_id,std::unique_ptr<WebRtcLogPaths> log_paths,GenericDoneCallback done_callback,const base::FilePath & directory)437 void WebRtcLoggingController::StoreLogInDirectory(
438 const std::string& log_id,
439 std::unique_ptr<WebRtcLogPaths> log_paths,
440 GenericDoneCallback done_callback,
441 const base::FilePath& directory) {
442 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
443
444 // If channel is not closing, storing is only allowed when in STOPPED state.
445 // If channel is closing, storing is allowed for all states except CLOSED.
446 const WebRtcTextLogHandler::LoggingState text_logging_state =
447 text_log_handler_->GetState();
448 const bool channel_is_closing = text_log_handler_->GetChannelIsClosing();
449 if ((!channel_is_closing &&
450 text_logging_state != WebRtcTextLogHandler::STOPPED) ||
451 (channel_is_closing &&
452 text_log_handler_->GetState() == WebRtcTextLogHandler::CLOSED)) {
453 base::SequencedTaskRunnerHandle::Get()->PostTask(
454 FROM_HERE, base::BindOnce(std::move(done_callback), false,
455 "Logging not stopped or no log open."));
456 return;
457 }
458
459 log_paths->directory = directory;
460
461 std::unique_ptr<WebRtcLogBuffer> log_buffer;
462 std::unique_ptr<WebRtcLogMetaDataMap> meta_data;
463 text_log_handler_->ReleaseLog(&log_buffer, &meta_data);
464 CHECK(log_buffer.get()) << "State=" << text_log_handler_->GetState()
465 << ", uorc=" << upload_log_on_render_close_;
466
467 log_uploader_->background_task_runner()->PostTask(
468 FROM_HERE,
469 base::BindOnce(&WebRtcLogUploader::LoggingStoppedDoStore,
470 base::Unretained(log_uploader_), *log_paths, log_id,
471 std::move(log_buffer), std::move(meta_data),
472 std::move(done_callback)));
473 }
474
DoUploadLogAndRtpDumps(const base::FilePath & log_directory,UploadDoneCallback callback)475 void WebRtcLoggingController::DoUploadLogAndRtpDumps(
476 const base::FilePath& log_directory,
477 UploadDoneCallback callback) {
478 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
479
480 // If channel is not closing, upload is only allowed when in STOPPED state.
481 // If channel is closing, uploading is allowed for all states except CLOSED.
482 const WebRtcTextLogHandler::LoggingState text_logging_state =
483 text_log_handler_->GetState();
484 const bool channel_is_closing = text_log_handler_->GetChannelIsClosing();
485 if ((!channel_is_closing &&
486 text_logging_state != WebRtcTextLogHandler::STOPPED) ||
487 (channel_is_closing &&
488 text_log_handler_->GetState() == WebRtcTextLogHandler::CLOSED)) {
489 // If the channel is not closing the log is expected to be uploaded, so
490 // it's considered a failure if it isn't.
491 // If the channel is closing we don't log failure to UMA for consistency,
492 // since there are other cases during shutdown were we don't get a chance
493 // to log.
494 if (!channel_is_closing) {
495 base::UmaHistogramSparse("WebRtcTextLogging.UploadFailed", web_app_id_);
496 base::UmaHistogramSparse("WebRtcTextLogging.UploadFailureReason",
497 WebRtcLogUploadFailureReason::kInvalidState);
498 }
499
500 // Do not fire callback if it is null. Nesting null callbacks is not
501 // allowed, as it can lead to crashes. See https://crbug.com/1071475
502 if (!callback.is_null()) {
503 base::SequencedTaskRunnerHandle::Get()->PostTask(
504 FROM_HERE, base::BindOnce(std::move(callback), false, "",
505 "Logging not stopped or no log open."));
506 }
507 return;
508 }
509
510 WebRtcLogUploader::UploadDoneData upload_done_data;
511 upload_done_data.paths.directory = log_directory;
512 upload_done_data.callback = std::move(callback);
513 upload_done_data.web_app_id = web_app_id_;
514 ReleaseRtpDumps(&upload_done_data.paths);
515
516 std::unique_ptr<WebRtcLogBuffer> log_buffer;
517 std::unique_ptr<WebRtcLogMetaDataMap> meta_data;
518 text_log_handler_->ReleaseLog(&log_buffer, &meta_data);
519 CHECK(log_buffer.get()) << "State=" << text_log_handler_->GetState()
520 << ", uorc=" << upload_log_on_render_close_;
521
522 log_uploader_->background_task_runner()->PostTask(
523 FROM_HERE,
524 base::BindOnce(&WebRtcLogUploader::LoggingStoppedDoUpload,
525 base::Unretained(log_uploader_), std::move(log_buffer),
526 std::move(meta_data), std::move(upload_done_data)));
527 }
528
CreateRtpDumpHandlerAndStart(RtpDumpType type,GenericDoneCallback callback,const base::FilePath & dump_dir)529 void WebRtcLoggingController::CreateRtpDumpHandlerAndStart(
530 RtpDumpType type,
531 GenericDoneCallback callback,
532 const base::FilePath& dump_dir) {
533 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
534
535 // |rtp_dump_handler_| may be non-null if StartRtpDump is called again before
536 // GetLogDirectoryAndEnsureExists returns on the FILE thread for a previous
537 // StartRtpDump.
538 if (!rtp_dump_handler_)
539 rtp_dump_handler_.reset(new WebRtcRtpDumpHandler(dump_dir));
540
541 DoStartRtpDump(type, std::move(callback));
542 }
543
DoStartRtpDump(RtpDumpType type,GenericDoneCallback callback)544 void WebRtcLoggingController::DoStartRtpDump(RtpDumpType type,
545 GenericDoneCallback callback) {
546 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
547 DCHECK(rtp_dump_handler_);
548
549 std::string error;
550 bool result = rtp_dump_handler_->StartDump(type, &error);
551 FireGenericDoneCallback(std::move(callback), result, error);
552 }
553
ReleaseRtpDumps(WebRtcLogPaths * log_paths)554 bool WebRtcLoggingController::ReleaseRtpDumps(WebRtcLogPaths* log_paths) {
555 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
556 DCHECK(log_paths);
557
558 if (!rtp_dump_handler_)
559 return false;
560
561 WebRtcRtpDumpHandler::ReleasedDumps rtp_dumps(
562 rtp_dump_handler_->ReleaseDumps());
563 log_paths->incoming_rtp_dump = rtp_dumps.incoming_dump_path;
564 log_paths->outgoing_rtp_dump = rtp_dumps.outgoing_dump_path;
565
566 rtp_dump_handler_.reset();
567
568 return true;
569 }
570
FireGenericDoneCallback(GenericDoneCallback callback,bool success,const std::string & error_message)571 void WebRtcLoggingController::FireGenericDoneCallback(
572 GenericDoneCallback callback,
573 bool success,
574 const std::string& error_message) {
575 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
576 DCHECK(!callback.is_null());
577 DCHECK_EQ(success, error_message.empty());
578
579 base::SequencedTaskRunnerHandle::Get()->PostTask(
580 FROM_HERE, base::BindOnce(std::move(callback), success, error_message));
581 }
582
583 // static
GetLogDirectoryAndEnsureExists(const base::FilePath & browser_context_directory_path)584 base::FilePath WebRtcLoggingController::GetLogDirectoryAndEnsureExists(
585 const base::FilePath& browser_context_directory_path) {
586 DCHECK(!browser_context_directory_path.empty());
587 // Since we can be alive after the RenderProcessHost and the BrowserContext
588 // (profile) have gone away, we could create the log directory here after a
589 // profile has been deleted and removed from disk. If that happens it will be
590 // cleaned up (at a higher level) the next browser restart.
591 base::FilePath log_dir_path =
592 webrtc_logging::TextLogList::GetWebRtcLogDirectoryForBrowserContextPath(
593 browser_context_directory_path);
594 base::File::Error error;
595 if (!base::CreateDirectoryAndGetError(log_dir_path, &error)) {
596 DLOG(ERROR) << "Could not create WebRTC log directory, error: " << error;
597 return base::FilePath();
598 }
599 return log_dir_path;
600 }
601