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 3 // found in the LICENSE file. 4 5 #include "build/intsafe_workaround.h" 6 7 #include <atlbase.h> 8 #include <atlcom.h> 9 #include <atlctl.h> 10 #include <initguid.h> 11 #include <shellapi.h> 12 13 #include "base/at_exit.h" 14 #include "base/command_line.h" 15 #include "base/file_util.h" 16 #include "base/memory/scoped_ptr.h" 17 #include "base/process/kill.h" 18 #include "base/strings/string16.h" 19 #include "base/win/scoped_com_initializer.h" 20 #include "base/win/scoped_handle.h" 21 #include "breakpad/src/client/windows/handler/exception_handler.h" 22 #include "chrome/common/chrome_switches.h" 23 #include "win8/delegate_execute/command_execute_impl.h" 24 #include "win8/delegate_execute/crash_server_init.h" 25 #include "win8/delegate_execute/delegate_execute_operation.h" 26 #include "win8/delegate_execute/resource.h" 27 28 using namespace ATL; 29 30 class DelegateExecuteModule 31 : public ATL::CAtlExeModuleT< DelegateExecuteModule > { 32 public : 33 typedef ATL::CAtlExeModuleT<DelegateExecuteModule> ParentClass; 34 35 HRESULT RegisterServer(BOOL reg_type_lib) { 36 return ParentClass::RegisterServer(FALSE); 37 } 38 39 virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* registrar) throw() { 40 AtlTrace(L"In %hs\n", __FUNCTION__); 41 HRESULT hr = ParentClass::AddCommonRGSReplacements(registrar); 42 if (FAILED(hr)) 43 return hr; 44 45 wchar_t delegate_execute_clsid[MAX_PATH] = {0}; 46 if (!StringFromGUID2(__uuidof(CommandExecuteImpl), delegate_execute_clsid, 47 ARRAYSIZE(delegate_execute_clsid))) { 48 ATLASSERT(false); 49 return E_FAIL; 50 } 51 52 hr = registrar->AddReplacement(L"DELEGATE_EXECUTE_CLSID", 53 delegate_execute_clsid); 54 ATLASSERT(SUCCEEDED(hr)); 55 return hr; 56 } 57 }; 58 59 DelegateExecuteModule _AtlModule; 60 61 using delegate_execute::DelegateExecuteOperation; 62 using base::win::ScopedHandle; 63 64 int RelaunchChrome(const DelegateExecuteOperation& operation) { 65 AtlTrace("Relaunching [%ls] with flags [%s]\n", 66 operation.mutex().c_str(), operation.relaunch_flags()); 67 ScopedHandle mutex(OpenMutexW(SYNCHRONIZE, FALSE, operation.mutex().c_str())); 68 if (mutex.IsValid()) { 69 const int kWaitSeconds = 5; 70 DWORD result = ::WaitForSingleObject(mutex, kWaitSeconds * 1000); 71 if (result == WAIT_ABANDONED) { 72 // This is the normal case. Chrome exits and windows marks the mutex as 73 // abandoned. 74 } else if (result == WAIT_OBJECT_0) { 75 // This is unexpected. Check if somebody is not closing the mutex on 76 // RelaunchChromehelper, the mutex should not be closed. 77 AtlTrace("Unexpected release of the relaunch mutex!!\n"); 78 } else if (result == WAIT_TIMEOUT) { 79 // This could mean that Chrome is hung. Proceed to exterminate. 80 DWORD pid = operation.GetParentPid(); 81 AtlTrace("%ds timeout. Killing Chrome %d\n", kWaitSeconds, pid); 82 base::KillProcessById(pid, 0, false); 83 } else { 84 AtlTrace("Failed to wait for relaunch mutex, result is 0x%x\n", result); 85 } 86 } else { 87 // It is possible that chrome exits so fast that the mutex is not there. 88 AtlTrace("No relaunch mutex found\n"); 89 } 90 91 base::win::ScopedCOMInitializer com_initializer; 92 93 string16 relaunch_flags(operation.relaunch_flags()); 94 SHELLEXECUTEINFO sei = { sizeof(sei) }; 95 sei.fMask = SEE_MASK_FLAG_LOG_USAGE; 96 sei.nShow = SW_SHOWNORMAL; 97 sei.lpFile = operation.shortcut().value().c_str(); 98 sei.lpParameters = relaunch_flags.c_str(); 99 100 AtlTrace(L"Relaunching Chrome via shortcut [%ls]\n", sei.lpFile); 101 102 if (!::ShellExecuteExW(&sei)) { 103 int error = HRESULT_FROM_WIN32(::GetLastError()); 104 AtlTrace("ShellExecute returned 0x%08X\n", error); 105 return error; 106 } 107 return S_OK; 108 } 109 110 extern "C" int WINAPI _tWinMain(HINSTANCE , HINSTANCE, LPTSTR, int nShowCmd) { 111 scoped_ptr<google_breakpad::ExceptionHandler> breakpad = 112 delegate_execute::InitializeCrashReporting(); 113 114 base::AtExitManager exit_manager; 115 AtlTrace("delegate_execute enter\n"); 116 117 CommandLine::Init(0, NULL); 118 HRESULT ret_code = E_UNEXPECTED; 119 DelegateExecuteOperation operation; 120 if (operation.Init(CommandLine::ForCurrentProcess())) { 121 switch (operation.operation_type()) { 122 case DelegateExecuteOperation::DELEGATE_EXECUTE: 123 ret_code = _AtlModule.WinMain(nShowCmd); 124 break; 125 case DelegateExecuteOperation::RELAUNCH_CHROME: 126 ret_code = RelaunchChrome(operation); 127 break; 128 default: 129 NOTREACHED(); 130 } 131 } 132 AtlTrace("delegate_execute exit, code = %d\n", ret_code); 133 return ret_code; 134 } 135