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