diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-18 19:10:38 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-18 19:10:38 +0000 |
commit | 71e99ae1dfb04b4a432d00570638f82f36888323 (patch) | |
tree | a70efbecb6b2b09df401946927a54ad495e0098c /chrome/renderer | |
parent | c2297a2fed5b6d33a3fdb6adbfb7dfb7caba7aed (diff) | |
download | chromium_src-71e99ae1dfb04b4a432d00570638f82f36888323.zip chromium_src-71e99ae1dfb04b4a432d00570638f82f36888323.tar.gz chromium_src-71e99ae1dfb04b4a432d00570638f82f36888323.tar.bz2 |
Enforce no more includes through DEPS. I also added DEPS checking for gpu/plugin/worker directories as well.
I've moved the breakpad specific code out of content\renderer\renderer_main.cc into chrome\renderer\chrome_render_process_observer.cc. I've also moved the rest of the process-specific initialization from chrome_content_renderer_client.cc there as well, so that all the chrome renderer process init code is one place (some of it existed before chrome_render_process_observer.cc was created).
Review URL: http://codereview.chromium.org/6884001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81979 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r-- | chrome/renderer/chrome_content_renderer_client.cc | 99 | ||||
-rw-r--r-- | chrome/renderer/chrome_render_process_observer.cc | 260 |
2 files changed, 244 insertions, 115 deletions
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 76bd2da..e3d03c5 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc @@ -17,7 +17,6 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" -#include "chrome/common/extensions/extension_localization_peer.h" #include "chrome/common/extensions/extension_set.h" #include "chrome/common/jstemplate_builder.h" #include "chrome/common/render_messages.h" @@ -53,12 +52,10 @@ #include "chrome/renderer/search_extension.h" #include "chrome/renderer/searchbox.h" #include "chrome/renderer/searchbox_extension.h" -#include "chrome/renderer/security_filter_peer.h" #include "chrome/renderer/spellchecker/spellcheck.h" #include "chrome/renderer/spellchecker/spellcheck_provider.h" #include "chrome/renderer/translate_helper.h" #include "chrome/renderer/visitedlink_slave.h" -#include "content/common/resource_dispatcher.h" #include "content/common/view_messages.h" #include "content/renderer/render_thread.h" #include "content/renderer/render_view.h" @@ -79,10 +76,6 @@ #include "webkit/plugins/npapi/plugin_list.h" #include "webkit/plugins/ppapi/plugin_module.h" -#if defined(OS_MACOSX) -#include "chrome/app/breakpad_mac.h" -#endif - using autofill::AutofillAgent; using autofill::FormManager; using autofill::PasswordAutofillManager; @@ -100,93 +93,6 @@ using WebKit::WebVector; namespace { -static const unsigned int kCacheStatsDelayMS = 2000 /* milliseconds */; - -#if defined(OS_POSIX) -class SuicideOnChannelErrorFilter : public IPC::ChannelProxy::MessageFilter { - void OnChannelError() { - // On POSIX, at least, one can install an unload handler which loops - // forever and leave behind a renderer process which eats 100% CPU forever. - // - // This is because the terminate signals (ViewMsg_ShouldClose and the error - // from the IPC channel) are routed to the main message loop but never - // processed (because that message loop is stuck in V8). - // - // One could make the browser SIGKILL the renderers, but that leaves open a - // large window where a browser failure (or a user, manually terminating - // the browser because "it's stuck") will leave behind a process eating all - // the CPU. - // - // So, we install a filter on the channel so that we can process this event - // here and kill the process. - -#if defined(OS_MACOSX) - // TODO(viettrungluu): crbug.com/28547: The following is needed, as a - // stopgap, to avoid leaking due to not releasing Breakpad properly. - // TODO(viettrungluu): Investigate why this is being called. - if (IsCrashReporterEnabled()) { - VLOG(1) << "Cleaning up Breakpad."; - DestructCrashReporter(); - } else { - VLOG(1) << "Breakpad not enabled; no clean-up needed."; - } -#endif // OS_MACOSX - - _exit(0); - } -}; -#endif - -class RenderResourceObserver : public ResourceDispatcher::Observer { - public: - RenderResourceObserver() - : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { - } - - virtual webkit_glue::ResourceLoaderBridge::Peer* OnRequestComplete( - webkit_glue::ResourceLoaderBridge::Peer* current_peer, - ResourceType::Type resource_type, - const net::URLRequestStatus& status) { - // Update the browser about our cache. - // Rate limit informing the host of our cache stats. - if (method_factory_.empty()) { - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - method_factory_.NewRunnableMethod( - &RenderResourceObserver::InformHostOfCacheStats), - kCacheStatsDelayMS); - } - - if (status.status() != net::URLRequestStatus::CANCELED || - status.os_error() == net::ERR_ABORTED) { - return NULL; - } - - // Resource canceled with a specific error are filtered. - return SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest( - resource_type, current_peer, status.os_error()); - } - - virtual webkit_glue::ResourceLoaderBridge::Peer* OnReceivedResponse( - webkit_glue::ResourceLoaderBridge::Peer* current_peer, - const std::string& mime_type, - const GURL& url) { - return ExtensionLocalizationPeer::CreateExtensionLocalizationPeer( - current_peer, RenderThread::current(), mime_type, url); - } - - private: - void InformHostOfCacheStats() { - WebCache::UsageStats stats; - WebCache::getUsageStats(&stats); - RenderThread::current()->Send(new ViewHostMsg_UpdatedCacheStats(stats)); - } - - ScopedRunnableMethodFactory<RenderResourceObserver> method_factory_; - - DISALLOW_COPY_AND_ASSIGN(RenderResourceObserver); -}; - static void AppendParams(const std::vector<string16>& additional_names, const std::vector<string16>& additional_values, WebVector<WebString>* existing_names, @@ -235,9 +141,6 @@ void ChromeContentRendererClient::RenderThreadStarted() { RenderThread* thread = RenderThread::current(); thread->AddFilter(new DevToolsAgentFilter()); -#if defined(OS_POSIX) - thread->AddFilter(new SuicideOnChannelErrorFilter()); -#endif thread->AddObserver(chrome_observer_.get()); thread->AddObserver(extension_dispatcher_.get()); @@ -259,8 +162,6 @@ void ChromeContentRendererClient::RenderThreadStarted() { thread->RegisterExtension(DomAutomationV8Extension::Get()); } - thread->resource_dispatcher()->set_observer(new RenderResourceObserver()); - // chrome: pages should not be accessible by normal content, and should // also be unable to script anything but themselves (to help limit the damage // that a corrupt chrome: page could cause). diff --git a/chrome/renderer/chrome_render_process_observer.cc b/chrome/renderer/chrome_render_process_observer.cc index 4ebb6c4..6ae9668 100644 --- a/chrome/renderer/chrome_render_process_observer.cc +++ b/chrome/renderer/chrome_render_process_observer.cc @@ -9,16 +9,21 @@ #include "base/metrics/histogram.h" #include "base/path_service.h" #include "base/process_util.h" +#include "base/threading/platform_thread.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/extensions/extension_localization_peer.h" #include "chrome/common/net/net_resource_provider.h" #include "chrome/common/render_messages.h" #include "chrome/renderer/content_settings_observer.h" +#include "chrome/renderer/security_filter_peer.h" +#include "content/common/resource_dispatcher.h" #include "content/common/view_messages.h" #include "content/renderer/render_thread.h" #include "content/renderer/render_view.h" #include "content/renderer/render_view_visitor.h" #include "crypto/nss_util.h" +#include "net/base/net_errors.h" #include "net/base/net_module.h" #include "third_party/sqlite/sqlite3.h" #include "third_party/tcmalloc/chromium/src/google/malloc_extension.h" @@ -28,18 +33,98 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" #include "v8/include/v8.h" + #if defined(OS_WIN) #include "app/win/iat_patch_function.h" #endif +#if defined(OS_MACOSX) +#include "base/eintr_wrapper.h" +#include "chrome/app/breakpad_mac.h" +#endif + using WebKit::WebCache; using WebKit::WebCrossOriginPreflightResultCache; using WebKit::WebFontCache; namespace { -#if defined(OS_WIN) +static const unsigned int kCacheStatsDelayMS = 2000 /* milliseconds */; + +class RenderResourceObserver : public ResourceDispatcher::Observer { + public: + RenderResourceObserver() + : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { + } + + virtual webkit_glue::ResourceLoaderBridge::Peer* OnRequestComplete( + webkit_glue::ResourceLoaderBridge::Peer* current_peer, + ResourceType::Type resource_type, + const net::URLRequestStatus& status) { + // Update the browser about our cache. + // Rate limit informing the host of our cache stats. + if (method_factory_.empty()) { + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &RenderResourceObserver::InformHostOfCacheStats), + kCacheStatsDelayMS); + } + + if (status.status() != net::URLRequestStatus::CANCELED || + status.os_error() == net::ERR_ABORTED) { + return NULL; + } + + // Resource canceled with a specific error are filtered. + return SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest( + resource_type, current_peer, status.os_error()); + } + + virtual webkit_glue::ResourceLoaderBridge::Peer* OnReceivedResponse( + webkit_glue::ResourceLoaderBridge::Peer* current_peer, + const std::string& mime_type, + const GURL& url) { + return ExtensionLocalizationPeer::CreateExtensionLocalizationPeer( + current_peer, RenderThread::current(), mime_type, url); + } + + private: + void InformHostOfCacheStats() { + WebCache::UsageStats stats; + WebCache::getUsageStats(&stats); + RenderThread::current()->Send(new ViewHostMsg_UpdatedCacheStats(stats)); + } + + ScopedRunnableMethodFactory<RenderResourceObserver> method_factory_; + DISALLOW_COPY_AND_ASSIGN(RenderResourceObserver); +}; + +class RenderViewContentSettingsSetter : public RenderViewVisitor { + public: + RenderViewContentSettingsSetter(const GURL& url, + const ContentSettings& content_settings) + : url_(url), + content_settings_(content_settings) { + } + + virtual bool Visit(RenderView* render_view) { + if (GURL(render_view->webview()->mainFrame()->url()) == url_) { + ContentSettingsObserver::Get(render_view)->SetContentSettings( + content_settings_); + } + return true; + } + + private: + GURL url_; + ContentSettings content_settings_; + + DISALLOW_COPY_AND_ASSIGN(RenderViewContentSettingsSetter); +}; + +#if defined(OS_WIN) static app::win::IATPatchFunction g_iat_patch_createdca; HDC WINAPI CreateDCAPatch(LPCSTR driver_name, LPCSTR device_name, @@ -73,31 +158,143 @@ DWORD WINAPI GetFontDataPatch(HDC hdc, } return rv; } +#endif // OS_WIN + +#if defined(OS_POSIX) +class SuicideOnChannelErrorFilter : public IPC::ChannelProxy::MessageFilter { + void OnChannelError() { + // On POSIX, at least, one can install an unload handler which loops + // forever and leave behind a renderer process which eats 100% CPU forever. + // + // This is because the terminate signals (ViewMsg_ShouldClose and the error + // from the IPC channel) are routed to the main message loop but never + // processed (because that message loop is stuck in V8). + // + // One could make the browser SIGKILL the renderers, but that leaves open a + // large window where a browser failure (or a user, manually terminating + // the browser because "it's stuck") will leave behind a process eating all + // the CPU. + // + // So, we install a filter on the channel so that we can process this event + // here and kill the process. + +#if defined(OS_MACOSX) + // TODO(viettrungluu): crbug.com/28547: The following is needed, as a + // stopgap, to avoid leaking due to not releasing Breakpad properly. + // TODO(viettrungluu): Investigate why this is being called. + if (IsCrashReporterEnabled()) { + VLOG(1) << "Cleaning up Breakpad."; + DestructCrashReporter(); + } else { + VLOG(1) << "Breakpad not enabled; no clean-up needed."; + } +#endif // OS_MACOSX -#endif + _exit(0); + } +}; +#endif // OS_POSIX + +#if defined(OS_MACOSX) +// TODO(viettrungluu): crbug.com/28547: The following signal handling is needed, +// as a stopgap, to avoid leaking due to not releasing Breakpad properly. +// Without this problem, this could all be eliminated. Remove when Breakpad is +// fixed? +// TODO(viettrungluu): Code taken from browser_main.cc (with a bit of editing). +// The code should be properly shared (or this code should be eliminated). +int g_shutdown_pipe_write_fd = -1; + +void SIGTERMHandler(int signal) { + RAW_CHECK(signal == SIGTERM); + RAW_LOG(INFO, "Handling SIGTERM in renderer."); + + // Reinstall the default handler. We had one shot at graceful shutdown. + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_DFL; + CHECK(sigaction(signal, &action, NULL) == 0); + + RAW_CHECK(g_shutdown_pipe_write_fd != -1); + size_t bytes_written = 0; + do { + int rv = HANDLE_EINTR( + write(g_shutdown_pipe_write_fd, + reinterpret_cast<const char*>(&signal) + bytes_written, + sizeof(signal) - bytes_written)); + RAW_CHECK(rv >= 0); + bytes_written += rv; + } while (bytes_written < sizeof(signal)); + + RAW_LOG(INFO, "Wrote signal to shutdown pipe."); +} -class RenderViewContentSettingsSetter : public RenderViewVisitor { +class ShutdownDetector : public base::PlatformThread::Delegate { public: - RenderViewContentSettingsSetter(const GURL& url, - const ContentSettings& content_settings) - : url_(url), - content_settings_(content_settings) { + explicit ShutdownDetector(int shutdown_fd) : shutdown_fd_(shutdown_fd) { + CHECK(shutdown_fd_ != -1); } - virtual bool Visit(RenderView* render_view) { - if (GURL(render_view->webview()->mainFrame()->url()) == url_) { - ContentSettingsObserver::Get(render_view)->SetContentSettings( - content_settings_); + virtual void ThreadMain() { + int signal; + size_t bytes_read = 0; + ssize_t ret; + do { + ret = HANDLE_EINTR( + read(shutdown_fd_, + reinterpret_cast<char*>(&signal) + bytes_read, + sizeof(signal) - bytes_read)); + if (ret < 0) { + NOTREACHED() << "Unexpected error: " << strerror(errno); + break; + } else if (ret == 0) { + NOTREACHED() << "Unexpected closure of shutdown pipe."; + break; + } + bytes_read += ret; + } while (bytes_read < sizeof(signal)); + + if (bytes_read == sizeof(signal)) + VLOG(1) << "Handling shutdown for signal " << signal << "."; + else + VLOG(1) << "Handling shutdown for unknown signal."; + + // Clean up Breakpad if necessary. + if (IsCrashReporterEnabled()) { + VLOG(1) << "Cleaning up Breakpad."; + DestructCrashReporter(); + } else { + VLOG(1) << "Breakpad not enabled; no clean-up needed."; } - return true; + + // Something went seriously wrong, so get out. + if (bytes_read != sizeof(signal)) { + LOG(WARNING) << "Failed to get signal. Quitting ungracefully."; + _exit(1); + } + + // Re-raise the signal. + kill(getpid(), signal); + + // The signal may be handled on another thread. Give that a chance to + // happen. + sleep(3); + + // We really should be dead by now. For whatever reason, we're not. Exit + // immediately, with the exit status set to the signal number with bit 8 + // set. On the systems that we care about, this exit status is what is + // normally used to indicate an exit by this signal's default handler. + // This mechanism isn't a de jure standard, but even in the worst case, it + // should at least result in an immediate exit. + LOG(WARNING) << "Still here, exiting really ungracefully."; + _exit(signal | (1 << 7)); } private: - GURL url_; - ContentSettings content_settings_; + const int shutdown_fd_; - DISALLOW_COPY_AND_ASSIGN(RenderViewContentSettingsSetter); + DISALLOW_COPY_AND_ASSIGN(ShutdownDetector); }; +#endif // OS_MACOSX } // namespace @@ -105,7 +302,6 @@ bool ChromeRenderProcessObserver::is_incognito_process_ = false; ChromeRenderProcessObserver::ChromeRenderProcessObserver() { const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - if (command_line.HasSwitch(switches::kEnableWatchdog)) { // TODO(JAR): Need to implement renderer IO msgloop watchdog. } @@ -114,6 +310,38 @@ ChromeRenderProcessObserver::ChromeRenderProcessObserver() { base::StatisticsRecorder::set_dump_on_exit(true); } + RenderThread* thread = RenderThread::current(); + thread->resource_dispatcher()->set_observer(new RenderResourceObserver()); + +#if defined(OS_POSIX) + thread->AddFilter(new SuicideOnChannelErrorFilter()); +#endif + +#if defined(OS_MACOSX) + // TODO(viettrungluu): Code taken from browser_main.cc. + int pipefd[2]; + int ret = pipe(pipefd); + if (ret < 0) { + PLOG(DFATAL) << "Failed to create pipe"; + } else { + int shutdown_pipe_read_fd = pipefd[0]; + g_shutdown_pipe_write_fd = pipefd[1]; + const size_t kShutdownDetectorThreadStackSize = 4096; + if (!base::PlatformThread::CreateNonJoinable( + kShutdownDetectorThreadStackSize, + new ShutdownDetector(shutdown_pipe_read_fd))) { + LOG(DFATAL) << "Failed to create shutdown detector task."; + } + } + + // crbug.com/28547: When Breakpad is in use, handle SIGTERM to avoid leaking + // Mach ports. + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_handler = SIGTERMHandler; + CHECK(sigaction(SIGTERM, &action, NULL) == 0); +#endif + // Configure modules that need access to resources. net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider); |