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 |