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