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.
11 #include "base/at_exit.h"
12 #include "base/command_line.h"
13 #include "base/file_util.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/process/kill.h"
16 #include "base/strings/string16.h"
17 #include "base/win/scoped_com_initializer.h"
18 #include "base/win/scoped_comptr.h"
19 #include "base/win/scoped_handle.h"
20 #include "breakpad/src/client/windows/handler/exception_handler.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/installer/util/browser_distribution.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"
30 // Usually classes derived from CAtlExeModuleT, or other types of ATL
31 // COM module classes statically define their CLSID at compile time through
32 // the use of various macros, and ATL internals takes care of creating the
33 // class objects and registering them. However, we need to register the same
34 // object with different CLSIDs depending on a runtime setting, so we handle
35 // that logic here, before the main ATL message loop runs.
36 class DelegateExecuteModule
37 : public ATL::CAtlExeModuleT
< DelegateExecuteModule
> {
39 typedef ATL::CAtlExeModuleT
<DelegateExecuteModule
> ParentClass
;
40 typedef CComObject
<CommandExecuteImpl
> ImplType
;
42 DelegateExecuteModule()
43 : registration_token_(0) {
46 HRESULT
PreMessageLoop(int nShowCmd
) {
48 base::string16 clsid_string
;
50 BrowserDistribution
* dist
= BrowserDistribution::GetDistribution();
51 if (!dist
->GetCommandExecuteImplClsid(&clsid_string
))
53 hr
= ::CLSIDFromString(clsid_string
.c_str(), &clsid
);
57 // We use the same class creation logic as ATL itself. See
58 // _ATL_OBJMAP_ENTRY::RegisterClassObject() in atlbase.h
59 hr
= ImplType::_ClassFactoryCreatorClass::CreateInstance(
60 ImplType::_CreatorClass::CreateInstance
, IID_IUnknown
,
61 instance_
.ReceiveVoid());
64 hr
= ::CoRegisterClassObject(clsid
, instance_
, CLSCTX_LOCAL_SERVER
,
65 REGCLS_MULTIPLEUSE
| REGCLS_SUSPENDED
, ®istration_token_
);
69 return ParentClass::PreMessageLoop(nShowCmd
);
72 HRESULT
PostMessageLoop() {
73 if (registration_token_
!= 0) {
74 ::CoRevokeClassObject(registration_token_
);
75 registration_token_
= 0;
80 return ParentClass::PostMessageLoop();
84 base::win::ScopedComPtr
<IUnknown
> instance_
;
85 DWORD registration_token_
;
88 DelegateExecuteModule _AtlModule
;
90 using delegate_execute::DelegateExecuteOperation
;
91 using base::win::ScopedHandle
;
93 int RelaunchChrome(const DelegateExecuteOperation
& operation
) {
94 AtlTrace("Relaunching [%ls] with flags [%ls]\n",
95 operation
.mutex().c_str(), operation
.relaunch_flags().c_str());
96 ScopedHandle
mutex(OpenMutexW(SYNCHRONIZE
, FALSE
, operation
.mutex().c_str()));
97 if (mutex
.IsValid()) {
98 const int kWaitSeconds
= 5;
99 DWORD result
= ::WaitForSingleObject(mutex
, kWaitSeconds
* 1000);
100 if (result
== WAIT_ABANDONED
) {
101 // This is the normal case. Chrome exits and windows marks the mutex as
103 } else if (result
== WAIT_OBJECT_0
) {
104 // This is unexpected. Check if somebody is not closing the mutex on
105 // RelaunchChromehelper, the mutex should not be closed.
106 AtlTrace("Unexpected release of the relaunch mutex!!\n");
107 } else if (result
== WAIT_TIMEOUT
) {
108 // This could mean that Chrome is hung. Proceed to exterminate.
109 DWORD pid
= operation
.GetParentPid();
110 AtlTrace("%ds timeout. Killing Chrome %d\n", kWaitSeconds
, pid
);
111 base::KillProcessById(pid
, 0, false);
113 AtlTrace("Failed to wait for relaunch mutex, result is 0x%x\n", result
);
116 // It is possible that chrome exits so fast that the mutex is not there.
117 AtlTrace("No relaunch mutex found\n");
120 base::win::ScopedCOMInitializer com_initializer
;
122 base::string16
relaunch_flags(operation
.relaunch_flags());
123 SHELLEXECUTEINFO sei
= { sizeof(sei
) };
124 sei
.fMask
= SEE_MASK_FLAG_LOG_USAGE
;
125 sei
.nShow
= SW_SHOWNORMAL
;
126 sei
.lpFile
= operation
.shortcut().value().c_str();
127 sei
.lpParameters
= relaunch_flags
.c_str();
129 AtlTrace(L
"Relaunching Chrome via shortcut [%ls]\n", sei
.lpFile
);
131 if (!::ShellExecuteExW(&sei
)) {
132 int error
= HRESULT_FROM_WIN32(::GetLastError());
133 AtlTrace("ShellExecute returned 0x%08X\n", error
);
139 extern "C" int WINAPI
_tWinMain(HINSTANCE
, HINSTANCE
, LPTSTR
, int nShowCmd
) {
140 scoped_ptr
<google_breakpad::ExceptionHandler
> breakpad
=
141 delegate_execute::InitializeCrashReporting();
143 base::AtExitManager exit_manager
;
144 AtlTrace("delegate_execute enter\n");
146 CommandLine::Init(0, NULL
);
147 HRESULT ret_code
= E_UNEXPECTED
;
148 DelegateExecuteOperation operation
;
149 if (operation
.Init(CommandLine::ForCurrentProcess())) {
150 switch (operation
.operation_type()) {
151 case DelegateExecuteOperation::DELEGATE_EXECUTE
:
152 ret_code
= _AtlModule
.WinMain(nShowCmd
);
154 case DelegateExecuteOperation::RELAUNCH_CHROME
:
155 ret_code
= RelaunchChrome(operation
);
161 AtlTrace("delegate_execute exit, code = %d\n", ret_code
);