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 using content::BrowserThread; 31 32 namespace { 33 34 // See comment in |PreEarlyInitialization()|, where sigaction is called. 35 void 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>. 44 pid_t g_pipe_pid = -1; 45 int g_shutdown_pipe_write_fd = -1; 46 int g_shutdown_pipe_read_fd = -1; 47 48 // Common code between SIG{HUP, INT, TERM}Handler. 49 void 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. 71 void SIGHUPHandler(int signal) { 72 RAW_CHECK(signal == SIGHUP); 73 GracefulShutdownHandler(signal); 74 } 75 76 // See comment in |PostMainMessageLoopStart()|, where sigaction is called. 77 void SIGINTHandler(int signal) { 78 RAW_CHECK(signal == SIGINT); 79 GracefulShutdownHandler(signal); 80 } 81 82 // See comment in |PostMainMessageLoopStart()|, where sigaction is called. 83 void 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. 92 class 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 115 void 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 125 void 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 138 ExitHandler::ExitHandler() { 139 registrar_.Add( 140 this, chrome::NOTIFICATION_SESSION_RESTORE_DONE, 141 content::NotificationService::AllBrowserContextsAndSources()); 142 } 143 144 ExitHandler::~ExitHandler() { 145 } 146 147 // static 148 void 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 157 class 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 169 ShutdownDetector::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. 176 NOINLINE void ShutdownFDReadError() { 177 // Ensure function isn't optimized away. 178 asm(""); 179 sleep(UINT_MAX); 180 } 181 182 NOINLINE void ShutdownFDClosedError() { 183 // Ensure function isn't optimized away. 184 asm(""); 185 sleep(UINT_MAX); 186 } 187 188 NOINLINE void ExitPosted() { 189 // Ensure function isn't optimized away. 190 asm(""); 191 sleep(UINT_MAX); 192 } 193 194 void 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 246 ChromeBrowserMainPartsPosix::ChromeBrowserMainPartsPosix( 247 const content::MainFunctionParams& parameters) 248 : ChromeBrowserMainParts(parameters) { 249 } 250 251 void 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 262 void 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 312 void 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