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