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