Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(304)

Side by Side Diff: content/app/content_main_runner.cc

Issue 9372027: Revert 121236 - Support sharing of ContentMain and BrowserMain code with embedded use cases (try ... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/app/content_main.cc ('k') | content/browser/browser_main.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "base/at_exit.h"
8 #include "base/command_line.h"
9 #include "base/debug/debugger.h"
10 #include "base/debug/trace_event.h"
11 #include "base/i18n/icu_util.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/metrics/stats_table.h"
15 #include "base/process_util.h"
16 #include "base/stringprintf.h"
17 #include "base/string_number_conversions.h"
18 #include "content/browser/browser_main.h"
19 #include "content/common/set_process_title.h"
20 #include "content/public/app/content_main_delegate.h"
21 #include "content/public/app/startup_helper_win.h"
22 #include "content/public/common/content_client.h"
23 #include "content/public/common/content_constants.h"
24 #include "content/public/common/content_paths.h"
25 #include "content/public/common/content_switches.h"
26 #include "content/public/common/main_function_params.h"
27 #include "content/public/common/sandbox_init.h"
28 #include "crypto/nss_util.h"
29 #include "ipc/ipc_switches.h"
30 #include "sandbox/src/sandbox_types.h"
31 #include "ui/base/ui_base_switches.h"
32 #include "ui/base/ui_base_paths.h"
33 #include "webkit/glue/webkit_glue.h"
34
35 #if defined(OS_WIN)
36 #include <atlbase.h>
37 #include <atlapp.h>
38 #include <malloc.h>
39 #elif defined(OS_MACOSX)
40 #include "base/mac/scoped_nsautorelease_pool.h"
41 #include "base/mach_ipc_mac.h"
42 #include "base/system_monitor/system_monitor.h"
43 #include "content/browser/mach_broker_mac.h"
44 #include "content/common/sandbox_init_mac.h"
45 #endif // OS_WIN
46
47 #if defined(OS_POSIX)
48 #include <signal.h>
49
50 #include "base/global_descriptors_posix.h"
51 #include "content/common/chrome_descriptors.h"
52
53 #if !defined(OS_MACOSX)
54 #include "content/public/common/zygote_fork_delegate_linux.h"
55 #endif
56
57 #endif // OS_POSIX
58
59 #if !defined(OS_MACOSX) && defined(USE_TCMALLOC)
60 extern "C" {
61 int tc_set_new_mode(int mode);
62 }
63 #endif
64
65 extern int GpuMain(const content::MainFunctionParams&);
66 extern int PluginMain(const content::MainFunctionParams&);
67 extern int PpapiPluginMain(const content::MainFunctionParams&);
68 extern int PpapiBrokerMain(const content::MainFunctionParams&);
69 extern int RendererMain(const content::MainFunctionParams&);
70 extern int WorkerMain(const content::MainFunctionParams&);
71 extern int UtilityMain(const content::MainFunctionParams&);
72 #if defined(OS_POSIX) && !defined(OS_MACOSX)
73 extern int ZygoteMain(const content::MainFunctionParams&,
74 content::ZygoteForkDelegate* forkdelegate);
75 #endif
76
77 namespace {
78
79 #if defined(OS_MACOSX)
80
81 // Completes the Mach IPC handshake by sending this process' task port to the
82 // parent process. The parent is listening on the Mach port given by
83 // |GetMachPortName()|. The task port is used by the parent to get CPU/memory
84 // stats to display in the task manager.
85 void SendTaskPortToParentProcess() {
86 const mach_msg_timeout_t kTimeoutMs = 100;
87 const int32_t kMessageId = 0;
88 std::string mach_port_name = MachBroker::GetMachPortName();
89
90 base::MachSendMessage child_message(kMessageId);
91 if (!child_message.AddDescriptor(mach_task_self())) {
92 LOG(ERROR) << "child AddDescriptor(mach_task_self()) failed.";
93 return;
94 }
95
96 base::MachPortSender child_sender(mach_port_name.c_str());
97 kern_return_t err = child_sender.SendMessage(child_message, kTimeoutMs);
98 if (err != KERN_SUCCESS) {
99 LOG(ERROR) << StringPrintf("child SendMessage() failed: 0x%x %s", err,
100 mach_error_string(err));
101 }
102 }
103
104 #endif // defined(OS_WIN)
105
106 #if defined(OS_POSIX)
107
108 // Setup signal-handling state: resanitize most signals, ignore SIGPIPE.
109 void SetupSignalHandlers() {
110 // Sanitise our signal handling state. Signals that were ignored by our
111 // parent will also be ignored by us. We also inherit our parent's sigmask.
112 sigset_t empty_signal_set;
113 CHECK(0 == sigemptyset(&empty_signal_set));
114 CHECK(0 == sigprocmask(SIG_SETMASK, &empty_signal_set, NULL));
115
116 struct sigaction sigact;
117 memset(&sigact, 0, sizeof(sigact));
118 sigact.sa_handler = SIG_DFL;
119 static const int signals_to_reset[] =
120 {SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGSEGV,
121 SIGALRM, SIGTERM, SIGCHLD, SIGBUS, SIGTRAP}; // SIGPIPE is set below.
122 for (unsigned i = 0; i < arraysize(signals_to_reset); i++) {
123 CHECK(0 == sigaction(signals_to_reset[i], &sigact, NULL));
124 }
125
126 // Always ignore SIGPIPE. We check the return value of write().
127 CHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
128 }
129
130 #endif // OS_POSIX
131
132 void CommonSubprocessInit(const std::string& process_type) {
133 #if defined(OS_WIN)
134 // HACK: Let Windows know that we have started. This is needed to suppress
135 // the IDC_APPSTARTING cursor from being displayed for a prolonged period
136 // while a subprocess is starting.
137 PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0);
138 MSG msg;
139 PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
140 #endif
141 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
142 // Various things break when you're using a locale where the decimal
143 // separator isn't a period. See e.g. bugs 22782 and 39964. For
144 // all processes except the browser process (where we call system
145 // APIs that may rely on the correct locale for formatting numbers
146 // when presenting them to the user), reset the locale for numeric
147 // formatting.
148 // Note that this is not correct for plugin processes -- they can
149 // surface UI -- but it's likely they get this wrong too so why not.
150 setlocale(LC_NUMERIC, "C");
151 #endif
152 }
153
154 void InitializeStatsTable(base::ProcessId browser_pid,
155 const CommandLine& command_line) {
156 // Initialize the Stats Counters table. With this initialized,
157 // the StatsViewer can be utilized to read counters outside of
158 // Chrome. These lines can be commented out to effectively turn
159 // counters 'off'. The table is created and exists for the life
160 // of the process. It is not cleaned up.
161 if (command_line.HasSwitch(switches::kEnableStatsTable)) {
162 // NOTIMPLEMENTED: we probably need to shut this down correctly to avoid
163 // leaking shared memory regions on posix platforms.
164 std::string statsfile =
165 base::StringPrintf("%s-%u",
166 content::kStatsFilename,
167 static_cast<unsigned int>(browser_pid));
168 base::StatsTable* stats_table = new base::StatsTable(statsfile,
169 content::kStatsMaxThreads, content::kStatsMaxCounters);
170 base::StatsTable::set_current(stats_table);
171 }
172 }
173
174 // We dispatch to a process-type-specific FooMain() based on a command-line
175 // flag. This struct is used to build a table of (flag, main function) pairs.
176 struct MainFunction {
177 const char* name;
178 int (*function)(const content::MainFunctionParams&);
179 };
180
181 #if defined(OS_POSIX) && !defined(OS_MACOSX)
182 // On platforms that use the zygote, we have a special subset of
183 // subprocesses that are launched via the zygote. This function
184 // fills in some process-launching bits around ZygoteMain().
185 // Returns the exit code of the subprocess.
186 int RunZygote(const content::MainFunctionParams& main_function_params,
187 content::ContentMainDelegate* delegate) {
188 static const MainFunction kMainFunctions[] = {
189 { switches::kRendererProcess, RendererMain },
190 { switches::kWorkerProcess, WorkerMain },
191 { switches::kPpapiPluginProcess, PpapiPluginMain },
192 { switches::kUtilityProcess, UtilityMain },
193 };
194
195 scoped_ptr<content::ZygoteForkDelegate> zygote_fork_delegate;
196 if (delegate) zygote_fork_delegate.reset(delegate->ZygoteStarting());
197
198 // This function call can return multiple times, once per fork().
199 if (!ZygoteMain(main_function_params, zygote_fork_delegate.get()))
200 return 1;
201
202 if (delegate) delegate->ZygoteForked();
203
204 // Zygote::HandleForkRequest may have reallocated the command
205 // line so update it here with the new version.
206 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
207
208 // If a custom user agent was passed on the command line, we need
209 // to (re)set it now, rather than using the default one the zygote
210 // initialized.
211 bool custom = false;
212 std::string ua = content::GetContentClient()->GetUserAgent(&custom);
213 if (custom) webkit_glue::SetUserAgent(ua, custom);
214
215 // The StatsTable must be initialized in each process; we already
216 // initialized for the browser process, now we need to initialize
217 // within the new processes as well.
218 pid_t browser_pid = base::GetParentProcessId(
219 base::GetParentProcessId(base::GetCurrentProcId()));
220 InitializeStatsTable(browser_pid, command_line);
221
222 content::MainFunctionParams main_params(command_line);
223
224 // Get the new process type from the new command line.
225 std::string process_type =
226 command_line.GetSwitchValueASCII(switches::kProcessType);
227
228 for (size_t i = 0; i < arraysize(kMainFunctions); ++i) {
229 if (process_type == kMainFunctions[i].name)
230 return kMainFunctions[i].function(main_params);
231 }
232
233 if (delegate)
234 return delegate->RunProcess(process_type, main_params);
235
236 NOTREACHED() << "Unknown zygote process type: " << process_type;
237 return 1;
238 }
239 #endif // defined(OS_POSIX) && !defined(OS_MACOSX)
240
241 // Run the FooMain() for a given process type.
242 // If |process_type| is empty, runs BrowserMain().
243 // Returns the exit code for this process.
244 int RunNamedProcessTypeMain(
245 const std::string& process_type,
246 const content::MainFunctionParams& main_function_params,
247 content::ContentMainDelegate* delegate) {
248 static const MainFunction kMainFunctions[] = {
249 { "", BrowserMain },
250 { switches::kRendererProcess, RendererMain },
251 { switches::kPluginProcess, PluginMain },
252 { switches::kWorkerProcess, WorkerMain },
253 { switches::kPpapiPluginProcess, PpapiPluginMain },
254 { switches::kPpapiBrokerProcess, PpapiBrokerMain },
255 { switches::kUtilityProcess, UtilityMain },
256 { switches::kGpuProcess, GpuMain },
257 };
258
259 for (size_t i = 0; i < arraysize(kMainFunctions); ++i) {
260 if (process_type == kMainFunctions[i].name) {
261 if (delegate) {
262 int exit_code = delegate->RunProcess(process_type,
263 main_function_params);
264 if (exit_code >= 0)
265 return exit_code;
266 }
267 return kMainFunctions[i].function(main_function_params);
268 }
269 }
270
271 #if defined(OS_POSIX) && !defined(OS_MACOSX)
272 // Zygote startup is special -- see RunZygote comments above
273 // for why we don't use ZygoteMain directly.
274 if (process_type == switches::kZygoteProcess)
275 return RunZygote(main_function_params, delegate);
276 #endif
277
278 // If it's a process we don't know about, the embedder should know.
279 if (delegate)
280 return delegate->RunProcess(process_type, main_function_params);
281
282 NOTREACHED() << "Unknown process type: " << process_type;
283 return 1;
284 }
285
286 class ContentMainRunnerImpl : public content::ContentMainRunner {
287 public:
288 ContentMainRunnerImpl()
289 : is_initialized_(false),
290 is_shutdown_(false) {
291 }
292
293 ~ContentMainRunnerImpl() {
294 if (is_initialized_ && !is_shutdown_)
295 Shutdown();
296 }
297
298 #if defined(OS_WIN)
299 virtual int Initialize(HINSTANCE instance,
300 sandbox::SandboxInterfaceInfo* sandbox_info,
301 content::ContentMainDelegate* delegate) OVERRIDE {
302 // argc/argv are ignored on Windows; see command_line.h for details.
303 int argc = 0;
304 char** argv = NULL;
305
306 content::RegisterInvalidParamHandler();
307 app_module_.reset(new CAppModule);
308 app_module_->Init(NULL, static_cast<HINSTANCE>(instance));
309
310 if (sandbox_info)
311 sandbox_info_ = *sandbox_info;
312 else
313 memset(&sandbox_info_, 0, sizeof(sandbox_info_));
314
315 #else // !OS_WIN
316 virtual int Initialize(int argc,
317 const char** argv,
318 content::ContentMainDelegate* delegate) OVERRIDE {
319 // NOTE(willchan): One might ask why this call is done here rather than in
320 // process_util_linux.cc with the definition of
321 // EnableTerminationOnOutOfMemory(). That's because base shouldn't have a
322 // dependency on TCMalloc. Really, we ought to have our allocator shim code
323 // implement this EnableTerminationOnOutOfMemory() function. Whateverz.
324 // This works for now.
325 #if !defined(OS_MACOSX) && defined(USE_TCMALLOC)
326 // For tcmalloc, we need to tell it to behave like new.
327 tc_set_new_mode(1);
328 #endif
329
330 #if !defined(OS_ANDROID)
331 // Set C library locale to make sure CommandLine can parse argument values
332 // in correct encoding.
333 setlocale(LC_ALL, "");
334 #endif
335
336 SetupSignalHandlers();
337
338 base::GlobalDescriptors* g_fds = base::GlobalDescriptors::GetInstance();
339 g_fds->Set(kPrimaryIPCChannel,
340 kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor);
341 #if defined(OS_LINUX) || defined(OS_OPENBSD)
342 g_fds->Set(kCrashDumpSignal,
343 kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor);
344 #endif
345
346 #endif // !OS_WIN
347
348 is_initialized_ = true;
349 delegate_ = delegate;
350
351 base::EnableTerminationOnHeapCorruption();
352 base::EnableTerminationOnOutOfMemory();
353
354 // The exit manager is in charge of calling the dtors of singleton objects.
355 exit_manager_.reset(new base::AtExitManager);
356
357 #if defined(OS_MACOSX)
358 // We need this pool for all the objects created before we get to the
359 // event loop, but we don't want to leave them hanging around until the
360 // app quits. Each "main" needs to flush this pool right before it goes into
361 // its main event loop to get rid of the cruft.
362 autorelease_pool_.reset(new base::mac::ScopedNSAutoreleasePool());
363 #endif
364
365 CommandLine::Init(argc, argv);
366
367 int exit_code;
368 if (delegate && delegate->BasicStartupComplete(&exit_code))
369 return exit_code;
370
371 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
372 std::string process_type =
373 command_line.GetSwitchValueASCII(switches::kProcessType);
374
375 // Enable startup tracing asap to avoid early TRACE_EVENT calls being
376 // ignored.
377 if (command_line.HasSwitch(switches::kTraceStartup)) {
378 base::debug::TraceLog::GetInstance()->SetEnabled(
379 command_line.GetSwitchValueASCII(switches::kTraceStartup));
380 }
381
382 #if defined(OS_MACOSX)
383 // We need to allocate the IO Ports before the Sandbox is initialized or
384 // the first instance of SystemMonitor is created.
385 // It's important not to allocate the ports for processes which don't
386 // register with the system monitor - see crbug.com/88867.
387 if (process_type.empty() ||
388 process_type == switches::kPluginProcess ||
389 process_type == switches::kRendererProcess ||
390 process_type == switches::kUtilityProcess ||
391 process_type == switches::kWorkerProcess ||
392 (delegate &&
393 delegate->ProcessRegistersWithSystemProcess(process_type))) {
394 base::SystemMonitor::AllocateSystemIOPorts();
395 }
396
397 if (!process_type.empty() &&
398 (!delegate || delegate->ShouldSendMachPort(process_type))) {
399 SendTaskPortToParentProcess();
400 }
401 #elif defined(OS_WIN)
402 content::SetupCRT(command_line);
403 #endif
404
405 #if defined(OS_POSIX)
406 if (!process_type.empty()) {
407 // When you hit Ctrl-C in a terminal running the browser
408 // process, a SIGINT is delivered to the entire process group.
409 // When debugging the browser process via gdb, gdb catches the
410 // SIGINT for the browser process (and dumps you back to the gdb
411 // console) but doesn't for the child processes, killing them.
412 // The fix is to have child processes ignore SIGINT; they'll die
413 // on their own when the browser process goes away.
414 //
415 // Note that we *can't* rely on BeingDebugged to catch this case because
416 // we are the child process, which is not being debugged.
417 // TODO(evanm): move this to some shared subprocess-init function.
418 if (!base::debug::BeingDebugged())
419 signal(SIGINT, SIG_IGN);
420 }
421 #endif
422
423 #if defined(USE_NSS)
424 crypto::EarlySetupForNSSInit();
425 #endif
426
427 ui::RegisterPathProvider();
428 content::RegisterPathProvider();
429
430 CHECK(icu_util::Initialize());
431
432 base::ProcessId browser_pid = base::GetCurrentProcId();
433 if (command_line.HasSwitch(switches::kProcessChannelID)) {
434 #if defined(OS_WIN) || defined(OS_MACOSX)
435 std::string channel_name =
436 command_line.GetSwitchValueASCII(switches::kProcessChannelID);
437
438 int browser_pid_int;
439 base::StringToInt(channel_name, &browser_pid_int);
440 browser_pid = static_cast<base::ProcessId>(browser_pid_int);
441 DCHECK_NE(browser_pid_int, 0);
442 #elif defined(OS_POSIX)
443 // On linux, we're in the zygote here; so we need the parent process' id.
444 browser_pid = base::GetParentProcessId(base::GetCurrentProcId());
445 #endif
446 }
447
448 InitializeStatsTable(browser_pid, command_line);
449
450 if (delegate)
451 delegate->PreSandboxStartup();
452
453 if (!process_type.empty())
454 CommonSubprocessInit(process_type);
455
456 #if defined(OS_WIN)
457 CHECK(content::InitializeSandbox(sandbox_info));
458 #elif defined(OS_MACOSX)
459 if (process_type == switches::kRendererProcess ||
460 process_type == switches::kPpapiPluginProcess ||
461 (delegate && delegate->DelaySandboxInitialization(process_type))) {
462 // On OS X the renderer sandbox needs to be initialized later in the
463 // startup sequence in RendererMainPlatformDelegate::EnableSandbox().
464 } else {
465 CHECK(content::InitializeSandbox());
466 }
467 #endif
468
469 if (delegate)
470 delegate->SandboxInitialized(process_type);
471
472 #if defined(OS_POSIX)
473 SetProcessTitleFromCommandLine(argv);
474 #endif
475
476 // Return -1 to indicate no early termination.
477 return -1;
478 }
479
480 virtual int Run() OVERRIDE {
481 DCHECK(is_initialized_);
482 DCHECK(!is_shutdown_);
483 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
484 std::string process_type =
485 command_line.GetSwitchValueASCII(switches::kProcessType);
486
487 content::MainFunctionParams main_params(command_line);
488 #if defined(OS_WIN)
489 main_params.sandbox_info = &sandbox_info_;
490 #elif defined(OS_MACOSX)
491 main_params.autorelease_pool = autorelease_pool_.get();
492 #endif
493
494 return RunNamedProcessTypeMain(process_type, main_params, delegate_);
495 }
496
497 virtual void Shutdown() OVERRIDE {
498 DCHECK(is_initialized_);
499 DCHECK(!is_shutdown_);
500 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
501 std::string process_type =
502 command_line.GetSwitchValueASCII(switches::kProcessType);
503
504 if (delegate_)
505 delegate_->ProcessExiting(process_type);
506
507 #if defined(OS_WIN)
508 #ifdef _CRTDBG_MAP_ALLOC
509 _CrtDumpMemoryLeaks();
510 #endif // _CRTDBG_MAP_ALLOC
511
512 app_module_->Term();
513 #endif // OS_WIN
514
515 #if defined(OS_MACOSX)
516 autorelease_pool_.reset(NULL);
517 #endif
518
519 exit_manager_.reset(NULL);
520
521 #if defined(OS_WIN)
522 app_module_.reset(NULL);
523 #endif
524
525 delegate_ = NULL;
526 is_shutdown_ = true;
527 }
528
529 protected:
530 // True if the runner has been initialized.
531 bool is_initialized_;
532
533 // True if the runner has been shut down.
534 bool is_shutdown_;
535
536 // The delegate will outlive this object.
537 content::ContentMainDelegate* delegate_;
538
539 scoped_ptr<base::AtExitManager> exit_manager_;
540 #if defined(OS_WIN)
541 sandbox::SandboxInterfaceInfo sandbox_info_;
542 scoped_ptr<CAppModule> app_module_;
543 #elif defined(OS_MACOSX)
544 scoped_ptr<base::mac::ScopedNSAutoreleasePool> autorelease_pool_;
545 #endif
546
547 DISALLOW_COPY_AND_ASSIGN(ContentMainRunnerImpl);
548 };
549
550 } // namespace
551
552 namespace content {
553
554 // static
555 ContentMainRunner* ContentMainRunner::Create() {
556 return new ContentMainRunnerImpl();
557 }
558
559 } // namespace content
OLDNEW
« no previous file with comments | « content/app/content_main.cc ('k') | content/browser/browser_main.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698