render_thread_impl.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
1// Copyright (c) 2012 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 "content/renderer/render_thread_impl.h" 6 7#include <algorithm> 8#include <limits> 9#include <map> 10#include <vector> 11 12#include "base/allocator/allocator_extension.h" 13#include "base/command_line.h" 14#include "base/debug/trace_event.h" 15#include "base/lazy_instance.h" 16#include "base/logging.h" 17#include "base/metrics/field_trial.h" 18#include "base/metrics/histogram.h" 19#include "base/metrics/stats_table.h" 20#include "base/path_service.h" 21#include "base/shared_memory.h" 22#include "base/strings/string16.h" 23#include "base/strings/string_number_conversions.h" // Temporary 24#include "base/strings/utf_string_conversions.h" 25#include "base/threading/thread_local.h" 26#include "base/threading/thread_restrictions.h" 27#include "base/values.h" 28#include "content/child/appcache_dispatcher.h" 29#include "content/child/child_histogram_message_filter.h" 30#include "content/child/indexed_db/indexed_db_dispatcher.h" 31#include "content/child/indexed_db/indexed_db_message_filter.h" 32#include "content/child/npobject_util.h" 33#include "content/child/plugin_messages.h" 34#include "content/child/resource_dispatcher.h" 35#include "content/child/runtime_features.h" 36#include "content/child/web_database_observer_impl.h" 37#include "content/common/child_process_messages.h" 38#include "content/common/database_messages.h" 39#include "content/common/db_message_filter.h" 40#include "content/common/dom_storage_messages.h" 41#include "content/common/gpu/client/context_provider_command_buffer.h" 42#include "content/common/gpu/client/gpu_channel_host.h" 43#include "content/common/gpu/gpu_messages.h" 44#include "content/common/resource_messages.h" 45#include "content/common/view_messages.h" 46#include "content/public/common/content_constants.h" 47#include "content/public/common/content_paths.h" 48#include "content/public/common/content_switches.h" 49#include "content/public/common/renderer_preferences.h" 50#include "content/public/common/url_constants.h" 51#include "content/public/renderer/content_renderer_client.h" 52#include "content/public/renderer/render_process_observer.h" 53#include "content/public/renderer/render_view_visitor.h" 54#include "content/renderer/devtools/devtools_agent_filter.h" 55#include "content/renderer/dom_storage/dom_storage_dispatcher.h" 56#include "content/renderer/dom_storage/webstoragearea_impl.h" 57#include "content/renderer/dom_storage/webstoragenamespace_impl.h" 58#include "content/renderer/gpu/compositor_output_surface.h" 59#include "content/renderer/gpu/gpu_benchmarking_extension.h" 60#include "content/renderer/gpu/input_event_filter.h" 61#include "content/renderer/gpu/input_handler_manager.h" 62#include "content/renderer/media/audio_input_message_filter.h" 63#include "content/renderer/media/audio_message_filter.h" 64#include "content/renderer/media/audio_renderer_mixer_manager.h" 65#include "content/renderer/media/media_stream_center.h" 66#include "content/renderer/media/media_stream_dependency_factory.h" 67#include "content/renderer/media/peer_connection_tracker.h" 68#include "content/renderer/media/video_capture_impl_manager.h" 69#include "content/renderer/media/video_capture_message_filter.h" 70#include "content/renderer/memory_benchmarking_extension.h" 71#include "content/renderer/p2p/socket_dispatcher.h" 72#include "content/renderer/plugin_channel_host.h" 73#include "content/renderer/render_process_impl.h" 74#include "content/renderer/render_view_impl.h" 75#include "content/renderer/renderer_webkitplatformsupport_impl.h" 76#include "content/renderer/skia_benchmarking_extension.h" 77#include "grit/content_resources.h" 78#include "ipc/ipc_channel_handle.h" 79#include "ipc/ipc_forwarding_message_filter.h" 80#include "ipc/ipc_platform_file.h" 81#include "media/base/audio_hardware_config.h" 82#include "media/base/media.h" 83#include "net/base/net_errors.h" 84#include "net/base/net_util.h" 85#include "third_party/WebKit/public/web/WebColorName.h" 86#include "third_party/WebKit/public/web/WebDatabase.h" 87#include "third_party/WebKit/public/web/WebDocument.h" 88#include "third_party/WebKit/public/web/WebFrame.h" 89#include "third_party/WebKit/public/web/WebKit.h" 90#include "third_party/WebKit/public/web/WebNetworkStateNotifier.h" 91#include "third_party/WebKit/public/web/WebPopupMenu.h" 92#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" 93#include "third_party/WebKit/public/web/WebScriptController.h" 94#include "third_party/WebKit/public/web/WebSecurityPolicy.h" 95#include "third_party/WebKit/public/web/WebSharedWorkerRepository.h" 96#include "third_party/WebKit/public/web/WebView.h" 97#include "third_party/WebKit/public/platform/WebString.h" 98#include "ui/base/layout.h" 99#include "ui/base/ui_base_switches.h" 100#include "v8/include/v8.h" 101#include "webkit/glue/webkit_glue.h" 102#include "webkit/child/worker_task_runner.h" 103#include "webkit/renderer/appcache/appcache_frontend_impl.h" 104 105#if defined(OS_WIN) 106#include <windows.h> 107#include <objbase.h> 108#include "base/win/scoped_com_initializer.h" 109#else 110// TODO(port) 111#include "base/memory/scoped_handle.h" 112#include "content/child/np_channel_base.h" 113#endif 114 115#if defined(OS_POSIX) 116#include "ipc/ipc_channel_posix.h" 117#endif 118 119#if defined(OS_ANDROID) 120#include <cpu-features.h> 121#include "content/renderer/android/synchronous_compositor_factory.h" 122#endif 123 124using base::ThreadRestrictions; 125using WebKit::WebDocument; 126using WebKit::WebFrame; 127using WebKit::WebNetworkStateNotifier; 128using WebKit::WebRuntimeFeatures; 129using WebKit::WebScriptController; 130using WebKit::WebSecurityPolicy; 131using WebKit::WebString; 132using WebKit::WebView; 133 134namespace content { 135 136namespace { 137 138const int64 kInitialIdleHandlerDelayMs = 1000; 139const int64 kShortIdleHandlerDelayMs = 1000; 140const int64 kLongIdleHandlerDelayMs = 30*1000; 141const int kIdleCPUUsageThresholdInPercents = 3; 142 143// Keep the global RenderThreadImpl in a TLS slot so it is impossible to access 144// incorrectly from the wrong thread. 145base::LazyInstance<base::ThreadLocalPointer<RenderThreadImpl> > 146 lazy_tls = LAZY_INSTANCE_INITIALIZER; 147 148class RenderViewZoomer : public RenderViewVisitor { 149 public: 150 RenderViewZoomer(const std::string& scheme, 151 const std::string& host, 152 double zoom_level) : scheme_(scheme), 153 host_(host), 154 zoom_level_(zoom_level) { 155 } 156 157 virtual bool Visit(RenderView* render_view) OVERRIDE { 158 WebView* webview = render_view->GetWebView(); 159 WebDocument document = webview->mainFrame()->document(); 160 161 // Don't set zoom level for full-page plugin since they don't use the same 162 // zoom settings. 163 if (document.isPluginDocument()) 164 return true; 165 GURL url(document.url()); 166 // Empty scheme works as wildcard that matches any scheme, 167 if ((net::GetHostOrSpecFromURL(url) == host_) && 168 (scheme_.empty() || scheme_ == url.scheme())) { 169 webview->setZoomLevel(false, zoom_level_); 170 } 171 return true; 172 } 173 174 private: 175 const std::string scheme_; 176 const std::string host_; 177 const double zoom_level_; 178 179 DISALLOW_COPY_AND_ASSIGN(RenderViewZoomer); 180}; 181 182std::string HostToCustomHistogramSuffix(const std::string& host) { 183 if (host == "mail.google.com") 184 return ".gmail"; 185 if (host == "docs.google.com" || host == "drive.google.com") 186 return ".docs"; 187 if (host == "plus.google.com") 188 return ".plus"; 189 return std::string(); 190} 191 192void* CreateHistogram( 193 const char *name, int min, int max, size_t buckets) { 194 if (min <= 0) 195 min = 1; 196 std::string histogram_name; 197 RenderThreadImpl* render_thread_impl = RenderThreadImpl::current(); 198 if (render_thread_impl) { // Can be null in tests. 199 histogram_name = render_thread_impl-> 200 histogram_customizer()->ConvertToCustomHistogramName(name); 201 } else { 202 histogram_name = std::string(name); 203 } 204 base::HistogramBase* histogram = base::Histogram::FactoryGet( 205 histogram_name, min, max, buckets, 206 base::Histogram::kUmaTargetedHistogramFlag); 207 return histogram; 208} 209 210void AddHistogramSample(void* hist, int sample) { 211 base::Histogram* histogram = static_cast<base::Histogram*>(hist); 212 histogram->Add(sample); 213} 214 215} // namespace 216 217class RenderThreadImpl::GpuVDAContextLostCallback 218 : public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback { 219 public: 220 GpuVDAContextLostCallback() {} 221 virtual ~GpuVDAContextLostCallback() {} 222 virtual void onContextLost() { 223 ChildThread::current()->message_loop()->PostTask(FROM_HERE, base::Bind( 224 &RenderThreadImpl::OnGpuVDAContextLoss)); 225 } 226}; 227 228class RenderThreadImpl::RendererContextProviderCommandBuffer 229 : public ContextProviderCommandBuffer { 230 public: 231 static scoped_refptr<RendererContextProviderCommandBuffer> Create() { 232 scoped_refptr<RendererContextProviderCommandBuffer> provider = 233 new RendererContextProviderCommandBuffer(); 234 if (!provider->InitializeOnMainThread()) 235 return NULL; 236 return provider; 237 } 238 239 protected: 240 virtual ~RendererContextProviderCommandBuffer() {} 241 242 virtual scoped_ptr<WebGraphicsContext3DCommandBufferImpl> 243 CreateOffscreenContext3d() OVERRIDE { 244 RenderThreadImpl* self = RenderThreadImpl::current(); 245 DCHECK(self); 246 return self->CreateOffscreenContext3d().Pass(); 247 } 248}; 249 250RenderThreadImpl::HistogramCustomizer::HistogramCustomizer() { 251 custom_histograms_.insert("V8.MemoryExternalFragmentationTotal"); 252 custom_histograms_.insert("V8.MemoryHeapSampleTotalCommitted"); 253 custom_histograms_.insert("V8.MemoryHeapSampleTotalUsed"); 254} 255 256RenderThreadImpl::HistogramCustomizer::~HistogramCustomizer() {} 257 258void RenderThreadImpl::HistogramCustomizer::RenderViewNavigatedToHost( 259 const std::string& host, size_t view_count) { 260 if (CommandLine::ForCurrentProcess()->HasSwitch( 261 switches::kDisableHistogramCustomizer)) { 262 return; 263 } 264 // Check if all RenderViews are displaying a page from the same host. If there 265 // is only one RenderView, the common host is this view's host. If there are 266 // many, check if this one shares the common host of the other 267 // RenderViews. It's ok to not detect some cases where the RenderViews share a 268 // common host. This information is only used for producing custom histograms. 269 if (view_count == 1) 270 SetCommonHost(host); 271 else if (host != common_host_) 272 SetCommonHost(std::string()); 273} 274 275std::string RenderThreadImpl::HistogramCustomizer::ConvertToCustomHistogramName( 276 const char* histogram_name) const { 277 std::string name(histogram_name); 278 if (!common_host_histogram_suffix_.empty() && 279 custom_histograms_.find(name) != custom_histograms_.end()) 280 name += common_host_histogram_suffix_; 281 return name; 282} 283 284void RenderThreadImpl::HistogramCustomizer::SetCommonHost( 285 const std::string& host) { 286 if (host != common_host_) { 287 common_host_ = host; 288 common_host_histogram_suffix_ = HostToCustomHistogramSuffix(host); 289 v8::V8::SetCreateHistogramFunction(CreateHistogram); 290 } 291} 292 293RenderThreadImpl* RenderThreadImpl::current() { 294 return lazy_tls.Pointer()->Get(); 295} 296 297// When we run plugins in process, we actually run them on the render thread, 298// which means that we need to make the render thread pump UI events. 299RenderThreadImpl::RenderThreadImpl() { 300 Init(); 301} 302 303RenderThreadImpl::RenderThreadImpl(const std::string& channel_name) 304 : ChildThread(channel_name) { 305 Init(); 306} 307 308void RenderThreadImpl::Init() { 309 TRACE_EVENT_BEGIN_ETW("RenderThreadImpl::Init", 0, ""); 310 311 v8::V8::SetCounterFunction(base::StatsTable::FindLocation); 312 v8::V8::SetCreateHistogramFunction(CreateHistogram); 313 v8::V8::SetAddHistogramSampleFunction(AddHistogramSample); 314 315#if defined(OS_MACOSX) || defined(OS_ANDROID) 316 // On Mac and Android, the select popups are rendered by the browser. 317 WebKit::WebView::setUseExternalPopupMenus(true); 318#endif 319 320 lazy_tls.Pointer()->Set(this); 321 322#if defined(OS_WIN) 323 // If you are running plugins in this thread you need COM active but in 324 // the normal case you don't. 325 if (RenderProcessImpl::InProcessPlugins()) 326 initialize_com_.reset(new base::win::ScopedCOMInitializer()); 327#endif 328 329 // Register this object as the main thread. 330 ChildProcess::current()->set_main_thread(this); 331 332 // In single process the single process is all there is. 333 suspend_webkit_shared_timer_ = true; 334 notify_webkit_of_modal_loop_ = true; 335 widget_count_ = 0; 336 hidden_widget_count_ = 0; 337 idle_notification_delay_in_ms_ = kInitialIdleHandlerDelayMs; 338 idle_notifications_to_skip_ = 0; 339 layout_test_mode_ = false; 340 341 appcache_dispatcher_.reset( 342 new AppCacheDispatcher(Get(), new appcache::AppCacheFrontendImpl())); 343 dom_storage_dispatcher_.reset(new DomStorageDispatcher()); 344 main_thread_indexed_db_dispatcher_.reset(new IndexedDBDispatcher()); 345 346 media_stream_center_ = NULL; 347 348 db_message_filter_ = new DBMessageFilter(); 349 AddFilter(db_message_filter_.get()); 350 351#if defined(ENABLE_WEBRTC) 352 peer_connection_tracker_.reset(new PeerConnectionTracker()); 353 AddObserver(peer_connection_tracker_.get()); 354 355 p2p_socket_dispatcher_ = 356 new P2PSocketDispatcher(GetIOMessageLoopProxy().get()); 357 AddFilter(p2p_socket_dispatcher_.get()); 358#endif // defined(ENABLE_WEBRTC) 359 vc_manager_ = new VideoCaptureImplManager(); 360 AddFilter(vc_manager_->video_capture_message_filter()); 361 362 audio_input_message_filter_ = 363 new AudioInputMessageFilter(GetIOMessageLoopProxy()); 364 AddFilter(audio_input_message_filter_.get()); 365 366 audio_message_filter_ = new AudioMessageFilter(GetIOMessageLoopProxy()); 367 AddFilter(audio_message_filter_.get()); 368 369 AddFilter(new IndexedDBMessageFilter); 370 371 GetContentClient()->renderer()->RenderThreadStarted(); 372 373 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 374 if (command_line.HasSwitch(switches::kEnableGpuBenchmarking)) 375 RegisterExtension(GpuBenchmarkingExtension::Get()); 376 377#if defined(USE_TCMALLOC) && (defined(OS_LINUX) || defined(OS_ANDROID)) 378 if (command_line.HasSwitch(switches::kEnableMemoryBenchmarking)) 379 RegisterExtension(MemoryBenchmarkingExtension::Get()); 380#endif // USE_TCMALLOC 381 382 if (command_line.HasSwitch(switches::kEnableSkiaBenchmarking)) { 383 LOG(WARNING) << "Enabling unsafe Skia benchmarking extension."; 384 RegisterExtension(SkiaBenchmarkingExtension::Get()); 385 } 386 387 context_lost_cb_.reset(new GpuVDAContextLostCallback()); 388 389 // Note that under Linux, the media library will normally already have 390 // been initialized by the Zygote before this instance became a Renderer. 391 base::FilePath media_path; 392 PathService::Get(DIR_MEDIA_LIBS, &media_path); 393 if (!media_path.empty()) 394 media::InitializeMediaLibrary(media_path); 395 396 TRACE_EVENT_END_ETW("RenderThreadImpl::Init", 0, ""); 397} 398 399RenderThreadImpl::~RenderThreadImpl() { 400} 401 402void RenderThreadImpl::Shutdown() { 403 FOR_EACH_OBSERVER( 404 RenderProcessObserver, observers_, OnRenderProcessShutdown()); 405 406 // Wait for all databases to be closed. 407 if (web_database_observer_impl_) 408 web_database_observer_impl_->WaitForAllDatabasesToClose(); 409 410 // Shutdown in reverse of the initialization order. 411 if (devtools_agent_message_filter_.get()) { 412 RemoveFilter(devtools_agent_message_filter_.get()); 413 devtools_agent_message_filter_ = NULL; 414 } 415 416 RemoveFilter(audio_input_message_filter_.get()); 417 audio_input_message_filter_ = NULL; 418 419 RemoveFilter(audio_message_filter_.get()); 420 audio_message_filter_ = NULL; 421 422 RemoveFilter(vc_manager_->video_capture_message_filter()); 423 424 RemoveFilter(db_message_filter_.get()); 425 db_message_filter_ = NULL; 426 427 // Shutdown the file thread if it's running. 428 if (file_thread_) 429 file_thread_->Stop(); 430 431 if (compositor_output_surface_filter_.get()) { 432 RemoveFilter(compositor_output_surface_filter_.get()); 433 compositor_output_surface_filter_ = NULL; 434 } 435 436 compositor_thread_.reset(); 437 input_handler_manager_.reset(); 438 if (input_event_filter_.get()) { 439 RemoveFilter(input_event_filter_.get()); 440 input_event_filter_ = NULL; 441 } 442 443 if (webkit_platform_support_) 444 WebKit::shutdown(); 445 446 lazy_tls.Pointer()->Set(NULL); 447 448 // TODO(port) 449#if defined(OS_WIN) 450 // Clean up plugin channels before this thread goes away. 451 NPChannelBase::CleanupChannels(); 452#endif 453 454 // Leak shared contexts on other threads, as we can not get to the correct 455 // thread to destroy them. 456 if (shared_contexts_compositor_thread_.get()) 457 shared_contexts_compositor_thread_->set_leak_on_destroy(); 458} 459 460bool RenderThreadImpl::Send(IPC::Message* msg) { 461 // Certain synchronous messages cannot always be processed synchronously by 462 // the browser, e.g., Chrome frame communicating with the embedding browser. 463 // This could cause a complete hang of Chrome if a windowed plug-in is trying 464 // to communicate with the renderer thread since the browser's UI thread 465 // could be stuck (within a Windows API call) trying to synchronously 466 // communicate with the plug-in. The remedy is to pump messages on this 467 // thread while the browser is processing this request. This creates an 468 // opportunity for re-entrancy into WebKit, so we need to take care to disable 469 // callbacks, timers, and pending network loads that could trigger such 470 // callbacks. 471 bool pumping_events = false; 472 if (msg->is_sync()) { 473 if (msg->is_caller_pumping_messages()) { 474 pumping_events = true; 475 } else { 476 if ((msg->type() == ViewHostMsg_GetCookies::ID || 477 msg->type() == ViewHostMsg_GetRawCookies::ID || 478 msg->type() == ViewHostMsg_CookiesEnabled::ID) && 479 GetContentClient()->renderer()-> 480 ShouldPumpEventsDuringCookieMessage()) { 481 pumping_events = true; 482 } 483 } 484 } 485 486 bool suspend_webkit_shared_timer = true; // default value 487 std::swap(suspend_webkit_shared_timer, suspend_webkit_shared_timer_); 488 489 bool notify_webkit_of_modal_loop = true; // default value 490 std::swap(notify_webkit_of_modal_loop, notify_webkit_of_modal_loop_); 491 492 int render_view_id = MSG_ROUTING_NONE; 493 494 if (pumping_events) { 495 if (suspend_webkit_shared_timer) 496 webkit_platform_support_->SuspendSharedTimer(); 497 498 if (notify_webkit_of_modal_loop) 499 WebView::willEnterModalLoop(); 500 501 RenderViewImpl* render_view = 502 RenderViewImpl::FromRoutingID(msg->routing_id()); 503 if (render_view) { 504 render_view_id = msg->routing_id(); 505 PluginChannelHost::Broadcast( 506 new PluginMsg_SignalModalDialogEvent(render_view_id)); 507 } 508 } 509 510 bool rv = ChildThread::Send(msg); 511 512 if (pumping_events) { 513 if (render_view_id != MSG_ROUTING_NONE) { 514 PluginChannelHost::Broadcast( 515 new PluginMsg_ResetModalDialogEvent(render_view_id)); 516 } 517 518 if (notify_webkit_of_modal_loop) 519 WebView::didExitModalLoop(); 520 521 if (suspend_webkit_shared_timer) 522 webkit_platform_support_->ResumeSharedTimer(); 523 } 524 525 return rv; 526} 527 528base::MessageLoop* RenderThreadImpl::GetMessageLoop() { 529 return message_loop(); 530} 531 532IPC::SyncChannel* RenderThreadImpl::GetChannel() { 533 return channel(); 534} 535 536std::string RenderThreadImpl::GetLocale() { 537 // The browser process should have passed the locale to the renderer via the 538 // --lang command line flag. 539 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); 540 const std::string& lang = 541 parsed_command_line.GetSwitchValueASCII(switches::kLang); 542 DCHECK(!lang.empty()); 543 return lang; 544} 545 546IPC::SyncMessageFilter* RenderThreadImpl::GetSyncMessageFilter() { 547 return sync_message_filter(); 548} 549 550scoped_refptr<base::MessageLoopProxy> 551 RenderThreadImpl::GetIOMessageLoopProxy() { 552 return ChildProcess::current()->io_message_loop_proxy(); 553} 554 555void RenderThreadImpl::AddRoute(int32 routing_id, IPC::Listener* listener) { 556 widget_count_++; 557 return ChildThread::AddRoute(routing_id, listener); 558} 559 560void RenderThreadImpl::RemoveRoute(int32 routing_id) { 561 widget_count_--; 562 return ChildThread::RemoveRoute(routing_id); 563} 564 565int RenderThreadImpl::GenerateRoutingID() { 566 int routing_id = MSG_ROUTING_NONE; 567 Send(new ViewHostMsg_GenerateRoutingID(&routing_id)); 568 return routing_id; 569} 570 571void RenderThreadImpl::AddFilter(IPC::ChannelProxy::MessageFilter* filter) { 572 channel()->AddFilter(filter); 573} 574 575void RenderThreadImpl::RemoveFilter(IPC::ChannelProxy::MessageFilter* filter) { 576 channel()->RemoveFilter(filter); 577} 578 579void RenderThreadImpl::SetOutgoingMessageFilter( 580 IPC::ChannelProxy::OutgoingMessageFilter* filter) { 581} 582 583void RenderThreadImpl::AddObserver(RenderProcessObserver* observer) { 584 observers_.AddObserver(observer); 585} 586 587void RenderThreadImpl::RemoveObserver(RenderProcessObserver* observer) { 588 observers_.RemoveObserver(observer); 589} 590 591void RenderThreadImpl::SetResourceDispatcherDelegate( 592 ResourceDispatcherDelegate* delegate) { 593 resource_dispatcher()->set_delegate(delegate); 594} 595 596void RenderThreadImpl::WidgetHidden() { 597 DCHECK(hidden_widget_count_ < widget_count_); 598 hidden_widget_count_++; 599 600 if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden()) { 601 return; 602 } 603 604 if (widget_count_ && hidden_widget_count_ == widget_count_) 605 ScheduleIdleHandler(kInitialIdleHandlerDelayMs); 606} 607 608void RenderThreadImpl::WidgetRestored() { 609 DCHECK_GT(hidden_widget_count_, 0); 610 hidden_widget_count_--; 611 if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden()) { 612 return; 613 } 614 615 ScheduleIdleHandler(kLongIdleHandlerDelayMs); 616} 617 618void RenderThreadImpl::EnsureWebKitInitialized() { 619 if (webkit_platform_support_) 620 return; 621 622 webkit_platform_support_.reset(new RendererWebKitPlatformSupportImpl); 623 WebKit::initialize(webkit_platform_support_.get()); 624 WebKit::setSharedWorkerRepository( 625 webkit_platform_support_.get()->sharedWorkerRepository()); 626 627 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 628 629 bool enable = command_line.HasSwitch(switches::kEnableThreadedCompositing); 630 if (enable) { 631#if defined(OS_ANDROID) 632 if (SynchronousCompositorFactory* factory = 633 SynchronousCompositorFactory::GetInstance()) 634 compositor_message_loop_proxy_ = 635 factory->GetCompositorMessageLoop(); 636#endif 637 if (!compositor_message_loop_proxy_.get()) { 638 compositor_thread_.reset(new base::Thread("Compositor")); 639 compositor_thread_->Start(); 640#if defined(OS_ANDROID) 641 compositor_thread_->SetPriority(base::kThreadPriority_Display); 642#endif 643 compositor_message_loop_proxy_ = 644 compositor_thread_->message_loop_proxy(); 645 compositor_message_loop_proxy_->PostTask( 646 FROM_HERE, 647 base::Bind(base::IgnoreResult(&ThreadRestrictions::SetIOAllowed), 648 false)); 649 } 650 651 InputHandlerManagerClient* input_handler_manager_client = NULL; 652#if defined(OS_ANDROID) 653 if (SynchronousCompositorFactory* factory = 654 SynchronousCompositorFactory::GetInstance()) { 655 input_handler_manager_client = factory->GetInputHandlerManagerClient(); 656 } 657#endif 658 if (!input_handler_manager_client) { 659 input_event_filter_ = 660 new InputEventFilter(this, compositor_message_loop_proxy_); 661 AddFilter(input_event_filter_.get()); 662 input_handler_manager_client = input_event_filter_.get(); 663 } 664 input_handler_manager_.reset( 665 new InputHandlerManager(compositor_message_loop_proxy_, 666 input_handler_manager_client)); 667 } 668 669 scoped_refptr<base::MessageLoopProxy> output_surface_loop; 670 if (enable) 671 output_surface_loop = compositor_message_loop_proxy_; 672 else 673 output_surface_loop = base::MessageLoopProxy::current(); 674 675 compositor_output_surface_filter_ = 676 CompositorOutputSurface::CreateFilter(output_surface_loop.get()); 677 AddFilter(compositor_output_surface_filter_.get()); 678 679 WebScriptController::enableV8SingleThreadMode(); 680 681 RenderThreadImpl::RegisterSchemes(); 682 683 webkit_glue::EnableWebCoreLogChannels( 684 command_line.GetSwitchValueASCII(switches::kWebCoreLogChannels)); 685 686 web_database_observer_impl_.reset( 687 new WebDatabaseObserverImpl(sync_message_filter())); 688 WebKit::WebDatabase::setObserver(web_database_observer_impl_.get()); 689 690 SetRuntimeFeaturesDefaultsAndUpdateFromArgs(command_line); 691 692 if (!media::IsMediaLibraryInitialized()) { 693 WebRuntimeFeatures::enableMediaPlayer(false); 694 WebRuntimeFeatures::enableWebAudio(false); 695 } 696 697 FOR_EACH_OBSERVER(RenderProcessObserver, observers_, WebKitInitialized()); 698 699 devtools_agent_message_filter_ = new DevToolsAgentFilter(); 700 AddFilter(devtools_agent_message_filter_.get()); 701 702 if (GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden()) 703 ScheduleIdleHandler(kLongIdleHandlerDelayMs); 704} 705 706void RenderThreadImpl::RegisterSchemes() { 707 // swappedout: pages should not be accessible, and should also 708 // be treated as empty documents that can commit synchronously. 709 WebString swappedout_scheme(ASCIIToUTF16(chrome::kSwappedOutScheme)); 710 WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(swappedout_scheme); 711 WebSecurityPolicy::registerURLSchemeAsEmptyDocument(swappedout_scheme); 712} 713 714void RenderThreadImpl::RecordUserMetrics(const std::string& action) { 715 Send(new ViewHostMsg_UserMetricsRecordAction(action)); 716} 717 718scoped_ptr<base::SharedMemory> 719 RenderThreadImpl::HostAllocateSharedMemoryBuffer(size_t size) { 720 if (size > static_cast<size_t>(std::numeric_limits<int>::max())) 721 return scoped_ptr<base::SharedMemory>(); 722 723 base::SharedMemoryHandle handle; 724 bool success; 725 IPC::Message* message = 726 new ChildProcessHostMsg_SyncAllocateSharedMemory(size, &handle); 727 728 // Allow calling this from the compositor thread. 729 if (base::MessageLoop::current() == message_loop()) 730 success = ChildThread::Send(message); 731 else 732 success = sync_message_filter()->Send(message); 733 734 if (!success) 735 return scoped_ptr<base::SharedMemory>(); 736 737 if (!base::SharedMemory::IsHandleValid(handle)) 738 return scoped_ptr<base::SharedMemory>(); 739 740 return scoped_ptr<base::SharedMemory>(new base::SharedMemory(handle, false)); 741} 742 743void RenderThreadImpl::RegisterExtension(v8::Extension* extension) { 744 WebScriptController::registerExtension(extension); 745} 746 747void RenderThreadImpl::ScheduleIdleHandler(int64 initial_delay_ms) { 748 idle_notification_delay_in_ms_ = initial_delay_ms; 749 idle_timer_.Stop(); 750 idle_timer_.Start(FROM_HERE, 751 base::TimeDelta::FromMilliseconds(initial_delay_ms), 752 this, &RenderThreadImpl::IdleHandler); 753} 754 755void RenderThreadImpl::IdleHandler() { 756 bool run_in_foreground_tab = (widget_count_ > hidden_widget_count_) && 757 GetContentClient()->renderer()-> 758 RunIdleHandlerWhenWidgetsHidden(); 759 if (run_in_foreground_tab) { 760 IdleHandlerInForegroundTab(); 761 return; 762 } 763 764 base::allocator::ReleaseFreeMemory(); 765 766 v8::V8::IdleNotification(); 767 768 // Schedule next invocation. 769 // Dampen the delay using the algorithm (if delay is in seconds): 770 // delay = delay + 1 / (delay + 2) 771 // Using floor(delay) has a dampening effect such as: 772 // 1s, 1, 1, 2, 2, 2, 2, 3, 3, ... 773 // If the delay is in milliseconds, the above formula is equivalent to: 774 // delay_ms / 1000 = delay_ms / 1000 + 1 / (delay_ms / 1000 + 2) 775 // which is equivalent to 776 // delay_ms = delay_ms + 1000*1000 / (delay_ms + 2000). 777 // Note that idle_notification_delay_in_ms_ would be reset to 778 // kInitialIdleHandlerDelayMs in RenderThreadImpl::WidgetHidden. 779 ScheduleIdleHandler(idle_notification_delay_in_ms_ + 780 1000000 / (idle_notification_delay_in_ms_ + 2000)); 781 782 FOR_EACH_OBSERVER(RenderProcessObserver, observers_, IdleNotification()); 783} 784 785void RenderThreadImpl::IdleHandlerInForegroundTab() { 786 // Increase the delay in the same way as in IdleHandler, 787 // but make it periodic by reseting it once it is too big. 788 int64 new_delay_ms = idle_notification_delay_in_ms_ + 789 1000000 / (idle_notification_delay_in_ms_ + 2000); 790 if (new_delay_ms >= kLongIdleHandlerDelayMs) 791 new_delay_ms = kShortIdleHandlerDelayMs; 792 793 if (idle_notifications_to_skip_ > 0) { 794 idle_notifications_to_skip_--; 795 } else { 796 int cpu_usage = 0; 797 Send(new ViewHostMsg_GetCPUUsage(&cpu_usage)); 798 // Idle notification hint roughly specifies the expected duration of the 799 // idle pause. We set it proportional to the idle timer delay. 800 int idle_hint = static_cast<int>(new_delay_ms / 10); 801 if (cpu_usage < kIdleCPUUsageThresholdInPercents) { 802 base::allocator::ReleaseFreeMemory(); 803 if (v8::V8::IdleNotification(idle_hint)) { 804 // V8 finished collecting garbage. 805 new_delay_ms = kLongIdleHandlerDelayMs; 806 } 807 } 808 } 809 ScheduleIdleHandler(new_delay_ms); 810} 811 812int64 RenderThreadImpl::GetIdleNotificationDelayInMs() const { 813 return idle_notification_delay_in_ms_; 814} 815 816void RenderThreadImpl::SetIdleNotificationDelayInMs( 817 int64 idle_notification_delay_in_ms) { 818 idle_notification_delay_in_ms_ = idle_notification_delay_in_ms; 819} 820 821void RenderThreadImpl::ToggleWebKitSharedTimer(bool suspend) { 822 if (suspend_webkit_shared_timer_) { 823 EnsureWebKitInitialized(); 824 if (suspend) { 825 webkit_platform_support_->SuspendSharedTimer(); 826 } else { 827 webkit_platform_support_->ResumeSharedTimer(); 828 } 829 } 830} 831 832void RenderThreadImpl::UpdateHistograms(int sequence_number) { 833 child_histogram_message_filter()->SendHistograms(sequence_number); 834} 835 836int RenderThreadImpl::PostTaskToAllWebWorkers(const base::Closure& closure) { 837 return webkit_glue::WorkerTaskRunner::Instance()->PostTaskToAllThreads( 838 closure); 839} 840 841bool RenderThreadImpl::ResolveProxy(const GURL& url, std::string* proxy_list) { 842 bool result = false; 843 Send(new ViewHostMsg_ResolveProxy(url, &result, proxy_list)); 844 return result; 845} 846 847void RenderThreadImpl::PostponeIdleNotification() { 848 idle_notifications_to_skip_ = 2; 849} 850 851/* static */ 852void RenderThreadImpl::OnGpuVDAContextLoss() { 853 RenderThreadImpl* self = RenderThreadImpl::current(); 854 DCHECK(self); 855 if (!self->gpu_vda_context3d_) 856 return; 857 if (self->compositor_message_loop_proxy().get()) { 858 self->compositor_message_loop_proxy() 859 ->DeleteSoon(FROM_HERE, self->gpu_vda_context3d_.release()); 860 } else { 861 self->gpu_vda_context3d_.reset(); 862 } 863} 864 865WebGraphicsContext3DCommandBufferImpl* 866RenderThreadImpl::GetGpuVDAContext3D() { 867 if (!gpu_vda_context3d_) { 868 gpu_vda_context3d_.reset( 869 WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext( 870 this, WebKit::WebGraphicsContext3D::Attributes(), 871 GURL("chrome://gpu/RenderThreadImpl::GetGpuVDAContext3D"))); 872 if (gpu_vda_context3d_) 873 gpu_vda_context3d_->setContextLostCallback(context_lost_cb_.get()); 874 } 875 return gpu_vda_context3d_.get(); 876} 877 878scoped_ptr<WebGraphicsContext3DCommandBufferImpl> 879RenderThreadImpl::CreateOffscreenContext3d() { 880 WebKit::WebGraphicsContext3D::Attributes attributes; 881 attributes.shareResources = true; 882 attributes.depth = false; 883 attributes.stencil = false; 884 attributes.antialias = false; 885 attributes.noAutomaticFlushes = true; 886 887 return make_scoped_ptr( 888 WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext( 889 this, 890 attributes, 891 GURL("chrome://gpu/RenderThreadImpl::CreateOffscreenContext3d"))); 892} 893 894scoped_refptr<cc::ContextProvider> 895RenderThreadImpl::OffscreenContextProviderForMainThread() { 896 DCHECK(IsMainThread()); 897 898#if defined(OS_ANDROID) 899 if (SynchronousCompositorFactory* factory = 900 SynchronousCompositorFactory::GetInstance()) { 901 return factory->GetOffscreenContextProviderForMainThread(); 902 } 903#endif 904 905 if (!shared_contexts_main_thread_.get() || 906 shared_contexts_main_thread_->DestroyedOnMainThread()) { 907 shared_contexts_main_thread_ = 908 RendererContextProviderCommandBuffer::Create(); 909 if (shared_contexts_main_thread_.get() && 910 !shared_contexts_main_thread_->BindToCurrentThread()) 911 shared_contexts_main_thread_ = NULL; 912 } 913 return shared_contexts_main_thread_; 914} 915 916scoped_refptr<cc::ContextProvider> 917RenderThreadImpl::OffscreenContextProviderForCompositorThread() { 918 DCHECK(IsMainThread()); 919 920#if defined(OS_ANDROID) 921 if (SynchronousCompositorFactory* factory = 922 SynchronousCompositorFactory::GetInstance()) { 923 return factory->GetOffscreenContextProviderForCompositorThread(); 924 } 925#endif 926 927 if (!shared_contexts_compositor_thread_.get() || 928 shared_contexts_compositor_thread_->DestroyedOnMainThread()) { 929 shared_contexts_compositor_thread_ = 930 RendererContextProviderCommandBuffer::Create(); 931 } 932 return shared_contexts_compositor_thread_; 933} 934 935AudioRendererMixerManager* RenderThreadImpl::GetAudioRendererMixerManager() { 936 if (!audio_renderer_mixer_manager_) { 937 audio_renderer_mixer_manager_.reset(new AudioRendererMixerManager( 938 GetAudioHardwareConfig())); 939 } 940 941 return audio_renderer_mixer_manager_.get(); 942} 943 944media::AudioHardwareConfig* RenderThreadImpl::GetAudioHardwareConfig() { 945 if (!audio_hardware_config_) { 946 media::AudioParameters input_params; 947 media::AudioParameters output_params; 948 Send(new ViewHostMsg_GetAudioHardwareConfig( 949 &input_params, &output_params)); 950 951 audio_hardware_config_.reset(new media::AudioHardwareConfig( 952 input_params, output_params)); 953 audio_message_filter_->SetAudioHardwareConfig(audio_hardware_config_.get()); 954 } 955 956 return audio_hardware_config_.get(); 957} 958 959#if defined(OS_WIN) 960void RenderThreadImpl::PreCacheFontCharacters(const LOGFONT& log_font, 961 const string16& str) { 962 Send(new ViewHostMsg_PreCacheFontCharacters(log_font, str)); 963} 964 965void RenderThreadImpl::PreCacheFont(const LOGFONT& log_font) { 966 Send(new ChildProcessHostMsg_PreCacheFont(log_font)); 967} 968 969void RenderThreadImpl::ReleaseCachedFonts() { 970 Send(new ChildProcessHostMsg_ReleaseCachedFonts()); 971} 972 973#endif // OS_WIN 974 975bool RenderThreadImpl::IsWebFrameValid(WebKit::WebFrame* web_frame) { 976 if (!web_frame) 977 return false; // We must be shutting down. 978 979 RenderViewImpl* render_view = RenderViewImpl::FromWebView(web_frame->view()); 980 if (!render_view) 981 return false; // We must be shutting down. 982 983 return true; 984} 985 986bool RenderThreadImpl::IsMainThread() { 987 return !!current(); 988} 989 990base::MessageLoop* RenderThreadImpl::GetMainLoop() { 991 return message_loop(); 992} 993 994scoped_refptr<base::MessageLoopProxy> RenderThreadImpl::GetIOLoopProxy() { 995 return ChildProcess::current()->io_message_loop_proxy(); 996} 997 998base::WaitableEvent* RenderThreadImpl::GetShutDownEvent() { 999 return ChildProcess::current()->GetShutDownEvent(); 1000} 1001 1002scoped_ptr<base::SharedMemory> RenderThreadImpl::AllocateSharedMemory( 1003 size_t size) { 1004 return scoped_ptr<base::SharedMemory>( 1005 HostAllocateSharedMemoryBuffer(size)); 1006} 1007 1008int32 RenderThreadImpl::CreateViewCommandBuffer( 1009 int32 surface_id, const GPUCreateCommandBufferConfig& init_params) { 1010 TRACE_EVENT1("gpu", 1011 "RenderThreadImpl::CreateViewCommandBuffer", 1012 "surface_id", 1013 surface_id); 1014 1015 int32 route_id = MSG_ROUTING_NONE; 1016 IPC::Message* message = new GpuHostMsg_CreateViewCommandBuffer( 1017 surface_id, 1018 init_params, 1019 &route_id); 1020 1021 // Allow calling this from the compositor thread. 1022 if (base::MessageLoop::current() == message_loop()) 1023 ChildThread::Send(message); 1024 else 1025 sync_message_filter()->Send(message); 1026 1027 return route_id; 1028} 1029 1030void RenderThreadImpl::CreateImage( 1031 gfx::PluginWindowHandle window, 1032 int32 image_id, 1033 const CreateImageCallback& callback) { 1034 NOTREACHED(); 1035} 1036 1037void RenderThreadImpl::DeleteImage(int32 image_id, int32 sync_point) { 1038 NOTREACHED(); 1039} 1040 1041void RenderThreadImpl::DoNotSuspendWebKitSharedTimer() { 1042 suspend_webkit_shared_timer_ = false; 1043} 1044 1045void RenderThreadImpl::DoNotNotifyWebKitOfModalLoop() { 1046 notify_webkit_of_modal_loop_ = false; 1047} 1048 1049void RenderThreadImpl::OnSetZoomLevelForCurrentURL(const std::string& scheme, 1050 const std::string& host, 1051 double zoom_level) { 1052 RenderViewZoomer zoomer(scheme, host, zoom_level); 1053 RenderView::ForEach(&zoomer); 1054} 1055 1056bool RenderThreadImpl::OnControlMessageReceived(const IPC::Message& msg) { 1057 ObserverListBase<RenderProcessObserver>::Iterator it(observers_); 1058 RenderProcessObserver* observer; 1059 while ((observer = it.GetNext()) != NULL) { 1060 if (observer->OnControlMessageReceived(msg)) 1061 return true; 1062 } 1063 1064 // Some messages are handled by delegates. 1065 if (appcache_dispatcher_->OnMessageReceived(msg) || 1066 dom_storage_dispatcher_->OnMessageReceived(msg)) { 1067 return true; 1068 } 1069 1070 bool handled = true; 1071 IPC_BEGIN_MESSAGE_MAP(RenderThreadImpl, msg) 1072 IPC_MESSAGE_HANDLER(ViewMsg_SetZoomLevelForCurrentURL, 1073 OnSetZoomLevelForCurrentURL) 1074 // TODO(port): removed from render_messages_internal.h; 1075 // is there a new non-windows message I should add here? 1076 IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView) 1077 IPC_MESSAGE_HANDLER(ViewMsg_PurgePluginListCache, OnPurgePluginListCache) 1078 IPC_MESSAGE_HANDLER(ViewMsg_NetworkStateChanged, OnNetworkStateChanged) 1079 IPC_MESSAGE_HANDLER(ViewMsg_TempCrashWithData, OnTempCrashWithData) 1080 IPC_MESSAGE_HANDLER(ViewMsg_SetWebKitSharedTimersSuspended, 1081 OnSetWebKitSharedTimersSuspended) 1082 IPC_MESSAGE_UNHANDLED(handled = false) 1083 IPC_END_MESSAGE_MAP() 1084 return handled; 1085} 1086 1087void RenderThreadImpl::OnCreateNewView(const ViewMsg_New_Params& params) { 1088 EnsureWebKitInitialized(); 1089 // When bringing in render_view, also bring in webkit's glue and jsbindings. 1090 RenderViewImpl::Create( 1091 params.opener_route_id, 1092 params.renderer_preferences, 1093 params.web_preferences, 1094 new SharedRenderViewCounter(0), 1095 params.view_id, 1096 params.main_frame_routing_id, 1097 params.surface_id, 1098 params.session_storage_namespace_id, 1099 params.frame_name, 1100 false, 1101 params.swapped_out, 1102 params.next_page_id, 1103 params.screen_info, 1104 params.accessibility_mode, 1105 params.allow_partial_swap); 1106} 1107 1108GpuChannelHost* RenderThreadImpl::EstablishGpuChannelSync( 1109 CauseForGpuLaunch cause_for_gpu_launch) { 1110 TRACE_EVENT0("gpu", "RenderThreadImpl::EstablishGpuChannelSync"); 1111 1112 if (gpu_channel_.get()) { 1113 // Do nothing if we already have a GPU channel or are already 1114 // establishing one. 1115 if (!gpu_channel_->IsLost()) 1116 return gpu_channel_.get(); 1117 1118 // Recreate the channel if it has been lost. 1119 gpu_channel_ = NULL; 1120 } 1121 1122 // Ask the browser for the channel name. 1123 int client_id = 0; 1124 IPC::ChannelHandle channel_handle; 1125 gpu::GPUInfo gpu_info; 1126 if (!Send(new GpuHostMsg_EstablishGpuChannel(cause_for_gpu_launch, 1127 &client_id, 1128 &channel_handle, 1129 &gpu_info)) || 1130#if defined(OS_POSIX) 1131 channel_handle.socket.fd == -1 || 1132#endif 1133 channel_handle.name.empty()) { 1134 // Otherwise cancel the connection. 1135 return NULL; 1136 } 1137 1138 GetContentClient()->SetGpuInfo(gpu_info); 1139 gpu_channel_ = GpuChannelHost::Create( 1140 this, 0, client_id, gpu_info, channel_handle); 1141 return gpu_channel_.get(); 1142} 1143 1144WebKit::WebMediaStreamCenter* RenderThreadImpl::CreateMediaStreamCenter( 1145 WebKit::WebMediaStreamCenterClient* client) { 1146#if defined(OS_ANDROID) 1147 if (CommandLine::ForCurrentProcess()->HasSwitch( 1148 switches::kDisableWebRTC)) 1149 return NULL; 1150#endif 1151 1152#if defined(ENABLE_WEBRTC) 1153 if (!media_stream_center_) { 1154 media_stream_center_ = GetContentClient()->renderer() 1155 ->OverrideCreateWebMediaStreamCenter(client); 1156 if (!media_stream_center_) { 1157 media_stream_center_ = new MediaStreamCenter( 1158 client, GetMediaStreamDependencyFactory()); 1159 } 1160 } 1161#endif 1162 return media_stream_center_; 1163} 1164 1165MediaStreamDependencyFactory* 1166RenderThreadImpl::GetMediaStreamDependencyFactory() { 1167#if defined(ENABLE_WEBRTC) 1168 if (!media_stream_factory_) { 1169 media_stream_factory_.reset(new MediaStreamDependencyFactory( 1170 vc_manager_.get(), p2p_socket_dispatcher_.get())); 1171 } 1172#endif 1173 return media_stream_factory_.get(); 1174} 1175 1176GpuChannelHost* RenderThreadImpl::GetGpuChannel() { 1177 if (!gpu_channel_.get()) 1178 return NULL; 1179 1180 if (gpu_channel_->IsLost()) 1181 return NULL; 1182 1183 return gpu_channel_.get(); 1184} 1185 1186void RenderThreadImpl::OnPurgePluginListCache(bool reload_pages) { 1187 EnsureWebKitInitialized(); 1188 // The call below will cause a GetPlugins call with refresh=true, but at this 1189 // point we already know that the browser has refreshed its list, so disable 1190 // refresh temporarily to prevent each renderer process causing the list to be 1191 // regenerated. 1192 webkit_platform_support_->set_plugin_refresh_allowed(false); 1193 WebKit::resetPluginCache(reload_pages); 1194 webkit_platform_support_->set_plugin_refresh_allowed(true); 1195 1196 FOR_EACH_OBSERVER(RenderProcessObserver, observers_, PluginListChanged()); 1197} 1198 1199void RenderThreadImpl::OnNetworkStateChanged(bool online) { 1200 EnsureWebKitInitialized(); 1201 WebNetworkStateNotifier::setOnLine(online); 1202} 1203 1204void RenderThreadImpl::OnTempCrashWithData(const GURL& data) { 1205 GetContentClient()->SetActiveURL(data); 1206 CHECK(false); 1207} 1208 1209void RenderThreadImpl::OnSetWebKitSharedTimersSuspended(bool suspend) { 1210 ToggleWebKitSharedTimer(suspend); 1211} 1212 1213scoped_refptr<base::MessageLoopProxy> 1214RenderThreadImpl::GetFileThreadMessageLoopProxy() { 1215 DCHECK(message_loop() == base::MessageLoop::current()); 1216 if (!file_thread_) { 1217 file_thread_.reset(new base::Thread("Renderer::FILE")); 1218 file_thread_->Start(); 1219 } 1220 return file_thread_->message_loop_proxy(); 1221} 1222 1223scoped_refptr<base::MessageLoopProxy> 1224RenderThreadImpl::GetMediaThreadMessageLoopProxy() { 1225 DCHECK(message_loop() == base::MessageLoop::current()); 1226 if (!media_thread_) { 1227 media_thread_.reset(new base::Thread("Media")); 1228 media_thread_->Start(); 1229 } 1230 return media_thread_->message_loop_proxy(); 1231} 1232 1233void RenderThreadImpl::SetFlingCurveParameters( 1234 const std::vector<float>& new_touchpad, 1235 const std::vector<float>& new_touchscreen) { 1236 webkit_platform_support_->SetFlingCurveParameters(new_touchpad, 1237 new_touchscreen); 1238 1239} 1240 1241} // namespace content 1242