Home | History | Annotate | Download | only in delegate_execute
      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