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. 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 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 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 122 WebRtcLoggingHandlerHost::~WebRtcLoggingHandlerHost() {} 123 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 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 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 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 198 void WebRtcLoggingHandlerHost::UploadLogDone() { 199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 200 logging_state_ = CLOSED; 201 } 202 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 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 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 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 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 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 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 337 void WebRtcLoggingHandlerHost::OnDestruct() const { 338 BrowserThread::DeleteOnIOThread::Destruct(this); 339 } 340 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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