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