• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "chrome/service/cloud_print/cloud_print_proxy.h"
6 
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/metrics/histogram.h"
10 #include "base/path_service.h"
11 #include "base/process/kill.h"
12 #include "base/process/launch.h"
13 #include "base/values.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/cloud_print/cloud_print_constants.h"
16 #include "chrome/common/cloud_print/cloud_print_proxy_info.h"
17 #include "chrome/common/pref_names.h"
18 #include "chrome/service/cloud_print/print_system.h"
19 #include "chrome/service/service_process.h"
20 #include "chrome/service/service_process_prefs.h"
21 #include "google_apis/gaia/gaia_oauth_client.h"
22 #include "google_apis/google_api_keys.h"
23 #include "url/gurl.h"
24 
25 namespace {
26 
LaunchBrowserProcessWithSwitch(const std::string & switch_string)27 void LaunchBrowserProcessWithSwitch(const std::string& switch_string) {
28   DCHECK(g_service_process->io_thread()->message_loop_proxy()->
29       BelongsToCurrentThread());
30   base::FilePath exe_path;
31   PathService::Get(base::FILE_EXE, &exe_path);
32   if (exe_path.empty()) {
33     NOTREACHED() << "Unable to get browser process binary name.";
34   }
35   CommandLine cmd_line(exe_path);
36 
37   const CommandLine& process_command_line = *CommandLine::ForCurrentProcess();
38   base::FilePath user_data_dir =
39       process_command_line.GetSwitchValuePath(switches::kUserDataDir);
40   if (!user_data_dir.empty())
41     cmd_line.AppendSwitchPath(switches::kUserDataDir, user_data_dir);
42   cmd_line.AppendSwitch(switch_string);
43 
44 #if defined(OS_POSIX) && !defined(OS_MACOSX)
45   base::ProcessHandle pid = 0;
46   base::LaunchProcess(cmd_line, base::LaunchOptions(), &pid);
47   base::EnsureProcessGetsReaped(pid);
48 #else
49   base::LaunchOptions launch_options;
50 #if defined(OS_WIN)
51   launch_options.force_breakaway_from_job_ = true;
52 #endif  // OS_WIN
53   base::LaunchProcess(cmd_line, launch_options, NULL);
54 #endif
55 }
56 
CheckCloudPrintProxyPolicyInBrowser()57 void CheckCloudPrintProxyPolicyInBrowser() {
58   LaunchBrowserProcessWithSwitch(switches::kCheckCloudPrintConnectorPolicy);
59 }
60 
61 }  // namespace
62 
63 namespace cloud_print {
64 
CloudPrintProxy()65 CloudPrintProxy::CloudPrintProxy()
66     : service_prefs_(NULL),
67       client_(NULL),
68       enabled_(false) {
69 }
70 
~CloudPrintProxy()71 CloudPrintProxy::~CloudPrintProxy() {
72   DCHECK(CalledOnValidThread());
73   ShutdownBackend();
74 }
75 
Initialize(ServiceProcessPrefs * service_prefs,Client * client)76 void CloudPrintProxy::Initialize(ServiceProcessPrefs* service_prefs,
77                                  Client* client) {
78   DCHECK(CalledOnValidThread());
79   service_prefs_ = service_prefs;
80   client_ = client;
81 }
82 
EnableForUser()83 void CloudPrintProxy::EnableForUser() {
84   DCHECK(CalledOnValidThread());
85   if (!CreateBackend())
86     return;
87   DCHECK(backend_.get());
88   // Read persisted robot credentials because we may decide to reuse it if the
89   // passed in LSID belongs the same user.
90   std::string robot_refresh_token = service_prefs_->GetString(
91       prefs::kCloudPrintRobotRefreshToken, std::string());
92   std::string robot_email =
93       service_prefs_->GetString(prefs::kCloudPrintRobotEmail, std::string());
94   user_email_ = service_prefs_->GetString(prefs::kCloudPrintEmail, user_email_);
95 
96   // See if we have persisted robot credentials.
97   if (!robot_refresh_token.empty()) {
98     DCHECK(!robot_email.empty());
99     backend_->InitializeWithRobotToken(robot_refresh_token, robot_email);
100   } else {
101     // Finally see if we have persisted user credentials (legacy case).
102     std::string cloud_print_token =
103         service_prefs_->GetString(prefs::kCloudPrintAuthToken, std::string());
104     DCHECK(!cloud_print_token.empty());
105     backend_->InitializeWithToken(cloud_print_token);
106   }
107   if (client_) {
108     client_->OnCloudPrintProxyEnabled(true);
109   }
110 }
111 
EnableForUserWithRobot(const std::string & robot_auth_code,const std::string & robot_email,const std::string & user_email,const base::DictionaryValue & user_settings)112 void CloudPrintProxy::EnableForUserWithRobot(
113     const std::string& robot_auth_code,
114     const std::string& robot_email,
115     const std::string& user_email,
116     const base::DictionaryValue& user_settings) {
117   DCHECK(CalledOnValidThread());
118 
119   ShutdownBackend();
120   std::string proxy_id(
121       service_prefs_->GetString(prefs::kCloudPrintProxyId, std::string()));
122   service_prefs_->RemovePref(prefs::kCloudPrintRoot);
123   if (!proxy_id.empty()) {
124     // Keep only proxy id;
125     service_prefs_->SetString(prefs::kCloudPrintProxyId, proxy_id);
126   }
127   service_prefs_->SetValue(prefs::kCloudPrintUserSettings,
128                            user_settings.DeepCopy());
129   service_prefs_->WritePrefs();
130 
131   if (!CreateBackend())
132     return;
133   DCHECK(backend_.get());
134   user_email_ = user_email;
135   backend_->InitializeWithRobotAuthCode(robot_auth_code, robot_email);
136   if (client_) {
137     client_->OnCloudPrintProxyEnabled(true);
138   }
139 }
140 
CreateBackend()141 bool CloudPrintProxy::CreateBackend() {
142   DCHECK(CalledOnValidThread());
143   if (backend_.get())
144     return false;
145 
146   settings_.InitFrom(service_prefs_);
147 
148   // By default we don't poll for jobs when we lose XMPP connection. But this
149   // behavior can be overridden by a preference.
150   bool enable_job_poll =
151     service_prefs_->GetBoolean(prefs::kCloudPrintEnableJobPoll, false);
152 
153   gaia::OAuthClientInfo oauth_client_info;
154   oauth_client_info.client_id =
155     google_apis::GetOAuth2ClientID(google_apis::CLIENT_CLOUD_PRINT);
156   oauth_client_info.client_secret =
157     google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_CLOUD_PRINT);
158   oauth_client_info.redirect_uri = "oob";
159   backend_.reset(new CloudPrintProxyBackend(this, settings_, oauth_client_info,
160                                             enable_job_poll));
161   return true;
162 }
163 
UnregisterPrintersAndDisableForUser()164 void CloudPrintProxy::UnregisterPrintersAndDisableForUser() {
165   DCHECK(CalledOnValidThread());
166   if (backend_.get()) {
167     // Try getting auth and printers info from the backend.
168     // We'll get notified in this case.
169     backend_->UnregisterPrinters();
170   } else {
171     // If no backend avaialble, disable connector immidiately.
172     DisableForUser();
173   }
174 }
175 
DisableForUser()176 void CloudPrintProxy::DisableForUser() {
177   DCHECK(CalledOnValidThread());
178   user_email_.clear();
179   enabled_ = false;
180   if (client_) {
181     client_->OnCloudPrintProxyDisabled(true);
182   }
183   ShutdownBackend();
184 }
185 
GetProxyInfo(CloudPrintProxyInfo * info)186 void CloudPrintProxy::GetProxyInfo(CloudPrintProxyInfo* info) {
187   info->enabled = enabled_;
188   info->email.clear();
189   if (enabled_)
190     info->email = user_email();
191   info->proxy_id = settings_.proxy_id();
192   // If the Cloud Print service is not enabled, we may need to read the old
193   // value of proxy_id from prefs.
194   if (info->proxy_id.empty())
195     info->proxy_id =
196         service_prefs_->GetString(prefs::kCloudPrintProxyId, std::string());
197 }
198 
CheckCloudPrintProxyPolicy()199 void CloudPrintProxy::CheckCloudPrintProxyPolicy() {
200   g_service_process->io_thread()->message_loop_proxy()->PostTask(
201       FROM_HERE, base::Bind(&CheckCloudPrintProxyPolicyInBrowser));
202 }
203 
OnAuthenticated(const std::string & robot_oauth_refresh_token,const std::string & robot_email,const std::string & user_email)204 void CloudPrintProxy::OnAuthenticated(
205     const std::string& robot_oauth_refresh_token,
206     const std::string& robot_email,
207     const std::string& user_email) {
208   DCHECK(CalledOnValidThread());
209   service_prefs_->SetString(prefs::kCloudPrintRobotRefreshToken,
210                             robot_oauth_refresh_token);
211   service_prefs_->SetString(prefs::kCloudPrintRobotEmail,
212                             robot_email);
213   // If authenticating from a robot, the user email will be empty.
214   if (!user_email.empty()) {
215     user_email_ = user_email;
216   }
217   service_prefs_->SetString(prefs::kCloudPrintEmail, user_email_);
218   enabled_ = true;
219   DCHECK(!user_email_.empty());
220   service_prefs_->WritePrefs();
221   // When this switch used we don't want connector continue running, we just
222   // need authentication.
223   if (CommandLine::ForCurrentProcess()->HasSwitch(
224           switches::kCloudPrintSetupProxy)) {
225     ShutdownBackend();
226     if (client_) {
227       client_->OnCloudPrintProxyDisabled(false);
228     }
229   }
230 }
231 
OnAuthenticationFailed()232 void CloudPrintProxy::OnAuthenticationFailed() {
233   DCHECK(CalledOnValidThread());
234   // Don't disable permanently. Could be just connection issue.
235   ShutdownBackend();
236   if (client_) {
237     client_->OnCloudPrintProxyDisabled(false);
238   }
239 }
240 
OnPrintSystemUnavailable()241 void CloudPrintProxy::OnPrintSystemUnavailable() {
242   // If the print system is unavailable, we want to shutdown the proxy and
243   // disable it non-persistently.
244   ShutdownBackend();
245   if (client_) {
246     client_->OnCloudPrintProxyDisabled(false);
247   }
248 }
249 
OnUnregisterPrinters(const std::string & auth_token,const std::list<std::string> & printer_ids)250 void CloudPrintProxy::OnUnregisterPrinters(
251     const std::string& auth_token,
252     const std::list<std::string>& printer_ids) {
253   UMA_HISTOGRAM_COUNTS_10000("CloudPrint.UnregisterPrinters",
254                              printer_ids.size());
255   ShutdownBackend();
256   wipeout_.reset(new CloudPrintWipeout(this, settings_.server_url()));
257   wipeout_->UnregisterPrinters(auth_token, printer_ids);
258 }
259 
OnXmppPingUpdated(int ping_timeout)260 void CloudPrintProxy::OnXmppPingUpdated(int ping_timeout) {
261   DCHECK(CalledOnValidThread());
262   service_prefs_->SetInt(prefs::kCloudPrintXmppPingTimeout, ping_timeout);
263   service_prefs_->WritePrefs();
264 }
265 
OnUnregisterPrintersComplete()266 void CloudPrintProxy::OnUnregisterPrintersComplete() {
267   wipeout_.reset();
268   // Finish disabling cloud print for this user.
269   DisableForUser();
270 }
271 
ShutdownBackend()272 void CloudPrintProxy::ShutdownBackend() {
273   DCHECK(CalledOnValidThread());
274   if (backend_.get())
275     backend_->Shutdown();
276   backend_.reset();
277 }
278 
279 }  // namespace cloud_print
280