| 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 |