diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-02 21:05:00 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-02 21:05:00 +0000 |
commit | f0bc06a7b29cc6c69f30eaebf6770fcb349287a5 (patch) | |
tree | 919787c1590b38a6f922bf6d97cfac42b6b934b9 /content/app | |
parent | c2ef83f7ebd4de858056e85944037398fc112b9e (diff) | |
download | chromium_src-f0bc06a7b29cc6c69f30eaebf6770fcb349287a5.zip chromium_src-f0bc06a7b29cc6c69f30eaebf6770fcb349287a5.tar.gz chromium_src-f0bc06a7b29cc6c69f30eaebf6770fcb349287a5.tar.bz2 |
Finish moving all the generic startup code from ChromeMain to ContentMain, and add callbacks to ContentMainDelegate to handle the Chrome specific pieces.
BUG=90445
Review URL: http://codereview.chromium.org/7792080
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99452 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/app')
-rw-r--r-- | content/app/content_main.cc | 308 | ||||
-rw-r--r-- | content/app/content_main.h | 3 | ||||
-rw-r--r-- | content/app/content_main_delegate.h | 59 |
3 files changed, 340 insertions, 30 deletions
diff --git a/content/app/content_main.cc b/content/app/content_main.cc index 6204f95..971766d 100644 --- a/content/app/content_main.cc +++ b/content/app/content_main.cc @@ -5,23 +5,47 @@ #include "content/app/content_main.h" #include "base/at_exit.h" +#include "base/base_switches.h" #include "base/command_line.h" +#include "base/debug/debugger.h" +#include "base/i18n/icu_util.h" #include "base/logging.h" #include "base/mac/scoped_nsautorelease_pool.h" +#include "base/memory/scoped_ptr.h" #include "base/process_util.h" +#include "base/stringprintf.h" #include "content/app/content_main_delegate.h" +#include "content/common/content_paths.h" +#include "content/common/content_switches.h" +#include "content/common/main_function_params.h" +#include "content/common/sandbox_init_wrapper.h" +#include "content/common/set_process_title.h" +#include "crypto/nss_util.h" +#include "ui/base/ui_base_switches.h" +#include "ui/base/ui_base_paths.h" #if defined(OS_WIN) #include <atlbase.h> #include <atlapp.h> #include <new.h> #include <malloc.h> -#elif defined(OS_POSIX) +#elif defined(OS_MACOSX) +#include "base/mach_ipc_mac.h" +#include "base/system_monitor/system_monitor.h" +#include "content/browser/mach_broker_mac.h" +#endif // OS_WIN + +#if defined(OS_POSIX) #include <signal.h> #include "base/global_descriptors_posix.h" #include "content/common/chrome_descriptors.h" -#endif // OS_WIN + +#if !defined(OS_MACOSX) +#include "content/common/zygote_fork_delegate_linux.h" +#endif + +#endif // OS_POSIX #if !defined(OS_MACOSX) && defined(USE_TCMALLOC) extern "C" { @@ -29,10 +53,19 @@ int tc_set_new_mode(int mode); } #endif -namespace { +extern int RendererMain(const MainFunctionParams&); +extern int GpuMain(const MainFunctionParams&); +extern int PluginMain(const MainFunctionParams&); +extern int PpapiPluginMain(const MainFunctionParams&); +extern int PpapiBrokerMain(const MainFunctionParams&); +extern int WorkerMain(const MainFunctionParams&); +extern int UtilityMain(const MainFunctionParams&); +#if defined(OS_POSIX) && !defined(OS_MACOSX) +extern int ZygoteMain(const MainFunctionParams&, + ZygoteForkDelegate* forkdelegate); +#endif -base::AtExitManager* g_exit_manager; -base::mac::ScopedNSAutoreleasePool* g_autorelease_pool; +namespace { #if defined(OS_WIN) @@ -63,7 +96,34 @@ void RegisterInvalidParamHandler() { _set_new_mode(1); } -#elif defined(OS_POSIX) +#elif defined(OS_MACOSX) + +// Completes the Mach IPC handshake by sending this process' task port to the +// parent process. The parent is listening on the Mach port given by +// |GetMachPortName()|. The task port is used by the parent to get CPU/memory +// stats to display in the task manager. +void SendTaskPortToParentProcess() { + const mach_msg_timeout_t kTimeoutMs = 100; + const int32_t kMessageId = 0; + std::string mach_port_name = MachBroker::GetMachPortName(); + + base::MachSendMessage child_message(kMessageId); + if (!child_message.AddDescriptor(mach_task_self())) { + LOG(ERROR) << "child AddDescriptor(mach_task_self()) failed."; + return; + } + + base::MachPortSender child_sender(mach_port_name.c_str()); + kern_return_t err = child_sender.SendMessage(child_message, kTimeoutMs); + if (err != KERN_SUCCESS) { + LOG(ERROR) << StringPrintf("child SendMessage() failed: 0x%x %s", err, + mach_error_string(err)); + } +} + +#endif // defined(OS_WIN) + +#if defined(OS_POSIX) // Setup signal-handling state: resanitize most signals, ignore SIGPIPE. void SetupSignalHandlers() { @@ -87,7 +147,131 @@ void SetupSignalHandlers() { CHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR); } -#endif // OS_WIN +#endif // OS_POSIX + +void SetupCRT(const CommandLine& command_line) { +#if defined(OS_WIN) +#if defined(_CRTDBG_MAP_ALLOC) + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); +#else + if (!command_line.HasSwitch(switches::kDisableBreakpad)) { + _CrtSetReportMode(_CRT_ASSERT, 0); + } +#endif +#endif +} + +void CommonSubprocessInit(const std::string& process_type) { +#if defined(OS_WIN) + // HACK: Let Windows know that we have started. This is needed to suppress + // the IDC_APPSTARTING cursor from being displayed for a prolonged period + // while a subprocess is starting. + PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0); + MSG msg; + PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); +#endif +#if defined(OS_POSIX) && !defined(OS_MACOSX) + // Various things break when you're using a locale where the decimal + // separator isn't a period. See e.g. bugs 22782 and 39964. For + // all processes except the browser process (where we call system + // APIs that may rely on the correct locale for formatting numbers + // when presenting them to the user), reset the locale for numeric + // formatting. + // Note that this is not correct for plugin processes -- they can + // surface UI -- but it's likely they get this wrong too so why not. + setlocale(LC_NUMERIC, "C"); +#endif +} + +// We dispatch to a process-type-specific FooMain() based on a command-line +// flag. This struct is used to build a table of (flag, main function) pairs. +struct MainFunction { + const char* name; + int (*function)(const MainFunctionParams&); +}; + +#if defined(OS_POSIX) && !defined(OS_MACOSX) +// On platforms that use the zygote, we have a special subset of +// subprocesses that are launched via the zygote. This function +// fills in some process-launching bits around ZygoteMain(). +// Returns the exit code of the subprocess. +int RunZygote(const MainFunctionParams& main_function_params, + content::ContentMainDelegate* delegate) { + static const MainFunction kMainFunctions[] = { + { switches::kRendererProcess, RendererMain }, + { switches::kWorkerProcess, WorkerMain }, + { switches::kPpapiPluginProcess, PpapiPluginMain }, + }; + + scoped_ptr<ZygoteForkDelegate> zygote_fork_delegate; + if (delegate) zygote_fork_delegate.reset(delegate->ZygoteStarting()); + + // This function call can return multiple times, once per fork(). + if (!ZygoteMain(main_function_params, zygote_fork_delegate.get())) + return 1; + + if (delegate) delegate->ZygoteForked(); + + // Zygote::HandleForkRequest may have reallocated the command + // line so update it here with the new version. + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + + MainFunctionParams main_params(command_line, + main_function_params.sandbox_info_, + main_function_params.autorelease_pool_); + // Get the new process type from the new command line. + std::string process_type = + command_line.GetSwitchValueASCII(switches::kProcessType); + + for (size_t i = 0; i < arraysize(kMainFunctions); ++i) { + if (process_type == kMainFunctions[i].name) + return kMainFunctions[i].function(main_params); + } + + if (delegate) + return delegate->RunProcess(process_type, main_function_params); + + NOTREACHED() << "Unknown zygote process type: " << process_type; + return 1; +} +#endif // defined(OS_POSIX) && !defined(OS_MACOSX) + +// Run the FooMain() for a given process type. +// If |process_type| is empty, runs BrowserMain(). +// Returns the exit code for this process. +int RunNamedProcessTypeMain(const std::string& process_type, + const MainFunctionParams& main_function_params, + content::ContentMainDelegate* delegate) { + static const MainFunction kMainFunctions[] = { + { switches::kRendererProcess, RendererMain }, + { switches::kPluginProcess, PluginMain }, + { switches::kWorkerProcess, WorkerMain }, + { switches::kPpapiPluginProcess, PpapiPluginMain }, + { switches::kPpapiBrokerProcess, PpapiBrokerMain }, + { switches::kUtilityProcess, UtilityMain }, + { switches::kGpuProcess, GpuMain }, + }; + + for (size_t i = 0; i < arraysize(kMainFunctions); ++i) { + if (process_type == kMainFunctions[i].name) + return kMainFunctions[i].function(main_function_params); + } + +#if defined(OS_POSIX) && !defined(OS_MACOSX) + // Zygote startup is special -- see RunZygote comments above + // for why we don't use ZygoteMain directly. + if (process_type == switches::kZygoteProcess) + return RunZygote(main_function_params, delegate); +#endif + + // If it's a process we don't know about, the embedder should know. + if (delegate) + return delegate->RunProcess(process_type, main_function_params); + + NOTREACHED() << "Unknown process type: " << process_type; + return 1; +} } // namespace @@ -138,36 +322,124 @@ int ContentMain(int argc, base::EnableTerminationOnOutOfMemory(); // The exit manager is in charge of calling the dtors of singleton objects. - g_exit_manager = new base::AtExitManager(); + base::AtExitManager exit_manager; // We need this pool for all the objects created before we get to the // event loop, but we don't want to leave them hanging around until the // app quits. Each "main" needs to flush this pool right before it goes into // its main event loop to get rid of the cruft. - g_autorelease_pool = new base::mac::ScopedNSAutoreleasePool(); + base::mac::ScopedNSAutoreleasePool autorelease_pool; CommandLine::Init(argc, argv); int exit_code; - if (delegate && - delegate->BasicStartupComplete(&exit_code, g_autorelease_pool)) + if (delegate && delegate->BasicStartupComplete(&exit_code)) return exit_code; - // Temporary - return 0; -} + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + std::string process_type = + command_line.GetSwitchValueASCII(switches::kProcessType); + +#if defined(OS_MACOSX) + // We need to allocate the IO Ports before the Sandbox is initialized or + // the first instance of SystemMonitor is created. + // It's important not to allocate the ports for processes which don't register + // with the system monitor - see crbug.com/88867. + if (process_type.empty() || + process_type == switches::kPluginProcess || + process_type == switches::kRendererProcess || + process_type == switches::kUtilityProcess || + process_type == switches::kWorkerProcess || + (delegate && delegate->ProcessRegistersWithSystemProcess(process_type))) { + base::SystemMonitor::AllocateSystemIOPorts(); + } + + if (!process_type.empty() && + (!delegate || delegate->ShouldSendMachPort(process_type))) { + SendTaskPortToParentProcess(); + } +#endif + +#if defined(OS_POSIX) + if (!process_type.empty()) { + // When you hit Ctrl-C in a terminal running the browser + // process, a SIGINT is delivered to the entire process group. + // When debugging the browser process via gdb, gdb catches the + // SIGINT for the browser process (and dumps you back to the gdb + // console) but doesn't for the child processes, killing them. + // The fix is to have child processes ignore SIGINT; they'll die + // on their own when the browser process goes away. + // + // Note that we *can't* rely on BeingDebugged to catch this case because we + // are the child process, which is not being debugged. + // TODO(evanm): move this to some shared subprocess-init function. + if (!base::debug::BeingDebugged()) + signal(SIGINT, SIG_IGN); + } +#endif + + SetupCRT(command_line); + +#if defined(USE_NSS) + crypto::EarlySetupForNSSInit(); +#endif + + ui::RegisterPathProvider(); + content::RegisterPathProvider(); + + CHECK(icu_util::Initialize()); + + if (delegate) delegate->PreSandboxStartup(); + + if (!process_type.empty()) + CommonSubprocessInit(process_type); + + // Initialize the sandbox for this process. + SandboxInitWrapper sandbox_wrapper; + bool initialize_sandbox = true; + +#if defined(OS_WIN) + sandbox_wrapper.SetServices(sandbox_info); +#elif defined(OS_MACOSX) + // On OS X the renderer sandbox needs to be initialized later in the startup + // sequence in RendererMainPlatformDelegate::EnableSandbox(). + if (process_type == switches::kRendererProcess || + process_type == switches::kPpapiPluginProcess || + (delegate && delegate->DelaySandboxInitialization(process_type))) { + initialize_sandbox = false; + } +#endif + + if (initialize_sandbox) { + bool sandbox_initialized_ok = + sandbox_wrapper.InitializeSandbox(command_line, process_type); + // Die if the sandbox can't be enabled. + CHECK(sandbox_initialized_ok) << "Error initializing sandbox for " + << process_type; + } + + if (delegate) delegate->SandboxInitialized(process_type); + +#if defined(OS_POSIX) + SetProcessTitleFromCommandLine(argv); +#endif + + MainFunctionParams main_params(command_line, sandbox_wrapper, + &autorelease_pool); + + exit_code = RunNamedProcessTypeMain(process_type, main_params, delegate); + + if (delegate) delegate->ProcessExiting(process_type); -void ContentMainEnd() { #if defined(OS_WIN) #ifdef _CRTDBG_MAP_ALLOC _CrtDumpMemoryLeaks(); #endif // _CRTDBG_MAP_ALLOC _Module.Term(); - - delete g_autorelease_pool; - delete g_exit_manager; #endif // OS_WIN + + return exit_code; } } // namespace content diff --git a/content/app/content_main.h b/content/app/content_main.h index 285fc6a..259c813 100644 --- a/content/app/content_main.h +++ b/content/app/content_main.h @@ -37,9 +37,6 @@ int ContentMain(int argc, ContentMainDelegate* delegate); #endif -// Temporary function so that we can move code from chrome in stages. -void ContentMainEnd(); - } // namespace content #endif // CONTENT_APP_CONTENT_MAIN_H_ diff --git a/content/app/content_main_delegate.h b/content/app/content_main_delegate.h index 78b84dc..3e28c5d 100644 --- a/content/app/content_main_delegate.h +++ b/content/app/content_main_delegate.h @@ -6,22 +6,63 @@ #define CONTENT_APP_CONTENT_MAIN_DELEGATE_H_ #pragma once -namespace base { -namespace mac { -class ScopedNSAutoreleasePool; -} -} +#include <string> + +#include "build/build_config.h" + +struct MainFunctionParams; +class ZygoteForkDelegate; namespace content { class ContentMainDelegate { public: // Tells the embedder that the absolute basic startup has been done, i.e. it's - // now safe to create singeltons and check the command line. Return true if + // now safe to create singletons and check the command line. Return true if // the process should exit afterwards, and if so, |exit_code| should be set. - virtual bool BasicStartupComplete( - int* exit_code, - base::mac::ScopedNSAutoreleasePool* autorelease_pool) = 0; + // This is the place for embedder to do the things that must happen at the + // start. Most of its startup code should be in the methods below. + virtual bool BasicStartupComplete(int* exit_code) = 0; + + // This is where the embedder puts all of its startup code that needs to run + // before the sandbox is engaged. + virtual void PreSandboxStartup() = 0; + + // This is where the embedder can add startup code to run after the sandbox + // has been initialized. + virtual void SandboxInitialized(const std::string& process_type) = 0; + + // Asks the embedder to start a process that content doesn't know about. + virtual int RunProcess(const std::string& process_type, + const MainFunctionParams& main_function_params) = 0; + + // Called right before the process exits. + virtual void ProcessExiting(const std::string& process_type) = 0; + +#if defined(OS_MACOSX) + // Returns true if the process registers with the system monitor, so that we + // can allocate an IO port for it before the sandbox is initialized. Embedders + // are called only for process types that content doesn't know about. + virtual bool ProcessRegistersWithSystemProcess( + const std::string& process_type) = 0; + + // Used to determine if we should send the mach port to the parent process or + // not. The embedder usually sends it for all child processes, use this to + // override this behavior. + virtual bool ShouldSendMachPort(const std::string& process_type) = 0; + + // Allows the embedder to override initializing the sandbox. This is needed + // because some processes might not want to enable it right away or might not + // want it at all. + virtual bool DelaySandboxInitialization(const std::string& process_type) = 0; +#elif defined(OS_POSIX) + // Tells the embedder that the zygote process is starting, and allows it to + // specify a zygote delegate if it wishes. + virtual ZygoteForkDelegate* ZygoteStarting() = 0; + + // Called every time the zygote process forks. + virtual void ZygoteForked() = 0; +#endif // OS_MACOSX }; } // namespace content |