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

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

Issue 330733002: Move IdentityProvider usage from GCMDriverDesktop to GCMProfileService (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Patch Created 6 years, 6 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_driver/gcm_driver_desktop.h" 5 #include "components/gcm_driver/gcm_driver_desktop.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/bind_helpers.h" 10 #include "base/bind_helpers.h"
11 #include "base/files/file_path.h" 11 #include "base/files/file_path.h"
12 #include "base/location.h" 12 #include "base/location.h"
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/sequenced_task_runner.h" 14 #include "base/sequenced_task_runner.h"
15 #include "base/threading/sequenced_worker_pool.h" 15 #include "base/threading/sequenced_worker_pool.h"
16 #include "components/gcm_driver/gcm_app_handler.h" 16 #include "components/gcm_driver/gcm_app_handler.h"
17 #include "components/gcm_driver/gcm_client_factory.h" 17 #include "components/gcm_driver/gcm_client_factory.h"
18 #include "components/gcm_driver/system_encryptor.h" 18 #include "components/gcm_driver/system_encryptor.h"
19 #include "google_apis/gaia/oauth2_token_service.h" 19 #include "google_apis/gaia/oauth2_token_service.h"
bartfab (slow) 2014/06/13 11:27:21 Nit: No longer used.
jianli 2014/06/13 18:04:49 Done.
20 #include "net/url_request/url_request_context_getter.h" 20 #include "net/url_request/url_request_context_getter.h"
21 21
22 namespace gcm { 22 namespace gcm {
23 23
24 // Helper class to save tasks to run until we're ready to execute them. 24 // Helper class to save tasks to run until we're ready to execute them.
25 class GCMDriverDesktop::DelayedTaskController { 25 class GCMDriverDesktop::DelayedTaskController {
26 public: 26 public:
27 DelayedTaskController(); 27 DelayedTaskController();
28 ~DelayedTaskController(); 28 ~DelayedTaskController();
29 29
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 const std::string& app_id, 102 const std::string& app_id,
103 const GCMClient::SendErrorDetails& send_error_details) OVERRIDE; 103 const GCMClient::SendErrorDetails& send_error_details) OVERRIDE;
104 virtual void OnGCMReady() OVERRIDE; 104 virtual void OnGCMReady() OVERRIDE;
105 virtual void OnActivityRecorded() OVERRIDE; 105 virtual void OnActivityRecorded() OVERRIDE;
106 106
107 // Called on IO thread. 107 // Called on IO thread.
108 void Initialize( 108 void Initialize(
109 scoped_ptr<GCMClientFactory> gcm_client_factory, 109 scoped_ptr<GCMClientFactory> gcm_client_factory,
110 const GCMClient::ChromeBuildInfo& chrome_build_info, 110 const GCMClient::ChromeBuildInfo& chrome_build_info,
111 const base::FilePath& store_path, 111 const base::FilePath& store_path,
112 const std::vector<std::string>& account_ids,
113 const scoped_refptr<net::URLRequestContextGetter>& request_context, 112 const scoped_refptr<net::URLRequestContextGetter>& request_context,
114 const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner); 113 const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
115 void Start(const base::WeakPtr<GCMDriverDesktop>& service); 114 void Start(const base::WeakPtr<GCMDriverDesktop>& service);
116 void Stop(); 115 void Stop();
117 void CheckOut(); 116 void CheckOut();
118 void Register(const std::string& app_id, 117 void Register(const std::string& app_id,
119 const std::vector<std::string>& sender_ids); 118 const std::vector<std::string>& sender_ids);
120 void Unregister(const std::string& app_id); 119 void Unregister(const std::string& app_id);
121 void Send(const std::string& app_id, 120 void Send(const std::string& app_id,
122 const std::string& receiver_id, 121 const std::string& receiver_id,
(...skipping 24 matching lines...) Expand all
147 } 146 }
148 147
149 GCMDriverDesktop::IOWorker::~IOWorker() { 148 GCMDriverDesktop::IOWorker::~IOWorker() {
150 DCHECK(io_thread_->RunsTasksOnCurrentThread()); 149 DCHECK(io_thread_->RunsTasksOnCurrentThread());
151 } 150 }
152 151
153 void GCMDriverDesktop::IOWorker::Initialize( 152 void GCMDriverDesktop::IOWorker::Initialize(
154 scoped_ptr<GCMClientFactory> gcm_client_factory, 153 scoped_ptr<GCMClientFactory> gcm_client_factory,
155 const GCMClient::ChromeBuildInfo& chrome_build_info, 154 const GCMClient::ChromeBuildInfo& chrome_build_info,
156 const base::FilePath& store_path, 155 const base::FilePath& store_path,
157 const std::vector<std::string>& account_ids,
158 const scoped_refptr<net::URLRequestContextGetter>& request_context, 156 const scoped_refptr<net::URLRequestContextGetter>& request_context,
159 const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) { 157 const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) {
160 DCHECK(io_thread_->RunsTasksOnCurrentThread()); 158 DCHECK(io_thread_->RunsTasksOnCurrentThread());
161 159
162 gcm_client_ = gcm_client_factory->BuildInstance(); 160 gcm_client_ = gcm_client_factory->BuildInstance();
163 161
164 gcm_client_->Initialize(chrome_build_info, 162 gcm_client_->Initialize(chrome_build_info,
165 store_path, 163 store_path,
166 account_ids,
167 blocking_task_runner, 164 blocking_task_runner,
168 request_context, 165 request_context,
169 make_scoped_ptr<Encryptor>(new SystemEncryptor), 166 make_scoped_ptr<Encryptor>(new SystemEncryptor),
170 this); 167 this);
171 } 168 }
172 169
173 void GCMDriverDesktop::IOWorker::OnRegisterFinished( 170 void GCMDriverDesktop::IOWorker::OnRegisterFinished(
174 const std::string& app_id, 171 const std::string& app_id,
175 const std::string& registration_id, 172 const std::string& registration_id,
176 GCMClient::Result result) { 173 GCMClient::Result result) {
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 stats.gcm_client_created = true; 318 stats.gcm_client_created = true;
322 } 319 }
323 320
324 ui_thread_->PostTask( 321 ui_thread_->PostTask(
325 FROM_HERE, 322 FROM_HERE,
326 base::Bind(&GCMDriverDesktop::GetGCMStatisticsFinished, service_, stats)); 323 base::Bind(&GCMDriverDesktop::GetGCMStatisticsFinished, service_, stats));
327 } 324 }
328 325
329 GCMDriverDesktop::GCMDriverDesktop( 326 GCMDriverDesktop::GCMDriverDesktop(
330 scoped_ptr<GCMClientFactory> gcm_client_factory, 327 scoped_ptr<GCMClientFactory> gcm_client_factory,
331 scoped_ptr<IdentityProvider> identity_provider,
332 const GCMClient::ChromeBuildInfo& chrome_build_info, 328 const GCMClient::ChromeBuildInfo& chrome_build_info,
333 const base::FilePath& store_path, 329 const base::FilePath& store_path,
334 const scoped_refptr<net::URLRequestContextGetter>& request_context, 330 const scoped_refptr<net::URLRequestContextGetter>& request_context,
335 const scoped_refptr<base::SequencedTaskRunner>& ui_thread, 331 const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
336 const scoped_refptr<base::SequencedTaskRunner>& io_thread, 332 const scoped_refptr<base::SequencedTaskRunner>& io_thread,
337 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner) 333 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
338 : gcm_enabled_(true), 334 : signed_in_(false),
335 gcm_started_(false),
336 gcm_enabled_(true),
339 gcm_client_ready_(false), 337 gcm_client_ready_(false),
340 identity_provider_(identity_provider.Pass()),
341 ui_thread_(ui_thread), 338 ui_thread_(ui_thread),
342 io_thread_(io_thread), 339 io_thread_(io_thread),
343 weak_ptr_factory_(this) { 340 weak_ptr_factory_(this) {
344 // Get the list of available accounts.
345 std::vector<std::string> account_ids;
346 account_ids = identity_provider_->GetTokenService()->GetAccounts();
347
348 // Create and initialize the GCMClient. Note that this does not initiate the 341 // Create and initialize the GCMClient. Note that this does not initiate the
349 // GCM check-in. 342 // GCM check-in.
350 io_worker_.reset(new IOWorker(ui_thread, io_thread)); 343 io_worker_.reset(new IOWorker(ui_thread, io_thread));
351 io_thread_->PostTask( 344 io_thread_->PostTask(
352 FROM_HERE, 345 FROM_HERE,
353 base::Bind(&GCMDriverDesktop::IOWorker::Initialize, 346 base::Bind(&GCMDriverDesktop::IOWorker::Initialize,
354 base::Unretained(io_worker_.get()), 347 base::Unretained(io_worker_.get()),
355 base::Passed(&gcm_client_factory), 348 base::Passed(&gcm_client_factory),
356 chrome_build_info, 349 chrome_build_info,
357 store_path, 350 store_path,
358 account_ids,
359 request_context, 351 request_context,
360 blocking_task_runner)); 352 blocking_task_runner));
361
362 identity_provider_->AddObserver(this);
363 } 353 }
364 354
365 GCMDriverDesktop::~GCMDriverDesktop() { 355 GCMDriverDesktop::~GCMDriverDesktop() {
366 } 356 }
367 357
368 void GCMDriverDesktop::OnActiveAccountLogin() {
369 EnsureStarted();
370 }
371
372 void GCMDriverDesktop::OnActiveAccountLogout() {
373 CheckOut();
374 }
375
376 void GCMDriverDesktop::Shutdown() { 358 void GCMDriverDesktop::Shutdown() {
377 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 359 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
378 identity_provider_->RemoveObserver(this);
379 GCMDriver::Shutdown(); 360 GCMDriver::Shutdown();
380 io_thread_->DeleteSoon(FROM_HERE, io_worker_.release()); 361 io_thread_->DeleteSoon(FROM_HERE, io_worker_.release());
381 } 362 }
382 363
364 void GCMDriverDesktop::SignIn() {
365 signed_in_ = true;
366 EnsureStarted();
367 }
368
369 void GCMDriverDesktop::Purge() {
370 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
371
372 // We still proceed with the check-out logic even if the check-in is not
373 // initiated in the current session. This will make sure that all the
374 // persisted data written previously will get purged.
375
bartfab (slow) 2014/06/13 11:27:21 Nit: No need for a blank line here.
jianli 2014/06/13 18:04:49 Done.
376 signed_in_ = false;
377 RemoveCachedData();
378
379 io_thread_->PostTask(
380 FROM_HERE,
bartfab (slow) 2014/06/13 11:27:21 Nit: Indent two more spaces or, even better, break
jianli 2014/06/13 18:04:49 Done. Caused by new version of VS that did the aut
381 base::Bind(&GCMDriverDesktop::IOWorker::CheckOut,
382 base::Unretained(io_worker_.get())));
383 }
384
383 void GCMDriverDesktop::AddAppHandler(const std::string& app_id, 385 void GCMDriverDesktop::AddAppHandler(const std::string& app_id,
384 GCMAppHandler* handler) { 386 GCMAppHandler* handler) {
385 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 387 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
386 GCMDriver::AddAppHandler(app_id, handler); 388 GCMDriver::AddAppHandler(app_id, handler);
387 389
388 // Ensures that the GCM service is started when there is an interest. 390 // Ensures that the GCM service is started when there is an interest.
389 EnsureStarted(); 391 EnsureStarted();
390 } 392 }
391 393
392 void GCMDriverDesktop::RemoveAppHandler(const std::string& app_id) { 394 void GCMDriverDesktop::RemoveAppHandler(const std::string& app_id) {
(...skipping 22 matching lines...) Expand all
415 return; 417 return;
416 gcm_enabled_ = false; 418 gcm_enabled_ = false;
417 419
418 Stop(); 420 Stop();
419 } 421 }
420 422
421 void GCMDriverDesktop::Stop() { 423 void GCMDriverDesktop::Stop() {
422 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 424 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
423 425
424 // No need to stop GCM service if not started yet. 426 // No need to stop GCM service if not started yet.
425 if (account_id_.empty()) 427 if (!gcm_started_)
426 return; 428 return;
427 429
428 RemoveCachedData(); 430 RemoveCachedData();
429 431
430 io_thread_->PostTask( 432 io_thread_->PostTask(
431 FROM_HERE, 433 FROM_HERE,
432 base::Bind(&GCMDriverDesktop::IOWorker::Stop, 434 base::Bind(&GCMDriverDesktop::IOWorker::Stop,
433 base::Unretained(io_worker_.get()))); 435 base::Unretained(io_worker_.get())));
434 } 436 }
435 437
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 message)); 521 message));
520 } 522 }
521 523
522 GCMClient* GCMDriverDesktop::GetGCMClientForTesting() const { 524 GCMClient* GCMDriverDesktop::GetGCMClientForTesting() const {
523 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 525 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
524 return io_worker_ ? io_worker_->gcm_client_for_testing() : NULL; 526 return io_worker_ ? io_worker_->gcm_client_for_testing() : NULL;
525 } 527 }
526 528
527 bool GCMDriverDesktop::IsStarted() const { 529 bool GCMDriverDesktop::IsStarted() const {
528 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 530 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
529 return !account_id_.empty(); 531 return gcm_started_;
530 } 532 }
531 533
532 bool GCMDriverDesktop::IsGCMClientReady() const { 534 bool GCMDriverDesktop::IsGCMClientReady() const {
533 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 535 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
534 return gcm_client_ready_; 536 return gcm_client_ready_;
535 } 537 }
536 538
537 void GCMDriverDesktop::GetGCMStatistics( 539 void GCMDriverDesktop::GetGCMStatistics(
538 const GetGCMStatisticsCallback& callback, 540 const GetGCMStatisticsCallback& callback,
539 bool clear_logs) { 541 bool clear_logs) {
(...skipping 16 matching lines...) Expand all
556 io_thread_->PostTask( 558 io_thread_->PostTask(
557 FROM_HERE, 559 FROM_HERE,
558 base::Bind(&GCMDriverDesktop::IOWorker::SetGCMRecording, 560 base::Bind(&GCMDriverDesktop::IOWorker::SetGCMRecording,
559 base::Unretained(io_worker_.get()), 561 base::Unretained(io_worker_.get()),
560 recording)); 562 recording));
561 } 563 }
562 564
563 GCMClient::Result GCMDriverDesktop::EnsureStarted() { 565 GCMClient::Result GCMDriverDesktop::EnsureStarted() {
564 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 566 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
565 567
568 if (gcm_started_)
569 return GCMClient::SUCCESS;
570
566 if (!gcm_enabled_) 571 if (!gcm_enabled_)
567 return GCMClient::GCM_DISABLED; 572 return GCMClient::GCM_DISABLED;
568 573
569 // Have any app requested the service? 574 // Have any app requested the service?
570 if (app_handlers().empty()) 575 if (app_handlers().empty())
571 return GCMClient::UNKNOWN_ERROR; 576 return GCMClient::UNKNOWN_ERROR;
572 577
573 // Is the user signed in? 578 // TODO(jianli): to be removed when sign-in enforcement is dropped.
574 const std::string account_id = identity_provider_->GetActiveAccountId(); 579 if (!signed_in_)
575 if (account_id.empty())
576 return GCMClient::NOT_SIGNED_IN; 580 return GCMClient::NOT_SIGNED_IN;
577 581
578 // CheckIn could be called more than once when:
579 // 1) The password changes.
580 // 2) Register/send function calls it to ensure CheckIn is done.
581 if (account_id_ == account_id)
582 return GCMClient::SUCCESS;
583 account_id_ = account_id;
584
585 DCHECK(!delayed_task_controller_);
bartfab (slow) 2014/06/13 11:27:21 Why did you remove this DCHECK?
jianli 2014/06/13 18:04:49 This is accidentally removed. Thanks for noticing
586 delayed_task_controller_.reset(new DelayedTaskController); 582 delayed_task_controller_.reset(new DelayedTaskController);
587 583
588 // Note that we need to pass weak pointer again since the existing weak 584 // Note that we need to pass weak pointer again since the existing weak
589 // pointer in IOWorker might have been invalidated when check-out occurs. 585 // pointer in IOWorker might have been invalidated when check-out occurs.
590 io_thread_->PostTask( 586 io_thread_->PostTask(
591 FROM_HERE, 587 FROM_HERE,
592 base::Bind(&GCMDriverDesktop::IOWorker::Start, 588 base::Bind(&GCMDriverDesktop::IOWorker::Start,
593 base::Unretained(io_worker_.get()), 589 base::Unretained(io_worker_.get()),
594 weak_ptr_factory_.GetWeakPtr())); 590 weak_ptr_factory_.GetWeakPtr()));
595 591
592 gcm_started_ = true;
596 return GCMClient::SUCCESS; 593 return GCMClient::SUCCESS;
597 } 594 }
598 595
599 void GCMDriverDesktop::RemoveCachedData() { 596 void GCMDriverDesktop::RemoveCachedData() {
600 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 597 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
601 // Remove all the queued tasks since they no longer make sense after 598 // Remove all the queued tasks since they no longer make sense after
602 // GCM service is stopped. 599 // GCM service is stopped.
603 weak_ptr_factory_.InvalidateWeakPtrs(); 600 weak_ptr_factory_.InvalidateWeakPtrs();
604 601
605 account_id_.clear(); 602 gcm_started_ = false;
606 gcm_client_ready_ = false; 603 gcm_client_ready_ = false;
607 delayed_task_controller_.reset(); 604 delayed_task_controller_.reset();
608 ClearCallbacks(); 605 ClearCallbacks();
609 } 606 }
610 607
611 void GCMDriverDesktop::CheckOut() {
612 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
613
614 // We still proceed with the check-out logic even if the check-in is not
615 // initiated in the current session. This will make sure that all the
616 // persisted data written previously will get purged.
617
618 RemoveCachedData();
619
620 io_thread_->PostTask(
621 FROM_HERE,
622 base::Bind(&GCMDriverDesktop::IOWorker::CheckOut,
623 base::Unretained(io_worker_.get())));
624 }
625
626 void GCMDriverDesktop::MessageReceived( 608 void GCMDriverDesktop::MessageReceived(
627 const std::string& app_id, 609 const std::string& app_id,
628 const GCMClient::IncomingMessage& message) { 610 const GCMClient::IncomingMessage& message) {
629 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 611 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
630 612
631 // Drop the event if signed out. 613 // Drop the event if the service has been stopped.
632 if (account_id_.empty()) 614 if (!gcm_started_)
633 return; 615 return;
634 616
635 GetAppHandler(app_id)->OnMessage(app_id, message); 617 GetAppHandler(app_id)->OnMessage(app_id, message);
636 } 618 }
637 619
638 void GCMDriverDesktop::MessagesDeleted(const std::string& app_id) { 620 void GCMDriverDesktop::MessagesDeleted(const std::string& app_id) {
639 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 621 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
640 622
641 // Drop the event if signed out. 623 // Drop the event if the service has been stopped.
642 if (account_id_.empty()) 624 if (!gcm_started_)
643 return; 625 return;
644 626
645 GetAppHandler(app_id)->OnMessagesDeleted(app_id); 627 GetAppHandler(app_id)->OnMessagesDeleted(app_id);
646 } 628 }
647 629
648 void GCMDriverDesktop::MessageSendError( 630 void GCMDriverDesktop::MessageSendError(
649 const std::string& app_id, 631 const std::string& app_id,
650 const GCMClient::SendErrorDetails& send_error_details) { 632 const GCMClient::SendErrorDetails& send_error_details) {
651 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 633 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
652 634
653 // Drop the event if signed out. 635 // Drop the event if the service has been stopped.
654 if (account_id_.empty()) 636 if (!gcm_started_)
655 return; 637 return;
656 638
657 GetAppHandler(app_id)->OnSendError(app_id, send_error_details); 639 GetAppHandler(app_id)->OnSendError(app_id, send_error_details);
658 } 640 }
659 641
660 void GCMDriverDesktop::GCMClientReady() { 642 void GCMDriverDesktop::GCMClientReady() {
661 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 643 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
662 644
663 if (gcm_client_ready_) 645 if (gcm_client_ready_)
664 return; 646 return;
665 gcm_client_ready_ = true; 647 gcm_client_ready_ = true;
666 648
667 delayed_task_controller_->SetReady(); 649 delayed_task_controller_->SetReady();
668 } 650 }
669 651
670 void GCMDriverDesktop::GetGCMStatisticsFinished( 652 void GCMDriverDesktop::GetGCMStatisticsFinished(
671 const GCMClient::GCMStatistics& stats) { 653 const GCMClient::GCMStatistics& stats) {
672 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 654 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
673 655
674 // Normally request_gcm_statistics_callback_ would not be null. 656 // Normally request_gcm_statistics_callback_ would not be null.
675 if (!request_gcm_statistics_callback_.is_null()) 657 if (!request_gcm_statistics_callback_.is_null())
676 request_gcm_statistics_callback_.Run(stats); 658 request_gcm_statistics_callback_.Run(stats);
677 else 659 else
678 LOG(WARNING) << "request_gcm_statistics_callback_ is NULL."; 660 LOG(WARNING) << "request_gcm_statistics_callback_ is NULL.";
679 } 661 }
680 662
681 std::string GCMDriverDesktop::SignedInUserName() const {
682 if (IsStarted())
683 return identity_provider_->GetActiveUsername();
684 return std::string();
685 }
686
687 } // namespace gcm 663 } // namespace gcm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698