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