| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 #if defined(OS_MACOSX) | |
| 6 #include <signal.h> | |
| 7 #include <unistd.h> | |
| 8 #endif // OS_MACOSX | |
| 9 | |
| 10 #include "base/command_line.h" | |
| 11 #include "base/debug/trace_event.h" | |
| 12 #include "base/i18n/rtl.h" | |
| 13 #include "base/mac/scoped_nsautorelease_pool.h" | |
| 14 #include "base/memory/ref_counted.h" | |
| 15 #include "base/metrics/field_trial.h" | |
| 16 #include "base/message_loop.h" | |
| 17 #include "base/metrics/histogram.h" | |
| 18 #include "base/metrics/stats_counters.h" | |
| 19 #include "base/path_service.h" | |
| 20 #include "base/process_util.h" | |
| 21 #include "base/string_util.h" | |
| 22 #include "base/threading/platform_thread.h" | |
| 23 #include "base/time.h" | |
| 24 #include "chrome/common/chrome_constants.h" | |
| 25 #include "chrome/common/chrome_counters.h" | |
| 26 #include "chrome/common/chrome_switches.h" | |
| 27 #include "chrome/common/logging_chrome.h" | |
| 28 #include "chrome/common/net/net_resource_provider.h" | |
| 29 #include "chrome/common/pepper_plugin_registry.h" | |
| 30 #include "chrome/renderer/renderer_main_platform_delegate.h" | |
| 31 #include "content/common/main_function_params.h" | |
| 32 #include "content/common/hi_res_timer_manager.h" | |
| 33 #include "content/renderer/render_process_impl.h" | |
| 34 #include "content/renderer/render_thread.h" | |
| 35 #include "grit/generated_resources.h" | |
| 36 #include "net/base/net_module.h" | |
| 37 #include "ui/base/system_monitor/system_monitor.h" | |
| 38 #include "ui/base/ui_base_switches.h" | |
| 39 | |
| 40 #if defined(OS_MACOSX) | |
| 41 #include <Carbon/Carbon.h> // TISCreateInputSourceList | |
| 42 | |
| 43 #include "base/eintr_wrapper.h" | |
| 44 #include "base/sys_info.h" | |
| 45 #include "chrome/app/breakpad_mac.h" | |
| 46 #include "third_party/mach_override/mach_override.h" | |
| 47 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | |
| 48 #endif // OS_MACOSX | |
| 49 | |
| 50 #if defined(OS_MACOSX) | |
| 51 namespace { | |
| 52 | |
| 53 CFArrayRef ChromeTISCreateInputSourceList( | |
| 54 CFDictionaryRef properties, | |
| 55 Boolean includeAllInstalled) { | |
| 56 CFTypeRef values[] = { CFSTR("") }; | |
| 57 return CFArrayCreate( | |
| 58 kCFAllocatorDefault, values, arraysize(values), &kCFTypeArrayCallBacks); | |
| 59 } | |
| 60 | |
| 61 void InstallFrameworkHacks() { | |
| 62 int32 os_major, os_minor, os_bugfix; | |
| 63 base::SysInfo::OperatingSystemVersionNumbers( | |
| 64 &os_major, &os_minor, &os_bugfix); | |
| 65 | |
| 66 // See http://crbug.com/31225 | |
| 67 // TODO: Don't do this on newer OS X revisions that have a fix for | |
| 68 // http://openradar.appspot.com/radar?id=1156410 | |
| 69 if (os_major == 10 && os_minor >= 6) { | |
| 70 // Chinese Handwriting was introduced in 10.6. Since doing this override | |
| 71 // regresses page cycler memory usage on 10.5, don't do the unnecessary | |
| 72 // override there. | |
| 73 mach_error_t err = mach_override_ptr( | |
| 74 (void*)&TISCreateInputSourceList, | |
| 75 (void*)&ChromeTISCreateInputSourceList, | |
| 76 NULL); | |
| 77 CHECK_EQ(err_none, err); | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 // TODO(viettrungluu): crbug.com/28547: The following signal handling is needed, | |
| 82 // as a stopgap, to avoid leaking due to not releasing Breakpad properly. | |
| 83 // Without this problem, this could all be eliminated. Remove when Breakpad is | |
| 84 // fixed? | |
| 85 // TODO(viettrungluu): Code taken from browser_main.cc (with a bit of editing). | |
| 86 // The code should be properly shared (or this code should be eliminated). | |
| 87 int g_shutdown_pipe_write_fd = -1; | |
| 88 | |
| 89 void SIGTERMHandler(int signal) { | |
| 90 RAW_CHECK(signal == SIGTERM); | |
| 91 RAW_LOG(INFO, "Handling SIGTERM in renderer."); | |
| 92 | |
| 93 // Reinstall the default handler. We had one shot at graceful shutdown. | |
| 94 struct sigaction action; | |
| 95 memset(&action, 0, sizeof(action)); | |
| 96 action.sa_handler = SIG_DFL; | |
| 97 CHECK(sigaction(signal, &action, NULL) == 0); | |
| 98 | |
| 99 RAW_CHECK(g_shutdown_pipe_write_fd != -1); | |
| 100 size_t bytes_written = 0; | |
| 101 do { | |
| 102 int rv = HANDLE_EINTR( | |
| 103 write(g_shutdown_pipe_write_fd, | |
| 104 reinterpret_cast<const char*>(&signal) + bytes_written, | |
| 105 sizeof(signal) - bytes_written)); | |
| 106 RAW_CHECK(rv >= 0); | |
| 107 bytes_written += rv; | |
| 108 } while (bytes_written < sizeof(signal)); | |
| 109 | |
| 110 RAW_LOG(INFO, "Wrote signal to shutdown pipe."); | |
| 111 } | |
| 112 | |
| 113 class ShutdownDetector : public base::PlatformThread::Delegate { | |
| 114 public: | |
| 115 explicit ShutdownDetector(int shutdown_fd) : shutdown_fd_(shutdown_fd) { | |
| 116 CHECK(shutdown_fd_ != -1); | |
| 117 } | |
| 118 | |
| 119 virtual void ThreadMain() { | |
| 120 int signal; | |
| 121 size_t bytes_read = 0; | |
| 122 ssize_t ret; | |
| 123 do { | |
| 124 ret = HANDLE_EINTR( | |
| 125 read(shutdown_fd_, | |
| 126 reinterpret_cast<char*>(&signal) + bytes_read, | |
| 127 sizeof(signal) - bytes_read)); | |
| 128 if (ret < 0) { | |
| 129 NOTREACHED() << "Unexpected error: " << strerror(errno); | |
| 130 break; | |
| 131 } else if (ret == 0) { | |
| 132 NOTREACHED() << "Unexpected closure of shutdown pipe."; | |
| 133 break; | |
| 134 } | |
| 135 bytes_read += ret; | |
| 136 } while (bytes_read < sizeof(signal)); | |
| 137 | |
| 138 if (bytes_read == sizeof(signal)) | |
| 139 VLOG(1) << "Handling shutdown for signal " << signal << "."; | |
| 140 else | |
| 141 VLOG(1) << "Handling shutdown for unknown signal."; | |
| 142 | |
| 143 // Clean up Breakpad if necessary. | |
| 144 if (IsCrashReporterEnabled()) { | |
| 145 VLOG(1) << "Cleaning up Breakpad."; | |
| 146 DestructCrashReporter(); | |
| 147 } else { | |
| 148 VLOG(1) << "Breakpad not enabled; no clean-up needed."; | |
| 149 } | |
| 150 | |
| 151 // Something went seriously wrong, so get out. | |
| 152 if (bytes_read != sizeof(signal)) { | |
| 153 LOG(WARNING) << "Failed to get signal. Quitting ungracefully."; | |
| 154 _exit(1); | |
| 155 } | |
| 156 | |
| 157 // Re-raise the signal. | |
| 158 kill(getpid(), signal); | |
| 159 | |
| 160 // The signal may be handled on another thread. Give that a chance to | |
| 161 // happen. | |
| 162 sleep(3); | |
| 163 | |
| 164 // We really should be dead by now. For whatever reason, we're not. Exit | |
| 165 // immediately, with the exit status set to the signal number with bit 8 | |
| 166 // set. On the systems that we care about, this exit status is what is | |
| 167 // normally used to indicate an exit by this signal's default handler. | |
| 168 // This mechanism isn't a de jure standard, but even in the worst case, it | |
| 169 // should at least result in an immediate exit. | |
| 170 LOG(WARNING) << "Still here, exiting really ungracefully."; | |
| 171 _exit(signal | (1 << 7)); | |
| 172 } | |
| 173 | |
| 174 private: | |
| 175 const int shutdown_fd_; | |
| 176 | |
| 177 DISALLOW_COPY_AND_ASSIGN(ShutdownDetector); | |
| 178 }; | |
| 179 | |
| 180 } // namespace | |
| 181 #endif // OS_MACOSX | |
| 182 | |
| 183 // This function provides some ways to test crash and assertion handling | |
| 184 // behavior of the renderer. | |
| 185 static void HandleRendererErrorTestParameters(const CommandLine& command_line) { | |
| 186 // This parameter causes an assertion. | |
| 187 if (command_line.HasSwitch(switches::kRendererAssertTest)) { | |
| 188 DCHECK(false); | |
| 189 } | |
| 190 | |
| 191 | |
| 192 #if !defined(OFFICIAL_BUILD) | |
| 193 // This parameter causes an assertion too. | |
| 194 if (command_line.HasSwitch(switches::kRendererCheckFalseTest)) { | |
| 195 CHECK(false); | |
| 196 } | |
| 197 #endif // !defined(OFFICIAL_BUILD) | |
| 198 | |
| 199 | |
| 200 // This parameter causes a null pointer crash (crash reporter trigger). | |
| 201 if (command_line.HasSwitch(switches::kRendererCrashTest)) { | |
| 202 int* bad_pointer = NULL; | |
| 203 *bad_pointer = 0; | |
| 204 } | |
| 205 | |
| 206 if (command_line.HasSwitch(switches::kRendererStartupDialog)) { | |
| 207 ChildProcess::WaitForDebugger("Renderer"); | |
| 208 } | |
| 209 } | |
| 210 | |
| 211 // This is a simplified version of the browser Jankometer, which measures | |
| 212 // the processing time of tasks on the render thread. | |
| 213 class RendererMessageLoopObserver : public MessageLoop::TaskObserver { | |
| 214 public: | |
| 215 RendererMessageLoopObserver() | |
| 216 : process_times_(base::Histogram::FactoryGet( | |
| 217 "Chrome.ProcMsgL RenderThread", | |
| 218 1, 3600000, 50, base::Histogram::kUmaTargetedHistogramFlag)) {} | |
| 219 virtual ~RendererMessageLoopObserver() {} | |
| 220 | |
| 221 virtual void WillProcessTask(const Task* task) { | |
| 222 begin_process_message_ = base::TimeTicks::Now(); | |
| 223 } | |
| 224 | |
| 225 virtual void DidProcessTask(const Task* task) { | |
| 226 if (begin_process_message_ != base::TimeTicks()) | |
| 227 process_times_->AddTime(base::TimeTicks::Now() - begin_process_message_); | |
| 228 } | |
| 229 | |
| 230 private: | |
| 231 base::TimeTicks begin_process_message_; | |
| 232 base::Histogram* const process_times_; | |
| 233 DISALLOW_COPY_AND_ASSIGN(RendererMessageLoopObserver); | |
| 234 }; | |
| 235 | |
| 236 // mainline routine for running as the Renderer process | |
| 237 int RendererMain(const MainFunctionParams& parameters) { | |
| 238 TRACE_EVENT_BEGIN("RendererMain", 0, ""); | |
| 239 | |
| 240 const CommandLine& parsed_command_line = parameters.command_line_; | |
| 241 base::mac::ScopedNSAutoreleasePool* pool = parameters.autorelease_pool_; | |
| 242 | |
| 243 #if defined(OS_MACOSX) | |
| 244 // TODO(viettrungluu): Code taken from browser_main.cc. | |
| 245 int pipefd[2]; | |
| 246 int ret = pipe(pipefd); | |
| 247 if (ret < 0) { | |
| 248 PLOG(DFATAL) << "Failed to create pipe"; | |
| 249 } else { | |
| 250 int shutdown_pipe_read_fd = pipefd[0]; | |
| 251 g_shutdown_pipe_write_fd = pipefd[1]; | |
| 252 const size_t kShutdownDetectorThreadStackSize = 4096; | |
| 253 if (!base::PlatformThread::CreateNonJoinable( | |
| 254 kShutdownDetectorThreadStackSize, | |
| 255 new ShutdownDetector(shutdown_pipe_read_fd))) { | |
| 256 LOG(DFATAL) << "Failed to create shutdown detector task."; | |
| 257 } | |
| 258 } | |
| 259 | |
| 260 // crbug.com/28547: When Breakpad is in use, handle SIGTERM to avoid leaking | |
| 261 // Mach ports. | |
| 262 struct sigaction action; | |
| 263 memset(&action, 0, sizeof(action)); | |
| 264 action.sa_handler = SIGTERMHandler; | |
| 265 CHECK(sigaction(SIGTERM, &action, NULL) == 0); | |
| 266 | |
| 267 InstallFrameworkHacks(); | |
| 268 #endif // OS_MACOSX | |
| 269 | |
| 270 #if defined(OS_CHROMEOS) | |
| 271 // As Zygote process starts up earlier than browser process gets its own | |
| 272 // locale (at login time for Chrome OS), we have to set the ICU default | |
| 273 // locale for renderer process here. | |
| 274 // ICU locale will be used for fallback font selection etc. | |
| 275 if (parsed_command_line.HasSwitch(switches::kLang)) { | |
| 276 const std::string locale = | |
| 277 parsed_command_line.GetSwitchValueASCII(switches::kLang); | |
| 278 base::i18n::SetICUDefaultLocale(locale); | |
| 279 } | |
| 280 #endif | |
| 281 | |
| 282 // Configure modules that need access to resources. | |
| 283 net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider); | |
| 284 | |
| 285 // This function allows pausing execution using the --renderer-startup-dialog | |
| 286 // flag allowing us to attach a debugger. | |
| 287 // Do not move this function down since that would mean we can't easily debug | |
| 288 // whatever occurs before it. | |
| 289 HandleRendererErrorTestParameters(parsed_command_line); | |
| 290 | |
| 291 RendererMainPlatformDelegate platform(parameters); | |
| 292 | |
| 293 base::StatsScope<base::StatsCounterTimer> | |
| 294 startup_timer(chrome::Counters::renderer_main()); | |
| 295 | |
| 296 RendererMessageLoopObserver task_observer; | |
| 297 #if defined(OS_MACOSX) | |
| 298 // As long as we use Cocoa in the renderer (for the forseeable future as of | |
| 299 // now; see http://crbug.com/13890 for info) we need to have a UI loop. | |
| 300 MessageLoop main_message_loop(MessageLoop::TYPE_UI); | |
| 301 #else | |
| 302 // The main message loop of the renderer services doesn't have IO or UI tasks, | |
| 303 // unless in-process-plugins is used. | |
| 304 MessageLoop main_message_loop(RenderProcessImpl::InProcessPlugins() ? | |
| 305 MessageLoop::TYPE_UI : MessageLoop::TYPE_DEFAULT); | |
| 306 #endif | |
| 307 main_message_loop.AddTaskObserver(&task_observer); | |
| 308 | |
| 309 base::PlatformThread::SetName("CrRendererMain"); | |
| 310 | |
| 311 ui::SystemMonitor system_monitor; | |
| 312 HighResolutionTimerManager hi_res_timer_manager; | |
| 313 | |
| 314 platform.PlatformInitialize(); | |
| 315 | |
| 316 bool no_sandbox = parsed_command_line.HasSwitch(switches::kNoSandbox); | |
| 317 platform.InitSandboxTests(no_sandbox); | |
| 318 | |
| 319 // Initialize histogram statistics gathering system. | |
| 320 // Don't create StatisticsRecorder in the single process mode. | |
| 321 scoped_ptr<base::StatisticsRecorder> statistics; | |
| 322 if (!base::StatisticsRecorder::IsActive()) { | |
| 323 statistics.reset(new base::StatisticsRecorder()); | |
| 324 } | |
| 325 | |
| 326 // Initialize statistical testing infrastructure. | |
| 327 base::FieldTrialList field_trial; | |
| 328 // Ensure any field trials in browser are reflected into renderer. | |
| 329 if (parsed_command_line.HasSwitch(switches::kForceFieldTestNameAndValue)) { | |
| 330 std::string persistent = parsed_command_line.GetSwitchValueASCII( | |
| 331 switches::kForceFieldTestNameAndValue); | |
| 332 bool ret = field_trial.CreateTrialsInChildProcess(persistent); | |
| 333 DCHECK(ret); | |
| 334 } | |
| 335 | |
| 336 // Load pepper plugins before engaging the sandbox. | |
| 337 PepperPluginRegistry::GetInstance(); | |
| 338 | |
| 339 { | |
| 340 #if !defined(OS_LINUX) | |
| 341 // TODO(markus): Check if it is OK to unconditionally move this | |
| 342 // instruction down. | |
| 343 RenderProcessImpl render_process; | |
| 344 render_process.set_main_thread(new RenderThread()); | |
| 345 #endif | |
| 346 bool run_loop = true; | |
| 347 if (!no_sandbox) { | |
| 348 run_loop = platform.EnableSandbox(); | |
| 349 } else { | |
| 350 LOG(ERROR) << "Running without renderer sandbox"; | |
| 351 } | |
| 352 #if defined(OS_LINUX) | |
| 353 RenderProcessImpl render_process; | |
| 354 render_process.set_main_thread(new RenderThread()); | |
| 355 #endif | |
| 356 | |
| 357 platform.RunSandboxTests(); | |
| 358 | |
| 359 startup_timer.Stop(); // End of Startup Time Measurement. | |
| 360 | |
| 361 if (run_loop) { | |
| 362 if (pool) | |
| 363 pool->Recycle(); | |
| 364 TRACE_EVENT_BEGIN("RendererMain.START_MSG_LOOP", 0, 0); | |
| 365 MessageLoop::current()->Run(); | |
| 366 TRACE_EVENT_END("RendererMain.START_MSG_LOOP", 0, 0); | |
| 367 } | |
| 368 } | |
| 369 platform.PlatformUninitialize(); | |
| 370 TRACE_EVENT_END("RendererMain", 0, ""); | |
| 371 return 0; | |
| 372 } | |
| OLD | NEW |