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/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 "chromeos/settings/cros_settings_names.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/content_browser_client.h"
30 #include "content/public/browser/gpu_data_manager.h"
31 #include "content/public/browser/render_process_host.h"
32 #include "gpu/config/gpu_info.h"
33 #include "net/base/address_family.h"
34 #include "net/url_request/url_request_context_getter.h"
37 #include "base/linux_util.h"
40 #if defined(OS_MACOSX)
41 #include "base/mac/mac_util.h"
44 #if defined(OS_CHROMEOS)
45 #include "chromeos/system/statistics_provider.h"
48 using base::IntToString
;
49 using content::BrowserThread
;
53 const char kLogNotStoppedOrNoLogOpen
[] =
54 "Logging not stopped or no log open.";
56 // For privacy reasons when logging IP addresses. The returned "sensitive
57 // string" is for release builds a string with the end stripped away. Last
58 // octet for IPv4 and last 80 bits (5 groups) for IPv6. String will be
59 // "1.2.3.x" and "1.2.3::" respectively. For debug builds, the string is
61 std::string
IPAddressToSensitiveString(const net::IPAddressNumber
& address
) {
63 std::string sensitive_address
;
64 switch (net::GetAddressFamily(address
)) {
65 case net::ADDRESS_FAMILY_IPV4
: {
66 sensitive_address
= net::IPAddressToString(address
);
67 size_t find_pos
= sensitive_address
.rfind('.');
68 if (find_pos
== std::string::npos
)
70 sensitive_address
.resize(find_pos
);
71 sensitive_address
+= ".x";
74 case net::ADDRESS_FAMILY_IPV6
: {
75 // TODO(grunell): Create a string of format "1:2:3:x:x:x:x:x" to clarify
76 // that the end has been stripped out.
77 net::IPAddressNumber sensitive_address_number
= address
;
78 sensitive_address_number
.resize(net::kIPv6AddressSize
- 10);
79 sensitive_address_number
.resize(net::kIPv6AddressSize
, 0);
80 sensitive_address
= net::IPAddressToString(sensitive_address_number
);
83 case net::ADDRESS_FAMILY_UNSPECIFIED
: {
87 return sensitive_address
;
89 return net::IPAddressToString(address
);
93 void FormatMetaDataAsLogMessage(
94 const MetaDataMap
& meta_data
,
95 std::string
* message
) {
96 for (MetaDataMap::const_iterator it
= meta_data
.begin();
97 it
!= meta_data
.end(); ++it
) {
98 *message
+= it
->first
+ ": " + it
->second
+ '\n';
101 message
->resize(message
->size() - 1);
104 void FireGenericDoneCallback(
105 const WebRtcLoggingHandlerHost::GenericDoneCallback
& callback
,
107 const std::string
& error_message
) {
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
109 DCHECK(!callback
.is_null());
110 content::BrowserThread::PostTask(
111 content::BrowserThread::UI
,
113 base::Bind(callback
, success
, error_message
));
116 void FireAndResetGenericDoneCallback(
117 WebRtcLoggingHandlerHost::GenericDoneCallback
* callback
,
119 const std::string
& error_message
) {
120 FireGenericDoneCallback(*callback
, success
, error_message
);
126 WebRtcLogBuffer::WebRtcLogBuffer()
128 circular_(&buffer_
[0], sizeof(buffer_
), sizeof(buffer_
) / 2, false),
132 WebRtcLogBuffer::~WebRtcLogBuffer() {
133 DCHECK(read_only_
|| thread_checker_
.CalledOnValidThread());
136 void WebRtcLogBuffer::Log(const std::string
& message
) {
137 DCHECK(thread_checker_
.CalledOnValidThread());
139 circular_
.Write(message
.c_str(), message
.length());
140 const char eol
= '\n';
141 circular_
.Write(&eol
, 1);
144 PartialCircularBuffer
WebRtcLogBuffer::Read() {
145 DCHECK(thread_checker_
.CalledOnValidThread());
147 return PartialCircularBuffer(&buffer_
[0], sizeof(buffer_
));
150 void WebRtcLogBuffer::SetComplete() {
151 DCHECK(thread_checker_
.CalledOnValidThread());
152 DCHECK(!read_only_
) << "Already set? (programmer error)";
154 // Detach from the current thread so that we can check reads on a different
155 // thread. This is to make sure that Read()s still happen on one thread only.
156 thread_checker_
.DetachFromThread();
159 WebRtcLoggingHandlerHost::WebRtcLoggingHandlerHost(Profile
* profile
)
160 : BrowserMessageFilter(WebRtcLoggingMsgStart
),
162 logging_state_(CLOSED
),
163 upload_log_on_render_close_(false) {
167 WebRtcLoggingHandlerHost::~WebRtcLoggingHandlerHost() {}
169 void WebRtcLoggingHandlerHost::SetMetaData(
170 scoped_ptr
<MetaDataMap
> meta_data
,
171 const GenericDoneCallback
& callback
) {
172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
173 DCHECK(!callback
.is_null());
175 std::string error_message
;
176 if (logging_state_
== CLOSED
) {
177 if (!meta_data_
.get())
178 meta_data_
= meta_data
.Pass();
179 } else if (logging_state_
== STARTED
) {
180 std::string meta_data_message
;
181 FormatMetaDataAsLogMessage(*meta_data
.get(), &meta_data_message
);
182 LogToCircularBuffer(meta_data_message
);
184 error_message
= "Meta data must be set before stop or upload.";
187 if (error_message
.empty() && meta_data
.get()) {
188 // Keep the meta data around for uploading separately from the log.
189 for (const auto& it
: *meta_data
.get())
190 (*meta_data_
.get())[it
.first
] = it
.second
;
193 FireGenericDoneCallback(callback
, error_message
.empty(), error_message
);
196 void WebRtcLoggingHandlerHost::StartLogging(
197 const GenericDoneCallback
& callback
) {
198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
199 DCHECK(!callback
.is_null());
201 if (logging_state_
!= CLOSED
) {
202 FireGenericDoneCallback(callback
, false, "A log is already open");
206 logging_state_
= STARTING
;
207 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, base::Bind(
208 &WebRtcLoggingHandlerHost::StartLoggingIfAllowed
, this, callback
));
211 void WebRtcLoggingHandlerHost::StopLogging(
212 const GenericDoneCallback
& callback
) {
213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
214 DCHECK(!callback
.is_null());
216 if (logging_state_
!= STARTED
) {
217 FireGenericDoneCallback(callback
, false, "Logging not started");
221 stop_callback_
= callback
;
222 logging_state_
= STOPPING
;
223 Send(new WebRtcLoggingMsg_StopLogging());
226 void WebRtcLoggingHandlerHost::UploadLog(const UploadDoneCallback
& callback
) {
227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
228 DCHECK(!callback
.is_null());
230 if (logging_state_
!= STOPPED
) {
231 if (!callback
.is_null()) {
232 content::BrowserThread::PostTask(content::BrowserThread::UI
, FROM_HERE
,
233 base::Bind(callback
, false, "", kLogNotStoppedOrNoLogOpen
));
238 content::BrowserThread::PostTaskAndReplyWithResult(
239 content::BrowserThread::FILE,
241 base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists
,
243 base::Bind(&WebRtcLoggingHandlerHost::TriggerUpload
, this, callback
));
246 void WebRtcLoggingHandlerHost::UploadStoredLog(
247 const std::string
& log_id
,
248 const UploadDoneCallback
& callback
) {
249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
250 DCHECK(!callback
.is_null());
252 content::BrowserThread::PostTask(content::BrowserThread::FILE,
254 base::Bind(&WebRtcLoggingHandlerHost::UploadStoredLogOnFileThread
,
255 this, log_id
, callback
));
258 void WebRtcLoggingHandlerHost::UploadStoredLogOnFileThread(
259 const std::string
& log_id
,
260 const UploadDoneCallback
& callback
) {
261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
263 WebRtcLogUploadDoneData upload_data
;
264 upload_data
.log_path
= GetLogDirectoryAndEnsureExists();
265 upload_data
.callback
= callback
;
266 upload_data
.host
= this;
267 upload_data
.local_log_id
= log_id
;
269 g_browser_process
->webrtc_log_uploader()->UploadStoredLog(upload_data
);
272 void WebRtcLoggingHandlerHost::UploadLogDone() {
273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
274 logging_state_
= CLOSED
;
277 void WebRtcLoggingHandlerHost::DiscardLog(const GenericDoneCallback
& callback
) {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
279 DCHECK(!callback
.is_null());
281 if (logging_state_
!= STOPPED
) {
282 FireGenericDoneCallback(callback
, false, kLogNotStoppedOrNoLogOpen
);
285 g_browser_process
->webrtc_log_uploader()->LoggingStoppedDontUpload();
288 logging_state_
= CLOSED
;
289 rtp_dump_handler_
.reset();
290 stop_rtp_dump_callback_
.Reset();
291 FireGenericDoneCallback(callback
, true, "");
294 // Stores the log locally using a hash of log_id + security origin.
295 void WebRtcLoggingHandlerHost::StoreLog(
296 const std::string
& log_id
,
297 const GenericDoneCallback
& callback
) {
298 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
299 DCHECK(!callback
.is_null());
301 if (logging_state_
!= STOPPED
) {
302 FireGenericDoneCallback(callback
, false, kLogNotStoppedOrNoLogOpen
);
306 if (rtp_dump_handler_
) {
307 BrowserThread::PostTask(
310 base::Bind(stop_rtp_dump_callback_
, true, true));
312 rtp_dump_handler_
->StopOngoingDumps(
313 base::Bind(&WebRtcLoggingHandlerHost::StoreLogContinue
,
314 this, log_id
, callback
));
318 StoreLogContinue(log_id
, callback
);
321 void WebRtcLoggingHandlerHost::StoreLogContinue(
322 const std::string
& log_id
,
323 const GenericDoneCallback
& callback
) {
324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
325 DCHECK(!callback
.is_null());
327 scoped_ptr
<WebRtcLogPaths
> log_paths(new WebRtcLogPaths());
328 ReleaseRtpDumps(log_paths
.get());
330 content::BrowserThread::PostTaskAndReplyWithResult(
331 content::BrowserThread::FILE,
333 base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists
,
335 base::Bind(&WebRtcLoggingHandlerHost::StoreLogInDirectory
, this, log_id
,
336 Passed(&log_paths
), callback
));
339 void WebRtcLoggingHandlerHost::LogMessage(const std::string
& message
) {
340 BrowserThread::PostTask(
344 &WebRtcLoggingHandlerHost::AddLogMessageFromBrowser
,
346 WebRtcLoggingMessageData(base::Time::Now(), message
)));
349 void WebRtcLoggingHandlerHost::StartRtpDump(
351 const GenericDoneCallback
& callback
,
352 const content::RenderProcessHost::WebRtcStopRtpDumpCallback
&
354 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
355 DCHECK(stop_rtp_dump_callback_
.is_null() ||
356 stop_rtp_dump_callback_
.Equals(stop_callback
));
358 stop_rtp_dump_callback_
= stop_callback
;
360 if (!rtp_dump_handler_
) {
361 content::BrowserThread::PostTaskAndReplyWithResult(
362 content::BrowserThread::FILE,
364 base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists
,
366 base::Bind(&WebRtcLoggingHandlerHost::CreateRtpDumpHandlerAndStart
,
373 DoStartRtpDump(type
, callback
);
376 void WebRtcLoggingHandlerHost::StopRtpDump(
378 const GenericDoneCallback
& callback
) {
379 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
380 DCHECK(!callback
.is_null());
382 if (!rtp_dump_handler_
) {
383 FireGenericDoneCallback(callback
, false, "RTP dump has not been started.");
387 if (!stop_rtp_dump_callback_
.is_null()) {
388 BrowserThread::PostTask(
391 base::Bind(stop_rtp_dump_callback_
,
392 type
== RTP_DUMP_INCOMING
|| type
== RTP_DUMP_BOTH
,
393 type
== RTP_DUMP_OUTGOING
|| type
== RTP_DUMP_BOTH
));
396 rtp_dump_handler_
->StopDump(type
, callback
);
399 void WebRtcLoggingHandlerHost::OnRtpPacket(scoped_ptr
<uint8
[]> packet_header
,
400 size_t header_length
,
401 size_t packet_length
,
403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
405 BrowserThread::PostTask(
408 base::Bind(&WebRtcLoggingHandlerHost::DumpRtpPacketOnIOThread
,
410 base::Passed(&packet_header
),
416 void WebRtcLoggingHandlerHost::DumpRtpPacketOnIOThread(
417 scoped_ptr
<uint8
[]> packet_header
,
418 size_t header_length
,
419 size_t packet_length
,
421 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
423 // |rtp_dump_handler_| could be NULL if we are waiting for the FILE thread to
424 // create/ensure the log directory.
425 if (rtp_dump_handler_
) {
426 rtp_dump_handler_
->OnRtpPacket(
427 packet_header
.get(), header_length
, packet_length
, incoming
);
431 void WebRtcLoggingHandlerHost::OnChannelClosing() {
432 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
433 if (logging_state_
== STARTED
|| logging_state_
== STOPPED
) {
434 if (upload_log_on_render_close_
) {
435 logging_started_time_
= base::Time();
437 content::BrowserThread::PostTaskAndReplyWithResult(
438 content::BrowserThread::FILE,
440 base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists
,
442 base::Bind(&WebRtcLoggingHandlerHost::TriggerUpload
, this,
443 UploadDoneCallback()));
445 g_browser_process
->webrtc_log_uploader()->LoggingStoppedDontUpload();
448 content::BrowserMessageFilter::OnChannelClosing();
451 void WebRtcLoggingHandlerHost::OnDestruct() const {
452 BrowserThread::DeleteOnIOThread::Destruct(this);
455 bool WebRtcLoggingHandlerHost::OnMessageReceived(const IPC::Message
& message
) {
456 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
458 IPC_BEGIN_MESSAGE_MAP(WebRtcLoggingHandlerHost
, message
)
459 IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_AddLogMessages
, OnAddLogMessages
)
460 IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_LoggingStopped
,
461 OnLoggingStoppedInRenderer
)
462 IPC_MESSAGE_UNHANDLED(handled
= false)
463 IPC_END_MESSAGE_MAP()
468 void WebRtcLoggingHandlerHost::AddLogMessageFromBrowser(
469 const WebRtcLoggingMessageData
& message
) {
470 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
471 if (logging_state_
== STARTED
)
472 LogToCircularBuffer(message
.Format(logging_started_time_
));
475 void WebRtcLoggingHandlerHost::OnAddLogMessages(
476 const std::vector
<WebRtcLoggingMessageData
>& messages
) {
477 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
478 if (logging_state_
== STARTED
|| logging_state_
== STOPPING
) {
479 for (size_t i
= 0; i
< messages
.size(); ++i
) {
480 LogToCircularBuffer(messages
[i
].Format(logging_started_time_
));
485 void WebRtcLoggingHandlerHost::OnLoggingStoppedInRenderer() {
486 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
487 if (logging_state_
!= STOPPING
) {
488 // If an out-of-order response is received, stop_callback_ may be invalid,
489 // and must not be invoked.
490 DLOG(ERROR
) << "OnLoggingStoppedInRenderer invoked in state "
492 BadMessageReceived();
495 logging_started_time_
= base::Time();
496 logging_state_
= STOPPED
;
497 FireAndResetGenericDoneCallback(&stop_callback_
, true, "");
500 void WebRtcLoggingHandlerHost::StartLoggingIfAllowed(
501 const GenericDoneCallback
& callback
) {
502 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
503 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
, base::Bind(
504 &WebRtcLoggingHandlerHost::DoStartLogging
, this,
505 g_browser_process
->webrtc_log_uploader()->ApplyForStartLogging(),
509 void WebRtcLoggingHandlerHost::DoStartLogging(
510 bool permissions_granted
,
511 const GenericDoneCallback
& callback
) {
512 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
513 if (logging_state_
!= STARTING
) {
514 FireGenericDoneCallback(callback
, false, "Logging cancelled.");
518 if (!permissions_granted
) {
519 logging_state_
= CLOSED
;
520 FireGenericDoneCallback(callback
, false,
521 "Cannot start, maybe the maximum number of "
522 "simultaneuos logs has been reached.");
526 DCHECK(!log_buffer_
.get());
527 log_buffer_
.reset(new WebRtcLogBuffer());
528 if (!meta_data_
.get())
529 meta_data_
.reset(new MetaDataMap());
531 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
, base::Bind(
532 &WebRtcLoggingHandlerHost::LogInitialInfoOnFileThread
, this, callback
));
535 void WebRtcLoggingHandlerHost::LogInitialInfoOnFileThread(
536 const GenericDoneCallback
& callback
) {
537 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
539 net::NetworkInterfaceList network_list
;
540 net::GetNetworkList(&network_list
,
541 net::EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES
);
543 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
, base::Bind(
544 &WebRtcLoggingHandlerHost::LogInitialInfoOnIOThread
, this, network_list
,
548 void WebRtcLoggingHandlerHost::LogInitialInfoOnIOThread(
549 const net::NetworkInterfaceList
& network_list
,
550 const GenericDoneCallback
& callback
) {
551 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
552 if (logging_state_
!= STARTING
) {
553 FireGenericDoneCallback(callback
, false, "Logging cancelled.");
557 // Log start time (current time). We don't use base/i18n/time_formatting.h
558 // here because we don't want the format of the current locale.
559 base::Time::Exploded now
= {0};
560 base::Time::Now().LocalExplode(&now
);
561 LogToCircularBuffer(base::StringPrintf(
562 "Start %d-%02d-%02d %02d:%02d:%02d", now
.year
, now
.month
,
563 now
.day_of_month
, now
.hour
, now
.minute
, now
.second
));
565 // Write metadata if received before logging started.
566 if (meta_data_
.get() && !meta_data_
->empty()) {
568 FormatMetaDataAsLogMessage(*meta_data_
.get(), &info
);
569 LogToCircularBuffer(info
);
573 chrome::VersionInfo version_info
;
574 LogToCircularBuffer("Chrome version: " + version_info
.Version() + " " +
575 chrome::VersionInfo::GetVersionStringModifier());
578 LogToCircularBuffer(base::SysInfo::OperatingSystemName() + " " +
579 base::SysInfo::OperatingSystemVersion() + " " +
580 base::SysInfo::OperatingSystemArchitecture());
581 #if defined(OS_LINUX)
582 LogToCircularBuffer("Linux distribution: " + base::GetLinuxDistro());
588 "Cpu: " + IntToString(cpu
.family()) + "." + IntToString(cpu
.model()) +
589 "." + IntToString(cpu
.stepping()) + ", x" +
590 IntToString(base::SysInfo::NumberOfProcessors()) + ", " +
591 IntToString(base::SysInfo::AmountOfPhysicalMemoryMB()) + "MB");
592 std::string cpu_brand
= cpu
.cpu_brand();
593 // Workaround for crbug.com/249713.
594 // TODO(grunell): Remove workaround when bug is fixed.
595 size_t null_pos
= cpu_brand
.find('\0');
596 if (null_pos
!= std::string::npos
)
597 cpu_brand
.erase(null_pos
);
598 LogToCircularBuffer("Cpu brand: " + cpu_brand
);
601 std::string computer_model
= "Not available";
602 #if defined(OS_MACOSX)
603 computer_model
= base::mac::GetModelIdentifier();
604 #elif defined(OS_CHROMEOS)
605 chromeos::system::StatisticsProvider::GetInstance()->
606 GetMachineStatistic(chromeos::system::kHardwareClassKey
, &computer_model
);
608 LogToCircularBuffer("Computer model: " + computer_model
);
611 gpu::GPUInfo gpu_info
= content::GpuDataManager::GetInstance()->GetGPUInfo();
613 "Gpu: machine-model-name=" + gpu_info
.machine_model_name
+
614 ", machine-model-version=" + gpu_info
.machine_model_version
+
615 ", vendor-id=" + IntToString(gpu_info
.gpu
.vendor_id
) +
616 ", device-id=" + IntToString(gpu_info
.gpu
.device_id
) +
617 ", driver-vendor=" + gpu_info
.driver_vendor
+
618 ", driver-version=" + gpu_info
.driver_version
);
620 "OpenGL: gl-vendor=" + gpu_info
.gl_vendor
+
621 ", gl-renderer=" + gpu_info
.gl_renderer
+
622 ", gl-version=" + gpu_info
.gl_version
);
624 // Network interfaces
625 LogToCircularBuffer("Discovered " + IntToString(network_list
.size()) +
626 " network interfaces:");
627 for (net::NetworkInterfaceList::const_iterator it
= network_list
.begin();
628 it
!= network_list
.end(); ++it
) {
630 "Name: " + it
->friendly_name
+ ", Address: " +
631 IPAddressToSensitiveString(it
->address
) + ", Type: " +
632 net::NetworkChangeNotifier::ConnectionTypeToString(it
->type
));
635 NotifyLoggingStarted(callback
);
638 void WebRtcLoggingHandlerHost::NotifyLoggingStarted(
639 const GenericDoneCallback
& callback
) {
640 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
641 DCHECK_EQ(logging_state_
, STARTING
);
642 Send(new WebRtcLoggingMsg_StartLogging());
643 logging_started_time_
= base::Time::Now();
644 logging_state_
= STARTED
;
645 FireGenericDoneCallback(callback
, true, "");
648 void WebRtcLoggingHandlerHost::LogToCircularBuffer(const std::string
& message
) {
649 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
650 DCHECK_NE(logging_state_
, CLOSED
);
651 log_buffer_
->Log(message
);
654 base::FilePath
WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists() {
655 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
656 base::FilePath log_dir_path
=
657 WebRtcLogList::GetWebRtcLogDirectoryForProfile(profile_
->GetPath());
658 base::File::Error error
;
659 if (!base::CreateDirectoryAndGetError(log_dir_path
, &error
)) {
660 DLOG(ERROR
) << "Could not create WebRTC log directory, error: " << error
;
661 return base::FilePath();
666 void WebRtcLoggingHandlerHost::TriggerUpload(
667 const UploadDoneCallback
& callback
,
668 const base::FilePath
& log_directory
) {
669 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
671 if (rtp_dump_handler_
) {
672 BrowserThread::PostTask(
675 base::Bind(stop_rtp_dump_callback_
, true, true));
677 rtp_dump_handler_
->StopOngoingDumps(
678 base::Bind(&WebRtcLoggingHandlerHost::DoUploadLogAndRtpDumps
,
685 DoUploadLogAndRtpDumps(log_directory
, callback
);
688 void WebRtcLoggingHandlerHost::StoreLogInDirectory(
689 const std::string
& log_id
,
690 scoped_ptr
<WebRtcLogPaths
> log_paths
,
691 const GenericDoneCallback
& done_callback
,
692 const base::FilePath
& directory
) {
693 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
694 log_paths
->log_path
= directory
;
696 log_buffer_
->SetComplete();
697 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
,
698 base::Bind(&WebRtcLogUploader::LoggingStoppedDoStore
,
699 base::Unretained(g_browser_process
->webrtc_log_uploader()),
700 *log_paths
.get(), log_id
, Passed(&log_buffer_
), Passed(&meta_data_
),
703 logging_state_
= CLOSED
;
706 void WebRtcLoggingHandlerHost::DoUploadLogAndRtpDumps(
707 const base::FilePath
& log_directory
,
708 const UploadDoneCallback
& callback
) {
709 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
711 WebRtcLogUploadDoneData upload_done_data
;
712 upload_done_data
.log_path
= log_directory
;
713 upload_done_data
.callback
= callback
;
714 upload_done_data
.host
= this;
715 ReleaseRtpDumps(&upload_done_data
);
717 log_buffer_
->SetComplete();
718 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
, base::Bind(
719 &WebRtcLogUploader::LoggingStoppedDoUpload
,
720 base::Unretained(g_browser_process
->webrtc_log_uploader()),
721 Passed(&log_buffer_
),
725 logging_state_
= CLOSED
;
728 void WebRtcLoggingHandlerHost::CreateRtpDumpHandlerAndStart(
730 const GenericDoneCallback
& callback
,
731 const base::FilePath
& dump_dir
) {
732 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
734 // |rtp_dump_handler_| may be non-NULL if StartRtpDump is called again before
735 // GetLogDirectoryAndEnsureExists returns on the FILE thread for a previous
737 if (!rtp_dump_handler_
)
738 rtp_dump_handler_
.reset(new WebRtcRtpDumpHandler(dump_dir
));
740 DoStartRtpDump(type
, callback
);
743 void WebRtcLoggingHandlerHost::DoStartRtpDump(
744 RtpDumpType type
, const GenericDoneCallback
& callback
) {
745 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
746 DCHECK(rtp_dump_handler_
);
749 bool result
= rtp_dump_handler_
->StartDump(type
, &error
);
750 FireGenericDoneCallback(callback
, result
, error
);
753 bool WebRtcLoggingHandlerHost::ReleaseRtpDumps(WebRtcLogPaths
* log_paths
) {
754 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
757 if (!rtp_dump_handler_
)
760 WebRtcRtpDumpHandler::ReleasedDumps
rtp_dumps(
761 rtp_dump_handler_
->ReleaseDumps());
762 log_paths
->incoming_rtp_dump
= rtp_dumps
.incoming_dump_path
;
763 log_paths
->outgoing_rtp_dump
= rtp_dumps
.outgoing_dump_path
;
765 rtp_dump_handler_
.reset();
766 stop_rtp_dump_callback_
.Reset();