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