// 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 #include #include #include "chrome/renderer/render_process.h" #include "base/basictypes.h" #include "base/command_line.h" #include "base/message_loop.h" #include "base/histogram.h" #include "base/path_service.h" #include "chrome/browser/net/dns_global.h" // TODO(jar): DNS calls should be renderer specific, not including browser. #include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/ipc_channel.h" #include "chrome/common/ipc_message_utils.h" #include "chrome/common/render_messages.h" #include "chrome/renderer/render_view.h" #include "webkit/glue/webkit_glue.h" //----------------------------------------------------------------------------- IMLangFontLink2* RenderProcess::lang_font_link_ = NULL; bool RenderProcess::load_plugins_in_process_ = false; //----------------------------------------------------------------------------- RenderProcess::RenderProcess(const std::wstring& channel_name) : render_thread_(channel_name), #pragma warning(suppress: 4355) // Okay to pass "this" here. clearer_factory_(this) { for (int i = 0; i < arraysize(shared_mem_cache_); ++i) shared_mem_cache_[i] = NULL; } RenderProcess::~RenderProcess() { // We need to stop the RenderThread as the clearer_factory_ // member could be in use while the object itself is destroyed, // as a result of the containing RenderProcess object being destroyed. // This race condition causes a crash when the renderer process is shutting // down. render_thread_.Stop(); ClearSharedMemCache(); } // static bool RenderProcess::GlobalInit(const std::wstring &channel_name) { // HACK: See http://b/issue?id=1024307 for rationale. if (GetModuleHandle(L"LPK.DLL") == NULL) { // Makes sure lpk.dll is loaded by gdi32 to make sure ExtTextOut() works // when buffering into a EMF buffer for printing. typedef BOOL (__stdcall *GdiInitializeLanguagePack)(int LoadedShapingDLLs); GdiInitializeLanguagePack gdi_init_lpk = reinterpret_cast(GetProcAddress( GetModuleHandle(L"GDI32.DLL"), "GdiInitializeLanguagePack")); DCHECK(gdi_init_lpk); if (gdi_init_lpk) { gdi_init_lpk(0); } } InitializeLangFontLink(); CommandLine command_line; if (command_line.HasSwitch(switches::kJavaScriptFlags)) { webkit_glue::SetJavaScriptFlags( command_line.GetSwitchValue(switches::kJavaScriptFlags)); } if (command_line.HasSwitch(switches::kPlaybackMode) || command_line.HasSwitch(switches::kRecordMode)) { webkit_glue::SetRecordPlaybackMode(true); } if (command_line.HasSwitch(switches::kInProcessPlugins) || command_line.HasSwitch(switches::kSingleProcess)) load_plugins_in_process_ = true; if (command_line.HasSwitch(switches::kEnableWatchdog)) { // TODO(JAR): Need to implement renderer IO msgloop watchdog. } if (command_line.HasSwitch(switches::kDumpHistogramsOnExit)) { StatisticsRecorder::set_dump_on_exit(true); } if (command_line.HasSwitch(switches::kGearsInRenderer)) { // Load gears.dll on startup so we can access it before the sandbox // blocks us. std::wstring path; if (PathService::Get(chrome::FILE_GEARS_PLUGIN, &path)) LoadLibrary(path.c_str()); } ChildProcessFactory factory; return ChildProcess::GlobalInit(channel_name, &factory); } // static void RenderProcess::GlobalCleanup() { ChildProcess::GlobalCleanup(); ReleaseLangFontLink(); } // static void RenderProcess::InitializeLangFontLink() { // TODO(hbono): http://b/1072298 Experimentally commented out this code to // prevent registry leaks caused by this IMLangFontLink2 interface. // If you find any font-rendering regressions. Please feel free to blame me. #ifdef USE_IMLANGFONTLINK2 IMultiLanguage* multi_language = NULL; lang_font_link_ = NULL; if (S_OK != CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_ALL, IID_IMultiLanguage, reinterpret_cast(&multi_language))) { DLOG(ERROR) << "Cannot CoCreate CMultiLanguage"; } else { if (S_OK != multi_language->QueryInterface(IID_IMLangFontLink2, reinterpret_cast(&lang_font_link_))) { DLOG(ERROR) << "Cannot query LangFontLink2 interface"; } } if (multi_language) multi_language->Release(); #endif } // static void RenderProcess::ReleaseLangFontLink() { // TODO(hbono): http://b/1072298 Experimentally commented out this code to // prevent registry leaks caused by this IMLangFontLink2 interface. // If you find any font-rendering regressions. Please feel free to blame me. #ifdef USE_IMLANGFONTLINK2 if (lang_font_link_) lang_font_link_->Release(); #endif } // static IMLangFontLink2* RenderProcess::GetLangFontLink() { return lang_font_link_; } // static bool RenderProcess::ShouldLoadPluginsInProcess() { return load_plugins_in_process_; } // static SharedMemory* RenderProcess::AllocSharedMemory(size_t size) { self()->clearer_factory_.RevokeAll(); SharedMemory* mem = self()->GetSharedMemFromCache(size); if (mem) return mem; // Round-up size to allocation granularity SYSTEM_INFO info; GetSystemInfo(&info); size = size / info.dwAllocationGranularity + 1; size = size * info.dwAllocationGranularity; mem = new SharedMemory(); if (!mem) return NULL; if (!mem->Create(L"", false, true, size)) { delete mem; return NULL; } return mem; } // static void RenderProcess::FreeSharedMemory(SharedMemory* mem) { if (self()->PutSharedMemInCache(mem)) { self()->ScheduleCacheClearer(); return; } DeleteSharedMem(mem); } // static void RenderProcess::DeleteSharedMem(SharedMemory* mem) { delete mem; } SharedMemory* RenderProcess::GetSharedMemFromCache(size_t size) { // look for a cached object that is suitable for the requested size. for (int i = 0; i < arraysize(shared_mem_cache_); ++i) { SharedMemory* mem = shared_mem_cache_[i]; if (mem && mem->max_size() >= size) { shared_mem_cache_[i] = NULL; return mem; } } return NULL; } bool RenderProcess::PutSharedMemInCache(SharedMemory* mem) { // simple algorithm: // - look for an empty slot to store mem, or // - if full, then replace any existing cache entry that is smaller than the // given shared memory object. for (int i = 0; i < arraysize(shared_mem_cache_); ++i) { if (!shared_mem_cache_[i]) { shared_mem_cache_[i] = mem; return true; } } for (int i = 0; i < arraysize(shared_mem_cache_); ++i) { SharedMemory* cached_mem = shared_mem_cache_[i]; if (cached_mem->max_size() < mem->max_size()) { shared_mem_cache_[i] = mem; DeleteSharedMem(cached_mem); return true; } } return false; } void RenderProcess::ClearSharedMemCache() { for (int i = 0; i < arraysize(shared_mem_cache_); ++i) { if (shared_mem_cache_[i]) { DeleteSharedMem(shared_mem_cache_[i]); shared_mem_cache_[i] = NULL; } } } void RenderProcess::ScheduleCacheClearer() { // If we already have a deferred clearer, then revoke it so we effectively // delay cache clearing until idle for our desired interval. clearer_factory_.RevokeAll(); MessageLoop::current()->PostDelayedTask(FROM_HERE, clearer_factory_.NewRunnableMethod(&RenderProcess::ClearSharedMemCache), 5000 /* 5 seconds */); } void RenderProcess::Cleanup() { #ifndef NDEBUG // log important leaked objects webkit_glue::CheckForLeaks(); #endif }