• 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_backend.h"
6 
7 #include <map>
8 #include <vector>
9 
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/compiler_specific.h"
13 #include "base/metrics/histogram.h"
14 #include "base/rand_util.h"
15 #include "base/strings/string_util.h"
16 #include "base/values.h"
17 #include "chrome/common/cloud_print/cloud_print_constants.h"
18 #include "chrome/service/cloud_print/cloud_print_auth.h"
19 #include "chrome/service/cloud_print/cloud_print_connector.h"
20 #include "chrome/service/cloud_print/cloud_print_service_helpers.h"
21 #include "chrome/service/cloud_print/cloud_print_token_store.h"
22 #include "chrome/service/cloud_print/connector_settings.h"
23 #include "chrome/service/net/service_url_request_context_getter.h"
24 #include "chrome/service/service_process.h"
25 #include "components/cloud_devices/common/cloud_devices_switches.h"
26 #include "google_apis/gaia/gaia_oauth_client.h"
27 #include "google_apis/gaia/gaia_urls.h"
28 #include "jingle/notifier/base/notifier_options.h"
29 #include "jingle/notifier/listener/push_client.h"
30 #include "jingle/notifier/listener/push_client_observer.h"
31 #include "url/gurl.h"
32 
33 namespace cloud_print {
34 
35 // The real guts of CloudPrintProxyBackend, to keep the public client API clean.
36 class CloudPrintProxyBackend::Core
37     : public base::RefCountedThreadSafe<CloudPrintProxyBackend::Core>,
38       public CloudPrintAuth::Client,
39       public CloudPrintConnector::Client,
40       public notifier::PushClientObserver {
41  public:
42   // It is OK for print_server_url to be empty. In this case system should
43   // use system default (local) print server.
44   Core(CloudPrintProxyBackend* backend,
45        const ConnectorSettings& settings,
46        const gaia::OAuthClientInfo& oauth_client_info,
47        bool enable_job_poll);
48 
49   // Note:
50   //
51   // The Do* methods are the various entry points from CloudPrintProxyBackend
52   // It calls us on a dedicated thread to actually perform synchronous
53   // (and potentially blocking) operations.
54   void DoInitializeWithToken(const std::string& cloud_print_token);
55   void DoInitializeWithRobotToken(const std::string& robot_oauth_refresh_token,
56                                   const std::string& robot_email);
57   void DoInitializeWithRobotAuthCode(const std::string& robot_oauth_auth_code,
58                                      const std::string& robot_email);
59 
60   // Called on the CloudPrintProxyBackend core_thread_ to perform
61   // shutdown.
62   void DoShutdown();
63   void DoRegisterSelectedPrinters(
64       const printing::PrinterList& printer_list);
65   void DoUnregisterPrinters();
66 
67   // CloudPrintAuth::Client implementation.
68   virtual void OnAuthenticationComplete(
69       const std::string& access_token,
70       const std::string& robot_oauth_refresh_token,
71       const std::string& robot_email,
72       const std::string& user_email) OVERRIDE;
73   virtual void OnInvalidCredentials() OVERRIDE;
74 
75   // CloudPrintConnector::Client implementation.
76   virtual void OnAuthFailed() OVERRIDE;
77   virtual void OnXmppPingUpdated(int ping_timeout) OVERRIDE;
78 
79   // notifier::PushClientObserver implementation.
80   virtual void OnNotificationsEnabled() OVERRIDE;
81   virtual void OnNotificationsDisabled(
82       notifier::NotificationsDisabledReason reason) OVERRIDE;
83   virtual void OnIncomingNotification(
84       const notifier::Notification& notification) OVERRIDE;
85   virtual void OnPingResponse() OVERRIDE;
86 
87  private:
88   friend class base::RefCountedThreadSafe<Core>;
89 
~Core()90   virtual ~Core() {}
91 
92   void CreateAuthAndConnector();
93   void DestroyAuthAndConnector();
94 
95   // NotifyXXX is how the Core communicates with the frontend across
96   // threads.
97   void NotifyPrinterListAvailable(
98       const printing::PrinterList& printer_list);
99   void NotifyAuthenticated(
100     const std::string& robot_oauth_refresh_token,
101     const std::string& robot_email,
102     const std::string& user_email);
103   void NotifyAuthenticationFailed();
104   void NotifyPrintSystemUnavailable();
105   void NotifyUnregisterPrinters(const std::string& auth_token,
106                                 const std::list<std::string>& printer_ids);
107   void NotifyXmppPingUpdated(int ping_timeout);
108 
109   // Init XMPP channel
110   void InitNotifications(const std::string& robot_email,
111                          const std::string& access_token);
112 
113   void HandlePrinterNotification(const std::string& notification);
114   void PollForJobs();
115   // Schedules a task to poll for jobs. Does nothing if a task is already
116   // scheduled.
117   void ScheduleJobPoll();
118   void PingXmppServer();
119   void ScheduleXmppPing();
120   void CheckXmppPingStatus();
121 
122   CloudPrintTokenStore* GetTokenStore();
123 
124   // Our parent CloudPrintProxyBackend
125   CloudPrintProxyBackend* backend_;
126 
127   // Cloud Print authenticator.
128   scoped_refptr<CloudPrintAuth> auth_;
129 
130   // Cloud Print connector.
131   scoped_refptr<CloudPrintConnector> connector_;
132 
133   // OAuth client info.
134   gaia::OAuthClientInfo oauth_client_info_;
135   // Notification (xmpp) handler.
136   scoped_ptr<notifier::PushClient> push_client_;
137   // Indicates whether XMPP notifications are currently enabled.
138   bool notifications_enabled_;
139   // The time when notifications were enabled. Valid only when
140   // notifications_enabled_ is true.
141   base::TimeTicks notifications_enabled_since_;
142   // Indicates whether a task to poll for jobs has been scheduled.
143   bool job_poll_scheduled_;
144   // Indicates whether we should poll for jobs when we lose XMPP connection.
145   bool enable_job_poll_;
146   // Indicates whether a task to ping xmpp server has been scheduled.
147   bool xmpp_ping_scheduled_;
148   // Number of XMPP pings pending reply from the server.
149   int pending_xmpp_pings_;
150   // Connector settings.
151   ConnectorSettings settings_;
152   std::string robot_email_;
153   scoped_ptr<CloudPrintTokenStore> token_store_;
154 
155   DISALLOW_COPY_AND_ASSIGN(Core);
156 };
157 
CloudPrintProxyBackend(CloudPrintProxyFrontend * frontend,const ConnectorSettings & settings,const gaia::OAuthClientInfo & oauth_client_info,bool enable_job_poll)158 CloudPrintProxyBackend::CloudPrintProxyBackend(
159     CloudPrintProxyFrontend* frontend,
160     const ConnectorSettings& settings,
161     const gaia::OAuthClientInfo& oauth_client_info,
162     bool enable_job_poll)
163     : core_thread_("Chrome_CloudPrintProxyCoreThread"),
164       frontend_loop_(base::MessageLoop::current()),
165       frontend_(frontend) {
166   DCHECK(frontend_);
167   core_ = new Core(this, settings, oauth_client_info, enable_job_poll);
168 }
169 
~CloudPrintProxyBackend()170 CloudPrintProxyBackend::~CloudPrintProxyBackend() { DCHECK(!core_.get()); }
171 
InitializeWithToken(const std::string & cloud_print_token)172 bool CloudPrintProxyBackend::InitializeWithToken(
173     const std::string& cloud_print_token) {
174   if (!core_thread_.Start())
175     return false;
176   core_thread_.message_loop()->PostTask(
177       FROM_HERE,
178       base::Bind(&CloudPrintProxyBackend::Core::DoInitializeWithToken,
179                  core_.get(), cloud_print_token));
180   return true;
181 }
182 
InitializeWithRobotToken(const std::string & robot_oauth_refresh_token,const std::string & robot_email)183 bool CloudPrintProxyBackend::InitializeWithRobotToken(
184     const std::string& robot_oauth_refresh_token,
185     const std::string& robot_email) {
186   if (!core_thread_.Start())
187     return false;
188   core_thread_.message_loop()->PostTask(
189       FROM_HERE,
190       base::Bind(&CloudPrintProxyBackend::Core::DoInitializeWithRobotToken,
191                  core_.get(), robot_oauth_refresh_token, robot_email));
192   return true;
193 }
194 
InitializeWithRobotAuthCode(const std::string & robot_oauth_auth_code,const std::string & robot_email)195 bool CloudPrintProxyBackend::InitializeWithRobotAuthCode(
196     const std::string& robot_oauth_auth_code,
197     const std::string& robot_email) {
198   if (!core_thread_.Start())
199     return false;
200   core_thread_.message_loop()->PostTask(
201       FROM_HERE,
202       base::Bind(&CloudPrintProxyBackend::Core::DoInitializeWithRobotAuthCode,
203                  core_.get(), robot_oauth_auth_code, robot_email));
204   return true;
205 }
206 
Shutdown()207 void CloudPrintProxyBackend::Shutdown() {
208   core_thread_.message_loop()->PostTask(
209       FROM_HERE,
210       base::Bind(&CloudPrintProxyBackend::Core::DoShutdown, core_.get()));
211   core_thread_.Stop();
212   core_ = NULL;  // Releases reference to core_.
213 }
214 
UnregisterPrinters()215 void CloudPrintProxyBackend::UnregisterPrinters() {
216   core_thread_.message_loop()->PostTask(
217       FROM_HERE,
218       base::Bind(&CloudPrintProxyBackend::Core::DoUnregisterPrinters,
219                  core_.get()));
220 }
221 
Core(CloudPrintProxyBackend * backend,const ConnectorSettings & settings,const gaia::OAuthClientInfo & oauth_client_info,bool enable_job_poll)222 CloudPrintProxyBackend::Core::Core(
223     CloudPrintProxyBackend* backend,
224     const ConnectorSettings& settings,
225     const gaia::OAuthClientInfo& oauth_client_info,
226     bool enable_job_poll)
227       : backend_(backend),
228         oauth_client_info_(oauth_client_info),
229         notifications_enabled_(false),
230         job_poll_scheduled_(false),
231         enable_job_poll_(enable_job_poll),
232         xmpp_ping_scheduled_(false),
233         pending_xmpp_pings_(0) {
234   settings_.CopyFrom(settings);
235 }
236 
CreateAuthAndConnector()237 void CloudPrintProxyBackend::Core::CreateAuthAndConnector() {
238   if (!auth_.get()) {
239     auth_ = new CloudPrintAuth(this, settings_.server_url(), oauth_client_info_,
240                                settings_.proxy_id());
241   }
242 
243   if (!connector_.get()) {
244     connector_ = new CloudPrintConnector(this, settings_);
245   }
246 }
247 
DestroyAuthAndConnector()248 void CloudPrintProxyBackend::Core::DestroyAuthAndConnector() {
249   auth_ = NULL;
250   connector_ = NULL;
251 }
252 
DoInitializeWithToken(const std::string & cloud_print_token)253 void CloudPrintProxyBackend::Core::DoInitializeWithToken(
254     const std::string& cloud_print_token) {
255   DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
256   CreateAuthAndConnector();
257   auth_->AuthenticateWithToken(cloud_print_token);
258 }
259 
DoInitializeWithRobotToken(const std::string & robot_oauth_refresh_token,const std::string & robot_email)260 void CloudPrintProxyBackend::Core::DoInitializeWithRobotToken(
261     const std::string& robot_oauth_refresh_token,
262     const std::string& robot_email) {
263   DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
264   CreateAuthAndConnector();
265   auth_->AuthenticateWithRobotToken(robot_oauth_refresh_token, robot_email);
266 }
267 
DoInitializeWithRobotAuthCode(const std::string & robot_oauth_auth_code,const std::string & robot_email)268 void CloudPrintProxyBackend::Core::DoInitializeWithRobotAuthCode(
269     const std::string& robot_oauth_auth_code,
270     const std::string& robot_email) {
271   DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
272   CreateAuthAndConnector();
273   auth_->AuthenticateWithRobotAuthCode(robot_oauth_auth_code, robot_email);
274 }
275 
OnAuthenticationComplete(const std::string & access_token,const std::string & robot_oauth_refresh_token,const std::string & robot_email,const std::string & user_email)276 void CloudPrintProxyBackend::Core::OnAuthenticationComplete(
277     const std::string& access_token,
278     const std::string& robot_oauth_refresh_token,
279     const std::string& robot_email,
280     const std::string& user_email) {
281   CloudPrintTokenStore* token_store  = GetTokenStore();
282   bool first_time = token_store->token().empty();
283   token_store->SetToken(access_token);
284   robot_email_ = robot_email;
285   // Let the frontend know that we have authenticated.
286   backend_->frontend_loop_->PostTask(
287       FROM_HERE,
288       base::Bind(&Core::NotifyAuthenticated, this, robot_oauth_refresh_token,
289                  robot_email, user_email));
290   if (first_time) {
291     InitNotifications(robot_email, access_token);
292   } else {
293     // If we are refreshing a token, update the XMPP token too.
294     DCHECK(push_client_.get());
295     push_client_->UpdateCredentials(robot_email, access_token);
296   }
297   // Start cloud print connector if needed.
298   if (!connector_->IsRunning()) {
299     if (!connector_->Start()) {
300       // Let the frontend know that we do not have a print system.
301       backend_->frontend_loop_->PostTask(
302           FROM_HERE, base::Bind(&Core::NotifyPrintSystemUnavailable, this));
303     }
304   }
305 }
306 
OnInvalidCredentials()307 void CloudPrintProxyBackend::Core::OnInvalidCredentials() {
308   DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
309   VLOG(1) << "CP_CONNECTOR: Auth Error";
310   backend_->frontend_loop_->PostTask(
311       FROM_HERE, base::Bind(&Core::NotifyAuthenticationFailed, this));
312 }
313 
OnAuthFailed()314 void CloudPrintProxyBackend::Core::OnAuthFailed() {
315   VLOG(1) << "CP_CONNECTOR: Authentication failed in connector.";
316   // Let's stop connecter and refresh token. We'll restart connecter once
317   // new token available.
318   if (connector_->IsRunning())
319     connector_->Stop();
320 
321   // Refresh Auth token.
322   auth_->RefreshAccessToken();
323 }
324 
OnXmppPingUpdated(int ping_timeout)325 void CloudPrintProxyBackend::Core::OnXmppPingUpdated(int ping_timeout) {
326   settings_.SetXmppPingTimeoutSec(ping_timeout);
327   backend_->frontend_loop_->PostTask(
328       FROM_HERE,
329       base::Bind(&Core::NotifyXmppPingUpdated, this, ping_timeout));
330 }
331 
InitNotifications(const std::string & robot_email,const std::string & access_token)332 void CloudPrintProxyBackend::Core::InitNotifications(
333     const std::string& robot_email,
334     const std::string& access_token) {
335   DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
336 
337   pending_xmpp_pings_ = 0;
338   notifier::NotifierOptions notifier_options;
339   notifier_options.request_context_getter =
340       g_service_process->GetServiceURLRequestContextGetter();
341   notifier_options.auth_mechanism = "X-OAUTH2";
342   notifier_options.try_ssltcp_first = true;
343   notifier_options.xmpp_host_port = net::HostPortPair::FromString(
344       CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
345           switches::kCloudPrintXmppEndpoint));
346   push_client_ = notifier::PushClient::CreateDefault(notifier_options);
347   push_client_->AddObserver(this);
348   notifier::Subscription subscription;
349   subscription.channel = kCloudPrintPushNotificationsSource;
350   subscription.from = kCloudPrintPushNotificationsSource;
351   push_client_->UpdateSubscriptions(
352       notifier::SubscriptionList(1, subscription));
353   push_client_->UpdateCredentials(robot_email, access_token);
354 }
355 
DoShutdown()356 void CloudPrintProxyBackend::Core::DoShutdown() {
357   DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
358   VLOG(1) << "CP_CONNECTOR: Shutdown connector, id: " << settings_.proxy_id();
359 
360   if (connector_->IsRunning())
361     connector_->Stop();
362 
363   // Important to delete the PushClient on this thread.
364   if (push_client_.get()) {
365     push_client_->RemoveObserver(this);
366   }
367   push_client_.reset();
368   notifications_enabled_ = false;
369   notifications_enabled_since_ = base::TimeTicks();
370   token_store_.reset();
371 
372   DestroyAuthAndConnector();
373 }
374 
DoUnregisterPrinters()375 void CloudPrintProxyBackend::Core::DoUnregisterPrinters() {
376   DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
377 
378   std::string access_token = GetTokenStore()->token();
379 
380   std::list<std::string> printer_ids;
381   connector_->GetPrinterIds(&printer_ids);
382 
383   backend_->frontend_loop_->PostTask(
384       FROM_HERE,
385       base::Bind(&Core::NotifyUnregisterPrinters,
386                  this, access_token, printer_ids));
387 }
388 
HandlePrinterNotification(const std::string & notification)389 void CloudPrintProxyBackend::Core::HandlePrinterNotification(
390     const std::string& notification) {
391   DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
392 
393   size_t pos = notification.rfind(kNotificationUpdateSettings);
394   if (pos == std::string::npos) {
395     VLOG(1) << "CP_CONNECTOR: Handle printer notification, id: "
396             << notification;
397     connector_->CheckForJobs(kJobFetchReasonNotified, notification);
398   } else {
399     DCHECK(pos == notification.length() - strlen(kNotificationUpdateSettings));
400     std::string printer_id = notification.substr(0, pos);
401     VLOG(1) << "CP_CONNECTOR: Update printer settings, id: " << printer_id;
402     connector_->UpdatePrinterSettings(printer_id);
403   }
404 }
405 
PollForJobs()406 void CloudPrintProxyBackend::Core::PollForJobs() {
407   VLOG(1) << "CP_CONNECTOR: Polling for jobs.";
408   DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
409   // Check all printers for jobs.
410   connector_->CheckForJobs(kJobFetchReasonPoll, std::string());
411 
412   job_poll_scheduled_ = false;
413   // If we don't have notifications and job polling is enabled, poll again
414   // after a while.
415   if (!notifications_enabled_ && enable_job_poll_)
416     ScheduleJobPoll();
417 }
418 
ScheduleJobPoll()419 void CloudPrintProxyBackend::Core::ScheduleJobPoll() {
420   if (!job_poll_scheduled_) {
421     base::TimeDelta interval = base::TimeDelta::FromSeconds(
422         base::RandInt(kMinJobPollIntervalSecs, kMaxJobPollIntervalSecs));
423     base::MessageLoop::current()->PostDelayedTask(
424         FROM_HERE,
425         base::Bind(&CloudPrintProxyBackend::Core::PollForJobs, this),
426         interval);
427     job_poll_scheduled_ = true;
428   }
429 }
430 
PingXmppServer()431 void CloudPrintProxyBackend::Core::PingXmppServer() {
432   xmpp_ping_scheduled_ = false;
433 
434   if (!push_client_.get())
435     return;
436 
437   push_client_->SendPing();
438 
439   pending_xmpp_pings_++;
440   if (pending_xmpp_pings_ >= kMaxFailedXmppPings) {
441     // Check ping status when we close to the limit.
442     base::MessageLoop::current()->PostDelayedTask(
443         FROM_HERE,
444         base::Bind(&CloudPrintProxyBackend::Core::CheckXmppPingStatus, this),
445         base::TimeDelta::FromSeconds(kXmppPingCheckIntervalSecs));
446   }
447 
448   // Schedule next ping if needed.
449   if (notifications_enabled_)
450     ScheduleXmppPing();
451 }
452 
ScheduleXmppPing()453 void CloudPrintProxyBackend::Core::ScheduleXmppPing() {
454   // settings_.xmpp_ping_enabled() is obsolete, we are now control
455   // XMPP pings from Cloud Print server.
456   if (!xmpp_ping_scheduled_) {
457     base::TimeDelta interval = base::TimeDelta::FromSeconds(
458       base::RandInt(settings_.xmpp_ping_timeout_sec() * 0.9,
459                     settings_.xmpp_ping_timeout_sec() * 1.1));
460     base::MessageLoop::current()->PostDelayedTask(
461         FROM_HERE,
462         base::Bind(&CloudPrintProxyBackend::Core::PingXmppServer, this),
463         interval);
464     xmpp_ping_scheduled_ = true;
465   }
466 }
467 
CheckXmppPingStatus()468 void CloudPrintProxyBackend::Core::CheckXmppPingStatus() {
469   if (pending_xmpp_pings_ >= kMaxFailedXmppPings) {
470     UMA_HISTOGRAM_COUNTS_100("CloudPrint.XmppPingTry", 99);  // Max on fail.
471     // Reconnect to XMPP.
472     pending_xmpp_pings_ = 0;
473     push_client_.reset();
474     InitNotifications(robot_email_, GetTokenStore()->token());
475   }
476 }
477 
GetTokenStore()478 CloudPrintTokenStore* CloudPrintProxyBackend::Core::GetTokenStore() {
479   DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
480   if (!token_store_.get())
481     token_store_.reset(new CloudPrintTokenStore);
482   return token_store_.get();
483 }
484 
NotifyAuthenticated(const std::string & robot_oauth_refresh_token,const std::string & robot_email,const std::string & user_email)485 void CloudPrintProxyBackend::Core::NotifyAuthenticated(
486     const std::string& robot_oauth_refresh_token,
487     const std::string& robot_email,
488     const std::string& user_email) {
489   DCHECK(base::MessageLoop::current() == backend_->frontend_loop_);
490   backend_->frontend_
491       ->OnAuthenticated(robot_oauth_refresh_token, robot_email, user_email);
492 }
493 
NotifyAuthenticationFailed()494 void CloudPrintProxyBackend::Core::NotifyAuthenticationFailed() {
495   DCHECK(base::MessageLoop::current() == backend_->frontend_loop_);
496   backend_->frontend_->OnAuthenticationFailed();
497 }
498 
NotifyPrintSystemUnavailable()499 void CloudPrintProxyBackend::Core::NotifyPrintSystemUnavailable() {
500   DCHECK(base::MessageLoop::current() == backend_->frontend_loop_);
501   backend_->frontend_->OnPrintSystemUnavailable();
502 }
503 
NotifyUnregisterPrinters(const std::string & auth_token,const std::list<std::string> & printer_ids)504 void CloudPrintProxyBackend::Core::NotifyUnregisterPrinters(
505     const std::string& auth_token,
506     const std::list<std::string>& printer_ids) {
507   DCHECK(base::MessageLoop::current() == backend_->frontend_loop_);
508   backend_->frontend_->OnUnregisterPrinters(auth_token, printer_ids);
509 }
510 
NotifyXmppPingUpdated(int ping_timeout)511 void CloudPrintProxyBackend::Core::NotifyXmppPingUpdated(int ping_timeout) {
512   DCHECK(base::MessageLoop::current() == backend_->frontend_loop_);
513   backend_->frontend_->OnXmppPingUpdated(ping_timeout);
514 }
515 
OnNotificationsEnabled()516 void CloudPrintProxyBackend::Core::OnNotificationsEnabled() {
517   DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
518   notifications_enabled_ = true;
519   notifications_enabled_since_ = base::TimeTicks::Now();
520   VLOG(1) << "Notifications for connector " << settings_.proxy_id()
521           << " were enabled at "
522           << notifications_enabled_since_.ToInternalValue();
523   // Notifications just got re-enabled. In this case we want to schedule
524   // a poll once for jobs we might have missed when we were dark.
525   // Note that ScheduleJobPoll will not schedule again if a job poll task is
526   // already scheduled.
527   ScheduleJobPoll();
528 
529   // Schedule periodic ping for XMPP notification channel.
530   ScheduleXmppPing();
531 }
532 
OnNotificationsDisabled(notifier::NotificationsDisabledReason reason)533 void CloudPrintProxyBackend::Core::OnNotificationsDisabled(
534     notifier::NotificationsDisabledReason reason) {
535   DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
536   notifications_enabled_ = false;
537   LOG(ERROR) << "Notifications for connector " << settings_.proxy_id()
538              << " disabled.";
539   notifications_enabled_since_ = base::TimeTicks();
540   // We just lost notifications. This this case we want to schedule a
541   // job poll if enable_job_poll_ is true.
542   if (enable_job_poll_)
543     ScheduleJobPoll();
544 }
545 
546 
OnIncomingNotification(const notifier::Notification & notification)547 void CloudPrintProxyBackend::Core::OnIncomingNotification(
548     const notifier::Notification& notification) {
549   // Since we got some notification from the server,
550   // reset pending ping counter to 0.
551   pending_xmpp_pings_ = 0;
552 
553   DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
554   VLOG(1) << "CP_CONNECTOR: Incoming notification.";
555   if (0 == base::strcasecmp(kCloudPrintPushNotificationsSource,
556                             notification.channel.c_str()))
557     HandlePrinterNotification(notification.data);
558 }
559 
OnPingResponse()560 void CloudPrintProxyBackend::Core::OnPingResponse() {
561   UMA_HISTOGRAM_COUNTS_100("CloudPrint.XmppPingTry", pending_xmpp_pings_);
562   pending_xmpp_pings_ = 0;
563   VLOG(1) << "CP_CONNECTOR: Ping response received.";
564 }
565 
566 }  // namespace cloud_print
567