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"
11 #include <sys/resource.h>
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
;
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;
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
));
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
{
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
;
113 virtual ~ExitHandler();
115 // Does the appropriate call to Exit.
118 content::NotificationRegistrar registrar_
;
120 DISALLOW_COPY_AND_ASSIGN(ExitHandler
);
124 void ExitHandler::ExitWhenPossibleOnUIThread() {
125 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
126 if (SessionRestore::IsRestoringSynchronously()) {
127 // ExitHandler takes care of deleting itself.
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
));
147 ExitHandler::ExitHandler() {
149 this, chrome::NOTIFICATION_SESSION_RESTORE_DONE
,
150 content::NotificationService::AllBrowserContextsAndSources());
153 ExitHandler::~ExitHandler() {
157 void ExitHandler::Exit() {
158 #if defined(OS_CHROMEOS)
159 // On ChromeOS, exiting on signal should be always clean.
160 chrome::ExitCleanly();
162 chrome::AttemptExit();
166 class ShutdownDetector
: public base::PlatformThread::Delegate
{
168 explicit ShutdownDetector(int shutdown_fd
);
170 virtual void ThreadMain() OVERRIDE
;
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.
191 NOINLINE
void ShutdownFDClosedError() {
192 // Ensure function isn't optimized away.
197 NOINLINE
void ExitPosted() {
198 // Ensure function isn't optimized away.
203 void ShutdownDetector::ThreadMain() {
204 base::PlatformThread::SetName("CrShutdownDetector");
207 size_t bytes_read
= 0;
212 reinterpret_cast<char*>(&signal
) + bytes_read
,
213 sizeof(signal
) - bytes_read
));
215 NOTREACHED() << "Unexpected error: " << strerror(errno
);
216 ShutdownFDReadError();
218 } else if (ret
== 0) {
219 NOTREACHED() << "Unexpected closure of shutdown pipe.";
220 ShutdownFDClosedError();
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
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));
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";
265 PLOG(INFO
) << "Failed to get file descriptor limit";
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
);
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.
303 SetFileDescriptorLimit(fd_limit
);
306 void ChromeBrowserMainPartsPosix::PostMainMessageLoopStart() {
307 ChromeBrowserMainParts::PostMainMessageLoopStart();
310 int ret
= pipe(pipefd
);
312 PLOG(DFATAL
) << "Failed to create pipe";
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;
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;
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
);
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.
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
377 #error "Need MessageBox implementation."