Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(90)

Side by Side Diff: chrome/browser/process_singleton_linux.cc

Issue 155772: This CL implements the second TODO item of issue 12343:... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/process_singleton.h ('k') | chrome/browser/process_singleton_linux_uitest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // On Linux, when the user tries to launch a second copy of chrome, we check 5 // On Linux, when the user tries to launch a second copy of chrome, we check
6 // for a socket in the user's profile directory. If the socket file is open we 6 // for a socket in the user's profile directory. If the socket file is open we
7 // send a message to the first chrome browser process with the current 7 // send a message to the first chrome browser process with the current
8 // directory and second process command line flags. The second process then 8 // directory and second process command line flags. The second process then
9 // exits. 9 // exits.
10 //
11 // The socket file's name contains the process id of chrome's browser process,
12 // eg. "SingletonSocket-9156". A symbol link named "SingletonSocket" will be
13 // created and pointed to the real socket file, so they would look like:
14 //
15 // SingletonSocket -> SingletonSocket-9156
16 // SingletonSocket-9156
17 //
18 // So that the socket file can be connected through "SingletonSocket" and the
19 // process id can also be retrieved from it by calling readlink().
20 //
21 // When the second process sends the current directory and command line flags to
22 // the first process, it waits for an ACK message back from the first process
23 // for a certain time. If there is no ACK message back in time, then the first
24 // process will be considered as hung for some reason. The second process then
25 // retrieves the process id from the symbol link and kills it by sending
26 // SIGKILL. Then the second process starts as normal.
27 //
28 // TODO(james.su@gmail.com): Add unittest for this class.
10 29
11 #include "chrome/browser/process_singleton.h" 30 #include "chrome/browser/process_singleton.h"
12 31
13 #include <errno.h> 32 #include <errno.h>
14 #include <fcntl.h> 33 #include <fcntl.h>
15 #include <sys/types.h> 34 #include <sys/types.h>
16 #include <sys/socket.h> 35 #include <sys/socket.h>
36 #include <sys/stat.h>
17 #include <sys/un.h> 37 #include <sys/un.h>
38 #include <signal.h>
39 #include <unistd.h>
40 #include <cstring>
18 #include <set> 41 #include <set>
42 #include <string>
19 43
20 #include "base/base_paths.h" 44 #include "base/base_paths.h"
21 #include "base/basictypes.h" 45 #include "base/basictypes.h"
22 #include "base/command_line.h" 46 #include "base/command_line.h"
23 #include "base/eintr_wrapper.h" 47 #include "base/eintr_wrapper.h"
24 #include "base/logging.h" 48 #include "base/logging.h"
25 #include "base/message_loop.h" 49 #include "base/message_loop.h"
26 #include "base/path_service.h" 50 #include "base/path_service.h"
51 #include "base/process_util.h"
27 #include "base/stl_util-inl.h" 52 #include "base/stl_util-inl.h"
28 #include "base/string_util.h" 53 #include "base/string_util.h"
29 #include "base/time.h" 54 #include "base/time.h"
30 #include "base/timer.h" 55 #include "base/timer.h"
31 #include "chrome/browser/browser_init.h" 56 #include "chrome/browser/browser_init.h"
32 #include "chrome/browser/browser_process.h" 57 #include "chrome/browser/browser_process.h"
33 #include "chrome/browser/chrome_thread.h" 58 #include "chrome/browser/chrome_thread.h"
34 #include "chrome/browser/profile.h" 59 #include "chrome/browser/profile.h"
35 #include "chrome/browser/profile_manager.h" 60 #include "chrome/browser/profile_manager.h"
36 #include "chrome/common/chrome_constants.h" 61 #include "chrome/common/chrome_constants.h"
37 #include "chrome/common/chrome_paths.h" 62 #include "chrome/common/chrome_paths.h"
38 63
64 const int ProcessSingleton::kTimeoutInSeconds;
65
39 namespace { 66 namespace {
40 67
41 const char kStartToken[] = "START"; 68 const char kStartToken[] = "START";
69 const char kACKToken[] = "ACK";
70 const char kShutdownToken[] = "SHUTDOWN";
42 const char kTokenDelimiter = '\0'; 71 const char kTokenDelimiter = '\0';
43 const int kTimeOutInSeconds = 5;
44 const int kMaxMessageLength = 32 * 1024; 72 const int kMaxMessageLength = 32 * 1024;
73 const int kMaxACKMessageLength = arraysize(kShutdownToken) - 1;
45 74
46 // Return 0 on success, -1 on failure. 75 // Return 0 on success, -1 on failure.
47 int SetNonBlocking(int fd) { 76 int SetNonBlocking(int fd) {
48 int flags = fcntl(fd, F_GETFL, 0); 77 int flags = fcntl(fd, F_GETFL, 0);
49 if (-1 == flags) 78 if (-1 == flags)
50 return flags; 79 return flags;
51 if (flags & O_NONBLOCK) 80 if (flags & O_NONBLOCK)
52 return 0; 81 return 0;
53 return fcntl(fd, F_SETFL, flags | O_NONBLOCK); 82 return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
54 } 83 }
55 84
85 // Close a socket and check return value.
86 void CloseSocket(int fd) {
87 int rv = HANDLE_EINTR(close(fd));
88 DCHECK_EQ(0, rv) << "Error closing socket: " << strerror(errno);
89 }
90
91 // Write a message to a socket fd.
92 bool WriteToSocket(int fd, const char *message, size_t length) {
93 DCHECK(message);
94 DCHECK(length);
95 size_t bytes_written = 0;
96 do {
97 ssize_t rv = HANDLE_EINTR(
98 write(fd, message + bytes_written, length - bytes_written));
99 if (rv < 0) {
100 if (errno == EAGAIN || errno == EWOULDBLOCK) {
101 // The socket shouldn't block, we're sending so little data. Just give
102 // up here, since NotifyOtherProcess() doesn't have an asynchronous api.
103 LOG(ERROR) << "ProcessSingleton would block on write(), so it gave up.";
104 return false;
105 }
106 LOG(ERROR) << "write() failed: " << strerror(errno);
107 return false;
108 }
109 bytes_written += rv;
110 } while (bytes_written < length);
111
112 return true;
113 }
114
115 // Wait a socket for read for a certain timeout in seconds.
116 // Returns -1 if error occurred, 0 if timeout reached, > 0 if the socket is
117 // ready for read.
118 int WaitSocketForRead(int fd, int timeout) {
119 fd_set read_fds;
120 struct timeval tv;
121
122 FD_ZERO(&read_fds);
123 FD_SET(fd, &read_fds);
124 tv.tv_sec = timeout;
125 tv.tv_usec = 0;
126
127 return HANDLE_EINTR(select(fd + 1, &read_fds, NULL, NULL, &tv));
128 }
129
130 // Read a message from a socket fd, with an optional timeout in seconds.
131 // If |timeout| <= 0 then read immediately.
132 // Return number of bytes actually read, or -1 on error.
133 ssize_t ReadFromSocket(int fd, char *buf, size_t bufsize, int timeout) {
134 if (timeout > 0) {
135 int rv = WaitSocketForRead(fd, timeout);
136 if (rv <= 0)
137 return rv;
138 }
139
140 size_t bytes_read = 0;
141 do {
142 ssize_t rv = HANDLE_EINTR(read(fd, buf + bytes_read, bufsize - bytes_read));
143 if (rv < 0) {
144 if (errno != EAGAIN && errno != EWOULDBLOCK) {
145 LOG(ERROR) << "read() failed: " << strerror(errno);
146 return rv;
147 } else {
148 // It would block, so we just return what has been read.
149 return bytes_read;
150 }
151 } else if (!rv) {
152 // No more data to read.
153 return bytes_read;
154 } else {
155 bytes_read += rv;
156 }
157 } while (bytes_read < bufsize);
158
159 return bytes_read;
160 }
161
162 // Set up a socket and sockaddr appropriate for messaging.
163 void SetupSocket(const std::string& path, int* sock, struct sockaddr_un* addr) {
164 *sock = socket(PF_UNIX, SOCK_STREAM, 0);
165 CHECK(*sock >= 0) << "socket() failed: " << strerror(errno);
166
167 int rv = SetNonBlocking(*sock);
168 DCHECK_EQ(0, rv) << "Failed to make non-blocking socket.";
169
170 addr->sun_family = AF_UNIX;
171 CHECK(path.length() < arraysize(addr->sun_path))
172 << "Socket path too long: " << path;
173 base::strlcpy(addr->sun_path, path.c_str(), arraysize(addr->sun_path));
174 }
175
176 // Read a symbol link, return empty string if given path is not a symbol link.
177 std::string ReadLink(const std::string& path) {
178 struct stat statbuf;
179
180 if (lstat(path.c_str(), &statbuf) < 0) {
181 DCHECK_EQ(errno, ENOENT);
182 return std::string();
183 }
184
185 if (S_ISLNK(statbuf.st_mode)) {
186 char buf[PATH_MAX + 1];
187 ssize_t len = readlink(path.c_str(), buf, PATH_MAX);
188 if (len > 0) {
189 buf[len] = '\0';
190 FilePath real_path(buf);
191 // If it's not an absolute path, then it's necessary to prepend the
192 // original path's dirname.
193 if (!real_path.IsAbsolute()) {
194 real_path = FilePath(path).DirName().Append(real_path);
195 }
196 return real_path.value();
197 } else {
198 LOG(ERROR) << "readlink(" << path << ") failed: " << strerror(errno);
199 }
200 }
201
202 return std::string();
203 }
204
205 // Unlink a socket path. If the path is a symbol link, then the symbol link
206 // and the real path referenced by the symbol link will be unlinked together.
207 bool UnlinkSocketPath(const std::string& path) {
208 std::string real_path = ReadLink(path);
209
210 bool ret = true;
211 if (real_path.length())
212 ret = UnlinkSocketPath(real_path);
213
214 int rv = unlink(path.c_str());
215 if (rv < 0)
216 DCHECK_EQ(errno, ENOENT);
217
218 return rv == 0 && ret;
219 }
220
221 // Extract the process's pid from a symbol link path and kill it.
222 // The pid will be appended to the end of path with a preceding dash, such as:
223 // .../SingletonSocket-1234
224 void KillProcessBySocketPath(const std::string& path) {
225 std::string real_path = ReadLink(path);
226
227 // If the path is not a symbol link, try to extract pid from the path itself.
228 if (real_path.empty())
229 real_path = path;
230
231 // Only extract pid from the base name, to avoid finding wrong value from its
232 // parent path name.
233 std::string base_name = FilePath(real_path).BaseName().value();
234 DCHECK(base_name.length());
235
236 std::string::size_type pos = base_name.rfind('-');
237 if (pos != std::string::npos) {
238 std::string pid_str = base_name.substr(pos + 1);
239 int pid;
240 if (StringToInt(pid_str, &pid)) {
241 // TODO(james.su@gmail.com): Is SIGKILL ok?
242 int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL);
243 DCHECK_EQ(0, rv) << "Error killing process:" << strerror(errno);
244 return;
245 }
246 }
247
248 LOG(ERROR) << "Failed to extract pid from path: " << real_path;
249 }
250
251 // A helper class to close a socket automatically.
252 class SocketCloser {
253 public:
254 explicit SocketCloser(int fd) : fd_(fd) { }
255 ~SocketCloser() { CloseSocket(fd_); }
256 private:
257 int fd_;
258 };
259
56 } // namespace 260 } // namespace
57 261
58 /////////////////////////////////////////////////////////////////////////////// 262 ///////////////////////////////////////////////////////////////////////////////
59 // ProcessSingleton::LinuxWatcher 263 // ProcessSingleton::LinuxWatcher
60 // A helper class for a Linux specific implementation of the process singleton. 264 // A helper class for a Linux specific implementation of the process singleton.
61 // This class sets up a listener on the singleton socket and handles parsing 265 // This class sets up a listener on the singleton socket and handles parsing
62 // messages that come in on the singleton socket. 266 // messages that come in on the singleton socket.
63 class ProcessSingleton::LinuxWatcher 267 class ProcessSingleton::LinuxWatcher
64 : public MessageLoopForIO::Watcher, 268 : public MessageLoopForIO::Watcher,
65 public MessageLoop::DestructionObserver, 269 public MessageLoop::DestructionObserver,
66 public base::RefCountedThreadSafe<ProcessSingleton::LinuxWatcher> { 270 public base::RefCountedThreadSafe<ProcessSingleton::LinuxWatcher> {
67 public: 271 public:
68 // We expect to only be constructed on the UI thread. 272 // A helper class to read message from an established socket.
69 explicit LinuxWatcher(ProcessSingleton* parent)
70 : ui_message_loop_(MessageLoop::current()),
71 parent_(parent) {
72 }
73
74 virtual ~LinuxWatcher() {
75 STLDeleteElements(&readers_);
76 }
77
78 // Start listening for connections on the socket. This method should be
79 // called from the IO thread.
80 void StartListening(int socket);
81
82 // This method determines if we should use the same process and if we should,
83 // opens a new browser tab. This runs on the UI thread.
84 void HandleMessage(std::string current_dir, std::vector<std::string> argv);
85
86 // MessageLoopForIO::Watcher impl. These run on the IO thread.
87 virtual void OnFileCanReadWithoutBlocking(int fd);
88 virtual void OnFileCanWriteWithoutBlocking(int fd) {
89 // ProcessSingleton only watches for accept (read) events.
90 NOTREACHED();
91 }
92
93 // MessageLoop::DestructionObserver
94 virtual void WillDestroyCurrentMessageLoop() {
95 fd_watcher_.StopWatchingFileDescriptor();
96 }
97
98 private:
99 class SocketReader : public MessageLoopForIO::Watcher { 273 class SocketReader : public MessageLoopForIO::Watcher {
100 public: 274 public:
101 SocketReader(ProcessSingleton::LinuxWatcher* parent, 275 SocketReader(ProcessSingleton::LinuxWatcher* parent,
102 MessageLoop* ui_message_loop, 276 MessageLoop* ui_message_loop,
103 int fd) 277 int fd)
104 : parent_(parent), 278 : parent_(parent),
105 ui_message_loop_(ui_message_loop), 279 ui_message_loop_(ui_message_loop),
106 fd_(fd), 280 fd_(fd),
107 bytes_read_(0) { 281 bytes_read_(0) {
108 // Wait for reads. 282 // Wait for reads.
109 MessageLoopForIO::current()->WatchFileDescriptor( 283 MessageLoopForIO::current()->WatchFileDescriptor(
110 fd, true, MessageLoopForIO::WATCH_READ, &fd_reader_, this); 284 fd, true, MessageLoopForIO::WATCH_READ, &fd_reader_, this);
111 timer_.Start(base::TimeDelta::FromSeconds(kTimeOutInSeconds), 285 timer_.Start(base::TimeDelta::FromSeconds(kTimeoutInSeconds),
112 this, &SocketReader::OnTimerExpiry); 286 this, &SocketReader::OnTimerExpiry);
113 } 287 }
114 288
115 virtual ~SocketReader() { 289 virtual ~SocketReader() {
116 int rv = HANDLE_EINTR(close(fd_)); 290 CloseSocket(fd_);
117 DCHECK_EQ(0, rv) << "Error closing socket: " << strerror(errno);
118 } 291 }
119 292
120 // MessageLoopForIO::Watcher impl. 293 // MessageLoopForIO::Watcher impl.
121 virtual void OnFileCanReadWithoutBlocking(int fd); 294 virtual void OnFileCanReadWithoutBlocking(int fd);
122 virtual void OnFileCanWriteWithoutBlocking(int fd) { 295 virtual void OnFileCanWriteWithoutBlocking(int fd) {
123 // SocketReader only watches for accept (read) events. 296 // SocketReader only watches for accept (read) events.
124 NOTREACHED(); 297 NOTREACHED();
125 } 298 }
126 299
300 // Finish handling the incoming message by optionally sending back an ACK
301 // message and removing this SocketReader.
302 void FinishWithACK(const char *message, size_t length);
303
127 private: 304 private:
128 // If we haven't completed in a reasonable amount of time, give up. 305 // If we haven't completed in a reasonable amount of time, give up.
129 void OnTimerExpiry() { 306 void OnTimerExpiry() {
130 parent_->RemoveSocketReader(this); 307 parent_->RemoveSocketReader(this);
131 // We're deleted beyond this point. 308 // We're deleted beyond this point.
132 } 309 }
133 310
134 MessageLoopForIO::FileDescriptorWatcher fd_reader_; 311 MessageLoopForIO::FileDescriptorWatcher fd_reader_;
135 312
136 // The ProcessSingleton::LinuxWatcher that owns us. 313 // The ProcessSingleton::LinuxWatcher that owns us.
(...skipping 10 matching lines...) Expand all
147 324
148 // Tracks the number of bytes we've read in case we're getting partial 325 // Tracks the number of bytes we've read in case we're getting partial
149 // reads. 326 // reads.
150 size_t bytes_read_; 327 size_t bytes_read_;
151 328
152 base::OneShotTimer<SocketReader> timer_; 329 base::OneShotTimer<SocketReader> timer_;
153 330
154 DISALLOW_COPY_AND_ASSIGN(SocketReader); 331 DISALLOW_COPY_AND_ASSIGN(SocketReader);
155 }; 332 };
156 333
334 // We expect to only be constructed on the UI thread.
335 explicit LinuxWatcher(ProcessSingleton* parent)
336 : ui_message_loop_(MessageLoop::current()),
337 parent_(parent) {
338 }
339
340 virtual ~LinuxWatcher() {
341 STLDeleteElements(&readers_);
342 }
343
344 // Start listening for connections on the socket. This method should be
345 // called from the IO thread.
346 void StartListening(int socket);
347
348 // This method determines if we should use the same process and if we should,
349 // opens a new browser tab. This runs on the UI thread.
350 // |reader| is for sending back ACK message.
351 void HandleMessage(const std::string& current_dir,
352 const std::vector<std::string>& argv,
353 SocketReader *reader);
354
355 // MessageLoopForIO::Watcher impl. These run on the IO thread.
356 virtual void OnFileCanReadWithoutBlocking(int fd);
357 virtual void OnFileCanWriteWithoutBlocking(int fd) {
358 // ProcessSingleton only watches for accept (read) events.
359 NOTREACHED();
360 }
361
362 // MessageLoop::DestructionObserver
363 virtual void WillDestroyCurrentMessageLoop() {
364 fd_watcher_.StopWatchingFileDescriptor();
365 }
366
367 private:
157 // Removes and deletes the SocketReader. 368 // Removes and deletes the SocketReader.
158 void RemoveSocketReader(SocketReader* reader); 369 void RemoveSocketReader(SocketReader* reader);
159 370
160 MessageLoopForIO::FileDescriptorWatcher fd_watcher_; 371 MessageLoopForIO::FileDescriptorWatcher fd_watcher_;
161 372
162 // A reference to the UI message loop (i.e., the message loop we were 373 // A reference to the UI message loop (i.e., the message loop we were
163 // constructed on). 374 // constructed on).
164 MessageLoop* ui_message_loop_; 375 MessageLoop* ui_message_loop_;
165 376
166 // The ProcessSingleton that owns us. 377 // The ProcessSingleton that owns us.
167 ProcessSingleton* const parent_; 378 ProcessSingleton* const parent_;
168 379
169 std::set<SocketReader*> readers_; 380 std::set<SocketReader*> readers_;
170 381
171 DISALLOW_COPY_AND_ASSIGN(LinuxWatcher); 382 DISALLOW_COPY_AND_ASSIGN(LinuxWatcher);
172 }; 383 };
173 384
174 void ProcessSingleton::LinuxWatcher::OnFileCanReadWithoutBlocking(int fd) { 385 void ProcessSingleton::LinuxWatcher::OnFileCanReadWithoutBlocking(int fd) {
175 // Accepting incoming client. 386 // Accepting incoming client.
176 sockaddr_un from; 387 sockaddr_un from;
177 socklen_t from_len = sizeof(from); 388 socklen_t from_len = sizeof(from);
178 int connection_socket = HANDLE_EINTR(accept( 389 int connection_socket = HANDLE_EINTR(accept(
179 fd, reinterpret_cast<sockaddr*>(&from), &from_len)); 390 fd, reinterpret_cast<sockaddr*>(&from), &from_len));
180 if (-1 == connection_socket) { 391 if (-1 == connection_socket) {
181 LOG(ERROR) << "accept() failed: " << strerror(errno); 392 LOG(ERROR) << "accept() failed: " << strerror(errno);
182 return; 393 return;
183 } 394 }
395 int rv = SetNonBlocking(connection_socket);
396 DCHECK_EQ(0, rv) << "Failed to make non-blocking socket.";
184 SocketReader* reader = new SocketReader(this, 397 SocketReader* reader = new SocketReader(this,
185 ui_message_loop_, 398 ui_message_loop_,
186 connection_socket); 399 connection_socket);
187 readers_.insert(reader); 400 readers_.insert(reader);
188 } 401 }
189 402
190 void ProcessSingleton::LinuxWatcher::StartListening(int socket) { 403 void ProcessSingleton::LinuxWatcher::StartListening(int socket) {
191 DCHECK(ChromeThread::GetMessageLoop(ChromeThread::IO) == 404 DCHECK(ChromeThread::GetMessageLoop(ChromeThread::IO) ==
192 MessageLoop::current()); 405 MessageLoop::current());
193 // Watch for client connections on this socket. 406 // Watch for client connections on this socket.
194 MessageLoopForIO* ml = MessageLoopForIO::current(); 407 MessageLoopForIO* ml = MessageLoopForIO::current();
195 ml->AddDestructionObserver(this); 408 ml->AddDestructionObserver(this);
196 ml->WatchFileDescriptor(socket, true, MessageLoopForIO::WATCH_READ, 409 ml->WatchFileDescriptor(socket, true, MessageLoopForIO::WATCH_READ,
197 &fd_watcher_, this); 410 &fd_watcher_, this);
198 } 411 }
199 412
200 void ProcessSingleton::LinuxWatcher::HandleMessage(std::string current_dir, 413 void ProcessSingleton::LinuxWatcher::HandleMessage(
201 std::vector<std::string> argv) { 414 const std::string& current_dir, const std::vector<std::string>& argv,
415 SocketReader* reader) {
202 DCHECK(ui_message_loop_ == MessageLoop::current()); 416 DCHECK(ui_message_loop_ == MessageLoop::current());
417 DCHECK(reader);
203 // Ignore the request if the browser process is already in shutdown path. 418 // Ignore the request if the browser process is already in shutdown path.
204 if (!g_browser_process || g_browser_process->IsShuttingDown()) { 419 if (!g_browser_process || g_browser_process->IsShuttingDown()) {
205 LOG(WARNING) << "Not handling interprocess notification as browser" 420 LOG(WARNING) << "Not handling interprocess notification as browser"
206 " is shutting down"; 421 " is shutting down";
422 // Send back "SHUTDOWN" message, so that the client process can start up
423 // without killing this process.
424 reader->FinishWithACK(kShutdownToken, arraysize(kShutdownToken) - 1);
207 return; 425 return;
208 } 426 }
209 427
210 // If locked, it means we are not ready to process this message because 428 // If locked, it means we are not ready to process this message because
211 // we are probably in a first run critical phase. 429 // we are probably in a first run critical phase.
212 if (parent_->locked()) { 430 if (parent_->locked()) {
213 DLOG(WARNING) << "Browser is locked"; 431 DLOG(WARNING) << "Browser is locked";
432 // Send back "ACK" message to prevent the client process from starting up.
433 reader->FinishWithACK(kACKToken, arraysize(kACKToken) - 1);
214 return; 434 return;
215 } 435 }
216 436
217 CommandLine parsed_command_line(argv); 437 CommandLine parsed_command_line(argv);
218 PrefService* prefs = g_browser_process->local_state(); 438 PrefService* prefs = g_browser_process->local_state();
219 DCHECK(prefs); 439 DCHECK(prefs);
220 440
221 FilePath user_data_dir; 441 FilePath user_data_dir;
222 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); 442 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
223 ProfileManager* profile_manager = g_browser_process->profile_manager(); 443 ProfileManager* profile_manager = g_browser_process->profile_manager();
224 Profile* profile = profile_manager->GetDefaultProfile(user_data_dir); 444 Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
225 if (!profile) { 445 if (!profile) {
226 // We should only be able to get here if the profile already exists and 446 // We should only be able to get here if the profile already exists and
227 // has been created. 447 // has been created.
228 NOTREACHED(); 448 NOTREACHED();
229 return; 449 return;
230 } 450 }
231 451
232 // TODO(tc): Send an ACK response on success.
233
234 // Run the browser startup sequence again, with the command line of the 452 // Run the browser startup sequence again, with the command line of the
235 // signalling process. 453 // signalling process.
236 FilePath current_dir_file_path(current_dir); 454 FilePath current_dir_file_path(current_dir);
237 BrowserInit::ProcessCommandLine(parsed_command_line, 455 BrowserInit::ProcessCommandLine(parsed_command_line,
238 current_dir_file_path.ToWStringHack(), 456 current_dir_file_path.ToWStringHack(),
239 false, profile, NULL); 457 false, profile, NULL);
458
459 // Send back "ACK" message to prevent the client process from starting up.
460 reader->FinishWithACK(kACKToken, arraysize(kACKToken) - 1);
240 } 461 }
241 462
242 void ProcessSingleton::LinuxWatcher::RemoveSocketReader(SocketReader* reader) { 463 void ProcessSingleton::LinuxWatcher::RemoveSocketReader(SocketReader* reader) {
243 DCHECK(reader); 464 DCHECK(reader);
244 readers_.erase(reader); 465 readers_.erase(reader);
245 delete reader; 466 delete reader;
246 } 467 }
247 468
248 /////////////////////////////////////////////////////////////////////////////// 469 ///////////////////////////////////////////////////////////////////////////////
249 // ProcessSingleton::LinuxWatcher::SocketReader 470 // ProcessSingleton::LinuxWatcher::SocketReader
250 // 471 //
251 472
252 void ProcessSingleton::LinuxWatcher::SocketReader::OnFileCanReadWithoutBlocking( 473 void ProcessSingleton::LinuxWatcher::SocketReader::OnFileCanReadWithoutBlocking(
253 int fd) { 474 int fd) {
254 DCHECK_EQ(fd, fd_); 475 DCHECK_EQ(fd, fd_);
255 while (bytes_read_ < sizeof(buf_)) { 476 while (bytes_read_ < sizeof(buf_)) {
256 ssize_t rv = HANDLE_EINTR( 477 ssize_t rv = HANDLE_EINTR(
257 read(fd, buf_ + bytes_read_, sizeof(buf_) - bytes_read_)); 478 read(fd, buf_ + bytes_read_, sizeof(buf_) - bytes_read_));
258 if (rv < 0) { 479 if (rv < 0) {
259 if (errno != EAGAIN && errno != EWOULDBLOCK) { 480 if (errno != EAGAIN && errno != EWOULDBLOCK) {
260 LOG(ERROR) << "read() failed: " << strerror(errno); 481 LOG(ERROR) << "read() failed: " << strerror(errno);
261 rv = HANDLE_EINTR(close(fd)); 482 CloseSocket(fd);
262 DCHECK_EQ(0, rv) << "Error closing socket: " << strerror(errno);
263 return; 483 return;
264 } else { 484 } else {
265 // It would block, so we just return and continue to watch for the next 485 // It would block, so we just return and continue to watch for the next
266 // opportunity to read. 486 // opportunity to read.
267 return; 487 return;
268 } 488 }
269 } else if (!rv) { 489 } else if (!rv) {
270 // No more data to read. It's time to process the message. 490 // No more data to read. It's time to process the message.
271 break; 491 break;
272 } else { 492 } else {
(...skipping 11 matching lines...) Expand all
284 504
285 std::string str(buf_, bytes_read_); 505 std::string str(buf_, bytes_read_);
286 std::vector<std::string> tokens; 506 std::vector<std::string> tokens;
287 SplitString(str, kTokenDelimiter, &tokens); 507 SplitString(str, kTokenDelimiter, &tokens);
288 508
289 if (tokens.size() < 3 || tokens[0] != kStartToken) { 509 if (tokens.size() < 3 || tokens[0] != kStartToken) {
290 LOG(ERROR) << "Wrong message format: " << str; 510 LOG(ERROR) << "Wrong message format: " << str;
291 return; 511 return;
292 } 512 }
293 513
514 // Stop the expiration timer to prevent this SocketReader object from being
515 // terminated unexpectly.
516 timer_.Stop();
517
294 std::string current_dir = tokens[1]; 518 std::string current_dir = tokens[1];
295 // Remove the first two tokens. The remaining tokens should be the command 519 // Remove the first two tokens. The remaining tokens should be the command
296 // line argv array. 520 // line argv array.
297 tokens.erase(tokens.begin()); 521 tokens.erase(tokens.begin());
298 tokens.erase(tokens.begin()); 522 tokens.erase(tokens.begin());
299 523
300 // Return to the UI thread to handle opening a new browser tab. 524 // Return to the UI thread to handle opening a new browser tab.
301 ui_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( 525 ui_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
302 parent_, 526 parent_,
303 &ProcessSingleton::LinuxWatcher::HandleMessage, 527 &ProcessSingleton::LinuxWatcher::HandleMessage,
304 current_dir, 528 current_dir,
305 tokens)); 529 tokens,
530 this));
306 fd_reader_.StopWatchingFileDescriptor(); 531 fd_reader_.StopWatchingFileDescriptor();
307 532
533 // LinuxWatcher::HandleMessage() is in charge of destroying this SocketReader
534 // object by invoking SocketReader::FinishWithACK().
535 }
536
537 void ProcessSingleton::LinuxWatcher::SocketReader::FinishWithACK(
538 const char *message, size_t length) {
539 if (message && length) {
540 // Not necessary to care about the return value.
541 WriteToSocket(fd_, message, length);
542 }
543
544 if (shutdown(fd_, SHUT_WR) < 0)
545 LOG(ERROR) << "shutdown() failed: " << strerror(errno);
546
308 parent_->RemoveSocketReader(this); 547 parent_->RemoveSocketReader(this);
309 // We are deleted beyond this point. 548 // We are deleted beyond this point.
310 } 549 }
311 550
312 /////////////////////////////////////////////////////////////////////////////// 551 ///////////////////////////////////////////////////////////////////////////////
313 // ProcessSingleton 552 // ProcessSingleton
314 // 553 //
315 ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir) 554 ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir)
316 : locked_(false), 555 : locked_(false),
317 foreground_window_(NULL), 556 foreground_window_(NULL),
318 ALLOW_THIS_IN_INITIALIZER_LIST(watcher_(new LinuxWatcher(this))) { 557 ALLOW_THIS_IN_INITIALIZER_LIST(watcher_(new LinuxWatcher(this))) {
319 socket_path_ = user_data_dir.Append(chrome::kSingletonSocketFilename); 558 socket_path_ = user_data_dir.Append(chrome::kSingletonSocketFilename);
320 } 559 }
321 560
322 ProcessSingleton::~ProcessSingleton() { 561 ProcessSingleton::~ProcessSingleton() {
323 } 562 }
324 563
325 bool ProcessSingleton::NotifyOtherProcess() { 564 bool ProcessSingleton::NotifyOtherProcess() {
326 int socket; 565 int socket;
327 sockaddr_un addr; 566 sockaddr_un addr;
328 SetupSocket(&socket, &addr); 567 SetupSocket(socket_path_.value(), &socket, &addr);
568
569 // It'll close the socket automatically when exiting this method.
570 SocketCloser socket_closer(socket);
329 571
330 // Connecting to the socket 572 // Connecting to the socket
331 int ret = HANDLE_EINTR(connect(socket, 573 int ret = HANDLE_EINTR(connect(socket,
332 reinterpret_cast<sockaddr*>(&addr), 574 reinterpret_cast<sockaddr*>(&addr),
333 sizeof(addr))); 575 sizeof(addr)));
334 if (ret < 0) 576 if (ret < 0)
335 return false; // Tell the caller there's nobody to notify. 577 return false; // Tell the caller there's nobody to notify.
336 578
337 timeval timeout = {20, 0}; 579 timeval timeout = {20, 0};
338 setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); 580 setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
(...skipping 10 matching lines...) Expand all
349 591
350 const std::vector<std::string>& argv = 592 const std::vector<std::string>& argv =
351 CommandLine::ForCurrentProcess()->argv(); 593 CommandLine::ForCurrentProcess()->argv();
352 for (std::vector<std::string>::const_iterator it = argv.begin(); 594 for (std::vector<std::string>::const_iterator it = argv.begin();
353 it != argv.end(); ++it) { 595 it != argv.end(); ++it) {
354 to_send.push_back(kTokenDelimiter); 596 to_send.push_back(kTokenDelimiter);
355 to_send.append(*it); 597 to_send.append(*it);
356 } 598 }
357 599
358 // Send the message 600 // Send the message
359 int bytes_written = 0; 601 if (!WriteToSocket(socket, to_send.data(), to_send.length())) {
360 const int buf_len = to_send.length(); 602 // Try to kill the other process, because it might have been dead.
361 do { 603 KillProcessBySocketPath(socket_path_.value());
362 int rv = HANDLE_EINTR( 604 return false;
363 write(socket, to_send.data() + bytes_written, buf_len - bytes_written));
364 if (rv < 0) {
365 if (errno == EAGAIN || errno == EWOULDBLOCK) {
366 // The socket shouldn't block, we're sending so little data. Just give
367 // up here, since NotifyOtherProcess() doesn't have an asynchronous api.
368 LOG(ERROR) << "ProcessSingleton would block on write(), so it gave up.";
369 return false;
370 }
371 LOG(ERROR) << "write() failed: " << strerror(errno);
372 return false;
373 }
374 bytes_written += rv;
375 } while (bytes_written < buf_len);
376
377 int rv = shutdown(socket, SHUT_WR);
378 if (rv < 0) {
379 LOG(ERROR) << "shutdown() failed: " << strerror(errno);
380 } else {
381 // TODO(tc): We should wait for an ACK, and if we don't get it in a certain
382 // time period, kill the other process.
383 } 605 }
384 606
385 rv = HANDLE_EINTR(close(socket)); 607 if (shutdown(socket, SHUT_WR) < 0)
386 DCHECK_EQ(0, rv) << strerror(errno); 608 LOG(ERROR) << "shutdown() failed: " << strerror(errno);
387 609
388 // Assume the other process is handling the request. 610 // Read ACK message from the other process. It might be blocked for a certain
611 // timeout, to make sure the other process has enough time to return ACK.
612 char buf[kMaxACKMessageLength + 1];
613 ssize_t len =
614 ReadFromSocket(socket, buf, kMaxACKMessageLength, kTimeoutInSeconds);
615
616 // Failed to read ACK, the other process might have been frozen.
617 if (len <= 0) {
618 KillProcessBySocketPath(socket_path_.value());
619 return false;
620 }
621
622 buf[len] = '\0';
623 if (strncmp(buf, kShutdownToken, arraysize(kShutdownToken) - 1) == 0) {
624 // The other process is shutting down, it's safe to start a new process.
625 return false;
626 } else if (strncmp(buf, kACKToken, arraysize(kACKToken) - 1) == 0) {
627 // Assume the other process is handling the request.
628 return true;
629 }
630
631 NOTREACHED() << "The other process returned unknown message: " << buf;
389 return true; 632 return true;
390 } 633 }
391 634
392 void ProcessSingleton::Create() { 635 void ProcessSingleton::Create() {
393 int sock; 636 int sock;
394 sockaddr_un addr; 637 sockaddr_un addr;
395 SetupSocket(&sock, &addr);
396 638
397 if (unlink(socket_path_.value().c_str()) < 0) 639 // Append the process id to the socket path, so that other process can find it
398 DCHECK_EQ(errno, ENOENT); 640 // out.
641 std::string path = StringPrintf(
642 "%s-%u", socket_path_.value().c_str(), base::GetCurrentProcId());
643 SetupSocket(path, &sock, &addr);
644
645 UnlinkSocketPath(socket_path_.value());
646
647 // Create symbol link before binding the socket, so that the socket file can
648 // always be reached and removed by another process.
649 // The symbol link only contains the filename part of the socket file, so that
650 // the whole config directory can be moved without breaking the symbol link.
651 std::string symlink_content = FilePath(path).BaseName().value();
652 if (symlink(symlink_content.c_str(), socket_path_.value().c_str()) < 0)
653 NOTREACHED() << "Failed to create symbol link: " << strerror(errno);
399 654
400 if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) { 655 if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
401 LOG(ERROR) << "bind() failed: " << strerror(errno); 656 LOG(ERROR) << "bind() failed: " << strerror(errno);
402 LOG(ERROR) << "SingletonSocket failed to create a socket in your home " 657 LOG(ERROR) << "SingletonSocket failed to create a socket in your home "
403 "directory. This means that running multiple instances of " 658 "directory. This means that running multiple instances of "
404 "the Chrome binary will start multiple browser process " 659 "the Chrome binary will start multiple browser process "
405 "rather than opening a new window in the existing process."; 660 "rather than opening a new window in the existing process.";
406 close(sock); 661 CloseSocket(sock);
407 return; 662 return;
408 } 663 }
409 664
410 if (listen(sock, 5) < 0) 665 if (listen(sock, 5) < 0)
411 NOTREACHED() << "listen failed: " << strerror(errno); 666 NOTREACHED() << "listen failed: " << strerror(errno);
412 667
413 // Normally we would use ChromeThread, but the IO thread hasn't started yet. 668 // Normally we would use ChromeThread, but the IO thread hasn't started yet.
414 // Using g_browser_process, we start the thread so we can listen on the 669 // Using g_browser_process, we start the thread so we can listen on the
415 // socket. 670 // socket.
416 MessageLoop* ml = g_browser_process->io_thread()->message_loop(); 671 MessageLoop* ml = g_browser_process->io_thread()->message_loop();
417 DCHECK(ml); 672 DCHECK(ml);
418 ml->PostTask(FROM_HERE, NewRunnableMethod( 673 ml->PostTask(FROM_HERE, NewRunnableMethod(
419 watcher_.get(), 674 watcher_.get(),
420 &ProcessSingleton::LinuxWatcher::StartListening, 675 &ProcessSingleton::LinuxWatcher::StartListening,
421 sock)); 676 sock));
422 } 677 }
423
424 void ProcessSingleton::SetupSocket(int* sock, struct sockaddr_un* addr) {
425 *sock = socket(PF_UNIX, SOCK_STREAM, 0);
426 if (*sock < 0)
427 LOG(FATAL) << "socket() failed: " << strerror(errno);
428
429 int rv = SetNonBlocking(*sock);
430 DCHECK_EQ(0, rv) << "Failed to make non-blocking socket.";
431
432 addr->sun_family = AF_UNIX;
433 if (socket_path_.value().length() > sizeof(addr->sun_path) - 1)
434 LOG(FATAL) << "Socket path too long: " << socket_path_.value();
435 base::strlcpy(addr->sun_path, socket_path_.value().c_str(),
436 sizeof(addr->sun_path));
437 }
OLDNEW
« no previous file with comments | « chrome/browser/process_singleton.h ('k') | chrome/browser/process_singleton_linux_uitest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698