gcm_driver_desktop.cc revision 1675a649fd7a8b3cb80ffddae2dc181f122353c5
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    const std::string& channel_status_request_url,
338    const std::string& user_agent,
339    PrefService* prefs,
340    const base::FilePath& store_path,
341    const scoped_refptr<net::URLRequestContextGetter>& request_context,
342    const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
343    const scoped_refptr<base::SequencedTaskRunner>& io_thread,
344    const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
345    : gcm_channel_status_syncer_(
346          new GCMChannelStatusSyncer(this,
347                                     prefs,
348                                     channel_status_request_url,
349                                     user_agent,
350                                     request_context)),
351      signed_in_(false),
352      gcm_started_(false),
353      gcm_enabled_(true),
354      connected_(false),
355      ui_thread_(ui_thread),
356      io_thread_(io_thread),
357      weak_ptr_factory_(this) {
358  gcm_enabled_ = gcm_channel_status_syncer_->gcm_enabled();
359
360  // Create and initialize the GCMClient. Note that this does not initiate the
361  // GCM check-in.
362  io_worker_.reset(new IOWorker(ui_thread, io_thread));
363  io_thread_->PostTask(
364      FROM_HERE,
365      base::Bind(&GCMDriverDesktop::IOWorker::Initialize,
366                 base::Unretained(io_worker_.get()),
367                 base::Passed(&gcm_client_factory),
368                 chrome_build_info,
369                 store_path,
370                 request_context,
371                 blocking_task_runner));
372}
373
374GCMDriverDesktop::~GCMDriverDesktop() {
375}
376
377void GCMDriverDesktop::Shutdown() {
378  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
379  GCMDriver::Shutdown();
380
381  // Dispose the syncer in order to release the reference to
382  // URLRequestContextGetter that needs to be done before IOThread gets
383  // deleted.
384  gcm_channel_status_syncer_.reset();
385
386  io_thread_->DeleteSoon(FROM_HERE, io_worker_.release());
387}
388
389void GCMDriverDesktop::OnSignedIn() {
390  signed_in_ = true;
391  EnsureStarted();
392}
393
394void GCMDriverDesktop::OnSignedOut() {
395  signed_in_ = false;
396
397  // When sign-in enforcement is not dropped, we will stop the GCM connection
398  // when the user signs out.
399  if (!GCMDriver::IsAllowedForAllUsers())
400    Stop();
401}
402
403void GCMDriverDesktop::Purge() {
404  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
405
406  RemoveCachedData();
407
408  io_thread_->PostTask(FROM_HERE,
409                       base::Bind(&GCMDriverDesktop::IOWorker::CheckOut,
410                       base::Unretained(io_worker_.get())));
411}
412
413void GCMDriverDesktop::AddAppHandler(const std::string& app_id,
414                                     GCMAppHandler* handler) {
415  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
416  GCMDriver::AddAppHandler(app_id, handler);
417
418   // Ensures that the GCM service is started when there is an interest.
419  EnsureStarted();
420}
421
422void GCMDriverDesktop::RemoveAppHandler(const std::string& app_id) {
423  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
424  GCMDriver::RemoveAppHandler(app_id);
425
426  // Stops the GCM service when no app intends to consume it.
427  if (app_handlers().empty()) {
428    Stop();
429    gcm_channel_status_syncer_->Stop();
430  }
431}
432
433void GCMDriverDesktop::AddConnectionObserver(GCMConnectionObserver* observer) {
434  connection_observer_list_.AddObserver(observer);
435}
436
437void GCMDriverDesktop::RemoveConnectionObserver(
438    GCMConnectionObserver* observer) {
439  connection_observer_list_.RemoveObserver(observer);
440}
441
442void GCMDriverDesktop::Enable() {
443  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
444
445  if (gcm_enabled_)
446    return;
447  gcm_enabled_ = true;
448
449  EnsureStarted();
450}
451
452void GCMDriverDesktop::Disable() {
453  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
454
455  if (!gcm_enabled_)
456    return;
457  gcm_enabled_ = false;
458
459  Stop();
460}
461
462void GCMDriverDesktop::Stop() {
463  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
464
465  // No need to stop GCM service if not started yet.
466  if (!gcm_started_)
467    return;
468
469  RemoveCachedData();
470
471  io_thread_->PostTask(
472      FROM_HERE,
473      base::Bind(&GCMDriverDesktop::IOWorker::Stop,
474                 base::Unretained(io_worker_.get())));
475}
476
477void GCMDriverDesktop::RegisterImpl(
478    const std::string& app_id,
479    const std::vector<std::string>& sender_ids) {
480  // Delay the register operation until GCMClient is ready.
481  if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
482    delayed_task_controller_->AddTask(base::Bind(&GCMDriverDesktop::DoRegister,
483                                                 weak_ptr_factory_.GetWeakPtr(),
484                                                 app_id,
485                                                 sender_ids));
486    return;
487  }
488
489  DoRegister(app_id, sender_ids);
490}
491
492void GCMDriverDesktop::DoRegister(const std::string& app_id,
493                                  const std::vector<std::string>& sender_ids) {
494  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
495  if (!HasRegisterCallback(app_id)) {
496    // The callback could have been removed when the app is uninstalled.
497    return;
498  }
499
500  io_thread_->PostTask(
501      FROM_HERE,
502      base::Bind(&GCMDriverDesktop::IOWorker::Register,
503                 base::Unretained(io_worker_.get()),
504                 app_id,
505                 sender_ids));
506}
507
508void GCMDriverDesktop::UnregisterImpl(const std::string& app_id) {
509  // Delay the unregister operation until GCMClient is ready.
510  if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
511    delayed_task_controller_->AddTask(
512        base::Bind(&GCMDriverDesktop::DoUnregister,
513                   weak_ptr_factory_.GetWeakPtr(),
514                   app_id));
515    return;
516  }
517
518  DoUnregister(app_id);
519}
520
521void GCMDriverDesktop::DoUnregister(const std::string& app_id) {
522  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
523
524  // Ask the server to unregister it. There could be a small chance that the
525  // unregister request fails. If this occurs, it does not bring any harm since
526  // we simply reject the messages/events received from the server.
527  io_thread_->PostTask(
528      FROM_HERE,
529      base::Bind(&GCMDriverDesktop::IOWorker::Unregister,
530                 base::Unretained(io_worker_.get()),
531                 app_id));
532}
533
534void GCMDriverDesktop::SendImpl(const std::string& app_id,
535                                const std::string& receiver_id,
536                                const GCMClient::OutgoingMessage& message) {
537  // Delay the send operation until all GCMClient is ready.
538  if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
539    delayed_task_controller_->AddTask(base::Bind(&GCMDriverDesktop::DoSend,
540                                                 weak_ptr_factory_.GetWeakPtr(),
541                                                 app_id,
542                                                 receiver_id,
543                                                 message));
544    return;
545  }
546
547  DoSend(app_id, receiver_id, message);
548}
549
550void GCMDriverDesktop::DoSend(const std::string& app_id,
551                              const std::string& receiver_id,
552                              const GCMClient::OutgoingMessage& message) {
553  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
554  io_thread_->PostTask(
555      FROM_HERE,
556      base::Bind(&GCMDriverDesktop::IOWorker::Send,
557                 base::Unretained(io_worker_.get()),
558                 app_id,
559                 receiver_id,
560                 message));
561}
562
563GCMClient* GCMDriverDesktop::GetGCMClientForTesting() const {
564  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
565  return io_worker_ ? io_worker_->gcm_client_for_testing() : NULL;
566}
567
568bool GCMDriverDesktop::IsStarted() const {
569  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
570  return gcm_started_;
571}
572
573bool GCMDriverDesktop::IsConnected() const {
574  return connected_;
575}
576
577void GCMDriverDesktop::GetGCMStatistics(
578    const GetGCMStatisticsCallback& callback,
579    bool clear_logs) {
580  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
581  DCHECK(!callback.is_null());
582
583  request_gcm_statistics_callback_ = callback;
584  io_thread_->PostTask(
585      FROM_HERE,
586      base::Bind(&GCMDriverDesktop::IOWorker::GetGCMStatistics,
587                 base::Unretained(io_worker_.get()),
588                 clear_logs));
589}
590
591void GCMDriverDesktop::SetGCMRecording(const GetGCMStatisticsCallback& callback,
592                                       bool recording) {
593  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
594
595  request_gcm_statistics_callback_ = callback;
596  io_thread_->PostTask(
597      FROM_HERE,
598      base::Bind(&GCMDriverDesktop::IOWorker::SetGCMRecording,
599                 base::Unretained(io_worker_.get()),
600                 recording));
601}
602
603void GCMDriverDesktop::UpdateAccountMapping(
604    const AccountMapping& account_mapping) {
605  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
606
607  io_thread_->PostTask(
608      FROM_HERE,
609      base::Bind(&GCMDriverDesktop::IOWorker::UpdateAccountMapping,
610                 base::Unretained(io_worker_.get()),
611                 account_mapping));
612}
613
614void GCMDriverDesktop::RemoveAccountMapping(const std::string& account_id) {
615  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
616
617  io_thread_->PostTask(
618      FROM_HERE,
619      base::Bind(&GCMDriverDesktop::IOWorker::RemoveAccountMapping,
620                 base::Unretained(io_worker_.get()),
621                 account_id));
622}
623
624void GCMDriverDesktop::SetAccountsForCheckin(
625    const std::map<std::string, std::string>& account_tokens) {
626  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
627
628  io_thread_->PostTask(
629      FROM_HERE,
630      base::Bind(&GCMDriverDesktop::IOWorker::SetAccountsForCheckin,
631                 base::Unretained(io_worker_.get()),
632                 account_tokens));
633}
634
635GCMClient::Result GCMDriverDesktop::EnsureStarted() {
636  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
637
638  if (gcm_started_)
639    return GCMClient::SUCCESS;
640
641  if (!gcm_enabled_) {
642    // Poll for channel status in order to find out when it is re-enabled when
643    // GCM is currently disabled.
644    if (GCMDriver::IsAllowedForAllUsers())
645      gcm_channel_status_syncer_->EnsureStarted();
646
647    return GCMClient::GCM_DISABLED;
648  }
649
650  // Have any app requested the service?
651  if (app_handlers().empty())
652    return GCMClient::UNKNOWN_ERROR;
653
654  // TODO(jianli): To be removed when sign-in enforcement is dropped.
655  if (!signed_in_ && !GCMDriver::IsAllowedForAllUsers())
656    return GCMClient::NOT_SIGNED_IN;
657
658  DCHECK(!delayed_task_controller_);
659  delayed_task_controller_.reset(new GCMDelayedTaskController);
660
661  // Polling for channel status is only needed when GCM is supported for all
662  // users.
663  if (GCMDriver::IsAllowedForAllUsers())
664    gcm_channel_status_syncer_->EnsureStarted();
665
666  UMA_HISTOGRAM_BOOLEAN("GCM.UserSignedIn", signed_in_);
667
668  // Note that we need to pass weak pointer again since the existing weak
669  // pointer in IOWorker might have been invalidated when check-out occurs.
670  io_thread_->PostTask(
671      FROM_HERE,
672      base::Bind(&GCMDriverDesktop::IOWorker::Start,
673                 base::Unretained(io_worker_.get()),
674                 weak_ptr_factory_.GetWeakPtr()));
675
676  gcm_started_ = true;
677  return GCMClient::SUCCESS;
678}
679
680void GCMDriverDesktop::RemoveCachedData() {
681  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
682  // Remove all the queued tasks since they no longer make sense after
683  // GCM service is stopped.
684  weak_ptr_factory_.InvalidateWeakPtrs();
685
686  gcm_started_ = false;
687  delayed_task_controller_.reset();
688  ClearCallbacks();
689}
690
691void GCMDriverDesktop::MessageReceived(
692    const std::string& app_id,
693    const GCMClient::IncomingMessage& message) {
694  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
695
696  // Drop the event if the service has been stopped.
697  if (!gcm_started_)
698    return;
699
700  GetAppHandler(app_id)->OnMessage(app_id, message);
701}
702
703void GCMDriverDesktop::MessagesDeleted(const std::string& app_id) {
704  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
705
706  // Drop the event if the service has been stopped.
707  if (!gcm_started_)
708    return;
709
710  GetAppHandler(app_id)->OnMessagesDeleted(app_id);
711}
712
713void GCMDriverDesktop::MessageSendError(
714    const std::string& app_id,
715    const GCMClient::SendErrorDetails& send_error_details) {
716  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
717
718  // Drop the event if the service has been stopped.
719  if (!gcm_started_)
720    return;
721
722  GetAppHandler(app_id)->OnSendError(app_id, send_error_details);
723}
724
725void GCMDriverDesktop::SendAcknowledged(const std::string& app_id,
726                                        const std::string& message_id) {
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)->OnSendAcknowledged(app_id, message_id);
734}
735
736void GCMDriverDesktop::GCMClientReady(
737    const std::vector<AccountMapping>& account_mappings) {
738  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
739
740  delayed_task_controller_->SetReady();
741}
742
743void GCMDriverDesktop::OnConnected(const net::IPEndPoint& ip_endpoint) {
744  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
745
746  connected_ = true;
747
748  // Drop the event if the service has been stopped.
749  if (!gcm_started_)
750    return;
751
752  FOR_EACH_OBSERVER(GCMConnectionObserver,
753                    connection_observer_list_,
754                    OnConnected(ip_endpoint));
755}
756
757void GCMDriverDesktop::OnDisconnected() {
758  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
759
760  connected_ = false;
761
762  // Drop the event if the service has been stopped.
763  if (!gcm_started_)
764    return;
765
766  FOR_EACH_OBSERVER(
767      GCMConnectionObserver, connection_observer_list_, OnDisconnected());
768}
769
770void GCMDriverDesktop::GetGCMStatisticsFinished(
771    const GCMClient::GCMStatistics& stats) {
772  DCHECK(ui_thread_->RunsTasksOnCurrentThread());
773
774  // Normally request_gcm_statistics_callback_ would not be null.
775  if (!request_gcm_statistics_callback_.is_null())
776    request_gcm_statistics_callback_.Run(stats);
777  else
778    LOG(WARNING) << "request_gcm_statistics_callback_ is NULL.";
779}
780
781}  // namespace gcm
782
783