1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2009 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include <errno.h> 6731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include <fcntl.h> 7731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include <sys/file.h> 8731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/process_singleton.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 11731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/eintr_wrapper.h" 12731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/file_util.h" 13731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h" 14731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/common/chrome_constants.h" 15731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 16731df977c0511bca2206b5f333555b1205ff1f43Iain Merricknamespace { 17731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 18731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// From "man 2 intro", the largest errno is |EOPNOTSUPP|, which is 19731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// |102|. Since the histogram memory usage is proportional to this 20731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// number, using the |102| directly rather than the macro. 21731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickconst int kMaxErrno = 102; 22731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 23731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} // namespace 24731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This class is used to funnel messages to a single instance of the browser 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// process. This is needed for several reasons on other platforms. 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// On Windows, when the user re-opens the application from the shell (e.g. an 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// explicit double-click, a shortcut that opens a webpage, etc.) we need to send 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the message to the currently-existing copy of the browser. 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// On Linux, opening a URL is done by creating an instance of the web browser 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// process and passing it the URL to go to on its commandline. 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Neither of those cases apply on the Mac. Launch Services ensures that there 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// is only one instance of the process, and we get URLs to open via AppleEvents 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// and, once again, the Launch Services system. We have no need to manage this 38731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// ourselves. An exclusive lock is used to flush out anyone making incorrect 39731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// assumptions. 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 41731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickProcessSingleton::ProcessSingleton(const FilePath& user_data_dir) 42731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick : locked_(false), 43731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick foreground_window_(NULL), 44731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick lock_path_(user_data_dir.Append(chrome::kSingletonLockFilename)), 45731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick lock_fd_(-1) { 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochProcessSingleton::~ProcessSingleton() { 49731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Make sure the lock is released. Process death will also release 50731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // it, even if this is not called. 51731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick Cleanup(); 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This space intentionally left blank. 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return PROCESS_NONE; 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() { 60731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Windows tries NotifyOtherProcess() first. 61731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return Create() ? PROCESS_NONE : PROFILE_IN_USE; 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 64731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Attempt to acquire an exclusive lock on an empty file in the 6521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// profile directory. Returns |true| if it gets the lock. Returns 6621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// |false| if the lock is held, or if there is an error. 67731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// TODO(shess): Rather than logging failures, popup an alert. Punting 68731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// that for now because it would require confidence that this code is 69731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// never called in a situation where an alert wouldn't work. 70731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// http://crbug.com/59061 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ProcessSingleton::Create() { 72731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK_EQ(-1, lock_fd_) << "lock_path_ is already open."; 73731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 74731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick lock_fd_ = HANDLE_EINTR(open(lock_path_.value().c_str(), 75731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick O_RDONLY | O_CREAT, 0644)); 76731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (lock_fd_ == -1) { 77731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const int capture_errno = errno; 78731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DPCHECK(lock_fd_ != -1) << "Unexpected failure opening profile lockfile"; 79731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick UMA_HISTOGRAM_ENUMERATION("ProcessSingleton.OpenError", 80731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick capture_errno, kMaxErrno); 8121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return false; 82731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 83731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 84731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Acquire an exclusive lock in non-blocking fashion. If the lock 85731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // is already held, this will return |EWOULDBLOCK|. 86731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int rc = HANDLE_EINTR(flock(lock_fd_, LOCK_EX|LOCK_NB)); 87731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (rc == -1) { 88731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const int capture_errno = errno; 89731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DPCHECK(errno == EWOULDBLOCK) 90731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick << "Unexpected failure locking profile lockfile"; 91731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 92731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick Cleanup(); 93731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 94731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Other errors indicate something crazy is happening. 95731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (capture_errno != EWOULDBLOCK) { 96731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick UMA_HISTOGRAM_ENUMERATION("ProcessSingleton.LockError", 97731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick capture_errno, kMaxErrno); 9821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return false; 99731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 100731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 101731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // The file is open by another process and locked. 102731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick LOG(ERROR) << "Unable to obtain profile lock."; 103731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return false; 104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ProcessSingleton::Cleanup() { 110731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Closing the file also releases the lock. 111731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (lock_fd_ != -1) { 112731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int rc = HANDLE_EINTR(close(lock_fd_)); 113731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DPCHECK(!rc) << "Closing lock_fd_:"; 114731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 115731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick lock_fd_ = -1; 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 117