diff options
author | vitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-01 01:20:58 +0000 |
---|---|---|
committer | vitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-01 01:20:58 +0000 |
commit | 3bd9bbd27d14fa7b9763b3e1d9dc8af83b0d33bf (patch) | |
tree | 3ee386e78666752f963ff3a7fa62da15808b3e9d /cloud_print | |
parent | b33c1df66917b68e01b91ec0dcc4413edc518d13 (diff) | |
download | chromium_src-3bd9bbd27d14fa7b9763b3e1d9dc8af83b0d33bf.zip chromium_src-3bd9bbd27d14fa7b9763b3e1d9dc8af83b0d33bf.tar.gz chromium_src-3bd9bbd27d14fa7b9763b3e1d9dc8af83b0d33bf.tar.bz2 |
Added ChromeLauncher.
Added --app switch for debuggin.
BUG=125026
TEST=none
Review URL: https://chromiumcodereview.appspot.com/10444101
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@139947 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cloud_print')
-rw-r--r-- | cloud_print/service/win/chrome_launcher.cc | 172 | ||||
-rw-r--r-- | cloud_print/service/win/chrome_launcher.h | 37 | ||||
-rw-r--r-- | cloud_print/service/win/cloud_print_service.cc | 46 | ||||
-rw-r--r-- | cloud_print/service/win/service.gyp | 8 | ||||
-rw-r--r-- | cloud_print/service/win/service_switches.cc | 16 | ||||
-rw-r--r-- | cloud_print/service/win/service_switches.h | 19 |
6 files changed, 281 insertions, 17 deletions
diff --git a/cloud_print/service/win/chrome_launcher.cc b/cloud_print/service/win/chrome_launcher.cc new file mode 100644 index 0000000..8b984f0 --- /dev/null +++ b/cloud_print/service/win/chrome_launcher.cc @@ -0,0 +1,172 @@ +// 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 "cloud_print/service/win/chrome_launcher.h" + +#include "base/command_line.h" +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/process.h" +#include "base/process_util.h" +#include "base/win/registry.h" +#include "base/win/scoped_handle.h" +#include "base/win/scoped_process_information.h" +#include "cloud_print/service/win/service_switches.h" + +namespace { + +const wchar_t kChromeRegClientStateKey[] = + L"Software\\Google\\Update\\ClientState\\" + L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; + +const wchar_t kGoogleChromeExePath[] = + L"Google\\Chrome\\Application\\chrome.exe"; + +const wchar_t kUninstallStringField[] = L"UninstallString"; + +const wchar_t kChromeExe[] = L"chrome.exe"; + +const int kShutdownTimeoutMs = 30 * 1000; + +void ShutdownChrome(HANDLE process, DWORD thread_id) { + if (::PostThreadMessage(thread_id, WM_QUIT, 0, 0) && + WAIT_OBJECT_0 == ::WaitForSingleObject(process, kShutdownTimeoutMs)) { + return; + } + LOG(ERROR) << "Failed to shutdown process."; + base::KillProcess(process, 0, true); +} + +bool LaunchProcess(const CommandLine& cmdline, + base::ProcessHandle* process_handle, + DWORD* thread_id) { + STARTUPINFO startup_info = {}; + startup_info.cb = sizeof(startup_info); + startup_info.dwFlags = STARTF_USESHOWWINDOW; + startup_info.wShowWindow = SW_SHOW; + + base::win::ScopedProcessInformation process_info; + if (!CreateProcess(NULL, + const_cast<wchar_t*>(cmdline.GetCommandLineString().c_str()), NULL, NULL, + FALSE, 0, NULL, NULL, &startup_info, process_info.Receive())) { + return false; + } + + if (process_handle) + *process_handle = process_info.TakeProcessHandle(); + + if (thread_id) + *thread_id = process_info.thread_id(); + + return true; +} + +FilePath GetAnyChromePath() { + FilePath chrome_path = ChromeLauncher::GetChromePath(HKEY_LOCAL_MACHINE); + if (!chrome_path.empty()) + return chrome_path; + chrome_path = ChromeLauncher::GetChromePath(HKEY_CURRENT_USER); + if (!chrome_path.empty()) + return chrome_path; + if (PathService::Get(base::DIR_PROGRAM_FILES, &chrome_path)) { + chrome_path.Append(kGoogleChromeExePath); + if (file_util::PathExists(chrome_path)) + return chrome_path; + } + return FilePath(); +} + +} // namespace + +ChromeLauncher::ChromeLauncher(const FilePath& user_data) + : stop_event_(true, true), + user_data_(user_data) { +} + +ChromeLauncher::~ChromeLauncher() { +} + +bool ChromeLauncher::Start() { + stop_event_.Reset(); + thread_.reset(new base::DelegateSimpleThread(this, "chrome_launcher")); + thread_->Start(); + return true; +} + +void ChromeLauncher::Stop() { + stop_event_.Signal(); + thread_->Join(); + thread_.reset(); +} + +void ChromeLauncher::Run() { + const base::TimeDelta default_time_out = base::TimeDelta::FromSeconds(1); + const base::TimeDelta max_time_out = base::TimeDelta::FromHours(1); + + for (base::TimeDelta time_out = default_time_out;; + time_out = std::min(time_out * 2, max_time_out)) { + FilePath chrome_path = GetAnyChromePath(); + + if (!chrome_path.empty()) { + CommandLine cmd(chrome_path); + cmd.AppendSwitchASCII(kChromeTypeSwitch, "service"); + cmd.AppendSwitchPath(kUserDataDirSwitch, user_data_); + base::win::ScopedHandle chrome_handle; + base::Time started = base::Time::Now(); + DWORD thread_id = 0; + LaunchProcess(cmd, chrome_handle.Receive(), &thread_id); + int exit_code = 0; + HANDLE handles[] = {stop_event_.handle(), chrome_handle}; + DWORD wait_result = ::WaitForMultipleObjects(arraysize(handles), handles, + FALSE, INFINITE); + if (wait_result == WAIT_OBJECT_0) { + ShutdownChrome(chrome_handle, thread_id); + break; + } else if (wait_result == WAIT_OBJECT_0 + 1) { + LOG(ERROR) << "Chrome process exited."; + } else { + LOG(ERROR) << "Error waiting Chrome (" << ::GetLastError() << ")."; + } + if (base::Time::Now() - started > base::TimeDelta::FromHours(1)) { + // Reset timeout because process worked long enough. + time_out = default_time_out; + } + } + if (stop_event_.TimedWait(time_out)) + break; + } +} + +FilePath ChromeLauncher::GetChromePath(HKEY key) { + using base::win::RegKey; + RegKey reg_key(key, kChromeRegClientStateKey, KEY_QUERY_VALUE); + + FilePath chrome_exe_path; + + if (reg_key.Valid()) { + // Now grab the uninstall string from the appropriate ClientState key + // and use that as the base for a path to chrome.exe. + string16 uninstall; + if (reg_key.ReadValue(kUninstallStringField, &uninstall) == ERROR_SUCCESS) { + // The uninstall path contains the path to setup.exe which is two levels + // down from chrome.exe. Move up two levels (plus one to drop the file + // name) and look for chrome.exe from there. + FilePath uninstall_path(uninstall); + chrome_exe_path = + uninstall_path.DirName().DirName().DirName().Append(kChromeExe); + if (!file_util::PathExists(chrome_exe_path)) { + // By way of mild future proofing, look up one to see if there's a + // chrome.exe in the version directory + chrome_exe_path = + uninstall_path.DirName().DirName().Append(kChromeExe); + } + } + } + + if (file_util::PathExists(chrome_exe_path)) + return chrome_exe_path; + + return FilePath(); +} + diff --git a/cloud_print/service/win/chrome_launcher.h b/cloud_print/service/win/chrome_launcher.h new file mode 100644 index 0000000..8b98141 --- /dev/null +++ b/cloud_print/service/win/chrome_launcher.h @@ -0,0 +1,37 @@ +// 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. + +#ifndef CLOUD_PRINT_SERVICE_CHROME_LAUNCHER_H_ +#define CLOUD_PRINT_SERVICE_CHROME_LAUNCHER_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/memory/scoped_ptr.h" +#include "base/threading/simple_thread.h" + +class ChromeLauncher : public base::DelegateSimpleThread::Delegate { + public: + explicit ChromeLauncher(const FilePath& user_data); + + virtual ~ChromeLauncher(); + + bool Start(); + void Stop(); + + virtual void Run() OVERRIDE; + + static FilePath GetChromePath(HKEY key); + + private: + FilePath user_data_; + base::WaitableEvent stop_event_; + scoped_ptr<base::DelegateSimpleThread> thread_; + + DISALLOW_COPY_AND_ASSIGN(ChromeLauncher); +}; + +#endif // CLOUD_PRINT_SERVICE_CHROME_LAUNCHER_H_ + diff --git a/cloud_print/service/win/cloud_print_service.cc b/cloud_print/service/win/cloud_print_service.cc index d53d7a7..08ef93d 100644 --- a/cloud_print/service/win/cloud_print_service.cc +++ b/cloud_print/service/win/cloud_print_service.cc @@ -14,21 +14,13 @@ #include "base/path_service.h" #include "base/string_util.h" #include "base/win/scoped_handle.h" +#include "cloud_print/service/win/chrome_launcher.h" #include "cloud_print/service/win/resource.h" #include "cloud_print/service/win/service_state.h" +#include "cloud_print/service/win/service_switches.h" namespace { -const char kInstallSwitch[] = "install"; -const char kUninstallSwitch[] = "uninstall"; -const char kStartSwitch[] = "start"; -const char kStopSwitch[] = "stop"; - -const char kServiceSwitch[] = "service"; - -const char kUserDataDirSwitch[] = "user-data-dir"; -const char kQuietSwitch[] = "quiet"; - const wchar_t kServiceStateFileName[] = L"Service State"; // The traits class for Windows Service. @@ -156,6 +148,11 @@ class CloudPrintServiceModule if (FAILED(hr)) return hr; + if (ChromeLauncher::GetChromePath(HKEY_LOCAL_MACHINE).empty()) { + LOG(ERROR) << "Found no Chrome installed for all users."; + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + hr = UpdateRegistryAppId(true); if (FAILED(hr)) return hr; @@ -214,6 +211,7 @@ class CloudPrintServiceModule LogEvent(_T("Service started/resumed")); SetServiceStatus(SERVICE_RUNNING); + return hr; } @@ -228,6 +226,7 @@ class CloudPrintServiceModule return E_INVALIDARG; *is_service = false; + user_data_dir_ = command_line.GetSwitchValuePath(kUserDataDirSwitch); if (command_line.HasSwitch(kStopSwitch)) return StopService(); @@ -240,12 +239,12 @@ class CloudPrintServiceModule return S_FALSE; } - FilePath data_dir = command_line.GetSwitchValuePath(kUserDataDirSwitch); - HRESULT hr = ProcessServiceState(data_dir, + HRESULT hr = ProcessServiceState(user_data_dir_, command_line.HasSwitch(kQuietSwitch)); if (FAILED(hr)) return hr; - hr = InstallService(data_dir); + + hr = InstallService(user_data_dir_); if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch)) return StartService(); @@ -256,11 +255,17 @@ class CloudPrintServiceModule return StartService(); if (command_line.HasSwitch(kServiceSwitch)) { - user_data_dir_ = command_line.GetSwitchValuePath(kUserDataDirSwitch); *is_service = true; return S_OK; } + if (command_line.HasSwitch(kConsoleSwitch)) { + ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE); + HRESULT hr = Run(); + ::SetConsoleCtrlHandler(NULL, FALSE); + return hr; + } + InvalidUsage(); return S_FALSE; } @@ -372,17 +377,28 @@ class CloudPrintServiceModule } HRESULT StartConnector() { - return S_OK; + chrome_.reset(new ChromeLauncher(user_data_dir_)); + return chrome_->Start() ? S_OK : E_FAIL; } void StopConnector() { + chrome_->Stop(); + chrome_.reset(); } + static BOOL WINAPI ConsoleCtrlHandler(DWORD type); + FilePath user_data_dir_; + scoped_ptr<ChromeLauncher> chrome_; }; CloudPrintServiceModule _AtlModule; +BOOL CloudPrintServiceModule::ConsoleCtrlHandler(DWORD type) { + PostThreadMessage(_AtlModule.m_dwThreadID, WM_QUIT, 0, 0); + return TRUE; +} + int main() { base::AtExitManager at_exit; return _AtlModule.WinMain(0); diff --git a/cloud_print/service/win/service.gyp b/cloud_print/service/win/service.gyp index 83fe58c..b365e83 100644 --- a/cloud_print/service/win/service.gyp +++ b/cloud_print/service/win/service.gyp @@ -16,12 +16,16 @@ 'type': 'static_library', 'dependencies': [ '../../../base/base.gyp:base', - '../../../net/net.gyp:net', '../../../build/temp_gyp/googleurl.gyp:googleurl', + '../../../net/net.gyp:net', ], 'sources': [ + 'chrome_launcher.cc', + 'chrome_launcher.h', 'service_state.cc', 'service_state.h', + 'service_switches.cc', + 'service_switches.h', ] }, { @@ -34,7 +38,7 @@ 'resource.h', ], 'dependencies': [ - 'cloud_print_service_lib' + 'cloud_print_service_lib', ], 'msvs_settings': { 'VCLinkerTool': { diff --git a/cloud_print/service/win/service_switches.cc b/cloud_print/service/win/service_switches.cc new file mode 100644 index 0000000..296eae0 --- /dev/null +++ b/cloud_print/service/win/service_switches.cc @@ -0,0 +1,16 @@ +// 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 "cloud_print/service/win/service_switches.h" + +const char kChromeTypeSwitch[] = "type"; +const char kConsoleSwitch[] = "console"; +const char kInstallSwitch[] = "install"; +const char kQuietSwitch[] = "quiet"; +const char kServiceSwitch[] = "service"; +const char kStartSwitch[] = "start"; +const char kStopSwitch[] = "stop"; +const char kUninstallSwitch[] = "uninstall"; +const char kUserDataDirSwitch[] = "user-data-dir"; + diff --git a/cloud_print/service/win/service_switches.h b/cloud_print/service/win/service_switches.h new file mode 100644 index 0000000..17af981 --- /dev/null +++ b/cloud_print/service/win/service_switches.h @@ -0,0 +1,19 @@ +// 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. + +#ifndef CLOUD_PRINT_SERVICE_SERVICE_SWITCHES_H_ +#define CLOUD_PRINT_SERVICE_SERVICE_SWITCHES_H_ + +extern const char kChromeTypeSwitch[]; +extern const char kConsoleSwitch[]; +extern const char kInstallSwitch[]; +extern const char kQuietSwitch[]; +extern const char kServiceSwitch[]; +extern const char kStartSwitch[]; +extern const char kStopSwitch[]; +extern const char kUninstallSwitch[]; +extern const char kUserDataDirSwitch[]; + +#endif // CLOUD_PRINT_SERVICE_SERVICE_SWITCHES_H_ + |