Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / chrome_browser_main_posix.cc
blob9bdacc7eedf10c5ef232bcee4fcb24bacd8d4252
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.
5 #include "chrome/browser/chrome_browser_main_posix.h"
7 #include <errno.h>
8 #include <limits.h>
9 #include <pthread.h>
10 #include <signal.h>
11 #include <sys/resource.h>
12 #include <unistd.h>
14 #include <string>
16 #include "base/bind.h"
17 #include "base/command_line.h"
18 #include "base/logging.h"
19 #include "base/posix/eintr_wrapper.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/lifetime/application_lifetime.h"
23 #include "chrome/browser/sessions/session_restore.h"
24 #include "chrome/common/chrome_switches.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/notification_observer.h"
27 #include "content/public/browser/notification_registrar.h"
28 #include "content/public/browser/notification_service.h"
30 #if defined(TOOLKIT_GTK)
31 #include "chrome/browser/ui/gtk/chrome_browser_main_extra_parts_gtk.h"
33 #if defined(ENABLE_PRINTING)
34 #include "chrome/browser/printing/print_dialog_gtk.h"
35 #include "chrome/browser/printing/printing_gtk_util.h"
36 #endif // defined(ENABLE_PRINTING)
37 #endif // defined(TOOLKIT_GTK)
39 using content::BrowserThread;
41 namespace {
43 // See comment in |PreEarlyInitialization()|, where sigaction is called.
44 void SIGCHLDHandler(int signal) {
47 // The OSX fork() implementation can crash in the child process before
48 // fork() returns. In that case, the shutdown pipe will still be
49 // shared with the parent process. To prevent child crashes from
50 // causing parent shutdowns, |g_pipe_pid| is the pid for the process
51 // which registered |g_shutdown_pipe_write_fd|.
52 // See <http://crbug.com/175341>.
53 pid_t g_pipe_pid = -1;
54 int g_shutdown_pipe_write_fd = -1;
55 int g_shutdown_pipe_read_fd = -1;
57 // Common code between SIG{HUP, INT, TERM}Handler.
58 void GracefulShutdownHandler(int signal) {
59 // Reinstall the default handler. We had one shot at graceful shutdown.
60 struct sigaction action;
61 memset(&action, 0, sizeof(action));
62 action.sa_handler = SIG_DFL;
63 RAW_CHECK(sigaction(signal, &action, NULL) == 0);
65 RAW_CHECK(g_pipe_pid == getpid());
66 RAW_CHECK(g_shutdown_pipe_write_fd != -1);
67 RAW_CHECK(g_shutdown_pipe_read_fd != -1);
68 size_t bytes_written = 0;
69 do {
70 int rv = HANDLE_EINTR(
71 write(g_shutdown_pipe_write_fd,
72 reinterpret_cast<const char*>(&signal) + bytes_written,
73 sizeof(signal) - bytes_written));
74 RAW_CHECK(rv >= 0);
75 bytes_written += rv;
76 } while (bytes_written < sizeof(signal));
79 // See comment in |PostMainMessageLoopStart()|, where sigaction is called.
80 void SIGHUPHandler(int signal) {
81 RAW_CHECK(signal == SIGHUP);
82 GracefulShutdownHandler(signal);
85 // See comment in |PostMainMessageLoopStart()|, where sigaction is called.
86 void SIGINTHandler(int signal) {
87 RAW_CHECK(signal == SIGINT);
88 GracefulShutdownHandler(signal);
91 // See comment in |PostMainMessageLoopStart()|, where sigaction is called.
92 void SIGTERMHandler(int signal) {
93 RAW_CHECK(signal == SIGTERM);
94 GracefulShutdownHandler(signal);
97 // ExitHandler takes care of servicing an exit (from a signal) at the
98 // appropriate time. Specifically if we get an exit and have not finished
99 // session restore we delay the exit. To do otherwise means we're exiting part
100 // way through startup which causes all sorts of problems.
101 class ExitHandler : public content::NotificationObserver {
102 public:
103 // Invokes exit when appropriate.
104 static void ExitWhenPossibleOnUIThread();
106 // Overridden from content::NotificationObserver:
107 virtual void Observe(int type,
108 const content::NotificationSource& source,
109 const content::NotificationDetails& details) OVERRIDE;
111 private:
112 ExitHandler();
113 virtual ~ExitHandler();
115 // Does the appropriate call to Exit.
116 static void Exit();
118 content::NotificationRegistrar registrar_;
120 DISALLOW_COPY_AND_ASSIGN(ExitHandler);
123 // static
124 void ExitHandler::ExitWhenPossibleOnUIThread() {
125 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
126 if (SessionRestore::IsRestoringSynchronously()) {
127 // ExitHandler takes care of deleting itself.
128 new ExitHandler();
129 } else {
130 Exit();
134 void ExitHandler::Observe(int type,
135 const content::NotificationSource& source,
136 const content::NotificationDetails& details) {
137 if (!SessionRestore::IsRestoringSynchronously()) {
138 // At this point the message loop may not be running (meaning we haven't
139 // gotten through browser startup, but are close). Post the task to at which
140 // point the message loop is running.
141 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
142 base::Bind(&ExitHandler::Exit));
143 delete this;
147 ExitHandler::ExitHandler() {
148 registrar_.Add(
149 this, chrome::NOTIFICATION_SESSION_RESTORE_DONE,
150 content::NotificationService::AllBrowserContextsAndSources());
153 ExitHandler::~ExitHandler() {
156 // static
157 void ExitHandler::Exit() {
158 #if defined(OS_CHROMEOS)
159 // On ChromeOS, exiting on signal should be always clean.
160 chrome::ExitCleanly();
161 #else
162 chrome::AttemptExit();
163 #endif
166 class ShutdownDetector : public base::PlatformThread::Delegate {
167 public:
168 explicit ShutdownDetector(int shutdown_fd);
170 virtual void ThreadMain() OVERRIDE;
172 private:
173 const int shutdown_fd_;
175 DISALLOW_COPY_AND_ASSIGN(ShutdownDetector);
178 ShutdownDetector::ShutdownDetector(int shutdown_fd)
179 : shutdown_fd_(shutdown_fd) {
180 CHECK_NE(shutdown_fd_, -1);
183 // These functions are used to help us diagnose crash dumps that happen
184 // during the shutdown process.
185 NOINLINE void ShutdownFDReadError() {
186 // Ensure function isn't optimized away.
187 asm("");
188 sleep(UINT_MAX);
191 NOINLINE void ShutdownFDClosedError() {
192 // Ensure function isn't optimized away.
193 asm("");
194 sleep(UINT_MAX);
197 NOINLINE void ExitPosted() {
198 // Ensure function isn't optimized away.
199 asm("");
200 sleep(UINT_MAX);
203 void ShutdownDetector::ThreadMain() {
204 base::PlatformThread::SetName("CrShutdownDetector");
206 int signal;
207 size_t bytes_read = 0;
208 ssize_t ret;
209 do {
210 ret = HANDLE_EINTR(
211 read(shutdown_fd_,
212 reinterpret_cast<char*>(&signal) + bytes_read,
213 sizeof(signal) - bytes_read));
214 if (ret < 0) {
215 NOTREACHED() << "Unexpected error: " << strerror(errno);
216 ShutdownFDReadError();
217 break;
218 } else if (ret == 0) {
219 NOTREACHED() << "Unexpected closure of shutdown pipe.";
220 ShutdownFDClosedError();
221 break;
223 bytes_read += ret;
224 } while (bytes_read < sizeof(signal));
225 VLOG(1) << "Handling shutdown for signal " << signal << ".";
226 base::Closure task = base::Bind(&ExitHandler::ExitWhenPossibleOnUIThread);
228 if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task)) {
229 // Without a UI thread to post the exit task to, there aren't many
230 // options. Raise the signal again. The default handler will pick it up
231 // and cause an ungraceful exit.
232 RAW_LOG(WARNING, "No UI thread, exiting ungracefully.");
233 kill(getpid(), signal);
235 // The signal may be handled on another thread. Give that a chance to
236 // happen.
237 sleep(3);
239 // We really should be dead by now. For whatever reason, we're not. Exit
240 // immediately, with the exit status set to the signal number with bit 8
241 // set. On the systems that we care about, this exit status is what is
242 // normally used to indicate an exit by this signal's default handler.
243 // This mechanism isn't a de jure standard, but even in the worst case, it
244 // should at least result in an immediate exit.
245 RAW_LOG(WARNING, "Still here, exiting really ungracefully.");
246 _exit(signal | (1 << 7));
248 ExitPosted();
251 // Sets the file descriptor soft limit to |max_descriptors| or the OS hard
252 // limit, whichever is lower.
253 void SetFileDescriptorLimit(unsigned int max_descriptors) {
254 struct rlimit limits;
255 if (getrlimit(RLIMIT_NOFILE, &limits) == 0) {
256 unsigned int new_limit = max_descriptors;
257 if (limits.rlim_max > 0 && limits.rlim_max < max_descriptors) {
258 new_limit = limits.rlim_max;
260 limits.rlim_cur = new_limit;
261 if (setrlimit(RLIMIT_NOFILE, &limits) != 0) {
262 PLOG(INFO) << "Failed to set file descriptor limit";
264 } else {
265 PLOG(INFO) << "Failed to get file descriptor limit";
269 } // namespace
271 // ChromeBrowserMainPartsPosix -------------------------------------------------
273 ChromeBrowserMainPartsPosix::ChromeBrowserMainPartsPosix(
274 const content::MainFunctionParams& parameters)
275 : ChromeBrowserMainParts(parameters) {
278 void ChromeBrowserMainPartsPosix::PreEarlyInitialization() {
279 ChromeBrowserMainParts::PreEarlyInitialization();
281 // We need to accept SIGCHLD, even though our handler is a no-op because
282 // otherwise we cannot wait on children. (According to POSIX 2001.)
283 struct sigaction action;
284 memset(&action, 0, sizeof(action));
285 action.sa_handler = SIGCHLDHandler;
286 CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
288 const std::string fd_limit_string =
289 parsed_command_line().GetSwitchValueASCII(
290 switches::kFileDescriptorLimit);
291 int fd_limit = 0;
292 if (!fd_limit_string.empty()) {
293 base::StringToInt(fd_limit_string, &fd_limit);
295 #if defined(OS_MACOSX)
296 // We use quite a few file descriptors for our IPC, and the default limit on
297 // the Mac is low (256), so bump it up if there is no explicit override.
298 if (fd_limit == 0) {
299 fd_limit = 1024;
301 #endif // OS_MACOSX
302 if (fd_limit > 0)
303 SetFileDescriptorLimit(fd_limit);
306 void ChromeBrowserMainPartsPosix::PostMainMessageLoopStart() {
307 ChromeBrowserMainParts::PostMainMessageLoopStart();
309 int pipefd[2];
310 int ret = pipe(pipefd);
311 if (ret < 0) {
312 PLOG(DFATAL) << "Failed to create pipe";
313 } else {
314 g_pipe_pid = getpid();
315 g_shutdown_pipe_read_fd = pipefd[0];
316 g_shutdown_pipe_write_fd = pipefd[1];
317 #if !defined(ADDRESS_SANITIZER) && !defined(KEEP_SHADOW_STACKS)
318 const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 2;
319 #else
320 // ASan instrumentation and -finstrument-functions (used for keeping the
321 // shadow stacks) bloat the stack frames, so we need to increase the stack
322 // size to avoid hitting the guard page.
323 const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 4;
324 #endif
325 // TODO(viettrungluu,willchan): crbug.com/29675 - This currently leaks, so
326 // if you change this, you'll probably need to change the suppression.
327 if (!base::PlatformThread::CreateNonJoinable(
328 kShutdownDetectorThreadStackSize,
329 new ShutdownDetector(g_shutdown_pipe_read_fd))) {
330 LOG(DFATAL) << "Failed to create shutdown detector task.";
333 // Setup signal handlers for shutdown AFTER shutdown pipe is setup because
334 // it may be called right away after handler is set.
336 // If adding to this list of signal handlers, note the new signal probably
337 // needs to be reset in child processes. See
338 // base/process_util_posix.cc:LaunchProcess.
340 // We need to handle SIGTERM, because that is how many POSIX-based distros ask
341 // processes to quit gracefully at shutdown time.
342 struct sigaction action;
343 memset(&action, 0, sizeof(action));
344 action.sa_handler = SIGTERMHandler;
345 CHECK(sigaction(SIGTERM, &action, NULL) == 0);
346 // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If
347 // the browser process is being debugged, GDB will catch the SIGINT first.
348 action.sa_handler = SIGINTHandler;
349 CHECK(sigaction(SIGINT, &action, NULL) == 0);
350 // And SIGHUP, for when the terminal disappears. On shutdown, many Linux
351 // distros send SIGHUP, SIGTERM, and then SIGKILL.
352 action.sa_handler = SIGHUPHandler;
353 CHECK(sigaction(SIGHUP, &action, NULL) == 0);
355 #if defined(TOOLKIT_GTK) && defined(ENABLE_PRINTING)
356 printing::PrintingContextLinux::SetCreatePrintDialogFunction(
357 &PrintDialogGtk::CreatePrintDialog);
358 printing::PrintingContextLinux::SetPdfPaperSizeFunction(
359 &GetPdfPaperSizeDeviceUnitsGtk);
360 #endif
363 void ChromeBrowserMainPartsPosix::ShowMissingLocaleMessageBox() {
364 #if defined(OS_CHROMEOS)
365 NOTREACHED(); // Should not ever happen on ChromeOS.
366 #elif defined(OS_MACOSX)
367 // Not called on Mac because we load the locale files differently.
368 NOTREACHED();
369 #elif defined(TOOLKIT_GTK)
370 ChromeBrowserMainExtraPartsGtk::ShowMessageBox(
371 chrome_browser::kMissingLocaleDataMessage);
372 #elif defined(USE_AURA)
373 // TODO(port): We may want a views based message dialog here eventually, but
374 // for now, crash.
375 NOTREACHED();
376 #else
377 #error "Need MessageBox implementation."
378 #endif