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