Support SizeClassIdiom on iOS7.
[chromium-blink-merge.git] / chrome / browser / chrome_browser_main_posix.cc
blob4ae63979aa6f1a00e05e643507f56ebf9555fc7a
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"
7 #include <errno.h>
8 #include <limits.h>
9 #include <pthread.h>
10 #include <signal.h>
11 #include <sys/resource.h>
12 #include <unistd.h>
14 #include <string>
16 #include "base/bind.h"
17 #include "base/command_line.h"
18 #include "base/logging.h"
19 #include "base/posix/eintr_wrapper.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/lifetime/application_lifetime.h"
23 #include "chrome/browser/sessions/session_restore.h"
24 #include "chrome/common/chrome_switches.h"
25 #include "content/public/browser/browser_thread.h"
27 using content::BrowserThread;
29 namespace {
31 // See comment in |PreEarlyInitialization()|, where sigaction is called.
32 void SIGCHLDHandler(int signal) {
35 // The OSX fork() implementation can crash in the child process before
36 // fork() returns. In that case, the shutdown pipe will still be
37 // shared with the parent process. To prevent child crashes from
38 // causing parent shutdowns, |g_pipe_pid| is the pid for the process
39 // which registered |g_shutdown_pipe_write_fd|.
40 // See <http://crbug.com/175341>.
41 pid_t g_pipe_pid = -1;
42 int g_shutdown_pipe_write_fd = -1;
43 int g_shutdown_pipe_read_fd = -1;
45 // Common code between SIG{HUP, INT, TERM}Handler.
46 void GracefulShutdownHandler(int signal) {
47 // Reinstall the default handler. We had one shot at graceful shutdown.
48 struct sigaction action;
49 memset(&action, 0, sizeof(action));
50 action.sa_handler = SIG_DFL;
51 RAW_CHECK(sigaction(signal, &action, NULL) == 0);
53 RAW_CHECK(g_pipe_pid == getpid());
54 RAW_CHECK(g_shutdown_pipe_write_fd != -1);
55 RAW_CHECK(g_shutdown_pipe_read_fd != -1);
56 size_t bytes_written = 0;
57 do {
58 int rv = HANDLE_EINTR(
59 write(g_shutdown_pipe_write_fd,
60 reinterpret_cast<const char*>(&signal) + bytes_written,
61 sizeof(signal) - bytes_written));
62 RAW_CHECK(rv >= 0);
63 bytes_written += rv;
64 } while (bytes_written < sizeof(signal));
67 // See comment in |PostMainMessageLoopStart()|, where sigaction is called.
68 void SIGHUPHandler(int signal) {
69 RAW_CHECK(signal == SIGHUP);
70 GracefulShutdownHandler(signal);
73 // See comment in |PostMainMessageLoopStart()|, where sigaction is called.
74 void SIGINTHandler(int signal) {
75 RAW_CHECK(signal == SIGINT);
76 GracefulShutdownHandler(signal);
79 // See comment in |PostMainMessageLoopStart()|, where sigaction is called.
80 void SIGTERMHandler(int signal) {
81 RAW_CHECK(signal == SIGTERM);
82 GracefulShutdownHandler(signal);
85 // ExitHandler takes care of servicing an exit (from a signal) at the
86 // appropriate time. Specifically if we get an exit and have not finished
87 // session restore we delay the exit. To do otherwise means we're exiting part
88 // way through startup which causes all sorts of problems.
89 class ExitHandler {
90 public:
91 // Invokes exit when appropriate.
92 static void ExitWhenPossibleOnUIThread();
94 private:
95 ExitHandler();
96 ~ExitHandler();
98 // Called when a session restore has finished.
99 void OnSessionRestoreDone(int num_tabs_restored);
101 // Does the appropriate call to Exit.
102 static void Exit();
104 // Points to the on-session-restored callback that was registered with
105 // SessionRestore's callback list. When objects of this class are destroyed,
106 // the subscription object's destructor will automatically unregister the
107 // callback in SessionRestore, so that the callback list does not contain any
108 // obsolete callbacks.
109 SessionRestore::CallbackSubscription
110 on_session_restored_callback_subscription_;
112 DISALLOW_COPY_AND_ASSIGN(ExitHandler);
115 // static
116 void ExitHandler::ExitWhenPossibleOnUIThread() {
117 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
118 if (SessionRestore::IsRestoringSynchronously()) {
119 // ExitHandler takes care of deleting itself.
120 new ExitHandler();
121 } else {
122 Exit();
126 ExitHandler::ExitHandler() {
127 on_session_restored_callback_subscription_ =
128 SessionRestore::RegisterOnSessionRestoredCallback(
129 base::Bind(&ExitHandler::OnSessionRestoreDone,
130 base::Unretained(this)));
133 ExitHandler::~ExitHandler() {
136 void ExitHandler::OnSessionRestoreDone(int /* num_tabs */) {
137 if (!SessionRestore::IsRestoringSynchronously()) {
138 // At this point the message loop may not be running (meaning we haven't
139 // gotten through browser startup, but are close). Post the task to at which
140 // point the message loop is running.
141 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
142 base::Bind(&ExitHandler::Exit));
143 delete this;
147 // static
148 void ExitHandler::Exit() {
149 #if defined(OS_CHROMEOS)
150 // On ChromeOS, exiting on signal should be always clean.
151 chrome::ExitCleanly();
152 #else
153 chrome::AttemptExit();
154 #endif
157 class ShutdownDetector : public base::PlatformThread::Delegate {
158 public:
159 explicit ShutdownDetector(int shutdown_fd);
161 void ThreadMain() override;
163 private:
164 const int shutdown_fd_;
166 DISALLOW_COPY_AND_ASSIGN(ShutdownDetector);
169 ShutdownDetector::ShutdownDetector(int shutdown_fd)
170 : shutdown_fd_(shutdown_fd) {
171 CHECK_NE(shutdown_fd_, -1);
174 // These functions are used to help us diagnose crash dumps that happen
175 // during the shutdown process.
176 NOINLINE void ShutdownFDReadError() {
177 // Ensure function isn't optimized away.
178 asm("");
179 sleep(UINT_MAX);
182 NOINLINE void ShutdownFDClosedError() {
183 // Ensure function isn't optimized away.
184 asm("");
185 sleep(UINT_MAX);
188 NOINLINE void ExitPosted() {
189 // Ensure function isn't optimized away.
190 asm("");
191 sleep(UINT_MAX);
194 void ShutdownDetector::ThreadMain() {
195 base::PlatformThread::SetName("CrShutdownDetector");
197 int signal;
198 size_t bytes_read = 0;
199 ssize_t ret;
200 do {
201 ret = HANDLE_EINTR(
202 read(shutdown_fd_,
203 reinterpret_cast<char*>(&signal) + bytes_read,
204 sizeof(signal) - bytes_read));
205 if (ret < 0) {
206 NOTREACHED() << "Unexpected error: " << strerror(errno);
207 ShutdownFDReadError();
208 break;
209 } else if (ret == 0) {
210 NOTREACHED() << "Unexpected closure of shutdown pipe.";
211 ShutdownFDClosedError();
212 break;
214 bytes_read += ret;
215 } while (bytes_read < sizeof(signal));
216 VLOG(1) << "Handling shutdown for signal " << signal << ".";
217 base::Closure task = base::Bind(&ExitHandler::ExitWhenPossibleOnUIThread);
219 if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task)) {
220 // Without a UI thread to post the exit task to, there aren't many
221 // options. Raise the signal again. The default handler will pick it up
222 // and cause an ungraceful exit.
223 RAW_LOG(WARNING, "No UI thread, exiting ungracefully.");
224 kill(getpid(), signal);
226 // The signal may be handled on another thread. Give that a chance to
227 // happen.
228 sleep(3);
230 // We really should be dead by now. For whatever reason, we're not. Exit
231 // immediately, with the exit status set to the signal number with bit 8
232 // set. On the systems that we care about, this exit status is what is
233 // normally used to indicate an exit by this signal's default handler.
234 // This mechanism isn't a de jure standard, but even in the worst case, it
235 // should at least result in an immediate exit.
236 RAW_LOG(WARNING, "Still here, exiting really ungracefully.");
237 _exit(signal | (1 << 7));
239 ExitPosted();
242 } // namespace
244 // ChromeBrowserMainPartsPosix -------------------------------------------------
246 ChromeBrowserMainPartsPosix::ChromeBrowserMainPartsPosix(
247 const content::MainFunctionParams& parameters)
248 : ChromeBrowserMainParts(parameters) {
251 void ChromeBrowserMainPartsPosix::PreEarlyInitialization() {
252 ChromeBrowserMainParts::PreEarlyInitialization();
254 // We need to accept SIGCHLD, even though our handler is a no-op because
255 // otherwise we cannot wait on children. (According to POSIX 2001.)
256 struct sigaction action;
257 memset(&action, 0, sizeof(action));
258 action.sa_handler = SIGCHLDHandler;
259 CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
262 void ChromeBrowserMainPartsPosix::PostMainMessageLoopStart() {
263 ChromeBrowserMainParts::PostMainMessageLoopStart();
265 int pipefd[2];
266 int ret = pipe(pipefd);
267 if (ret < 0) {
268 PLOG(DFATAL) << "Failed to create pipe";
269 } else {
270 g_pipe_pid = getpid();
271 g_shutdown_pipe_read_fd = pipefd[0];
272 g_shutdown_pipe_write_fd = pipefd[1];
273 #if !defined(ADDRESS_SANITIZER) && !defined(KEEP_SHADOW_STACKS)
274 const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 2;
275 #else
276 // ASan instrumentation and -finstrument-functions (used for keeping the
277 // shadow stacks) bloat the stack frames, so we need to increase the stack
278 // size to avoid hitting the guard page.
279 const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 4;
280 #endif
281 // TODO(viettrungluu,willchan): crbug.com/29675 - This currently leaks, so
282 // if you change this, you'll probably need to change the suppression.
283 if (!base::PlatformThread::CreateNonJoinable(
284 kShutdownDetectorThreadStackSize,
285 new ShutdownDetector(g_shutdown_pipe_read_fd))) {
286 LOG(DFATAL) << "Failed to create shutdown detector task.";
289 // Setup signal handlers for shutdown AFTER shutdown pipe is setup because
290 // it may be called right away after handler is set.
292 // If adding to this list of signal handlers, note the new signal probably
293 // needs to be reset in child processes. See
294 // base/process_util_posix.cc:LaunchProcess.
296 // We need to handle SIGTERM, because that is how many POSIX-based distros ask
297 // processes to quit gracefully at shutdown time.
298 struct sigaction action;
299 memset(&action, 0, sizeof(action));
300 action.sa_handler = SIGTERMHandler;
301 CHECK(sigaction(SIGTERM, &action, NULL) == 0);
302 // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If
303 // the browser process is being debugged, GDB will catch the SIGINT first.
304 action.sa_handler = SIGINTHandler;
305 CHECK(sigaction(SIGINT, &action, NULL) == 0);
306 // And SIGHUP, for when the terminal disappears. On shutdown, many Linux
307 // distros send SIGHUP, SIGTERM, and then SIGKILL.
308 action.sa_handler = SIGHUPHandler;
309 CHECK(sigaction(SIGHUP, &action, NULL) == 0);
312 void ChromeBrowserMainPartsPosix::ShowMissingLocaleMessageBox() {
313 #if defined(OS_CHROMEOS)
314 NOTREACHED(); // Should not ever happen on ChromeOS.
315 #elif defined(OS_MACOSX)
316 // Not called on Mac because we load the locale files differently.
317 NOTREACHED();
318 #elif defined(USE_AURA)
319 // TODO(port): We may want a views based message dialog here eventually, but
320 // for now, crash.
321 NOTREACHED();
322 #else
323 #error "Need MessageBox implementation."
324 #endif