summaryrefslogtreecommitdiffstats
path: root/cloud_print
diff options
context:
space:
mode:
authorvitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-01 01:20:58 +0000
committervitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-01 01:20:58 +0000
commit3bd9bbd27d14fa7b9763b3e1d9dc8af83b0d33bf (patch)
tree3ee386e78666752f963ff3a7fa62da15808b3e9d /cloud_print
parentb33c1df66917b68e01b91ec0dcc4413edc518d13 (diff)
downloadchromium_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.cc172
-rw-r--r--cloud_print/service/win/chrome_launcher.h37
-rw-r--r--cloud_print/service/win/cloud_print_service.cc46
-rw-r--r--cloud_print/service/win/service.gyp8
-rw-r--r--cloud_print/service/win/service_switches.cc16
-rw-r--r--cloud_print/service/win/service_switches.h19
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_
+