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