Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(417)

Side by Side Diff: components/gcm/gcm_driver.cc

Issue 278493002: Split GCMDriver into platform-specific implementations (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/gcm/gcm_driver.h" 5 #include "components/gcm/gcm_driver.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/bind_helpers.h" 11 #include "base/bind_helpers.h"
12 #include "base/files/file_path.h" 12 #include "base/files/file_path.h"
13 #include "base/location.h" 13 #include "base/location.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/message_loop/message_loop_proxy.h" 15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/sequenced_task_runner.h" 16 #include "base/sequenced_task_runner.h"
17 #include "base/threading/sequenced_worker_pool.h" 17 #include "base/threading/sequenced_worker_pool.h"
18 #include "components/gcm/gcm_app_handler.h" 18 #include "components/gcm/gcm_app_handler.h"
19 #include "components/gcm/gcm_client_factory.h" 19 #include "components/gcm/gcm_client_factory.h"
20 #include "google_apis/gaia/oauth2_token_service.h" 20 #include "google_apis/gaia/oauth2_token_service.h"
21 #include "google_apis/gcm/protocol/android_checkin.pb.h" 21 #include "google_apis/gcm/protocol/android_checkin.pb.h"
22 #include "net/url_request/url_request_context_getter.h" 22 #include "net/url_request/url_request_context_getter.h"
23 23
24 namespace gcm { 24 namespace gcm {
25 25
26 // Helper class to save tasks to run until we're ready to execute them. 26 GCMDriver::GCMDriver(const scoped_refptr<base::MessageLoopProxy>& ui_thread)
27 class GCMDriver::DelayedTaskController { 27 : ui_thread_(ui_thread) {
28 public:
29 DelayedTaskController();
30 ~DelayedTaskController();
31
32 // Adds a task that will be invoked once we're ready.
33 void AddTask(const base::Closure& task);
34
35 // Sets ready status. It is ready only when check-in is completed and
36 // the GCMClient is fully initialized.
37 void SetReady();
38
39 // Returns true if it is ready to perform tasks.
40 bool CanRunTaskWithoutDelay() const;
41
42 private:
43 void RunTasks();
44
45 // Flag that indicates that GCM is ready.
46 bool ready_;
47
48 std::vector<base::Closure> delayed_tasks_;
49
50 DISALLOW_COPY_AND_ASSIGN(DelayedTaskController);
51 };
52
53 GCMDriver::DelayedTaskController::DelayedTaskController() : ready_(false) {
54 } 28 }
55 29
56 GCMDriver::DelayedTaskController::~DelayedTaskController() { 30 GCMDriver::GCMDriver() {
57 }
58
59 void GCMDriver::DelayedTaskController::AddTask(const base::Closure& task) {
60 delayed_tasks_.push_back(task);
61 }
62
63 void GCMDriver::DelayedTaskController::SetReady() {
64 ready_ = true;
65 RunTasks();
66 }
67
68 bool GCMDriver::DelayedTaskController::CanRunTaskWithoutDelay() const {
69 return ready_;
70 }
71
72 void GCMDriver::DelayedTaskController::RunTasks() {
73 DCHECK(ready_);
74
75 for (size_t i = 0; i < delayed_tasks_.size(); ++i)
76 delayed_tasks_[i].Run();
77 delayed_tasks_.clear();
78 }
79
80 class GCMDriver::IOWorker : public GCMClient::Delegate {
81 public:
82 // Called on UI thread.
83 IOWorker(const scoped_refptr<base::MessageLoopProxy>& ui_thread,
84 const scoped_refptr<base::MessageLoopProxy>& io_thread);
85 virtual ~IOWorker();
86
87 // Overridden from GCMClient::Delegate:
88 // Called on IO thread.
89 virtual void OnRegisterFinished(const std::string& app_id,
90 const std::string& registration_id,
91 GCMClient::Result result) OVERRIDE;
92 virtual void OnUnregisterFinished(const std::string& app_id,
93 GCMClient::Result result) OVERRIDE;
94 virtual void OnSendFinished(const std::string& app_id,
95 const std::string& message_id,
96 GCMClient::Result result) OVERRIDE;
97 virtual void OnMessageReceived(
98 const std::string& app_id,
99 const GCMClient::IncomingMessage& message) OVERRIDE;
100 virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE;
101 virtual void OnMessageSendError(
102 const std::string& app_id,
103 const GCMClient::SendErrorDetails& send_error_details) OVERRIDE;
104 virtual void OnGCMReady() OVERRIDE;
105
106 // Called on IO thread.
107 void Initialize(
108 const checkin_proto::ChromeBuildProto& chrome_build_proto,
109 scoped_ptr<GCMClientFactory> gcm_client_factory,
110 const base::FilePath& store_path,
111 const std::vector<std::string>& account_ids,
112 const scoped_refptr<net::URLRequestContextGetter>& request_context,
113 const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
114 void Start(const base::WeakPtr<GCMDriver>& service);
115 void Stop();
116 void CheckOut();
117 void Register(const std::string& app_id,
118 const std::vector<std::string>& sender_ids);
119 void Unregister(const std::string& app_id);
120 void Send(const std::string& app_id,
121 const std::string& receiver_id,
122 const GCMClient::OutgoingMessage& message);
123 void GetGCMStatistics(bool clear_logs);
124 void SetGCMRecording(bool recording);
125
126 // For testing purpose. Can be called from UI thread. Use with care.
127 GCMClient* gcm_client_for_testing() const { return gcm_client_.get(); }
128
129 private:
130 scoped_refptr<base::MessageLoopProxy> ui_thread_;
131 scoped_refptr<base::MessageLoopProxy> io_thread_;
132
133 base::WeakPtr<GCMDriver> service_;
134
135 scoped_ptr<GCMClient> gcm_client_;
136
137 DISALLOW_COPY_AND_ASSIGN(IOWorker);
138 };
139
140 GCMDriver::IOWorker::IOWorker(
141 const scoped_refptr<base::MessageLoopProxy>& ui_thread,
142 const scoped_refptr<base::MessageLoopProxy>& io_thread)
143 : ui_thread_(ui_thread),
144 io_thread_(io_thread) {
145 DCHECK(ui_thread_->BelongsToCurrentThread());
146 }
147
148 GCMDriver::IOWorker::~IOWorker() {
149 DCHECK(io_thread_->BelongsToCurrentThread());
150 }
151
152 void GCMDriver::IOWorker::Initialize(
153 const checkin_proto::ChromeBuildProto& chrome_build_proto,
154 scoped_ptr<GCMClientFactory> gcm_client_factory,
155 const base::FilePath& store_path,
156 const std::vector<std::string>& account_ids,
157 const scoped_refptr<net::URLRequestContextGetter>& request_context,
158 const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) {
159 DCHECK(io_thread_->BelongsToCurrentThread());
160
161 gcm_client_ = gcm_client_factory->BuildInstance().Pass();
162
163 gcm_client_->Initialize(chrome_build_proto,
164 store_path,
165 account_ids,
166 blocking_task_runner,
167 request_context,
168 this);
169 }
170
171 void GCMDriver::IOWorker::OnRegisterFinished(
172 const std::string& app_id,
173 const std::string& registration_id,
174 GCMClient::Result result) {
175 DCHECK(io_thread_->BelongsToCurrentThread());
176
177 ui_thread_->PostTask(
178 FROM_HERE,
179 base::Bind(&GCMDriver::RegisterFinished, service_, app_id,
180 registration_id, result));
181 }
182
183 void GCMDriver::IOWorker::OnUnregisterFinished(const std::string& app_id,
184 GCMClient::Result result) {
185 DCHECK(io_thread_->BelongsToCurrentThread());
186
187 ui_thread_->PostTask(
188 FROM_HERE,
189 base::Bind(&GCMDriver::UnregisterFinished, service_, app_id, result));
190 }
191
192 void GCMDriver::IOWorker::OnSendFinished(const std::string& app_id,
193 const std::string& message_id,
194 GCMClient::Result result) {
195 DCHECK(io_thread_->BelongsToCurrentThread());
196
197 ui_thread_->PostTask(
198 FROM_HERE,
199 base::Bind(&GCMDriver::SendFinished, service_, app_id, message_id,
200 result));
201 }
202
203 void GCMDriver::IOWorker::OnMessageReceived(
204 const std::string& app_id,
205 const GCMClient::IncomingMessage& message) {
206 DCHECK(io_thread_->BelongsToCurrentThread());
207
208 ui_thread_->PostTask(
209 FROM_HERE,
210 base::Bind(&GCMDriver::MessageReceived, service_, app_id, message));
211 }
212
213 void GCMDriver::IOWorker::OnMessagesDeleted(const std::string& app_id) {
214 DCHECK(io_thread_->BelongsToCurrentThread());
215
216 ui_thread_->PostTask(
217 FROM_HERE,
218 base::Bind(&GCMDriver::MessagesDeleted, service_, app_id));
219 }
220
221 void GCMDriver::IOWorker::OnMessageSendError(
222 const std::string& app_id,
223 const GCMClient::SendErrorDetails& send_error_details) {
224 DCHECK(io_thread_->BelongsToCurrentThread());
225
226 ui_thread_->PostTask(
227 FROM_HERE,
228 base::Bind(&GCMDriver::MessageSendError, service_, app_id,
229 send_error_details));
230 }
231
232 void GCMDriver::IOWorker::OnGCMReady() {
233 ui_thread_->PostTask(
234 FROM_HERE,
235 base::Bind(&GCMDriver::GCMClientReady, service_));
236 }
237
238 void GCMDriver::IOWorker::Start(const base::WeakPtr<GCMDriver>& service) {
239 DCHECK(io_thread_->BelongsToCurrentThread());
240
241 service_ = service;
242 gcm_client_->Start();
243 }
244
245 void GCMDriver::IOWorker::Stop() {
246 DCHECK(io_thread_->BelongsToCurrentThread());
247
248 gcm_client_->Stop();
249 }
250
251 void GCMDriver::IOWorker::CheckOut() {
252 DCHECK(io_thread_->BelongsToCurrentThread());
253
254 gcm_client_->CheckOut();
255
256 // Note that we still need to keep GCMClient instance alive since the
257 // GCMDriver may check in again.
258 }
259
260 void GCMDriver::IOWorker::Register(
261 const std::string& app_id,
262 const std::vector<std::string>& sender_ids) {
263 DCHECK(io_thread_->BelongsToCurrentThread());
264
265 gcm_client_->Register(app_id, sender_ids);
266 }
267
268 void GCMDriver::IOWorker::Unregister(const std::string& app_id) {
269 DCHECK(io_thread_->BelongsToCurrentThread());
270
271 gcm_client_->Unregister(app_id);
272 }
273
274 void GCMDriver::IOWorker::Send(const std::string& app_id,
275 const std::string& receiver_id,
276 const GCMClient::OutgoingMessage& message) {
277 DCHECK(io_thread_->BelongsToCurrentThread());
278
279 gcm_client_->Send(app_id, receiver_id, message);
280 }
281
282 void GCMDriver::IOWorker::GetGCMStatistics(bool clear_logs) {
283 DCHECK(io_thread_->BelongsToCurrentThread());
284 gcm::GCMClient::GCMStatistics stats;
285
286 if (gcm_client_.get()) {
287 if (clear_logs)
288 gcm_client_->ClearActivityLogs();
289 stats = gcm_client_->GetStatistics();
290 }
291
292 ui_thread_->PostTask(
293 FROM_HERE,
294 base::Bind(&GCMDriver::GetGCMStatisticsFinished, service_, stats));
295 }
296
297 void GCMDriver::IOWorker::SetGCMRecording(bool recording) {
298 DCHECK(io_thread_->BelongsToCurrentThread());
299 gcm::GCMClient::GCMStatistics stats;
300
301 if (gcm_client_.get()) {
302 gcm_client_->SetRecording(recording);
303 stats = gcm_client_->GetStatistics();
304 stats.gcm_client_created = true;
305 }
306
307 ui_thread_->PostTask(
308 FROM_HERE,
309 base::Bind(&GCMDriver::GetGCMStatisticsFinished, service_, stats));
310 }
311
312 GCMDriver::GCMDriver(
313 const checkin_proto::ChromeBuildProto& chrome_build_proto,
314 scoped_ptr<GCMClientFactory> gcm_client_factory,
315 scoped_ptr<IdentityProvider> identity_provider,
316 const base::FilePath& store_path,
317 const scoped_refptr<net::URLRequestContextGetter>& request_context,
318 const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
319 const scoped_refptr<base::MessageLoopProxy>& ui_thread,
320 const scoped_refptr<base::MessageLoopProxy>& io_thread)
321 : identity_provider_(identity_provider.Pass()),
322 ui_thread_(ui_thread),
323 io_thread_(io_thread),
324 gcm_enabled_(true),
325 gcm_client_ready_(false),
326 weak_ptr_factory_(this) {
327 // Get the list of available accounts.
328 std::vector<std::string> account_ids;
329 #if !defined(OS_ANDROID)
330 account_ids = identity_provider_->GetTokenService()->GetAccounts();
331 #endif
332
333 // Create and initialize the GCMClient. Note that this does not initiate the
334 // GCM check-in.
335 DCHECK(!io_worker_);
336 io_worker_.reset(new IOWorker(ui_thread, io_thread));
337 io_thread_->PostTask(
338 FROM_HERE,
339 base::Bind(&GCMDriver::IOWorker::Initialize,
340 base::Unretained(io_worker_.get()),
341 chrome_build_proto,
342 base::Passed(&gcm_client_factory),
343 store_path,
344 account_ids,
345 request_context,
346 blocking_task_runner));
347
348 identity_provider_->AddObserver(this);
349 }
350
351 GCMDriver::GCMDriver()
352 : gcm_enabled_(true),
353 gcm_client_ready_(false),
354 weak_ptr_factory_(this) {
355 } 31 }
356 32
357 GCMDriver::~GCMDriver() { 33 GCMDriver::~GCMDriver() {
358 } 34 }
359 35
360 void GCMDriver::Enable() {
361 DCHECK(ui_thread_->BelongsToCurrentThread());
362
363 if (gcm_enabled_)
364 return;
365 gcm_enabled_ = true;
366
367 EnsureStarted();
368 }
369
370 void GCMDriver::Disable() {
371 DCHECK(ui_thread_->BelongsToCurrentThread());
372
373 if (!gcm_enabled_)
374 return;
375 gcm_enabled_ = false;
376
377 Stop();
378 }
379
380 void GCMDriver::Shutdown() { 36 void GCMDriver::Shutdown() {
381 DCHECK(ui_thread_->BelongsToCurrentThread()); 37 DCHECK(ui_thread_->BelongsToCurrentThread());
382 identity_provider_->RemoveObserver(this);
383 for (GCMAppHandlerMap::const_iterator iter = app_handlers_.begin(); 38 for (GCMAppHandlerMap::const_iterator iter = app_handlers_.begin();
384 iter != app_handlers_.end(); ++iter) { 39 iter != app_handlers_.end(); ++iter) {
385 iter->second->ShutdownHandler(); 40 iter->second->ShutdownHandler();
386 } 41 }
387 app_handlers_.clear(); 42 app_handlers_.clear();
388 io_thread_->DeleteSoon(FROM_HERE, io_worker_.release());
389 } 43 }
390 44
391 void GCMDriver::AddAppHandler(const std::string& app_id, 45 void GCMDriver::AddAppHandler(const std::string& app_id,
392 GCMAppHandler* handler) { 46 GCMAppHandler* handler) {
393 DCHECK(ui_thread_->BelongsToCurrentThread()); 47 DCHECK(ui_thread_->BelongsToCurrentThread());
394 DCHECK(!app_id.empty()); 48 DCHECK(!app_id.empty());
395 DCHECK(handler); 49 DCHECK(handler);
396 50
397 app_handlers_[app_id] = handler; 51 app_handlers_[app_id] = handler;
398
399 // Ensures that the GCM service is started when there is an interest.
400 EnsureStarted();
401 } 52 }
402 53
403 void GCMDriver::RemoveAppHandler(const std::string& app_id) { 54 void GCMDriver::RemoveAppHandler(const std::string& app_id) {
404 DCHECK(ui_thread_->BelongsToCurrentThread()); 55 DCHECK(ui_thread_->BelongsToCurrentThread());
405 DCHECK(!app_id.empty()); 56 DCHECK(!app_id.empty());
406 57
407 app_handlers_.erase(app_id); 58 app_handlers_.erase(app_id);
408
409 // Stops the GCM service when no app intends to consume it.
410 if (app_handlers_.empty())
411 Stop();
412 }
413
414 void GCMDriver::Register(const std::string& app_id,
415 const std::vector<std::string>& sender_ids,
416 const RegisterCallback& callback) {
417 DCHECK(ui_thread_->BelongsToCurrentThread());
418 DCHECK(!app_id.empty());
419 DCHECK(!sender_ids.empty());
420 DCHECK(!callback.is_null());
421
422 GCMClient::Result result = EnsureStarted();
423 if (result != GCMClient::SUCCESS) {
424 callback.Run(std::string(), result);
425 return;
426 }
427
428 // If previous un/register operation is still in progress, bail out.
429 if (IsAsyncOperationPending(app_id)) {
430 callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING);
431 return;
432 }
433
434 register_callbacks_[app_id] = callback;
435
436 // Delay the register operation until GCMClient is ready.
437 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
438 delayed_task_controller_->AddTask(base::Bind(&GCMDriver::DoRegister,
439 weak_ptr_factory_.GetWeakPtr(),
440 app_id,
441 sender_ids));
442 return;
443 }
444
445 DoRegister(app_id, sender_ids);
446 }
447
448 void GCMDriver::DoRegister(const std::string& app_id,
449 const std::vector<std::string>& sender_ids) {
450 DCHECK(ui_thread_->BelongsToCurrentThread());
451 std::map<std::string, RegisterCallback>::iterator callback_iter =
452 register_callbacks_.find(app_id);
453 if (callback_iter == register_callbacks_.end()) {
454 // The callback could have been removed when the app is uninstalled.
455 return;
456 }
457
458 // Normalize the sender IDs by making them sorted.
459 std::vector<std::string> normalized_sender_ids = sender_ids;
460 std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end());
461
462 io_thread_->PostTask(
463 FROM_HERE,
464 base::Bind(&GCMDriver::IOWorker::Register,
465 base::Unretained(io_worker_.get()),
466 app_id,
467 normalized_sender_ids));
468 }
469
470 void GCMDriver::Unregister(const std::string& app_id,
471 const UnregisterCallback& callback) {
472 DCHECK(ui_thread_->BelongsToCurrentThread());
473 DCHECK(!app_id.empty());
474 DCHECK(!callback.is_null());
475
476 GCMClient::Result result = EnsureStarted();
477 if (result != GCMClient::SUCCESS) {
478 callback.Run(result);
479 return;
480 }
481
482 // If previous un/register operation is still in progress, bail out.
483 if (IsAsyncOperationPending(app_id)) {
484 callback.Run(GCMClient::ASYNC_OPERATION_PENDING);
485 return;
486 }
487
488 unregister_callbacks_[app_id] = callback;
489
490 // Delay the unregister operation until GCMClient is ready.
491 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
492 delayed_task_controller_->AddTask(base::Bind(&GCMDriver::DoUnregister,
493 weak_ptr_factory_.GetWeakPtr(),
494 app_id));
495 return;
496 }
497
498 DoUnregister(app_id);
499 }
500
501 void GCMDriver::DoUnregister(const std::string& app_id) {
502 DCHECK(ui_thread_->BelongsToCurrentThread());
503
504 // Ask the server to unregister it. There could be a small chance that the
505 // unregister request fails. If this occurs, it does not bring any harm since
506 // we simply reject the messages/events received from the server.
507 io_thread_->PostTask(
508 FROM_HERE,
509 base::Bind(&GCMDriver::IOWorker::Unregister,
510 base::Unretained(io_worker_.get()),
511 app_id));
512 }
513
514 void GCMDriver::Send(const std::string& app_id,
515 const std::string& receiver_id,
516 const GCMClient::OutgoingMessage& message,
517 const SendCallback& callback) {
518 DCHECK(ui_thread_->BelongsToCurrentThread());
519 DCHECK(!app_id.empty());
520 DCHECK(!receiver_id.empty());
521 DCHECK(!callback.is_null());
522
523 GCMClient::Result result = EnsureStarted();
524 if (result != GCMClient::SUCCESS) {
525 callback.Run(std::string(), result);
526 return;
527 }
528
529 // If the message with send ID is still in progress, bail out.
530 std::pair<std::string, std::string> key(app_id, message.id);
531 if (send_callbacks_.find(key) != send_callbacks_.end()) {
532 callback.Run(message.id, GCMClient::INVALID_PARAMETER);
533 return;
534 }
535
536 send_callbacks_[key] = callback;
537
538 // Delay the send operation until all GCMClient is ready.
539 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
540 delayed_task_controller_->AddTask(base::Bind(&GCMDriver::DoSend,
541 weak_ptr_factory_.GetWeakPtr(),
542 app_id,
543 receiver_id,
544 message));
545 return;
546 }
547
548 DoSend(app_id, receiver_id, message);
549 }
550
551 void GCMDriver::DoSend(const std::string& app_id,
552 const std::string& receiver_id,
553 const GCMClient::OutgoingMessage& message) {
554 DCHECK(ui_thread_->BelongsToCurrentThread());
555 io_thread_->PostTask(
556 FROM_HERE,
557 base::Bind(&GCMDriver::IOWorker::Send,
558 base::Unretained(io_worker_.get()),
559 app_id,
560 receiver_id,
561 message));
562 }
563
564 GCMClient* GCMDriver::GetGCMClientForTesting() const {
565 DCHECK(ui_thread_->BelongsToCurrentThread());
566 return io_worker_ ? io_worker_->gcm_client_for_testing() : NULL;
567 }
568
569 bool GCMDriver::IsStarted() const {
570 DCHECK(ui_thread_->BelongsToCurrentThread());
571 return !account_id_.empty();
572 }
573
574 bool GCMDriver::IsGCMClientReady() const {
575 DCHECK(ui_thread_->BelongsToCurrentThread());
576 return gcm_client_ready_;
577 }
578
579 void GCMDriver::GetGCMStatistics(GetGCMStatisticsCallback callback,
580 bool clear_logs) {
581 DCHECK(ui_thread_->BelongsToCurrentThread());
582 DCHECK(!callback.is_null());
583
584 request_gcm_statistics_callback_ = callback;
585 io_thread_->PostTask(
586 FROM_HERE,
587 base::Bind(&GCMDriver::IOWorker::GetGCMStatistics,
588 base::Unretained(io_worker_.get()),
589 clear_logs));
590 }
591
592 void GCMDriver::SetGCMRecording(GetGCMStatisticsCallback callback,
593 bool recording) {
594 DCHECK(ui_thread_->BelongsToCurrentThread());
595
596 request_gcm_statistics_callback_ = callback;
597 io_thread_->PostTask(
598 FROM_HERE,
599 base::Bind(&GCMDriver::IOWorker::SetGCMRecording,
600 base::Unretained(io_worker_.get()),
601 recording));
602 }
603
604 void GCMDriver::OnActiveAccountLogin() {
605 EnsureStarted();
606 }
607
608 void GCMDriver::OnActiveAccountLogout() {
609 CheckOut();
610 }
611
612 GCMClient::Result GCMDriver::EnsureStarted() {
613 DCHECK(ui_thread_->BelongsToCurrentThread());
614
615 // Is GCM enabled?
616 if (!gcm_enabled_)
617 return GCMClient::GCM_DISABLED;
618
619 // Has any app requested the service?
620 if (app_handlers_.empty())
621 return GCMClient::UNKNOWN_ERROR;
622
623 // Can we get an account ID from the identity provider?
624 const std::string account_id = identity_provider_->GetActiveAccountId();
625 if (account_id.empty())
626 return GCMClient::NOT_SIGNED_IN;
627
628 // CheckIn could be called more than once when:
629 // 1) The password changes.
630 // 2) Register/send function calls it to ensure CheckIn is done.
631 if (account_id_ == account_id)
632 return GCMClient::SUCCESS;
633 account_id_ = account_id;
634
635 DCHECK(!delayed_task_controller_);
636 delayed_task_controller_.reset(new DelayedTaskController);
637
638 // This will load the data from the gcm store and trigger the check-in if
639 // the persisted check-in info is not found.
640 // Note that we need to pass weak pointer again since the existing weak
641 // pointer in IOWorker might have been invalidated when check-out occurs.
642 io_thread_->PostTask(
643 FROM_HERE,
644 base::Bind(&GCMDriver::IOWorker::Start,
645 base::Unretained(io_worker_.get()),
646 weak_ptr_factory_.GetWeakPtr()));
647
648 return GCMClient::SUCCESS;
649 }
650
651 void GCMDriver::Stop() {
652 // No need to stop GCM service if not started yet.
653 if (account_id_.empty())
654 return;
655
656 RemoveCachedData();
657
658 io_thread_->PostTask(
659 FROM_HERE,
660 base::Bind(&GCMDriver::IOWorker::Stop,
661 base::Unretained(io_worker_.get())));
662 }
663
664 void GCMDriver::RemoveCachedData() {
665 DCHECK(ui_thread_->BelongsToCurrentThread());
666 // Remove all the queued tasks since they no longer make sense after
667 // GCM service is stopped.
668 weak_ptr_factory_.InvalidateWeakPtrs();
669
670 account_id_.clear();
671 gcm_client_ready_ = false;
672 delayed_task_controller_.reset();
673 register_callbacks_.clear();
674 send_callbacks_.clear();
675 }
676
677 void GCMDriver::CheckOut() {
678 DCHECK(ui_thread_->BelongsToCurrentThread());
679
680 // We still proceed with the check-out logic even if the check-in is not
681 // initiated in the current session. This will make sure that all the
682 // persisted data written previously will get purged.
683
684 RemoveCachedData();
685
686 io_thread_->PostTask(
687 FROM_HERE,
688 base::Bind(&GCMDriver::IOWorker::CheckOut,
689 base::Unretained(io_worker_.get())));
690 }
691
692 bool GCMDriver::IsAsyncOperationPending(const std::string& app_id) const {
693 DCHECK(ui_thread_->BelongsToCurrentThread());
694 return register_callbacks_.find(app_id) != register_callbacks_.end() ||
695 unregister_callbacks_.find(app_id) != unregister_callbacks_.end();
696 }
697
698 void GCMDriver::RegisterFinished(const std::string& app_id,
699 const std::string& registration_id,
700 GCMClient::Result result) {
701 DCHECK(ui_thread_->BelongsToCurrentThread());
702
703 std::map<std::string, RegisterCallback>::iterator callback_iter =
704 register_callbacks_.find(app_id);
705 if (callback_iter == register_callbacks_.end()) {
706 // The callback could have been removed when the app is uninstalled.
707 return;
708 }
709
710 RegisterCallback callback = callback_iter->second;
711 register_callbacks_.erase(callback_iter);
712 callback.Run(registration_id, result);
713 }
714
715 void GCMDriver::UnregisterFinished(const std::string& app_id,
716 GCMClient::Result result) {
717 DCHECK(ui_thread_->BelongsToCurrentThread());
718
719 std::map<std::string, UnregisterCallback>::iterator callback_iter =
720 unregister_callbacks_.find(app_id);
721 if (callback_iter == unregister_callbacks_.end())
722 return;
723
724 UnregisterCallback callback = callback_iter->second;
725 unregister_callbacks_.erase(callback_iter);
726 callback.Run(result);
727 }
728
729 void GCMDriver::SendFinished(const std::string& app_id,
730 const std::string& message_id,
731 GCMClient::Result result) {
732 DCHECK(ui_thread_->BelongsToCurrentThread());
733
734 std::map<std::pair<std::string, std::string>, SendCallback>::iterator
735 callback_iter = send_callbacks_.find(
736 std::pair<std::string, std::string>(app_id, message_id));
737 if (callback_iter == send_callbacks_.end()) {
738 // The callback could have been removed when the app is uninstalled.
739 return;
740 }
741
742 SendCallback callback = callback_iter->second;
743 send_callbacks_.erase(callback_iter);
744 callback.Run(message_id, result);
745 }
746
747 void GCMDriver::MessageReceived(const std::string& app_id,
748 GCMClient::IncomingMessage message) {
749 DCHECK(ui_thread_->BelongsToCurrentThread());
750
751 // Drop the event if signed out.
752 if (account_id_.empty())
753 return;
754
755 GetAppHandler(app_id)->OnMessage(app_id, message);
756 }
757
758 void GCMDriver::MessagesDeleted(const std::string& app_id) {
759 DCHECK(ui_thread_->BelongsToCurrentThread());
760
761 // Drop the event if signed out.
762 if (account_id_.empty())
763 return;
764
765 GetAppHandler(app_id)->OnMessagesDeleted(app_id);
766 }
767
768 void GCMDriver::MessageSendError(
769 const std::string& app_id,
770 const GCMClient::SendErrorDetails& send_error_details) {
771 DCHECK(ui_thread_->BelongsToCurrentThread());
772
773 // Drop the event if signed out.
774 if (account_id_.empty())
775 return;
776
777 GetAppHandler(app_id)->OnSendError(app_id, send_error_details);
778 }
779
780 void GCMDriver::GCMClientReady() {
781 DCHECK(ui_thread_->BelongsToCurrentThread());
782
783 if (gcm_client_ready_)
784 return;
785 gcm_client_ready_ = true;
786
787 delayed_task_controller_->SetReady();
788 }
789
790 GCMAppHandler* GCMDriver::GetAppHandler(const std::string& app_id) {
791 DCHECK(ui_thread_->BelongsToCurrentThread());
792
793 std::map<std::string, GCMAppHandler*>::const_iterator iter =
794 app_handlers_.find(app_id);
795 return iter == app_handlers_.end() ? &default_app_handler_ : iter->second;
796 }
797
798 void GCMDriver::GetGCMStatisticsFinished(GCMClient::GCMStatistics stats) {
799 DCHECK(ui_thread_->BelongsToCurrentThread());
800 request_gcm_statistics_callback_.Run(stats);
801 }
802
803 std::string GCMDriver::SignedInUserName() const {
804 if (IsStarted())
805 return identity_provider_->GetActiveUsername();
806 return std::string();
807 } 59 }
808 60
809 } // namespace gcm 61 } // namespace gcm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698