Home | History | Annotate | Download | only in browser
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/browser_main_posix.h"
      6 
      7 #include <errno.h>
      8 #include <limits.h>
      9 #include <signal.h>
     10 #include <sys/resource.h>
     11 #include <unistd.h>
     12 
     13 #include <string>
     14 
     15 #include "base/command_line.h"
     16 #include "base/eintr_wrapper.h"
     17 #include "base/logging.h"
     18 #include "base/string_number_conversions.h"
     19 #include "chrome/browser/defaults.h"
     20 #include "chrome/browser/ui/browser_list.h"
     21 #include "chrome/common/chrome_switches.h"
     22 #include "content/browser/browser_thread.h"
     23 
     24 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
     25 #include "chrome/browser/printing/print_dialog_gtk.h"
     26 #endif
     27 
     28 namespace {
     29 
     30 // See comment in |PreEarlyInitialization()|, where sigaction is called.
     31 void SIGCHLDHandler(int signal) {
     32 }
     33 
     34 int g_shutdown_pipe_write_fd = -1;
     35 int g_shutdown_pipe_read_fd = -1;
     36 
     37 // Common code between SIG{HUP, INT, TERM}Handler.
     38 void GracefulShutdownHandler(int signal) {
     39   // Reinstall the default handler.  We had one shot at graceful shutdown.
     40   struct sigaction action;
     41   memset(&action, 0, sizeof(action));
     42   action.sa_handler = SIG_DFL;
     43   RAW_CHECK(sigaction(signal, &action, NULL) == 0);
     44 
     45   RAW_CHECK(g_shutdown_pipe_write_fd != -1);
     46   RAW_CHECK(g_shutdown_pipe_read_fd != -1);
     47   size_t bytes_written = 0;
     48   do {
     49     int rv = HANDLE_EINTR(
     50         write(g_shutdown_pipe_write_fd,
     51               reinterpret_cast<const char*>(&signal) + bytes_written,
     52               sizeof(signal) - bytes_written));
     53     RAW_CHECK(rv >= 0);
     54     bytes_written += rv;
     55   } while (bytes_written < sizeof(signal));
     56 }
     57 
     58 // See comment in |PreEarlyInitialization()|, where sigaction is called.
     59 void SIGHUPHandler(int signal) {
     60   RAW_CHECK(signal == SIGHUP);
     61   GracefulShutdownHandler(signal);
     62 }
     63 
     64 // See comment in |PreEarlyInitialization()|, where sigaction is called.
     65 void SIGINTHandler(int signal) {
     66   RAW_CHECK(signal == SIGINT);
     67   GracefulShutdownHandler(signal);
     68 }
     69 
     70 // See comment in |PreEarlyInitialization()|, where sigaction is called.
     71 void SIGTERMHandler(int signal) {
     72   RAW_CHECK(signal == SIGTERM);
     73   GracefulShutdownHandler(signal);
     74 }
     75 
     76 class ShutdownDetector : public base::PlatformThread::Delegate {
     77  public:
     78   explicit ShutdownDetector(int shutdown_fd);
     79 
     80   virtual void ThreadMain();
     81 
     82  private:
     83   const int shutdown_fd_;
     84 
     85   DISALLOW_COPY_AND_ASSIGN(ShutdownDetector);
     86 };
     87 
     88 ShutdownDetector::ShutdownDetector(int shutdown_fd)
     89     : shutdown_fd_(shutdown_fd) {
     90   CHECK_NE(shutdown_fd_, -1);
     91 }
     92 
     93 
     94 // These functions are used to help us diagnose crash dumps that happen
     95 // during the shutdown process.
     96 NOINLINE void ShutdownFDReadError() {
     97   // Ensure function isn't optimized away.
     98   asm("");
     99   sleep(UINT_MAX);
    100 }
    101 
    102 NOINLINE void ShutdownFDClosedError() {
    103   // Ensure function isn't optimized away.
    104   asm("");
    105   sleep(UINT_MAX);
    106 }
    107 
    108 NOINLINE void CloseAllBrowsersAndExitPosted() {
    109   // Ensure function isn't optimized away.
    110   asm("");
    111   sleep(UINT_MAX);
    112 }
    113 
    114 void ShutdownDetector::ThreadMain() {
    115   base::PlatformThread::SetName("CrShutdownDetector");
    116 
    117   int signal;
    118   size_t bytes_read = 0;
    119   ssize_t ret;
    120   do {
    121     ret = HANDLE_EINTR(
    122         read(shutdown_fd_,
    123              reinterpret_cast<char*>(&signal) + bytes_read,
    124              sizeof(signal) - bytes_read));
    125     if (ret < 0) {
    126       NOTREACHED() << "Unexpected error: " << strerror(errno);
    127       ShutdownFDReadError();
    128       break;
    129     } else if (ret == 0) {
    130       NOTREACHED() << "Unexpected closure of shutdown pipe.";
    131       ShutdownFDClosedError();
    132       break;
    133     }
    134     bytes_read += ret;
    135   } while (bytes_read < sizeof(signal));
    136 
    137   VLOG(1) << "Handling shutdown for signal " << signal << ".";
    138 
    139   if (!BrowserThread::PostTask(
    140       BrowserThread::UI, FROM_HERE,
    141       NewRunnableFunction(BrowserList::CloseAllBrowsersAndExit))) {
    142     // Without a UI thread to post the exit task to, there aren't many
    143     // options.  Raise the signal again.  The default handler will pick it up
    144     // and cause an ungraceful exit.
    145     RAW_LOG(WARNING, "No UI thread, exiting ungracefully.");
    146     kill(getpid(), signal);
    147 
    148     // The signal may be handled on another thread.  Give that a chance to
    149     // happen.
    150     sleep(3);
    151 
    152     // We really should be dead by now.  For whatever reason, we're not. Exit
    153     // immediately, with the exit status set to the signal number with bit 8
    154     // set.  On the systems that we care about, this exit status is what is
    155     // normally used to indicate an exit by this signal's default handler.
    156     // This mechanism isn't a de jure standard, but even in the worst case, it
    157     // should at least result in an immediate exit.
    158     RAW_LOG(WARNING, "Still here, exiting really ungracefully.");
    159     _exit(signal | (1 << 7));
    160   }
    161   CloseAllBrowsersAndExitPosted();
    162 }
    163 
    164 // Sets the file descriptor soft limit to |max_descriptors| or the OS hard
    165 // limit, whichever is lower.
    166 void SetFileDescriptorLimit(unsigned int max_descriptors) {
    167   struct rlimit limits;
    168   if (getrlimit(RLIMIT_NOFILE, &limits) == 0) {
    169     unsigned int new_limit = max_descriptors;
    170     if (limits.rlim_max > 0 && limits.rlim_max < max_descriptors) {
    171       new_limit = limits.rlim_max;
    172     }
    173     limits.rlim_cur = new_limit;
    174     if (setrlimit(RLIMIT_NOFILE, &limits) != 0) {
    175       PLOG(INFO) << "Failed to set file descriptor limit";
    176     }
    177   } else {
    178     PLOG(INFO) << "Failed to get file descriptor limit";
    179   }
    180 }
    181 
    182 }  // namespace
    183 
    184 // BrowserMainPartsPosix -------------------------------------------------------
    185 
    186 void BrowserMainPartsPosix::PreEarlyInitialization() {
    187   // We need to accept SIGCHLD, even though our handler is a no-op because
    188   // otherwise we cannot wait on children. (According to POSIX 2001.)
    189   struct sigaction action;
    190   memset(&action, 0, sizeof(action));
    191   action.sa_handler = SIGCHLDHandler;
    192   CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
    193 
    194   // If adding to this list of signal handlers, note the new signal probably
    195   // needs to be reset in child processes. See
    196   // base/process_util_posix.cc:LaunchApp
    197 
    198   // We need to handle SIGTERM, because that is how many POSIX-based distros ask
    199   // processes to quit gracefully at shutdown time.
    200   memset(&action, 0, sizeof(action));
    201   action.sa_handler = SIGTERMHandler;
    202   CHECK(sigaction(SIGTERM, &action, NULL) == 0);
    203   // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If
    204   // the browser process is being debugged, GDB will catch the SIGINT first.
    205   action.sa_handler = SIGINTHandler;
    206   CHECK(sigaction(SIGINT, &action, NULL) == 0);
    207   // And SIGHUP, for when the terminal disappears. On shutdown, many Linux
    208   // distros send SIGHUP, SIGTERM, and then SIGKILL.
    209   action.sa_handler = SIGHUPHandler;
    210   CHECK(sigaction(SIGHUP, &action, NULL) == 0);
    211 
    212   const std::string fd_limit_string =
    213       parsed_command_line().GetSwitchValueASCII(
    214           switches::kFileDescriptorLimit);
    215   int fd_limit = 0;
    216   if (!fd_limit_string.empty()) {
    217     base::StringToInt(fd_limit_string, &fd_limit);
    218   }
    219 #if defined(OS_MACOSX)
    220   // We use quite a few file descriptors for our IPC, and the default limit on
    221   // the Mac is low (256), so bump it up if there is no explicit override.
    222   if (fd_limit == 0) {
    223     fd_limit = 1024;
    224   }
    225 #endif  // OS_MACOSX
    226   if (fd_limit > 0)
    227     SetFileDescriptorLimit(fd_limit);
    228 
    229 #if defined(OS_CHROMEOS)
    230   if (parsed_command_line().HasSwitch(switches::kGuestSession)) {
    231     // Disable sync and extensions if we're in "browse without sign-in" mode.
    232     CommandLine* singleton_command_line = CommandLine::ForCurrentProcess();
    233     singleton_command_line->AppendSwitch(switches::kDisableSync);
    234     singleton_command_line->AppendSwitch(switches::kDisableExtensions);
    235     browser_defaults::bookmarks_enabled = false;
    236   }
    237 #endif
    238 }
    239 
    240 void BrowserMainPartsPosix::PostMainMessageLoopStart() {
    241   int pipefd[2];
    242   int ret = pipe(pipefd);
    243   if (ret < 0) {
    244     PLOG(DFATAL) << "Failed to create pipe";
    245   } else {
    246     g_shutdown_pipe_read_fd = pipefd[0];
    247     g_shutdown_pipe_write_fd = pipefd[1];
    248     const size_t kShutdownDetectorThreadStackSize = 4096;
    249     // TODO(viettrungluu,willchan): crbug.com/29675 - This currently leaks, so
    250     // if you change this, you'll probably need to change the suppression.
    251     if (!base::PlatformThread::CreateNonJoinable(
    252             kShutdownDetectorThreadStackSize,
    253             new ShutdownDetector(g_shutdown_pipe_read_fd))) {
    254       LOG(DFATAL) << "Failed to create shutdown detector task.";
    255     }
    256   }
    257 
    258 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
    259   printing::PrintingContextCairo::SetCreatePrintDialogFunction(
    260       &PrintDialogGtk::CreatePrintDialog);
    261 #endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
    262 }
    263