15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/process_singleton.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shellapi.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base_paths.h" 107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/bind.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h" 14bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/kill.h" 15bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/process_info.h" 16a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/metro.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/registry.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_handle.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/browser_process.h" 2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/browser_process_platform_part.h" 26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/chrome_process_finder_win.h" 27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/metro_utils/metro_chrome_win.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/shell_integration.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/simple_message_box.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_paths.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_paths_internal.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h" 3403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/grit/chromium_strings.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/wmi.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/result_codes.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/escape.h" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 39d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/win/hwnd_util.h" 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kLockfile[] = "lockfile"; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kMetroChromeActivationTimeoutMs = 3000; 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// A helper class that acquires the given |mutex| while the AutoLockMutex is in 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// scope. 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class AutoLockMutex { 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) explicit AutoLockMutex(HANDLE mutex) : mutex_(mutex) { 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DWORD result = ::WaitForSingleObject(mutex_, INFINITE); 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result; 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ~AutoLockMutex() { 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) BOOL released = ::ReleaseMutex(mutex_); 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DPCHECK(released); 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HANDLE mutex_; 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(AutoLockMutex); 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// A helper class that releases the given |mutex| while the AutoUnlockMutex is 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// in scope and immediately re-acquires it when going out of scope. 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class AutoUnlockMutex { 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) explicit AutoUnlockMutex(HANDLE mutex) : mutex_(mutex) { 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) BOOL released = ::ReleaseMutex(mutex_); 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DPCHECK(released); 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ~AutoUnlockMutex() { 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DWORD result = ::WaitForSingleObject(mutex_, INFINITE); 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result; 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HANDLE mutex_; 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(AutoUnlockMutex); 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Checks the visibility of the enumerated window and signals once a visible 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// window has been found. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* result = reinterpret_cast<bool*>(param); 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *result = ::IsWindowVisible(window) != 0; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Stops enumeration if a visible window has been found. 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !*result; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ParseCommandLine(const COPYDATASTRUCT* cds, 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandLine* parsed_command_line, 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath* current_directory) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should have enough room for the shortest command (min_message_size) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and also be a multiple of wchar_t bytes. The shortest command 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // possible is L"START\0\0" (empty current directory and command line). 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int min_message_size = 7; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cds->cbData < min_message_size * sizeof(wchar_t) || 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cds->cbData % sizeof(wchar_t) != 0) { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(WARNING) << "Invalid WM_COPYDATA, length = " << cds->cbData; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We split the string into 4 parts on NULLs. 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(cds->lpData); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring msg(static_cast<wchar_t*>(cds->lpData), 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cds->cbData / sizeof(wchar_t)); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring::size_type first_null = msg.find_first_of(L'\0'); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (first_null == 0 || first_null == std::wstring::npos) { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // no NULL byte, don't know what to do 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(WARNING) << "Invalid WM_COPYDATA, length = " << msg.length() << 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ", first null = " << first_null; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Decode the command, which is everything until the first NULL. 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (msg.substr(0, first_null) == L"START") { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Another instance is starting parse the command line & do what it would 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have done. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "Handling STARTUP request from another process"; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring::size_type second_null = 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg.find_first_of(L'\0', first_null + 1); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (second_null == std::wstring::npos || 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) first_null == msg.length() - 1 || second_null == msg.length()) { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(WARNING) << "Invalid format for start command, we need a string in 4 " 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "parts separated by NULLs"; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get current directory. 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *current_directory = base::FilePath(msg.substr(first_null + 1, 135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) second_null - first_null)); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring::size_type third_null = 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg.find_first_of(L'\0', second_null + 1); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (third_null == std::wstring::npos || 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) third_null == msg.length()) { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(WARNING) << "Invalid format for start command, we need a string in 4 " 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "parts separated by NULLs"; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get command line. 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring cmd_line = 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg.substr(second_null + 1, third_null - second_null); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *parsed_command_line = CommandLine::FromString(cmd_line); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool ProcessLaunchNotification( 1557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const ProcessSingleton::NotificationCallback& notification_callback, 1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch UINT message, 1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch WPARAM wparam, 1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch LPARAM lparam, 1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch LRESULT* result) { 1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (message != WM_COPYDATA) 1617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return false; 1627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // Handle the WM_COPYDATA message from another process. 1647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch HWND hwnd = reinterpret_cast<HWND>(wparam); 1657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const COPYDATASTRUCT* cds = reinterpret_cast<COPYDATASTRUCT*>(lparam); 1667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch CommandLine parsed_command_line(CommandLine::NO_PROGRAM); 1687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::FilePath current_directory; 1697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!ParseCommandLine(cds, &parsed_command_line, ¤t_directory)) { 1707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch *result = TRUE; 1717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return true; 1727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 1737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch *result = notification_callback.Run(parsed_command_line, current_directory) ? 1757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch TRUE : FALSE; 1767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return true; 1777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 1787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if Chrome needs to be relaunched into Windows 8 immersive mode. 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Following conditions apply:- 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 1. Windows 8 or greater. 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2. Not in Windows 8 immersive mode. 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 3. Chrome is default browser. 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 4. Process integrity level is not high. 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 5. The profile data directory is the default directory. 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 6. Last used mode was immersive/machine is a tablet. 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(ananta) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Move this function to a common place as the Windows 8 delegate_execute 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// handler can possibly use this. 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ShouldLaunchInWindows8ImmersiveMode(const base::FilePath& user_data_dir) { 191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#if defined(USE_AURA) 192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Returning false from this function doesn't mean we don't launch immersive 193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // mode in Aura. This function is specifically called in case when we need 194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // to relaunch desktop launched chrome into immersive mode through 'relaunch' 195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // menu. In case of Aura, we will use delegate_execute to do the relaunch. 196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 19723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#else 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::win::GetVersion() < base::win::VERSION_WIN8) 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::win::IsProcessImmersive(base::GetCurrentProcessHandle())) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ShellIntegration::GetDefaultBrowser() != ShellIntegration::IS_DEFAULT) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntegrityLevel integrity_level = base::INTEGRITY_UNKNOWN; 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::GetProcessIntegrityLevel(base::GetCurrentProcessHandle(), 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &integrity_level); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (integrity_level == base::HIGH_INTEGRITY) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath default_user_data_dir; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!chrome::GetDefaultUserDataDirectory(&default_user_data_dir)) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (default_user_data_dir != user_data_dir) 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::win::RegKey reg_key; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD reg_value = 0; 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (reg_key.Create(HKEY_CURRENT_USER, chrome::kMetroRegistryPath, 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) KEY_READ) == ERROR_SUCCESS && 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reg_key.ReadValueDW(chrome::kLaunchModeValue, 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ®_value) == ERROR_SUCCESS) { 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return reg_value == 1; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 22923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#endif 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Microsoft's Softricity virtualization breaks the sandbox processes. 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// So, if we detect the Softricity DLL we use WMI Win32_Process.Create to 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// break out of the virtualization environment. 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://code.google.com/p/chromium/issues/detail?id=43650 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ProcessSingleton::EscapeVirtualization( 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& user_data_dir) { 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (::GetModuleHandle(L"sftldr_wow64.dll") || 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ::GetModuleHandle(L"sftldr.dll")) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int process_id; 243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!installer::WMIProcess::Launch(::GetCommandLineW(), &process_id)) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_virtualized_ = true; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The new window was spawned from WMI, and won't be in the foreground. 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // So, first we sleep while the new chrome.exe instance starts (because 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // WaitForInputIdle doesn't work here). Then we poll for up to two more 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // seconds and make the window foreground if we find it (or we give up). 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HWND hwnd = 0; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ::Sleep(90); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int tries = 200; tries; --tries) { 253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) hwnd = chrome::FindRunningChromeWindow(user_data_dir); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (hwnd) { 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ::SetForegroundWindow(hwnd); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ::Sleep(10); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ProcessSingleton::ProcessSingleton( 266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::FilePath& user_data_dir, 267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const NotificationCallback& notification_callback) 2687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch : notification_callback_(notification_callback), 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) is_virtualized_(false), lock_file_(INVALID_HANDLE_VALUE), 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) user_data_dir_(user_data_dir) { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProcessSingleton::~ProcessSingleton() { 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (lock_file_ != INVALID_HANDLE_VALUE) 275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ::CloseHandle(lock_file_); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Code roughly based on Mozilla. 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_virtualized_) 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PROCESS_NOTIFIED; // We already spawned the process in this case. 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (lock_file_ == INVALID_HANDLE_VALUE && !remote_window_) { 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOCK_ERROR; 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (!remote_window_) { 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PROCESS_NONE; 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch switch (chrome::AttemptToNotifyRunningChrome(remote_window_, false)) { 289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) case chrome::NOTIFY_SUCCESS: 290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return PROCESS_NOTIFIED; 291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) case chrome::NOTIFY_FAILED: 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) remote_window_ = NULL; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PROCESS_NONE; 294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) case chrome::NOTIFY_WINDOW_HUNG: 295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) remote_window_ = NULL; 296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) break; 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DWORD process_id = 0; 300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DWORD thread_id = ::GetWindowThreadProcessId(remote_window_, &process_id); 301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!thread_id || !process_id) { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) remote_window_ = NULL; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PROCESS_NONE; 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The window is hung. Scan for every window to find a visible one. 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool visible_window = false; 308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ::EnumThreadWindows(thread_id, 309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &BrowserWindowEnumeration, 310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) reinterpret_cast<LPARAM>(&visible_window)); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there is a visible browser window, ask the user before killing it. 313868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (visible_window && 314868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) chrome::ShowMessageBox( 315868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) NULL, 316868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), 317868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) l10n_util::GetStringUTF16(IDS_BROWSER_HUNGBROWSER_MESSAGE), 318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) chrome::MESSAGE_BOX_TYPE_QUESTION) == chrome::MESSAGE_BOX_RESULT_NO) { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The user denied. Quit silently. 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PROCESS_NOTIFIED; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Time to take action. Kill the browser process. 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::KillProcessById(process_id, content::RESULT_CODE_HUNG, true); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) remote_window_ = NULL; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PROCESS_NONE; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ProcessSingleton::NotifyResult 330868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ProcessSingleton::NotifyOtherProcessOrCreate() { 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ProcessSingleton::NotifyResult result = PROCESS_NONE; 332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!Create()) { 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result = NotifyOtherProcess(); 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (result == PROCESS_NONE) 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result = PROFILE_IN_USE; 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) g_browser_process->platform_part()->PlatformSpecificCommandLineProcessing( 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *CommandLine::ForCurrentProcess()); 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return result; 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Look for a Chrome instance that uses the same profile directory. If there 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// isn't one, create a message window with its title set to the profile 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// directory path. 346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ProcessSingleton::Create() { 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static const wchar_t kMutexName[] = L"Local\\ChromeProcessSingletonStartup!"; 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static const wchar_t kMetroActivationEventName[] = 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) L"Local\\ChromeProcessSingletonStartupMetroActivation!"; 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_); 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!remote_window_ && !EscapeVirtualization(user_data_dir_)) { 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Make sure we will be the one and only process creating the window. 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We use a named Mutex since we are protecting against multi-process 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // access. As documented, it's clearer to NOT request ownership on creation 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // since it isn't guaranteed we will get it. It is better to create it 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // without ownership and explicitly get the ownership afterward. 358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::win::ScopedHandle only_me(::CreateMutex(NULL, FALSE, kMutexName)); 3591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!only_me.IsValid()) { 3601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DPLOG(FATAL) << "CreateMutex failed"; 3611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 3621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AutoLockMutex auto_lock_only_me(only_me.Get()); 3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We now own the mutex so we are the only process that can create the 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // window at this time, but we must still check if someone created it 3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // between the time where we looked for it above and the time the mutex 3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // was given to us. 370868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_); 3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // In Win8+, a new Chrome process launched in Desktop mode may need to be 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // transmuted into Metro Chrome (see ShouldLaunchInWindows8ImmersiveMode for 3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // heuristics). To accomplish this, the current Chrome activates Metro 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Chrome, releases the startup mutex, and waits for metro Chrome to take 3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the singleton. From that point onward, the command line for this Chrome 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // process will be sent to Metro Chrome by the usual channels. 3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!remote_window_ && base::win::GetVersion() >= base::win::VERSION_WIN8 && 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !base::win::IsMetroProcess()) { 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |metro_activation_event| is created right before activating a Metro 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Chrome (note that there can only be one Metro Chrome process; by OS 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // design); all following Desktop processes will then wait for this event 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // to be signaled by Metro Chrome which will do so as soon as it grabs 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // this singleton (should any of the waiting processes timeout waiting for 3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the signal they will try to grab the singleton for themselves which 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // will result in a forced Desktop Chrome launch in the worst case). 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::win::ScopedHandle metro_activation_event( 389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ::OpenEvent(SYNCHRONIZE, FALSE, kMetroActivationEventName)); 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!metro_activation_event.IsValid() && 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ShouldLaunchInWindows8ImmersiveMode(user_data_dir_)) { 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // No Metro activation is under way, but the desire is to launch in 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Metro mode: activate and rendez-vous with the activated process. 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) metro_activation_event.Set( 395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ::CreateEvent(NULL, TRUE, FALSE, kMetroActivationEventName)); 3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!chrome::ActivateMetroChrome()) { 3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Failed to launch immersive Chrome, default to launching on Desktop. 3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Failed to launch immersive chrome"; 3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) metro_activation_event.Close(); 4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (metro_activation_event.IsValid()) { 4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Release |only_me| (to let Metro Chrome grab this singleton) and wait 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // until the event is signaled (i.e. Metro Chrome was successfully 4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // activated). Ignore timeout waiting for |metro_activation_event|. 4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) { 4081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AutoUnlockMutex auto_unlock_only_me(only_me.Get()); 4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DWORD result = ::WaitForSingleObject(metro_activation_event.Get(), 411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) kMetroChromeActivationTimeoutMs); 4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DPCHECK(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT) 4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << "Result = " << result; 4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check if this singleton was successfully grabbed by another process 4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // (hopefully Metro Chrome). Failing to do so, this process will grab 4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the singleton and launch in Desktop mode. 419868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_); 4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!remote_window_) { 4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We have to make sure there is no Chrome instance running on another 4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // machine that uses the same profile. 4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath lock_file_path = user_data_dir_.AppendASCII(kLockfile); 427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) lock_file_ = ::CreateFile(lock_file_path.value().c_str(), 428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) GENERIC_WRITE, 429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) FILE_SHARE_READ, 430c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NULL, 431c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CREATE_ALWAYS, 432c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) FILE_ATTRIBUTE_NORMAL | 433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) FILE_FLAG_DELETE_ON_CLOSE, 434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NULL); 435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DWORD error = ::GetLastError(); 4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG_IF(WARNING, lock_file_ != INVALID_HANDLE_VALUE && 4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) error == ERROR_ALREADY_EXISTS) << "Lock file exists but is writable."; 4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG_IF(ERROR, lock_file_ == INVALID_HANDLE_VALUE) 4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << "Lock file can not be created! Error code: " << error; 4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (lock_file_ != INVALID_HANDLE_VALUE) { 4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Set the window's title to the path of our user data directory so 4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // other Chrome instances can decide if they should forward to us. 4447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch bool result = window_.CreateNamed( 4457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::Bind(&ProcessLaunchNotification, notification_callback_), 4467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch user_data_dir_.value()); 4477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch CHECK(result && window_.hwnd()); 4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (base::win::GetVersion() >= base::win::VERSION_WIN8) { 4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Make sure no one is still waiting on Metro activation whether it 4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // succeeded (i.e., this is the Metro process) or failed. 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::win::ScopedHandle metro_activation_event( 454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ::OpenEvent(EVENT_MODIFY_STATE, FALSE, kMetroActivationEventName)); 4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (metro_activation_event.IsValid()) 4561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ::SetEvent(metro_activation_event.Get()); 4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return window_.hwnd() != NULL; 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProcessSingleton::Cleanup() { 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 466