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.
5 #include "chrome/browser/media/webrtc_logging_handler_host.h"
10 #include "base/command_line.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_uploader.h"
19 #include "chrome/browser/profiles/profile.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 "chromeos/settings/cros_settings_names.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/content_browser_client.h"
27 #include "content/public/browser/gpu_data_manager.h"
28 #include "content/public/browser/render_process_host.h"
29 #include "gpu/config/gpu_info.h"
30 #include "net/base/address_family.h"
31 #include "net/base/net_util.h"
32 #include "net/url_request/url_request_context_getter.h"
35 #include "base/linux_util.h"
38 #if defined(OS_MACOSX)
39 #include "base/mac/mac_util.h"
42 using base::IntToString;
43 using content::BrowserThread;
46 #if defined(OS_ANDROID)
47 const size_t kWebRtcLogSize = 1 * 1024 * 1024; // 1 MB
49 const size_t kWebRtcLogSize = 6 * 1024 * 1024; // 6 MB
54 const char kLogNotStoppedOrNoLogOpen[] =
55 "Logging not stopped or no log open.";
57 // For privacy reasons when logging IP addresses. The returned "sensitive
58 // string" is for release builds a string with the end stripped away. Last
59 // octet for IPv4 and last 80 bits (5 groups) for IPv6. String will be
60 // "1.2.3.x" and "1.2.3::" respectively. For debug builds, the string is
62 std::string IPAddressToSensitiveString(const net::IPAddressNumber& address) {
64 std::string sensitive_address;
65 switch (net::GetAddressFamily(address)) {
66 case net::ADDRESS_FAMILY_IPV4: {
67 sensitive_address = net::IPAddressToString(address);
68 size_t find_pos = sensitive_address.rfind('.');
69 if (find_pos == std::string::npos)
71 sensitive_address.resize(find_pos);
72 sensitive_address += ".x";
75 case net::ADDRESS_FAMILY_IPV6: {
76 // TODO(grunell): Create a string of format "1:2:3:x:x:x:x:x" to clarify
77 // that the end has been stripped out.
78 net::IPAddressNumber sensitive_address_number = address;
79 sensitive_address_number.resize(net::kIPv6AddressSize - 10);
80 sensitive_address_number.resize(net::kIPv6AddressSize, 0);
81 sensitive_address = net::IPAddressToString(sensitive_address_number);
84 case net::ADDRESS_FAMILY_UNSPECIFIED: {
88 return sensitive_address;
90 return net::IPAddressToString(address);
96 WebRtcLoggingHandlerHost::WebRtcLoggingHandlerHost(Profile* profile)
98 logging_state_(CLOSED),
99 upload_log_on_render_close_(false) {
103 WebRtcLoggingHandlerHost::~WebRtcLoggingHandlerHost() {}
105 void WebRtcLoggingHandlerHost::SetMetaData(
106 const std::map<std::string, std::string>& meta_data,
107 const GenericDoneCallback& callback) {
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
109 DCHECK(!callback.is_null());
111 bool success = false;
112 std::string error_message;
113 if (logging_state_ == CLOSED) {
114 meta_data_ = meta_data;
117 error_message = "Meta data must be set before starting";
119 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
120 base::Bind(callback, success,
124 void WebRtcLoggingHandlerHost::StartLogging(
125 const GenericDoneCallback& callback) {
126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
127 DCHECK(!callback.is_null());
129 start_callback_ = callback;
130 if (logging_state_ != CLOSED) {
131 FireGenericDoneCallback(&start_callback_, false, "A log is already open");
134 logging_state_ = STARTING;
135 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
136 &WebRtcLoggingHandlerHost::StartLoggingIfAllowed, this));
139 void WebRtcLoggingHandlerHost::StopLogging(
140 const GenericDoneCallback& callback) {
141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
142 DCHECK(!callback.is_null());
144 stop_callback_ = callback;
145 if (logging_state_ != STARTED) {
146 FireGenericDoneCallback(&stop_callback_, false, "Logging not started");
149 logging_state_ = STOPPING;
150 Send(new WebRtcLoggingMsg_StopLogging());
153 void WebRtcLoggingHandlerHost::UploadLog(const UploadDoneCallback& callback) {
154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
155 DCHECK(!callback.is_null());
157 if (logging_state_ != STOPPED) {
158 if (!callback.is_null()) {
159 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
160 base::Bind(callback, false, "", kLogNotStoppedOrNoLogOpen));
164 upload_callback_ = callback;
168 void WebRtcLoggingHandlerHost::UploadLogDone() {
169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
170 logging_state_ = CLOSED;
173 void WebRtcLoggingHandlerHost::DiscardLog(const GenericDoneCallback& callback) {
174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
175 DCHECK(!callback.is_null());
177 GenericDoneCallback discard_callback = callback;
178 if (logging_state_ != STOPPED) {
179 FireGenericDoneCallback(&discard_callback, false,
180 kLogNotStoppedOrNoLogOpen);
183 g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload();
184 shared_memory_.reset(NULL);
185 logging_state_ = CLOSED;
186 FireGenericDoneCallback(&discard_callback, true, "");
189 void WebRtcLoggingHandlerHost::OnChannelClosing() {
190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
191 if (logging_state_ == STARTED || logging_state_ == STOPPED) {
192 if (upload_log_on_render_close_) {
193 logging_state_ = STOPPED;
196 g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload();
199 content::BrowserMessageFilter::OnChannelClosing();
202 void WebRtcLoggingHandlerHost::OnDestruct() const {
203 BrowserThread::DeleteOnIOThread::Destruct(this);
206 bool WebRtcLoggingHandlerHost::OnMessageReceived(const IPC::Message& message,
207 bool* message_was_ok) {
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
210 IPC_BEGIN_MESSAGE_MAP_EX(WebRtcLoggingHandlerHost, message, *message_was_ok)
211 IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_LoggingStopped,
212 OnLoggingStoppedInRenderer)
213 IPC_MESSAGE_UNHANDLED(handled = false)
214 IPC_END_MESSAGE_MAP_EX()
219 void WebRtcLoggingHandlerHost::OnLoggingStoppedInRenderer() {
220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
221 logging_state_ = STOPPED;
222 FireGenericDoneCallback(&stop_callback_, true, "");
225 void WebRtcLoggingHandlerHost::StartLoggingIfAllowed() {
226 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
227 if (!g_browser_process->webrtc_log_uploader()->ApplyForStartLogging()) {
228 logging_state_ = CLOSED;
229 FireGenericDoneCallback(
230 &start_callback_, false, "Cannot start, maybe the maximum number of "
231 "simultaneuos logs has been reached.");
234 system_request_context_ = g_browser_process->system_request_context();
235 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
236 &WebRtcLoggingHandlerHost::DoStartLogging, this));
239 void WebRtcLoggingHandlerHost::DoStartLogging() {
240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
241 DCHECK(!shared_memory_);
243 shared_memory_.reset(new base::SharedMemory());
245 if (!shared_memory_->CreateAndMapAnonymous(kWebRtcLogSize)) {
246 const std::string error_message = "Failed to create shared memory";
247 DLOG(ERROR) << error_message;
248 logging_state_ = CLOSED;
249 FireGenericDoneCallback(&start_callback_, false, error_message);
253 if (!shared_memory_->ShareToProcess(PeerHandle(),
254 &foreign_memory_handle_)) {
255 const std::string error_message =
256 "Failed to share memory to render process";
257 DLOG(ERROR) << error_message;
258 logging_state_ = CLOSED;
259 FireGenericDoneCallback(&start_callback_, false, error_message);
263 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
264 &WebRtcLoggingHandlerHost::LogMachineInfo, this));
267 void WebRtcLoggingHandlerHost::LogMachineInfo() {
268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
269 PartialCircularBuffer pcb(shared_memory_->memory(),
276 std::map<std::string, std::string>::iterator it = meta_data_.begin();
277 for (; it != meta_data_.end(); ++it) {
278 info = it->first + ": " + it->second + '\n';
279 pcb.Write(info.c_str(), info.length());
283 info = base::SysInfo::OperatingSystemName() + " " +
284 base::SysInfo::OperatingSystemVersion() + " " +
285 base::SysInfo::OperatingSystemArchitecture() + '\n';
286 pcb.Write(info.c_str(), info.length());
287 #if defined(OS_LINUX)
288 info = "Linux distribution: " + base::GetLinuxDistro() + '\n';
289 pcb.Write(info.c_str(), info.length());
294 info = "Cpu: " + IntToString(cpu.family()) + "." + IntToString(cpu.model()) +
295 "." + IntToString(cpu.stepping()) +
296 ", x" + IntToString(base::SysInfo::NumberOfProcessors()) + ", " +
297 IntToString(base::SysInfo::AmountOfPhysicalMemoryMB()) + "MB" + '\n';
298 pcb.Write(info.c_str(), info.length());
299 std::string cpu_brand = cpu.cpu_brand();
300 // Workaround for crbug.com/249713.
301 // TODO(grunell): Remove workaround when bug is fixed.
302 size_t null_pos = cpu_brand.find('\0');
303 if (null_pos != std::string::npos)
304 cpu_brand.erase(null_pos);
305 info = "Cpu brand: " + cpu_brand + '\n';
306 pcb.Write(info.c_str(), info.length());
309 #if defined(OS_MACOSX)
310 info = "Computer model: " + base::mac::GetModelIdentifier() + '\n';
312 info = "Computer model: Not available\n";
314 pcb.Write(info.c_str(), info.length());
317 gpu::GPUInfo gpu_info = content::GpuDataManager::GetInstance()->GetGPUInfo();
318 info = "Gpu: machine-model='" + gpu_info.machine_model +
319 "', vendor-id=" + IntToString(gpu_info.gpu.vendor_id) +
320 ", device-id=" + IntToString(gpu_info.gpu.device_id) +
321 ", driver-vendor='" + gpu_info.driver_vendor +
322 "', driver-version=" + gpu_info.driver_version + '\n';
323 pcb.Write(info.c_str(), info.length());
325 // Network interfaces
326 net::NetworkInterfaceList network_list;
327 net::GetNetworkList(&network_list);
328 info = "Discovered " + IntToString(network_list.size()) +
329 " network interfaces:" + '\n';
330 pcb.Write(info.c_str(), info.length());
331 for (net::NetworkInterfaceList::iterator it = network_list.begin();
332 it != network_list.end(); ++it) {
333 info = "Name: " + it->name +
334 ", Address: " + IPAddressToSensitiveString(it->address) + '\n';
335 pcb.Write(info.c_str(), info.length());
338 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
339 &WebRtcLoggingHandlerHost::NotifyLoggingStarted, this));
342 void WebRtcLoggingHandlerHost::NotifyLoggingStarted() {
343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
344 Send(new WebRtcLoggingMsg_StartLogging(foreign_memory_handle_,
346 logging_state_ = STARTED;
347 FireGenericDoneCallback(&start_callback_, true, "");
350 void WebRtcLoggingHandlerHost::TriggerUploadLog() {
351 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
352 DCHECK(logging_state_ == STOPPED);
354 logging_state_ = UPLOADING;
355 WebRtcLogUploadDoneData upload_done_data;
356 upload_done_data.profile = profile_;
357 upload_done_data.callback = upload_callback_;
358 upload_done_data.host = this;
359 upload_callback_.Reset();
361 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
362 &WebRtcLogUploader::LoggingStoppedDoUpload,
363 base::Unretained(g_browser_process->webrtc_log_uploader()),
364 system_request_context_,
365 Passed(&shared_memory_),
373 void WebRtcLoggingHandlerHost::FireGenericDoneCallback(
374 GenericDoneCallback* callback, bool success,
375 const std::string& error_message) {
376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
377 DCHECK(!(*callback).is_null());
378 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
379 base::Bind(*callback, success,