1 // Copyright (c) 2012 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 #include "content/public/app/content_main_runner.h"
6
7 #include <stdlib.h>
8
9 #include "base/allocator/allocator_extension.h"
10 #include "base/at_exit.h"
11 #include "base/command_line.h"
12 #include "base/debug/debugger.h"
13 #include "base/debug/trace_event.h"
14 #include "base/files/file_path.h"
15 #include "base/i18n/icu_util.h"
16 #include "base/lazy_instance.h"
17 #include "base/logging.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "base/metrics/stats_table.h"
20 #include "base/path_service.h"
21 #include "base/process/launch.h"
22 #include "base/process/memory.h"
23 #include "base/process/process_handle.h"
24 #include "base/profiler/alternate_timer.h"
25 #include "base/strings/string_number_conversions.h"
26 #include "base/strings/string_util.h"
27 #include "base/strings/stringprintf.h"
28 #include "content/browser/browser_main.h"
29 #include "content/browser/gpu/gpu_process_host.h"
30 #include "content/common/set_process_title.h"
31 #include "content/common/url_schemes.h"
32 #include "content/gpu/in_process_gpu_thread.h"
33 #include "content/public/app/content_main_delegate.h"
34 #include "content/public/app/startup_helper_win.h"
35 #include "content/public/browser/content_browser_client.h"
36 #include "content/public/browser/render_process_host.h"
37 #include "content/public/browser/utility_process_host.h"
38 #include "content/public/common/content_client.h"
39 #include "content/public/common/content_constants.h"
40 #include "content/public/common/content_paths.h"
41 #include "content/public/common/content_switches.h"
42 #include "content/public/common/main_function_params.h"
43 #include "content/public/common/sandbox_init.h"
44 #include "content/renderer/in_process_renderer_thread.h"
45 #include "content/utility/in_process_utility_thread.h"
46 #include "crypto/nss_util.h"
47 #include "ipc/ipc_switches.h"
48 #include "media/base/media.h"
49 #include "sandbox/win/src/sandbox_types.h"
50 #include "ui/base/ui_base_paths.h"
51 #include "ui/base/ui_base_switches.h"
52 #include "ui/gfx/win/dpi.h"
53 #include "webkit/common/user_agent/user_agent.h"
54
55 #if defined(USE_TCMALLOC)
56 #include "third_party/tcmalloc/chromium/src/gperftools/malloc_extension.h"
57 #if defined(TYPE_PROFILING)
58 #include "base/allocator/type_profiler.h"
59 #include "base/allocator/type_profiler_tcmalloc.h"
60 #endif
61 #endif
62
63 #if !defined(OS_IOS)
64 #include "content/public/plugin/content_plugin_client.h"
65 #include "content/public/renderer/content_renderer_client.h"
66 #include "content/public/utility/content_utility_client.h"
67 #endif
68
69 #if defined(OS_WIN)
70 #include <atlbase.h>
71 #include <atlapp.h>
72 #include <malloc.h>
73 #include <cstring>
74 #elif defined(OS_MACOSX)
75 #include "base/mac/scoped_nsautorelease_pool.h"
76 #if !defined(OS_IOS)
77 #include "base/power_monitor/power_monitor_device_source.h"
78 #include "content/browser/mach_broker_mac.h"
79 #include "content/common/sandbox_init_mac.h"
80 #endif // !OS_IOS
81 #endif // OS_WIN
82
83 #if defined(OS_POSIX)
84 #include <signal.h>
85
86 #include "base/posix/global_descriptors.h"
87 #include "content/public/common/content_descriptors.h"
88
89 #if !defined(OS_MACOSX)
90 #include "content/public/common/zygote_fork_delegate_linux.h"
91 #endif
92 #if !defined(OS_MACOSX) && !defined(OS_ANDROID)
93 #include "content/zygote/zygote_main.h"
94 #endif
95
96 #endif // OS_POSIX
97
98 #if !defined(OS_MACOSX) && defined(USE_TCMALLOC)
99 extern "C" {
100 int tc_set_new_mode(int mode);
101 }
102 #endif
103
104 namespace content {
105 extern int GpuMain(const content::MainFunctionParams&);
106 #if defined(ENABLE_PLUGINS)
107 extern int PluginMain(const content::MainFunctionParams&);
108 extern int PpapiPluginMain(const MainFunctionParams&);
109 extern int PpapiBrokerMain(const MainFunctionParams&);
110 #endif
111 extern int RendererMain(const content::MainFunctionParams&);
112 extern int UtilityMain(const MainFunctionParams&);
113 extern int WorkerMain(const MainFunctionParams&);
114 } // namespace content
115
116 namespace {
117 #if defined(OS_WIN)
118 // In order to have Theme support, we need to connect to the theme service.
119 // This needs to be done before we lock down the process. Officially this
120 // can be done with OpenThemeData() but it fails unless you pass a valid
121 // window at least the first time. Interestingly, the very act of creating a
122 // window also sets the connection to the theme service.
EnableThemeSupportOnAllWindowStations()123 void EnableThemeSupportOnAllWindowStations() {
124 HDESK desktop_handle = ::OpenInputDesktop(0, FALSE, READ_CONTROL);
125 if (desktop_handle) {
126 // This means we are running in an input desktop, which implies WinSta0.
127 ::CloseDesktop(desktop_handle);
128 return;
129 }
130
131 HWINSTA current_station = ::GetProcessWindowStation();
132 DCHECK(current_station);
133
134 HWINSTA winsta0 = ::OpenWindowStationA("WinSta0", FALSE, GENERIC_READ);
135 if (!winsta0) {
136 DVLOG(0) << "Unable to open to WinSta0, we: "<< ::GetLastError();
137 return;
138 }
139 if (!::SetProcessWindowStation(winsta0)) {
140 // Could not set the alternate window station. There is a possibility
141 // that the theme wont be correctly initialized.
142 NOTREACHED() << "Unable to switch to WinSta0, we: "<< ::GetLastError();
143 ::CloseWindowStation(winsta0);
144 return;
145 }
146
147 HWND window = ::CreateWindowExW(0, L"Static", L"", WS_POPUP | WS_DISABLED,
148 CW_USEDEFAULT, 0, 0, 0, HWND_MESSAGE, NULL,
149 ::GetModuleHandleA(NULL), NULL);
150 if (!window) {
151 DLOG(WARNING) << "failed to enable theme support";
152 } else {
153 ::DestroyWindow(window);
154 window = NULL;
155 }
156
157 // Revert the window station.
158 if (!::SetProcessWindowStation(current_station)) {
159 // We failed to switch back to the secure window station. This might
160 // confuse the process enough that we should kill it now.
161 LOG(FATAL) << "Failed to restore alternate window station";
162 }
163
164 if (!::CloseWindowStation(winsta0)) {
165 // We might be leaking a winsta0 handle. This is a security risk, but
166 // since we allow fail over to no desktop protection in low memory
167 // condition, this is not a big risk.
168 NOTREACHED();
169 }
170 }
171 #endif // defined(OS_WIN)
172 } // namespace
173
174 namespace content {
175
176 base::LazyInstance<ContentBrowserClient>
177 g_empty_content_browser_client = LAZY_INSTANCE_INITIALIZER;
178 #if !defined(OS_IOS) && !defined(CHROME_MULTIPLE_DLL_BROWSER)
179 base::LazyInstance<ContentPluginClient>
180 g_empty_content_plugin_client = LAZY_INSTANCE_INITIALIZER;
181 base::LazyInstance<ContentRendererClient>
182 g_empty_content_renderer_client = LAZY_INSTANCE_INITIALIZER;
183 base::LazyInstance<ContentUtilityClient>
184 g_empty_content_utility_client = LAZY_INSTANCE_INITIALIZER;
185 #endif // !OS_IOS && !CHROME_MULTIPLE_DLL_BROWSER
186
187 #if defined(OS_WIN)
188
189 static CAppModule _Module;
190
191 #endif // defined(OS_WIN)
192
193 #if defined(OS_POSIX) && !defined(OS_IOS)
194
195 // Setup signal-handling state: resanitize most signals, ignore SIGPIPE.
SetupSignalHandlers()196 void SetupSignalHandlers() {
197 // Sanitise our signal handling state. Signals that were ignored by our
198 // parent will also be ignored by us. We also inherit our parent's sigmask.
199 sigset_t empty_signal_set;
200 CHECK(0 == sigemptyset(&empty_signal_set));
201 CHECK(0 == sigprocmask(SIG_SETMASK, &empty_signal_set, NULL));
202
203 struct sigaction sigact;
204 memset(&sigact, 0, sizeof(sigact));
205 sigact.sa_handler = SIG_DFL;
206 static const int signals_to_reset[] =
207 {SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGSEGV,
208 SIGALRM, SIGTERM, SIGCHLD, SIGBUS, SIGTRAP}; // SIGPIPE is set below.
209 for (unsigned i = 0; i < arraysize(signals_to_reset); i++) {
210 CHECK(0 == sigaction(signals_to_reset[i], &sigact, NULL));
211 }
212
213 // Always ignore SIGPIPE. We check the return value of write().
214 CHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
215 }
216
217 #endif // OS_POSIX && !OS_IOS
218
CommonSubprocessInit(const std::string & process_type)219 void CommonSubprocessInit(const std::string& process_type) {
220 #if defined(OS_WIN)
221 // HACK: Let Windows know that we have started. This is needed to suppress
222 // the IDC_APPSTARTING cursor from being displayed for a prolonged period
223 // while a subprocess is starting.
224 PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0);
225 MSG msg;
226 PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
227 #endif
228 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
229 // Various things break when you're using a locale where the decimal
230 // separator isn't a period. See e.g. bugs 22782 and 39964. For
231 // all processes except the browser process (where we call system
232 // APIs that may rely on the correct locale for formatting numbers
233 // when presenting them to the user), reset the locale for numeric
234 // formatting.
235 // Note that this is not correct for plugin processes -- they can
236 // surface UI -- but it's likely they get this wrong too so why not.
237 setlocale(LC_NUMERIC, "C");
238 #endif
239 }
240
GetBrowserPid(const CommandLine & command_line)241 static base::ProcessId GetBrowserPid(const CommandLine& command_line) {
242 base::ProcessId browser_pid = base::GetCurrentProcId();
243 #if !defined(OS_IOS)
244 if (command_line.HasSwitch(switches::kProcessChannelID)) {
245 #if defined(OS_WIN) || defined(OS_MACOSX)
246 std::string channel_name =
247 command_line.GetSwitchValueASCII(switches::kProcessChannelID);
248
249 int browser_pid_int;
250 base::StringToInt(channel_name, &browser_pid_int);
251 browser_pid = static_cast<base::ProcessId>(browser_pid_int);
252 DCHECK_NE(browser_pid_int, 0);
253 #elif defined(OS_ANDROID)
254 // On Android, the browser process isn't the parent. A bunch
255 // of work will be required before callers of this routine will
256 // get what they want.
257 //
258 // Note: On Linux, base::GetParentProcessId() is defined in
259 // process_util_linux.cc. Note that *_linux.cc is excluded from
260 // Android builds but a special exception is made in base.gypi
261 // for a few files including process_util_linux.cc.
262 LOG(ERROR) << "GetBrowserPid() not implemented for Android().";
263 #elif defined(OS_POSIX)
264 // On linux, we're in a process forked from the zygote here; so we need the
265 // parent's parent process' id.
266 browser_pid =
267 base::GetParentProcessId(
268 base::GetParentProcessId(base::GetCurrentProcId()));
269 #endif
270 }
271 #endif // !OS_IOS
272 return browser_pid;
273 }
274
InitializeStatsTable(const CommandLine & command_line)275 static void InitializeStatsTable(const CommandLine& command_line) {
276 // Initialize the Stats Counters table. With this initialized,
277 // the StatsViewer can be utilized to read counters outside of
278 // Chrome. These lines can be commented out to effectively turn
279 // counters 'off'. The table is created and exists for the life
280 // of the process. It is not cleaned up.
281 if (command_line.HasSwitch(switches::kEnableStatsTable)) {
282 // NOTIMPLEMENTED: we probably need to shut this down correctly to avoid
283 // leaking shared memory regions on posix platforms.
284 std::string statsfile =
285 base::StringPrintf("%s-%u", kStatsFilename,
286 static_cast<unsigned int>(GetBrowserPid(command_line)));
287 base::StatsTable* stats_table = new base::StatsTable(statsfile,
288 kStatsMaxThreads, kStatsMaxCounters);
289 base::StatsTable::set_current(stats_table);
290 }
291 }
292
293 class ContentClientInitializer {
294 public:
Set(const std::string & process_type,ContentMainDelegate * delegate)295 static void Set(const std::string& process_type,
296 ContentMainDelegate* delegate) {
297 ContentClient* content_client = GetContentClient();
298 if (process_type.empty()) {
299 if (delegate)
300 content_client->browser_ = delegate->CreateContentBrowserClient();
301 if (!content_client->browser_)
302 content_client->browser_ = &g_empty_content_browser_client.Get();
303 }
304
305 #if !defined(OS_IOS) && !defined(CHROME_MULTIPLE_DLL_BROWSER)
306 if (process_type == switches::kPluginProcess ||
307 process_type == switches::kPpapiPluginProcess) {
308 if (delegate)
309 content_client->plugin_ = delegate->CreateContentPluginClient();
310 if (!content_client->plugin_)
311 content_client->plugin_ = &g_empty_content_plugin_client.Get();
312 // Single process not supported in split dll mode.
313 } else if (process_type == switches::kRendererProcess ||
314 CommandLine::ForCurrentProcess()->HasSwitch(
315 switches::kSingleProcess)) {
316 if (delegate)
317 content_client->renderer_ = delegate->CreateContentRendererClient();
318 if (!content_client->renderer_)
319 content_client->renderer_ = &g_empty_content_renderer_client.Get();
320 }
321
322 if (process_type == switches::kUtilityProcess ||
323 CommandLine::ForCurrentProcess()->HasSwitch(
324 switches::kSingleProcess)) {
325 if (delegate)
326 content_client->utility_ = delegate->CreateContentUtilityClient();
327 // TODO(scottmg): http://crbug.com/237249 Should be in _child.
328 if (!content_client->utility_)
329 content_client->utility_ = &g_empty_content_utility_client.Get();
330 }
331 #endif // !OS_IOS && !CHROME_MULTIPLE_DLL_BROWSER
332 }
333 };
334
335 // We dispatch to a process-type-specific FooMain() based on a command-line
336 // flag. This struct is used to build a table of (flag, main function) pairs.
337 struct MainFunction {
338 const char* name;
339 int (*function)(const MainFunctionParams&);
340 };
341
342 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
343 // On platforms that use the zygote, we have a special subset of
344 // subprocesses that are launched via the zygote. This function
345 // fills in some process-launching bits around ZygoteMain().
346 // Returns the exit code of the subprocess.
RunZygote(const MainFunctionParams & main_function_params,ContentMainDelegate * delegate)347 int RunZygote(const MainFunctionParams& main_function_params,
348 ContentMainDelegate* delegate) {
349 static const MainFunction kMainFunctions[] = {
350 { switches::kRendererProcess, RendererMain },
351 { switches::kWorkerProcess, WorkerMain },
352 #if defined(ENABLE_PLUGINS)
353 { switches::kPpapiPluginProcess, PpapiPluginMain },
354 #endif
355 { switches::kUtilityProcess, UtilityMain },
356 };
357
358 scoped_ptr<ZygoteForkDelegate> zygote_fork_delegate;
359 if (delegate) {
360 zygote_fork_delegate.reset(delegate->ZygoteStarting());
361 // Each Renderer we spawn will re-attempt initialization of the media
362 // libraries, at which point failure will be detected and handled, so
363 // we do not need to cope with initialization failures here.
364 base::FilePath media_path;
365 if (PathService::Get(DIR_MEDIA_LIBS, &media_path))
366 media::InitializeMediaLibrary(media_path);
367 }
368
369 // This function call can return multiple times, once per fork().
370 if (!ZygoteMain(main_function_params, zygote_fork_delegate.get()))
371 return 1;
372
373 if (delegate) delegate->ZygoteForked();
374
375 // Zygote::HandleForkRequest may have reallocated the command
376 // line so update it here with the new version.
377 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
378 std::string process_type =
379 command_line.GetSwitchValueASCII(switches::kProcessType);
380 ContentClientInitializer::Set(process_type, delegate);
381
382 // If a custom user agent was passed on the command line, we need
383 // to (re)set it now, rather than using the default one the zygote
384 // initialized.
385 if (command_line.HasSwitch(switches::kUserAgent)) {
386 webkit_glue::SetUserAgent(
387 command_line.GetSwitchValueASCII(switches::kUserAgent), true);
388 }
389
390 // The StatsTable must be initialized in each process; we already
391 // initialized for the browser process, now we need to initialize
392 // within the new processes as well.
393 InitializeStatsTable(command_line);
394
395 MainFunctionParams main_params(command_line);
396
397 for (size_t i = 0; i < arraysize(kMainFunctions); ++i) {
398 if (process_type == kMainFunctions[i].name)
399 return kMainFunctions[i].function(main_params);
400 }
401
402 if (delegate)
403 return delegate->RunProcess(process_type, main_params);
404
405 NOTREACHED() << "Unknown zygote process type: " << process_type;
406 return 1;
407 }
408 #endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
409
410 #if !defined(OS_IOS)
RegisterMainThreadFactories()411 static void RegisterMainThreadFactories() {
412 #if !defined(CHROME_MULTIPLE_DLL_BROWSER)
413 UtilityProcessHost::RegisterUtilityMainThreadFactory(
414 CreateInProcessUtilityThread);
415 RenderProcessHost::RegisterRendererMainThreadFactory(
416 CreateInProcessRendererThread);
417 GpuProcessHost::RegisterGpuMainThreadFactory(
418 CreateInProcessGpuThread);
419 #else
420 CommandLine& command_line = *CommandLine::ForCurrentProcess();
421 if (command_line.HasSwitch(switches::kSingleProcess)) {
422 LOG(FATAL) <<
423 "--single-process is not supported in chrome multiple dll browser.";
424 }
425 if (command_line.HasSwitch(switches::kInProcessGPU)) {
426 LOG(FATAL) <<
427 "--in-process-gpu is not supported in chrome multiple dll browser.";
428 }
429 #endif
430 }
431
432 // Run the FooMain() for a given process type.
433 // If |process_type| is empty, runs BrowserMain().
434 // Returns the exit code for this process.
RunNamedProcessTypeMain(const std::string & process_type,const MainFunctionParams & main_function_params,ContentMainDelegate * delegate)435 int RunNamedProcessTypeMain(
436 const std::string& process_type,
437 const MainFunctionParams& main_function_params,
438 ContentMainDelegate* delegate) {
439 static const MainFunction kMainFunctions[] = {
440 #if !defined(CHROME_MULTIPLE_DLL_CHILD)
441 { "", BrowserMain },
442 #endif
443 #if !defined(CHROME_MULTIPLE_DLL_BROWSER)
444 #if defined(ENABLE_PLUGINS)
445 { switches::kPluginProcess, PluginMain },
446 { switches::kWorkerProcess, WorkerMain },
447 { switches::kPpapiPluginProcess, PpapiPluginMain },
448 { switches::kPpapiBrokerProcess, PpapiBrokerMain },
449 #endif // ENABLE_PLUGINS
450 { switches::kUtilityProcess, UtilityMain },
451 { switches::kRendererProcess, RendererMain },
452 { switches::kGpuProcess, GpuMain },
453 #endif // !CHROME_MULTIPLE_DLL_BROWSER
454 };
455
456 RegisterMainThreadFactories();
457
458 for (size_t i = 0; i < arraysize(kMainFunctions); ++i) {
459 if (process_type == kMainFunctions[i].name) {
460 if (delegate) {
461 int exit_code = delegate->RunProcess(process_type,
462 main_function_params);
463 #if defined(OS_ANDROID)
464 // In Android's browser process, the negative exit code doesn't mean the
465 // default behavior should be used as the UI message loop is managed by
466 // the Java and the browser process's default behavior is always
467 // overridden.
468 if (process_type.empty())
469 return exit_code;
470 #endif
471 if (exit_code >= 0)
472 return exit_code;
473 }
474 return kMainFunctions[i].function(main_function_params);
475 }
476 }
477
478 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
479 // Zygote startup is special -- see RunZygote comments above
480 // for why we don't use ZygoteMain directly.
481 if (process_type == switches::kZygoteProcess)
482 return RunZygote(main_function_params, delegate);
483 #endif
484
485 // If it's a process we don't know about, the embedder should know.
486 if (delegate)
487 return delegate->RunProcess(process_type, main_function_params);
488
489 NOTREACHED() << "Unknown process type: " << process_type;
490 return 1;
491 }
492 #endif // !OS_IOS
493
494 class ContentMainRunnerImpl : public ContentMainRunner {
495 public:
ContentMainRunnerImpl()496 ContentMainRunnerImpl()
497 : is_initialized_(false),
498 is_shutdown_(false),
499 completed_basic_startup_(false),
500 delegate_(NULL) {
501 #if defined(OS_WIN)
502 memset(&sandbox_info_, 0, sizeof(sandbox_info_));
503 #endif
504 }
505
~ContentMainRunnerImpl()506 virtual ~ContentMainRunnerImpl() {
507 if (is_initialized_ && !is_shutdown_)
508 Shutdown();
509 }
510
511 #if defined(USE_TCMALLOC)
GetAllocatorWasteSizeThunk(size_t * size)512 static bool GetAllocatorWasteSizeThunk(size_t* size) {
513 size_t heap_size, allocated_bytes, unmapped_bytes;
514 MallocExtension* ext = MallocExtension::instance();
515 if (ext->GetNumericProperty("generic.heap_size", &heap_size) &&
516 ext->GetNumericProperty("generic.current_allocated_bytes",
517 &allocated_bytes) &&
518 ext->GetNumericProperty("tcmalloc.pageheap_unmapped_bytes",
519 &unmapped_bytes)) {
520 *size = heap_size - allocated_bytes - unmapped_bytes;
521 return true;
522 }
523 DCHECK(false);
524 return false;
525 }
526
GetStatsThunk(char * buffer,int buffer_length)527 static void GetStatsThunk(char* buffer, int buffer_length) {
528 MallocExtension::instance()->GetStats(buffer, buffer_length);
529 }
530
ReleaseFreeMemoryThunk()531 static void ReleaseFreeMemoryThunk() {
532 MallocExtension::instance()->ReleaseFreeMemory();
533 }
534 #endif
535
536 #if defined(OS_WIN)
Initialize(HINSTANCE instance,sandbox::SandboxInterfaceInfo * sandbox_info,ContentMainDelegate * delegate)537 virtual int Initialize(HINSTANCE instance,
538 sandbox::SandboxInterfaceInfo* sandbox_info,
539 ContentMainDelegate* delegate) OVERRIDE {
540 // argc/argv are ignored on Windows; see command_line.h for details.
541 int argc = 0;
542 char** argv = NULL;
543
544 RegisterInvalidParamHandler();
545 _Module.Init(NULL, static_cast<HINSTANCE>(instance));
546
547 sandbox_info_ = *sandbox_info;
548 #else // !OS_WIN
549 virtual int Initialize(int argc,
550 const char** argv,
551 ContentMainDelegate* delegate) OVERRIDE {
552
553 #if defined(OS_ANDROID)
554 // See note at the initialization of ExitManager, below; basically,
555 // only Android builds have the ctor/dtor handlers set up to use
556 // TRACE_EVENT right away.
557 TRACE_EVENT0("startup", "ContentMainRunnerImpl::Initialize");
558 #endif // OS_ANDROID
559
560 // NOTE(willchan): One might ask why these TCMalloc-related calls are done
561 // here rather than in process_util_linux.cc with the definition of
562 // EnableTerminationOnOutOfMemory(). That's because base shouldn't have a
563 // dependency on TCMalloc. Really, we ought to have our allocator shim code
564 // implement this EnableTerminationOnOutOfMemory() function. Whateverz.
565 // This works for now.
566 #if !defined(OS_MACOSX) && defined(USE_TCMALLOC)
567
568 #if defined(TYPE_PROFILING)
569 base::type_profiler::InterceptFunctions::SetFunctions(
570 base::type_profiler::NewInterceptForTCMalloc,
571 base::type_profiler::DeleteInterceptForTCMalloc);
572 #endif
573
574 // For tcmalloc, we need to tell it to behave like new.
575 tc_set_new_mode(1);
576
577 // On windows, we've already set these thunks up in _heap_init()
578 base::allocator::SetGetAllocatorWasteSizeFunction(
579 GetAllocatorWasteSizeThunk);
580 base::allocator::SetGetStatsFunction(GetStatsThunk);
581 base::allocator::SetReleaseFreeMemoryFunction(ReleaseFreeMemoryThunk);
582
583 // Provide optional hook for monitoring allocation quantities on a
584 // per-thread basis. Only set the hook if the environment indicates this
585 // needs to be enabled.
586 const char* profiling = getenv(tracked_objects::kAlternateProfilerTime);
587 if (profiling &&
588 (atoi(profiling) == tracked_objects::TIME_SOURCE_TYPE_TCMALLOC)) {
589 tracked_objects::SetAlternateTimeSource(
590 MallocExtension::GetBytesAllocatedOnCurrentThread,
591 tracked_objects::TIME_SOURCE_TYPE_TCMALLOC);
592 }
593 #endif
594
595 // On Android,
596 // - setlocale() is not supported.
597 // - We do not override the signal handlers so that we can get
598 // stack trace when crashing.
599 // - The ipc_fd is passed through the Java service.
600 // Thus, these are all disabled.
601 #if !defined(OS_ANDROID) && !defined(OS_IOS)
602 // Set C library locale to make sure CommandLine can parse argument values
603 // in correct encoding.
604 setlocale(LC_ALL, "");
605
606 SetupSignalHandlers();
607
608 base::GlobalDescriptors* g_fds = base::GlobalDescriptors::GetInstance();
609 g_fds->Set(kPrimaryIPCChannel,
610 kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor);
611 #endif // !OS_ANDROID && !OS_IOS
612
613 #if defined(OS_LINUX) || defined(OS_OPENBSD)
614 g_fds->Set(kCrashDumpSignal,
615 kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor);
616 #endif
617
618 #endif // !OS_WIN
619
620 is_initialized_ = true;
621 delegate_ = delegate;
622
623 base::EnableTerminationOnHeapCorruption();
624 base::EnableTerminationOnOutOfMemory();
625
626 // The exit manager is in charge of calling the dtors of singleton objects.
627 // On Android, AtExitManager is set up when library is loaded.
628 // On iOS, it's set up in main(), which can't call directly through to here.
629 // A consequence of this is that you can't use the ctor/dtor-based
630 // TRACE_EVENT methods on Linux or iOS builds till after we set this up.
631 #if !defined(OS_ANDROID) && !defined(OS_IOS)
632 exit_manager_.reset(new base::AtExitManager);
633 #endif // !OS_ANDROID && !OS_IOS
634
635 #if defined(OS_MACOSX)
636 // We need this pool for all the objects created before we get to the
637 // event loop, but we don't want to leave them hanging around until the
638 // app quits. Each "main" needs to flush this pool right before it goes into
639 // its main event loop to get rid of the cruft.
640 autorelease_pool_.reset(new base::mac::ScopedNSAutoreleasePool());
641 #endif
642
643 // On Android, the command line is initialized when library is loaded and
644 // we have already started our TRACE_EVENT0.
645 #if !defined(OS_ANDROID)
646 CommandLine::Init(argc, argv);
647 #endif // !OS_ANDROID
648
649 int exit_code;
650 if (delegate && delegate->BasicStartupComplete(&exit_code))
651 return exit_code;
652
653 completed_basic_startup_ = true;
654
655 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
656 std::string process_type =
657 command_line.GetSwitchValueASCII(switches::kProcessType);
658
659 if (!GetContentClient())
660 SetContentClient(&empty_content_client_);
661 ContentClientInitializer::Set(process_type, delegate_);
662
663 #if defined(OS_WIN)
664 // Route stdio to parent console (if any) or create one.
665 if (command_line.HasSwitch(switches::kEnableLogging))
666 base::RouteStdioToConsole();
667 #endif
668
669 // Enable startup tracing asap to avoid early TRACE_EVENT calls being
670 // ignored.
671 if (command_line.HasSwitch(switches::kTraceStartup)) {
672 base::debug::CategoryFilter category_filter(
673 command_line.GetSwitchValueASCII(switches::kTraceStartup));
674 base::debug::TraceLog::GetInstance()->SetEnabled(
675 category_filter,
676 base::debug::TraceLog::RECORD_UNTIL_FULL);
677 }
678 #if !defined(OS_ANDROID)
679 // Android tracing started at the beginning of the method.
680 // Other OSes have to wait till we get here in order for all the memory
681 // management setup to be completed.
682 TRACE_EVENT0("startup", "ContentMainRunnerImpl::Initialize");
683 #endif // !OS_ANDROID
684
685 #if defined(OS_MACOSX) && !defined(OS_IOS)
686 // We need to allocate the IO Ports before the Sandbox is initialized or
687 // the first instance of PowerMonitor is created.
688 // It's important not to allocate the ports for processes which don't
689 // register with the power monitor - see crbug.com/88867.
690 if (process_type.empty() ||
691 (delegate &&
692 delegate->ProcessRegistersWithSystemProcess(process_type))) {
693 base::PowerMonitorDeviceSource::AllocateSystemIOPorts();
694 }
695
696 if (!process_type.empty() &&
697 (!delegate || delegate->ShouldSendMachPort(process_type))) {
698 MachBroker::ChildSendTaskPortToParent();
699 }
700 #elif defined(OS_WIN)
701 if (command_line.HasSwitch(switches::kEnableHighResolutionTime))
702 base::TimeTicks::SetNowIsHighResNowIfSupported();
703
704 // This must be done early enough since some helper functions like
705 // IsTouchEnabled, needed to load resources, may call into the theme dll.
706 EnableThemeSupportOnAllWindowStations();
707 SetupCRT(command_line);
708 #endif
709
710 #if defined(OS_POSIX)
711 if (!process_type.empty()) {
712 // When you hit Ctrl-C in a terminal running the browser
713 // process, a SIGINT is delivered to the entire process group.
714 // When debugging the browser process via gdb, gdb catches the
715 // SIGINT for the browser process (and dumps you back to the gdb
716 // console) but doesn't for the child processes, killing them.
717 // The fix is to have child processes ignore SIGINT; they'll die
718 // on their own when the browser process goes away.
719 //
720 // Note that we *can't* rely on BeingDebugged to catch this case because
721 // we are the child process, which is not being debugged.
722 // TODO(evanm): move this to some shared subprocess-init function.
723 if (!base::debug::BeingDebugged())
724 signal(SIGINT, SIG_IGN);
725 }
726 #endif
727
728 #if defined(USE_NSS)
729 crypto::EarlySetupForNSSInit();
730 #endif
731
732 ui::RegisterPathProvider();
733 RegisterPathProvider();
734 RegisterContentSchemes(true);
735
736 CHECK(base::i18n::InitializeICU());
737
738 InitializeStatsTable(command_line);
739
740 if (delegate)
741 delegate->PreSandboxStartup();
742
743 // Set any custom user agent passed on the command line now so the string
744 // doesn't change between calls to webkit_glue::GetUserAgent(), otherwise it
745 // defaults to the user agent set during SetContentClient().
746 if (command_line.HasSwitch(switches::kUserAgent)) {
747 webkit_glue::SetUserAgent(
748 command_line.GetSwitchValueASCII(switches::kUserAgent), true);
749 }
750
751 if (!process_type.empty())
752 CommonSubprocessInit(process_type);
753
754 #if defined(OS_WIN)
755 CHECK(InitializeSandbox(sandbox_info));
756 #elif defined(OS_MACOSX) && !defined(OS_IOS)
757 if (process_type == switches::kRendererProcess ||
758 process_type == switches::kPpapiPluginProcess ||
759 (delegate && delegate->DelaySandboxInitialization(process_type))) {
760 // On OS X the renderer sandbox needs to be initialized later in the
761 // startup sequence in RendererMainPlatformDelegate::EnableSandbox().
762 } else {
763 CHECK(InitializeSandbox());
764 }
765 #endif
766
767 if (delegate)
768 delegate->SandboxInitialized(process_type);
769
770 #if defined(OS_POSIX) && !defined(OS_IOS)
771 SetProcessTitleFromCommandLine(argv);
772 #endif
773
774 // Return -1 to indicate no early termination.
775 return -1;
776 }
777
778 virtual int Run() OVERRIDE {
779 DCHECK(is_initialized_);
780 DCHECK(!is_shutdown_);
781 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
782 std::string process_type =
783 command_line.GetSwitchValueASCII(switches::kProcessType);
784
785 MainFunctionParams main_params(command_line);
786 #if defined(OS_WIN)
787 main_params.sandbox_info = &sandbox_info_;
788 #elif defined(OS_MACOSX)
789 main_params.autorelease_pool = autorelease_pool_.get();
790 #endif
791
792 #if !defined(OS_IOS)
793 return RunNamedProcessTypeMain(process_type, main_params, delegate_);
794 #else
795 return 1;
796 #endif
797 }
798
799 virtual void Shutdown() OVERRIDE {
800 DCHECK(is_initialized_);
801 DCHECK(!is_shutdown_);
802
803 if (completed_basic_startup_ && delegate_) {
804 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
805 std::string process_type =
806 command_line.GetSwitchValueASCII(switches::kProcessType);
807
808 delegate_->ProcessExiting(process_type);
809 }
810
811 #if defined(OS_WIN)
812 #ifdef _CRTDBG_MAP_ALLOC
813 _CrtDumpMemoryLeaks();
814 #endif // _CRTDBG_MAP_ALLOC
815
816 _Module.Term();
817 #endif // OS_WIN
818
819 #if defined(OS_MACOSX)
820 autorelease_pool_.reset(NULL);
821 #endif
822
823 exit_manager_.reset(NULL);
824
825 delegate_ = NULL;
826 is_shutdown_ = true;
827 }
828
829 private:
830 // True if the runner has been initialized.
831 bool is_initialized_;
832
833 // True if the runner has been shut down.
834 bool is_shutdown_;
835
836 // True if basic startup was completed.
837 bool completed_basic_startup_;
838
839 // Used if the embedder doesn't set one.
840 ContentClient empty_content_client_;
841
842 // The delegate will outlive this object.
843 ContentMainDelegate* delegate_;
844
845 scoped_ptr<base::AtExitManager> exit_manager_;
846 #if defined(OS_WIN)
847 sandbox::SandboxInterfaceInfo sandbox_info_;
848 #elif defined(OS_MACOSX)
849 scoped_ptr<base::mac::ScopedNSAutoreleasePool> autorelease_pool_;
850 #endif
851
852 DISALLOW_COPY_AND_ASSIGN(ContentMainRunnerImpl);
853 };
854
855 // static
Create()856 ContentMainRunner* ContentMainRunner::Create() {
857 return new ContentMainRunnerImpl();
858 }
859
860 } // namespace content
861