1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_PROCESS_SINGLETON_H_ 6 #define CHROME_BROWSER_PROCESS_SINGLETON_H_ 7 #pragma once 8 9 #include "build/build_config.h" 10 11 #if defined(OS_WIN) 12 #include <windows.h> 13 #endif // defined(OS_WIN) 14 15 #include "base/basictypes.h" 16 #include "base/logging.h" 17 #include "base/memory/ref_counted.h" 18 #include "base/threading/non_thread_safe.h" 19 #include "ui/gfx/native_widget_types.h" 20 21 #if defined(OS_POSIX) 22 #include "base/file_path.h" 23 #endif // defined(OS_POSIX) 24 25 #if defined(USE_X11) 26 #include "base/memory/scoped_temp_dir.h" 27 #endif // defined(USE_X11) 28 29 class CommandLine; 30 class FilePath; 31 32 // ProcessSingleton ---------------------------------------------------------- 33 // 34 // This class allows different browser processes to communicate with 35 // each other. It is named according to the user data directory, so 36 // we can be sure that no more than one copy of the application can be 37 // running at once with a given data directory. 38 // 39 // Implementation notes: 40 // - the Windows implementation uses an invisible global message window; 41 // - the Linux implementation uses a Unix domain socket in the user data dir. 42 43 class ProcessSingleton : public base::NonThreadSafe { 44 public: 45 enum NotifyResult { 46 PROCESS_NONE, 47 PROCESS_NOTIFIED, 48 PROFILE_IN_USE, 49 LOCK_ERROR, 50 }; 51 52 explicit ProcessSingleton(const FilePath& user_data_dir); 53 ~ProcessSingleton(); 54 55 // Notify another process, if available. 56 // Returns true if another process was found and notified, false if we 57 // should continue with this process. 58 // Windows code roughly based on Mozilla. 59 // 60 // TODO(brettw): this will not handle all cases. If two process start up too 61 // close to each other, the Create() might not yet have happened for the 62 // first one, so this function won't find it. 63 NotifyResult NotifyOtherProcess(); 64 65 // Notify another process, if available. Otherwise sets ourselves as the 66 // singleton instance. Returns PROCESS_NONE if we became the singleton 67 // instance. 68 NotifyResult NotifyOtherProcessOrCreate(); 69 70 #if defined(OS_LINUX) 71 // Exposed for testing. We use a timeout on Linux, and in tests we want 72 // this timeout to be short. 73 NotifyResult NotifyOtherProcessWithTimeout(const CommandLine& command_line, 74 int timeout_seconds, 75 bool kill_unresponsive); 76 NotifyResult NotifyOtherProcessWithTimeoutOrCreate( 77 const CommandLine& command_line, 78 int timeout_seconds); 79 #endif // defined(OS_LINUX) 80 81 #if defined(OS_WIN) 82 // Used in specific cases to let us know that there is an existing instance 83 // of Chrome running with this profile. In general, you should not use this 84 // function. Instead consider using NotifyOtherProcessOrCreate(). 85 // For non profile-specific method, use 86 // browser_util::IsBrowserAlreadyRunning(). FoundOtherProcessWindow()87 bool FoundOtherProcessWindow() const { 88 return (NULL != remote_window_); 89 } 90 #endif // defined(OS_WIN) 91 92 // Sets ourself up as the singleton instance. Returns true on success. If 93 // false is returned, we are not the singleton instance and the caller must 94 // exit. 95 bool Create(); 96 97 // Clear any lock state during shutdown. 98 void Cleanup(); 99 100 // Blocks the dispatch of CopyData messages. foreground_window refers 101 // to the window that should be set to the foreground if a CopyData message 102 // is received while the ProcessSingleton is locked. Lock(gfx::NativeWindow foreground_window)103 void Lock(gfx::NativeWindow foreground_window) { 104 DCHECK(CalledOnValidThread()); 105 locked_ = true; 106 foreground_window_ = foreground_window; 107 } 108 109 // Allows the dispatch of CopyData messages. Unlock()110 void Unlock() { 111 DCHECK(CalledOnValidThread()); 112 locked_ = false; 113 foreground_window_ = NULL; 114 } 115 locked()116 bool locked() { 117 DCHECK(CalledOnValidThread()); 118 return locked_; 119 } 120 121 private: 122 #if !defined(OS_MACOSX) 123 // Timeout for the current browser process to respond. 20 seconds should be 124 // enough. It's only used in Windows and Linux implementations. 125 static const int kTimeoutInSeconds = 20; 126 #endif 127 128 bool locked_; 129 gfx::NativeWindow foreground_window_; 130 131 #if defined(OS_WIN) 132 // This ugly behemoth handles startup commands sent from another process. 133 LRESULT OnCopyData(HWND hwnd, const COPYDATASTRUCT* cds); 134 135 LRESULT CALLBACK WndProc(HWND hwnd, 136 UINT message, 137 WPARAM wparam, 138 LPARAM lparam); 139 WndProcStatic(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)140 static LRESULT CALLBACK WndProcStatic(HWND hwnd, 141 UINT message, 142 WPARAM wparam, 143 LPARAM lparam) { 144 ProcessSingleton* msg_wnd = reinterpret_cast<ProcessSingleton*>( 145 GetWindowLongPtr(hwnd, GWLP_USERDATA)); 146 return msg_wnd->WndProc(hwnd, message, wparam, lparam); 147 } 148 149 HWND remote_window_; // The HWND_MESSAGE of another browser. 150 HWND window_; // The HWND_MESSAGE window. 151 #elif defined(USE_X11) 152 // Path in file system to the socket. 153 FilePath socket_path_; 154 155 // Path in file system to the lock. 156 FilePath lock_path_; 157 158 // Path in file system to the cookie file. 159 FilePath cookie_path_; 160 161 // Temporary directory to hold the socket. 162 ScopedTempDir socket_dir_; 163 164 // Helper class for linux specific messages. LinuxWatcher is ref counted 165 // because it posts messages between threads. 166 class LinuxWatcher; 167 scoped_refptr<LinuxWatcher> watcher_; 168 #elif defined(OS_MACOSX) 169 // Path in file system to the lock. 170 FilePath lock_path_; 171 172 // File descriptor associated with the lockfile, valid between 173 // |Create()| and |Cleanup()|. Two instances cannot have a lock on 174 // the same file at the same time. 175 int lock_fd_; 176 #endif 177 178 DISALLOW_COPY_AND_ASSIGN(ProcessSingleton); 179 }; 180 181 #endif // CHROME_BROWSER_PROCESS_SINGLETON_H_ 182