chrome_launcher.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "cloud_print/service/win/chrome_launcher.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/base_switches.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/file_util.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/files/scoped_temp_dir.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/json/json_reader.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/json/json_writer.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/process.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/process_util.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/values.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/win/registry.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_handle.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_process_information.h"
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/chrome_constants.h"
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/chrome_switches.h"
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/pref_names.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/launcher_support/chrome_launcher_support.h"
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "cloud_print/common/win/cloud_print_utils.h"
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "cloud_print/service/service_constants.h"
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "cloud_print/service/win/service_utils.h"
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "google_apis/gaia/gaia_urls.h"
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/base/url_util.h"
287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kShutdownTimeoutMs = 30 * 1000;
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kUsageUpdateTimeoutMs = 6 * 3600 * 1000;  // 6 hours.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static const char16 kAutoRunKeyPath[] =
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Terminates any process.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ShutdownChrome(HANDLE process, DWORD thread_id) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::PostThreadMessage(thread_id, WM_QUIT, 0, 0) &&
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WAIT_OBJECT_0 == ::WaitForSingleObject(process, kShutdownTimeoutMs)) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG(ERROR) << "Failed to shutdown process.";
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::KillProcess(process, 0, true);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)BOOL CALLBACK CloseIfPidEqual(HWND wnd, LPARAM lparam) {
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DWORD pid = 0;
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ::GetWindowThreadProcessId(wnd, &pid);
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (pid == static_cast<DWORD>(lparam))
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ::PostMessage(wnd, WM_CLOSE, 0, 0);
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return TRUE;
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void CloseAllProcessWindows(HANDLE process) {
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ::EnumWindows(&CloseIfPidEqual, GetProcessId(process));
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Close Chrome browser window.
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void CloseChrome(HANDLE process, DWORD thread_id) {
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CloseAllProcessWindows(process);
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (WAIT_OBJECT_0 == ::WaitForSingleObject(process, kShutdownTimeoutMs)) {
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ShutdownChrome(process, thread_id);
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool LaunchProcess(const CommandLine& cmdline,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   base::ProcessHandle* process_handle,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   DWORD* thread_id) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STARTUPINFO startup_info = {};
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  startup_info.cb = sizeof(startup_info);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  startup_info.dwFlags = STARTF_USESHOWWINDOW;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  startup_info.wShowWindow = SW_SHOW;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedProcessInformation process_info;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CreateProcess(NULL,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const_cast<wchar_t*>(cmdline.GetCommandLineString().c_str()), NULL, NULL,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FALSE, 0, NULL, NULL, &startup_info, process_info.Receive())) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (process_handle)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *process_handle = process_info.TakeProcessHandle();
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (thread_id)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *thread_id = process_info.thread_id();
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)GURL GetCloudPrintServiceEnableURL(const std::string& proxy_id) {
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GURL url(
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          switches::kCloudPrintServiceURL));
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (url.is_empty())
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    url = GURL("https://www.google.com/cloudprint");
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  url = net::AppendQueryParameter(url, "proxy", proxy_id);
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string url_path(url.path() + "/enable_chrome_connector/enable.html");
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GURL::Replacements replacements;
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  replacements.SetPathStr(url_path);
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return url.ReplaceComponents(replacements);
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)GURL GetCloudPrintServiceEnableURLWithSignin(const std::string& proxy_id) {
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GURL url(GaiaUrls::GetInstance()->service_login_url());
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  url = net::AppendQueryParameter(url, "service", "cloudprint");
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  url = net::AppendQueryParameter(url, "sarp", "1");
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return net::AppendQueryParameter(
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      url, "continue", GetCloudPrintServiceEnableURL(proxy_id).spec());
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string ReadAndUpdateServiceState(const base::FilePath& directory,
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                      const std::string& proxy_id) {
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string json;
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath file_path = directory.Append(chrome::kServiceStateFileName);
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!file_util::ReadFileToString(file_path, &json)) {
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return std::string();
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<base::Value> service_state(base::JSONReader::Read(json));
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* dictionary = NULL;
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!service_state->GetAsDictionary(&dictionary) || !dictionary) {
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return std::string();
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool enabled = false;
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!dictionary->GetBoolean(prefs::kCloudPrintProxyEnabled, &enabled) ||
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      !enabled) {
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return std::string();
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string refresh_token;
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!dictionary->GetString(prefs::kCloudPrintRobotRefreshToken,
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             &refresh_token) ||
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      refresh_token.empty()) {
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return std::string();
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remove everything except kCloudPrintRoot.
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::Value* cloud_print_root = NULL;
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dictionary->Remove(prefs::kCloudPrintRoot, &cloud_print_root);
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dictionary->Clear();
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dictionary->Set(prefs::kCloudPrintRoot, cloud_print_root);
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dictionary->SetBoolean(prefs::kCloudPrintXmppPingEnabled, true);
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!proxy_id.empty())  // Reuse proxy id if we already had one.
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dictionary->SetString(prefs::kCloudPrintProxyId, proxy_id);
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string result;
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::JSONWriter::WriteWithOptions(dictionary,
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                     &result);
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return result;
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void DeleteAutorunKeys(const base::FilePath& user_data_dir) {
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::win::RegKey key(HKEY_CURRENT_USER, kAutoRunKeyPath, KEY_SET_VALUE);
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!key.Valid())
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::vector<string16> to_delete;
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath abs_user_data_dir = base::MakeAbsoluteFilePath(user_data_dir);
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  {
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::win::RegistryValueIterator value(HKEY_CURRENT_USER, kAutoRunKeyPath);
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (; value.Valid(); ++value) {
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (value.Type() == REG_SZ && value.Value()) {
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        CommandLine cmd = CommandLine::FromString(value.Value());
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (cmd.GetSwitchValueASCII(switches::kProcessType) ==
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            switches::kServiceProcess &&
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            cmd.HasSwitch(switches::kUserDataDir)) {
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          base::FilePath path_from_reg = base::MakeAbsoluteFilePath(
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              cmd.GetSwitchValuePath(switches::kUserDataDir));
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          if (path_from_reg == abs_user_data_dir) {
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            to_delete.push_back(value.Name());
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          }
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (size_t i = 0; i < to_delete.size(); ++i) {
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    key.DeleteValue(to_delete[i].c_str());
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeLauncher::ChromeLauncher(const base::FilePath& user_data)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : stop_event_(true, true),
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      user_data_(user_data) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ChromeLauncher::~ChromeLauncher() {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ChromeLauncher::Start() {
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DeleteAutorunKeys(user_data_);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stop_event_.Reset();
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread_.reset(new base::DelegateSimpleThread(this, "chrome_launcher"));
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread_->Start();
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeLauncher::Stop() {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stop_event_.Signal();
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread_->Join();
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread_.reset();
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeLauncher::Run() {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::TimeDelta default_time_out = base::TimeDelta::FromSeconds(1);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::TimeDelta max_time_out = base::TimeDelta::FromHours(1);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (base::TimeDelta time_out = default_time_out;;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       time_out = std::min(time_out * 2, max_time_out)) {
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath chrome_path = chrome_launcher_support::GetAnyChromePath();
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!chrome_path.empty()) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CommandLine cmd(chrome_path);
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      CopyChromeSwitchesFromCurrentProcess(&cmd);
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Required switches.
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cmd.AppendSwitchASCII(switches::kProcessType, switches::kServiceProcess);
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cmd.AppendSwitchPath(switches::kUserDataDir, user_data_);
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cmd.AppendSwitch(switches::kNoServiceAutorun);
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Optional.
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cmd.AppendSwitch(switches::kAutoLaunchAtStartup);
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cmd.AppendSwitch(switches::kDisableBackgroundMode);
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cmd.AppendSwitch(switches::kDisableDefaultApps);
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cmd.AppendSwitch(switches::kDisableExtensions);
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cmd.AppendSwitch(switches::kDisableGpu);
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cmd.AppendSwitch(switches::kDisableSoftwareRasterizer);
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cmd.AppendSwitch(switches::kDisableSync);
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cmd.AppendSwitch(switches::kNoFirstRun);
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cmd.AppendSwitch(switches::kNoStartupWindow);
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::win::ScopedHandle chrome_handle;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Time started = base::Time::Now();
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DWORD thread_id = 0;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LaunchProcess(cmd, chrome_handle.Receive(), &thread_id);
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HANDLE handles[] = {stop_event_.handle(), chrome_handle};
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      DWORD wait_result = WAIT_TIMEOUT;
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      while (wait_result == WAIT_TIMEOUT) {
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        cloud_print::SetGoogleUpdateUsage(kGoogleUpdateId);
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        wait_result = ::WaitForMultipleObjects(arraysize(handles), handles,
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                               FALSE, kUsageUpdateTimeoutMs);
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (wait_result == WAIT_OBJECT_0) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ShutdownChrome(chrome_handle, thread_id);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (wait_result == WAIT_OBJECT_0 + 1) {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "Chrome process exited.";
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "Error waiting Chrome (" << ::GetLastError() << ").";
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (base::Time::Now() - started > base::TimeDelta::FromHours(1)) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Reset timeout because process worked long enough.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        time_out = default_time_out;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (stop_event_.TimedWait(time_out))
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string ChromeLauncher::CreateServiceStateFile(
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& proxy_id,
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::vector<std::string>& printers) {
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string result;
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ScopedTempDir temp_user_data;
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!temp_user_data.CreateUniqueTempDir()) {
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(ERROR) << "Can't create temp dir.";
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return result;
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath chrome_path = chrome_launcher_support::GetAnyChromePath();
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (chrome_path.empty()) {
284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(ERROR) << "Can't find Chrome.";
285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return result;
286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath printers_file = temp_user_data.path().Append(L"printers.json");
289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ListValue printer_list;
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  printer_list.AppendStrings(printers);
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string printers_json;
293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::JSONWriter::Write(&printer_list, &printers_json);
294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  size_t written = file_util::WriteFile(printers_file,
295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        printers_json.c_str(),
296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        printers_json.size());
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (written != printers_json.size()) {
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(ERROR) << "Can't write file.";
299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return result;
300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CommandLine cmd(chrome_path);
303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CopyChromeSwitchesFromCurrentProcess(&cmd);
304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cmd.AppendSwitchPath(switches::kUserDataDir, temp_user_data.path());
305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cmd.AppendSwitchPath(switches::kCloudPrintSetupProxy, printers_file);
306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cmd.AppendSwitch(switches::kNoServiceAutorun);
307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Optional.
309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cmd.AppendSwitch(switches::kDisableBackgroundMode);
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cmd.AppendSwitch(switches::kDisableDefaultApps);
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cmd.AppendSwitch(switches::kDisableExtensions);
312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cmd.AppendSwitch(switches::kDisableSync);
313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cmd.AppendSwitch(switches::kNoDefaultBrowserCheck);
314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cmd.AppendSwitch(switches::kNoFirstRun);
315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cmd.AppendArg(GetCloudPrintServiceEnableURLWithSignin(proxy_id).spec());
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::win::ScopedHandle chrome_handle;
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DWORD thread_id = 0;
320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!LaunchProcess(cmd, chrome_handle.Receive(), &thread_id)) {
321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(ERROR) << "Unable to launch Chrome.";
322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return result;
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (;;) {
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DWORD wait_result = ::WaitForSingleObject(chrome_handle, 500);
327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string json = ReadAndUpdateServiceState(temp_user_data.path(),
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 proxy_id);
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (wait_result == WAIT_OBJECT_0) {
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Return what we have because browser is closed.
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return json;
332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else if (wait_result == WAIT_TIMEOUT) {
333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!json.empty()) {
334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Close chrome because Service State is ready.
335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        CloseChrome(chrome_handle, thread_id);
336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return json;
337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      LOG(ERROR) << "Chrome launch failed.";
340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return result;
341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  NOTREACHED();
344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return std::string();
345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
347