gcm_driver_desktop.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
1// Copyright 2014 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 "components/gcm_driver/gcm_driver_desktop.h"
6
7#include <utility>
8
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/files/file_path.h"
12#include "base/location.h"
13#include "base/logging.h"
14#include "base/sequenced_task_runner.h"
15#include "base/threading/sequenced_worker_pool.h"
16#include "components/gcm_driver/gcm_app_handler.h"
17#include "components/gcm_driver/gcm_client_factory.h"
18#include "components/gcm_driver/system_encryptor.h"
19#include "net/base/ip_endpoint.h"
20#include "net/url_request/url_request_context_getter.h"
21
22namespace gcm {
23
24namespace {
25
26// Empty string is reserved for the default app handler.
27const char kDefaultAppHandler[] = "";
28
29}  // namespace
30
31// Helper class to save tasks to run until we're ready to execute them.
32class GCMDriverDesktop::DelayedTaskController {
33 public:
34  DelayedTaskController();
35  ~DelayedTaskController();
36
37  // Adds a task that will be invoked once we're ready.
38  void AddTask(const base::Closure& task);
39
40  // Sets ready status. It is ready only when check-in is completed and
41  // the GCMClient is fully initialized.
42  void SetReady();
43
44  // Returns true if it is ready to perform tasks.
45  bool CanRunTaskWithoutDelay() const;
46
47 private:
48  void RunTasks();
49
50  // Flag that indicates that GCM is ready.
51  bool ready_;
52
53  std::vector<base::Closure> delayed_tasks_;
54
55  DISALLOW_COPY_AND_ASSIGN(DelayedTaskController);
56};
57
58GCMDriverDesktop::DelayedTaskController::DelayedTaskController()
59    : ready_(false) {
60}
61
62GCMDriverDesktop::DelayedTaskController::~DelayedTaskController() {
63}
64
65void GCMDriverDesktop::DelayedTaskController::AddTask(
66    const base::Closure& task) {
67  delayed_tasks_.push_back(task);
68}
69
70void GCMDriverDesktop::DelayedTaskController::SetReady() {
71  ready_ = true;
72  RunTasks();
73}
74
75bool GCMDriverDesktop::DelayedTaskController::CanRunTaskWithoutDelay() const {
76  return ready_;
77}
78
79void GCMDriverDesktop::DelayedTaskController::RunTasks() {
80  DCHECK(ready_);
81
82  for (size_t i = 0; i < delayed_tasks_.size(); ++i)
83    delayed_tasks_[i].Run();
84  delayed_tasks_.clear();
85}
86
87class GCMDriverDesktop::IOWorker : public GCMClient::Delegate {
88 public:
89  // Called on UI thread.
90  IOWorker(const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
91           const scoped_refptr<base::SequencedTaskRunner>& io_thread);
92  virtual ~IOWorker();
93
94  // Overridden from GCMClient::Delegate:
95  // Called on IO thread.
96  virtual void OnRegisterFinished(const std::string& app_id,
97                                  const std::string& registration_id,
98                                  GCMClient::Result result) OVERRIDE;
99  virtual void OnUnregisterFinished(const std::string& app_id,
100                                    GCMClient::Result result) OVERRIDE;
101  virtual void OnSendFinished(const std::string& app_id,
102                              const std::string& message_id,
103                              GCMClient::Result result) OVERRIDE;
104  virtual void OnMessageReceived(
105      const std::string& app_id,
106      const GCMClient::IncomingMessage& message) OVERRIDE;
107  virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE;
108  virtual void OnMessageSendError(
109      const std::string& app_id,
110      const GCMClient::SendErrorDetails& send_error_details) OVERRIDE;
111  virtual void OnGCMReady() OVERRIDE;
112  virtual void OnActivityRecorded() OVERRIDE;
113  virtual void OnConnected(const net::IPEndPoint& ip_endpoint) OVERRIDE;
114  virtual void OnDisconnected() OVERRIDE;
115
116  // Called on IO thread.
117  void Initialize(
118      scoped_ptr<GCMClientFactory> gcm_client_factory,
119      const GCMClient::ChromeBuildInfo& chrome_build_info,
120      const base::FilePath& store_path,
121      const scoped_refptr<net::URLRequestContextGetter>& request_context,
122      const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
123  void Start(const base::WeakPtr<GCMDriverDesktop>& service);
124  void Stop();
125  void CheckOut();
126  void Register(const std::string& app_id,
127                const std::vector<std::string>& sender_ids);
128  void Unregister(const std::string& app_id);
129  void Send(const std::string& app_id,
130            const std::string& receiver_id,
131            const GCMClient::OutgoingMessage& message);
132  void GetGCMStatistics(bool clear_logs);
133  void SetGCMRecording(bool recording);
134
135  // For testing purpose. Can be called from UI thread. Use with care.
136  GCMClient* gcm_client_for_testing() const { return gcm_client_.get(); }
137
138 private:
139  scoped_refptr<base::SequencedTaskRunner> ui_thread_;
140  scoped_refptr<base::SequencedTaskRunner> io_thread_;
141
142  base::WeakPtr<GCMDriverDesktop> service_;
143
144  scoped_ptr<GCMClient> gcm_client_;
145
146  DISALLOW_COPY_AND_ASSIGN(IOWorker);
147};
148
149GCMDriverDesktop::IOWorker::IOWorker(
150    const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
151    const scoped_refptr<base::SequencedTaskRunner>& io_thread)
152    : ui_thread_(ui_thread),
153      io_thread_(io_thread) {
154  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
155}
156
157GCMDriverDesktop::IOWorker::~IOWorker() {
158  DCHECK(io_thread_->RunsTasksOnCurrentThread());
159}
160
161void GCMDriverDesktop::IOWorker::Initialize(
162    scoped_ptr<GCMClientFactory> gcm_client_factory,
163    const GCMClient::ChromeBuildInfo& chrome_build_info,
164    const base::FilePath& store_path,
165    const scoped_refptr<net::URLRequestContextGetter>& request_context,
166    const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) {
167  DCHECK(io_thread_->RunsTasksOnCurrentThread());
168
169  gcm_client_ = gcm_client_factory->BuildInstance();
170
171  gcm_client_->Initialize(chrome_build_info,
172                          store_path,
173                          blocking_task_runner,
174                          request_context,
175                          make_scoped_ptr<Encryptor>(new SystemEncryptor),
176                          this);
177}
178
179void GCMDriverDesktop::IOWorker::OnRegisterFinished(
180    const std::string& app_id,
181    const std::string& registration_id,
182    GCMClient::Result result) {
183  DCHECK(io_thread_->RunsTasksOnCurrentThread());
184
185  ui_thread_->PostTask(
186      FROM_HERE,
187      base::Bind(&GCMDriverDesktop::RegisterFinished, service_, app_id,
188                 registration_id, result));
189}
190
191void GCMDriverDesktop::IOWorker::OnUnregisterFinished(
192    const std::string& app_id,
193    GCMClient::Result result) {
194  DCHECK(io_thread_->RunsTasksOnCurrentThread());
195
196  ui_thread_->PostTask(FROM_HERE,
197                       base::Bind(&GCMDriverDesktop::UnregisterFinished,
198                                  service_,
199                                  app_id,
200                                  result));
201}
202
203void GCMDriverDesktop::IOWorker::OnSendFinished(const std::string& app_id,
204                                                const std::string& message_id,
205                                                GCMClient::Result result) {
206  DCHECK(io_thread_->RunsTasksOnCurrentThread());
207
208  ui_thread_->PostTask(
209      FROM_HERE,
210      base::Bind(&GCMDriverDesktop::SendFinished, service_, app_id, message_id,
211                 result));
212}
213
214void GCMDriverDesktop::IOWorker::OnMessageReceived(
215    const std::string& app_id,
216    const GCMClient::IncomingMessage& message) {
217  DCHECK(io_thread_->RunsTasksOnCurrentThread());
218
219  ui_thread_->PostTask(
220      FROM_HERE,
221      base::Bind(&GCMDriverDesktop::MessageReceived,
222                 service_,
223                 app_id,
224                 message));
225}
226
227void GCMDriverDesktop::IOWorker::OnMessagesDeleted(const std::string& app_id) {
228  DCHECK(io_thread_->RunsTasksOnCurrentThread());
229
230  ui_thread_->PostTask(
231      FROM_HERE,
232      base::Bind(&GCMDriverDesktop::MessagesDeleted, service_, app_id));
233}
234
235void GCMDriverDesktop::IOWorker::OnMessageSendError(
236    const std::string& app_id,
237    const GCMClient::SendErrorDetails& send_error_details) {
238  DCHECK(io_thread_->RunsTasksOnCurrentThread());
239
240  ui_thread_->PostTask(
241      FROM_HERE,
242      base::Bind(&GCMDriverDesktop::MessageSendError, service_, app_id,
243                 send_error_details));
244}
245
246void GCMDriverDesktop::IOWorker::OnGCMReady() {
247  ui_thread_->PostTask(
248      FROM_HERE,
249      base::Bind(&GCMDriverDesktop::GCMClientReady, service_));
250}
251
252void GCMDriverDesktop::IOWorker::OnActivityRecorded() {
253  DCHECK(io_thread_->RunsTasksOnCurrentThread());
254  // When an activity is recorded, get all the stats and refresh the UI of
255  // gcm-internals page.
256  GetGCMStatistics(false);
257}
258
259void GCMDriverDesktop::IOWorker::OnConnected(
260    const net::IPEndPoint& ip_endpoint) {
261  ui_thread_->PostTask(FROM_HERE,
262                       base::Bind(&GCMDriverDesktop::OnConnected,
263                                  service_,
264                                  ip_endpoint));
265}
266
267void GCMDriverDesktop::IOWorker::OnDisconnected() {
268  ui_thread_->PostTask(FROM_HERE,
269                       base::Bind(&GCMDriverDesktop::OnDisconnected, service_));
270}
271
272void GCMDriverDesktop::IOWorker::Start(
273    const base::WeakPtr<GCMDriverDesktop>& service) {
274  DCHECK(io_thread_->RunsTasksOnCurrentThread());
275
276  service_ = service;
277  gcm_client_->Start();
278}
279
280void GCMDriverDesktop::IOWorker::Stop() {
281  DCHECK(io_thread_->RunsTasksOnCurrentThread());
282
283  gcm_client_->Stop();
284}
285
286void GCMDriverDesktop::IOWorker::CheckOut() {
287  DCHECK(io_thread_->RunsTasksOnCurrentThread());
288
289  gcm_client_->CheckOut();
290
291  // Note that we still need to keep GCMClient instance alive since the
292  // GCMDriverDesktop may check in again.
293}
294
295void GCMDriverDesktop::IOWorker::Register(
296    const std::string& app_id,
297    const std::vector<std::string>& sender_ids) {
298  DCHECK(io_thread_->RunsTasksOnCurrentThread());
299
300  gcm_client_->Register(app_id, sender_ids);
301}
302
303void GCMDriverDesktop::IOWorker::Unregister(const std::string& app_id) {
304  DCHECK(io_thread_->RunsTasksOnCurrentThread());
305
306  gcm_client_->Unregister(app_id);
307}
308
309void GCMDriverDesktop::IOWorker::Send(
310    const std::string& app_id,
311    const std::string& receiver_id,
312    const GCMClient::OutgoingMessage& message) {
313  DCHECK(io_thread_->RunsTasksOnCurrentThread());
314
315  gcm_client_->Send(app_id, receiver_id, message);
316}
317
318void GCMDriverDesktop::IOWorker::GetGCMStatistics(bool clear_logs) {
319  DCHECK(io_thread_->RunsTasksOnCurrentThread());
320  gcm::GCMClient::GCMStatistics stats;
321
322  if (gcm_client_.get()) {
323    if (clear_logs)
324      gcm_client_->ClearActivityLogs();
325    stats = gcm_client_->GetStatistics();
326  }
327
328  ui_thread_->PostTask(
329      FROM_HERE,
330      base::Bind(&GCMDriverDesktop::GetGCMStatisticsFinished, service_, stats));
331}
332
333void GCMDriverDesktop::IOWorker::SetGCMRecording(bool recording) {
334  DCHECK(io_thread_->RunsTasksOnCurrentThread());
335  gcm::GCMClient::GCMStatistics stats;
336
337  if (gcm_client_.get()) {
338    gcm_client_->SetRecording(recording);
339    stats = gcm_client_->GetStatistics();
340    stats.gcm_client_created = true;
341  }
342
343  ui_thread_->PostTask(
344      FROM_HERE,
345      base::Bind(&GCMDriverDesktop::GetGCMStatisticsFinished, service_, stats));
346}
347
348GCMDriverDesktop::GCMDriverDesktop(
349    scoped_ptr<GCMClientFactory> gcm_client_factory,
350    const GCMClient::ChromeBuildInfo& chrome_build_info,
351    const base::FilePath& store_path,
352    const scoped_refptr<net::URLRequestContextGetter>& request_context,
353    const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
354    const scoped_refptr<base::SequencedTaskRunner>& io_thread,
355    const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
356    : signed_in_(false),
357      gcm_started_(false),
358      gcm_enabled_(true),
359      gcm_client_ready_(false),
360      connected_(false),
361      ui_thread_(ui_thread),
362      io_thread_(io_thread),
363      weak_ptr_factory_(this) {
364  // Create and initialize the GCMClient. Note that this does not initiate the
365  // GCM check-in.
366  io_worker_.reset(new IOWorker(ui_thread, io_thread));
367  io_thread_->PostTask(
368      FROM_HERE,
369      base::Bind(&GCMDriverDesktop::IOWorker::Initialize,
370                 base::Unretained(io_worker_.get()),
371                 base::Passed(&gcm_client_factory),
372                 chrome_build_info,
373                 store_path,
374                 request_context,
375                 blocking_task_runner));
376}
377
378GCMDriverDesktop::~GCMDriverDesktop() {
379}
380
381void GCMDriverDesktop::Shutdown() {
382  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
383  GCMDriver::Shutdown();
384  io_thread_->DeleteSoon(FROM_HERE, io_worker_.release());
385}
386
387void GCMDriverDesktop::OnSignedIn() {
388  signed_in_ = true;
389  EnsureStarted();
390}
391
392void GCMDriverDesktop::Purge() {
393  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
394
395  // We still proceed with the check-out logic even if the check-in is not
396  // initiated in the current session. This will make sure that all the
397  // persisted data written previously will get purged.
398  signed_in_ = false;
399  RemoveCachedData();
400
401  io_thread_->PostTask(FROM_HERE,
402                       base::Bind(&GCMDriverDesktop::IOWorker::CheckOut,
403                       base::Unretained(io_worker_.get())));
404}
405
406void GCMDriverDesktop::AddAppHandler(const std::string& app_id,
407                                     GCMAppHandler* handler) {
408  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
409  GCMDriver::AddAppHandler(app_id, handler);
410
411   // Ensures that the GCM service is started when there is an interest.
412  EnsureStarted();
413}
414
415void GCMDriverDesktop::RemoveAppHandler(const std::string& app_id) {
416  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
417  GCMDriver::RemoveAppHandler(app_id);
418
419  // Stops the GCM service when no app intends to consume it.
420  if (app_handlers().empty())
421    Stop();
422}
423
424void GCMDriverDesktop::Enable() {
425  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
426
427  if (gcm_enabled_)
428    return;
429  gcm_enabled_ = true;
430
431  EnsureStarted();
432}
433
434void GCMDriverDesktop::Disable() {
435  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
436
437  if (!gcm_enabled_)
438    return;
439  gcm_enabled_ = false;
440
441  Stop();
442}
443
444void GCMDriverDesktop::Stop() {
445  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
446
447  // No need to stop GCM service if not started yet.
448  if (!gcm_started_)
449    return;
450
451  RemoveCachedData();
452
453  io_thread_->PostTask(
454      FROM_HERE,
455      base::Bind(&GCMDriverDesktop::IOWorker::Stop,
456                 base::Unretained(io_worker_.get())));
457}
458
459void GCMDriverDesktop::RegisterImpl(
460    const std::string& app_id,
461    const std::vector<std::string>& sender_ids) {
462  // Delay the register operation until GCMClient is ready.
463  if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
464    delayed_task_controller_->AddTask(base::Bind(&GCMDriverDesktop::DoRegister,
465                                                 weak_ptr_factory_.GetWeakPtr(),
466                                                 app_id,
467                                                 sender_ids));
468    return;
469  }
470
471  DoRegister(app_id, sender_ids);
472}
473
474void GCMDriverDesktop::DoRegister(const std::string& app_id,
475                                  const std::vector<std::string>& sender_ids) {
476  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
477  if (!HasRegisterCallback(app_id)) {
478    // The callback could have been removed when the app is uninstalled.
479    return;
480  }
481
482  io_thread_->PostTask(
483      FROM_HERE,
484      base::Bind(&GCMDriverDesktop::IOWorker::Register,
485                 base::Unretained(io_worker_.get()),
486                 app_id,
487                 sender_ids));
488}
489
490void GCMDriverDesktop::UnregisterImpl(const std::string& app_id) {
491  // Delay the unregister operation until GCMClient is ready.
492  if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
493    delayed_task_controller_->AddTask(
494        base::Bind(&GCMDriverDesktop::DoUnregister,
495                   weak_ptr_factory_.GetWeakPtr(),
496                   app_id));
497    return;
498  }
499
500  DoUnregister(app_id);
501}
502
503void GCMDriverDesktop::DoUnregister(const std::string& app_id) {
504  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
505
506  // Ask the server to unregister it. There could be a small chance that the
507  // unregister request fails. If this occurs, it does not bring any harm since
508  // we simply reject the messages/events received from the server.
509  io_thread_->PostTask(
510      FROM_HERE,
511      base::Bind(&GCMDriverDesktop::IOWorker::Unregister,
512                 base::Unretained(io_worker_.get()),
513                 app_id));
514}
515
516void GCMDriverDesktop::SendImpl(const std::string& app_id,
517                                const std::string& receiver_id,
518                                const GCMClient::OutgoingMessage& message) {
519  // Delay the send operation until all GCMClient is ready.
520  if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
521    delayed_task_controller_->AddTask(base::Bind(&GCMDriverDesktop::DoSend,
522                                                 weak_ptr_factory_.GetWeakPtr(),
523                                                 app_id,
524                                                 receiver_id,
525                                                 message));
526    return;
527  }
528
529  DoSend(app_id, receiver_id, message);
530}
531
532void GCMDriverDesktop::DoSend(const std::string& app_id,
533                              const std::string& receiver_id,
534                              const GCMClient::OutgoingMessage& message) {
535  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
536  io_thread_->PostTask(
537      FROM_HERE,
538      base::Bind(&GCMDriverDesktop::IOWorker::Send,
539                 base::Unretained(io_worker_.get()),
540                 app_id,
541                 receiver_id,
542                 message));
543}
544
545GCMClient* GCMDriverDesktop::GetGCMClientForTesting() const {
546  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
547  return io_worker_ ? io_worker_->gcm_client_for_testing() : NULL;
548}
549
550bool GCMDriverDesktop::IsStarted() const {
551  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
552  return gcm_started_;
553}
554
555bool GCMDriverDesktop::IsGCMClientReady() const {
556  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
557  return gcm_client_ready_;
558}
559
560bool GCMDriverDesktop::IsConnected() const {
561  return connected_;
562}
563
564void GCMDriverDesktop::GetGCMStatistics(
565    const GetGCMStatisticsCallback& callback,
566    bool clear_logs) {
567  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
568  DCHECK(!callback.is_null());
569
570  request_gcm_statistics_callback_ = callback;
571  io_thread_->PostTask(
572      FROM_HERE,
573      base::Bind(&GCMDriverDesktop::IOWorker::GetGCMStatistics,
574                 base::Unretained(io_worker_.get()),
575                 clear_logs));
576}
577
578void GCMDriverDesktop::SetGCMRecording(const GetGCMStatisticsCallback& callback,
579                                       bool recording) {
580  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
581
582  request_gcm_statistics_callback_ = callback;
583  io_thread_->PostTask(
584      FROM_HERE,
585      base::Bind(&GCMDriverDesktop::IOWorker::SetGCMRecording,
586                 base::Unretained(io_worker_.get()),
587                 recording));
588}
589
590GCMClient::Result GCMDriverDesktop::EnsureStarted() {
591  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
592
593  if (gcm_started_)
594    return GCMClient::SUCCESS;
595
596  if (!gcm_enabled_)
597    return GCMClient::GCM_DISABLED;
598
599  // Have any app requested the service?
600  if (app_handlers().empty())
601    return GCMClient::UNKNOWN_ERROR;
602
603  // TODO(jianli): To be removed when sign-in enforcement is dropped.
604  if (!signed_in_)
605    return GCMClient::NOT_SIGNED_IN;
606
607  DCHECK(!delayed_task_controller_);
608  delayed_task_controller_.reset(new DelayedTaskController);
609
610  // Note that we need to pass weak pointer again since the existing weak
611  // pointer in IOWorker might have been invalidated when check-out occurs.
612  io_thread_->PostTask(
613      FROM_HERE,
614      base::Bind(&GCMDriverDesktop::IOWorker::Start,
615                 base::Unretained(io_worker_.get()),
616                 weak_ptr_factory_.GetWeakPtr()));
617
618  gcm_started_ = true;
619  return GCMClient::SUCCESS;
620}
621
622void GCMDriverDesktop::RemoveCachedData() {
623  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
624  // Remove all the queued tasks since they no longer make sense after
625  // GCM service is stopped.
626  weak_ptr_factory_.InvalidateWeakPtrs();
627
628  gcm_started_ = false;
629  gcm_client_ready_ = false;
630  delayed_task_controller_.reset();
631  ClearCallbacks();
632}
633
634void GCMDriverDesktop::MessageReceived(
635    const std::string& app_id,
636    const GCMClient::IncomingMessage& message) {
637  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
638
639  // Drop the event if the service has been stopped.
640  if (!gcm_started_)
641    return;
642
643  GetAppHandler(app_id)->OnMessage(app_id, message);
644}
645
646void GCMDriverDesktop::MessagesDeleted(const std::string& app_id) {
647  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
648
649  // Drop the event if the service has been stopped.
650  if (!gcm_started_)
651    return;
652
653  GetAppHandler(app_id)->OnMessagesDeleted(app_id);
654}
655
656void GCMDriverDesktop::MessageSendError(
657    const std::string& app_id,
658    const GCMClient::SendErrorDetails& send_error_details) {
659  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
660
661  // Drop the event if the service has been stopped.
662  if (!gcm_started_)
663    return;
664
665  GetAppHandler(app_id)->OnSendError(app_id, send_error_details);
666}
667
668void GCMDriverDesktop::GCMClientReady() {
669  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
670
671  if (gcm_client_ready_)
672    return;
673  gcm_client_ready_ = true;
674
675  delayed_task_controller_->SetReady();
676}
677
678void GCMDriverDesktop::OnConnected(const net::IPEndPoint& ip_endpoint) {
679  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
680
681  connected_ = true;
682
683  // Drop the event if signed out.
684  if (!signed_in_)
685    return;
686
687  const GCMAppHandlerMap& app_handler_map = app_handlers();
688  for (GCMAppHandlerMap::const_iterator iter = app_handler_map.begin();
689       iter != app_handler_map.end(); ++iter) {
690    iter->second->OnConnected(ip_endpoint);
691  }
692
693  GetAppHandler(kDefaultAppHandler)->OnConnected(ip_endpoint);
694}
695
696void GCMDriverDesktop::OnDisconnected() {
697  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
698
699  connected_ = false;
700
701  // Drop the event if signed out.
702  if (!signed_in_)
703    return;
704
705  const GCMAppHandlerMap& app_handler_map = app_handlers();
706  for (GCMAppHandlerMap::const_iterator iter = app_handler_map.begin();
707       iter != app_handler_map.end(); ++iter) {
708    iter->second->OnDisconnected();
709  }
710
711  GetAppHandler(kDefaultAppHandler)->OnDisconnected();
712}
713
714void GCMDriverDesktop::GetGCMStatisticsFinished(
715    const GCMClient::GCMStatistics& stats) {
716  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
717
718  // Normally request_gcm_statistics_callback_ would not be null.
719  if (!request_gcm_statistics_callback_.is_null())
720    request_gcm_statistics_callback_.Run(stats);
721  else
722    LOG(WARNING) << "request_gcm_statistics_callback_ is NULL.";
723}
724
725}  // namespace gcm
726
727