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