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/files/file_util.h"
13 #include "base/logging.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/sys_info.h"
17 #include "base/time/time.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/chromeos/settings/cros_settings.h"
20 #include "chrome/browser/media/webrtc_log_list.h"
21 #include "chrome/browser/media/webrtc_log_uploader.h"
22 #include "chrome/browser/media/webrtc_rtp_dump_handler.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/common/chrome_switches.h"
25 #include "chrome/common/chrome_version_info.h"
26 #include "chrome/common/media/webrtc_logging_messages.h"
27 #include "chrome/common/partial_circular_buffer.h"
28 #include "chrome/common/pref_names.h"
29 #include "chromeos/settings/cros_settings_names.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "content/public/browser/content_browser_client.h"
32 #include "content/public/browser/gpu_data_manager.h"
33 #include "content/public/browser/render_process_host.h"
34 #include "gpu/config/gpu_info.h"
35 #include "net/base/address_family.h"
36 #include "net/url_request/url_request_context_getter.h"
37
38 #if defined(OS_LINUX)
39 #include "base/linux_util.h"
40 #endif
41
42 #if defined(OS_MACOSX)
43 #include "base/mac/mac_util.h"
44 #endif
45
46 #if defined(OS_CHROMEOS)
47 #include "chromeos/system/statistics_provider.h"
48 #endif
49
50 using base::IntToString;
51 using content::BrowserThread;
52
53 namespace {
54
55 #if defined(OS_ANDROID)
56 const size_t kWebRtcLogSize = 1 * 1024 * 1024; // 1 MB
57 #else
58 const size_t kWebRtcLogSize = 6 * 1024 * 1024; // 6 MB
59 #endif
60
61 const char kLogNotStoppedOrNoLogOpen[] =
62 "Logging not stopped or no log open.";
63
64 // For privacy reasons when logging IP addresses. The returned "sensitive
65 // string" is for release builds a string with the end stripped away. Last
66 // octet for IPv4 and last 80 bits (5 groups) for IPv6. String will be
67 // "1.2.3.x" and "1.2.3::" respectively. For debug builds, the string is
68 // not stripped.
IPAddressToSensitiveString(const net::IPAddressNumber & address)69 std::string IPAddressToSensitiveString(const net::IPAddressNumber& address) {
70 #if defined(NDEBUG)
71 std::string sensitive_address;
72 switch (net::GetAddressFamily(address)) {
73 case net::ADDRESS_FAMILY_IPV4: {
74 sensitive_address = net::IPAddressToString(address);
75 size_t find_pos = sensitive_address.rfind('.');
76 if (find_pos == std::string::npos)
77 return std::string();
78 sensitive_address.resize(find_pos);
79 sensitive_address += ".x";
80 break;
81 }
82 case net::ADDRESS_FAMILY_IPV6: {
83 // TODO(grunell): Create a string of format "1:2:3:x:x:x:x:x" to clarify
84 // that the end has been stripped out.
85 net::IPAddressNumber sensitive_address_number = address;
86 sensitive_address_number.resize(net::kIPv6AddressSize - 10);
87 sensitive_address_number.resize(net::kIPv6AddressSize, 0);
88 sensitive_address = net::IPAddressToString(sensitive_address_number);
89 break;
90 }
91 case net::ADDRESS_FAMILY_UNSPECIFIED: {
92 break;
93 }
94 }
95 return sensitive_address;
96 #else
97 return net::IPAddressToString(address);
98 #endif
99 }
100
FormatMetaDataAsLogMessage(const MetaDataMap & meta_data,std::string * message)101 void FormatMetaDataAsLogMessage(
102 const MetaDataMap& meta_data,
103 std::string* message) {
104 for (MetaDataMap::const_iterator it = meta_data.begin();
105 it != meta_data.end(); ++it) {
106 *message += it->first + ": " + it->second + '\n';
107 }
108 // Remove last '\n'.
109 message->resize(message->size() - 1);
110 }
111
112 } // namespace
113
WebRtcLoggingHandlerHost(Profile * profile)114 WebRtcLoggingHandlerHost::WebRtcLoggingHandlerHost(Profile* profile)
115 : BrowserMessageFilter(WebRtcLoggingMsgStart),
116 profile_(profile),
117 logging_state_(CLOSED),
118 upload_log_on_render_close_(false) {
119 DCHECK(profile_);
120 }
121
~WebRtcLoggingHandlerHost()122 WebRtcLoggingHandlerHost::~WebRtcLoggingHandlerHost() {}
123
SetMetaData(const MetaDataMap & meta_data,const GenericDoneCallback & callback)124 void WebRtcLoggingHandlerHost::SetMetaData(
125 const MetaDataMap& meta_data,
126 const GenericDoneCallback& callback) {
127 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
128 DCHECK(!callback.is_null());
129
130 std::string error_message;
131 if (logging_state_ == CLOSED) {
132 meta_data_ = meta_data;
133 } else if (logging_state_ == STARTED) {
134 meta_data_ = meta_data;
135 std::string meta_data_message;
136 FormatMetaDataAsLogMessage(meta_data_, &meta_data_message);
137 LogToCircularBuffer(meta_data_message);
138 } else {
139 error_message = "Meta data must be set before stop or upload.";
140 }
141 bool success = error_message.empty();
142 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
143 base::Bind(callback, success,
144 error_message));
145 }
146
StartLogging(const GenericDoneCallback & callback)147 void WebRtcLoggingHandlerHost::StartLogging(
148 const GenericDoneCallback& callback) {
149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
150 DCHECK(!callback.is_null());
151
152 start_callback_ = callback;
153 if (logging_state_ != CLOSED) {
154 FireGenericDoneCallback(&start_callback_, false, "A log is already open");
155 return;
156 }
157 logging_state_ = STARTING;
158 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
159 &WebRtcLoggingHandlerHost::StartLoggingIfAllowed, this));
160 }
161
StopLogging(const GenericDoneCallback & callback)162 void WebRtcLoggingHandlerHost::StopLogging(
163 const GenericDoneCallback& callback) {
164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
165 DCHECK(!callback.is_null());
166
167 stop_callback_ = callback;
168 if (logging_state_ != STARTED) {
169 FireGenericDoneCallback(&stop_callback_, false, "Logging not started");
170 return;
171 }
172 logging_state_ = STOPPING;
173 Send(new WebRtcLoggingMsg_StopLogging());
174 }
175
UploadLog(const UploadDoneCallback & callback)176 void WebRtcLoggingHandlerHost::UploadLog(const UploadDoneCallback& callback) {
177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
178 DCHECK(!callback.is_null());
179
180 if (logging_state_ != STOPPED) {
181 if (!callback.is_null()) {
182 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
183 base::Bind(callback, false, "", kLogNotStoppedOrNoLogOpen));
184 }
185 return;
186 }
187
188 upload_callback_ = callback;
189 logging_state_ = UPLOADING;
190 content::BrowserThread::PostTaskAndReplyWithResult(
191 content::BrowserThread::FILE,
192 FROM_HERE,
193 base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
194 this),
195 base::Bind(&WebRtcLoggingHandlerHost::TriggerUpload, this));
196 }
197
UploadLogDone()198 void WebRtcLoggingHandlerHost::UploadLogDone() {
199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
200 logging_state_ = CLOSED;
201 }
202
DiscardLog(const GenericDoneCallback & callback)203 void WebRtcLoggingHandlerHost::DiscardLog(const GenericDoneCallback& callback) {
204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
205 DCHECK(!callback.is_null());
206
207 GenericDoneCallback discard_callback = callback;
208 if (logging_state_ != STOPPED) {
209 FireGenericDoneCallback(&discard_callback, false,
210 kLogNotStoppedOrNoLogOpen);
211 return;
212 }
213 g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload();
214 circular_buffer_.reset();
215 log_buffer_.reset();
216 logging_state_ = CLOSED;
217 rtp_dump_handler_.reset();
218 stop_rtp_dump_callback_.Reset();
219 FireGenericDoneCallback(&discard_callback, true, "");
220 }
221
LogMessage(const std::string & message)222 void WebRtcLoggingHandlerHost::LogMessage(const std::string& message) {
223 BrowserThread::PostTask(
224 BrowserThread::IO,
225 FROM_HERE,
226 base::Bind(
227 &WebRtcLoggingHandlerHost::AddLogMessageFromBrowser,
228 this,
229 WebRtcLoggingMessageData(base::Time::Now(), message)));
230 }
231
StartRtpDump(RtpDumpType type,const GenericDoneCallback & callback,const content::RenderProcessHost::WebRtcStopRtpDumpCallback & stop_callback)232 void WebRtcLoggingHandlerHost::StartRtpDump(
233 RtpDumpType type,
234 const GenericDoneCallback& callback,
235 const content::RenderProcessHost::WebRtcStopRtpDumpCallback&
236 stop_callback) {
237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
238 DCHECK(stop_rtp_dump_callback_.is_null() ||
239 stop_rtp_dump_callback_.Equals(stop_callback));
240
241 stop_rtp_dump_callback_ = stop_callback;
242
243 if (!rtp_dump_handler_) {
244 content::BrowserThread::PostTaskAndReplyWithResult(
245 content::BrowserThread::FILE,
246 FROM_HERE,
247 base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
248 this),
249 base::Bind(&WebRtcLoggingHandlerHost::CreateRtpDumpHandlerAndStart,
250 this,
251 type,
252 callback));
253 return;
254 }
255
256 GenericDoneCallback start_callback = callback;
257 DoStartRtpDump(type, &start_callback);
258 }
259
StopRtpDump(RtpDumpType type,const GenericDoneCallback & callback)260 void WebRtcLoggingHandlerHost::StopRtpDump(
261 RtpDumpType type,
262 const GenericDoneCallback& callback) {
263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
264 DCHECK(!callback.is_null());
265
266 if (!rtp_dump_handler_) {
267 GenericDoneCallback stop_callback = callback;
268 FireGenericDoneCallback(
269 &stop_callback, false, "RTP dump has not been started.");
270 return;
271 }
272
273 if (!stop_rtp_dump_callback_.is_null()) {
274 BrowserThread::PostTask(
275 BrowserThread::UI,
276 FROM_HERE,
277 base::Bind(stop_rtp_dump_callback_,
278 type == RTP_DUMP_INCOMING || type == RTP_DUMP_BOTH,
279 type == RTP_DUMP_OUTGOING || type == RTP_DUMP_BOTH));
280 }
281
282 rtp_dump_handler_->StopDump(type, callback);
283 }
284
OnRtpPacket(scoped_ptr<uint8[]> packet_header,size_t header_length,size_t packet_length,bool incoming)285 void WebRtcLoggingHandlerHost::OnRtpPacket(scoped_ptr<uint8[]> packet_header,
286 size_t header_length,
287 size_t packet_length,
288 bool incoming) {
289 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
290
291 BrowserThread::PostTask(
292 BrowserThread::IO,
293 FROM_HERE,
294 base::Bind(&WebRtcLoggingHandlerHost::DumpRtpPacketOnIOThread,
295 this,
296 base::Passed(&packet_header),
297 header_length,
298 packet_length,
299 incoming));
300 }
301
DumpRtpPacketOnIOThread(scoped_ptr<uint8[]> packet_header,size_t header_length,size_t packet_length,bool incoming)302 void WebRtcLoggingHandlerHost::DumpRtpPacketOnIOThread(
303 scoped_ptr<uint8[]> packet_header,
304 size_t header_length,
305 size_t packet_length,
306 bool incoming) {
307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
308
309 // |rtp_dump_handler_| could be NULL if we are waiting for the FILE thread to
310 // create/ensure the log directory.
311 if (rtp_dump_handler_) {
312 rtp_dump_handler_->OnRtpPacket(
313 packet_header.get(), header_length, packet_length, incoming);
314 }
315 }
316
OnChannelClosing()317 void WebRtcLoggingHandlerHost::OnChannelClosing() {
318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
319 if (logging_state_ == STARTED || logging_state_ == STOPPED) {
320 if (upload_log_on_render_close_) {
321 logging_state_ = UPLOADING;
322 logging_started_time_ = base::Time();
323
324 content::BrowserThread::PostTaskAndReplyWithResult(
325 content::BrowserThread::FILE,
326 FROM_HERE,
327 base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
328 this),
329 base::Bind(&WebRtcLoggingHandlerHost::TriggerUpload, this));
330 } else {
331 g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload();
332 }
333 }
334 content::BrowserMessageFilter::OnChannelClosing();
335 }
336
OnDestruct() const337 void WebRtcLoggingHandlerHost::OnDestruct() const {
338 BrowserThread::DeleteOnIOThread::Destruct(this);
339 }
340
OnMessageReceived(const IPC::Message & message)341 bool WebRtcLoggingHandlerHost::OnMessageReceived(const IPC::Message& message) {
342 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
343 bool handled = true;
344 IPC_BEGIN_MESSAGE_MAP(WebRtcLoggingHandlerHost, message)
345 IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_AddLogMessages, OnAddLogMessages)
346 IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_LoggingStopped,
347 OnLoggingStoppedInRenderer)
348 IPC_MESSAGE_UNHANDLED(handled = false)
349 IPC_END_MESSAGE_MAP()
350
351 return handled;
352 }
353
AddLogMessageFromBrowser(const WebRtcLoggingMessageData & message)354 void WebRtcLoggingHandlerHost::AddLogMessageFromBrowser(
355 const WebRtcLoggingMessageData& message) {
356 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
357 if (logging_state_ == STARTED)
358 LogToCircularBuffer(message.Format(logging_started_time_));
359 }
360
OnAddLogMessages(const std::vector<WebRtcLoggingMessageData> & messages)361 void WebRtcLoggingHandlerHost::OnAddLogMessages(
362 const std::vector<WebRtcLoggingMessageData>& messages) {
363 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
364 if (logging_state_ == STARTED || logging_state_ == STOPPING) {
365 for (size_t i = 0; i < messages.size(); ++i) {
366 LogToCircularBuffer(messages[i].Format(logging_started_time_));
367 }
368 }
369 }
370
OnLoggingStoppedInRenderer()371 void WebRtcLoggingHandlerHost::OnLoggingStoppedInRenderer() {
372 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
373 if (logging_state_ != STOPPING) {
374 // If an out-of-order response is received, stop_callback_ may be invalid,
375 // and must not be invoked.
376 DLOG(ERROR) << "OnLoggingStoppedInRenderer invoked in state "
377 << logging_state_;
378 BadMessageReceived();
379 return;
380 }
381 logging_started_time_ = base::Time();
382 logging_state_ = STOPPED;
383 FireGenericDoneCallback(&stop_callback_, true, "");
384 }
385
StartLoggingIfAllowed()386 void WebRtcLoggingHandlerHost::StartLoggingIfAllowed() {
387 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
388 if (!g_browser_process->webrtc_log_uploader()->ApplyForStartLogging()) {
389 logging_state_ = CLOSED;
390 FireGenericDoneCallback(
391 &start_callback_, false, "Cannot start, maybe the maximum number of "
392 "simultaneuos logs has been reached.");
393 return;
394 }
395 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
396 &WebRtcLoggingHandlerHost::DoStartLogging, this));
397 }
398
DoStartLogging()399 void WebRtcLoggingHandlerHost::DoStartLogging() {
400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
401
402 log_buffer_.reset(new unsigned char[kWebRtcLogSize]);
403 circular_buffer_.reset(
404 new PartialCircularBuffer(log_buffer_.get(),
405 kWebRtcLogSize,
406 kWebRtcLogSize / 2,
407 false));
408
409 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
410 &WebRtcLoggingHandlerHost::LogInitialInfoOnFileThread, this));
411 }
412
LogInitialInfoOnFileThread()413 void WebRtcLoggingHandlerHost::LogInitialInfoOnFileThread() {
414 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
415
416 net::NetworkInterfaceList network_list;
417 net::GetNetworkList(&network_list,
418 net::EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES);
419
420 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
421 &WebRtcLoggingHandlerHost::LogInitialInfoOnIOThread, this, network_list));
422 }
423
LogInitialInfoOnIOThread(const net::NetworkInterfaceList & network_list)424 void WebRtcLoggingHandlerHost::LogInitialInfoOnIOThread(
425 const net::NetworkInterfaceList& network_list) {
426 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
427
428 // Log start time (current time). We don't use base/i18n/time_formatting.h
429 // here because we don't want the format of the current locale.
430 base::Time::Exploded now = {0};
431 base::Time::Now().LocalExplode(&now);
432 LogToCircularBuffer(base::StringPrintf(
433 "Start %d-%02d-%02d %02d:%02d:%02d", now.year, now.month,
434 now.day_of_month, now.hour, now.minute, now.second));
435
436 // Write metadata if received before logging started.
437 if (!meta_data_.empty()) {
438 std::string info;
439 FormatMetaDataAsLogMessage(meta_data_, &info);
440 LogToCircularBuffer(info);
441 }
442
443 // Chrome version
444 chrome::VersionInfo version_info;
445 LogToCircularBuffer("Chrome version: " + version_info.Version() + " " +
446 chrome::VersionInfo::GetVersionStringModifier());
447
448 // OS
449 LogToCircularBuffer(base::SysInfo::OperatingSystemName() + " " +
450 base::SysInfo::OperatingSystemVersion() + " " +
451 base::SysInfo::OperatingSystemArchitecture());
452 #if defined(OS_LINUX)
453 LogToCircularBuffer("Linux distribution: " + base::GetLinuxDistro());
454 #endif
455
456 // CPU
457 base::CPU cpu;
458 LogToCircularBuffer(
459 "Cpu: " + IntToString(cpu.family()) + "." + IntToString(cpu.model()) +
460 "." + IntToString(cpu.stepping()) + ", x" +
461 IntToString(base::SysInfo::NumberOfProcessors()) + ", " +
462 IntToString(base::SysInfo::AmountOfPhysicalMemoryMB()) + "MB");
463 std::string cpu_brand = cpu.cpu_brand();
464 // Workaround for crbug.com/249713.
465 // TODO(grunell): Remove workaround when bug is fixed.
466 size_t null_pos = cpu_brand.find('\0');
467 if (null_pos != std::string::npos)
468 cpu_brand.erase(null_pos);
469 LogToCircularBuffer("Cpu brand: " + cpu_brand);
470
471 // Computer model
472 std::string computer_model = "Not available";
473 #if defined(OS_MACOSX)
474 computer_model = base::mac::GetModelIdentifier();
475 #elif defined(OS_CHROMEOS)
476 chromeos::system::StatisticsProvider::GetInstance()->
477 GetMachineStatistic(chromeos::system::kHardwareClassKey, &computer_model);
478 #endif
479 LogToCircularBuffer("Computer model: " + computer_model);
480
481 // GPU
482 gpu::GPUInfo gpu_info = content::GpuDataManager::GetInstance()->GetGPUInfo();
483 LogToCircularBuffer(
484 "Gpu: machine-model-name=" + gpu_info.machine_model_name +
485 ", machine-model-version=" + gpu_info.machine_model_version +
486 ", vendor-id=" + IntToString(gpu_info.gpu.vendor_id) +
487 ", device-id=" + IntToString(gpu_info.gpu.device_id) +
488 ", driver-vendor=" + gpu_info.driver_vendor +
489 ", driver-version=" + gpu_info.driver_version);
490 LogToCircularBuffer(
491 "OpenGL: gl-vendor=" + gpu_info.gl_vendor +
492 ", gl-renderer=" + gpu_info.gl_renderer +
493 ", gl-version=" + gpu_info.gl_version);
494
495 // Network interfaces
496 LogToCircularBuffer("Discovered " + IntToString(network_list.size()) +
497 " network interfaces:");
498 for (net::NetworkInterfaceList::const_iterator it = network_list.begin();
499 it != network_list.end(); ++it) {
500 LogToCircularBuffer("Name: " + it->friendly_name + ", Address: " +
501 IPAddressToSensitiveString(it->address));
502 }
503
504 NotifyLoggingStarted();
505 }
506
NotifyLoggingStarted()507 void WebRtcLoggingHandlerHost::NotifyLoggingStarted() {
508 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
509 Send(new WebRtcLoggingMsg_StartLogging());
510 logging_started_time_ = base::Time::Now();
511 logging_state_ = STARTED;
512 FireGenericDoneCallback(&start_callback_, true, "");
513 }
514
LogToCircularBuffer(const std::string & message)515 void WebRtcLoggingHandlerHost::LogToCircularBuffer(const std::string& message) {
516 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
517 DCHECK(circular_buffer_.get());
518 circular_buffer_->Write(message.c_str(), message.length());
519 const char eol = '\n';
520 circular_buffer_->Write(&eol, 1);
521 }
522
GetLogDirectoryAndEnsureExists()523 base::FilePath WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists() {
524 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
525 base::FilePath log_dir_path =
526 WebRtcLogList::GetWebRtcLogDirectoryForProfile(profile_->GetPath());
527 base::File::Error error;
528 if (!base::CreateDirectoryAndGetError(log_dir_path, &error)) {
529 DLOG(ERROR) << "Could not create WebRTC log directory, error: " << error;
530 return base::FilePath();
531 }
532 return log_dir_path;
533 }
534
TriggerUpload(const base::FilePath & log_directory)535 void WebRtcLoggingHandlerHost::TriggerUpload(
536 const base::FilePath& log_directory) {
537 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
538 DCHECK_EQ(logging_state_, UPLOADING);
539
540 if (rtp_dump_handler_) {
541 BrowserThread::PostTask(
542 BrowserThread::UI,
543 FROM_HERE,
544 base::Bind(stop_rtp_dump_callback_, true, true));
545
546 rtp_dump_handler_->StopOngoingDumps(
547 base::Bind(&WebRtcLoggingHandlerHost::DoUploadLogAndRtpDumps,
548 this,
549 log_directory));
550 return;
551 }
552
553 DoUploadLogAndRtpDumps(log_directory);
554 }
555
DoUploadLogAndRtpDumps(const base::FilePath & log_directory)556 void WebRtcLoggingHandlerHost::DoUploadLogAndRtpDumps(
557 const base::FilePath& log_directory) {
558 WebRtcLogUploadDoneData upload_done_data;
559 upload_done_data.log_path = log_directory;
560
561 if (rtp_dump_handler_) {
562 WebRtcRtpDumpHandler::ReleasedDumps rtp_dumps(
563 rtp_dump_handler_->ReleaseDumps());
564 upload_done_data.incoming_rtp_dump = rtp_dumps.incoming_dump_path;
565 upload_done_data.outgoing_rtp_dump = rtp_dumps.outgoing_dump_path;
566
567 rtp_dump_handler_.reset();
568 stop_rtp_dump_callback_.Reset();
569 }
570
571 upload_done_data.callback = upload_callback_;
572 upload_done_data.host = this;
573 upload_callback_.Reset();
574
575 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
576 &WebRtcLogUploader::LoggingStoppedDoUpload,
577 base::Unretained(g_browser_process->webrtc_log_uploader()),
578 Passed(&log_buffer_),
579 kWebRtcLogSize,
580 meta_data_,
581 upload_done_data));
582
583 meta_data_.clear();
584 circular_buffer_.reset();
585 }
586
FireGenericDoneCallback(GenericDoneCallback * callback,bool success,const std::string & error_message)587 void WebRtcLoggingHandlerHost::FireGenericDoneCallback(
588 GenericDoneCallback* callback,
589 bool success,
590 const std::string& error_message) {
591 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
592 DCHECK(!(*callback).is_null());
593 content::BrowserThread::PostTask(
594 content::BrowserThread::UI,
595 FROM_HERE,
596 base::Bind(*callback, success, error_message));
597 (*callback).Reset();
598 }
599
CreateRtpDumpHandlerAndStart(RtpDumpType type,GenericDoneCallback callback,const base::FilePath & dump_dir)600 void WebRtcLoggingHandlerHost::CreateRtpDumpHandlerAndStart(
601 RtpDumpType type,
602 GenericDoneCallback callback,
603 const base::FilePath& dump_dir) {
604 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
605
606 // |rtp_dump_handler_| may be non-NULL if StartRtpDump is called again before
607 // GetLogDirectoryAndEnsureExists returns on the FILE thread for a previous
608 // StartRtpDump.
609 if (!rtp_dump_handler_)
610 rtp_dump_handler_.reset(new WebRtcRtpDumpHandler(dump_dir));
611
612 DoStartRtpDump(type, &callback);
613 }
614
DoStartRtpDump(RtpDumpType type,GenericDoneCallback * callback)615 void WebRtcLoggingHandlerHost::DoStartRtpDump(RtpDumpType type,
616 GenericDoneCallback* callback) {
617 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
618 DCHECK(rtp_dump_handler_);
619
620 std::string error;
621
622 bool result = rtp_dump_handler_->StartDump(type, &error);
623 FireGenericDoneCallback(callback, result, error);
624 }
625