| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  | // Copyright (c) 2015 GitHub, Inc.
 | 
					
						
							|  |  |  | // Use of this source code is governed by the MIT license that can be
 | 
					
						
							|  |  |  | // found in the LICENSE file.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Most code came from: chrome/browser/chrome_browser_main_posix.cc.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-04 12:19:40 -08:00
										 |  |  | #include "shell/browser/electron_browser_main_parts.h"
 | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include <limits.h>
 | 
					
						
							|  |  |  | #include <pthread.h>
 | 
					
						
							|  |  |  | #include <signal.h>
 | 
					
						
							|  |  |  | #include <sys/resource.h>
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "base/posix/eintr_wrapper.h"
 | 
					
						
							| 
									
										
										
										
											2019-01-12 06:30:43 +05:30
										 |  |  | #include "base/task/post_task.h"
 | 
					
						
							|  |  |  | #include "content/public/browser/browser_task_traits.h"
 | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  | #include "content/public/browser/browser_thread.h"
 | 
					
						
							| 
									
										
										
										
											2019-06-19 13:46:59 -07:00
										 |  |  | #include "shell/browser/browser.h"
 | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | using content::BrowserThread; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-19 14:23:04 -07:00
										 |  |  | namespace electron { | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See comment in |PreEarlyInitialization()|, where sigaction is called.
 | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  | void SIGCHLDHandler(int signal) {} | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // The OSX fork() implementation can crash in the child process before
 | 
					
						
							|  |  |  | // fork() returns.  In that case, the shutdown pipe will still be
 | 
					
						
							|  |  |  | // shared with the parent process.  To prevent child crashes from
 | 
					
						
							|  |  |  | // causing parent shutdowns, |g_pipe_pid| is the pid for the process
 | 
					
						
							|  |  |  | // which registered |g_shutdown_pipe_write_fd|.
 | 
					
						
							|  |  |  | // See <http://crbug.com/175341>.
 | 
					
						
							|  |  |  | pid_t g_pipe_pid = -1; | 
					
						
							|  |  |  | int g_shutdown_pipe_write_fd = -1; | 
					
						
							|  |  |  | int g_shutdown_pipe_read_fd = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Common code between SIG{HUP, INT, TERM}Handler.
 | 
					
						
							|  |  |  | void GracefulShutdownHandler(int signal) { | 
					
						
							|  |  |  |   // Reinstall the default handler.  We had one shot at graceful shutdown.
 | 
					
						
							|  |  |  |   struct sigaction action; | 
					
						
							|  |  |  |   memset(&action, 0, sizeof(action)); | 
					
						
							|  |  |  |   action.sa_handler = SIG_DFL; | 
					
						
							| 
									
										
										
										
											2016-07-10 11:52:28 +02:00
										 |  |  |   RAW_CHECK(sigaction(signal, &action, nullptr) == 0); | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   RAW_CHECK(g_pipe_pid == getpid()); | 
					
						
							|  |  |  |   RAW_CHECK(g_shutdown_pipe_write_fd != -1); | 
					
						
							|  |  |  |   RAW_CHECK(g_shutdown_pipe_read_fd != -1); | 
					
						
							|  |  |  |   size_t bytes_written = 0; | 
					
						
							|  |  |  |   do { | 
					
						
							|  |  |  |     int rv = HANDLE_EINTR( | 
					
						
							|  |  |  |         write(g_shutdown_pipe_write_fd, | 
					
						
							|  |  |  |               reinterpret_cast<const char*>(&signal) + bytes_written, | 
					
						
							|  |  |  |               sizeof(signal) - bytes_written)); | 
					
						
							|  |  |  |     RAW_CHECK(rv >= 0); | 
					
						
							|  |  |  |     bytes_written += rv; | 
					
						
							|  |  |  |   } while (bytes_written < sizeof(signal)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See comment in |PostMainMessageLoopStart()|, where sigaction is called.
 | 
					
						
							|  |  |  | void SIGHUPHandler(int signal) { | 
					
						
							|  |  |  |   RAW_CHECK(signal == SIGHUP); | 
					
						
							|  |  |  |   GracefulShutdownHandler(signal); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See comment in |PostMainMessageLoopStart()|, where sigaction is called.
 | 
					
						
							|  |  |  | void SIGINTHandler(int signal) { | 
					
						
							|  |  |  |   RAW_CHECK(signal == SIGINT); | 
					
						
							|  |  |  |   GracefulShutdownHandler(signal); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See comment in |PostMainMessageLoopStart()|, where sigaction is called.
 | 
					
						
							|  |  |  | void SIGTERMHandler(int signal) { | 
					
						
							|  |  |  |   RAW_CHECK(signal == SIGTERM); | 
					
						
							|  |  |  |   GracefulShutdownHandler(signal); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ShutdownDetector : public base::PlatformThread::Delegate { | 
					
						
							|  |  |  |  public: | 
					
						
							| 
									
										
										
										
											2020-11-19 16:00:34 -08:00
										 |  |  |   explicit ShutdownDetector( | 
					
						
							|  |  |  |       int shutdown_fd, | 
					
						
							|  |  |  |       base::OnceCallback<void()> shutdown_callback, | 
					
						
							|  |  |  |       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-19 16:00:34 -08:00
										 |  |  |   // base::PlatformThread::Delegate:
 | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  |   void ThreadMain() override; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  private: | 
					
						
							|  |  |  |   const int shutdown_fd_; | 
					
						
							| 
									
										
										
										
											2020-11-19 16:00:34 -08:00
										 |  |  |   base::OnceCallback<void()> shutdown_callback_; | 
					
						
							|  |  |  |   const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   DISALLOW_COPY_AND_ASSIGN(ShutdownDetector); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-19 16:00:34 -08:00
										 |  |  | ShutdownDetector::ShutdownDetector( | 
					
						
							|  |  |  |     int shutdown_fd, | 
					
						
							|  |  |  |     base::OnceCallback<void()> shutdown_callback, | 
					
						
							|  |  |  |     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) | 
					
						
							|  |  |  |     : shutdown_fd_(shutdown_fd), | 
					
						
							|  |  |  |       shutdown_callback_(std::move(shutdown_callback)), | 
					
						
							|  |  |  |       task_runner_(task_runner) { | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  |   CHECK_NE(shutdown_fd_, -1); | 
					
						
							| 
									
										
										
										
											2020-11-19 16:00:34 -08:00
										 |  |  |   CHECK(!shutdown_callback_.is_null()); | 
					
						
							|  |  |  |   CHECK(task_runner_); | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // These functions are used to help us diagnose crash dumps that happen
 | 
					
						
							|  |  |  | // during the shutdown process.
 | 
					
						
							|  |  |  | NOINLINE void ShutdownFDReadError() { | 
					
						
							|  |  |  |   // Ensure function isn't optimized away.
 | 
					
						
							|  |  |  |   asm(""); | 
					
						
							|  |  |  |   sleep(UINT_MAX); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NOINLINE void ShutdownFDClosedError() { | 
					
						
							|  |  |  |   // Ensure function isn't optimized away.
 | 
					
						
							|  |  |  |   asm(""); | 
					
						
							|  |  |  |   sleep(UINT_MAX); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NOINLINE void ExitPosted() { | 
					
						
							|  |  |  |   // Ensure function isn't optimized away.
 | 
					
						
							|  |  |  |   asm(""); | 
					
						
							|  |  |  |   sleep(UINT_MAX); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ShutdownDetector::ThreadMain() { | 
					
						
							|  |  |  |   base::PlatformThread::SetName("CrShutdownDetector"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int signal; | 
					
						
							|  |  |  |   size_t bytes_read = 0; | 
					
						
							|  |  |  |   do { | 
					
						
							| 
									
										
										
										
											2020-11-19 16:00:34 -08:00
										 |  |  |     const ssize_t ret = HANDLE_EINTR( | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  |         read(shutdown_fd_, reinterpret_cast<char*>(&signal) + bytes_read, | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  |              sizeof(signal) - bytes_read)); | 
					
						
							|  |  |  |     if (ret < 0) { | 
					
						
							|  |  |  |       NOTREACHED() << "Unexpected error: " << strerror(errno); | 
					
						
							|  |  |  |       ShutdownFDReadError(); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } else if (ret == 0) { | 
					
						
							|  |  |  |       NOTREACHED() << "Unexpected closure of shutdown pipe."; | 
					
						
							|  |  |  |       ShutdownFDClosedError(); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     bytes_read += ret; | 
					
						
							|  |  |  |   } while (bytes_read < sizeof(signal)); | 
					
						
							|  |  |  |   VLOG(1) << "Handling shutdown for signal " << signal << "."; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-19 16:00:34 -08:00
										 |  |  |   if (!task_runner_->PostTask(FROM_HERE, | 
					
						
							|  |  |  |                               base::BindOnce(std::move(shutdown_callback_)))) { | 
					
						
							|  |  |  |     // Without a valid task runner to post the exit task to, there aren't many
 | 
					
						
							|  |  |  |     // options. Raise the signal again. The default handler will pick it up
 | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  |     // and cause an ungraceful exit.
 | 
					
						
							| 
									
										
										
										
											2020-11-19 16:00:34 -08:00
										 |  |  |     RAW_LOG(WARNING, "No valid task runner, exiting ungracefully."); | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  |     kill(getpid(), signal); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // The signal may be handled on another thread.  Give that a chance to
 | 
					
						
							|  |  |  |     // happen.
 | 
					
						
							|  |  |  |     sleep(3); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // We really should be dead by now.  For whatever reason, we're not. Exit
 | 
					
						
							|  |  |  |     // immediately, with the exit status set to the signal number with bit 8
 | 
					
						
							|  |  |  |     // set.  On the systems that we care about, this exit status is what is
 | 
					
						
							|  |  |  |     // normally used to indicate an exit by this signal's default handler.
 | 
					
						
							|  |  |  |     // This mechanism isn't a de jure standard, but even in the worst case, it
 | 
					
						
							|  |  |  |     // should at least result in an immediate exit.
 | 
					
						
							|  |  |  |     RAW_LOG(WARNING, "Still here, exiting really ungracefully."); | 
					
						
							|  |  |  |     _exit(signal | (1 << 7)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   ExitPosted(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }  // namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-04 12:19:40 -08:00
										 |  |  | void ElectronBrowserMainParts::HandleSIGCHLD() { | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  |   // We need to accept SIGCHLD, even though our handler is a no-op because
 | 
					
						
							|  |  |  |   // otherwise we cannot wait on children. (According to POSIX 2001.)
 | 
					
						
							|  |  |  |   struct sigaction action; | 
					
						
							|  |  |  |   memset(&action, 0, sizeof(action)); | 
					
						
							|  |  |  |   action.sa_handler = SIGCHLDHandler; | 
					
						
							| 
									
										
										
										
											2016-07-10 11:52:28 +02:00
										 |  |  |   CHECK_EQ(sigaction(SIGCHLD, &action, nullptr), 0); | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-19 16:00:34 -08:00
										 |  |  | void ElectronBrowserMainParts::InstallShutdownSignalHandlers( | 
					
						
							|  |  |  |     base::OnceCallback<void()> shutdown_callback, | 
					
						
							|  |  |  |     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  |   int pipefd[2]; | 
					
						
							|  |  |  |   int ret = pipe(pipefd); | 
					
						
							|  |  |  |   if (ret < 0) { | 
					
						
							|  |  |  |     PLOG(DFATAL) << "Failed to create pipe"; | 
					
						
							| 
									
										
										
										
											2020-11-19 16:00:34 -08:00
										 |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   g_pipe_pid = getpid(); | 
					
						
							|  |  |  |   g_shutdown_pipe_read_fd = pipefd[0]; | 
					
						
							|  |  |  |   g_shutdown_pipe_write_fd = pipefd[1]; | 
					
						
							|  |  |  | #if !defined(ADDRESS_SANITIZER)
 | 
					
						
							|  |  |  |   const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 2; | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2020-11-19 16:00:34 -08:00
										 |  |  |   // ASan instrumentation bloats the stack frames, so we need to increase the
 | 
					
						
							|  |  |  |   // stack size to avoid hitting the guard page.
 | 
					
						
							|  |  |  |   const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 4; | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2020-11-19 16:00:34 -08:00
										 |  |  |   ShutdownDetector* detector = new ShutdownDetector( | 
					
						
							|  |  |  |       g_shutdown_pipe_read_fd, std::move(shutdown_callback), task_runner); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // PlatformThread does not delete its delegate.
 | 
					
						
							|  |  |  |   ANNOTATE_LEAKING_OBJECT_PTR(detector); | 
					
						
							|  |  |  |   if (!base::PlatformThread::CreateNonJoinable(kShutdownDetectorThreadStackSize, | 
					
						
							|  |  |  |                                                detector)) { | 
					
						
							|  |  |  |     LOG(DFATAL) << "Failed to create shutdown detector task."; | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  |   } | 
					
						
							|  |  |  |   // Setup signal handlers for shutdown AFTER shutdown pipe is setup because
 | 
					
						
							|  |  |  |   // it may be called right away after handler is set.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // If adding to this list of signal handlers, note the new signal probably
 | 
					
						
							|  |  |  |   // needs to be reset in child processes. See
 | 
					
						
							|  |  |  |   // base/process_util_posix.cc:LaunchProcess.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-19 16:00:34 -08:00
										 |  |  |   // We need to handle SIGTERM, because that is how many POSIX-based distros
 | 
					
						
							|  |  |  |   // ask processes to quit gracefully at shutdown time.
 | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  |   struct sigaction action; | 
					
						
							|  |  |  |   memset(&action, 0, sizeof(action)); | 
					
						
							|  |  |  |   action.sa_handler = SIGTERMHandler; | 
					
						
							| 
									
										
										
										
											2016-07-10 11:52:28 +02:00
										 |  |  |   CHECK_EQ(sigaction(SIGTERM, &action, nullptr), 0); | 
					
						
							| 
									
										
										
										
											2020-11-19 16:00:34 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  |   // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If
 | 
					
						
							|  |  |  |   // the browser process is being debugged, GDB will catch the SIGINT first.
 | 
					
						
							|  |  |  |   action.sa_handler = SIGINTHandler; | 
					
						
							| 
									
										
										
										
											2016-07-10 11:52:28 +02:00
										 |  |  |   CHECK_EQ(sigaction(SIGINT, &action, nullptr), 0); | 
					
						
							| 
									
										
										
										
											2020-11-19 16:00:34 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  |   // And SIGHUP, for when the terminal disappears. On shutdown, many Linux
 | 
					
						
							|  |  |  |   // distros send SIGHUP, SIGTERM, and then SIGKILL.
 | 
					
						
							|  |  |  |   action.sa_handler = SIGHUPHandler; | 
					
						
							| 
									
										
										
										
											2016-07-10 11:52:28 +02:00
										 |  |  |   CHECK_EQ(sigaction(SIGHUP, &action, nullptr), 0); | 
					
						
							| 
									
										
										
										
											2015-10-04 19:21:36 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-19 14:23:04 -07:00
										 |  |  | }  // namespace electron
 |