chrome_browser_main_posix.cc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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. #include "chrome/browser/chrome_browser_main_posix.h"
  5. #include <errno.h>
  6. #include <pthread.h>
  7. #include <signal.h>
  8. #include <stddef.h>
  9. #include <string.h>
  10. #include <sys/resource.h>
  11. #include <string>
  12. #include "base/bind.h"
  13. #include "base/check_op.h"
  14. #include "base/notreached.h"
  15. #include "build/build_config.h"
  16. #include "build/chromeos_buildflags.h"
  17. #include "chrome/browser/lifetime/application_lifetime.h"
  18. #include "chrome/browser/sessions/session_restore.h"
  19. #include "chrome/browser/shutdown_signal_handlers_posix.h"
  20. #include "content/public/browser/browser_task_traits.h"
  21. #include "content/public/browser/browser_thread.h"
  22. #include "content/public/common/result_codes.h"
  23. using content::BrowserThread;
  24. namespace {
  25. // See comment in |PreEarlyInitialization()|, where sigaction is called.
  26. void SIGCHLDHandler(int signal) {
  27. }
  28. // ExitHandler takes care of servicing an exit (from a signal) at the
  29. // appropriate time. Specifically if we get an exit and have not finished
  30. // session restore we delay the exit. To do otherwise means we're exiting part
  31. // way through startup which causes all sorts of problems.
  32. class ExitHandler {
  33. public:
  34. ExitHandler(const ExitHandler&) = delete;
  35. ExitHandler& operator=(const ExitHandler&) = delete;
  36. // Invokes exit when appropriate.
  37. static void ExitWhenPossibleOnUIThread(int signal);
  38. private:
  39. ExitHandler();
  40. ~ExitHandler();
  41. // Called when a session restore has finished.
  42. void OnSessionRestoreDone(Profile* profile, int num_tabs_restored);
  43. // Does the appropriate call to Exit.
  44. static void Exit();
  45. // Points to the on-session-restored callback that was registered with
  46. // SessionRestore's callback list. When objects of this class are destroyed,
  47. // the subscription's destructor will automatically unregister the callback in
  48. // SessionRestore, so that the callback list does not contain any obsolete
  49. // callbacks.
  50. base::CallbackListSubscription on_session_restored_callback_subscription_;
  51. };
  52. // static
  53. void ExitHandler::ExitWhenPossibleOnUIThread(int signal) {
  54. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  55. if (SessionRestore::IsRestoringSynchronously()) {
  56. // ExitHandler takes care of deleting itself.
  57. new ExitHandler();
  58. } else {
  59. // TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
  60. // of lacros-chrome is complete.
  61. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
  62. switch (signal) {
  63. case SIGINT:
  64. case SIGHUP:
  65. // SIGINT gets sent when the user types Ctrl+C, but the session is
  66. // likely not going away, so try to exit gracefully. SIGHUP is sent on
  67. // most systems as a first warning of shutdown. If the process takes
  68. // too long to quit, the next signal is usually SIGTERM.
  69. Exit();
  70. break;
  71. case SIGTERM:
  72. // SIGTERM is usually sent instead of SIGKILL to gracefully shutdown
  73. // processes. But most systems use it as a shutdown warning, so
  74. // conservatively assume that the session is ending. If the process
  75. // still doesn't quit within a bounded time, most systems will finally
  76. // send SIGKILL, which we're unable to install a signal handler for.
  77. // TODO(thomasanderson): Try to distinguish if the session is really
  78. // ending or not. Maybe there's a systemd or DBus API to query.
  79. chrome::SessionEnding();
  80. break;
  81. default:
  82. NOTREACHED();
  83. }
  84. #else
  85. Exit();
  86. #endif
  87. }
  88. }
  89. ExitHandler::ExitHandler() {
  90. on_session_restored_callback_subscription_ =
  91. SessionRestore::RegisterOnSessionRestoredCallback(base::BindRepeating(
  92. &ExitHandler::OnSessionRestoreDone, base::Unretained(this)));
  93. }
  94. ExitHandler::~ExitHandler() {
  95. }
  96. void ExitHandler::OnSessionRestoreDone(Profile* profile, int /* num_tabs */) {
  97. if (!SessionRestore::IsRestoringSynchronously()) {
  98. // At this point the message loop may not be running (meaning we haven't
  99. // gotten through browser startup, but are close). Post the task to at which
  100. // point the message loop is running.
  101. content::GetUIThreadTaskRunner({})->PostTask(
  102. FROM_HERE, base::BindOnce(&ExitHandler::Exit));
  103. delete this;
  104. }
  105. }
  106. // static
  107. void ExitHandler::Exit() {
  108. #if BUILDFLAG(IS_CHROMEOS_ASH)
  109. // On ChromeOS, exiting on signal should be always clean.
  110. chrome::ExitIgnoreUnloadHandlers();
  111. #else
  112. chrome::AttemptExit();
  113. #endif
  114. }
  115. } // namespace
  116. // ChromeBrowserMainPartsPosix -------------------------------------------------
  117. ChromeBrowserMainPartsPosix::ChromeBrowserMainPartsPosix(
  118. bool is_integration_test,
  119. StartupData* startup_data)
  120. : ChromeBrowserMainParts(is_integration_test, startup_data) {}
  121. int ChromeBrowserMainPartsPosix::PreEarlyInitialization() {
  122. const int result = ChromeBrowserMainParts::PreEarlyInitialization();
  123. if (result != content::RESULT_CODE_NORMAL_EXIT)
  124. return result;
  125. // We need to accept SIGCHLD, even though our handler is a no-op because
  126. // otherwise we cannot wait on children. (According to POSIX 2001.)
  127. struct sigaction action;
  128. memset(&action, 0, sizeof(action));
  129. action.sa_handler = SIGCHLDHandler;
  130. CHECK_EQ(0, sigaction(SIGCHLD, &action, NULL));
  131. return content::RESULT_CODE_NORMAL_EXIT;
  132. }
  133. void ChromeBrowserMainPartsPosix::PostCreateMainMessageLoop() {
  134. ChromeBrowserMainParts::PostCreateMainMessageLoop();
  135. // Exit in response to SIGINT, SIGTERM, etc.
  136. InstallShutdownSignalHandlers(
  137. base::BindOnce(&ExitHandler::ExitWhenPossibleOnUIThread),
  138. content::GetUIThreadTaskRunner({}));
  139. }
  140. void ChromeBrowserMainPartsPosix::ShowMissingLocaleMessageBox() {
  141. #if BUILDFLAG(IS_CHROMEOS_ASH)
  142. NOTREACHED(); // Should not ever happen on ChromeOS.
  143. #elif BUILDFLAG(IS_MAC)
  144. // Not called on Mac because we load the locale files differently.
  145. NOTREACHED();
  146. #elif defined(USE_AURA)
  147. // TODO(port): We may want a views based message dialog here eventually, but
  148. // for now, crash.
  149. NOTREACHED();
  150. #else
  151. #error "Need MessageBox implementation."
  152. #endif
  153. }