Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/media/webrtc_logging_handler_host.h" | 5 #include "chrome/browser/media/webrtc_logging_handler_host.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 11 #include "base/cpu.h" | 11 #include "base/cpu.h" |
| 12 #include "base/file_util.h" | 12 #include "base/file_util.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/prefs/pref_service.h" | 14 #include "base/prefs/pref_service.h" |
| 15 #include "base/strings/string_number_conversions.h" | 15 #include "base/strings/string_number_conversions.h" |
| 16 #include "base/sys_info.h" | 16 #include "base/sys_info.h" |
| 17 #include "base/time/time.h" | 17 #include "base/time/time.h" |
| 18 #include "chrome/browser/browser_process.h" | 18 #include "chrome/browser/browser_process.h" |
| 19 #include "chrome/browser/chromeos/settings/cros_settings.h" | 19 #include "chrome/browser/chromeos/settings/cros_settings.h" |
| 20 #include "chrome/browser/media/webrtc_log_list.h" | 20 #include "chrome/browser/media/webrtc_log_list.h" |
| 21 #include "chrome/browser/media/webrtc_log_uploader.h" | 21 #include "chrome/browser/media/webrtc_log_uploader.h" |
| 22 #include "chrome/browser/media/webrtc_rtp_dump_handler.h" | |
| 23 #include "chrome/browser/media/webrtc_rtp_dump_writer.h" | |
| 22 #include "chrome/browser/profiles/profile.h" | 24 #include "chrome/browser/profiles/profile.h" |
| 23 #include "chrome/common/chrome_switches.h" | 25 #include "chrome/common/chrome_switches.h" |
| 24 #include "chrome/common/media/webrtc_logging_messages.h" | 26 #include "chrome/common/media/webrtc_logging_messages.h" |
| 25 #include "chrome/common/partial_circular_buffer.h" | 27 #include "chrome/common/partial_circular_buffer.h" |
| 26 #include "chrome/common/pref_names.h" | 28 #include "chrome/common/pref_names.h" |
| 27 #include "chromeos/settings/cros_settings_names.h" | 29 #include "chromeos/settings/cros_settings_names.h" |
| 28 #include "content/public/browser/browser_thread.h" | 30 #include "content/public/browser/browser_thread.h" |
| 29 #include "content/public/browser/content_browser_client.h" | 31 #include "content/public/browser/content_browser_client.h" |
| 30 #include "content/public/browser/gpu_data_manager.h" | 32 #include "content/public/browser/gpu_data_manager.h" |
| 31 #include "content/public/browser/render_process_host.h" | 33 #include "content/public/browser/render_process_host.h" |
| 32 #include "gpu/config/gpu_info.h" | 34 #include "gpu/config/gpu_info.h" |
| 33 #include "net/base/address_family.h" | 35 #include "net/base/address_family.h" |
| 34 #include "net/url_request/url_request_context_getter.h" | 36 #include "net/url_request/url_request_context_getter.h" |
| 35 | 37 |
| 36 #if defined(OS_LINUX) | 38 #if defined(OS_LINUX) |
| 37 #include "base/linux_util.h" | 39 #include "base/linux_util.h" |
| 38 #endif | 40 #endif |
| 39 | 41 |
| 40 #if defined(OS_MACOSX) | 42 #if defined(OS_MACOSX) |
| 41 #include "base/mac/mac_util.h" | 43 #include "base/mac/mac_util.h" |
| 42 #endif | 44 #endif |
| 43 | 45 |
| 44 #if defined(OS_CHROMEOS) | 46 #if defined(OS_CHROMEOS) |
| 45 #include "chromeos/system/statistics_provider.h" | 47 #include "chromeos/system/statistics_provider.h" |
| 46 #endif | 48 #endif |
| 47 | 49 |
| 48 using base::IntToString; | 50 using base::IntToString; |
| 49 using content::BrowserThread; | 51 using content::BrowserThread; |
| 50 | 52 |
| 53 namespace { | |
| 51 | 54 |
| 52 #if defined(OS_ANDROID) | 55 #if defined(OS_ANDROID) |
| 53 const size_t kWebRtcLogSize = 1 * 1024 * 1024; // 1 MB | 56 const size_t kWebRtcLogSize = 1 * 1024 * 1024; // 1 MB |
| 54 #else | 57 #else |
| 55 const size_t kWebRtcLogSize = 6 * 1024 * 1024; // 6 MB | 58 const size_t kWebRtcLogSize = 4 * 1024 * 1024; // 4 MB |
|
Henrik Grunell
2014/05/13 09:12:31
What's the rationale for decreasing this?
jiayl
2014/05/13 21:48:17
The max upload size including log and dumps is 10,
Henrik Grunell
2014/05/14 12:14:12
OK.
| |
| 56 #endif | 59 #endif |
| 57 | 60 |
| 58 namespace { | |
| 59 | |
| 60 const char kLogNotStoppedOrNoLogOpen[] = | 61 const char kLogNotStoppedOrNoLogOpen[] = |
| 61 "Logging not stopped or no log open."; | 62 "Logging not stopped or no log open."; |
| 62 | 63 |
| 63 // For privacy reasons when logging IP addresses. The returned "sensitive | 64 // For privacy reasons when logging IP addresses. The returned "sensitive |
| 64 // string" is for release builds a string with the end stripped away. Last | 65 // string" is for release builds a string with the end stripped away. Last |
| 65 // octet for IPv4 and last 80 bits (5 groups) for IPv6. String will be | 66 // octet for IPv4 and last 80 bits (5 groups) for IPv6. String will be |
| 66 // "1.2.3.x" and "1.2.3::" respectively. For debug builds, the string is | 67 // "1.2.3.x" and "1.2.3::" respectively. For debug builds, the string is |
| 67 // not stripped. | 68 // not stripped. |
| 68 std::string IPAddressToSensitiveString(const net::IPAddressNumber& address) { | 69 std::string IPAddressToSensitiveString(const net::IPAddressNumber& address) { |
| 69 #if defined(NDEBUG) | 70 #if defined(NDEBUG) |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 183 } | 184 } |
| 184 return; | 185 return; |
| 185 } | 186 } |
| 186 upload_callback_ = callback; | 187 upload_callback_ = callback; |
| 187 logging_state_ = UPLOADING; | 188 logging_state_ = UPLOADING; |
| 188 content::BrowserThread::PostTaskAndReplyWithResult( | 189 content::BrowserThread::PostTaskAndReplyWithResult( |
| 189 content::BrowserThread::FILE, | 190 content::BrowserThread::FILE, |
| 190 FROM_HERE, | 191 FROM_HERE, |
| 191 base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists, | 192 base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists, |
| 192 this), | 193 this), |
| 193 base::Bind(&WebRtcLoggingHandlerHost::TriggerUploadLog, this)); | 194 base::Bind(&WebRtcLoggingHandlerHost::TriggerUploadLogAndRtpDump, this)); |
| 194 } | 195 } |
| 195 | 196 |
| 196 void WebRtcLoggingHandlerHost::UploadLogDone() { | 197 void WebRtcLoggingHandlerHost::UploadLogDone() { |
| 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 198 logging_state_ = CLOSED; | 199 logging_state_ = CLOSED; |
| 199 } | 200 } |
| 200 | 201 |
| 201 void WebRtcLoggingHandlerHost::DiscardLog(const GenericDoneCallback& callback) { | 202 void WebRtcLoggingHandlerHost::DiscardLog(const GenericDoneCallback& callback) { |
| 202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 203 DCHECK(!callback.is_null()); | 204 DCHECK(!callback.is_null()); |
| 204 | 205 |
| 205 GenericDoneCallback discard_callback = callback; | 206 GenericDoneCallback discard_callback = callback; |
| 206 if (logging_state_ != STOPPED) { | 207 if (logging_state_ != STOPPED) { |
| 207 FireGenericDoneCallback(&discard_callback, false, | 208 FireGenericDoneCallback(&discard_callback, false, |
| 208 kLogNotStoppedOrNoLogOpen); | 209 kLogNotStoppedOrNoLogOpen); |
| 209 return; | 210 return; |
| 210 } | 211 } |
| 211 g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload(); | 212 g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload(); |
| 212 circular_buffer_.reset(); | 213 circular_buffer_.reset(); |
| 213 log_buffer_.reset(); | 214 log_buffer_.reset(); |
| 214 logging_state_ = CLOSED; | 215 logging_state_ = CLOSED; |
| 216 rtp_dump_handler_.reset(); | |
| 215 FireGenericDoneCallback(&discard_callback, true, ""); | 217 FireGenericDoneCallback(&discard_callback, true, ""); |
| 216 } | 218 } |
| 217 | 219 |
| 218 void WebRtcLoggingHandlerHost::LogMessage(const std::string& message) { | 220 void WebRtcLoggingHandlerHost::LogMessage(const std::string& message) { |
| 219 BrowserThread::PostTask( | 221 BrowserThread::PostTask( |
| 220 BrowserThread::IO, | 222 BrowserThread::IO, |
| 221 FROM_HERE, | 223 FROM_HERE, |
| 222 base::Bind( | 224 base::Bind( |
| 223 &WebRtcLoggingHandlerHost::AddLogMessageFromBrowser, | 225 &WebRtcLoggingHandlerHost::AddLogMessageFromBrowser, |
| 224 this, | 226 this, |
| 225 WebRtcLoggingMessageData(base::Time::Now(), message))); | 227 WebRtcLoggingMessageData(base::Time::Now(), message))); |
| 226 } | 228 } |
| 227 | 229 |
| 228 void WebRtcLoggingHandlerHost::StartRtpDump( | 230 void WebRtcLoggingHandlerHost::StartRtpDump( |
| 229 bool incoming, | 231 bool incoming, |
| 230 bool outgoing, | 232 bool outgoing, |
| 231 const GenericDoneCallback& callback) { | 233 const GenericDoneCallback& callback) { |
| 232 NOTIMPLEMENTED(); | 234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 235 DCHECK(!callback.is_null()); | |
| 236 | |
| 237 GenericDoneCallback start_callback = callback; | |
| 238 if (!incoming && !outgoing) { | |
| 239 FireGenericDoneCallback(&start_callback, false, ""); | |
|
Henrik Grunell
2014/05/13 09:12:31
Add an error message (third argument) for all plac
jiayl
2014/05/13 21:48:17
Done.
| |
| 240 return; | |
| 241 } | |
| 242 | |
| 243 if (!rtp_dump_handler_) { | |
| 244 content::BrowserThread::PostTaskAndReplyWithResult( | |
|
Henrik Grunell
2014/05/13 09:12:31
What happens if there's another call to StartRtpDu
jiayl
2014/05/13 21:48:17
Changed CreateRtpDumpHandlerAndStart to check if r
Henrik Grunell
2014/05/14 12:14:12
So, it's safe to call multiple times?
jiayl
2014/05/14 16:07:58
yes, it's safe.
| |
| 245 content::BrowserThread::FILE, | |
| 246 FROM_HERE, | |
| 247 base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists, | |
| 248 this), | |
| 249 base::Bind(&WebRtcLoggingHandlerHost::CreateRtpDumpHandlerAndStart, | |
| 250 this, | |
| 251 incoming, | |
| 252 outgoing, | |
| 253 callback)); | |
| 254 return; | |
| 255 } | |
| 256 | |
| 257 WebRtcRtpDumpHandler::PacketType type = {incoming, outgoing}; | |
|
Henrik Grunell
2014/05/13 09:12:31
I think this part should be moved to it's own func
jiayl
2014/05/13 21:48:17
Done.
| |
| 258 bool result = rtp_dump_handler_->StartDump(type); | |
| 259 FireGenericDoneCallback(&start_callback, result, ""); | |
| 233 } | 260 } |
| 234 | 261 |
| 235 void WebRtcLoggingHandlerHost::StopRtpDump( | 262 void WebRtcLoggingHandlerHost::StopRtpDump( |
| 236 bool incoming, | 263 bool incoming, |
| 237 bool outgoing, | 264 bool outgoing, |
| 238 const GenericDoneCallback& callback) { | 265 const GenericDoneCallback& callback) { |
| 239 NOTIMPLEMENTED(); | 266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 267 DCHECK(!callback.is_null()); | |
| 268 | |
| 269 GenericDoneCallback stop_callback = callback; | |
| 270 if (!(incoming || outgoing) || !rtp_dump_handler_) { | |
| 271 FireGenericDoneCallback(&stop_callback, false, ""); | |
| 272 return; | |
| 273 } | |
| 274 | |
| 275 WebRtcRtpDumpHandler::PacketType type = {incoming, outgoing}; | |
| 276 bool result = rtp_dump_handler_->StopDump(type); | |
| 277 FireGenericDoneCallback(&stop_callback, result, ""); | |
| 278 } | |
| 279 | |
| 280 void WebRtcLoggingHandlerHost::OnRtpPacket(const uint8* packet_header, | |
|
Henrik Grunell
2014/05/13 09:12:31
Which thread should this be called on? Thread chec
jiayl
2014/05/13 21:48:17
In practice it called on the browser UI thread. Si
| |
| 281 size_t header_length, | |
| 282 size_t packet_length, | |
| 283 bool incoming) { | |
| 284 scoped_ptr<uint8[]> header_data(new uint8[header_length]); | |
| 285 memcpy(header_data.get(), packet_header, header_length); | |
| 286 | |
| 287 BrowserThread::PostTask( | |
| 288 BrowserThread::IO, | |
| 289 FROM_HERE, | |
| 290 base::Bind(&WebRtcLoggingHandlerHost::DumpRtpPacketOnIOThread, | |
| 291 this, | |
| 292 base::Passed(&header_data), | |
| 293 header_length, | |
| 294 packet_length, | |
| 295 incoming)); | |
| 296 } | |
| 297 | |
| 298 void WebRtcLoggingHandlerHost::DumpRtpPacketOnIOThread( | |
| 299 scoped_ptr<uint8[]> packet_header, | |
| 300 size_t header_length, | |
| 301 size_t packet_length, | |
| 302 bool incoming) { | |
| 303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 304 | |
| 305 if (rtp_dump_handler_) { | |
|
Henrik Grunell
2014/05/13 09:12:31
Is |rtp_dump_handler_| expected to be NULL sometim
jiayl
2014/05/13 21:48:17
The call is triggered by P2PSocketHost, which live
Henrik Grunell
2014/05/14 12:14:12
This sounds dangerous. Do you mean it can be a rac
jiayl
2014/05/14 16:07:58
There is no race in the impl. What I mean is that
| |
| 306 rtp_dump_handler_->OnRtpPacket( | |
| 307 packet_header.get(), header_length, packet_length, incoming); | |
| 308 } | |
| 240 } | 309 } |
| 241 | 310 |
| 242 void WebRtcLoggingHandlerHost::OnChannelClosing() { | 311 void WebRtcLoggingHandlerHost::OnChannelClosing() { |
| 243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 312 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 244 if (logging_state_ == STARTED || logging_state_ == STOPPED) { | 313 if (logging_state_ == STARTED || logging_state_ == STOPPED) { |
| 245 if (upload_log_on_render_close_) { | 314 if (upload_log_on_render_close_) { |
| 246 logging_state_ = UPLOADING; | 315 logging_state_ = UPLOADING; |
| 247 logging_started_time_ = base::Time(); | 316 logging_started_time_ = base::Time(); |
| 248 content::BrowserThread::PostTaskAndReplyWithResult( | 317 content::BrowserThread::PostTaskAndReplyWithResult( |
| 249 content::BrowserThread::FILE, | 318 content::BrowserThread::FILE, |
| 250 FROM_HERE, | 319 FROM_HERE, |
| 251 base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists, | 320 base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists, |
| 252 this), | 321 this), |
| 253 base::Bind(&WebRtcLoggingHandlerHost::TriggerUploadLog, this)); | 322 base::Bind(&WebRtcLoggingHandlerHost::TriggerUploadLogAndRtpDump, |
| 323 this)); | |
| 254 } else { | 324 } else { |
| 255 g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload(); | 325 g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload(); |
| 256 } | 326 } |
| 257 } | 327 } |
| 258 content::BrowserMessageFilter::OnChannelClosing(); | 328 content::BrowserMessageFilter::OnChannelClosing(); |
| 259 } | 329 } |
| 260 | 330 |
| 261 void WebRtcLoggingHandlerHost::OnDestruct() const { | 331 void WebRtcLoggingHandlerHost::OnDestruct() const { |
| 262 BrowserThread::DeleteOnIOThread::Destruct(this); | 332 BrowserThread::DeleteOnIOThread::Destruct(this); |
| 263 } | 333 } |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 441 base::FilePath log_dir_path = | 511 base::FilePath log_dir_path = |
| 442 WebRtcLogList::GetWebRtcLogDirectoryForProfile(profile_->GetPath()); | 512 WebRtcLogList::GetWebRtcLogDirectoryForProfile(profile_->GetPath()); |
| 443 base::File::Error error; | 513 base::File::Error error; |
| 444 if (!base::CreateDirectoryAndGetError(log_dir_path, &error)) { | 514 if (!base::CreateDirectoryAndGetError(log_dir_path, &error)) { |
| 445 DLOG(ERROR) << "Could not create WebRTC log directory, error: " << error; | 515 DLOG(ERROR) << "Could not create WebRTC log directory, error: " << error; |
| 446 return base::FilePath(); | 516 return base::FilePath(); |
| 447 } | 517 } |
| 448 return log_dir_path; | 518 return log_dir_path; |
| 449 } | 519 } |
| 450 | 520 |
| 451 void WebRtcLoggingHandlerHost::TriggerUploadLog( | 521 void WebRtcLoggingHandlerHost::TriggerUploadLogAndRtpDump( |
| 452 const base::FilePath& log_directory) { | 522 const base::FilePath& log_directory) { |
| 453 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 523 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 454 DCHECK_EQ(logging_state_, UPLOADING); | 524 DCHECK_EQ(logging_state_, UPLOADING); |
| 455 | 525 |
| 526 if (rtp_dump_handler_ && | |
|
Henrik Grunell
2014/05/13 09:12:31
Same here, can it be NULL?
jiayl
2014/05/13 21:48:17
It can be NULL if rtp dump is never started.
| |
| 527 rtp_dump_handler_->ReleaseDump(base::Bind( | |
|
Henrik Grunell
2014/05/13 09:12:31
So the dump handler will call DoUpload in ReleaseD
jiayl
2014/05/13 21:48:17
Now Refactored to end the dump on StopDump. So Rel
| |
| 528 &WebRtcLoggingHandlerHost::DoUpload, this, log_directory))) { | |
| 529 return; | |
| 530 } | |
| 531 | |
| 532 DoUpload(log_directory, WebRtcRtpDumpHandler::ReleasedDumps()); | |
| 533 } | |
| 534 | |
| 535 void WebRtcLoggingHandlerHost::FireGenericDoneCallback( | |
| 536 GenericDoneCallback* callback, | |
| 537 bool success, | |
| 538 const std::string& error_message) { | |
| 539 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 540 DCHECK(!(*callback).is_null()); | |
| 541 content::BrowserThread::PostTask( | |
| 542 content::BrowserThread::UI, | |
| 543 FROM_HERE, | |
| 544 base::Bind(*callback, success, error_message)); | |
| 545 (*callback).Reset(); | |
| 546 } | |
| 547 | |
| 548 void WebRtcLoggingHandlerHost::CreateRtpDumpHandlerAndStart( | |
| 549 bool incoming, | |
| 550 bool outgoing, | |
| 551 GenericDoneCallback callback, | |
| 552 const base::FilePath& dump_dir) { | |
| 553 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 554 DCHECK(!rtp_dump_handler_); | |
| 555 | |
| 556 rtp_dump_handler_.reset(new WebRtcRtpDumpHandler(dump_dir)); | |
| 557 | |
| 558 StartRtpDump(incoming, outgoing, callback); | |
| 559 } | |
| 560 | |
| 561 void WebRtcLoggingHandlerHost::DoUpload( | |
| 562 const base::FilePath& log_directory, | |
| 563 const WebRtcRtpDumpHandler::ReleasedDumps& rtp_dumps) { | |
| 456 WebRtcLogUploadDoneData upload_done_data; | 564 WebRtcLogUploadDoneData upload_done_data; |
| 457 upload_done_data.log_path = log_directory; | 565 upload_done_data.log_path = log_directory; |
| 566 | |
| 567 if (!rtp_dumps.incoming_dump_path.empty()) { | |
| 568 upload_done_data.rtp_dumps.push_back( | |
| 569 WebRtcRtpDumpDescription("rtpdump_recv", rtp_dumps.incoming_dump_path)); | |
| 570 } | |
| 571 if (!rtp_dumps.outgoing_dump_path.empty()) { | |
| 572 upload_done_data.rtp_dumps.push_back( | |
| 573 WebRtcRtpDumpDescription("rtpdump_send", rtp_dumps.outgoing_dump_path)); | |
| 574 } | |
| 575 | |
| 458 upload_done_data.callback = upload_callback_; | 576 upload_done_data.callback = upload_callback_; |
| 459 upload_done_data.host = this; | 577 upload_done_data.host = this; |
| 460 upload_callback_.Reset(); | 578 upload_callback_.Reset(); |
| 461 | 579 |
| 462 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind( | 580 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind( |
| 463 &WebRtcLogUploader::LoggingStoppedDoUpload, | 581 &WebRtcLogUploader::LoggingStoppedDoUpload, |
| 464 base::Unretained(g_browser_process->webrtc_log_uploader()), | 582 base::Unretained(g_browser_process->webrtc_log_uploader()), |
| 465 Passed(&log_buffer_), | 583 Passed(&log_buffer_), |
| 466 kWebRtcLogSize, | 584 kWebRtcLogSize, |
| 467 meta_data_, | 585 meta_data_, |
| 468 upload_done_data)); | 586 upload_done_data)); |
| 469 | 587 |
| 470 meta_data_.clear(); | 588 meta_data_.clear(); |
| 471 circular_buffer_.reset(); | 589 circular_buffer_.reset(); |
| 472 } | 590 } |
| 473 | |
| 474 void WebRtcLoggingHandlerHost::FireGenericDoneCallback( | |
| 475 GenericDoneCallback* callback, bool success, | |
| 476 const std::string& error_message) { | |
| 477 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 478 DCHECK(!(*callback).is_null()); | |
| 479 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | |
| 480 base::Bind(*callback, success, | |
| 481 error_message)); | |
| 482 (*callback).Reset(); | |
| 483 } | |
| OLD | NEW |