| 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" |
| 11 #include "base/process_util.h" | 11 #include "base/process_util.h" |
| 12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
| 13 #include "base/win/scoped_handle.h" | 13 #include "base/win/scoped_handle.h" |
| 14 #include "base/win/wrapped_window_proc.h" | 14 #include "base/win/wrapped_window_proc.h" |
| 15 #include "chrome/browser/browser_process.h" | |
| 16 #include "chrome/browser/extensions/extensions_startup.h" | |
| 17 #include "chrome/browser/profiles/profile.h" | |
| 18 #include "chrome/browser/profiles/profile_manager.h" | |
| 19 #include "chrome/browser/simple_message_box.h" | 15 #include "chrome/browser/simple_message_box.h" |
| 20 #include "chrome/browser/ui/browser_init.h" | |
| 21 #include "chrome/common/chrome_constants.h" | 16 #include "chrome/common/chrome_constants.h" |
| 22 #include "chrome/common/chrome_paths.h" | |
| 23 #include "chrome/common/chrome_switches.h" | |
| 24 #include "chrome/installer/util/wmi.h" | 17 #include "chrome/installer/util/wmi.h" |
| 25 #include "content/public/common/result_codes.h" | 18 #include "content/public/common/result_codes.h" |
| 26 #include "grit/chromium_strings.h" | 19 #include "grit/chromium_strings.h" |
| 27 #include "grit/generated_resources.h" | 20 #include "grit/generated_resources.h" |
| 28 #include "ui/base/l10n/l10n_util.h" | 21 #include "ui/base/l10n/l10n_util.h" |
| 29 #include "ui/base/win/hwnd_util.h" | 22 #include "ui/base/win/hwnd_util.h" |
| 30 | 23 |
| 31 namespace { | 24 namespace { |
| 32 | 25 |
| 33 // Checks the visibility of the enumerated window and signals once a visible | 26 // Checks the visibility of the enumerated window and signals once a visible |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 HINSTANCE hinst = base::GetModuleFromAddress(&ThunkWndProc); | 179 HINSTANCE hinst = base::GetModuleFromAddress(&ThunkWndProc); |
| 187 | 180 |
| 188 WNDCLASSEX wc = {0}; | 181 WNDCLASSEX wc = {0}; |
| 189 wc.cbSize = sizeof(wc); | 182 wc.cbSize = sizeof(wc); |
| 190 wc.lpfnWndProc = base::win::WrappedWindowProc<ThunkWndProc>; | 183 wc.lpfnWndProc = base::win::WrappedWindowProc<ThunkWndProc>; |
| 191 wc.hInstance = hinst; | 184 wc.hInstance = hinst; |
| 192 wc.lpszClassName = chrome::kMessageWindowClass; | 185 wc.lpszClassName = chrome::kMessageWindowClass; |
| 193 ATOM clazz = ::RegisterClassEx(&wc); | 186 ATOM clazz = ::RegisterClassEx(&wc); |
| 194 DCHECK(clazz); | 187 DCHECK(clazz); |
| 195 | 188 |
| 196 FilePath user_data_dir; | |
| 197 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); | |
| 198 | |
| 199 // Set the window's title to the path of our user data directory so other | 189 // Set the window's title to the path of our user data directory so other |
| 200 // Chrome instances can decide if they should forward to us or not. | 190 // Chrome instances can decide if they should forward to us or not. |
| 201 window_ = ::CreateWindow(MAKEINTATOM(clazz), | 191 window_ = ::CreateWindow(MAKEINTATOM(clazz), |
| 202 user_data_dir.value().c_str(), | 192 user_data_dir.value().c_str(), |
| 203 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, this); | 193 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, this); |
| 204 CHECK(window_); | 194 CHECK(window_); |
| 205 } | 195 } |
| 206 BOOL success = ReleaseMutex(only_me); | 196 BOOL success = ReleaseMutex(only_me); |
| 207 DCHECK(success) << "GetLastError = " << GetLastError(); | 197 DCHECK(success) << "GetLastError = " << GetLastError(); |
| 208 } | 198 } |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 return PROCESS_NOTIFIED; | 272 return PROCESS_NOTIFIED; |
| 283 } | 273 } |
| 284 } | 274 } |
| 285 | 275 |
| 286 // Time to take action. Kill the browser process. | 276 // Time to take action. Kill the browser process. |
| 287 base::KillProcessById(process_id, content::RESULT_CODE_HUNG, true); | 277 base::KillProcessById(process_id, content::RESULT_CODE_HUNG, true); |
| 288 remote_window_ = NULL; | 278 remote_window_ = NULL; |
| 289 return PROCESS_NONE; | 279 return PROCESS_NONE; |
| 290 } | 280 } |
| 291 | 281 |
| 292 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() { | 282 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate( |
| 283 const NotificationCallback& notification_callback) { |
| 293 NotifyResult result = NotifyOtherProcess(); | 284 NotifyResult result = NotifyOtherProcess(); |
| 294 if (result != PROCESS_NONE) | 285 if (result != PROCESS_NONE) |
| 295 return result; | 286 return result; |
| 296 return window_ ? PROCESS_NONE : PROFILE_IN_USE; | 287 return Create(notification_callback) ? PROCESS_NONE : PROFILE_IN_USE; |
| 297 } | 288 } |
| 298 | 289 |
| 299 // On Windows, there is no need to call Create() since the message | 290 // On Windows, there is no need to call Create() since the message |
| 300 // window is created in the constructor but to avoid having more | 291 // window is created in the constructor but to avoid having more |
| 301 // platform specific code in browser_main.cc we tolerate calls to | 292 // platform specific code in browser_main.cc we tolerate calls to |
| 302 // Create(), which will do nothing. | 293 // Create(). |
| 303 bool ProcessSingleton::Create() { | 294 bool ProcessSingleton::Create( |
| 295 const NotificationCallback& notification_callback) { |
| 304 DCHECK(!remote_window_); | 296 DCHECK(!remote_window_); |
| 297 DCHECK(notification_callback_.is_null()); |
| 298 |
| 299 if (window_ != NULL) |
| 300 notification_callback_ = notification_callback; |
| 301 |
| 305 return window_ != NULL; | 302 return window_ != NULL; |
| 306 } | 303 } |
| 307 | 304 |
| 308 void ProcessSingleton::Cleanup() { | 305 void ProcessSingleton::Cleanup() { |
| 309 // Window classes registered by DLLs are not cleaned up automatically on | 306 // Window classes registered by DLLs are not cleaned up automatically on |
| 310 // process exit, so we must unregister at the earliest chance possible. | 307 // process exit, so we must unregister at the earliest chance possible. |
| 311 // During the fast shutdown sequence, ProcessSingleton::Cleanup() is | 308 // During the fast shutdown sequence, ProcessSingleton::Cleanup() is |
| 312 // called if our process was the first to start. Therefore we try cleaning | 309 // called if our process was the first to start. Therefore we try cleaning |
| 313 // up here, and again in the destructor if needed to catch as many cases | 310 // up here, and again in the destructor if needed to catch as many cases |
| 314 // as possible. | 311 // as possible. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 336 CommandLine parsed_command_line(CommandLine::NO_PROGRAM); | 333 CommandLine parsed_command_line(CommandLine::NO_PROGRAM); |
| 337 FilePath current_directory; | 334 FilePath current_directory; |
| 338 if (ParseCommandLine(cds, &parsed_command_line, ¤t_directory)) | 335 if (ParseCommandLine(cds, &parsed_command_line, ¤t_directory)) |
| 339 saved_startup_messages_.push_back( | 336 saved_startup_messages_.push_back( |
| 340 std::make_pair(parsed_command_line.argv(), current_directory)); | 337 std::make_pair(parsed_command_line.argv(), current_directory)); |
| 341 } | 338 } |
| 342 #endif | 339 #endif |
| 343 return TRUE; | 340 return TRUE; |
| 344 } | 341 } |
| 345 | 342 |
| 346 // Ignore the request if the browser process is already in shutdown path. | |
| 347 if (!g_browser_process || g_browser_process->IsShuttingDown()) { | |
| 348 LOG(WARNING) << "Not handling WM_COPYDATA as browser is shutting down"; | |
| 349 return FALSE; | |
| 350 } | |
| 351 | |
| 352 CommandLine parsed_command_line(CommandLine::NO_PROGRAM); | 343 CommandLine parsed_command_line(CommandLine::NO_PROGRAM); |
| 353 FilePath current_directory; | 344 FilePath current_directory; |
| 354 if (!ParseCommandLine(cds, &parsed_command_line, ¤t_directory)) | 345 if (!ParseCommandLine(cds, &parsed_command_line, ¤t_directory)) |
| 355 return TRUE; | 346 return TRUE; |
| 356 ProcessCommandLine(parsed_command_line, current_directory); | 347 return notification_callback_.Run(parsed_command_line, current_directory) ? |
| 357 return TRUE; | 348 TRUE : FALSE; |
| 358 } | 349 } |
| 359 | 350 |
| 360 LRESULT ProcessSingleton::WndProc(HWND hwnd, UINT message, | 351 LRESULT ProcessSingleton::WndProc(HWND hwnd, UINT message, |
| 361 WPARAM wparam, LPARAM lparam) { | 352 WPARAM wparam, LPARAM lparam) { |
| 362 switch (message) { | 353 switch (message) { |
| 363 case WM_COPYDATA: | 354 case WM_COPYDATA: |
| 364 return OnCopyData(reinterpret_cast<HWND>(wparam), | 355 return OnCopyData(reinterpret_cast<HWND>(wparam), |
| 365 reinterpret_cast<COPYDATASTRUCT*>(lparam)); | 356 reinterpret_cast<COPYDATASTRUCT*>(lparam)); |
| 366 default: | 357 default: |
| 367 break; | 358 break; |
| 368 } | 359 } |
| 369 | 360 |
| 370 return ::DefWindowProc(hwnd, message, wparam, lparam); | 361 return ::DefWindowProc(hwnd, message, wparam, lparam); |
| 371 } | 362 } |
| 372 | |
| 373 void ProcessSingleton::ProcessCommandLine(const CommandLine& command_line, | |
| 374 const FilePath& current_directory) { | |
| 375 PrefService* prefs = g_browser_process->local_state(); | |
| 376 DCHECK(prefs); | |
| 377 | |
| 378 // Handle the --uninstall-extension startup action. This needs to done here | |
| 379 // in the process that is running with the target profile, otherwise the | |
| 380 // uninstall will fail to unload and remove all components. | |
| 381 if (command_line.HasSwitch(switches::kUninstallExtension)) { | |
| 382 // The uninstall extension switch can't be combined with the profile | |
| 383 // directory switch. | |
| 384 DCHECK(!command_line.HasSwitch(switches::kProfileDirectory)); | |
| 385 | |
| 386 Profile* profile = ProfileManager::GetLastUsedProfile(); | |
| 387 if (!profile) { | |
| 388 // We should only be able to get here if the profile already exists and | |
| 389 // has been created. | |
| 390 NOTREACHED(); | |
| 391 return; | |
| 392 } | |
| 393 | |
| 394 ExtensionsStartupUtil ext_startup_util; | |
| 395 ext_startup_util.UninstallExtension(command_line, profile); | |
| 396 return; | |
| 397 } | |
| 398 | |
| 399 // Run the browser startup sequence again, with the command line of the | |
| 400 // signalling process. | |
| 401 BrowserInit::ProcessCommandLineAlreadyRunning(command_line, | |
| 402 current_directory); | |
| 403 } | |
| OLD | NEW |