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/chromeos/settings/cros_settings_names.h"
     19 #include "chrome/browser/media/webrtc_log_uploader.h"
     20 #include "chrome/common/chrome_switches.h"
     21 #include "chrome/common/media/webrtc_logging_messages.h"
     22 #include "chrome/common/partial_circular_buffer.h"
     23 #include "chrome/common/pref_names.h"
     24 #include "content/public/browser/browser_thread.h"
     25 #include "content/public/browser/content_browser_client.h"
     26 #include "content/public/browser/render_process_host.h"
     27 #include "gpu/config/gpu_info.h"
     28 #include "gpu/config/gpu_info_collector.h"
     29 #include "net/base/address_family.h"
     30 #include "net/base/net_util.h"
     31 #include "net/url_request/url_request_context_getter.h"
     32 
     33 #if defined(OS_LINUX)
     34 #include "base/linux_util.h"
     35 #endif
     36 
     37 #if defined(OS_MACOSX)
     38 #include "base/mac/mac_util.h"
     39 #endif
     40 
     41 using base::IntToString;
     42 using content::BrowserThread;
     43 
     44 
     45 #if defined(OS_ANDROID)
     46 const size_t kWebRtcLogSize = 1 * 1024 * 1024;  // 1 MB
     47 #else
     48 const size_t kWebRtcLogSize = 6 * 1024 * 1024;  // 6 MB
     49 #endif
     50 
     51 namespace {
     52 
     53 // For privacy reasons when logging IP addresses. The returned "sensitive
     54 // string" is for release builds a string with the end stripped away. Last
     55 // octet for IPv4 and last 80 bits (5 groups) for IPv6. String will be
     56 // "1.2.3.x" and "1.2.3::" respectively. For debug builds, the string is
     57 // not stripped.
     58 std::string IPAddressToSensitiveString(const net::IPAddressNumber& address) {
     59 #if defined(NDEBUG)
     60   std::string sensitive_address;
     61   switch (net::GetAddressFamily(address)) {
     62     case net::ADDRESS_FAMILY_IPV4: {
     63       sensitive_address = net::IPAddressToString(address);
     64       size_t find_pos = sensitive_address.rfind('.');
     65       if (find_pos == std::string::npos)
     66         return std::string();
     67       sensitive_address.resize(find_pos);
     68       sensitive_address += ".x";
     69       break;
     70     }
     71     case net::ADDRESS_FAMILY_IPV6: {
     72       // TODO(grunell): Create a string of format "1:2:3:x:x:x:x:x" to clarify
     73       // that the end has been stripped out.
     74       net::IPAddressNumber sensitive_address_number = address;
     75       sensitive_address_number.resize(net::kIPv6AddressSize - 10);
     76       sensitive_address_number.resize(net::kIPv6AddressSize, 0);
     77       sensitive_address = net::IPAddressToString(sensitive_address_number);
     78       break;
     79     }
     80     case net::ADDRESS_FAMILY_UNSPECIFIED: {
     81       break;
     82     }
     83   }
     84   return sensitive_address;
     85 #else
     86   return net::IPAddressToString(address);
     87 #endif
     88 }
     89 
     90 }  // namespace
     91 
     92 WebRtcLoggingHandlerHost::WebRtcLoggingHandlerHost() {}
     93 
     94 WebRtcLoggingHandlerHost::~WebRtcLoggingHandlerHost() {}
     95 
     96 void WebRtcLoggingHandlerHost::OnChannelClosing() {
     97   UploadLog();
     98   content::BrowserMessageFilter::OnChannelClosing();
     99 }
    100 
    101 void WebRtcLoggingHandlerHost::OnDestruct() const {
    102   BrowserThread::DeleteOnIOThread::Destruct(this);
    103 }
    104 
    105 bool WebRtcLoggingHandlerHost::OnMessageReceived(const IPC::Message& message,
    106                                                  bool* message_was_ok) {
    107   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    108   bool handled = true;
    109   IPC_BEGIN_MESSAGE_MAP_EX(WebRtcLoggingHandlerHost, message, *message_was_ok)
    110     IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_OpenLog, OnOpenLog)
    111     IPC_MESSAGE_UNHANDLED(handled = false)
    112   IPC_END_MESSAGE_MAP_EX()
    113 
    114   return handled;
    115 }
    116 
    117 void WebRtcLoggingHandlerHost::OnOpenLog(const std::string& app_session_id,
    118                                          const std::string& app_url) {
    119   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    120   app_session_id_ = app_session_id;
    121   app_url_ = app_url;
    122   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
    123       &WebRtcLoggingHandlerHost::OpenLogIfAllowed, this));
    124 }
    125 
    126 void WebRtcLoggingHandlerHost::OpenLogIfAllowed() {
    127   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    128 
    129   // If the user permits metrics reporting / crash uploading with the checkbox
    130   // in the prefs, we allow uploading automatically. We disable uploading
    131   // completely for non-official builds. Allowing can be forced with a flag.
    132   const CommandLine* command_line = CommandLine::ForCurrentProcess();
    133   if (!command_line->HasSwitch(switches::kEnableMetricsReportingForTesting)) {
    134     bool enabled = false;
    135 #if defined(GOOGLE_CHROME_BUILD)
    136 #if defined(OS_CHROMEOS)
    137     chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
    138                                               &enabled);
    139 #elif defined(OS_ANDROID)
    140     // Android has its own settings for metrics / crash uploading.
    141     enabled = g_browser_process->local_state()->GetBoolean(
    142         prefs::kCrashReportingEnabled);
    143 #else
    144     enabled = g_browser_process->local_state()->GetBoolean(
    145         prefs::kMetricsReportingEnabled);
    146 #endif  // #if defined(OS_CHROMEOS)
    147 #endif  // defined(GOOGLE_CHROME_BUILD)
    148     if (!enabled)
    149       return;
    150   }
    151 
    152   if (!g_browser_process->webrtc_log_uploader()->ApplyForStartLogging())
    153     return;
    154 
    155   system_request_context_ = g_browser_process->system_request_context();
    156   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
    157       &WebRtcLoggingHandlerHost::DoOpenLog, this));
    158 }
    159 
    160 void WebRtcLoggingHandlerHost::DoOpenLog() {
    161   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    162   DCHECK(!shared_memory_);
    163 
    164   shared_memory_.reset(new base::SharedMemory());
    165 
    166   if (!shared_memory_->CreateAndMapAnonymous(kWebRtcLogSize)) {
    167     DLOG(ERROR) << "Failed to create shared memory.";
    168     Send(new WebRtcLoggingMsg_OpenLogFailed());
    169     return;
    170   }
    171 
    172   if (!shared_memory_->ShareToProcess(PeerHandle(),
    173                                      &foreign_memory_handle_)) {
    174     Send(new WebRtcLoggingMsg_OpenLogFailed());
    175     return;
    176   }
    177 
    178   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
    179       &WebRtcLoggingHandlerHost::LogMachineInfo, this));
    180 }
    181 
    182 void WebRtcLoggingHandlerHost::LogMachineInfo() {
    183   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    184   PartialCircularBuffer pcb(shared_memory_->memory(),
    185                             kWebRtcLogSize,
    186                             kWebRtcLogSize / 2,
    187                             false);
    188 
    189   // App session ID
    190   std::string info = "App session ID: " + app_session_id_ + '\n';
    191   pcb.Write(info.c_str(), info.length());
    192 
    193   // OS
    194   info = base::SysInfo::OperatingSystemName() + " " +
    195          base::SysInfo::OperatingSystemVersion() + " " +
    196          base::SysInfo::OperatingSystemArchitecture() + '\n';
    197   pcb.Write(info.c_str(), info.length());
    198 #if defined(OS_LINUX)
    199   info = "Linux distribution: " + base::GetLinuxDistro() + '\n';
    200   pcb.Write(info.c_str(), info.length());
    201 #endif
    202 
    203   // CPU
    204   base::CPU cpu;
    205   info = "Cpu: " + IntToString(cpu.family()) + "." + IntToString(cpu.model()) +
    206          "." + IntToString(cpu.stepping()) +
    207          ", x" + IntToString(base::SysInfo::NumberOfProcessors()) + ", " +
    208          IntToString(base::SysInfo::AmountOfPhysicalMemoryMB()) + "MB" + '\n';
    209   pcb.Write(info.c_str(), info.length());
    210   std::string cpu_brand = cpu.cpu_brand();
    211   // Workaround for crbug.com/249713.
    212   // TODO(grunell): Remove workaround when bug is fixed.
    213   size_t null_pos = cpu_brand.find('\0');
    214   if (null_pos != std::string::npos)
    215     cpu_brand.erase(null_pos);
    216   info = "Cpu brand: " + cpu_brand + '\n';
    217   pcb.Write(info.c_str(), info.length());
    218 
    219   // Computer model
    220 #if defined(OS_MACOSX)
    221   info = "Computer model: " + base::mac::GetModelIdentifier() + '\n';
    222 #else
    223   info = "Computer model: Not available\n";
    224 #endif
    225   pcb.Write(info.c_str(), info.length());
    226 
    227   // GPU
    228   gpu::GPUInfo gpu_info;
    229   gpu::CollectBasicGraphicsInfo(&gpu_info);
    230   info = "Gpu: machine-model='" + gpu_info.machine_model +
    231          "', vendor-id=" + IntToString(gpu_info.gpu.vendor_id) +
    232          ", device-id=" + IntToString(gpu_info.gpu.device_id) +
    233          ", driver-vendor='" + gpu_info.driver_vendor +
    234          "', driver-version=" + gpu_info.driver_version + '\n';
    235   pcb.Write(info.c_str(), info.length());
    236 
    237   // Network interfaces
    238   net::NetworkInterfaceList network_list;
    239   net::GetNetworkList(&network_list);
    240   info  = "Discovered " + IntToString(network_list.size()) +
    241           " network interfaces:" + '\n';
    242   pcb.Write(info.c_str(), info.length());
    243   for (net::NetworkInterfaceList::iterator it = network_list.begin();
    244        it != network_list.end(); ++it) {
    245     info = "Name: " + it->name +
    246            ", Address: " + IPAddressToSensitiveString(it->address) + '\n';
    247     pcb.Write(info.c_str(), info.length());
    248   }
    249 
    250   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
    251       &WebRtcLoggingHandlerHost::NotifyLogOpened, this));
    252 }
    253 
    254 void WebRtcLoggingHandlerHost::NotifyLogOpened() {
    255   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    256   Send(new WebRtcLoggingMsg_LogOpened(foreign_memory_handle_, kWebRtcLogSize));
    257 }
    258 
    259 void WebRtcLoggingHandlerHost::UploadLog() {
    260   if (!shared_memory_)
    261     return;
    262 
    263   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
    264       &WebRtcLogUploader::UploadLog,
    265       base::Unretained(g_browser_process->webrtc_log_uploader()),
    266       system_request_context_,
    267       Passed(&shared_memory_),
    268       kWebRtcLogSize,
    269       app_session_id_,
    270       app_url_));
    271 }
    272