OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/browser_main.h" | 5 #include "content/browser/browser_main.h" |
6 | 6 |
7 #include "base/allocator/allocator_shim.h" | 7 #include "base/allocator/allocator_shim.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/metrics/field_trial.h" | |
12 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
13 #include "base/system_monitor/system_monitor.h" | 12 #include "content/browser/browser_main_loop.h" |
14 #include "base/threading/thread_restrictions.h" | |
15 #include "base/tracked_objects.h" | |
16 #include "content/browser/browser_thread.h" | 13 #include "content/browser/browser_thread.h" |
17 #include "content/browser/notification_service_impl.h" | 14 #include "content/browser/notification_service_impl.h" |
18 #include "content/common/hi_res_timer_manager.h" | |
19 #include "content/common/main_function_params.h" | 15 #include "content/common/main_function_params.h" |
20 #include "content/common/sandbox_policy.h" | |
21 #include "content/public/browser/content_browser_client.h" | |
22 #include "content/public/common/content_switches.h" | 16 #include "content/public/common/content_switches.h" |
23 #include "content/public/common/result_codes.h" | |
24 #include "crypto/nss_util.h" | |
25 #include "net/base/network_change_notifier.h" | |
26 #include "net/base/ssl_config_service.h" | |
27 #include "net/socket/client_socket_factory.h" | |
28 #include "net/socket/tcp_client_socket.h" | |
29 | 17 |
30 #if defined(OS_WIN) | 18 #if defined(OS_WIN) |
31 #include <windows.h> | |
32 #include <commctrl.h> | |
33 #include <ole2.h> | |
34 #include <shellapi.h> | |
35 | |
36 #include "base/win/scoped_com_initializer.h" | 19 #include "base/win/scoped_com_initializer.h" |
37 #include "net/base/winsock_init.h" | 20 #include "content/common/sandbox_policy.h" |
38 #include "sandbox/src/sandbox.h" | 21 #include "sandbox/src/sandbox.h" |
39 #include "ui/base/l10n/l10n_util_win.h" | |
40 #endif | |
41 | |
42 #if defined(OS_LINUX) | |
43 #include <glib-object.h> | |
44 #endif | |
45 | |
46 #if defined(OS_CHROMEOS) | |
47 #include <dbus/dbus-glib.h> | |
48 #endif | |
49 | |
50 #if defined(OS_POSIX) && !defined(OS_MACOSX) | |
51 #include <sys/stat.h> | |
52 | |
53 #include "content/browser/renderer_host/render_sandbox_host_linux.h" | |
54 #include "content/browser/zygote_host_linux.h" | |
55 #endif | |
56 | |
57 #if defined(TOOLKIT_USES_GTK) | |
58 #include "ui/gfx/gtk_util.h" | |
59 #endif | 22 #endif |
60 | 23 |
61 namespace { | 24 namespace { |
62 | 25 |
63 #if defined(OS_WIN) | 26 #if defined(OS_WIN) |
64 // Windows-specific initialization code for the sandbox broker services. | 27 // Windows-specific initialization code for the sandbox broker services. |
65 void InitializeBrokerServices(const MainFunctionParams& parameters, | 28 void InitializeBrokerServices(const MainFunctionParams& parameters, |
66 const CommandLine& parsed_command_line) { | 29 const CommandLine& parsed_command_line) { |
67 sandbox::BrokerServices* broker_services = | 30 sandbox::BrokerServices* broker_services = |
68 parameters.sandbox_info_.BrokerServices(); | 31 parameters.sandbox_info_.BrokerServices(); |
69 if (broker_services) { | 32 if (broker_services) { |
70 sandbox::InitBrokerServices(broker_services); | 33 sandbox::InitBrokerServices(broker_services); |
71 if (!parsed_command_line.HasSwitch(switches::kNoSandbox)) { | 34 if (!parsed_command_line.HasSwitch(switches::kNoSandbox)) { |
72 bool use_winsta = !parsed_command_line.HasSwitch( | 35 bool use_winsta = !parsed_command_line.HasSwitch( |
73 switches::kDisableAltWinstation); | 36 switches::kDisableAltWinstation); |
74 // Precreate the desktop and window station used by the renderers. | 37 // Precreate the desktop and window station used by the renderers. |
75 sandbox::TargetPolicy* policy = broker_services->CreatePolicy(); | 38 sandbox::TargetPolicy* policy = broker_services->CreatePolicy(); |
76 sandbox::ResultCode result = policy->CreateAlternateDesktop(use_winsta); | 39 sandbox::ResultCode result = policy->CreateAlternateDesktop(use_winsta); |
77 CHECK(sandbox::SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION != result); | 40 CHECK(sandbox::SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION != result); |
78 policy->Release(); | 41 policy->Release(); |
79 } | 42 } |
80 } | 43 } |
81 } | 44 } |
82 #elif defined(OS_POSIX) && !defined(OS_MACOSX) | |
83 void SetupSandbox(const CommandLine& parsed_command_line) { | |
84 // TODO(evanm): move this into SandboxWrapper; I'm just trying to move this | |
85 // code en masse out of chrome_main for now. | |
86 const char* sandbox_binary = NULL; | |
87 struct stat st; | |
88 | |
89 // In Chromium branded builds, developers can set an environment variable to | |
90 // use the development sandbox. See | |
91 // http://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment | |
92 if (stat("/proc/self/exe", &st) == 0 && st.st_uid == getuid()) | |
93 sandbox_binary = getenv("CHROME_DEVEL_SANDBOX"); | |
94 | |
95 #if defined(LINUX_SANDBOX_PATH) | |
96 if (!sandbox_binary) | |
97 sandbox_binary = LINUX_SANDBOX_PATH; | |
98 #endif | 45 #endif |
99 | 46 |
100 std::string sandbox_cmd; | 47 bool g_exited_main_message_loop = false; |
101 if (sandbox_binary && !parsed_command_line.HasSwitch(switches::kNoSandbox)) | |
102 sandbox_cmd = sandbox_binary; | |
103 | |
104 // Tickle the sandbox host and zygote host so they fork now. | |
105 RenderSandboxHostLinux* shost = RenderSandboxHostLinux::GetInstance(); | |
106 shost->Init(sandbox_cmd); | |
107 ZygoteHost* zhost = ZygoteHost::GetInstance(); | |
108 zhost->Init(sandbox_cmd); | |
109 } | |
110 #endif | |
111 | |
112 #if defined(OS_LINUX) | |
113 static void GLibLogHandler(const gchar* log_domain, | |
114 GLogLevelFlags log_level, | |
115 const gchar* message, | |
116 gpointer userdata) { | |
117 if (!log_domain) | |
118 log_domain = "<unknown>"; | |
119 if (!message) | |
120 message = "<no message>"; | |
121 | |
122 if (strstr(message, "Loading IM context type") || | |
123 strstr(message, "wrong ELF class: ELFCLASS64")) { | |
124 // http://crbug.com/9643 | |
125 // Until we have a real 64-bit build or all of these 32-bit package issues | |
126 // are sorted out, don't fatal on ELF 32/64-bit mismatch warnings and don't | |
127 // spam the user with more than one of them. | |
128 static bool alerted = false; | |
129 if (!alerted) { | |
130 LOG(ERROR) << "Bug 9643: " << log_domain << ": " << message; | |
131 alerted = true; | |
132 } | |
133 } else if (strstr(message, "Theme file for default has no") || | |
134 strstr(message, "Theme directory") || | |
135 strstr(message, "theme pixmap")) { | |
136 LOG(ERROR) << "GTK theme error: " << message; | |
137 } else if (strstr(message, "gtk_drag_dest_leave: assertion")) { | |
138 LOG(ERROR) << "Drag destination deleted: http://crbug.com/18557"; | |
139 } else if (strstr(message, "Out of memory") && | |
140 strstr(log_domain, "<unknown>")) { | |
141 LOG(ERROR) << "DBus call timeout or out of memory: " | |
142 << "http://crosbug.com/15496"; | |
143 } else if (strstr(message, "XDG_RUNTIME_DIR variable not set")) { | |
144 LOG(ERROR) << message << " (http://bugs.chromium.org/97293)"; | |
145 } else { | |
146 LOG(DFATAL) << log_domain << ": " << message; | |
147 } | |
148 } | |
149 | |
150 static void SetUpGLibLogHandler() { | |
151 // Register GLib-handled assertions to go through our logging system. | |
152 const char* kLogDomains[] = { NULL, "Gtk", "Gdk", "GLib", "GLib-GObject" }; | |
153 for (size_t i = 0; i < arraysize(kLogDomains); i++) { | |
154 g_log_set_handler(kLogDomains[i], | |
155 static_cast<GLogLevelFlags>(G_LOG_FLAG_RECURSION | | |
156 G_LOG_FLAG_FATAL | | |
157 G_LOG_LEVEL_ERROR | | |
158 G_LOG_LEVEL_CRITICAL | | |
159 G_LOG_LEVEL_WARNING), | |
160 GLibLogHandler, | |
161 NULL); | |
162 } | |
163 } | |
164 #endif | |
165 | 48 |
166 } // namespace | 49 } // namespace |
167 | 50 |
168 namespace content { | 51 namespace content { |
169 | 52 |
170 BrowserMainParts::BrowserMainParts(const MainFunctionParams& parameters) | |
171 : parameters_(parameters), | |
172 parsed_command_line_(parameters.command_line_), | |
173 result_code_(content::RESULT_CODE_NORMAL_EXIT) { | |
174 #if defined(OS_WIN) | |
175 OleInitialize(NULL); | |
176 #endif | |
177 } | |
178 | |
179 BrowserMainParts::~BrowserMainParts() { | |
180 #if defined(OS_WIN) | |
181 OleUninitialize(); | |
182 #endif | |
183 } | |
184 | |
185 void BrowserMainParts::EarlyInitialization() { | |
186 PreEarlyInitialization(); | |
187 | |
188 #if defined(OS_WIN) | |
189 net::EnsureWinsockInit(); | |
190 #endif | |
191 | |
192 // Use NSS for SSL by default. | |
193 // The default client socket factory uses NSS for SSL by default on | |
194 // Windows and Mac. | |
195 #if defined(OS_WIN) || defined(OS_MACOSX) | |
196 if (parsed_command_line().HasSwitch(switches::kUseSystemSSL)) { | |
197 net::ClientSocketFactory::UseSystemSSL(); | |
198 } else { | |
199 #elif defined(USE_NSS) | |
200 if (true) { | |
201 #else | |
202 if (false) { | |
203 #endif | |
204 // We want to be sure to init NSPR on the main thread. | |
205 crypto::EnsureNSPRInit(); | |
206 } | |
207 | |
208 #if defined(OS_POSIX) && !defined(OS_MACOSX) | |
209 SetupSandbox(parsed_command_line()); | |
210 #endif | |
211 | |
212 if (parsed_command_line().HasSwitch(switches::kDisableSSLFalseStart)) | |
213 net::SSLConfigService::DisableFalseStart(); | |
214 if (parsed_command_line().HasSwitch(switches::kEnableSSLCachedInfo)) | |
215 net::SSLConfigService::EnableCachedInfo(); | |
216 if (parsed_command_line().HasSwitch(switches::kEnableOriginBoundCerts)) | |
217 net::SSLConfigService::EnableOriginBoundCerts(); | |
218 if (parsed_command_line().HasSwitch( | |
219 switches::kEnableDNSCertProvenanceChecking)) { | |
220 net::SSLConfigService::EnableDNSCertProvenanceChecking(); | |
221 } | |
222 | |
223 // TODO(abarth): Should this move to InitializeNetworkOptions? This doesn't | |
224 // seem dependent on SSL initialization(). | |
225 if (parsed_command_line().HasSwitch(switches::kEnableTcpFastOpen)) | |
226 net::set_tcp_fastopen_enabled(true); | |
227 | |
228 PostEarlyInitialization(); | |
229 } | |
230 | |
231 void BrowserMainParts::MainMessageLoopStart() { | |
232 PreMainMessageLoopStart(); | |
233 | |
234 #if defined(OS_WIN) | |
235 // If we're running tests (ui_task is non-null), then the ResourceBundle | |
236 // has already been initialized. | |
237 if (!parameters().ui_task) { | |
238 // Override the configured locale with the user's preferred UI language. | |
239 l10n_util::OverrideLocaleWithUILanguageList(); | |
240 } | |
241 #endif | |
242 | |
243 main_message_loop_.reset(new MessageLoop(MessageLoop::TYPE_UI)); | |
244 | |
245 InitializeMainThread(); | |
246 | |
247 system_monitor_.reset(new base::SystemMonitor); | |
248 hi_res_timer_manager_.reset(new HighResolutionTimerManager); | |
249 | |
250 network_change_notifier_.reset(net::NetworkChangeNotifier::Create()); | |
251 | |
252 PostMainMessageLoopStart(); | |
253 } | |
254 | |
255 static bool g_exited_main_message_loop = false; | |
256 | |
257 void BrowserMainParts::RunMainMessageLoopParts() { | |
258 PreMainMessageLoopRun(); | |
259 | |
260 TRACE_EVENT_BEGIN_ETW("BrowserMain:MESSAGE_LOOP", 0, ""); | |
261 // If the UI thread blocks, the whole UI is unresponsive. | |
262 // Do not allow disk IO from the UI thread. | |
263 base::ThreadRestrictions::SetIOAllowed(false); | |
264 MainMessageLoopRun(); | |
265 TRACE_EVENT_END_ETW("BrowserMain:MESSAGE_LOOP", 0, ""); | |
266 | |
267 g_exited_main_message_loop = true; | |
268 | |
269 PostMainMessageLoopRun(); | |
270 } | |
271 | |
272 void BrowserMainParts::InitializeMainThread() { | |
273 const char* kThreadName = "CrBrowserMain"; | |
274 base::PlatformThread::SetName(kThreadName); | |
275 main_message_loop().set_thread_name(kThreadName); | |
276 | |
277 #if defined(TRACK_ALL_TASK_OBJECTS) | |
278 tracked_objects::ThreadData::InitializeThreadContext(kThreadName); | |
279 #endif // TRACK_ALL_TASK_OBJECTS | |
280 | |
281 // Register the main thread by instantiating it, but don't call any methods. | |
282 main_thread_.reset(new BrowserThread(BrowserThread::UI, | |
283 MessageLoop::current())); | |
284 } | |
285 | |
286 void BrowserMainParts::InitializeToolkit() { | |
287 // TODO(evan): this function is rather subtle, due to the variety | |
288 // of intersecting ifdefs we have. To keep it easy to follow, there | |
289 // are no #else branches on any #ifs. | |
290 | |
291 #if defined(OS_LINUX) | |
292 // We want to call g_thread_init(), but in some codepaths (tests) it | |
293 // is possible it has already been called. In older versions of | |
294 // GTK, it is an error to call g_thread_init twice; unfortunately, | |
295 // the API to tell whether it has been called already was also only | |
296 // added in a newer version of GTK! Thankfully, this non-intuitive | |
297 // check is actually equivalent and sufficient to work around the | |
298 // error. | |
299 if (!g_thread_supported()) | |
300 g_thread_init(NULL); | |
301 // Glib type system initialization. Needed at least for gconf, | |
302 // used in net/proxy/proxy_config_service_linux.cc. Most likely | |
303 // this is superfluous as gtk_init() ought to do this. It's | |
304 // definitely harmless, so retained as a reminder of this | |
305 // requirement for gconf. | |
306 g_type_init(); | |
307 #if defined(OS_CHROMEOS) | |
308 // ChromeOS still uses dbus-glib, so initialize its threading here. | |
309 // TODO(satorux, stevenjb): remove this once it is no longer needed. | |
310 dbus_g_thread_init(); | |
311 #endif | |
312 #if !defined(USE_AURA) | |
313 gfx::GtkInitFromCommandLine(parameters().command_line_); | |
314 #endif | |
315 SetUpGLibLogHandler(); | |
316 #endif | |
317 | |
318 #if defined(TOOLKIT_GTK) | |
319 // It is important for this to happen before the first run dialog, as it | |
320 // styles the dialog as well. | |
321 gfx::InitRCStyles(); | |
322 #endif | |
323 | |
324 #if defined(OS_WIN) | |
325 // Init common control sex. | |
326 INITCOMMONCONTROLSEX config; | |
327 config.dwSize = sizeof(config); | |
328 config.dwICC = ICC_WIN95_CLASSES; | |
329 if (!InitCommonControlsEx(&config)) | |
330 LOG_GETLASTERROR(FATAL); | |
331 #endif | |
332 | |
333 ToolkitInitialized(); | |
334 } | |
335 | |
336 void BrowserMainParts::PreEarlyInitialization() { | |
337 } | |
338 | |
339 void BrowserMainParts::PostEarlyInitialization() { | |
340 } | |
341 | |
342 void BrowserMainParts::PreMainMessageLoopStart() { | |
343 } | |
344 | |
345 void BrowserMainParts::PostMainMessageLoopStart() { | |
346 } | |
347 | |
348 void BrowserMainParts::PreMainMessageLoopRun() { | |
349 } | |
350 | |
351 void BrowserMainParts::MainMessageLoopRun() { | |
352 if (parameters().ui_task) | |
353 MessageLoopForUI::current()->PostTask(FROM_HERE, parameters().ui_task); | |
354 | |
355 #if defined(OS_MACOSX) | |
356 MessageLoopForUI::current()->Run(); | |
357 #else | |
358 MessageLoopForUI::current()->RunWithDispatcher(NULL); | |
359 #endif | |
360 } | |
361 | |
362 void BrowserMainParts::PostMainMessageLoopRun() { | |
363 } | |
364 | |
365 void BrowserMainParts::ToolkitInitialized() { | |
366 } | |
367 | |
368 bool ExitedMainMessageLoop() { | 53 bool ExitedMainMessageLoop() { |
369 return g_exited_main_message_loop; | 54 return g_exited_main_message_loop; |
370 } | 55 } |
371 | 56 |
372 } // namespace content | 57 } // namespace content |
373 | 58 |
374 // Main routine for running as the Browser process. | 59 // Main routine for running as the Browser process. |
375 int BrowserMain(const MainFunctionParams& parameters) { | 60 int BrowserMain(const MainFunctionParams& parameters) { |
376 TRACE_EVENT_BEGIN_ETW("BrowserMain", 0, ""); | 61 TRACE_EVENT_BEGIN_ETW("BrowserMain", 0, ""); |
377 | 62 |
378 NotificationServiceImpl main_notification_service; | 63 NotificationServiceImpl main_notification_service; |
379 | 64 |
380 scoped_ptr<content::BrowserMainParts> parts( | 65 scoped_ptr<content::BrowserMainLoop> main_loop( |
381 content::GetContentClient()->browser()->CreateBrowserMainParts( | 66 new content::BrowserMainLoop(parameters)); |
382 parameters)); | |
383 if (!parts.get()) | |
384 parts.reset(new content::BrowserMainParts(parameters)); | |
385 | 67 |
386 parts->EarlyInitialization(); | 68 main_loop->Init(); |
| 69 |
| 70 main_loop->EarlyInitialization(); |
387 | 71 |
388 // Must happen before we try to use a message loop or display any UI. | 72 // Must happen before we try to use a message loop or display any UI. |
389 parts->InitializeToolkit(); | 73 main_loop->InitializeToolkit(); |
390 | 74 |
391 parts->MainMessageLoopStart(); | 75 main_loop->MainMessageLoopStart(); |
392 | 76 |
393 // WARNING: If we get a WM_ENDSESSION, objects created on the stack here | 77 // WARNING: If we get a WM_ENDSESSION, objects created on the stack here |
394 // are NOT deleted. If you need something to run during WM_ENDSESSION add it | 78 // are NOT deleted. If you need something to run during WM_ENDSESSION add it |
395 // to browser_shutdown::Shutdown or BrowserProcess::EndSession. | 79 // to browser_shutdown::Shutdown or BrowserProcess::EndSession. |
396 | 80 |
397 // !!!!!!!!!! READ ME !!!!!!!!!! | 81 // !!!!!!!!!! READ ME !!!!!!!!!! |
398 // I (viettrungluu) am in the process of refactoring |BrowserMain()|. If you | 82 // I (viettrungluu) am in the process of refactoring |BrowserMain()|. If you |
399 // need to add something above this comment, read the documentation in | 83 // need to add something above this comment, read the documentation in |
400 // browser_main.h. If you need to add something below, please do the | 84 // browser_main.h. If you need to add something below, please do the |
401 // following: | 85 // following: |
(...skipping 25 matching lines...) Expand all Loading... |
427 // initialize the sandbox broker, which requires the process to swap its | 111 // initialize the sandbox broker, which requires the process to swap its |
428 // window station. During this time all the UI will be broken. This has to | 112 // window station. During this time all the UI will be broken. This has to |
429 // run before threads and windows are created. | 113 // run before threads and windows are created. |
430 InitializeBrokerServices(parameters, parameters.command_line_); | 114 InitializeBrokerServices(parameters, parameters.command_line_); |
431 | 115 |
432 base::win::ScopedCOMInitializer com_initializer; | 116 base::win::ScopedCOMInitializer com_initializer; |
433 #endif // OS_WIN | 117 #endif // OS_WIN |
434 | 118 |
435 base::StatisticsRecorder statistics; | 119 base::StatisticsRecorder statistics; |
436 | 120 |
437 parts->RunMainMessageLoopParts(); | 121 main_loop->RunMainMessageLoopParts(&g_exited_main_message_loop); |
438 | 122 |
439 TRACE_EVENT_END_ETW("BrowserMain", 0, 0); | 123 TRACE_EVENT_END_ETW("BrowserMain", 0, 0); |
440 return parts->result_code(); | 124 |
| 125 return main_loop->GetResultCode(); |
441 } | 126 } |
OLD | NEW |