blob: e7cc3c5bc7912b27f1f8ce0fb8f691e28284e238 [file] [log] [blame]
[email protected]e3ce40a2012-01-31 03:03:031// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]fc14cef2009-01-27 22:17:292// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]7c47ae3e2009-02-18 00:34:215#include "chrome/browser/process_singleton.h"
[email protected]fc14cef2009-01-27 22:17:296
manzagopf071e882016-04-13 14:36:007#include <windows.h>
[email protected]b1d7844b2012-08-22 22:37:478#include <shellapi.h>
avib896c712015-12-26 02:10:439#include <stddef.h>
[email protected]b1d7844b2012-08-22 22:37:4710
[email protected]fc14cef2009-01-27 22:17:2911#include "base/base_paths.h"
[email protected]4cf04bb2013-07-11 09:22:3812#include "base/bind.h"
[email protected]fc14cef2009-01-27 22:17:2913#include "base/command_line.h"
aseren028ea152017-05-16 17:22:4314#include "base/debug/activity_tracker.h"
[email protected]57999812013-02-24 05:40:5215#include "base/files/file_path.h"
Hans Wennborgf6ad69c2020-06-18 18:02:3216#include "base/logging.h"
avib896c712015-12-26 02:10:4317#include "base/macros.h"
Ilya Sherman982457e62017-12-13 02:19:3618#include "base/metrics/histogram_functions.h"
gab439f54f2016-10-07 22:24:2219#include "base/metrics/histogram_macros.h"
rvargas4683e5e2015-03-04 22:38:2020#include "base/process/process.h"
[email protected]d09a4ce1c2013-07-24 17:37:0221#include "base/process/process_info.h"
[email protected]84c584462013-05-13 05:05:0022#include "base/strings/string_number_conversions.h"
[email protected]e309f312013-06-07 21:50:0823#include "base/strings/utf_string_conversions.h"
[email protected]84813472013-06-28 00:25:1924#include "base/time/time.h"
Etienne Bergeronbacd29d82021-09-15 20:39:1225#include "base/trace_event/trace_event.h"
[email protected]b3d791c92012-10-05 19:01:2426#include "base/win/registry.h"
[email protected]b90d7e802011-01-09 16:32:2027#include "base/win/scoped_handle.h"
[email protected]6927f2e02012-09-18 00:13:4928#include "base/win/windows_version.h"
Guido Urdaneta73a943022018-08-24 15:42:2729#include "base/win/wmi.h"
[email protected]245900672012-10-13 02:27:1130#include "chrome/browser/shell_integration.h"
[email protected]b50892c5f2012-05-13 07:34:1431#include "chrome/browser/ui/simple_message_box.h"
pmonette23c8fb7e2016-06-27 20:45:1132#include "chrome/browser/win/chrome_process_finder.h"
[email protected]fc14cef2009-01-27 22:17:2933#include "chrome/common/chrome_constants.h"
[email protected]b3d791c92012-10-05 19:01:2434#include "chrome/common/chrome_paths.h"
35#include "chrome/common/chrome_paths_internal.h"
[email protected]cfa118a2012-10-10 22:27:5336#include "chrome/common/chrome_switches.h"
[email protected]af39f002014-08-22 10:18:1837#include "chrome/grit/chromium_strings.h"
[email protected]b39ef1cb2011-10-25 04:46:5538#include "content/public/common/result_codes.h"
[email protected]f394bc62012-08-22 21:42:2939#include "net/base/escape.h"
[email protected]c051a1b2011-01-21 23:30:1740#include "ui/base/l10n/l10n_util.h"
[email protected]bde885b2013-09-12 20:55:5341#include "ui/gfx/win/hwnd_util.h"
[email protected]fc14cef2009-01-27 22:17:2942
43namespace {
44
[email protected]2b7ff5b92012-07-17 22:45:1845const char kLockfile[] = "lockfile";
46
[email protected]14649ecd2012-12-05 01:00:2447// A helper class that acquires the given |mutex| while the AutoLockMutex is in
48// scope.
49class AutoLockMutex {
50 public:
51 explicit AutoLockMutex(HANDLE mutex) : mutex_(mutex) {
[email protected]b9057302013-03-28 12:40:3852 DWORD result = ::WaitForSingleObject(mutex_, INFINITE);
[email protected]14649ecd2012-12-05 01:00:2453 DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result;
54 }
55
Peter Boström53c6c5952021-09-17 09:41:2656 AutoLockMutex(const AutoLockMutex&) = delete;
57 AutoLockMutex& operator=(const AutoLockMutex&) = delete;
58
[email protected]14649ecd2012-12-05 01:00:2459 ~AutoLockMutex() {
[email protected]b9057302013-03-28 12:40:3860 BOOL released = ::ReleaseMutex(mutex_);
[email protected]14649ecd2012-12-05 01:00:2461 DPCHECK(released);
62 }
63
64 private:
65 HANDLE mutex_;
[email protected]14649ecd2012-12-05 01:00:2466};
67
68// A helper class that releases the given |mutex| while the AutoUnlockMutex is
69// in scope and immediately re-acquires it when going out of scope.
70class AutoUnlockMutex {
71 public:
72 explicit AutoUnlockMutex(HANDLE mutex) : mutex_(mutex) {
[email protected]b9057302013-03-28 12:40:3873 BOOL released = ::ReleaseMutex(mutex_);
[email protected]14649ecd2012-12-05 01:00:2474 DPCHECK(released);
75 }
76
Peter Boström53c6c5952021-09-17 09:41:2677 AutoUnlockMutex(const AutoUnlockMutex&) = delete;
78 AutoUnlockMutex& operator=(const AutoUnlockMutex&) = delete;
79
[email protected]14649ecd2012-12-05 01:00:2480 ~AutoUnlockMutex() {
[email protected]b9057302013-03-28 12:40:3881 DWORD result = ::WaitForSingleObject(mutex_, INFINITE);
[email protected]14649ecd2012-12-05 01:00:2482 DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result;
83 }
84
85 private:
86 HANDLE mutex_;
[email protected]14649ecd2012-12-05 01:00:2487};
[email protected]b3d791c92012-10-05 19:01:2488
[email protected]f891fb32009-04-08 00:20:3289// Checks the visibility of the enumerated window and signals once a visible
[email protected]fc14cef2009-01-27 22:17:2990// window has been found.
91BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) {
92 bool* result = reinterpret_cast<bool*>(param);
[email protected]b9057302013-03-28 12:40:3893 *result = ::IsWindowVisible(window) != 0;
[email protected]fc14cef2009-01-27 22:17:2994 // Stops enumeration if a visible window has been found.
95 return !*result;
96}
97
[email protected]edf04b512012-02-23 09:47:4398bool ParseCommandLine(const COPYDATASTRUCT* cds,
avi556c05022014-12-22 23:31:4399 base::CommandLine* parsed_command_line,
[email protected]650b2d52013-02-10 03:41:45100 base::FilePath* current_directory) {
[email protected]edf04b512012-02-23 09:47:43101 // We should have enough room for the shortest command (min_message_size)
102 // and also be a multiple of wchar_t bytes. The shortest command
103 // possible is L"START\0\0" (empty current directory and command line).
104 static const int min_message_size = 7;
105 if (cds->cbData < min_message_size * sizeof(wchar_t) ||
106 cds->cbData % sizeof(wchar_t) != 0) {
107 LOG(WARNING) << "Invalid WM_COPYDATA, length = " << cds->cbData;
108 return false;
109 }
110
111 // We split the string into 4 parts on NULLs.
112 DCHECK(cds->lpData);
113 const std::wstring msg(static_cast<wchar_t*>(cds->lpData),
114 cds->cbData / sizeof(wchar_t));
115 const std::wstring::size_type first_null = msg.find_first_of(L'\0');
116 if (first_null == 0 || first_null == std::wstring::npos) {
117 // no NULL byte, don't know what to do
118 LOG(WARNING) << "Invalid WM_COPYDATA, length = " << msg.length() <<
119 ", first null = " << first_null;
120 return false;
121 }
122
123 // Decode the command, which is everything until the first NULL.
124 if (msg.substr(0, first_null) == L"START") {
125 // Another instance is starting parse the command line & do what it would
126 // have done.
127 VLOG(1) << "Handling STARTUP request from another process";
128 const std::wstring::size_type second_null =
129 msg.find_first_of(L'\0', first_null + 1);
130 if (second_null == std::wstring::npos ||
131 first_null == msg.length() - 1 || second_null == msg.length()) {
132 LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
133 "parts separated by NULLs";
134 return false;
135 }
136
137 // Get current directory.
[email protected]650b2d52013-02-10 03:41:45138 *current_directory = base::FilePath(msg.substr(first_null + 1,
[email protected]b9057302013-03-28 12:40:38139 second_null - first_null));
[email protected]edf04b512012-02-23 09:47:43140
141 const std::wstring::size_type third_null =
142 msg.find_first_of(L'\0', second_null + 1);
143 if (third_null == std::wstring::npos ||
144 third_null == msg.length()) {
145 LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
146 "parts separated by NULLs";
147 }
148
149 // Get command line.
150 const std::wstring cmd_line =
151 msg.substr(second_null + 1, third_null - second_null);
avi556c05022014-12-22 23:31:43152 *parsed_command_line = base::CommandLine::FromString(cmd_line);
[email protected]edf04b512012-02-23 09:47:43153 return true;
154 }
155 return false;
156}
157
[email protected]4cf04bb2013-07-11 09:22:38158bool ProcessLaunchNotification(
159 const ProcessSingleton::NotificationCallback& notification_callback,
160 UINT message,
161 WPARAM wparam,
162 LPARAM lparam,
163 LRESULT* result) {
164 if (message != WM_COPYDATA)
165 return false;
166
167 // Handle the WM_COPYDATA message from another process.
[email protected]4cf04bb2013-07-11 09:22:38168 const COPYDATASTRUCT* cds = reinterpret_cast<COPYDATASTRUCT*>(lparam);
169
avi556c05022014-12-22 23:31:43170 base::CommandLine parsed_command_line(base::CommandLine::NO_PROGRAM);
[email protected]4cf04bb2013-07-11 09:22:38171 base::FilePath current_directory;
172 if (!ParseCommandLine(cds, &parsed_command_line, &current_directory)) {
173 *result = TRUE;
174 return true;
175 }
176
177 *result = notification_callback.Run(parsed_command_line, current_directory) ?
178 TRUE : FALSE;
179 return true;
180}
181
siggi2a0214b2015-03-12 14:50:27182bool DisplayShouldKillMessageBox() {
Collin Baker58ae65c2021-02-05 21:12:29183 return chrome::ShowQuestionMessageBoxSync(
siggi2a0214b2015-03-12 14:50:27184 NULL, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
estadee16f96ed2016-03-07 22:57:05185 l10n_util::GetStringUTF16(IDS_BROWSER_HUNGBROWSER_MESSAGE)) !=
siggi2a0214b2015-03-12 14:50:27186 chrome::MESSAGE_BOX_RESULT_NO;
187}
188
aseren028ea152017-05-16 17:22:43189void SendRemoteProcessInteractionResultHistogram(
190 ProcessSingleton::RemoteProcessInteractionResult result) {
191 UMA_HISTOGRAM_ENUMERATION(
192 "Chrome.ProcessSingleton.RemoteProcessInteractionResult", result,
193 ProcessSingleton::REMOTE_PROCESS_INTERACTION_RESULT_COUNT);
194}
195
196// Function was copied from Process::Terminate.
197void TerminateProcessWithHistograms(const base::Process& process,
198 int exit_code) {
199 DCHECK(process.IsValid());
200 base::TimeTicks start_time = base::TimeTicks::Now();
201 bool result = (::TerminateProcess(process.Handle(), exit_code) != FALSE);
202 DWORD terminate_error = 0;
203 if (result) {
204 DWORD wait_error = 0;
205 // The process may not end immediately due to pending I/O
206 DWORD wait_result = ::WaitForSingleObject(process.Handle(), 60 * 1000);
207 if (wait_result != WAIT_OBJECT_0) {
208 if (wait_result == WAIT_FAILED)
209 wait_error = ::GetLastError();
210 SendRemoteProcessInteractionResultHistogram(
211 ProcessSingleton::TERMINATE_WAIT_TIMEOUT);
212 DPLOG(ERROR) << "Error waiting for process exit";
213 } else {
214 SendRemoteProcessInteractionResultHistogram(
215 ProcessSingleton::TERMINATE_SUCCEEDED);
216 }
217 base::debug::GlobalActivityTracker::RecordProcessExitIfEnabled(
218 process.Pid(), exit_code);
219 UMA_HISTOGRAM_TIMES("Chrome.ProcessSingleton.TerminateProcessTime",
220 base::TimeTicks::Now() - start_time);
Ilya Sherman982457e62017-12-13 02:19:36221 base::UmaHistogramSparse(
aseren028ea152017-05-16 17:22:43222 "Chrome.ProcessSingleton.TerminationWaitErrorCode.Windows", wait_error);
223 } else {
224 terminate_error = ::GetLastError();
225 SendRemoteProcessInteractionResultHistogram(
226 ProcessSingleton::TERMINATE_FAILED);
227 DPLOG(ERROR) << "Unable to terminate process";
228 }
Ilya Sherman982457e62017-12-13 02:19:36229 base::UmaHistogramSparse(
Aleksei Seren75591e732017-12-01 21:47:45230 "Chrome.ProcessSingleton.TerminateProcessErrorCode.Windows",
aseren028ea152017-05-16 17:22:43231 terminate_error);
232}
233
[email protected]fc14cef2009-01-27 22:17:29234} // namespace
235
[email protected]0a194552011-09-14 17:53:35236// Microsoft's Softricity virtualization breaks the sandbox processes.
237// So, if we detect the Softricity DLL we use WMI Win32_Process.Create to
238// break out of the virtualization environment.
239// http://code.google.com/p/chromium/issues/detail?id=43650
[email protected]650b2d52013-02-10 03:41:45240bool ProcessSingleton::EscapeVirtualization(
241 const base::FilePath& user_data_dir) {
[email protected]0a194552011-09-14 17:53:35242 if (::GetModuleHandle(L"sftldr_wow64.dll") ||
243 ::GetModuleHandle(L"sftldr.dll")) {
244 int process_id;
Guido Urdaneta73a943022018-08-24 15:42:27245 if (!base::win::WmiLaunchProcess(::GetCommandLineW(), &process_id))
[email protected]0a194552011-09-14 17:53:35246 return false;
247 is_virtualized_ = true;
248 // The new window was spawned from WMI, and won't be in the foreground.
249 // So, first we sleep while the new chrome.exe instance starts (because
250 // WaitForInputIdle doesn't work here). Then we poll for up to two more
251 // seconds and make the window foreground if we find it (or we give up).
252 HWND hwnd = 0;
253 ::Sleep(90);
254 for (int tries = 200; tries; --tries) {
[email protected]10118162013-06-05 00:24:45255 hwnd = chrome::FindRunningChromeWindow(user_data_dir);
[email protected]0a194552011-09-14 17:53:35256 if (hwnd) {
257 ::SetForegroundWindow(hwnd);
258 break;
259 }
260 ::Sleep(10);
261 }
262 return true;
263 }
264 return false;
265}
266
[email protected]dd85d452013-03-28 12:39:59267ProcessSingleton::ProcessSingleton(
268 const base::FilePath& user_data_dir,
269 const NotificationCallback& notification_callback)
[email protected]4cf04bb2013-07-11 09:22:38270 : notification_callback_(notification_callback),
siggi2a0214b2015-03-12 14:50:27271 is_virtualized_(false),
272 lock_file_(INVALID_HANDLE_VALUE),
273 user_data_dir_(user_data_dir),
274 should_kill_remote_process_callback_(
Alexander Cooper4bcb0ce2020-07-16 23:10:38275 base::BindRepeating(&DisplayShouldKillMessageBox)) {}
[email protected]fc14cef2009-01-27 22:17:29276
[email protected]7c47ae3e2009-02-18 00:34:21277ProcessSingleton::~ProcessSingleton() {
gab25894fe2017-05-30 03:40:36278 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]2b7ff5b92012-07-17 22:45:18279 if (lock_file_ != INVALID_HANDLE_VALUE)
[email protected]b9057302013-03-28 12:40:38280 ::CloseHandle(lock_file_);
[email protected]fc14cef2009-01-27 22:17:29281}
282
[email protected]14649ecd2012-12-05 01:00:24283// Code roughly based on Mozilla.
[email protected]9f20a6d02009-08-21 01:18:37284ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
[email protected]0a194552011-09-14 17:53:35285 if (is_virtualized_)
286 return PROCESS_NOTIFIED; // We already spawned the process in this case.
[email protected]e9613b52012-11-27 22:35:13287 if (lock_file_ == INVALID_HANDLE_VALUE && !remote_window_) {
[email protected]2b7ff5b92012-07-17 22:45:18288 return LOCK_ERROR;
[email protected]e9613b52012-11-27 22:35:13289 } else if (!remote_window_) {
[email protected]9f20a6d02009-08-21 01:18:37290 return PROCESS_NONE;
[email protected]e9613b52012-11-27 22:35:13291 }
[email protected]fc14cef2009-01-27 22:17:29292
Francois Doray1aaf5a22020-01-22 16:04:45293 switch (chrome::AttemptToNotifyRunningChrome(remote_window_)) {
[email protected]10118162013-06-05 00:24:45294 case chrome::NOTIFY_SUCCESS:
295 return PROCESS_NOTIFIED;
296 case chrome::NOTIFY_FAILED:
[email protected]0815b6d2009-02-11 00:39:37297 remote_window_ = NULL;
aseren028ea152017-05-16 17:22:43298 SendRemoteProcessInteractionResultHistogram(RUNNING_PROCESS_NOTIFY_ERROR);
[email protected]9f20a6d02009-08-21 01:18:37299 return PROCESS_NONE;
[email protected]10118162013-06-05 00:24:45300 case chrome::NOTIFY_WINDOW_HUNG:
siggid896f9a2015-10-07 17:19:27301 // Fall through and potentially terminate the hung browser.
[email protected]10118162013-06-05 00:24:45302 break;
[email protected]fc14cef2009-01-27 22:17:29303 }
304
manzagopf071e882016-04-13 14:36:00305 // The window is hung.
[email protected]10118162013-06-05 00:24:45306 DWORD process_id = 0;
307 DWORD thread_id = ::GetWindowThreadProcessId(remote_window_, &process_id);
308 if (!thread_id || !process_id) {
[email protected]0815b6d2009-02-11 00:39:37309 remote_window_ = NULL;
aseren028ea152017-05-16 17:22:43310 SendRemoteProcessInteractionResultHistogram(REMOTE_PROCESS_NOT_FOUND);
[email protected]9f20a6d02009-08-21 01:18:37311 return PROCESS_NONE;
[email protected]0815b6d2009-02-11 00:39:37312 }
manzagopf071e882016-04-13 14:36:00313
314 // Get a handle to the process that created the window.
rvargas4683e5e2015-03-04 22:38:20315 base::Process process = base::Process::Open(process_id);
[email protected]0815b6d2009-02-11 00:39:37316
manzagopf071e882016-04-13 14:36:00317 // Scan for every window to find a visible one.
[email protected]fc14cef2009-01-27 22:17:29318 bool visible_window = false;
[email protected]b9057302013-03-28 12:40:38319 ::EnumThreadWindows(thread_id,
320 &BrowserWindowEnumeration,
321 reinterpret_cast<LPARAM>(&visible_window));
[email protected]fc14cef2009-01-27 22:17:29322
323 // If there is a visible browser window, ask the user before killing it.
siggi2a0214b2015-03-12 14:50:27324 if (visible_window && !should_kill_remote_process_callback_.Run()) {
Mikhail Atuchina6e8bcd32018-07-06 12:14:03325 SendRemoteProcessInteractionResultHistogram(USER_REFUSED_TERMINATION);
[email protected]5da155e2012-05-26 16:31:16326 // The user denied. Quit silently.
327 return PROCESS_NOTIFIED;
[email protected]fc14cef2009-01-27 22:17:29328 }
aseren028ea152017-05-16 17:22:43329 UMA_HISTOGRAM_ENUMERATION(
330 "Chrome.ProcessSingleton.RemoteHungProcessTerminateReason",
331 visible_window ? USER_ACCEPTED_TERMINATION : NO_VISIBLE_WINDOW_FOUND,
332 REMOTE_HUNG_PROCESS_TERMINATE_REASON_COUNT);
[email protected]fc14cef2009-01-27 22:17:29333
334 // Time to take action. Kill the browser process.
aseren028ea152017-05-16 17:22:43335 TerminateProcessWithHistograms(process, content::RESULT_CODE_HUNG);
336
[email protected]fc14cef2009-01-27 22:17:29337 remote_window_ = NULL;
[email protected]9f20a6d02009-08-21 01:18:37338 return PROCESS_NONE;
[email protected]fc14cef2009-01-27 22:17:29339}
340
[email protected]10118162013-06-05 00:24:45341ProcessSingleton::NotifyResult
342ProcessSingleton::NotifyOtherProcessOrCreate() {
Etienne Bergeronbacd29d82021-09-15 20:39:12343 TRACE_EVENT0("startup", "ProcessSingleton::NotifyOtherProcessOrCreate");
gab439f54f2016-10-07 22:24:22344 const base::TimeTicks begin_ticks = base::TimeTicks::Now();
gcomanici66815672016-08-30 04:54:10345 for (int i = 0; i < 2; ++i) {
346 if (Create()) {
gab439f54f2016-10-07 22:24:22347 UMA_HISTOGRAM_MEDIUM_TIMES("Chrome.ProcessSingleton.TimeToCreate",
348 base::TimeTicks::Now() - begin_ticks);
gcomanici66815672016-08-30 04:54:10349 return PROCESS_NONE; // This is the single browser process.
350 }
351 ProcessSingleton::NotifyResult result = NotifyOtherProcess();
352 if (result == PROCESS_NOTIFIED || result == LOCK_ERROR) {
gab439f54f2016-10-07 22:24:22353 if (result == PROCESS_NOTIFIED) {
354 UMA_HISTOGRAM_MEDIUM_TIMES("Chrome.ProcessSingleton.TimeToNotify",
355 base::TimeTicks::Now() - begin_ticks);
356 } else {
357 UMA_HISTOGRAM_MEDIUM_TIMES("Chrome.ProcessSingleton.TimeToFailure",
358 base::TimeTicks::Now() - begin_ticks);
359 }
gcomanici66815672016-08-30 04:54:10360 // The single browser process was notified, the user chose not to
361 // terminate a hung browser, or the lock file could not be created.
362 // Nothing more to do.
363 return result;
364 }
365 DCHECK_EQ(PROCESS_NONE, result);
366 // The process could not be notified for some reason, or it was hung and
367 // terminated. Retry once if this is the first time; otherwise, fall through
368 // to report that the process must exit because the profile is in use.
[email protected]14649ecd2012-12-05 01:00:24369 }
gab439f54f2016-10-07 22:24:22370 UMA_HISTOGRAM_MEDIUM_TIMES("Chrome.ProcessSingleton.TimeToFailure",
371 base::TimeTicks::Now() - begin_ticks);
gcomanici66815672016-08-30 04:54:10372 return PROFILE_IN_USE;
[email protected]4a44bc32010-05-28 22:22:44373}
374
[email protected]14649ecd2012-12-05 01:00:24375// Look for a Chrome instance that uses the same profile directory. If there
376// isn't one, create a message window with its title set to the profile
377// directory path.
[email protected]dd85d452013-03-28 12:39:59378bool ProcessSingleton::Create() {
[email protected]14649ecd2012-12-05 01:00:24379 static const wchar_t kMutexName[] = L"Local\\ChromeProcessSingletonStartup!";
[email protected]14649ecd2012-12-05 01:00:24380
[email protected]10118162013-06-05 00:24:45381 remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
[email protected]14649ecd2012-12-05 01:00:24382 if (!remote_window_ && !EscapeVirtualization(user_data_dir_)) {
383 // Make sure we will be the one and only process creating the window.
384 // We use a named Mutex since we are protecting against multi-process
385 // access. As documented, it's clearer to NOT request ownership on creation
386 // since it isn't guaranteed we will get it. It is better to create it
387 // without ownership and explicitly get the ownership afterward.
[email protected]b9057302013-03-28 12:40:38388 base::win::ScopedHandle only_me(::CreateMutex(NULL, FALSE, kMutexName));
rvargasd7743ba2014-09-25 01:35:28389 if (!only_me.IsValid()) {
390 DPLOG(FATAL) << "CreateMutex failed";
391 return false;
392 }
[email protected]14649ecd2012-12-05 01:00:24393
rvargasd7743ba2014-09-25 01:35:28394 AutoLockMutex auto_lock_only_me(only_me.Get());
[email protected]14649ecd2012-12-05 01:00:24395
396 // We now own the mutex so we are the only process that can create the
397 // window at this time, but we must still check if someone created it
398 // between the time where we looked for it above and the time the mutex
399 // was given to us.
[email protected]10118162013-06-05 00:24:45400 remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
[email protected]14649ecd2012-12-05 01:00:24401
[email protected]14649ecd2012-12-05 01:00:24402 if (!remote_window_) {
403 // We have to make sure there is no Chrome instance running on another
404 // machine that uses the same profile.
[email protected]650b2d52013-02-10 03:41:45405 base::FilePath lock_file_path = user_data_dir_.AppendASCII(kLockfile);
[email protected]b9057302013-03-28 12:40:38406 lock_file_ = ::CreateFile(lock_file_path.value().c_str(),
407 GENERIC_WRITE,
408 FILE_SHARE_READ,
409 NULL,
410 CREATE_ALWAYS,
411 FILE_ATTRIBUTE_NORMAL |
412 FILE_FLAG_DELETE_ON_CLOSE,
413 NULL);
414 DWORD error = ::GetLastError();
[email protected]14649ecd2012-12-05 01:00:24415 LOG_IF(WARNING, lock_file_ != INVALID_HANDLE_VALUE &&
416 error == ERROR_ALREADY_EXISTS) << "Lock file exists but is writable.";
417 LOG_IF(ERROR, lock_file_ == INVALID_HANDLE_VALUE)
418 << "Lock file can not be created! Error code: " << error;
419
420 if (lock_file_ != INVALID_HANDLE_VALUE) {
[email protected]14649ecd2012-12-05 01:00:24421 // Set the window's title to the path of our user data directory so
422 // other Chrome instances can decide if they should forward to us.
Alexander Cooper4bcb0ce2020-07-16 23:10:38423 bool result =
424 window_.CreateNamed(base::BindRepeating(&ProcessLaunchNotification,
425 notification_callback_),
426 user_data_dir_.value());
[email protected]4cf04bb2013-07-11 09:22:38427 CHECK(result && window_.hwnd());
[email protected]14649ecd2012-12-05 01:00:24428 }
[email protected]14649ecd2012-12-05 01:00:24429 }
430 }
431
[email protected]4cf04bb2013-07-11 09:22:38432 return window_.hwnd() != NULL;
[email protected]fc14cef2009-01-27 22:17:29433}
434
[email protected]9f20a6d02009-08-21 01:18:37435void ProcessSingleton::Cleanup() {
436}
siggi2a0214b2015-03-12 14:50:27437
438void ProcessSingleton::OverrideShouldKillRemoteProcessCallbackForTesting(
439 const ShouldKillRemoteProcessCallback& display_dialog_callback) {
440 should_kill_remote_process_callback_ = display_dialog_callback;
441}