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 30using content::BrowserThread; 31 32namespace { 33 34// See comment in |PreEarlyInitialization()|, where sigaction is called. 35void SIGCHLDHandler(int signal) { 36} 37 38// The OSX fork() implementation can crash in the child process before 39// fork() returns. In that case, the shutdown pipe will still be 40// shared with the parent process. To prevent child crashes from 41// causing parent shutdowns, |g_pipe_pid| is the pid for the process 42// which registered |g_shutdown_pipe_write_fd|. 43// See <http://crbug.com/175341>. 44pid_t g_pipe_pid = -1; 45int g_shutdown_pipe_write_fd = -1; 46int g_shutdown_pipe_read_fd = -1; 47 48// Common code between SIG{HUP, INT, TERM}Handler. 49void GracefulShutdownHandler(int signal) { 50 // Reinstall the default handler. We had one shot at graceful shutdown. 51 struct sigaction action; 52 memset(&action, 0, sizeof(action)); 53 action.sa_handler = SIG_DFL; 54 RAW_CHECK(sigaction(signal, &action, NULL) == 0); 55 56 RAW_CHECK(g_pipe_pid == getpid()); 57 RAW_CHECK(g_shutdown_pipe_write_fd != -1); 58 RAW_CHECK(g_shutdown_pipe_read_fd != -1); 59 size_t bytes_written = 0; 60 do { 61 int rv = HANDLE_EINTR( 62 write(g_shutdown_pipe_write_fd, 63 reinterpret_cast<const char*>(&signal) + bytes_written, 64 sizeof(signal) - bytes_written)); 65 RAW_CHECK(rv >= 0); 66 bytes_written += rv; 67 } while (bytes_written < sizeof(signal)); 68} 69 70// See comment in |PostMainMessageLoopStart()|, where sigaction is called. 71void SIGHUPHandler(int signal) { 72 RAW_CHECK(signal == SIGHUP); 73 GracefulShutdownHandler(signal); 74} 75 76// See comment in |PostMainMessageLoopStart()|, where sigaction is called. 77void SIGINTHandler(int signal) { 78 RAW_CHECK(signal == SIGINT); 79 GracefulShutdownHandler(signal); 80} 81 82// See comment in |PostMainMessageLoopStart()|, where sigaction is called. 83void SIGTERMHandler(int signal) { 84 RAW_CHECK(signal == SIGTERM); 85 GracefulShutdownHandler(signal); 86} 87 88// ExitHandler takes care of servicing an exit (from a signal) at the 89// appropriate time. Specifically if we get an exit and have not finished 90// session restore we delay the exit. To do otherwise means we're exiting part 91// way through startup which causes all sorts of problems. 92class ExitHandler : public content::NotificationObserver { 93 public: 94 // Invokes exit when appropriate. 95 static void ExitWhenPossibleOnUIThread(); 96 97 // Overridden from content::NotificationObserver: 98 virtual void Observe(int type, 99 const content::NotificationSource& source, 100 const content::NotificationDetails& details) OVERRIDE; 101 102 private: 103 ExitHandler(); 104 virtual ~ExitHandler(); 105 106 // Does the appropriate call to Exit. 107 static void Exit(); 108 109 content::NotificationRegistrar registrar_; 110 111 DISALLOW_COPY_AND_ASSIGN(ExitHandler); 112}; 113 114// static 115void ExitHandler::ExitWhenPossibleOnUIThread() { 116 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 117 if (SessionRestore::IsRestoringSynchronously()) { 118 // ExitHandler takes care of deleting itself. 119 new ExitHandler(); 120 } else { 121 Exit(); 122 } 123} 124 125void ExitHandler::Observe(int type, 126 const content::NotificationSource& source, 127 const content::NotificationDetails& details) { 128 if (!SessionRestore::IsRestoringSynchronously()) { 129 // At this point the message loop may not be running (meaning we haven't 130 // gotten through browser startup, but are close). Post the task to at which 131 // point the message loop is running. 132 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 133 base::Bind(&ExitHandler::Exit)); 134 delete this; 135 } 136} 137 138ExitHandler::ExitHandler() { 139 registrar_.Add( 140 this, chrome::NOTIFICATION_SESSION_RESTORE_DONE, 141 content::NotificationService::AllBrowserContextsAndSources()); 142} 143 144ExitHandler::~ExitHandler() { 145} 146 147// static 148void ExitHandler::Exit() { 149#if defined(OS_CHROMEOS) 150 // On ChromeOS, exiting on signal should be always clean. 151 chrome::ExitCleanly(); 152#else 153 chrome::AttemptExit(); 154#endif 155} 156 157class ShutdownDetector : public base::PlatformThread::Delegate { 158 public: 159 explicit ShutdownDetector(int shutdown_fd); 160 161 virtual void ThreadMain() OVERRIDE; 162 163 private: 164 const int shutdown_fd_; 165 166 DISALLOW_COPY_AND_ASSIGN(ShutdownDetector); 167}; 168 169ShutdownDetector::ShutdownDetector(int shutdown_fd) 170 : shutdown_fd_(shutdown_fd) { 171 CHECK_NE(shutdown_fd_, -1); 172} 173 174// These functions are used to help us diagnose crash dumps that happen 175// during the shutdown process. 176NOINLINE void ShutdownFDReadError() { 177 // Ensure function isn't optimized away. 178 asm(""); 179 sleep(UINT_MAX); 180} 181 182NOINLINE void ShutdownFDClosedError() { 183 // Ensure function isn't optimized away. 184 asm(""); 185 sleep(UINT_MAX); 186} 187 188NOINLINE void ExitPosted() { 189 // Ensure function isn't optimized away. 190 asm(""); 191 sleep(UINT_MAX); 192} 193 194void ShutdownDetector::ThreadMain() { 195 base::PlatformThread::SetName("CrShutdownDetector"); 196 197 int signal; 198 size_t bytes_read = 0; 199 ssize_t ret; 200 do { 201 ret = HANDLE_EINTR( 202 read(shutdown_fd_, 203 reinterpret_cast<char*>(&signal) + bytes_read, 204 sizeof(signal) - bytes_read)); 205 if (ret < 0) { 206 NOTREACHED() << "Unexpected error: " << strerror(errno); 207 ShutdownFDReadError(); 208 break; 209 } else if (ret == 0) { 210 NOTREACHED() << "Unexpected closure of shutdown pipe."; 211 ShutdownFDClosedError(); 212 break; 213 } 214 bytes_read += ret; 215 } while (bytes_read < sizeof(signal)); 216 VLOG(1) << "Handling shutdown for signal " << signal << "."; 217 base::Closure task = base::Bind(&ExitHandler::ExitWhenPossibleOnUIThread); 218 219 if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task)) { 220 // Without a UI thread to post the exit task to, there aren't many 221 // options. Raise the signal again. The default handler will pick it up 222 // and cause an ungraceful exit. 223 RAW_LOG(WARNING, "No UI thread, exiting ungracefully."); 224 kill(getpid(), signal); 225 226 // The signal may be handled on another thread. Give that a chance to 227 // happen. 228 sleep(3); 229 230 // We really should be dead by now. For whatever reason, we're not. Exit 231 // immediately, with the exit status set to the signal number with bit 8 232 // set. On the systems that we care about, this exit status is what is 233 // normally used to indicate an exit by this signal's default handler. 234 // This mechanism isn't a de jure standard, but even in the worst case, it 235 // should at least result in an immediate exit. 236 RAW_LOG(WARNING, "Still here, exiting really ungracefully."); 237 _exit(signal | (1 << 7)); 238 } 239 ExitPosted(); 240} 241 242} // namespace 243 244// ChromeBrowserMainPartsPosix ------------------------------------------------- 245 246ChromeBrowserMainPartsPosix::ChromeBrowserMainPartsPosix( 247 const content::MainFunctionParams& parameters) 248 : ChromeBrowserMainParts(parameters) { 249} 250 251void ChromeBrowserMainPartsPosix::PreEarlyInitialization() { 252 ChromeBrowserMainParts::PreEarlyInitialization(); 253 254 // We need to accept SIGCHLD, even though our handler is a no-op because 255 // otherwise we cannot wait on children. (According to POSIX 2001.) 256 struct sigaction action; 257 memset(&action, 0, sizeof(action)); 258 action.sa_handler = SIGCHLDHandler; 259 CHECK(sigaction(SIGCHLD, &action, NULL) == 0); 260} 261 262void ChromeBrowserMainPartsPosix::PostMainMessageLoopStart() { 263 ChromeBrowserMainParts::PostMainMessageLoopStart(); 264 265 int pipefd[2]; 266 int ret = pipe(pipefd); 267 if (ret < 0) { 268 PLOG(DFATAL) << "Failed to create pipe"; 269 } else { 270 g_pipe_pid = getpid(); 271 g_shutdown_pipe_read_fd = pipefd[0]; 272 g_shutdown_pipe_write_fd = pipefd[1]; 273#if !defined(ADDRESS_SANITIZER) && !defined(KEEP_SHADOW_STACKS) 274 const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 2; 275#else 276 // ASan instrumentation and -finstrument-functions (used for keeping the 277 // shadow stacks) bloat the stack frames, so we need to increase the stack 278 // size to avoid hitting the guard page. 279 const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 4; 280#endif 281 // TODO(viettrungluu,willchan): crbug.com/29675 - This currently leaks, so 282 // if you change this, you'll probably need to change the suppression. 283 if (!base::PlatformThread::CreateNonJoinable( 284 kShutdownDetectorThreadStackSize, 285 new ShutdownDetector(g_shutdown_pipe_read_fd))) { 286 LOG(DFATAL) << "Failed to create shutdown detector task."; 287 } 288 } 289 // Setup signal handlers for shutdown AFTER shutdown pipe is setup because 290 // it may be called right away after handler is set. 291 292 // If adding to this list of signal handlers, note the new signal probably 293 // needs to be reset in child processes. See 294 // base/process_util_posix.cc:LaunchProcess. 295 296 // We need to handle SIGTERM, because that is how many POSIX-based distros ask 297 // processes to quit gracefully at shutdown time. 298 struct sigaction action; 299 memset(&action, 0, sizeof(action)); 300 action.sa_handler = SIGTERMHandler; 301 CHECK(sigaction(SIGTERM, &action, NULL) == 0); 302 // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If 303 // the browser process is being debugged, GDB will catch the SIGINT first. 304 action.sa_handler = SIGINTHandler; 305 CHECK(sigaction(SIGINT, &action, NULL) == 0); 306 // And SIGHUP, for when the terminal disappears. On shutdown, many Linux 307 // distros send SIGHUP, SIGTERM, and then SIGKILL. 308 action.sa_handler = SIGHUPHandler; 309 CHECK(sigaction(SIGHUP, &action, NULL) == 0); 310} 311 312void ChromeBrowserMainPartsPosix::ShowMissingLocaleMessageBox() { 313#if defined(OS_CHROMEOS) 314 NOTREACHED(); // Should not ever happen on ChromeOS. 315#elif defined(OS_MACOSX) 316 // Not called on Mac because we load the locale files differently. 317 NOTREACHED(); 318#elif defined(USE_AURA) 319 // TODO(port): We may want a views based message dialog here eventually, but 320 // for now, crash. 321 NOTREACHED(); 322#else 323#error "Need MessageBox implementation." 324#endif 325} 326