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           &registered_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