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