• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_logging_handler_host.h"
6 
7 #include <string>
8 
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/cpu.h"
12 #include "base/file_util.h"
13 #include "base/logging.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/sys_info.h"
17 #include "base/time/time.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/chromeos/settings/cros_settings.h"
20 #include "chrome/browser/media/webrtc_log_list.h"
21 #include "chrome/browser/media/webrtc_log_uploader.h"
22 #include "chrome/browser/media/webrtc_rtp_dump_handler.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/common/chrome_switches.h"
25 #include "chrome/common/media/webrtc_logging_messages.h"
26 #include "chrome/common/partial_circular_buffer.h"
27 #include "chrome/common/pref_names.h"
28 #include "chromeos/settings/cros_settings_names.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/content_browser_client.h"
31 #include "content/public/browser/gpu_data_manager.h"
32 #include "content/public/browser/render_process_host.h"
33 #include "gpu/config/gpu_info.h"
34 #include "net/base/address_family.h"
35 #include "net/url_request/url_request_context_getter.h"
36 
37 #if defined(OS_LINUX)
38 #include "base/linux_util.h"
39 #endif
40 
41 #if defined(OS_MACOSX)
42 #include "base/mac/mac_util.h"
43 #endif
44 
45 #if defined(OS_CHROMEOS)
46 #include "chromeos/system/statistics_provider.h"
47 #endif
48 
49 using base::IntToString;
50 using content::BrowserThread;
51 
52 namespace {
53 
54 #if defined(OS_ANDROID)
55 const size_t kWebRtcLogSize = 1 * 1024 * 1024;  // 1 MB
56 #else
57 const size_t kWebRtcLogSize = 6 * 1024 * 1024;  // 6 MB
58 #endif
59 
60 const char kLogNotStoppedOrNoLogOpen[] =
61     "Logging not stopped or no log open.";
62 
63 // For privacy reasons when logging IP addresses. The returned "sensitive
64 // string" is for release builds a string with the end stripped away. Last
65 // octet for IPv4 and last 80 bits (5 groups) for IPv6. String will be
66 // "1.2.3.x" and "1.2.3::" respectively. For debug builds, the string is
67 // not stripped.
IPAddressToSensitiveString(const net::IPAddressNumber & address)68 std::string IPAddressToSensitiveString(const net::IPAddressNumber& address) {
69 #if defined(NDEBUG)
70   std::string sensitive_address;
71   switch (net::GetAddressFamily(address)) {
72     case net::ADDRESS_FAMILY_IPV4: {
73       sensitive_address = net::IPAddressToString(address);
74       size_t find_pos = sensitive_address.rfind('.');
75       if (find_pos == std::string::npos)
76         return std::string();
77       sensitive_address.resize(find_pos);
78       sensitive_address += ".x";
79       break;
80     }
81     case net::ADDRESS_FAMILY_IPV6: {
82       // TODO(grunell): Create a string of format "1:2:3:x:x:x:x:x" to clarify
83       // that the end has been stripped out.
84       net::IPAddressNumber sensitive_address_number = address;
85       sensitive_address_number.resize(net::kIPv6AddressSize - 10);
86       sensitive_address_number.resize(net::kIPv6AddressSize, 0);
87       sensitive_address = net::IPAddressToString(sensitive_address_number);
88       break;
89     }
90     case net::ADDRESS_FAMILY_UNSPECIFIED: {
91       break;
92     }
93   }
94   return sensitive_address;
95 #else
96   return net::IPAddressToString(address);
97 #endif
98 }
99 
FormatMetaDataAsLogMessage(const MetaDataMap & meta_data,std::string * message)100 void FormatMetaDataAsLogMessage(
101     const MetaDataMap& meta_data,
102     std::string* message) {
103   for (MetaDataMap::const_iterator it = meta_data.begin();
104        it != meta_data.end(); ++it) {
105     *message += it->first + ": " + it->second + '\n';
106   }
107   // Remove last '\n'.
108   message->resize(message->size() - 1);
109 }
110 
111 }  // namespace
112 
WebRtcLoggingHandlerHost(Profile * profile)113 WebRtcLoggingHandlerHost::WebRtcLoggingHandlerHost(Profile* profile)
114     : BrowserMessageFilter(WebRtcLoggingMsgStart),
115       profile_(profile),
116       logging_state_(CLOSED),
117       upload_log_on_render_close_(false) {
118   DCHECK(profile_);
119 }
120 
~WebRtcLoggingHandlerHost()121 WebRtcLoggingHandlerHost::~WebRtcLoggingHandlerHost() {}
122 
SetMetaData(const MetaDataMap & meta_data,const GenericDoneCallback & callback)123 void WebRtcLoggingHandlerHost::SetMetaData(
124     const MetaDataMap& meta_data,
125     const GenericDoneCallback& callback) {
126   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
127   DCHECK(!callback.is_null());
128 
129   std::string error_message;
130   if (logging_state_ == CLOSED) {
131     meta_data_ = meta_data;
132   } else if (logging_state_ == STARTED) {
133     meta_data_ = meta_data;
134     std::string meta_data_message;
135     FormatMetaDataAsLogMessage(meta_data_, &meta_data_message);
136     LogToCircularBuffer(meta_data_message);
137   } else {
138     error_message = "Meta data must be set before stop or upload.";
139   }
140   bool success = error_message.empty();
141   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
142                                    base::Bind(callback, success,
143                                               error_message));
144 }
145 
StartLogging(const GenericDoneCallback & callback)146 void WebRtcLoggingHandlerHost::StartLogging(
147     const GenericDoneCallback& callback) {
148   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
149   DCHECK(!callback.is_null());
150 
151   start_callback_ = callback;
152   if (logging_state_ != CLOSED) {
153     FireGenericDoneCallback(&start_callback_, false, "A log is already open");
154     return;
155   }
156   logging_state_ = STARTING;
157   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
158       &WebRtcLoggingHandlerHost::StartLoggingIfAllowed, this));
159 }
160 
StopLogging(const GenericDoneCallback & callback)161 void WebRtcLoggingHandlerHost::StopLogging(
162     const GenericDoneCallback& callback) {
163   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
164   DCHECK(!callback.is_null());
165 
166   stop_callback_ = callback;
167   if (logging_state_ != STARTED) {
168     FireGenericDoneCallback(&stop_callback_, false, "Logging not started");
169     return;
170   }
171   logging_state_ = STOPPING;
172   Send(new WebRtcLoggingMsg_StopLogging());
173 }
174 
UploadLog(const UploadDoneCallback & callback)175 void WebRtcLoggingHandlerHost::UploadLog(const UploadDoneCallback& callback) {
176   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
177   DCHECK(!callback.is_null());
178 
179   if (logging_state_ != STOPPED) {
180     if (!callback.is_null()) {
181       content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
182           base::Bind(callback, false, "", kLogNotStoppedOrNoLogOpen));
183     }
184     return;
185   }
186 
187   upload_callback_ = callback;
188   logging_state_ = UPLOADING;
189   content::BrowserThread::PostTaskAndReplyWithResult(
190       content::BrowserThread::FILE,
191       FROM_HERE,
192       base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
193                  this),
194       base::Bind(&WebRtcLoggingHandlerHost::TriggerUpload, this));
195 }
196 
UploadLogDone()197 void WebRtcLoggingHandlerHost::UploadLogDone() {
198   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
199   logging_state_ = CLOSED;
200 }
201 
DiscardLog(const GenericDoneCallback & callback)202 void WebRtcLoggingHandlerHost::DiscardLog(const GenericDoneCallback& callback) {
203   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
204   DCHECK(!callback.is_null());
205 
206   GenericDoneCallback discard_callback = callback;
207   if (logging_state_ != STOPPED) {
208     FireGenericDoneCallback(&discard_callback, false,
209                             kLogNotStoppedOrNoLogOpen);
210     return;
211   }
212   g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload();
213   circular_buffer_.reset();
214   log_buffer_.reset();
215   logging_state_ = CLOSED;
216   rtp_dump_handler_.reset();
217   stop_rtp_dump_callback_.Reset();
218   FireGenericDoneCallback(&discard_callback, true, "");
219 }
220 
LogMessage(const std::string & message)221 void WebRtcLoggingHandlerHost::LogMessage(const std::string& message) {
222   BrowserThread::PostTask(
223       BrowserThread::IO,
224       FROM_HERE,
225       base::Bind(
226           &WebRtcLoggingHandlerHost::AddLogMessageFromBrowser,
227           this,
228           WebRtcLoggingMessageData(base::Time::Now(), message)));
229 }
230 
StartRtpDump(RtpDumpType type,const GenericDoneCallback & callback,const content::RenderProcessHost::WebRtcStopRtpDumpCallback & stop_callback)231 void WebRtcLoggingHandlerHost::StartRtpDump(
232     RtpDumpType type,
233     const GenericDoneCallback& callback,
234     const content::RenderProcessHost::WebRtcStopRtpDumpCallback&
235         stop_callback) {
236   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
237   DCHECK(stop_rtp_dump_callback_.is_null() ||
238          stop_rtp_dump_callback_.Equals(stop_callback));
239 
240   stop_rtp_dump_callback_ = stop_callback;
241 
242   if (!rtp_dump_handler_) {
243     content::BrowserThread::PostTaskAndReplyWithResult(
244         content::BrowserThread::FILE,
245         FROM_HERE,
246         base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
247                    this),
248         base::Bind(&WebRtcLoggingHandlerHost::CreateRtpDumpHandlerAndStart,
249                    this,
250                    type,
251                    callback));
252     return;
253   }
254 
255   GenericDoneCallback start_callback = callback;
256   DoStartRtpDump(type, &start_callback);
257 }
258 
StopRtpDump(RtpDumpType type,const GenericDoneCallback & callback)259 void WebRtcLoggingHandlerHost::StopRtpDump(
260     RtpDumpType type,
261     const GenericDoneCallback& callback) {
262   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
263   DCHECK(!callback.is_null());
264 
265   if (!rtp_dump_handler_) {
266     GenericDoneCallback stop_callback = callback;
267     FireGenericDoneCallback(
268         &stop_callback, false, "RTP dump has not been started.");
269     return;
270   }
271 
272   if (!stop_rtp_dump_callback_.is_null()) {
273     BrowserThread::PostTask(
274         BrowserThread::UI,
275         FROM_HERE,
276         base::Bind(stop_rtp_dump_callback_,
277                    type == RTP_DUMP_INCOMING || type == RTP_DUMP_BOTH,
278                    type == RTP_DUMP_OUTGOING || type == RTP_DUMP_BOTH));
279   }
280 
281   rtp_dump_handler_->StopDump(type, callback);
282 }
283 
OnRtpPacket(scoped_ptr<uint8[]> packet_header,size_t header_length,size_t packet_length,bool incoming)284 void WebRtcLoggingHandlerHost::OnRtpPacket(scoped_ptr<uint8[]> packet_header,
285                                            size_t header_length,
286                                            size_t packet_length,
287                                            bool incoming) {
288   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
289 
290   BrowserThread::PostTask(
291       BrowserThread::IO,
292       FROM_HERE,
293       base::Bind(&WebRtcLoggingHandlerHost::DumpRtpPacketOnIOThread,
294                  this,
295                  base::Passed(&packet_header),
296                  header_length,
297                  packet_length,
298                  incoming));
299 }
300 
DumpRtpPacketOnIOThread(scoped_ptr<uint8[]> packet_header,size_t header_length,size_t packet_length,bool incoming)301 void WebRtcLoggingHandlerHost::DumpRtpPacketOnIOThread(
302     scoped_ptr<uint8[]> packet_header,
303     size_t header_length,
304     size_t packet_length,
305     bool incoming) {
306   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
307 
308   // |rtp_dump_handler_| could be NULL if we are waiting for the FILE thread to
309   // create/ensure the log directory.
310   if (rtp_dump_handler_) {
311     rtp_dump_handler_->OnRtpPacket(
312         packet_header.get(), header_length, packet_length, incoming);
313   }
314 }
315 
OnChannelClosing()316 void WebRtcLoggingHandlerHost::OnChannelClosing() {
317   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
318   if (logging_state_ == STARTED || logging_state_ == STOPPED) {
319     if (upload_log_on_render_close_) {
320       logging_state_ = UPLOADING;
321       logging_started_time_ = base::Time();
322 
323       content::BrowserThread::PostTaskAndReplyWithResult(
324           content::BrowserThread::FILE,
325           FROM_HERE,
326           base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
327                      this),
328           base::Bind(&WebRtcLoggingHandlerHost::TriggerUpload, this));
329     } else {
330       g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload();
331     }
332   }
333   content::BrowserMessageFilter::OnChannelClosing();
334 }
335 
OnDestruct() const336 void WebRtcLoggingHandlerHost::OnDestruct() const {
337   BrowserThread::DeleteOnIOThread::Destruct(this);
338 }
339 
OnMessageReceived(const IPC::Message & message)340 bool WebRtcLoggingHandlerHost::OnMessageReceived(const IPC::Message& message) {
341   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
342   bool handled = true;
343   IPC_BEGIN_MESSAGE_MAP(WebRtcLoggingHandlerHost, message)
344     IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_AddLogMessages, OnAddLogMessages)
345     IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_LoggingStopped,
346                         OnLoggingStoppedInRenderer)
347     IPC_MESSAGE_UNHANDLED(handled = false)
348   IPC_END_MESSAGE_MAP()
349 
350   return handled;
351 }
352 
AddLogMessageFromBrowser(const WebRtcLoggingMessageData & message)353 void WebRtcLoggingHandlerHost::AddLogMessageFromBrowser(
354     const WebRtcLoggingMessageData& message) {
355   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
356   if (logging_state_ == STARTED)
357     LogToCircularBuffer(message.Format(logging_started_time_));
358 }
359 
OnAddLogMessages(const std::vector<WebRtcLoggingMessageData> & messages)360 void WebRtcLoggingHandlerHost::OnAddLogMessages(
361     const std::vector<WebRtcLoggingMessageData>& messages) {
362   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
363   if (logging_state_ == STARTED || logging_state_ == STOPPING) {
364     for (size_t i = 0; i < messages.size(); ++i) {
365       LogToCircularBuffer(messages[i].Format(logging_started_time_));
366     }
367   }
368 }
369 
OnLoggingStoppedInRenderer()370 void WebRtcLoggingHandlerHost::OnLoggingStoppedInRenderer() {
371   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
372   if (logging_state_ != STOPPING) {
373     // If an out-of-order response is received, stop_callback_ may be invalid,
374     // and must not be invoked.
375     DLOG(ERROR) << "OnLoggingStoppedInRenderer invoked in state "
376                 << logging_state_;
377     BadMessageReceived();
378     return;
379   }
380   logging_started_time_ = base::Time();
381   logging_state_ = STOPPED;
382   FireGenericDoneCallback(&stop_callback_, true, "");
383 }
384 
StartLoggingIfAllowed()385 void WebRtcLoggingHandlerHost::StartLoggingIfAllowed() {
386   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
387   if (!g_browser_process->webrtc_log_uploader()->ApplyForStartLogging()) {
388     logging_state_ = CLOSED;
389       FireGenericDoneCallback(
390           &start_callback_, false, "Cannot start, maybe the maximum number of "
391           "simultaneuos logs has been reached.");
392     return;
393   }
394   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
395       &WebRtcLoggingHandlerHost::DoStartLogging, this));
396 }
397 
DoStartLogging()398 void WebRtcLoggingHandlerHost::DoStartLogging() {
399   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
400 
401   log_buffer_.reset(new unsigned char[kWebRtcLogSize]);
402   circular_buffer_.reset(
403     new PartialCircularBuffer(log_buffer_.get(),
404                               kWebRtcLogSize,
405                               kWebRtcLogSize / 2,
406                               false));
407 
408   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
409       &WebRtcLoggingHandlerHost::LogInitialInfoOnFileThread, this));
410 }
411 
LogInitialInfoOnFileThread()412 void WebRtcLoggingHandlerHost::LogInitialInfoOnFileThread() {
413   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
414 
415   net::NetworkInterfaceList network_list;
416   net::GetNetworkList(&network_list,
417                       net::EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES);
418 
419   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
420       &WebRtcLoggingHandlerHost::LogInitialInfoOnIOThread, this, network_list));
421 }
422 
LogInitialInfoOnIOThread(const net::NetworkInterfaceList & network_list)423 void WebRtcLoggingHandlerHost::LogInitialInfoOnIOThread(
424     const net::NetworkInterfaceList& network_list) {
425   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
426 
427   // Log start time (current time). We don't use base/i18n/time_formatting.h
428   // here because we don't want the format of the current locale.
429   base::Time::Exploded now = {0};
430   base::Time::Now().LocalExplode(&now);
431   LogToCircularBuffer(base::StringPrintf(
432       "Start %d-%02d-%02d %02d:%02d:%02d", now.year, now.month,
433       now.day_of_month, now.hour, now.minute, now.second));
434 
435   // Write metadata if received before logging started.
436   if (!meta_data_.empty()) {
437     std::string info;
438     FormatMetaDataAsLogMessage(meta_data_, &info);
439     LogToCircularBuffer(info);
440   }
441 
442   // OS
443   LogToCircularBuffer(base::SysInfo::OperatingSystemName() + " " +
444                       base::SysInfo::OperatingSystemVersion() + " " +
445                       base::SysInfo::OperatingSystemArchitecture());
446 #if defined(OS_LINUX)
447   LogToCircularBuffer("Linux distribution: " + base::GetLinuxDistro());
448 #endif
449 
450   // CPU
451   base::CPU cpu;
452   LogToCircularBuffer(
453       "Cpu: " + IntToString(cpu.family()) + "." + IntToString(cpu.model()) +
454       "." + IntToString(cpu.stepping()) + ", x" +
455       IntToString(base::SysInfo::NumberOfProcessors()) + ", " +
456       IntToString(base::SysInfo::AmountOfPhysicalMemoryMB()) + "MB");
457   std::string cpu_brand = cpu.cpu_brand();
458   // Workaround for crbug.com/249713.
459   // TODO(grunell): Remove workaround when bug is fixed.
460   size_t null_pos = cpu_brand.find('\0');
461   if (null_pos != std::string::npos)
462     cpu_brand.erase(null_pos);
463   LogToCircularBuffer("Cpu brand: " + cpu_brand);
464 
465   // Computer model
466   std::string computer_model = "Not available";
467 #if defined(OS_MACOSX)
468   computer_model = base::mac::GetModelIdentifier();
469 #elif defined(OS_CHROMEOS)
470   chromeos::system::StatisticsProvider::GetInstance()->
471       GetMachineStatistic(chromeos::system::kHardwareClassKey, &computer_model);
472 #endif
473   LogToCircularBuffer("Computer model: " + computer_model);
474 
475   // GPU
476   gpu::GPUInfo gpu_info = content::GpuDataManager::GetInstance()->GetGPUInfo();
477   LogToCircularBuffer(
478       "Gpu: machine-model-name=" + gpu_info.machine_model_name +
479       ", machine-model-version=" + gpu_info.machine_model_version +
480       ", vendor-id=" + IntToString(gpu_info.gpu.vendor_id) +
481       ", device-id=" + IntToString(gpu_info.gpu.device_id) +
482       ", driver-vendor=" + gpu_info.driver_vendor +
483       ", driver-version=" + gpu_info.driver_version);
484   LogToCircularBuffer(
485       "OpenGL: gl-vendor=" + gpu_info.gl_vendor +
486       ", gl-renderer=" + gpu_info.gl_renderer +
487       ", gl-version=" + gpu_info.gl_version);
488 
489   // Network interfaces
490   LogToCircularBuffer("Discovered " + IntToString(network_list.size()) +
491                       " network interfaces:");
492   for (net::NetworkInterfaceList::const_iterator it = network_list.begin();
493        it != network_list.end(); ++it) {
494     LogToCircularBuffer("Name: " + it->friendly_name + ", Address: " +
495                         IPAddressToSensitiveString(it->address));
496   }
497 
498   NotifyLoggingStarted();
499 }
500 
NotifyLoggingStarted()501 void WebRtcLoggingHandlerHost::NotifyLoggingStarted() {
502   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
503   Send(new WebRtcLoggingMsg_StartLogging());
504   logging_started_time_ = base::Time::Now();
505   logging_state_ = STARTED;
506   FireGenericDoneCallback(&start_callback_, true, "");
507 }
508 
LogToCircularBuffer(const std::string & message)509 void WebRtcLoggingHandlerHost::LogToCircularBuffer(const std::string& message) {
510   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
511   DCHECK(circular_buffer_.get());
512   circular_buffer_->Write(message.c_str(), message.length());
513   const char eol = '\n';
514   circular_buffer_->Write(&eol, 1);
515 }
516 
GetLogDirectoryAndEnsureExists()517 base::FilePath WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists() {
518   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
519   base::FilePath log_dir_path =
520       WebRtcLogList::GetWebRtcLogDirectoryForProfile(profile_->GetPath());
521   base::File::Error error;
522   if (!base::CreateDirectoryAndGetError(log_dir_path, &error)) {
523     DLOG(ERROR) << "Could not create WebRTC log directory, error: " << error;
524     return base::FilePath();
525   }
526   return log_dir_path;
527 }
528 
TriggerUpload(const base::FilePath & log_directory)529 void WebRtcLoggingHandlerHost::TriggerUpload(
530     const base::FilePath& log_directory) {
531   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
532   DCHECK_EQ(logging_state_, UPLOADING);
533 
534   if (rtp_dump_handler_) {
535     BrowserThread::PostTask(
536         BrowserThread::UI,
537         FROM_HERE,
538         base::Bind(stop_rtp_dump_callback_, true, true));
539 
540     rtp_dump_handler_->StopOngoingDumps(
541         base::Bind(&WebRtcLoggingHandlerHost::DoUploadLogAndRtpDumps,
542                    this,
543                    log_directory));
544     return;
545   }
546 
547   DoUploadLogAndRtpDumps(log_directory);
548 }
549 
DoUploadLogAndRtpDumps(const base::FilePath & log_directory)550 void WebRtcLoggingHandlerHost::DoUploadLogAndRtpDumps(
551     const base::FilePath& log_directory) {
552   WebRtcLogUploadDoneData upload_done_data;
553   upload_done_data.log_path = log_directory;
554 
555   if (rtp_dump_handler_) {
556     WebRtcRtpDumpHandler::ReleasedDumps rtp_dumps(
557         rtp_dump_handler_->ReleaseDumps());
558     upload_done_data.incoming_rtp_dump = rtp_dumps.incoming_dump_path;
559     upload_done_data.outgoing_rtp_dump = rtp_dumps.outgoing_dump_path;
560 
561     rtp_dump_handler_.reset();
562     stop_rtp_dump_callback_.Reset();
563   }
564 
565   upload_done_data.callback = upload_callback_;
566   upload_done_data.host = this;
567   upload_callback_.Reset();
568 
569   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
570       &WebRtcLogUploader::LoggingStoppedDoUpload,
571       base::Unretained(g_browser_process->webrtc_log_uploader()),
572       Passed(&log_buffer_),
573       kWebRtcLogSize,
574       meta_data_,
575       upload_done_data));
576 
577   meta_data_.clear();
578   circular_buffer_.reset();
579 }
580 
FireGenericDoneCallback(GenericDoneCallback * callback,bool success,const std::string & error_message)581 void WebRtcLoggingHandlerHost::FireGenericDoneCallback(
582     GenericDoneCallback* callback,
583     bool success,
584     const std::string& error_message) {
585   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
586   DCHECK(!(*callback).is_null());
587   content::BrowserThread::PostTask(
588       content::BrowserThread::UI,
589       FROM_HERE,
590       base::Bind(*callback, success, error_message));
591   (*callback).Reset();
592 }
593 
CreateRtpDumpHandlerAndStart(RtpDumpType type,GenericDoneCallback callback,const base::FilePath & dump_dir)594 void WebRtcLoggingHandlerHost::CreateRtpDumpHandlerAndStart(
595     RtpDumpType type,
596     GenericDoneCallback callback,
597     const base::FilePath& dump_dir) {
598   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
599 
600   // |rtp_dump_handler_| may be non-NULL if StartRtpDump is called again before
601   // GetLogDirectoryAndEnsureExists returns on the FILE thread for a previous
602   // StartRtpDump.
603   if (!rtp_dump_handler_)
604     rtp_dump_handler_.reset(new WebRtcRtpDumpHandler(dump_dir));
605 
606   DoStartRtpDump(type, &callback);
607 }
608 
DoStartRtpDump(RtpDumpType type,GenericDoneCallback * callback)609 void WebRtcLoggingHandlerHost::DoStartRtpDump(RtpDumpType type,
610                                               GenericDoneCallback* callback) {
611   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
612   DCHECK(rtp_dump_handler_);
613 
614   std::string error;
615 
616   bool result = rtp_dump_handler_->StartDump(type, &error);
617   FireGenericDoneCallback(callback, result, error);
618 }
619