// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "build/intsafe_workaround.h" #include #include #include #include #include #include "base/at_exit.h" #include "base/command_line.h" #include "base/file_util.h" #include "base/memory/scoped_ptr.h" #include "base/process/kill.h" #include "base/strings/string16.h" #include "base/win/scoped_com_initializer.h" #include "base/win/scoped_handle.h" #include "breakpad/src/client/windows/handler/exception_handler.h" #include "chrome/common/chrome_switches.h" #include "win8/delegate_execute/command_execute_impl.h" #include "win8/delegate_execute/crash_server_init.h" #include "win8/delegate_execute/delegate_execute_operation.h" #include "win8/delegate_execute/resource.h" using namespace ATL; class DelegateExecuteModule : public ATL::CAtlExeModuleT< DelegateExecuteModule > { public : typedef ATL::CAtlExeModuleT ParentClass; HRESULT RegisterServer(BOOL reg_type_lib) { return ParentClass::RegisterServer(FALSE); } virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* registrar) throw() { AtlTrace(L"In %hs\n", __FUNCTION__); HRESULT hr = ParentClass::AddCommonRGSReplacements(registrar); if (FAILED(hr)) return hr; wchar_t delegate_execute_clsid[MAX_PATH] = {0}; if (!StringFromGUID2(__uuidof(CommandExecuteImpl), delegate_execute_clsid, ARRAYSIZE(delegate_execute_clsid))) { ATLASSERT(false); return E_FAIL; } hr = registrar->AddReplacement(L"DELEGATE_EXECUTE_CLSID", delegate_execute_clsid); ATLASSERT(SUCCEEDED(hr)); return hr; } }; DelegateExecuteModule _AtlModule; using delegate_execute::DelegateExecuteOperation; using base::win::ScopedHandle; int RelaunchChrome(const DelegateExecuteOperation& operation) { AtlTrace("Relaunching [%ls] with flags [%s]\n", operation.mutex().c_str(), operation.relaunch_flags()); ScopedHandle mutex(OpenMutexW(SYNCHRONIZE, FALSE, operation.mutex().c_str())); if (mutex.IsValid()) { const int kWaitSeconds = 5; DWORD result = ::WaitForSingleObject(mutex, kWaitSeconds * 1000); if (result == WAIT_ABANDONED) { // This is the normal case. Chrome exits and windows marks the mutex as // abandoned. } else if (result == WAIT_OBJECT_0) { // This is unexpected. Check if somebody is not closing the mutex on // RelaunchChromehelper, the mutex should not be closed. AtlTrace("Unexpected release of the relaunch mutex!!\n"); } else if (result == WAIT_TIMEOUT) { // This could mean that Chrome is hung. Proceed to exterminate. DWORD pid = operation.GetParentPid(); AtlTrace("%ds timeout. Killing Chrome %d\n", kWaitSeconds, pid); base::KillProcessById(pid, 0, false); } else { AtlTrace("Failed to wait for relaunch mutex, result is 0x%x\n", result); } } else { // It is possible that chrome exits so fast that the mutex is not there. AtlTrace("No relaunch mutex found\n"); } base::win::ScopedCOMInitializer com_initializer; string16 relaunch_flags(operation.relaunch_flags()); SHELLEXECUTEINFO sei = { sizeof(sei) }; sei.fMask = SEE_MASK_FLAG_LOG_USAGE; sei.nShow = SW_SHOWNORMAL; sei.lpFile = operation.shortcut().value().c_str(); sei.lpParameters = relaunch_flags.c_str(); AtlTrace(L"Relaunching Chrome via shortcut [%ls]\n", sei.lpFile); if (!::ShellExecuteExW(&sei)) { int error = HRESULT_FROM_WIN32(::GetLastError()); AtlTrace("ShellExecute returned 0x%08X\n", error); return error; } return S_OK; } extern "C" int WINAPI _tWinMain(HINSTANCE , HINSTANCE, LPTSTR, int nShowCmd) { scoped_ptr breakpad = delegate_execute::InitializeCrashReporting(); base::AtExitManager exit_manager; AtlTrace("delegate_execute enter\n"); CommandLine::Init(0, NULL); HRESULT ret_code = E_UNEXPECTED; DelegateExecuteOperation operation; if (operation.Init(CommandLine::ForCurrentProcess())) { switch (operation.operation_type()) { case DelegateExecuteOperation::DELEGATE_EXECUTE: ret_code = _AtlModule.WinMain(nShowCmd); break; case DelegateExecuteOperation::RELAUNCH_CHROME: ret_code = RelaunchChrome(operation); break; default: NOTREACHED(); } } AtlTrace("delegate_execute exit, code = %d\n", ret_code); return ret_code; }