blob: e73e492346b2717372c9adc14fe4d7cada27825a [file] [log] [blame]
[email protected]7cb6beb82012-02-15 23:13:071// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]f8abf722010-07-07 19:46:242// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]e6b5bc22011-09-08 22:01:565#include "chrome/browser/chrome_browser_main_posix.h"
[email protected]1fec64352010-07-27 13:55:216
[email protected]f8abf722010-07-07 19:46:247#include <errno.h>
[email protected]50795a02011-05-09 20:11:018#include <limits.h>
[email protected]7cb6beb82012-02-15 23:13:079#include <pthread.h>
[email protected]f8abf722010-07-07 19:46:2410#include <signal.h>
11#include <sys/resource.h>
[email protected]50795a02011-05-09 20:11:0112#include <unistd.h>
[email protected]f8abf722010-07-07 19:46:2413
[email protected]5cc4c422011-02-19 00:09:2214#include <string>
15
[email protected]97f3ac632011-10-19 20:09:5616#include "base/bind.h"
[email protected]f8abf722010-07-07 19:46:2417#include "base/command_line.h"
[email protected]f8abf722010-07-07 19:46:2418#include "base/logging.h"
[email protected]2025d002012-11-14 20:54:3519#include "base/posix/eintr_wrapper.h"
[email protected]3ea1b182013-02-08 22:38:4120#include "base/strings/string_number_conversions.h"
[email protected]fdf40f3e2013-07-11 23:55:4621#include "chrome/browser/chrome_notification_types.h"
[email protected]2e6389f2012-05-18 19:41:2522#include "chrome/browser/lifetime/application_lifetime.h"
[email protected]7e6f9f72013-02-06 19:59:3723#include "chrome/browser/sessions/session_restore.h"
[email protected]f8abf722010-07-07 19:46:2424#include "chrome/common/chrome_switches.h"
[email protected]c38831a12011-10-28 12:44:4925#include "content/public/browser/browser_thread.h"
[email protected]7e6f9f72013-02-06 19:59:3726#include "content/public/browser/notification_observer.h"
27#include "content/public/browser/notification_registrar.h"
28#include "content/public/browser/notification_service.h"
[email protected]f8abf722010-07-07 19:46:2429
[email protected]a13283cc2012-04-05 00:21:2230#if defined(TOOLKIT_GTK)
[email protected]3ea1b182013-02-08 22:38:4131#include "chrome/browser/ui/gtk/chrome_browser_main_extra_parts_gtk.h"
[email protected]1e54c1c2013-08-12 17:16:0532
33#if defined(ENABLE_PRINTING)
34#include "chrome/browser/printing/print_dialog_gtk.h"
35#endif // defined(ENABLE_PRINTING)
36#endif // defined(TOOLKIT_GTK)
[email protected]5cc4c422011-02-19 00:09:2237
[email protected]631bb742011-11-02 11:29:3938using content::BrowserThread;
39
[email protected]f8abf722010-07-07 19:46:2440namespace {
41
42// See comment in |PreEarlyInitialization()|, where sigaction is called.
43void SIGCHLDHandler(int signal) {
44}
45
[email protected]c2f5a832013-02-27 00:53:0146// The OSX fork() implementation can crash in the child process before
47// fork() returns. In that case, the shutdown pipe will still be
48// shared with the parent process. To prevent child crashes from
49// causing parent shutdowns, |g_pipe_pid| is the pid for the process
50// which registered |g_shutdown_pipe_write_fd|.
51// See <http://crbug.com/175341>.
52pid_t g_pipe_pid = -1;
[email protected]f8abf722010-07-07 19:46:2453int g_shutdown_pipe_write_fd = -1;
54int g_shutdown_pipe_read_fd = -1;
55
56// Common code between SIG{HUP, INT, TERM}Handler.
57void GracefulShutdownHandler(int signal) {
58 // Reinstall the default handler. We had one shot at graceful shutdown.
59 struct sigaction action;
60 memset(&action, 0, sizeof(action));
61 action.sa_handler = SIG_DFL;
62 RAW_CHECK(sigaction(signal, &action, NULL) == 0);
63
[email protected]c2f5a832013-02-27 00:53:0164 RAW_CHECK(g_pipe_pid == getpid());
[email protected]f8abf722010-07-07 19:46:2465 RAW_CHECK(g_shutdown_pipe_write_fd != -1);
66 RAW_CHECK(g_shutdown_pipe_read_fd != -1);
67 size_t bytes_written = 0;
68 do {
69 int rv = HANDLE_EINTR(
70 write(g_shutdown_pipe_write_fd,
71 reinterpret_cast<const char*>(&signal) + bytes_written,
72 sizeof(signal) - bytes_written));
73 RAW_CHECK(rv >= 0);
74 bytes_written += rv;
75 } while (bytes_written < sizeof(signal));
[email protected]f8abf722010-07-07 19:46:2476}
77
[email protected]a1c2f8f2011-09-12 19:33:3178// See comment in |PostMainMessageLoopStart()|, where sigaction is called.
[email protected]f8abf722010-07-07 19:46:2479void SIGHUPHandler(int signal) {
80 RAW_CHECK(signal == SIGHUP);
[email protected]f8abf722010-07-07 19:46:2481 GracefulShutdownHandler(signal);
82}
83
[email protected]a1c2f8f2011-09-12 19:33:3184// See comment in |PostMainMessageLoopStart()|, where sigaction is called.
[email protected]f8abf722010-07-07 19:46:2485void SIGINTHandler(int signal) {
86 RAW_CHECK(signal == SIGINT);
[email protected]f8abf722010-07-07 19:46:2487 GracefulShutdownHandler(signal);
88}
89
[email protected]a1c2f8f2011-09-12 19:33:3190// See comment in |PostMainMessageLoopStart()|, where sigaction is called.
[email protected]f8abf722010-07-07 19:46:2491void SIGTERMHandler(int signal) {
92 RAW_CHECK(signal == SIGTERM);
[email protected]f8abf722010-07-07 19:46:2493 GracefulShutdownHandler(signal);
94}
95
[email protected]7e6f9f72013-02-06 19:59:3796// ExitHandler takes care of servicing an exit (from a signal) at the
97// appropriate time. Specifically if we get an exit and have not finished
98// session restore we delay the exit. To do otherwise means we're exiting part
99// way through startup which causes all sorts of problems.
100class ExitHandler : public content::NotificationObserver {
101 public:
102 // Invokes exit when appropriate.
103 static void ExitWhenPossibleOnUIThread();
104
105 // Overridden from content::NotificationObserver:
106 virtual void Observe(int type,
107 const content::NotificationSource& source,
108 const content::NotificationDetails& details) OVERRIDE;
109
110 private:
111 ExitHandler();
112 virtual ~ExitHandler();
113
114 // Does the appropriate call to Exit.
115 static void Exit();
116
117 content::NotificationRegistrar registrar_;
118
119 DISALLOW_COPY_AND_ASSIGN(ExitHandler);
120};
121
122// static
123void ExitHandler::ExitWhenPossibleOnUIThread() {
124 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
125 if (SessionRestore::IsRestoringSynchronously()) {
126 // ExitHandler takes care of deleting itself.
127 new ExitHandler();
128 } else {
129 Exit();
130 }
131}
132
133void ExitHandler::Observe(int type,
134 const content::NotificationSource& source,
135 const content::NotificationDetails& details) {
136 if (!SessionRestore::IsRestoringSynchronously()) {
137 // At this point the message loop may not be running (meaning we haven't
138 // gotten through browser startup, but are close). Post the task to at which
139 // point the message loop is running.
140 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
141 base::Bind(&ExitHandler::Exit));
142 delete this;
143 }
144}
145
146ExitHandler::ExitHandler() {
147 registrar_.Add(
148 this, chrome::NOTIFICATION_SESSION_RESTORE_DONE,
149 content::NotificationService::AllBrowserContextsAndSources());
150}
151
152ExitHandler::~ExitHandler() {
153}
154
155// static
156void ExitHandler::Exit() {
157#if defined(OS_CHROMEOS)
158 // On ChromeOS, exiting on signal should be always clean.
[email protected]0c98ab652013-02-18 00:39:37159 chrome::ExitCleanly();
[email protected]7e6f9f72013-02-06 19:59:37160#else
[email protected]0c98ab652013-02-18 00:39:37161 chrome::AttemptExit();
[email protected]7e6f9f72013-02-06 19:59:37162#endif
163}
164
[email protected]ce072a72010-12-31 20:02:16165class ShutdownDetector : public base::PlatformThread::Delegate {
[email protected]f8abf722010-07-07 19:46:24166 public:
167 explicit ShutdownDetector(int shutdown_fd);
168
[email protected]b94584a2013-02-07 03:02:08169 virtual void ThreadMain() OVERRIDE;
[email protected]f8abf722010-07-07 19:46:24170
171 private:
172 const int shutdown_fd_;
173
174 DISALLOW_COPY_AND_ASSIGN(ShutdownDetector);
175};
176
177ShutdownDetector::ShutdownDetector(int shutdown_fd)
178 : shutdown_fd_(shutdown_fd) {
179 CHECK_NE(shutdown_fd_, -1);
180}
181
[email protected]50795a02011-05-09 20:11:01182// These functions are used to help us diagnose crash dumps that happen
183// during the shutdown process.
184NOINLINE void ShutdownFDReadError() {
185 // Ensure function isn't optimized away.
186 asm("");
187 sleep(UINT_MAX);
188}
189
190NOINLINE void ShutdownFDClosedError() {
191 // Ensure function isn't optimized away.
192 asm("");
193 sleep(UINT_MAX);
194}
195
[email protected]24213932011-10-25 18:29:33196NOINLINE void ExitPosted() {
[email protected]50795a02011-05-09 20:11:01197 // Ensure function isn't optimized away.
198 asm("");
199 sleep(UINT_MAX);
200}
201
[email protected]f8abf722010-07-07 19:46:24202void ShutdownDetector::ThreadMain() {
[email protected]ce072a72010-12-31 20:02:16203 base::PlatformThread::SetName("CrShutdownDetector");
[email protected]fa9bf4382010-07-23 19:40:05204
[email protected]f8abf722010-07-07 19:46:24205 int signal;
206 size_t bytes_read = 0;
207 ssize_t ret;
208 do {
209 ret = HANDLE_EINTR(
210 read(shutdown_fd_,
211 reinterpret_cast<char*>(&signal) + bytes_read,
212 sizeof(signal) - bytes_read));
213 if (ret < 0) {
214 NOTREACHED() << "Unexpected error: " << strerror(errno);
[email protected]50795a02011-05-09 20:11:01215 ShutdownFDReadError();
[email protected]f8abf722010-07-07 19:46:24216 break;
217 } else if (ret == 0) {
218 NOTREACHED() << "Unexpected closure of shutdown pipe.";
[email protected]50795a02011-05-09 20:11:01219 ShutdownFDClosedError();
[email protected]f8abf722010-07-07 19:46:24220 break;
221 }
222 bytes_read += ret;
223 } while (bytes_read < sizeof(signal));
[email protected]8e96e502010-10-21 20:57:12224 VLOG(1) << "Handling shutdown for signal " << signal << ".";
[email protected]7e6f9f72013-02-06 19:59:37225 base::Closure task = base::Bind(&ExitHandler::ExitWhenPossibleOnUIThread);
[email protected]f8abf722010-07-07 19:46:24226
[email protected]bc63a072011-06-28 21:12:57227 if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task)) {
[email protected]f8abf722010-07-07 19:46:24228 // Without a UI thread to post the exit task to, there aren't many
229 // options. Raise the signal again. The default handler will pick it up
230 // and cause an ungraceful exit.
231 RAW_LOG(WARNING, "No UI thread, exiting ungracefully.");
232 kill(getpid(), signal);
233
234 // The signal may be handled on another thread. Give that a chance to
235 // happen.
236 sleep(3);
237
238 // We really should be dead by now. For whatever reason, we're not. Exit
239 // immediately, with the exit status set to the signal number with bit 8
240 // set. On the systems that we care about, this exit status is what is
241 // normally used to indicate an exit by this signal's default handler.
242 // This mechanism isn't a de jure standard, but even in the worst case, it
243 // should at least result in an immediate exit.
244 RAW_LOG(WARNING, "Still here, exiting really ungracefully.");
245 _exit(signal | (1 << 7));
246 }
[email protected]24213932011-10-25 18:29:33247 ExitPosted();
[email protected]f8abf722010-07-07 19:46:24248}
249
250// Sets the file descriptor soft limit to |max_descriptors| or the OS hard
251// limit, whichever is lower.
252void SetFileDescriptorLimit(unsigned int max_descriptors) {
253 struct rlimit limits;
254 if (getrlimit(RLIMIT_NOFILE, &limits) == 0) {
255 unsigned int new_limit = max_descriptors;
256 if (limits.rlim_max > 0 && limits.rlim_max < max_descriptors) {
257 new_limit = limits.rlim_max;
258 }
259 limits.rlim_cur = new_limit;
260 if (setrlimit(RLIMIT_NOFILE, &limits) != 0) {
261 PLOG(INFO) << "Failed to set file descriptor limit";
262 }
263 } else {
264 PLOG(INFO) << "Failed to get file descriptor limit";
265 }
266}
267
268} // namespace
269
[email protected]e6b5bc22011-09-08 22:01:56270// ChromeBrowserMainPartsPosix -------------------------------------------------
[email protected]f8abf722010-07-07 19:46:24271
[email protected]e6b5bc22011-09-08 22:01:56272ChromeBrowserMainPartsPosix::ChromeBrowserMainPartsPosix(
[email protected]4573fbd2011-10-31 20:25:18273 const content::MainFunctionParams& parameters)
[email protected]f967b722011-09-07 00:58:04274 : ChromeBrowserMainParts(parameters) {
275}
276
[email protected]e6b5bc22011-09-08 22:01:56277void ChromeBrowserMainPartsPosix::PreEarlyInitialization() {
[email protected]c7480942011-11-08 19:18:27278 ChromeBrowserMainParts::PreEarlyInitialization();
279
[email protected]1fec64352010-07-27 13:55:21280 // We need to accept SIGCHLD, even though our handler is a no-op because
281 // otherwise we cannot wait on children. (According to POSIX 2001.)
282 struct sigaction action;
283 memset(&action, 0, sizeof(action));
284 action.sa_handler = SIGCHLDHandler;
285 CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
[email protected]f8abf722010-07-07 19:46:24286
[email protected]1fec64352010-07-27 13:55:21287 const std::string fd_limit_string =
288 parsed_command_line().GetSwitchValueASCII(
289 switches::kFileDescriptorLimit);
290 int fd_limit = 0;
291 if (!fd_limit_string.empty()) {
[email protected]e83326f2010-07-31 17:29:25292 base::StringToInt(fd_limit_string, &fd_limit);
[email protected]c1275ae2010-07-12 17:40:49293 }
[email protected]f8abf722010-07-07 19:46:24294#if defined(OS_MACOSX)
[email protected]1fec64352010-07-27 13:55:21295 // We use quite a few file descriptors for our IPC, and the default limit on
296 // the Mac is low (256), so bump it up if there is no explicit override.
297 if (fd_limit == 0) {
298 fd_limit = 1024;
[email protected]f8abf722010-07-07 19:46:24299 }
[email protected]1fec64352010-07-27 13:55:21300#endif // OS_MACOSX
301 if (fd_limit > 0)
302 SetFileDescriptorLimit(fd_limit);
303}
[email protected]f8abf722010-07-07 19:46:24304
[email protected]e6b5bc22011-09-08 22:01:56305void ChromeBrowserMainPartsPosix::PostMainMessageLoopStart() {
[email protected]c7480942011-11-08 19:18:27306 ChromeBrowserMainParts::PostMainMessageLoopStart();
307
[email protected]1fec64352010-07-27 13:55:21308 int pipefd[2];
309 int ret = pipe(pipefd);
310 if (ret < 0) {
311 PLOG(DFATAL) << "Failed to create pipe";
312 } else {
[email protected]c2f5a832013-02-27 00:53:01313 g_pipe_pid = getpid();
[email protected]1fec64352010-07-27 13:55:21314 g_shutdown_pipe_read_fd = pipefd[0];
315 g_shutdown_pipe_write_fd = pipefd[1];
[email protected]77e7d8c2013-01-25 15:40:28316#if !defined(ADDRESS_SANITIZER) && !defined(KEEP_SHADOW_STACKS)
[email protected]7cb6beb82012-02-15 23:13:07317 const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN;
[email protected]5a4a7ab2012-04-05 07:11:12318#else
[email protected]77e7d8c2013-01-25 15:40:28319 // ASan instrumentation and -finstrument-functions (used for keeping the
320 // shadow stacks) bloat the stack frames, so we need to increase the stack
[email protected]5a4a7ab2012-04-05 07:11:12321 // size to avoid hitting the guard page.
322 const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 4;
323#endif
[email protected]5e634162010-07-27 17:37:38324 // TODO(viettrungluu,willchan): crbug.com/29675 - This currently leaks, so
325 // if you change this, you'll probably need to change the suppression.
[email protected]ce072a72010-12-31 20:02:16326 if (!base::PlatformThread::CreateNonJoinable(
327 kShutdownDetectorThreadStackSize,
328 new ShutdownDetector(g_shutdown_pipe_read_fd))) {
[email protected]1fec64352010-07-27 13:55:21329 LOG(DFATAL) << "Failed to create shutdown detector task.";
330 }
331 }
[email protected]a1c2f8f2011-09-12 19:33:31332 // Setup signal handlers for shutdown AFTER shutdown pipe is setup because
333 // it may be called right away after handler is set.
334
335 // If adding to this list of signal handlers, note the new signal probably
336 // needs to be reset in child processes. See
337 // base/process_util_posix.cc:LaunchProcess.
338
339 // We need to handle SIGTERM, because that is how many POSIX-based distros ask
340 // processes to quit gracefully at shutdown time.
341 struct sigaction action;
342 memset(&action, 0, sizeof(action));
343 action.sa_handler = SIGTERMHandler;
344 CHECK(sigaction(SIGTERM, &action, NULL) == 0);
345 // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If
346 // the browser process is being debugged, GDB will catch the SIGINT first.
347 action.sa_handler = SIGINTHandler;
348 CHECK(sigaction(SIGINT, &action, NULL) == 0);
349 // And SIGHUP, for when the terminal disappears. On shutdown, many Linux
350 // distros send SIGHUP, SIGTERM, and then SIGKILL.
351 action.sa_handler = SIGHUPHandler;
352 CHECK(sigaction(SIGHUP, &action, NULL) == 0);
[email protected]5cc4c422011-02-19 00:09:22353
[email protected]1e54c1c2013-08-12 17:16:05354#if defined(TOOLKIT_GTK) && defined(ENABLE_PRINTING)
[email protected]ea5e81d92011-11-08 18:45:15355 printing::PrintingContextGtk::SetCreatePrintDialogFunction(
[email protected]eaa389e2011-04-11 04:58:20356 &PrintDialogGtk::CreatePrintDialog);
[email protected]1fd5302c2011-05-28 04:06:43357#endif
[email protected]1fec64352010-07-27 13:55:21358}
[email protected]81ce2c42012-03-24 01:43:26359
360void ChromeBrowserMainPartsPosix::ShowMissingLocaleMessageBox() {
361#if defined(OS_CHROMEOS)
362 NOTREACHED(); // Should not ever happen on ChromeOS.
[email protected]81ce2c42012-03-24 01:43:26363#elif defined(OS_MACOSX)
364 // Not called on Mac because we load the locale files differently.
365 NOTREACHED();
[email protected]a13283cc2012-04-05 00:21:22366#elif defined(TOOLKIT_GTK)
[email protected]81ce2c42012-03-24 01:43:26367 ChromeBrowserMainExtraPartsGtk::ShowMessageBox(
368 chrome_browser::kMissingLocaleDataMessage);
[email protected]95721f62012-03-29 03:24:37369#elif defined(USE_AURA)
370 // TODO(port): We may want a views based message dialog here eventually, but
371 // for now, crash.
372 NOTREACHED();
[email protected]81ce2c42012-03-24 01:43:26373#else
374#error "Need MessageBox implementation."
375#endif
376}