- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / media / webrtc_logging_handler_host.cc
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_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"
33
34 #if defined(OS_LINUX)
35 #include "base/linux_util.h"
36 #endif
37
38 #if defined(OS_MACOSX)
39 #include "base/mac/mac_util.h"
40 #endif
41
42 using base::IntToString;
43 using content::BrowserThread;
44
45
46 #if defined(OS_ANDROID)
47 const size_t kWebRtcLogSize = 1 * 1024 * 1024;  // 1 MB
48 #else
49 const size_t kWebRtcLogSize = 6 * 1024 * 1024;  // 6 MB
50 #endif
51
52 namespace {
53
54 const char kLogNotStoppedOrNoLogOpen[] =
55     "Logging not stopped or no log open.";
56
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
61 // not stripped.
62 std::string IPAddressToSensitiveString(const net::IPAddressNumber& address) {
63 #if defined(NDEBUG)
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)
70         return std::string();
71       sensitive_address.resize(find_pos);
72       sensitive_address += ".x";
73       break;
74     }
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);
82       break;
83     }
84     case net::ADDRESS_FAMILY_UNSPECIFIED: {
85       break;
86     }
87   }
88   return sensitive_address;
89 #else
90   return net::IPAddressToString(address);
91 #endif
92 }
93
94 }  // namespace
95
96 WebRtcLoggingHandlerHost::WebRtcLoggingHandlerHost(Profile* profile)
97     : profile_(profile),
98       logging_state_(CLOSED),
99       upload_log_on_render_close_(false) {
100   DCHECK(profile_);
101 }
102
103 WebRtcLoggingHandlerHost::~WebRtcLoggingHandlerHost() {}
104
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());
110
111   bool success = false;
112   std::string error_message;
113   if (logging_state_ == CLOSED) {
114     meta_data_ = meta_data;
115     success = true;
116   } else {
117     error_message = "Meta data must be set before starting";
118   }
119   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
120                                    base::Bind(callback, success,
121                                               error_message));
122 }
123
124 void WebRtcLoggingHandlerHost::StartLogging(
125     const GenericDoneCallback& callback) {
126   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
127   DCHECK(!callback.is_null());
128
129   start_callback_ = callback;
130   if (logging_state_ != CLOSED) {
131     FireGenericDoneCallback(&start_callback_, false, "A log is already open");
132     return;
133   }
134   logging_state_ = STARTING;
135   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
136       &WebRtcLoggingHandlerHost::StartLoggingIfAllowed, this));
137 }
138
139 void WebRtcLoggingHandlerHost::StopLogging(
140     const GenericDoneCallback& callback) {
141   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
142   DCHECK(!callback.is_null());
143
144   stop_callback_ = callback;
145   if (logging_state_ != STARTED) {
146     FireGenericDoneCallback(&stop_callback_, false, "Logging not started");
147     return;
148   }
149   logging_state_ = STOPPING;
150   Send(new WebRtcLoggingMsg_StopLogging());
151 }
152
153 void WebRtcLoggingHandlerHost::UploadLog(const UploadDoneCallback& callback) {
154   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
155   DCHECK(!callback.is_null());
156
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));
161     }
162     return;
163   }
164   upload_callback_ = callback;
165   TriggerUploadLog();
166 }
167
168 void WebRtcLoggingHandlerHost::UploadLogDone() {
169   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
170   logging_state_ = CLOSED;
171 }
172
173 void WebRtcLoggingHandlerHost::DiscardLog(const GenericDoneCallback& callback) {
174   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
175   DCHECK(!callback.is_null());
176
177   GenericDoneCallback discard_callback = callback;
178   if (logging_state_ != STOPPED) {
179     FireGenericDoneCallback(&discard_callback, false,
180                             kLogNotStoppedOrNoLogOpen);
181     return;
182   }
183   g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload();
184   shared_memory_.reset(NULL);
185   logging_state_ = CLOSED;
186   FireGenericDoneCallback(&discard_callback, true, "");
187 }
188
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;
194       TriggerUploadLog();
195     } else {
196       g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload();
197     }
198   }
199   content::BrowserMessageFilter::OnChannelClosing();
200 }
201
202 void WebRtcLoggingHandlerHost::OnDestruct() const {
203   BrowserThread::DeleteOnIOThread::Destruct(this);
204 }
205
206 bool WebRtcLoggingHandlerHost::OnMessageReceived(const IPC::Message& message,
207                                                  bool* message_was_ok) {
208   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
209   bool handled = true;
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()
215
216   return handled;
217 }
218
219 void WebRtcLoggingHandlerHost::OnLoggingStoppedInRenderer() {
220   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
221   logging_state_ = STOPPED;
222   FireGenericDoneCallback(&stop_callback_, true, "");
223 }
224
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.");
232     return;
233   }
234   system_request_context_ = g_browser_process->system_request_context();
235   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
236       &WebRtcLoggingHandlerHost::DoStartLogging, this));
237 }
238
239 void WebRtcLoggingHandlerHost::DoStartLogging() {
240   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
241   DCHECK(!shared_memory_);
242
243   shared_memory_.reset(new base::SharedMemory());
244
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);
250     return;
251   }
252
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);
260     return;
261   }
262
263   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
264       &WebRtcLoggingHandlerHost::LogMachineInfo, this));
265 }
266
267 void WebRtcLoggingHandlerHost::LogMachineInfo() {
268   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
269   PartialCircularBuffer pcb(shared_memory_->memory(),
270                             kWebRtcLogSize,
271                             kWebRtcLogSize / 2,
272                             false);
273
274   // Meta data
275   std::string info;
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());
280   }
281
282   // OS
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());
290 #endif
291
292   // CPU
293   base::CPU cpu;
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());
307
308   // Computer model
309 #if defined(OS_MACOSX)
310   info = "Computer model: " + base::mac::GetModelIdentifier() + '\n';
311 #else
312   info = "Computer model: Not available\n";
313 #endif
314   pcb.Write(info.c_str(), info.length());
315
316   // GPU
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());
324
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());
336   }
337
338   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
339       &WebRtcLoggingHandlerHost::NotifyLoggingStarted, this));
340 }
341
342 void WebRtcLoggingHandlerHost::NotifyLoggingStarted() {
343   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
344   Send(new WebRtcLoggingMsg_StartLogging(foreign_memory_handle_,
345                                          kWebRtcLogSize));
346   logging_state_ = STARTED;
347   FireGenericDoneCallback(&start_callback_, true, "");
348 }
349
350 void WebRtcLoggingHandlerHost::TriggerUploadLog() {
351   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
352   DCHECK(logging_state_ == STOPPED);
353
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();
360
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_),
366       kWebRtcLogSize,
367       meta_data_,
368       upload_done_data));
369
370   meta_data_.clear();
371 }
372
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,
380                                               error_message));
381   (*callback).Reset();
382 }