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