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/files/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 }
    625