// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "build/build_config.h" #if defined(OS_WIN) #include #include #endif #include #include "chrome/renderer/render_thread.h" #include "base/shared_memory.h" #include "chrome/common/chrome_plugin_lib.h" #include "chrome/common/render_messages.h" #include "chrome/common/notification_service.h" #include "chrome/plugin/npobject_util.h" // TODO(port) #if defined(OS_WIN) #include "chrome/plugin/plugin_channel.h" #else #include #include "base/scoped_handle.h" #include "chrome/plugin/plugin_channel_base.h" #include "webkit/glue/weburlrequest.h" #endif #include "chrome/renderer/net/render_dns_master.h" #include "chrome/renderer/render_process.h" #include "chrome/renderer/render_view.h" #include "chrome/renderer/user_script_slave.h" #include "chrome/renderer/visitedlink_slave.h" #include "webkit/glue/cache_manager.h" #include "webkit/glue/webkit_client_impl.h" #include "WebKit.h" static const unsigned int kCacheStatsDelayMS = 2000 /* milliseconds */; // V8 needs a 1MB stack size. static const size_t kStackSize = 1024 * 1024; //----------------------------------------------------------------------------- // Methods below are only called on the owner's thread: // When we run plugins in process, we actually run them on the render thread, // which means that we need to make the render thread pump UI events. RenderThread::RenderThread() : ChildThread( base::Thread::Options(RenderProcess::InProcessPlugins() ? MessageLoop::TYPE_UI : MessageLoop::TYPE_DEFAULT, kStackSize)), visited_link_slave_(NULL), user_script_slave_(NULL), render_dns_master_(NULL) { } RenderThread::RenderThread(const std::wstring& channel_name) : ChildThread( base::Thread::Options(RenderProcess::InProcessPlugins() ? MessageLoop::TYPE_UI : MessageLoop::TYPE_DEFAULT, kStackSize)), visited_link_slave_(NULL), user_script_slave_(NULL), render_dns_master_(NULL), renderer_histogram_snapshots_(NULL) { SetChannelName(channel_name); } RenderThread::~RenderThread() { } RenderThread* RenderThread::current() { DCHECK(!IsPluginProcess()); return static_cast(ChildThread::current()); } void RenderThread::AddFilter(IPC::ChannelProxy::MessageFilter* filter) { channel()->AddFilter(filter); } void RenderThread::RemoveFilter(IPC::ChannelProxy::MessageFilter* filter) { channel()->RemoveFilter(filter); } void RenderThread::Resolve(const char* name, size_t length) { return render_dns_master_->Resolve(name, length); } void RenderThread::SendHistograms() { return renderer_histogram_snapshots_->SendHistograms(); } void RenderThread::Init() { ChildThread::Init(); notification_service_.reset(new NotificationService); cache_stats_factory_.reset( new ScopedRunnableMethodFactory(this)); #if defined(OS_WIN) // The renderer thread should wind-up COM. CoInitialize(0); #endif webkit_client_impl_.reset(new webkit_glue::WebKitClientImpl); WebKit::initialize(webkit_client_impl_.get()); visited_link_slave_ = new VisitedLinkSlave(); user_script_slave_ = new UserScriptSlave(); render_dns_master_.reset(new RenderDnsMaster()); renderer_histogram_snapshots_.reset(new RendererHistogramSnapshots()); } void RenderThread::CleanUp() { ChildThread::CleanUp(); // TODO(port) #if defined(OS_WIN) // Clean up plugin channels before this thread goes away. PluginChannelBase::CleanupChannels(); #endif notification_service_.reset(); delete visited_link_slave_; visited_link_slave_ = NULL; delete user_script_slave_; user_script_slave_ = NULL; #if defined(OS_WIN) CoUninitialize(); #endif } void RenderThread::OnUpdateVisitedLinks(base::SharedMemoryHandle table) { DCHECK(base::SharedMemory::IsHandleValid(table)) << "Bad table handle"; visited_link_slave_->Init(table); } void RenderThread::OnUpdateUserScripts( base::SharedMemoryHandle scripts) { DCHECK(base::SharedMemory::IsHandleValid(scripts)) << "Bad scripts handle"; user_script_slave_->UpdateScripts(scripts); } void RenderThread::OnControlMessageReceived(const IPC::Message& msg) { IPC_BEGIN_MESSAGE_MAP(RenderThread, msg) IPC_MESSAGE_HANDLER(ViewMsg_VisitedLink_NewTable, OnUpdateVisitedLinks) IPC_MESSAGE_HANDLER(ViewMsg_SetNextPageID, OnSetNextPageID) // TODO(port): removed from render_messages_internal.h; // is there a new non-windows message I should add here? IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView) IPC_MESSAGE_HANDLER(ViewMsg_SetCacheCapacities, OnSetCacheCapacities) IPC_MESSAGE_HANDLER(ViewMsg_GetRendererHistograms, OnGetRendererHistograms) IPC_MESSAGE_HANDLER(ViewMsg_GetCacheResourceStats, OnGetCacheResourceStats) IPC_MESSAGE_HANDLER(ViewMsg_PluginMessage, OnPluginMessage) IPC_MESSAGE_HANDLER(ViewMsg_UserScripts_NewScripts, OnUpdateUserScripts) IPC_END_MESSAGE_MAP() } void RenderThread::OnPluginMessage(const FilePath& plugin_path, const std::vector& data) { if (!ChromePluginLib::IsInitialized()) { return; } CHECK(ChromePluginLib::IsPluginThread()); ChromePluginLib *chrome_plugin = ChromePluginLib::Find(plugin_path); if (chrome_plugin) { void *data_ptr = const_cast(reinterpret_cast(&data[0])); uint32 data_len = static_cast(data.size()); chrome_plugin->functions().on_message(data_ptr, data_len); } } void RenderThread::OnSetNextPageID(int32 next_page_id) { // This should only be called at process initialization time, so we shouldn't // have to worry about thread-safety. // TODO(port) #if !defined(OS_LINUX) RenderView::SetNextPageID(next_page_id); #endif } void RenderThread::OnCreateNewView(gfx::NativeViewId parent_hwnd, ModalDialogEvent modal_dialog_event, const WebPreferences& webkit_prefs, int32 view_id) { // When bringing in render_view, also bring in webkit's glue and jsbindings. base::WaitableEvent* waitable_event = new base::WaitableEvent( #if defined(OS_WIN) modal_dialog_event.event); #else true, false); #endif // TODO(darin): once we have a RenderThread per RenderView, this will need to // change to assert that we are not creating more than one view. RenderView::Create( this, parent_hwnd, waitable_event, MSG_ROUTING_NONE, webkit_prefs, new SharedRenderViewCounter(0), view_id); } void RenderThread::OnSetCacheCapacities(size_t min_dead_capacity, size_t max_dead_capacity, size_t capacity) { #if defined(OS_WIN) || defined(OS_LINUX) CacheManager::SetCapacities(min_dead_capacity, max_dead_capacity, capacity); #else // TODO(port) NOTIMPLEMENTED(); #endif } void RenderThread::OnGetCacheResourceStats() { #if defined(OS_WIN) || defined(OS_LINUX) CacheManager::ResourceTypeStats stats; CacheManager::GetResourceTypeStats(&stats); Send(new ViewHostMsg_ResourceTypeStats(stats)); #else // TODO(port) NOTIMPLEMENTED(); #endif } void RenderThread::OnGetRendererHistograms() { SendHistograms(); } void RenderThread::InformHostOfCacheStats() { #if defined(OS_WIN) || defined(OS_LINUX) CacheManager::UsageStats stats; CacheManager::GetUsageStats(&stats); Send(new ViewHostMsg_UpdatedCacheStats(stats)); #else // TODO(port) NOTIMPLEMENTED(); #endif } void RenderThread::InformHostOfCacheStatsLater() { // Rate limit informing the host of our cache stats. if (!cache_stats_factory_->empty()) return; MessageLoop::current()->PostDelayedTask(FROM_HERE, cache_stats_factory_->NewRunnableMethod( &RenderThread::InformHostOfCacheStats), kCacheStatsDelayMS); }