diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-18 17:30:35 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-18 17:30:35 +0000 |
commit | bf2ecb42b2821b9609ce5736d8218c730011d7db (patch) | |
tree | de6abdf6c894199554631b9ca75405b026198588 /content | |
parent | 253b073edfdab221f0c71caf5c92759705d04170 (diff) | |
download | chromium_src-bf2ecb42b2821b9609ce5736d8218c730011d7db.zip chromium_src-bf2ecb42b2821b9609ce5736d8218c730011d7db.tar.gz chromium_src-bf2ecb42b2821b9609ce5736d8218c730011d7db.tar.bz2 |
Move renderer_main and renderer_glue to content.
Review URL: http://codereview.chromium.org/6878002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81962 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r-- | content/common/content_counters.cc | 35 | ||||
-rw-r--r-- | content/common/content_counters.h | 30 | ||||
-rw-r--r-- | content/common/content_switches.cc | 21 | ||||
-rw-r--r-- | content/common/content_switches.h | 6 | ||||
-rw-r--r-- | content/content_common.gypi | 2 | ||||
-rw-r--r-- | content/content_renderer.gypi | 7 | ||||
-rw-r--r-- | content/renderer/DEPS | 1 | ||||
-rw-r--r-- | content/renderer/renderer_glue.cc | 267 | ||||
-rw-r--r-- | content/renderer/renderer_main.cc | 364 | ||||
-rw-r--r-- | content/renderer/renderer_main_platform_delegate.h | 40 | ||||
-rw-r--r-- | content/renderer/renderer_main_platform_delegate_linux.cc | 52 | ||||
-rw-r--r-- | content/renderer/renderer_main_platform_delegate_mac.mm | 58 | ||||
-rw-r--r-- | content/renderer/renderer_main_platform_delegate_win.cc | 140 |
13 files changed, 1023 insertions, 0 deletions
diff --git a/content/common/content_counters.cc b/content/common/content_counters.cc new file mode 100644 index 0000000..1718568 --- /dev/null +++ b/content/common/content_counters.cc @@ -0,0 +1,35 @@ +// Copyright (c) 2011 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 "content/common/content_counters.h" + +#include "base/metrics/stats_counters.h" + +namespace content { + +using base::StatsCounterTimer; +using base::StatsRate; + +// Note: We use the construct-on-first-use pattern here, because we don't +// want to fight with any static initializer ordering problems later. +// The downside of this is that the objects don't ever get cleaned up. +// But they are small and this is okay. + +// Note: Because these are constructed on-first-use, there is a slight +// race condition - two threads could initialize the same counter. +// If this happened, the stats table would still work just fine; +// we'd leak the extraneous StatsCounter object once, and that +// would be it. But these are small objects, so this is ok. + +StatsCounterTimer& Counters::chrome_main() { + static StatsCounterTimer* ctr = new StatsCounterTimer("Chrome.Init"); + return *ctr; +} + +StatsCounterTimer& Counters::renderer_main() { + static StatsCounterTimer* ctr = new StatsCounterTimer("Chrome.RendererInit"); + return *ctr; +} + +} // namespace content diff --git a/content/common/content_counters.h b/content/common/content_counters.h new file mode 100644 index 0000000..16dc638 --- /dev/null +++ b/content/common/content_counters.h @@ -0,0 +1,30 @@ +// Copyright (c) 2011 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. + +// Counters used within the browser. + +#ifndef CONTENT_COMMON_CONTENT_COUNTERS_H_ +#define CONTENT_COMMON_CONTENT_COUNTERS_H_ +#pragma once + +namespace base { +class StatsCounter; +class StatsCounterTimer; +class StatsRate; +} + +namespace content { + +class Counters { + public: + // The amount of time spent in chrome initialization. + static base::StatsCounterTimer& chrome_main(); + + // The amount of time spent in renderer initialization. + static base::StatsCounterTimer& renderer_main(); +}; + +} // namespace content + +#endif // CONTENT_COMMON_CONTENT_COUNTERS_H_ diff --git a/content/common/content_switches.cc b/content/common/content_switches.cc index 9e64cb7..b6e64e6 100644 --- a/content/common/content_switches.cc +++ b/content/common/content_switches.cc @@ -182,6 +182,18 @@ const char kExtraPluginDir[] = "extra-plugin-dir"; // Causes the process to run as an extension subprocess. const char kExtensionProcess[] = "extension"; +// Some field tests may rendomized in the browser, and the randomly selected +// outcome needs to be propagated to the renderer. For instance, this is used +// to modify histograms recorded in the renderer, or to get the renderer to +// also set of its state (initialize, or not initialize components) to match the +// experiment(s). +// The argument is a string-ized list of experiment names, and the associated +// value that was randomly selected. In the recent implementetaion, the +// persistent representation generated by field_trial.cc and later decoded, is a +// list of name and value pairs, separated by slashes. See field trial.cc for +// current details. +const char kForceFieldTestNameAndValue[] = "force-fieldtest"; + // Extra command line options for launching the GPU process (normally used // for debugging). Use like renderer-cmd-prefix. const char kGpuLauncher[] = "gpu-launcher"; @@ -302,6 +314,9 @@ const char kProfileImportProcess[] = "profile-import"; // Register Pepper plugins (see pepper_plugin_registry.cc for its format). const char kRegisterPepperPlugins[] = "register-pepper-plugins"; +// Causes the renderer process to throw an assertion on launch. +const char kRendererAssertTest[] = "renderer-assert-test"; + // On POSIX only: the contents of this flag are prepended to the renderer // command line. Useful values might be "valgrind" or "xterm -e gdb --args". const char kRendererCmdPrefix[] = "renderer-cmd-prefix"; @@ -380,4 +395,10 @@ const char kZygoteCmdPrefix[] = "zygote-cmd-prefix"; // Causes the process to run as a renderer zygote. const char kZygoteProcess[] = "zygote"; + +#if !defined(OFFICIAL_BUILD) +// Causes the renderer process to throw an assertion on launch. +const char kRendererCheckFalseTest[] = "renderer-check-false-test"; +#endif + } // namespace switches diff --git a/content/common/content_switches.h b/content/common/content_switches.h index 761b35b..f5b756c 100644 --- a/content/common/content_switches.h +++ b/content/common/content_switches.h @@ -62,6 +62,7 @@ extern const char kExperimentalLocationFeatures[]; // TODO(jam): this doesn't belong in content. extern const char kExtensionProcess[]; extern const char kExtraPluginDir[]; +extern const char kForceFieldTestNameAndValue[]; extern const char kGpuLauncher[]; extern const char kGpuProcess[]; extern const char kGpuStartupDialog[]; @@ -97,6 +98,7 @@ extern const char kProcessType[]; extern const char kProfileImportProcess[]; extern const char kRecordMode[]; extern const char kRegisterPepperPlugins[]; +extern const char kRendererAssertTest[]; extern const char kRendererCmdPrefix[]; extern const char kRendererCrashTest[]; extern const char kRendererProcess[]; @@ -121,6 +123,10 @@ extern const char kWorkerProcess[]; extern const char kZygoteCmdPrefix[]; extern const char kZygoteProcess[]; +#if !defined(OFFICIAL_BUILD) +extern const char kRendererCheckFalseTest[]; +#endif + } // namespace switches #endif // CONTENT_COMMON_CONTENT_SWITCHES_H_ diff --git a/content/content_common.gypi b/content/content_common.gypi index 6a427c6..743b74a 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -54,6 +54,8 @@ 'common/content_client.h', 'common/content_constants.cc', 'common/content_constants.h', + 'common/content_counters.cc', + 'common/content_counters.h', 'common/content_paths.cc', 'common/content_paths.h', 'common/content_switches.cc', diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index 4eff5e7..dcc304e 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -15,6 +15,7 @@ '../skia/skia.gyp:skia', '../third_party/ffmpeg/ffmpeg.gyp:ffmpeg', '../third_party/icu/icu.gyp:icuuc', + '../third_party/icu/icu.gyp:icui18n', '../third_party/libjingle/libjingle.gyp:libjingle', '../third_party/libjingle/libjingle.gyp:libjingle_p2p', '../third_party/npapi/npapi.gyp:npapi', @@ -105,6 +106,12 @@ 'renderer/render_widget_fullscreen_pepper.h', 'renderer/renderer_gl_context.cc', 'renderer/renderer_gl_context.h', + 'renderer/renderer_glue.cc', + 'renderer/renderer_main.cc', + 'renderer/renderer_main_platform_delegate.h', + 'renderer/renderer_main_platform_delegate_linux.cc', + 'renderer/renderer_main_platform_delegate_mac.mm', + 'renderer/renderer_main_platform_delegate_win.cc', 'renderer/renderer_sandbox_support_linux.cc', 'renderer/renderer_sandbox_support_linux.h', 'renderer/renderer_webapplicationcachehost_impl.cc', diff --git a/content/renderer/DEPS b/content/renderer/DEPS index 378d848..730495c 100644 --- a/content/renderer/DEPS +++ b/content/renderer/DEPS @@ -7,6 +7,7 @@ include_rules = [ "-chrome/renderer/spellchecker",
"+content/plugin", # For shared npruntime proxying code.
+ "+third_party/mach_override",
"+third_party/tcmalloc",
"+v8/include",
]
diff --git a/content/renderer/renderer_glue.cc b/content/renderer/renderer_glue.cc new file mode 100644 index 0000000..58ec602 --- /dev/null +++ b/content/renderer/renderer_glue.cc @@ -0,0 +1,267 @@ +// Copyright (c) 2011 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. + +// This file provides the embedder's side of random webkit glue functions. + +#include "build/build_config.h" + +#if defined(OS_WIN) +#include <windows.h> +#endif + +#include <vector> + +#include "base/command_line.h" +#include "base/memory/ref_counted.h" +#include "base/string_util.h" +#include "chrome/common/url_constants.h" +#include "content/common/clipboard_messages.h" +#include "content/common/content_switches.h" +#include "content/common/socket_stream_dispatcher.h" +#include "content/common/view_messages.h" +#include "content/plugin/npobject_util.h" +#include "content/renderer/render_thread.h" +#include "googleurl/src/url_util.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebKitClient.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/clipboard/clipboard.h" +#include "ui/base/resource/resource_bundle.h" +#include "webkit/glue/scoped_clipboard_writer_glue.h" +#include "webkit/glue/webkit_glue.h" +#include "webkit/glue/websocketstreamhandle_bridge.h" + +#if defined(OS_LINUX) +#include "content/renderer/renderer_sandbox_support_linux.h" +#endif + +// This definition of WriteBitmapFromPixels uses shared memory to communicate +// across processes. +void ScopedClipboardWriterGlue::WriteBitmapFromPixels(const void* pixels, + const gfx::Size& size) { + // Do not try to write a bitmap more than once + if (shared_buf_) + return; + + uint32 buf_size = 4 * size.width() * size.height(); + + // Allocate a shared memory buffer to hold the bitmap bits. +#if defined(OS_POSIX) + // On POSIX, we need to ask the browser to create the shared memory for us, + // since this is blocked by the sandbox. + base::SharedMemoryHandle shared_mem_handle; + ViewHostMsg_AllocateSharedMemoryBuffer *msg = + new ViewHostMsg_AllocateSharedMemoryBuffer(buf_size, + &shared_mem_handle); + if (RenderThread::current()->Send(msg)) { + if (base::SharedMemory::IsHandleValid(shared_mem_handle)) { + shared_buf_ = new base::SharedMemory(shared_mem_handle, false); + if (!shared_buf_ || !shared_buf_->Map(buf_size)) { + NOTREACHED() << "Map failed"; + return; + } + } else { + NOTREACHED() << "Browser failed to allocate shared memory"; + return; + } + } else { + NOTREACHED() << "Browser allocation request message failed"; + return; + } +#else // !OS_POSIX + shared_buf_ = new base::SharedMemory; + if (!shared_buf_->CreateAndMapAnonymous(buf_size)) { + NOTREACHED(); + return; + } +#endif + + // Copy the bits into shared memory + memcpy(shared_buf_->memory(), pixels, buf_size); + shared_buf_->Unmap(); + + ui::Clipboard::ObjectMapParam size_param; + const char* size_data = reinterpret_cast<const char*>(&size); + for (size_t i = 0; i < sizeof(gfx::Size); ++i) + size_param.push_back(size_data[i]); + + ui::Clipboard::ObjectMapParams params; + + // The first parameter is replaced on the receiving end with a pointer to + // a shared memory object containing the bitmap. We reserve space for it here. + ui::Clipboard::ObjectMapParam place_holder_param; + params.push_back(place_holder_param); + params.push_back(size_param); + objects_[ui::Clipboard::CBF_SMBITMAP] = params; +} + +// Define a destructor that makes IPCs to flush the contents to the +// system clipboard. +ScopedClipboardWriterGlue::~ScopedClipboardWriterGlue() { + if (objects_.empty()) + return; + + if (shared_buf_) { + RenderThread::current()->Send( + new ClipboardHostMsg_WriteObjectsSync(objects_, + shared_buf_->handle())); + delete shared_buf_; + return; + } + + RenderThread::current()->Send( + new ClipboardHostMsg_WriteObjectsAsync(objects_)); +} + +namespace webkit_glue { + +void AppendToLog(const char* file, int line, const char* msg) { + logging::LogMessage(file, line).stream() << msg; +} + +base::StringPiece GetDataResource(int resource_id) { + return ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id); +} + +#if defined(OS_WIN) +HCURSOR LoadCursor(int cursor_id) { + return ResourceBundle::GetSharedInstance().LoadCursor(cursor_id); +} +#endif + +// Clipboard glue + +ui::Clipboard* ClipboardGetClipboard() { + return NULL; +} + +bool ClipboardIsFormatAvailable(const ui::Clipboard::FormatType& format, + ui::Clipboard::Buffer buffer) { + bool result; + RenderThread::current()->Send( + new ClipboardHostMsg_IsFormatAvailable(format, buffer, &result)); + return result; +} + +void ClipboardReadAvailableTypes(ui::Clipboard::Buffer buffer, + std::vector<string16>* types, + bool* contains_filenames) { + RenderThread::current()->Send(new ClipboardHostMsg_ReadAvailableTypes( + buffer, types, contains_filenames)); +} + +void ClipboardReadText(ui::Clipboard::Buffer buffer, string16* result) { + RenderThread::current()->Send(new ClipboardHostMsg_ReadText(buffer, result)); +} + +void ClipboardReadAsciiText(ui::Clipboard::Buffer buffer, std::string* result) { + RenderThread::current()->Send( + new ClipboardHostMsg_ReadAsciiText(buffer, result)); +} + +void ClipboardReadHTML(ui::Clipboard::Buffer buffer, string16* markup, + GURL* url) { + RenderThread::current()->Send( + new ClipboardHostMsg_ReadHTML(buffer, markup, url)); +} + +void ClipboardReadImage(ui::Clipboard::Buffer buffer, std::string* data) { + RenderThread::current()->Send(new ClipboardHostMsg_ReadImage(buffer, data)); +} + +bool ClipboardReadData(ui::Clipboard::Buffer buffer, const string16& type, + string16* data, string16* metadata) { + bool result = false; + RenderThread::current()->Send(new ClipboardHostMsg_ReadData( + buffer, type, &result, data, metadata)); + return result; +} + +bool ClipboardReadFilenames(ui::Clipboard::Buffer buffer, + std::vector<string16>* filenames) { + bool result; + RenderThread::current()->Send(new ClipboardHostMsg_ReadFilenames( + buffer, &result, filenames)); + return result; +} + +void GetPlugins(bool refresh, + std::vector<webkit::npapi::WebPluginInfo>* plugins) { + if (!RenderThread::current()->plugin_refresh_allowed()) + refresh = false; + RenderThread::current()->Send(new ViewHostMsg_GetPlugins(refresh, plugins)); +} + +bool IsProtocolSupportedForMedia(const GURL& url) { + // If new protocol is to be added here, we need to make sure the response is + // validated accordingly in the media engine. + if (url.SchemeIsFile() || url.SchemeIs(chrome::kHttpScheme) || + url.SchemeIs(chrome::kHttpsScheme) || + url.SchemeIs(chrome::kDataScheme) || + url.SchemeIs(chrome::kExtensionScheme) || + url.SchemeIs(chrome::kFileSystemScheme) || + url.SchemeIs(chrome::kBlobScheme)) + return true; + return false; +} + +// static factory function +ResourceLoaderBridge* ResourceLoaderBridge::Create( + const ResourceLoaderBridge::RequestInfo& request_info) { + return ChildThread::current()->CreateBridge(request_info); +} + +// static factory function +WebSocketStreamHandleBridge* WebSocketStreamHandleBridge::Create( + WebKit::WebSocketStreamHandle* handle, + WebSocketStreamHandleDelegate* delegate) { + SocketStreamDispatcher* dispatcher = + ChildThread::current()->socket_stream_dispatcher(); + return dispatcher->CreateBridge(handle, delegate); +} + +void CloseCurrentConnections() { + RenderThread::current()->CloseCurrentConnections(); +} + +void SetCacheMode(bool enabled) { + RenderThread::current()->SetCacheMode(enabled); +} + +void ClearCache(bool preserve_ssl_host_info) { + RenderThread::current()->ClearCache(preserve_ssl_host_info); +} + +void ClearHostResolverCache() { + RenderThread::current()->ClearHostResolverCache(); +} + +void ClearPredictorCache() { + RenderThread::current()->ClearPredictorCache(); +} + +bool IsSingleProcess() { + return CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess); +} + +void EnableSpdy(bool enable) { + RenderThread::current()->EnableSpdy(enable); +} + +#if defined(OS_LINUX) +int MatchFontWithFallback(const std::string& face, bool bold, + bool italic, int charset) { + return renderer_sandbox_support::MatchFontWithFallback( + face, bold, italic, charset); +} + +bool GetFontTable(int fd, uint32_t table, uint8_t* output, + size_t* output_length) { + return renderer_sandbox_support::GetFontTable( + fd, table, output, output_length); +} +#endif + +} // namespace webkit_glue diff --git a/content/renderer/renderer_main.cc b/content/renderer/renderer_main.cc new file mode 100644 index 0000000..f6dc81b --- /dev/null +++ b/content/renderer/renderer_main.cc @@ -0,0 +1,364 @@ +// Copyright (c) 2011 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. + +#if defined(OS_MACOSX) +#include <signal.h> +#include <unistd.h> +#endif // OS_MACOSX + +#include "base/command_line.h" +#include "base/debug/trace_event.h" +#include "base/i18n/rtl.h" +#include "base/mac/scoped_nsautorelease_pool.h" +#include "base/memory/ref_counted.h" +#include "base/metrics/field_trial.h" +#include "base/message_loop.h" +#include "base/metrics/histogram.h" +#include "base/metrics/stats_counters.h" +#include "base/path_service.h" +#include "base/process_util.h" +#include "base/string_util.h" +#include "base/threading/platform_thread.h" +#include "base/time.h" +#include "content/common/content_counters.h" +#include "content/common/content_switches.h" +#include "content/common/main_function_params.h" +#include "content/common/hi_res_timer_manager.h" +#include "content/common/pepper_plugin_registry.h" +#include "content/renderer/render_process_impl.h" +#include "content/renderer/render_thread.h" +#include "content/renderer/renderer_main_platform_delegate.h" +#include "ui/base/system_monitor/system_monitor.h" +#include "ui/base/ui_base_switches.h" + +#if defined(OS_MACOSX) +#include <Carbon/Carbon.h> // TISCreateInputSourceList + +#include "base/eintr_wrapper.h" +#include "base/sys_info.h" +#include "chrome/app/breakpad_mac.h" +#include "third_party/mach_override/mach_override.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" +#endif // OS_MACOSX + +#if defined(OS_MACOSX) +namespace { + +CFArrayRef ChromeTISCreateInputSourceList( + CFDictionaryRef properties, + Boolean includeAllInstalled) { + CFTypeRef values[] = { CFSTR("") }; + return CFArrayCreate( + kCFAllocatorDefault, values, arraysize(values), &kCFTypeArrayCallBacks); +} + +void InstallFrameworkHacks() { + int32 os_major, os_minor, os_bugfix; + base::SysInfo::OperatingSystemVersionNumbers( + &os_major, &os_minor, &os_bugfix); + + // See http://crbug.com/31225 + // TODO: Don't do this on newer OS X revisions that have a fix for + // http://openradar.appspot.com/radar?id=1156410 + if (os_major == 10 && os_minor >= 6) { + // Chinese Handwriting was introduced in 10.6. Since doing this override + // regresses page cycler memory usage on 10.5, don't do the unnecessary + // override there. + mach_error_t err = mach_override_ptr( + (void*)&TISCreateInputSourceList, + (void*)&ChromeTISCreateInputSourceList, + NULL); + CHECK_EQ(err_none, err); + } +} + +// 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 ShutdownDetector : public base::PlatformThread::Delegate { + public: + explicit ShutdownDetector(int shutdown_fd) : shutdown_fd_(shutdown_fd) { + CHECK(shutdown_fd_ != -1); + } + + 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."; + } + + // 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: + const int shutdown_fd_; + + DISALLOW_COPY_AND_ASSIGN(ShutdownDetector); +}; + +} // namespace +#endif // OS_MACOSX + +// This function provides some ways to test crash and assertion handling +// behavior of the renderer. +static void HandleRendererErrorTestParameters(const CommandLine& command_line) { + // This parameter causes an assertion. + if (command_line.HasSwitch(switches::kRendererAssertTest)) { + DCHECK(false); + } + + +#if !defined(OFFICIAL_BUILD) + // This parameter causes an assertion too. + if (command_line.HasSwitch(switches::kRendererCheckFalseTest)) { + CHECK(false); + } +#endif // !defined(OFFICIAL_BUILD) + + + // This parameter causes a null pointer crash (crash reporter trigger). + if (command_line.HasSwitch(switches::kRendererCrashTest)) { + int* bad_pointer = NULL; + *bad_pointer = 0; + } + + if (command_line.HasSwitch(switches::kRendererStartupDialog)) { + ChildProcess::WaitForDebugger("Renderer"); + } +} + +// This is a simplified version of the browser Jankometer, which measures +// the processing time of tasks on the render thread. +class RendererMessageLoopObserver : public MessageLoop::TaskObserver { + public: + RendererMessageLoopObserver() + : process_times_(base::Histogram::FactoryGet( + "Chrome.ProcMsgL RenderThread", + 1, 3600000, 50, base::Histogram::kUmaTargetedHistogramFlag)) {} + virtual ~RendererMessageLoopObserver() {} + + virtual void WillProcessTask(const Task* task) { + begin_process_message_ = base::TimeTicks::Now(); + } + + virtual void DidProcessTask(const Task* task) { + if (begin_process_message_ != base::TimeTicks()) + process_times_->AddTime(base::TimeTicks::Now() - begin_process_message_); + } + + private: + base::TimeTicks begin_process_message_; + base::Histogram* const process_times_; + DISALLOW_COPY_AND_ASSIGN(RendererMessageLoopObserver); +}; + +// mainline routine for running as the Renderer process +int RendererMain(const MainFunctionParams& parameters) { + TRACE_EVENT_BEGIN("RendererMain", 0, ""); + + const CommandLine& parsed_command_line = parameters.command_line_; + base::mac::ScopedNSAutoreleasePool* pool = parameters.autorelease_pool_; + +#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); + + InstallFrameworkHacks(); +#endif // OS_MACOSX + +#if defined(OS_CHROMEOS) + // As Zygote process starts up earlier than browser process gets its own + // locale (at login time for Chrome OS), we have to set the ICU default + // locale for renderer process here. + // ICU locale will be used for fallback font selection etc. + if (parsed_command_line.HasSwitch(switches::kLang)) { + const std::string locale = + parsed_command_line.GetSwitchValueASCII(switches::kLang); + base::i18n::SetICUDefaultLocale(locale); + } +#endif + + // This function allows pausing execution using the --renderer-startup-dialog + // flag allowing us to attach a debugger. + // Do not move this function down since that would mean we can't easily debug + // whatever occurs before it. + HandleRendererErrorTestParameters(parsed_command_line); + + RendererMainPlatformDelegate platform(parameters); + + base::StatsScope<base::StatsCounterTimer> + startup_timer(content::Counters::renderer_main()); + + RendererMessageLoopObserver task_observer; +#if defined(OS_MACOSX) + // As long as we use Cocoa in the renderer (for the forseeable future as of + // now; see http://crbug.com/13890 for info) we need to have a UI loop. + MessageLoop main_message_loop(MessageLoop::TYPE_UI); +#else + // The main message loop of the renderer services doesn't have IO or UI tasks, + // unless in-process-plugins is used. + MessageLoop main_message_loop(RenderProcessImpl::InProcessPlugins() ? + MessageLoop::TYPE_UI : MessageLoop::TYPE_DEFAULT); +#endif + main_message_loop.AddTaskObserver(&task_observer); + + base::PlatformThread::SetName("CrRendererMain"); + + ui::SystemMonitor system_monitor; + HighResolutionTimerManager hi_res_timer_manager; + + platform.PlatformInitialize(); + + bool no_sandbox = parsed_command_line.HasSwitch(switches::kNoSandbox); + platform.InitSandboxTests(no_sandbox); + + // Initialize histogram statistics gathering system. + // Don't create StatisticsRecorder in the single process mode. + scoped_ptr<base::StatisticsRecorder> statistics; + if (!base::StatisticsRecorder::IsActive()) { + statistics.reset(new base::StatisticsRecorder()); + } + + // Initialize statistical testing infrastructure. + base::FieldTrialList field_trial; + // Ensure any field trials in browser are reflected into renderer. + if (parsed_command_line.HasSwitch(switches::kForceFieldTestNameAndValue)) { + std::string persistent = parsed_command_line.GetSwitchValueASCII( + switches::kForceFieldTestNameAndValue); + bool ret = field_trial.CreateTrialsInChildProcess(persistent); + DCHECK(ret); + } + + // Load pepper plugins before engaging the sandbox. + PepperPluginRegistry::GetInstance(); + + { +#if !defined(OS_LINUX) + // TODO(markus): Check if it is OK to unconditionally move this + // instruction down. + RenderProcessImpl render_process; + render_process.set_main_thread(new RenderThread()); +#endif + bool run_loop = true; + if (!no_sandbox) { + run_loop = platform.EnableSandbox(); + } else { + LOG(ERROR) << "Running without renderer sandbox"; + } +#if defined(OS_LINUX) + RenderProcessImpl render_process; + render_process.set_main_thread(new RenderThread()); +#endif + + platform.RunSandboxTests(); + + startup_timer.Stop(); // End of Startup Time Measurement. + + if (run_loop) { + if (pool) + pool->Recycle(); + TRACE_EVENT_BEGIN("RendererMain.START_MSG_LOOP", 0, 0); + MessageLoop::current()->Run(); + TRACE_EVENT_END("RendererMain.START_MSG_LOOP", 0, 0); + } + } + platform.PlatformUninitialize(); + TRACE_EVENT_END("RendererMain", 0, ""); + return 0; +} diff --git a/content/renderer/renderer_main_platform_delegate.h b/content/renderer/renderer_main_platform_delegate.h new file mode 100644 index 0000000..c57e90e --- /dev/null +++ b/content/renderer/renderer_main_platform_delegate.h @@ -0,0 +1,40 @@ +// Copyright (c) 2009 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. + +#ifndef CHROME_RENDERER_RENDERER_MAIN_PLATFORM_DELEGATE_H_ +#define CHROME_RENDERER_RENDERER_MAIN_PLATFORM_DELEGATE_H_ +#pragma once + +#include "content/common/main_function_params.h" + +class RendererMainPlatformDelegate { + public: + explicit RendererMainPlatformDelegate(const MainFunctionParams& parameters); + ~RendererMainPlatformDelegate(); + + // Called first thing and last thing in the process' lifecycle, i.e. before + // the sandbox is enabled. + void PlatformInitialize(); + void PlatformUninitialize(); + + // Gives us an opportunity to initialize state used for tests before enabling + // the sandbox. + bool InitSandboxTests(bool no_sandbox); + + // Initiate Lockdown, returns true on success. + bool EnableSandbox(); + + // Runs Sandbox tests. + void RunSandboxTests(); + + private: + const MainFunctionParams& parameters_; +#if defined(OS_WIN) + HMODULE sandbox_test_module_; +#endif + + DISALLOW_COPY_AND_ASSIGN(RendererMainPlatformDelegate); +}; + +#endif // CHROME_RENDERER_RENDERER_MAIN_PLATFORM_DELEGATE_H_ diff --git a/content/renderer/renderer_main_platform_delegate_linux.cc b/content/renderer/renderer_main_platform_delegate_linux.cc new file mode 100644 index 0000000..b20caf9 --- /dev/null +++ b/content/renderer/renderer_main_platform_delegate_linux.cc @@ -0,0 +1,52 @@ +// Copyright (c) 2009 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 "content/renderer/renderer_main_platform_delegate.h" + +#include "base/command_line.h" +#include "content/common/content_switches.h" +#include "seccompsandbox/sandbox.h" + +RendererMainPlatformDelegate::RendererMainPlatformDelegate( + const MainFunctionParams& parameters) + : parameters_(parameters) { +} + +RendererMainPlatformDelegate::~RendererMainPlatformDelegate() { +} + +void RendererMainPlatformDelegate::PlatformInitialize() { +} + +void RendererMainPlatformDelegate::PlatformUninitialize() { +} + +bool RendererMainPlatformDelegate::InitSandboxTests(bool no_sandbox) { + // The sandbox is started in the zygote process: zygote_main_linux.cc + // http://code.google.com/p/chromium/wiki/LinuxSUIDSandbox + return true; +} + +bool RendererMainPlatformDelegate::EnableSandbox() { + // The setuid sandbox is started in the zygote process: zygote_main_linux.cc + // http://code.google.com/p/chromium/wiki/LinuxSUIDSandbox + // + // The seccomp sandbox is started in the renderer. + // http://code.google.com/p/seccompsandbox/ +#if defined(ARCH_CPU_X86_FAMILY) && !defined(CHROMIUM_SELINUX) && \ + !defined(__clang__) + // N.b. SupportsSeccompSandbox() returns a cached result, as we already + // called it earlier in the zygote. Thus, it is OK for us to not pass in + // a file descriptor for "/proc". + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableSeccompSandbox) && SupportsSeccompSandbox(-1)) + StartSeccompSandbox(); +#endif + return true; +} + +void RendererMainPlatformDelegate::RunSandboxTests() { + // The sandbox is started in the zygote process: zygote_main_linux.cc + // http://code.google.com/p/chromium/wiki/LinuxSUIDSandbox +} diff --git a/content/renderer/renderer_main_platform_delegate_mac.mm b/content/renderer/renderer_main_platform_delegate_mac.mm new file mode 100644 index 0000000..86edec7 --- /dev/null +++ b/content/renderer/renderer_main_platform_delegate_mac.mm @@ -0,0 +1,58 @@ +// Copyright (c) 2009 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 "content/renderer/renderer_main_platform_delegate.h" + +#import <Cocoa/Cocoa.h> + +#include "base/command_line.h" +#import "content/common/chrome_application_mac.h" +#include "content/common/content_switches.h" +#include "content/common/sandbox_mac.h" +#include "third_party/WebKit/Source/WebKit/mac/WebCoreSupport/WebSystemInterface.h" + +RendererMainPlatformDelegate::RendererMainPlatformDelegate( + const MainFunctionParams& parameters) + : parameters_(parameters) { +} + +RendererMainPlatformDelegate::~RendererMainPlatformDelegate() { +} + +// TODO(mac-port): Any code needed to initialize a process for purposes of +// running a renderer needs to also be reflected in chrome_main.cc for +// --single-process support. +void RendererMainPlatformDelegate::PlatformInitialize() { + // Initialize NSApplication using the custom subclass. Without this call, + // drawing of native UI elements (e.g. buttons) in WebKit will explode. + [CrApplication sharedApplication]; + + // Load WebKit system interfaces. + InitWebCoreSystemInterface(); + + if (![NSThread isMultiThreaded]) { + NSString* string = @""; + [NSThread detachNewThreadSelector:@selector(length) + toTarget:string + withObject:nil]; + } +} + +void RendererMainPlatformDelegate::PlatformUninitialize() { +} + +bool RendererMainPlatformDelegate::InitSandboxTests(bool no_sandbox) { + return true; +} + +bool RendererMainPlatformDelegate::EnableSandbox() { + CommandLine* parsed_command_line = CommandLine::ForCurrentProcess(); + SandboxInitWrapper sandbox_wrapper; + return sandbox_wrapper.InitializeSandbox(*parsed_command_line, + switches::kRendererProcess); +} + +void RendererMainPlatformDelegate::RunSandboxTests() { + // TODO(port): Run sandbox unit test here. +} diff --git a/content/renderer/renderer_main_platform_delegate_win.cc b/content/renderer/renderer_main_platform_delegate_win.cc new file mode 100644 index 0000000..50a8059 --- /dev/null +++ b/content/renderer/renderer_main_platform_delegate_win.cc @@ -0,0 +1,140 @@ +// Copyright (c) 2011 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 "content/renderer/renderer_main_platform_delegate.h" + +#include "base/command_line.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "content/common/content_switches.h" +#include "content/common/injection_test_dll.h" +#include "sandbox/src/sandbox.h" +#include "unicode/timezone.h" + +namespace { + +// In order to have Theme support, we need to connect to the theme service. +// This needs to be done before we lock down the renderer. Officially this +// can be done with OpenThemeData() but it fails unless you pass a valid +// window at least the first time. Interestingly, the very act of creating a +// window also sets the connection to the theme service. +void EnableThemeSupportForRenderer(bool no_sandbox) { + HWINSTA current = NULL; + HWINSTA winsta0 = NULL; + + if (!no_sandbox) { + current = ::GetProcessWindowStation(); + winsta0 = ::OpenWindowStationW(L"WinSta0", FALSE, GENERIC_READ); + if (!winsta0 || !::SetProcessWindowStation(winsta0)) { + // Could not set the alternate window station. There is a possibility + // that the theme wont be correctly initialized on XP. + NOTREACHED() << "Unable to switch to WinSt0"; + } + } + + HWND window = ::CreateWindowExW(0, L"Static", L"", WS_POPUP | WS_DISABLED, + CW_USEDEFAULT, 0, 0, 0, HWND_MESSAGE, NULL, + ::GetModuleHandleA(NULL), NULL); + if (!window) { + DLOG(WARNING) << "failed to enable theme support"; + } else { + ::DestroyWindow(window); + } + + if (!no_sandbox) { + // Revert the window station. + if (!current || !::SetProcessWindowStation(current)) { + // We failed to switch back to the secure window station. This might + // confuse the renderer enough that we should kill it now. + LOG(FATAL) << "Failed to restore alternate window station"; + } + + if (!::CloseWindowStation(winsta0)) { + // We might be leaking a winsta0 handle. This is a security risk, but + // since we allow fail over to no desktop protection in low memory + // condition, this is not a big risk. + NOTREACHED(); + } + } +} + +} // namespace + +RendererMainPlatformDelegate::RendererMainPlatformDelegate( + const MainFunctionParams& parameters) + : parameters_(parameters), + sandbox_test_module_(NULL) { +} + +RendererMainPlatformDelegate::~RendererMainPlatformDelegate() { +} + +void RendererMainPlatformDelegate::PlatformInitialize() { + // Be mindful of what resources you acquire here. They can be used by + // malicious code if the renderer gets compromised. + const CommandLine& command_line = parameters_.command_line_; + bool no_sandbox = command_line.HasSwitch(switches::kNoSandbox); + EnableThemeSupportForRenderer(no_sandbox); + + if (!no_sandbox) { + // ICU DateFormat class (used in base/time_format.cc) needs to get the + // Olson timezone ID by accessing the registry keys under + // HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones. + // After TimeZone::createDefault is called once here, the timezone ID is + // cached and there's no more need to access the registry. If the sandbox + // is disabled, we don't have to make this dummy call. + scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault()); + } +} + +void RendererMainPlatformDelegate::PlatformUninitialize() { +} + +bool RendererMainPlatformDelegate::InitSandboxTests(bool no_sandbox) { + const CommandLine& command_line = parameters_.command_line_; + + DVLOG(1) << "Started renderer with " << command_line.command_line_string(); + + sandbox::TargetServices* target_services = + parameters_.sandbox_info_.TargetServices(); + + if (target_services && !no_sandbox) { + std::wstring test_dll_name = + command_line.GetSwitchValueNative(switches::kTestSandbox); + if (!test_dll_name.empty()) { + sandbox_test_module_ = LoadLibrary(test_dll_name.c_str()); + DCHECK(sandbox_test_module_); + if (!sandbox_test_module_) { + return false; + } + } + } + return true; +} + +bool RendererMainPlatformDelegate::EnableSandbox() { + sandbox::TargetServices* target_services = + parameters_.sandbox_info_.TargetServices(); + + if (target_services) { + target_services->LowerToken(); + return true; + } + return false; +} + +void RendererMainPlatformDelegate::RunSandboxTests() { + if (sandbox_test_module_) { + RunRendererTests run_security_tests = + reinterpret_cast<RunRendererTests>(GetProcAddress(sandbox_test_module_, + kRenderTestCall)); + DCHECK(run_security_tests); + if (run_security_tests) { + int test_count = 0; + DVLOG(1) << "Running renderer security tests"; + BOOL result = run_security_tests(&test_count); + CHECK(result) << "Test number " << test_count << " has failed."; + } + } +} |