Home | History | Annotate | Download | only in media
      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.
     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 
    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 
    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 
    121 WebRtcLoggingHandlerHost::~WebRtcLoggingHandlerHost() {}
    122 
    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 
    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 
    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 
    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 
    197 void WebRtcLoggingHandlerHost::UploadLogDone() {
    198   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    199   logging_state_ = CLOSED;
    200 }
    201 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    336 void WebRtcLoggingHandlerHost::OnDestruct() const {
    337   BrowserThread::DeleteOnIOThread::Destruct(this);
    338 }
    339 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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