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.
5 #include "chrome/browser/chrome_browser_main_posix.h"
12 #include <sys/resource.h>
16 #include "base/bind.h"
17 #include "base/check_op.h"
18 #include "base/macros.h"
19 #include "base/notreached.h"
20 #include "build/build_config.h"
21 #include "chrome/app/shutdown_signal_handlers_posix.h"
22 #include "chrome/browser/lifetime/application_lifetime.h"
23 #include "chrome/browser/sessions/session_restore.h"
24 #include "content/public/browser/browser_task_traits.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/common/result_codes.h"
28 using content::BrowserThread;
32 // See comment in |PreEarlyInitialization()|, where sigaction is called.
33 void SIGCHLDHandler(int signal) {
36 // ExitHandler takes care of servicing an exit (from a signal) at the
37 // appropriate time. Specifically if we get an exit and have not finished
38 // session restore we delay the exit. To do otherwise means we're exiting part
39 // way through startup which causes all sorts of problems.
42 // Invokes exit when appropriate.
43 static void ExitWhenPossibleOnUIThread(int signal);
49 // Called when a session restore has finished.
50 void OnSessionRestoreDone(int num_tabs_restored);
52 // Does the appropriate call to Exit.
55 // Points to the on-session-restored callback that was registered with
56 // SessionRestore's callback list. When objects of this class are destroyed,
57 // the subscription object's destructor will automatically unregister the
58 // callback in SessionRestore, so that the callback list does not contain any
59 // obsolete callbacks.
60 SessionRestore::CallbackSubscription
61 on_session_restored_callback_subscription_;
63 DISALLOW_COPY_AND_ASSIGN(ExitHandler);
67 void ExitHandler::ExitWhenPossibleOnUIThread(int signal) {
68 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
69 if (SessionRestore::IsRestoringSynchronously()) {
70 // ExitHandler takes care of deleting itself.
73 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
77 // SIGINT gets sent when the user types Ctrl+C, but the session is
78 // likely not going away, so try to exit gracefully. SIGHUP is sent on
79 // most systems as a first warning of shutdown. If the process takes
80 // too long to quit, the next signal is usually SIGTERM.
84 // SIGTERM is usually sent instead of SIGKILL to gracefully shutdown
85 // processes. But most systems use it as a shutdown warning, so
86 // conservatively assume that the session is ending. If the process
87 // still doesn't quit within a bounded time, most systems will finally
88 // send SIGKILL, which we're unable to install a signal handler for.
89 // TODO(thomasanderson): Try to distinguish if the session is really
90 // ending or not. Maybe there's a systemd or DBus API to query.
91 chrome::SessionEnding();
102 ExitHandler::ExitHandler() {
103 on_session_restored_callback_subscription_ =
104 SessionRestore::RegisterOnSessionRestoredCallback(
105 base::Bind(&ExitHandler::OnSessionRestoreDone,
106 base::Unretained(this)));
109 ExitHandler::~ExitHandler() {
112 void ExitHandler::OnSessionRestoreDone(int /* num_tabs */) {
113 if (!SessionRestore::IsRestoringSynchronously()) {
114 // At this point the message loop may not be running (meaning we haven't
115 // gotten through browser startup, but are close). Post the task to at which
116 // point the message loop is running.
117 content::GetUIThreadTaskRunner({})->PostTask(
118 FROM_HERE, base::BindOnce(&ExitHandler::Exit));
124 void ExitHandler::Exit() {
125 #if defined(OS_CHROMEOS)
126 // On ChromeOS, exiting on signal should be always clean.
127 chrome::ExitIgnoreUnloadHandlers();
129 chrome::AttemptExit();
135 // ChromeBrowserMainPartsPosix -------------------------------------------------
137 ChromeBrowserMainPartsPosix::ChromeBrowserMainPartsPosix(
138 const content::MainFunctionParams& parameters,
139 StartupData* startup_data)
140 : ChromeBrowserMainParts(parameters, startup_data) {}
142 int ChromeBrowserMainPartsPosix::PreEarlyInitialization() {
143 const int result = ChromeBrowserMainParts::PreEarlyInitialization();
144 if (result != service_manager::RESULT_CODE_NORMAL_EXIT)
147 // We need to accept SIGCHLD, even though our handler is a no-op because
148 // otherwise we cannot wait on children. (According to POSIX 2001.)
149 struct sigaction action;
150 memset(&action, 0, sizeof(action));
151 action.sa_handler = SIGCHLDHandler;
152 CHECK_EQ(0, sigaction(SIGCHLD, &action, NULL));
154 return service_manager::RESULT_CODE_NORMAL_EXIT;
157 void ChromeBrowserMainPartsPosix::PostMainMessageLoopStart() {
158 ChromeBrowserMainParts::PostMainMessageLoopStart();
160 // Exit in response to SIGINT, SIGTERM, etc.
161 InstallShutdownSignalHandlers(
162 base::BindOnce(&ExitHandler::ExitWhenPossibleOnUIThread),
163 content::GetUIThreadTaskRunner({}));
166 void ChromeBrowserMainPartsPosix::ShowMissingLocaleMessageBox() {
167 #if defined(OS_CHROMEOS)
168 NOTREACHED(); // Should not ever happen on ChromeOS.
169 #elif defined(OS_MACOSX)
170 // Not called on Mac because we load the locale files differently.
172 #elif defined(USE_AURA)
173 // TODO(port): We may want a views based message dialog here eventually, but
177 #error "Need MessageBox implementation."