OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #include "chrome/browser/process_singleton.h" | 5 #include "chrome/browser/process_singleton.h" |
6 | 6 |
7 #include "base/base_paths.h" | 7 #include "base/base_paths.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/file_path.h" | 9 #include "base/file_path.h" |
10 #include "base/path_service.h" | 10 #include "base/path_service.h" |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 break; | 84 break; |
85 } | 85 } |
86 ::Sleep(10); | 86 ::Sleep(10); |
87 } | 87 } |
88 return true; | 88 return true; |
89 } | 89 } |
90 return false; | 90 return false; |
91 } | 91 } |
92 | 92 |
93 // Look for a Chrome instance that uses the same profile directory. | 93 // Look for a Chrome instance that uses the same profile directory. |
| 94 // If there isn't one, create a message window with its title set to |
| 95 // the profile directory path. |
94 ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir) | 96 ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir) |
95 : window_(NULL), locked_(false), foreground_window_(NULL), | 97 : window_(NULL), locked_(false), foreground_window_(NULL), |
96 is_virtualized_(false) { | 98 is_virtualized_(false) { |
97 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, | 99 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, |
98 chrome::kMessageWindowClass, | 100 chrome::kMessageWindowClass, |
99 user_data_dir.value().c_str()); | 101 user_data_dir.value().c_str()); |
100 if (!remote_window_ && !EscapeVirtualization(user_data_dir)) { | 102 if (!remote_window_ && !EscapeVirtualization(user_data_dir)) { |
101 // Make sure we will be the one and only process creating the window. | 103 // Make sure we will be the one and only process creating the window. |
102 // We use a named Mutex since we are protecting against multi-process | 104 // We use a named Mutex since we are protecting against multi-process |
103 // access. As documented, it's clearer to NOT request ownership on creation | 105 // access. As documented, it's clearer to NOT request ownership on creation |
104 // since it isn't guaranteed we will get it. It is better to create it | 106 // since it isn't guaranteed we will get it. It is better to create it |
105 // without ownership and explicitly get the ownership afterward. | 107 // without ownership and explicitly get the ownership afterward. |
106 std::wstring mutex_name(L"Local\\ChromeProcessSingletonStartup!"); | 108 std::wstring mutex_name(L"Local\\ChromeProcessSingletonStartup!"); |
107 base::win::ScopedHandle only_me( | 109 base::win::ScopedHandle only_me( |
108 CreateMutex(NULL, FALSE, mutex_name.c_str())); | 110 CreateMutex(NULL, FALSE, mutex_name.c_str())); |
109 DCHECK(only_me.Get() != NULL) << "GetLastError = " << GetLastError(); | 111 DCHECK(only_me.Get() != NULL) << "GetLastError = " << GetLastError(); |
110 | 112 |
111 // This is how we acquire the mutex (as opposed to the initial ownership). | 113 // This is how we acquire the mutex (as opposed to the initial ownership). |
112 DWORD result = WaitForSingleObject(only_me, INFINITE); | 114 DWORD result = WaitForSingleObject(only_me, INFINITE); |
113 DCHECK(result == WAIT_OBJECT_0) << "Result = " << result << | 115 DCHECK(result == WAIT_OBJECT_0) << "Result = " << result << |
114 "GetLastError = " << GetLastError(); | 116 "GetLastError = " << GetLastError(); |
115 | 117 |
116 // We now own the mutex so we are the only process that can create the | 118 // We now own the mutex so we are the only process that can create the |
117 // window at this time, but we must still check if someone created it | 119 // window at this time, but we must still check if someone created it |
118 // between the time where we looked for it above and the time the mutex | 120 // between the time where we looked for it above and the time the mutex |
119 // was given to us. | 121 // was given to us. |
120 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, | 122 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, |
121 chrome::kMessageWindowClass, | 123 chrome::kMessageWindowClass, |
122 user_data_dir.value().c_str()); | 124 user_data_dir.value().c_str()); |
123 if (!remote_window_) | 125 if (!remote_window_) { |
124 Create(); | 126 HINSTANCE hinst = base::GetModuleFromAddress(&ThunkWndProc); |
| 127 |
| 128 WNDCLASSEX wc = {0}; |
| 129 wc.cbSize = sizeof(wc); |
| 130 wc.lpfnWndProc = base::win::WrappedWindowProc<ThunkWndProc>; |
| 131 wc.hInstance = hinst; |
| 132 wc.lpszClassName = chrome::kMessageWindowClass; |
| 133 ATOM clazz = ::RegisterClassEx(&wc); |
| 134 DCHECK(clazz); |
| 135 |
| 136 FilePath user_data_dir; |
| 137 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); |
| 138 |
| 139 // Set the window's title to the path of our user data directory so other |
| 140 // Chrome instances can decide if they should forward to us or not. |
| 141 window_ = ::CreateWindow(MAKEINTATOM(clazz), |
| 142 user_data_dir.value().c_str(), |
| 143 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, this); |
| 144 CHECK(window_); |
| 145 } |
125 BOOL success = ReleaseMutex(only_me); | 146 BOOL success = ReleaseMutex(only_me); |
126 DCHECK(success) << "GetLastError = " << GetLastError(); | 147 DCHECK(success) << "GetLastError = " << GetLastError(); |
127 } | 148 } |
128 } | 149 } |
129 | 150 |
130 ProcessSingleton::~ProcessSingleton() { | 151 ProcessSingleton::~ProcessSingleton() { |
131 if (window_) { | 152 Cleanup(); |
132 ::DestroyWindow(window_); | |
133 ::UnregisterClass(chrome::kMessageWindowClass, GetModuleHandle(NULL)); | |
134 } | |
135 } | 153 } |
136 | 154 |
137 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { | 155 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { |
138 if (is_virtualized_) | 156 if (is_virtualized_) |
139 return PROCESS_NOTIFIED; // We already spawned the process in this case. | 157 return PROCESS_NOTIFIED; // We already spawned the process in this case. |
140 else if (!remote_window_) | 158 else if (!remote_window_) |
141 return PROCESS_NONE; | 159 return PROCESS_NONE; |
142 | 160 |
143 // Found another window, send our command line to it | 161 // Found another window, send our command line to it |
144 // format is "START\0<<<current directory>>>\0<<<commandline>>>". | 162 // format is "START\0<<<current directory>>>\0<<<commandline>>>". |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 // Time to take action. Kill the browser process. | 226 // Time to take action. Kill the browser process. |
209 base::KillProcessById(process_id, content::RESULT_CODE_HUNG, true); | 227 base::KillProcessById(process_id, content::RESULT_CODE_HUNG, true); |
210 remote_window_ = NULL; | 228 remote_window_ = NULL; |
211 return PROCESS_NONE; | 229 return PROCESS_NONE; |
212 } | 230 } |
213 | 231 |
214 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() { | 232 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() { |
215 NotifyResult result = NotifyOtherProcess(); | 233 NotifyResult result = NotifyOtherProcess(); |
216 if (result != PROCESS_NONE) | 234 if (result != PROCESS_NONE) |
217 return result; | 235 return result; |
218 return Create() ? PROCESS_NONE : PROFILE_IN_USE; | 236 return window_ ? PROCESS_NONE : PROFILE_IN_USE; |
219 } | 237 } |
220 | 238 |
221 // For windows, there is no need to call Create() since the call is made in | 239 // On Windows, there is no need to call Create() since the message |
222 // the constructor but to avoid having more platform specific code in | 240 // window is created in the constructor but to avoid having more |
223 // browser_main.cc we tolerate a second call which will do nothing. | 241 // platform specific code in browser_main.cc we tolerate calls to |
| 242 // Create(), which will do nothing. |
224 bool ProcessSingleton::Create() { | 243 bool ProcessSingleton::Create() { |
225 DCHECK(!remote_window_); | 244 DCHECK(!remote_window_); |
226 if (window_) | 245 return window_ != NULL; |
227 return true; | |
228 | |
229 HINSTANCE hinst = 0; | |
230 if (!::GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, | |
231 reinterpret_cast<char*>(&ThunkWndProc), | |
232 &hinst)) { | |
233 NOTREACHED(); | |
234 } | |
235 | |
236 WNDCLASSEX wc = {0}; | |
237 wc.cbSize = sizeof(wc); | |
238 wc.lpfnWndProc = base::win::WrappedWindowProc<ThunkWndProc>; | |
239 wc.hInstance = hinst; | |
240 wc.lpszClassName = chrome::kMessageWindowClass; | |
241 ATOM clazz = ::RegisterClassEx(&wc); | |
242 DCHECK(clazz); | |
243 | |
244 FilePath user_data_dir; | |
245 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); | |
246 | |
247 // Set the window's title to the path of our user data directory so other | |
248 // Chrome instances can decide if they should forward to us or not. | |
249 window_ = ::CreateWindow(MAKEINTATOM(clazz), | |
250 user_data_dir.value().c_str(), | |
251 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, this); | |
252 CHECK(window_); | |
253 return true; | |
254 } | 246 } |
255 | 247 |
256 void ProcessSingleton::Cleanup() { | 248 void ProcessSingleton::Cleanup() { |
| 249 // Window classes registered by DLLs are not cleaned up automatically on |
| 250 // process exit, so we must unregister at the earliest chance possible. |
| 251 // During the fast shutdown sequence, ProcessSingleton::Cleanup() is |
| 252 // called if our process was the first to start. Therefore we try cleaning |
| 253 // up here, and again in the destructor if needed to catch as many cases |
| 254 // as possible. |
| 255 if (window_) { |
| 256 ::DestroyWindow(window_); |
| 257 ::UnregisterClass(chrome::kMessageWindowClass, |
| 258 base::GetModuleFromAddress(&ThunkWndProc)); |
| 259 window_ = NULL; |
| 260 } |
257 } | 261 } |
258 | 262 |
259 LRESULT ProcessSingleton::OnCopyData(HWND hwnd, const COPYDATASTRUCT* cds) { | 263 LRESULT ProcessSingleton::OnCopyData(HWND hwnd, const COPYDATASTRUCT* cds) { |
260 // If locked, it means we are not ready to process this message because | 264 // If locked, it means we are not ready to process this message because |
261 // we are probably in a first run critical phase. | 265 // we are probably in a first run critical phase. |
262 if (locked_) { | 266 if (locked_) { |
263 #if defined(USE_AURA) | 267 #if defined(USE_AURA) |
264 NOTIMPLEMENTED(); | 268 NOTIMPLEMENTED(); |
265 #else | 269 #else |
266 // Attempt to place ourselves in the foreground / flash the task bar. | 270 // Attempt to place ourselves in the foreground / flash the task bar. |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 switch (message) { | 370 switch (message) { |
367 case WM_COPYDATA: | 371 case WM_COPYDATA: |
368 return OnCopyData(reinterpret_cast<HWND>(wparam), | 372 return OnCopyData(reinterpret_cast<HWND>(wparam), |
369 reinterpret_cast<COPYDATASTRUCT*>(lparam)); | 373 reinterpret_cast<COPYDATASTRUCT*>(lparam)); |
370 default: | 374 default: |
371 break; | 375 break; |
372 } | 376 } |
373 | 377 |
374 return ::DefWindowProc(hwnd, message, wparam, lparam); | 378 return ::DefWindowProc(hwnd, message, wparam, lparam); |
375 } | 379 } |
OLD | NEW |