Chromium Code Reviews| 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 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 141 return true; | 141 return true; |
| 142 } | 142 } |
| 143 return false; | 143 return false; |
| 144 } | 144 } |
| 145 | 145 |
| 146 // Look for a Chrome instance that uses the same profile directory. | 146 // Look for a Chrome instance that uses the same profile directory. |
| 147 // If there isn't one, create a message window with its title set to | 147 // If there isn't one, create a message window with its title set to |
| 148 // the profile directory path. | 148 // the profile directory path. |
| 149 ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir) | 149 ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir) |
| 150 : window_(NULL), locked_(false), foreground_window_(NULL), | 150 : window_(NULL), locked_(false), foreground_window_(NULL), |
| 151 is_virtualized_(false) { | 151 is_virtualized_(false), lock_file_(INVALID_HANDLE_VALUE) { |
| 152 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, | 152 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, |
| 153 chrome::kMessageWindowClass, | 153 chrome::kMessageWindowClass, |
| 154 user_data_dir.value().c_str()); | 154 user_data_dir.value().c_str()); |
| 155 if (!remote_window_ && !EscapeVirtualization(user_data_dir)) { | 155 if (!remote_window_ && !EscapeVirtualization(user_data_dir)) { |
| 156 // Make sure we will be the one and only process creating the window. | 156 // Make sure we will be the one and only process creating the window. |
| 157 // We use a named Mutex since we are protecting against multi-process | 157 // We use a named Mutex since we are protecting against multi-process |
| 158 // access. As documented, it's clearer to NOT request ownership on creation | 158 // access. As documented, it's clearer to NOT request ownership on creation |
| 159 // since it isn't guaranteed we will get it. It is better to create it | 159 // since it isn't guaranteed we will get it. It is better to create it |
| 160 // without ownership and explicitly get the ownership afterward. | 160 // without ownership and explicitly get the ownership afterward. |
| 161 std::wstring mutex_name(L"Local\\ChromeProcessSingletonStartup!"); | 161 std::wstring mutex_name(L"Local\\ChromeProcessSingletonStartup!"); |
| 162 base::win::ScopedHandle only_me( | 162 base::win::ScopedHandle only_me( |
| 163 CreateMutex(NULL, FALSE, mutex_name.c_str())); | 163 CreateMutex(NULL, FALSE, mutex_name.c_str())); |
| 164 DCHECK(only_me.Get() != NULL) << "GetLastError = " << GetLastError(); | 164 DCHECK(only_me.Get() != NULL) << "GetLastError = " << GetLastError(); |
| 165 | 165 |
| 166 // This is how we acquire the mutex (as opposed to the initial ownership). | 166 // This is how we acquire the mutex (as opposed to the initial ownership). |
| 167 DWORD result = WaitForSingleObject(only_me, INFINITE); | 167 DWORD result = WaitForSingleObject(only_me, INFINITE); |
| 168 DCHECK(result == WAIT_OBJECT_0) << "Result = " << result << | 168 DCHECK(result == WAIT_OBJECT_0) << "Result = " << result << |
| 169 "GetLastError = " << GetLastError(); | 169 "GetLastError = " << GetLastError(); |
| 170 | 170 |
| 171 // We now own the mutex so we are the only process that can create the | 171 // We now own the mutex so we are the only process that can create the |
| 172 // window at this time, but we must still check if someone created it | 172 // window at this time, but we must still check if someone created it |
| 173 // between the time where we looked for it above and the time the mutex | 173 // between the time where we looked for it above and the time the mutex |
| 174 // was given to us. | 174 // was given to us. |
| 175 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, | 175 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, |
| 176 chrome::kMessageWindowClass, | 176 chrome::kMessageWindowClass, |
| 177 user_data_dir.value().c_str()); | 177 user_data_dir.value().c_str()); |
| 178 if (!remote_window_) { | 178 // We have to make sure there is no Chrome instance running on another |
|
cpu_(ooo_6.6-7.5)
2012/07/13 23:16:53
why do it if the directory is not remote?
pastarmovj
2012/07/14 01:21:58
To check if a path contains a reparse point hence
| |
| 179 // machine that uses the same profile. | |
| 180 FilePath lock_file_path = user_data_dir.AppendASCII("lockfile"); | |
| 181 lock_file_ = CreateFile(lock_file_path.value().c_str(), | |
| 182 GENERIC_WRITE, | |
| 183 FILE_SHARE_READ, | |
| 184 NULL, | |
| 185 CREATE_NEW, | |
| 186 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, | |
| 187 NULL); | |
| 188 DWORD error = GetLastError(); | |
| 189 LOG(ERROR) << "@@@ First lock file attempt : " << lock_file_ | |
| 190 << " code " << error; | |
| 191 if (lock_file_ == INVALID_HANDLE_VALUE && error == ERROR_FILE_EXISTS) { | |
| 192 // If we are inside here that means that some other machine has or had an | |
| 193 // active chrome process. This second try destinguishes between stale file | |
| 194 // and really actively opened file. We should directly do this check but | |
| 195 // for completeness we do both check sequentially. | |
| 196 lock_file_ = CreateFile(lock_file_path.value().c_str(), | |
| 197 GENERIC_WRITE, | |
| 198 FILE_SHARE_READ, | |
| 199 NULL, | |
| 200 OPEN_EXISTING, | |
| 201 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, | |
| 202 NULL); | |
| 203 error = GetLastError(); | |
| 204 LOG(ERROR) << "@@@ Second lock file attempt : " << lock_file_ | |
| 205 << " code " << error; | |
| 206 } | |
| 207 if (lock_file_ == INVALID_HANDLE_VALUE) { | |
| 208 // If both attempts failed we are left with no other option but to admit | |
| 209 // defeat and make harakiri to ourselves. | |
| 210 LOG(ERROR) << "@@@ There is another chrome process that is still active"; | |
| 211 } | |
| 212 | |
| 213 if (!remote_window_ && lock_file_ != INVALID_HANDLE_VALUE) { | |
| 179 HINSTANCE hinst = base::GetModuleFromAddress(&ThunkWndProc); | 214 HINSTANCE hinst = base::GetModuleFromAddress(&ThunkWndProc); |
| 180 | 215 |
| 181 WNDCLASSEX wc = {0}; | 216 WNDCLASSEX wc = {0}; |
| 182 wc.cbSize = sizeof(wc); | 217 wc.cbSize = sizeof(wc); |
| 183 wc.lpfnWndProc = base::win::WrappedWindowProc<ThunkWndProc>; | 218 wc.lpfnWndProc = base::win::WrappedWindowProc<ThunkWndProc>; |
| 184 wc.hInstance = hinst; | 219 wc.hInstance = hinst; |
| 185 wc.lpszClassName = chrome::kMessageWindowClass; | 220 wc.lpszClassName = chrome::kMessageWindowClass; |
| 186 ATOM clazz = ::RegisterClassEx(&wc); | 221 ATOM clazz = ::RegisterClassEx(&wc); |
| 187 DCHECK(clazz); | 222 DCHECK(clazz); |
| 188 | 223 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 200 | 235 |
| 201 ProcessSingleton::~ProcessSingleton() { | 236 ProcessSingleton::~ProcessSingleton() { |
| 202 // We need to unregister the window as late as possible so that we can detect | 237 // We need to unregister the window as late as possible so that we can detect |
| 203 // another instance of chrome running. Otherwise we may end up writing out | 238 // another instance of chrome running. Otherwise we may end up writing out |
| 204 // data while a new chrome is starting up. | 239 // data while a new chrome is starting up. |
| 205 if (window_) { | 240 if (window_) { |
| 206 ::DestroyWindow(window_); | 241 ::DestroyWindow(window_); |
| 207 ::UnregisterClass(chrome::kMessageWindowClass, | 242 ::UnregisterClass(chrome::kMessageWindowClass, |
| 208 base::GetModuleFromAddress(&ThunkWndProc)); | 243 base::GetModuleFromAddress(&ThunkWndProc)); |
| 209 } | 244 } |
| 245 if (lock_file_ != INVALID_HANDLE_VALUE) | |
| 246 CloseHandle(lock_file_); | |
|
cpu_(ooo_6.6-7.5)
2012/07/13 23:16:53
why close it here?
pastarmovj
2012/07/14 01:21:58
Mmmm...clean up...I guess :-) .
Well basically th
| |
| 210 } | 247 } |
| 211 | 248 |
| 212 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { | 249 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { |
| 213 if (is_virtualized_) | 250 if (is_virtualized_) |
| 214 return PROCESS_NOTIFIED; // We already spawned the process in this case. | 251 return PROCESS_NOTIFIED; // We already spawned the process in this case. |
| 215 else if (!remote_window_) | 252 else if (!remote_window_) |
| 216 return PROCESS_NONE; | 253 return PROCESS_NONE; |
| 217 | 254 |
| 218 // Found another window, send our command line to it | 255 // Found another window, send our command line to it |
| 219 // format is "START\0<<<current directory>>>\0<<<commandline>>>". | 256 // format is "START\0<<<current directory>>>\0<<<commandline>>>". |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 292 return result; | 329 return result; |
| 293 return Create(notification_callback) ? PROCESS_NONE : PROFILE_IN_USE; | 330 return Create(notification_callback) ? PROCESS_NONE : PROFILE_IN_USE; |
| 294 } | 331 } |
| 295 | 332 |
| 296 // On Windows, there is no need to call Create() since the message | 333 // On Windows, there is no need to call Create() since the message |
| 297 // window is created in the constructor but to avoid having more | 334 // window is created in the constructor but to avoid having more |
| 298 // platform specific code in browser_main.cc we tolerate calls to | 335 // platform specific code in browser_main.cc we tolerate calls to |
| 299 // Create(). | 336 // Create(). |
| 300 bool ProcessSingleton::Create( | 337 bool ProcessSingleton::Create( |
| 301 const NotificationCallback& notification_callback) { | 338 const NotificationCallback& notification_callback) { |
| 339 if (lock_file_ == INVALID_HANDLE_VALUE) | |
| 340 return false; | |
| 341 | |
|
cpu_(ooo_6.6-7.5)
2012/07/13 23:16:53
and not sure we need this here either..
pastarmovj
2012/07/14 01:21:58
This actually will make the newly started process
| |
| 302 DCHECK(!remote_window_); | 342 DCHECK(!remote_window_); |
| 303 DCHECK(notification_callback_.is_null()); | 343 DCHECK(notification_callback_.is_null()); |
| 304 | 344 |
| 305 if (window_ != NULL) | 345 if (window_ != NULL) |
| 306 notification_callback_ = notification_callback; | 346 notification_callback_ = notification_callback; |
| 307 | 347 |
| 308 return window_ != NULL; | 348 return window_ != NULL; |
| 309 } | 349 } |
| 310 | 350 |
| 311 void ProcessSingleton::Cleanup() { | 351 void ProcessSingleton::Cleanup() { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 347 switch (message) { | 387 switch (message) { |
| 348 case WM_COPYDATA: | 388 case WM_COPYDATA: |
| 349 return OnCopyData(reinterpret_cast<HWND>(wparam), | 389 return OnCopyData(reinterpret_cast<HWND>(wparam), |
| 350 reinterpret_cast<COPYDATASTRUCT*>(lparam)); | 390 reinterpret_cast<COPYDATASTRUCT*>(lparam)); |
| 351 default: | 391 default: |
| 352 break; | 392 break; |
| 353 } | 393 } |
| 354 | 394 |
| 355 return ::DefWindowProc(hwnd, message, wparam, lparam); | 395 return ::DefWindowProc(hwnd, message, wparam, lparam); |
| 356 } | 396 } |
| OLD | NEW |