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