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