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/logging.h"
     13 #include "base/prefs/pref_service.h"
     14 #include "base/strings/string_number_conversions.h"
     15 #include "base/sys_info.h"
     16 #include "chrome/browser/browser_process.h"
     17 #include "chrome/browser/chromeos/settings/cros_settings.h"
     18 #include "chrome/browser/media/webrtc_log_upload_list.h"
     19 #include "chrome/browser/media/webrtc_log_uploader.h"
     20 #include "chrome/browser/profiles/profile.h"
     21 #include "chrome/common/chrome_switches.h"
     22 #include "chrome/common/media/webrtc_logging_messages.h"
     23 #include "chrome/common/partial_circular_buffer.h"
     24 #include "chrome/common/pref_names.h"
     25 #include "chromeos/settings/cros_settings_names.h"
     26 #include "content/public/browser/browser_thread.h"
     27 #include "content/public/browser/content_browser_client.h"
     28 #include "content/public/browser/gpu_data_manager.h"
     29 #include "content/public/browser/render_process_host.h"
     30 #include "gpu/config/gpu_info.h"
     31 #include "net/base/address_family.h"
     32 #include "net/base/net_util.h"
     33 #include "net/url_request/url_request_context_getter.h"
     34 
     35 #if defined(OS_LINUX)
     36 #include "base/linux_util.h"
     37 #endif
     38 
     39 #if defined(OS_MACOSX)
     40 #include "base/mac/mac_util.h"
     41 #endif
     42 
     43 using base::IntToString;
     44 using content::BrowserThread;
     45 
     46 
     47 #if defined(OS_ANDROID)
     48 const size_t kWebRtcLogSize = 1 * 1024 * 1024;  // 1 MB
     49 #else
     50 const size_t kWebRtcLogSize = 6 * 1024 * 1024;  // 6 MB
     51 #endif
     52 
     53 namespace {
     54 
     55 const char kLogNotStoppedOrNoLogOpen[] =
     56     "Logging not stopped or no log open.";
     57 
     58 // For privacy reasons when logging IP addresses. The returned "sensitive
     59 // string" is for release builds a string with the end stripped away. Last
     60 // octet for IPv4 and last 80 bits (5 groups) for IPv6. String will be
     61 // "1.2.3.x" and "1.2.3::" respectively. For debug builds, the string is
     62 // not stripped.
     63 std::string IPAddressToSensitiveString(const net::IPAddressNumber& address) {
     64 #if defined(NDEBUG)
     65   std::string sensitive_address;
     66   switch (net::GetAddressFamily(address)) {
     67     case net::ADDRESS_FAMILY_IPV4: {
     68       sensitive_address = net::IPAddressToString(address);
     69       size_t find_pos = sensitive_address.rfind('.');
     70       if (find_pos == std::string::npos)
     71         return std::string();
     72       sensitive_address.resize(find_pos);
     73       sensitive_address += ".x";
     74       break;
     75     }
     76     case net::ADDRESS_FAMILY_IPV6: {
     77       // TODO(grunell): Create a string of format "1:2:3:x:x:x:x:x" to clarify
     78       // that the end has been stripped out.
     79       net::IPAddressNumber sensitive_address_number = address;
     80       sensitive_address_number.resize(net::kIPv6AddressSize - 10);
     81       sensitive_address_number.resize(net::kIPv6AddressSize, 0);
     82       sensitive_address = net::IPAddressToString(sensitive_address_number);
     83       break;
     84     }
     85     case net::ADDRESS_FAMILY_UNSPECIFIED: {
     86       break;
     87     }
     88   }
     89   return sensitive_address;
     90 #else
     91   return net::IPAddressToString(address);
     92 #endif
     93 }
     94 
     95 }  // namespace
     96 
     97 WebRtcLoggingHandlerHost::WebRtcLoggingHandlerHost(Profile* profile)
     98     : profile_(profile),
     99       logging_state_(CLOSED),
    100       upload_log_on_render_close_(false) {
    101   DCHECK(profile_);
    102 }
    103 
    104 WebRtcLoggingHandlerHost::~WebRtcLoggingHandlerHost() {}
    105 
    106 void WebRtcLoggingHandlerHost::SetMetaData(
    107     const std::map<std::string, std::string>& meta_data,
    108     const GenericDoneCallback& callback) {
    109   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    110   DCHECK(!callback.is_null());
    111 
    112   bool success = false;
    113   std::string error_message;
    114   if (logging_state_ == CLOSED) {
    115     meta_data_ = meta_data;
    116     success = true;
    117   } else {
    118     error_message = "Meta data must be set before starting";
    119   }
    120   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
    121                                    base::Bind(callback, success,
    122                                               error_message));
    123 }
    124 
    125 void WebRtcLoggingHandlerHost::StartLogging(
    126     const GenericDoneCallback& callback) {
    127   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    128   DCHECK(!callback.is_null());
    129 
    130   start_callback_ = callback;
    131   if (logging_state_ != CLOSED) {
    132     FireGenericDoneCallback(&start_callback_, false, "A log is already open");
    133     return;
    134   }
    135   logging_state_ = STARTING;
    136   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
    137       &WebRtcLoggingHandlerHost::StartLoggingIfAllowed, this));
    138 }
    139 
    140 void WebRtcLoggingHandlerHost::StopLogging(
    141     const GenericDoneCallback& callback) {
    142   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    143   DCHECK(!callback.is_null());
    144 
    145   stop_callback_ = callback;
    146   if (logging_state_ != STARTED) {
    147     FireGenericDoneCallback(&stop_callback_, false, "Logging not started");
    148     return;
    149   }
    150   logging_state_ = STOPPING;
    151   Send(new WebRtcLoggingMsg_StopLogging());
    152 }
    153 
    154 void WebRtcLoggingHandlerHost::UploadLog(const UploadDoneCallback& callback) {
    155   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    156   DCHECK(!callback.is_null());
    157 
    158   if (logging_state_ != STOPPED) {
    159     if (!callback.is_null()) {
    160       content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
    161           base::Bind(callback, false, "", kLogNotStoppedOrNoLogOpen));
    162     }
    163     return;
    164   }
    165   upload_callback_ = callback;
    166   TriggerUploadLog();
    167 }
    168 
    169 void WebRtcLoggingHandlerHost::UploadLogDone() {
    170   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    171   logging_state_ = CLOSED;
    172 }
    173 
    174 void WebRtcLoggingHandlerHost::DiscardLog(const GenericDoneCallback& callback) {
    175   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    176   DCHECK(!callback.is_null());
    177 
    178   GenericDoneCallback discard_callback = callback;
    179   if (logging_state_ != STOPPED) {
    180     FireGenericDoneCallback(&discard_callback, false,
    181                             kLogNotStoppedOrNoLogOpen);
    182     return;
    183   }
    184   g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload();
    185   circular_buffer_.reset();
    186   log_buffer_.reset();
    187   logging_state_ = CLOSED;
    188   FireGenericDoneCallback(&discard_callback, true, "");
    189 }
    190 
    191 void WebRtcLoggingHandlerHost::OnChannelClosing() {
    192   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    193   if (logging_state_ == STARTED || logging_state_ == STOPPED) {
    194     if (upload_log_on_render_close_) {
    195       logging_state_ = STOPPED;
    196       TriggerUploadLog();
    197     } else {
    198       g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload();
    199     }
    200   }
    201   content::BrowserMessageFilter::OnChannelClosing();
    202 }
    203 
    204 void WebRtcLoggingHandlerHost::OnDestruct() const {
    205   BrowserThread::DeleteOnIOThread::Destruct(this);
    206 }
    207 
    208 bool WebRtcLoggingHandlerHost::OnMessageReceived(const IPC::Message& message,
    209                                                  bool* message_was_ok) {
    210   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    211   bool handled = true;
    212   IPC_BEGIN_MESSAGE_MAP_EX(WebRtcLoggingHandlerHost, message, *message_was_ok)
    213     IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_AddLogMessage, OnAddLogMessage)
    214     IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_LoggingStopped,
    215                         OnLoggingStoppedInRenderer)
    216     IPC_MESSAGE_UNHANDLED(handled = false)
    217   IPC_END_MESSAGE_MAP_EX()
    218 
    219   return handled;
    220 }
    221 
    222 void WebRtcLoggingHandlerHost::OnAddLogMessage(const std::string& message) {
    223   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    224   if (logging_state_ == STARTED || logging_state_ == STOPPING) {
    225     DCHECK(circular_buffer_.get());
    226     circular_buffer_->Write(message.c_str(), message.length());
    227     const char eol = '\n';
    228     circular_buffer_->Write(&eol, 1);
    229   }
    230 }
    231 
    232 void WebRtcLoggingHandlerHost::OnLoggingStoppedInRenderer() {
    233   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    234   logging_state_ = STOPPED;
    235   FireGenericDoneCallback(&stop_callback_, true, "");
    236 }
    237 
    238 void WebRtcLoggingHandlerHost::StartLoggingIfAllowed() {
    239   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    240   if (!g_browser_process->webrtc_log_uploader()->ApplyForStartLogging()) {
    241     logging_state_ = CLOSED;
    242       FireGenericDoneCallback(
    243           &start_callback_, false, "Cannot start, maybe the maximum number of "
    244           "simultaneuos logs has been reached.");
    245     return;
    246   }
    247   system_request_context_ = g_browser_process->system_request_context();
    248   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
    249       &WebRtcLoggingHandlerHost::DoStartLogging, this));
    250 }
    251 
    252 void WebRtcLoggingHandlerHost::DoStartLogging() {
    253   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    254 
    255   log_buffer_.reset(new unsigned char[kWebRtcLogSize]);
    256   circular_buffer_.reset(
    257     new PartialCircularBuffer(log_buffer_.get(),
    258                               kWebRtcLogSize,
    259                               kWebRtcLogSize / 2,
    260                               false));
    261 
    262   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
    263       &WebRtcLoggingHandlerHost::LogMachineInfo, this));
    264 }
    265 
    266 void WebRtcLoggingHandlerHost::LogMachineInfo() {
    267   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    268 
    269   // Meta data
    270   std::string info;
    271   std::map<std::string, std::string>::iterator it = meta_data_.begin();
    272   for (; it != meta_data_.end(); ++it) {
    273     info = it->first + ": " + it->second + '\n';
    274     circular_buffer_->Write(info.c_str(), info.length());
    275   }
    276 
    277   // OS
    278   info = base::SysInfo::OperatingSystemName() + " " +
    279          base::SysInfo::OperatingSystemVersion() + " " +
    280          base::SysInfo::OperatingSystemArchitecture() + '\n';
    281   circular_buffer_->Write(info.c_str(), info.length());
    282 #if defined(OS_LINUX)
    283   info = "Linux distribution: " + base::GetLinuxDistro() + '\n';
    284   circular_buffer_->Write(info.c_str(), info.length());
    285 #endif
    286 
    287   // CPU
    288   base::CPU cpu;
    289   info = "Cpu: " + IntToString(cpu.family()) + "." + IntToString(cpu.model()) +
    290          "." + IntToString(cpu.stepping()) +
    291          ", x" + IntToString(base::SysInfo::NumberOfProcessors()) + ", " +
    292          IntToString(base::SysInfo::AmountOfPhysicalMemoryMB()) + "MB" + '\n';
    293   circular_buffer_->Write(info.c_str(), info.length());
    294   std::string cpu_brand = cpu.cpu_brand();
    295   // Workaround for crbug.com/249713.
    296   // TODO(grunell): Remove workaround when bug is fixed.
    297   size_t null_pos = cpu_brand.find('\0');
    298   if (null_pos != std::string::npos)
    299     cpu_brand.erase(null_pos);
    300   info = "Cpu brand: " + cpu_brand + '\n';
    301   circular_buffer_->Write(info.c_str(), info.length());
    302 
    303   // Computer model
    304 #if defined(OS_MACOSX)
    305   info = "Computer model: " + base::mac::GetModelIdentifier() + '\n';
    306 #else
    307   info = "Computer model: Not available\n";
    308 #endif
    309   circular_buffer_->Write(info.c_str(), info.length());
    310 
    311   // GPU
    312   gpu::GPUInfo gpu_info = content::GpuDataManager::GetInstance()->GetGPUInfo();
    313   info = "Gpu: machine-model='" + gpu_info.machine_model +
    314          "', vendor-id=" + IntToString(gpu_info.gpu.vendor_id) +
    315          ", device-id=" + IntToString(gpu_info.gpu.device_id) +
    316          ", driver-vendor='" + gpu_info.driver_vendor +
    317          "', driver-version=" + gpu_info.driver_version + '\n';
    318   circular_buffer_->Write(info.c_str(), info.length());
    319 
    320   // Network interfaces
    321   net::NetworkInterfaceList network_list;
    322   net::GetNetworkList(&network_list);
    323   info  = "Discovered " + IntToString(network_list.size()) +
    324           " network interfaces:" + '\n';
    325   circular_buffer_->Write(info.c_str(), info.length());
    326   for (net::NetworkInterfaceList::iterator it = network_list.begin();
    327        it != network_list.end(); ++it) {
    328     info = "Name: " + it->name +
    329            ", Address: " + IPAddressToSensitiveString(it->address) + '\n';
    330     circular_buffer_->Write(info.c_str(), info.length());
    331   }
    332 
    333   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
    334       &WebRtcLoggingHandlerHost::NotifyLoggingStarted, this));
    335 }
    336 
    337 void WebRtcLoggingHandlerHost::NotifyLoggingStarted() {
    338   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    339   Send(new WebRtcLoggingMsg_StartLogging());
    340   logging_state_ = STARTED;
    341   FireGenericDoneCallback(&start_callback_, true, "");
    342 }
    343 
    344 void WebRtcLoggingHandlerHost::TriggerUploadLog() {
    345   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    346   DCHECK(logging_state_ == STOPPED);
    347 
    348   logging_state_ = UPLOADING;
    349   WebRtcLogUploadDoneData upload_done_data;
    350   upload_done_data.upload_list_path =
    351       WebRtcLogUploadList::GetFilePathForProfile(profile_);
    352   upload_done_data.callback = upload_callback_;
    353   upload_done_data.host = this;
    354   upload_callback_.Reset();
    355 
    356   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
    357       &WebRtcLogUploader::LoggingStoppedDoUpload,
    358       base::Unretained(g_browser_process->webrtc_log_uploader()),
    359       system_request_context_,
    360       Passed(&log_buffer_),
    361       kWebRtcLogSize,
    362       meta_data_,
    363       upload_done_data));
    364 
    365   meta_data_.clear();
    366   circular_buffer_.reset();
    367 }
    368 
    369 void WebRtcLoggingHandlerHost::FireGenericDoneCallback(
    370     GenericDoneCallback* callback, bool success,
    371     const std::string& error_message) {
    372   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    373   DCHECK(!(*callback).is_null());
    374   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
    375                                    base::Bind(*callback, success,
    376                                               error_message));
    377   (*callback).Reset();
    378 }
    379