Home | History | Annotate | Download | only in browser
      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 "chrome/browser/chrome_browser_main_posix.h"
      6 
      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>
     13 
     14 #include <string>
     15 
     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"
     29 
     30 #if defined(TOOLKIT_GTK)
     31 #include "chrome/browser/ui/gtk/chrome_browser_main_extra_parts_gtk.h"
     32 
     33 #if defined(ENABLE_PRINTING)
     34 #include "chrome/browser/printing/print_dialog_gtk.h"
     35 #endif  // defined(ENABLE_PRINTING)
     36 #endif  // defined(TOOLKIT_GTK)
     37 
     38 using content::BrowserThread;
     39 
     40 namespace {
     41 
     42 // See comment in |PreEarlyInitialization()|, where sigaction is called.
     43 void SIGCHLDHandler(int signal) {
     44 }
     45 
     46 // 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>.
     52 pid_t g_pipe_pid = -1;
     53 int g_shutdown_pipe_write_fd = -1;
     54 int g_shutdown_pipe_read_fd = -1;
     55 
     56 // Common code between SIG{HUP, INT, TERM}Handler.
     57 void 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 
     64   RAW_CHECK(g_pipe_pid == getpid());
     65   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));
     76 }
     77 
     78 // See comment in |PostMainMessageLoopStart()|, where sigaction is called.
     79 void SIGHUPHandler(int signal) {
     80   RAW_CHECK(signal == SIGHUP);
     81   GracefulShutdownHandler(signal);
     82 }
     83 
     84 // See comment in |PostMainMessageLoopStart()|, where sigaction is called.
     85 void SIGINTHandler(int signal) {
     86   RAW_CHECK(signal == SIGINT);
     87   GracefulShutdownHandler(signal);
     88 }
     89 
     90 // See comment in |PostMainMessageLoopStart()|, where sigaction is called.
     91 void SIGTERMHandler(int signal) {
     92   RAW_CHECK(signal == SIGTERM);
     93   GracefulShutdownHandler(signal);
     94 }
     95 
     96 // 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.
    100 class 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
    123 void 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 
    133 void 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 
    146 ExitHandler::ExitHandler() {
    147   registrar_.Add(
    148       this, chrome::NOTIFICATION_SESSION_RESTORE_DONE,
    149       content::NotificationService::AllBrowserContextsAndSources());
    150 }
    151 
    152 ExitHandler::~ExitHandler() {
    153 }
    154 
    155 // static
    156 void ExitHandler::Exit() {
    157 #if defined(OS_CHROMEOS)
    158   // On ChromeOS, exiting on signal should be always clean.
    159   chrome::ExitCleanly();
    160 #else
    161   chrome::AttemptExit();
    162 #endif
    163 }
    164 
    165 class ShutdownDetector : public base::PlatformThread::Delegate {
    166  public:
    167   explicit ShutdownDetector(int shutdown_fd);
    168 
    169   virtual void ThreadMain() OVERRIDE;
    170 
    171  private:
    172   const int shutdown_fd_;
    173 
    174   DISALLOW_COPY_AND_ASSIGN(ShutdownDetector);
    175 };
    176 
    177 ShutdownDetector::ShutdownDetector(int shutdown_fd)
    178     : shutdown_fd_(shutdown_fd) {
    179   CHECK_NE(shutdown_fd_, -1);
    180 }
    181 
    182 // These functions are used to help us diagnose crash dumps that happen
    183 // during the shutdown process.
    184 NOINLINE void ShutdownFDReadError() {
    185   // Ensure function isn't optimized away.
    186   asm("");
    187   sleep(UINT_MAX);
    188 }
    189 
    190 NOINLINE void ShutdownFDClosedError() {
    191   // Ensure function isn't optimized away.
    192   asm("");
    193   sleep(UINT_MAX);
    194 }
    195 
    196 NOINLINE void ExitPosted() {
    197   // Ensure function isn't optimized away.
    198   asm("");
    199   sleep(UINT_MAX);
    200 }
    201 
    202 void ShutdownDetector::ThreadMain() {
    203   base::PlatformThread::SetName("CrShutdownDetector");
    204 
    205   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);
    215       ShutdownFDReadError();
    216       break;
    217     } else if (ret == 0) {
    218       NOTREACHED() << "Unexpected closure of shutdown pipe.";
    219       ShutdownFDClosedError();
    220       break;
    221     }
    222     bytes_read += ret;
    223   } while (bytes_read < sizeof(signal));
    224   VLOG(1) << "Handling shutdown for signal " << signal << ".";
    225   base::Closure task = base::Bind(&ExitHandler::ExitWhenPossibleOnUIThread);
    226 
    227   if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task)) {
    228     // 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   }
    247   ExitPosted();
    248 }
    249 
    250 // Sets the file descriptor soft limit to |max_descriptors| or the OS hard
    251 // limit, whichever is lower.
    252 void 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 
    270 // ChromeBrowserMainPartsPosix -------------------------------------------------
    271 
    272 ChromeBrowserMainPartsPosix::ChromeBrowserMainPartsPosix(
    273     const content::MainFunctionParams& parameters)
    274     : ChromeBrowserMainParts(parameters) {
    275 }
    276 
    277 void ChromeBrowserMainPartsPosix::PreEarlyInitialization() {
    278   ChromeBrowserMainParts::PreEarlyInitialization();
    279 
    280   // 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);
    286 
    287   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()) {
    292     base::StringToInt(fd_limit_string, &fd_limit);
    293   }
    294 #if defined(OS_MACOSX)
    295   // 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;
    299   }
    300 #endif  // OS_MACOSX
    301   if (fd_limit > 0)
    302     SetFileDescriptorLimit(fd_limit);
    303 }
    304 
    305 void ChromeBrowserMainPartsPosix::PostMainMessageLoopStart() {
    306   ChromeBrowserMainParts::PostMainMessageLoopStart();
    307 
    308   int pipefd[2];
    309   int ret = pipe(pipefd);
    310   if (ret < 0) {
    311     PLOG(DFATAL) << "Failed to create pipe";
    312   } else {
    313     g_pipe_pid = getpid();
    314     g_shutdown_pipe_read_fd = pipefd[0];
    315     g_shutdown_pipe_write_fd = pipefd[1];
    316 #if !defined(ADDRESS_SANITIZER) && !defined(KEEP_SHADOW_STACKS)
    317     const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN;
    318 #else
    319     // ASan instrumentation and -finstrument-functions (used for keeping the
    320     // shadow stacks) bloat the stack frames, so we need to increase the stack
    321     // size to avoid hitting the guard page.
    322     const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 4;
    323 #endif
    324     // TODO(viettrungluu,willchan): crbug.com/29675 - This currently leaks, so
    325     // if you change this, you'll probably need to change the suppression.
    326     if (!base::PlatformThread::CreateNonJoinable(
    327             kShutdownDetectorThreadStackSize,
    328             new ShutdownDetector(g_shutdown_pipe_read_fd))) {
    329       LOG(DFATAL) << "Failed to create shutdown detector task.";
    330     }
    331   }
    332   // 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);
    353 
    354 #if defined(TOOLKIT_GTK) && defined(ENABLE_PRINTING)
    355   printing::PrintingContextGtk::SetCreatePrintDialogFunction(
    356       &PrintDialogGtk::CreatePrintDialog);
    357 #endif
    358 }
    359 
    360 void ChromeBrowserMainPartsPosix::ShowMissingLocaleMessageBox() {
    361 #if defined(OS_CHROMEOS)
    362   NOTREACHED();  // Should not ever happen on ChromeOS.
    363 #elif defined(OS_MACOSX)
    364   // Not called on Mac because we load the locale files differently.
    365   NOTREACHED();
    366 #elif defined(TOOLKIT_GTK)
    367   ChromeBrowserMainExtraPartsGtk::ShowMessageBox(
    368       chrome_browser::kMissingLocaleDataMessage);
    369 #elif defined(USE_AURA)
    370   // TODO(port): We may want a views based message dialog here eventually, but
    371   // for now, crash.
    372   NOTREACHED();
    373 #else
    374 #error "Need MessageBox implementation."
    375 #endif
    376 }
    377