| 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> |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } | |
| OLD | NEW |