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