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