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

Side by Side Diff: chrome/browser/services/gcm/gcm_profile_service.cc

Issue 207443002: [GCM] Move registration info persistence from extension state store to GCM store (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Patch to land Created 6 years, 9 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 (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 "chrome/browser/services/gcm/gcm_profile_service.h" 5 #include "chrome/browser/services/gcm/gcm_profile_service.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/base64.h" 11 #include "base/base64.h"
12 #include "base/files/file_path.h" 12 #include "base/files/file_path.h"
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/path_service.h" 14 #include "base/path_service.h"
15 #include "base/prefs/pref_service.h" 15 #include "base/prefs/pref_service.h"
16 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/string_number_conversions.h"
17 #include "base/threading/sequenced_worker_pool.h" 17 #include "base/threading/sequenced_worker_pool.h"
18 #include "chrome/browser/chrome_notification_types.h" 18 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/extensions/state_store.h"
20 #include "chrome/browser/services/gcm/gcm_app_handler.h" 19 #include "chrome/browser/services/gcm/gcm_app_handler.h"
21 #include "chrome/browser/services/gcm/gcm_client_factory.h" 20 #include "chrome/browser/services/gcm/gcm_client_factory.h"
22 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 21 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
23 #include "chrome/browser/signin/signin_manager.h" 22 #include "chrome/browser/signin/signin_manager.h"
24 #include "chrome/browser/signin/signin_manager_factory.h" 23 #include "chrome/browser/signin/signin_manager_factory.h"
25 #include "chrome/common/chrome_constants.h" 24 #include "chrome/common/chrome_constants.h"
26 #include "chrome/common/chrome_paths.h" 25 #include "chrome/common/chrome_paths.h"
27 #include "chrome/common/chrome_version_info.h" 26 #include "chrome/common/chrome_version_info.h"
28 #include "chrome/common/pref_names.h" 27 #include "chrome/common/pref_names.h"
29 #include "components/signin/core/profile_oauth2_token_service.h" 28 #include "components/signin/core/profile_oauth2_token_service.h"
30 #include "components/user_prefs/pref_registry_syncable.h" 29 #include "components/user_prefs/pref_registry_syncable.h"
31 #include "content/public/browser/browser_thread.h" 30 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/notification_details.h" 31 #include "content/public/browser/notification_details.h"
33 #include "content/public/browser/notification_source.h" 32 #include "content/public/browser/notification_source.h"
34 #include "extensions/browser/extension_system.h"
35 #include "google_apis/gcm/protocol/android_checkin.pb.h" 33 #include "google_apis/gcm/protocol/android_checkin.pb.h"
36 #include "net/url_request/url_request_context_getter.h" 34 #include "net/url_request/url_request_context_getter.h"
37 35
38 namespace gcm { 36 namespace gcm {
39 37
40 namespace { 38 namespace {
41 39
42 const char kRegistrationKey[] = "gcm.registration";
43 const char kSendersKey[] = "senders";
44 const char kRegistrationIDKey[] = "reg_id";
45
46 checkin_proto::ChromeBuildProto_Platform GetPlatform() { 40 checkin_proto::ChromeBuildProto_Platform GetPlatform() {
47 #if defined(OS_WIN) 41 #if defined(OS_WIN)
48 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_WIN; 42 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_WIN;
49 #elif defined(OS_MACOSX) 43 #elif defined(OS_MACOSX)
50 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_MAC; 44 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_MAC;
51 #elif defined(OS_CHROMEOS) 45 #elif defined(OS_CHROMEOS)
52 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_CROS; 46 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_CROS;
53 #elif defined(OS_LINUX) 47 #elif defined(OS_LINUX)
54 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_LINUX; 48 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_LINUX;
55 #else 49 #else
(...skipping 27 matching lines...) Expand all
83 } 77 }
84 78
85 } // namespace 79 } // namespace
86 80
87 // Helper class to save tasks to run until we're ready to execute them. 81 // Helper class to save tasks to run until we're ready to execute them.
88 class GCMProfileService::DelayedTaskController { 82 class GCMProfileService::DelayedTaskController {
89 public: 83 public:
90 DelayedTaskController(); 84 DelayedTaskController();
91 ~DelayedTaskController(); 85 ~DelayedTaskController();
92 86
93 // Adds an app to the tracking list. It will be first marked as not ready. 87 // Adds a task that will be invoked once we're ready.
94 // Tasks will be queued for delay execution until the app is marked as ready. 88 void AddTask(base::Closure task);
95 void AddApp(const std::string& app_id);
96 89
97 // Removes the app from the tracking list. 90 // Sets ready status. It is ready only when check-in is completed and
98 void RemoveApp(const std::string& app_id); 91 // the GCMClient is fully initialized.
92 void SetReady();
99 93
100 // Adds a task that will be invoked once we're ready. 94 // Returns true if it is ready to perform tasks.
101 void AddTask(const std::string& app_id, base::Closure task); 95 bool CanRunTaskWithoutDelay() const;
102
103 // Sets GCM ready status. GCM is ready only when check-in is completed and
104 // the GCMClient is fully initialized. If it is set to ready for the first
105 // time, all the pending tasks for any ready apps will be run.
106 void SetGCMReady();
107
108 // Sets ready status for the app. If GCM is already ready, all the pending
109 // tasks for this app will be run.
110 void SetAppReady(const std::string& app_id);
111
112 // Returns true if it is ready to perform operations for an app.
113 bool CanRunTaskWithoutDelay(const std::string& app_id) const;
114
115 // Returns true if the app has been tracked for readiness.
116 bool IsAppTracked(const std::string& app_id) const;
117 96
118 private: 97 private:
119 struct AppTaskQueue { 98 void RunTasks();
120 AppTaskQueue();
121 ~AppTaskQueue();
122 99
123 // The flag that indicates if GCMClient is ready. 100 // Flag that indicates that GCM is ready.
124 bool ready; 101 bool ready_;
125 102
126 // Tasks to be invoked upon ready. 103 std::vector<base::Closure> delayed_tasks_;
127 std::vector<base::Closure> tasks;
128 };
129
130 void RunTasks(AppTaskQueue* task_queue);
131
132 // Flag that indicates that GCM is done.
133 bool gcm_ready_;
134
135 // Map from app_id to AppTaskQueue storing the tasks that will be invoked
136 // when both GCM and the app get ready.
137 typedef std::map<std::string, AppTaskQueue*> DelayedTaskMap;
138 DelayedTaskMap delayed_task_map_;
139 }; 104 };
140 105
141 GCMProfileService::DelayedTaskController::AppTaskQueue::AppTaskQueue()
142 : ready(false) {
143 }
144
145 GCMProfileService::DelayedTaskController::AppTaskQueue::~AppTaskQueue() {
146 }
147
148 GCMProfileService::DelayedTaskController::DelayedTaskController() 106 GCMProfileService::DelayedTaskController::DelayedTaskController()
149 : gcm_ready_(false) { 107 : ready_(false) {
150 } 108 }
151 109
152 GCMProfileService::DelayedTaskController::~DelayedTaskController() { 110 GCMProfileService::DelayedTaskController::~DelayedTaskController() {
153 for (DelayedTaskMap::const_iterator iter = delayed_task_map_.begin();
154 iter != delayed_task_map_.end(); ++iter) {
155 delete iter->second;
156 }
157 } 111 }
158 112
159 void GCMProfileService::DelayedTaskController::AddApp( 113 void GCMProfileService::DelayedTaskController::AddTask(base::Closure task) {
160 const std::string& app_id) { 114 delayed_tasks_.push_back(task);
161 DCHECK(delayed_task_map_.find(app_id) == delayed_task_map_.end());
162 delayed_task_map_[app_id] = new AppTaskQueue;
163 } 115 }
164 116
165 void GCMProfileService::DelayedTaskController::RemoveApp( 117 void GCMProfileService::DelayedTaskController::SetReady() {
166 const std::string& app_id) { 118 ready_ = true;
167 DelayedTaskMap::iterator iter = delayed_task_map_.find(app_id); 119 RunTasks();
168 if (iter == delayed_task_map_.end())
169 return;
170 delete iter->second;
171 delayed_task_map_.erase(iter);
172 } 120 }
173 121
174 void GCMProfileService::DelayedTaskController::AddTask( 122 bool GCMProfileService::DelayedTaskController::CanRunTaskWithoutDelay() const {
175 const std::string& app_id, base::Closure task) { 123 return ready_;
176 DelayedTaskMap::const_iterator iter = delayed_task_map_.find(app_id);
177 DCHECK(iter != delayed_task_map_.end());
178 iter->second->tasks.push_back(task);
179 } 124 }
180 125
181 void GCMProfileService::DelayedTaskController::SetGCMReady() { 126 void GCMProfileService::DelayedTaskController::RunTasks() {
182 gcm_ready_ = true; 127 DCHECK(ready_);
183 128
184 for (DelayedTaskMap::iterator iter = delayed_task_map_.begin(); 129 for (size_t i = 0; i < delayed_tasks_.size(); ++i)
185 iter != delayed_task_map_.end(); ++iter) { 130 delayed_tasks_[i].Run();
186 if (iter->second->ready) 131 delayed_tasks_.clear();
187 RunTasks(iter->second);
188 }
189 }
190
191 void GCMProfileService::DelayedTaskController::SetAppReady(
192 const std::string& app_id) {
193 DelayedTaskMap::iterator iter = delayed_task_map_.find(app_id);
194 DCHECK(iter != delayed_task_map_.end());
195
196 AppTaskQueue* task_queue = iter->second;
197 DCHECK(task_queue);
198 task_queue->ready = true;
199
200 if (gcm_ready_)
201 RunTasks(task_queue);
202 }
203
204 bool GCMProfileService::DelayedTaskController::CanRunTaskWithoutDelay(
205 const std::string& app_id) const {
206 if (!gcm_ready_)
207 return false;
208 DelayedTaskMap::const_iterator iter = delayed_task_map_.find(app_id);
209 if (iter == delayed_task_map_.end())
210 return true;
211 return iter->second->ready;
212 }
213
214 bool GCMProfileService::DelayedTaskController::IsAppTracked(
215 const std::string& app_id) const {
216 return delayed_task_map_.find(app_id) != delayed_task_map_.end();
217 }
218
219 void GCMProfileService::DelayedTaskController::RunTasks(
220 AppTaskQueue* task_queue) {
221 DCHECK(gcm_ready_ && task_queue->ready);
222
223 for (size_t i = 0; i < task_queue->tasks.size(); ++i)
224 task_queue->tasks[i].Run();
225 task_queue->tasks.clear();
226 } 132 }
227 133
228 class GCMProfileService::IOWorker 134 class GCMProfileService::IOWorker
229 : public GCMClient::Delegate, 135 : public GCMClient::Delegate,
230 public base::RefCountedThreadSafe<GCMProfileService::IOWorker>{ 136 public base::RefCountedThreadSafe<GCMProfileService::IOWorker>{
231 public: 137 public:
232 // Called on UI thread. 138 // Called on UI thread.
233 IOWorker(); 139 IOWorker();
234 140
235 // Overridden from GCMClient::Delegate: 141 // Overridden from GCMClient::Delegate:
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after
487 case GCMProfileService::ENABLED_FOR_APPS: 393 case GCMProfileService::ENABLED_FOR_APPS:
488 return "ENABLED_FOR_APPS"; 394 return "ENABLED_FOR_APPS";
489 case GCMProfileService::ALWAYS_DISABLED: 395 case GCMProfileService::ALWAYS_DISABLED:
490 return "ALWAYS_DISABLED"; 396 return "ALWAYS_DISABLED";
491 default: 397 default:
492 NOTREACHED(); 398 NOTREACHED();
493 return std::string(); 399 return std::string();
494 } 400 }
495 } 401 }
496 402
497 GCMProfileService::RegistrationInfo::RegistrationInfo() {
498 }
499
500 GCMProfileService::RegistrationInfo::~RegistrationInfo() {
501 }
502
503 bool GCMProfileService::RegistrationInfo::IsValid() const {
504 return !sender_ids.empty() && !registration_id.empty();
505 }
506
507 // static 403 // static
508 GCMProfileService::GCMEnabledState GCMProfileService::GetGCMEnabledState( 404 GCMProfileService::GCMEnabledState GCMProfileService::GetGCMEnabledState(
509 Profile* profile) { 405 Profile* profile) {
510 const base::Value* gcm_enabled_value = 406 const base::Value* gcm_enabled_value =
511 profile->GetPrefs()->GetUserPrefValue(prefs::kGCMChannelEnabled); 407 profile->GetPrefs()->GetUserPrefValue(prefs::kGCMChannelEnabled);
512 if (!gcm_enabled_value) 408 if (!gcm_enabled_value)
513 return ENABLED_FOR_APPS; 409 return ENABLED_FOR_APPS;
514 410
515 bool gcm_enabled = false; 411 bool gcm_enabled = false;
516 if (!gcm_enabled_value->GetAsBoolean(&gcm_enabled)) 412 if (!gcm_enabled_value->GetAsBoolean(&gcm_enabled))
(...skipping 10 matching lines...) Expand all
527 bool on_by_default = false; 423 bool on_by_default = false;
528 if (channel == chrome::VersionInfo::CHANNEL_UNKNOWN || 424 if (channel == chrome::VersionInfo::CHANNEL_UNKNOWN ||
529 channel == chrome::VersionInfo::CHANNEL_CANARY || 425 channel == chrome::VersionInfo::CHANNEL_CANARY ||
530 channel == chrome::VersionInfo::CHANNEL_DEV) { 426 channel == chrome::VersionInfo::CHANNEL_DEV) {
531 on_by_default = true; 427 on_by_default = true;
532 } 428 }
533 registry->RegisterBooleanPref( 429 registry->RegisterBooleanPref(
534 prefs::kGCMChannelEnabled, 430 prefs::kGCMChannelEnabled,
535 on_by_default, 431 on_by_default,
536 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 432 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
537 registry->RegisterListPref(
538 prefs::kGCMRegisteredAppIDs,
539 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
540 } 433 }
541 434
542 GCMProfileService::GCMProfileService(Profile* profile) 435 GCMProfileService::GCMProfileService(Profile* profile)
543 : profile_(profile), 436 : profile_(profile),
544 gcm_client_ready_(false), 437 gcm_client_ready_(false),
545 weak_ptr_factory_(this) { 438 weak_ptr_factory_(this) {
546 DCHECK(!profile->IsOffTheRecord()); 439 DCHECK(!profile->IsOffTheRecord());
547 } 440 }
548 441
549 GCMProfileService::~GCMProfileService() { 442 GCMProfileService::~GCMProfileService() {
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 538
646 // If previous un/register operation is still in progress, bail out. 539 // If previous un/register operation is still in progress, bail out.
647 if (IsAsyncOperationPending(app_id)) { 540 if (IsAsyncOperationPending(app_id)) {
648 callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING); 541 callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING);
649 return; 542 return;
650 } 543 }
651 544
652 register_callbacks_[app_id] = callback; 545 register_callbacks_[app_id] = callback;
653 546
654 // Delay the register operation until GCMClient is ready. 547 // Delay the register operation until GCMClient is ready.
655 if (!delayed_task_controller_->CanRunTaskWithoutDelay(app_id)) { 548 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
656 delayed_task_controller_->AddTask( 549 delayed_task_controller_->AddTask(
657 app_id,
658 base::Bind(&GCMProfileService::DoRegister, 550 base::Bind(&GCMProfileService::DoRegister,
659 weak_ptr_factory_.GetWeakPtr(), 551 weak_ptr_factory_.GetWeakPtr(),
660 app_id, 552 app_id,
661 sender_ids)); 553 sender_ids));
662 return; 554 return;
663 } 555 }
664 556
665 DoRegister(app_id, sender_ids); 557 DoRegister(app_id, sender_ids);
666 } 558 }
667 559
668 void GCMProfileService::DoRegister(const std::string& app_id, 560 void GCMProfileService::DoRegister(const std::string& app_id,
669 const std::vector<std::string>& sender_ids) { 561 const std::vector<std::string>& sender_ids) {
670 std::map<std::string, RegisterCallback>::iterator callback_iter = 562 std::map<std::string, RegisterCallback>::iterator callback_iter =
671 register_callbacks_.find(app_id); 563 register_callbacks_.find(app_id);
672 if (callback_iter == register_callbacks_.end()) { 564 if (callback_iter == register_callbacks_.end()) {
673 // The callback could have been removed when the app is uninstalled. 565 // The callback could have been removed when the app is uninstalled.
674 return; 566 return;
675 } 567 }
676 568
677 // Normalize the sender IDs by making them sorted. 569 // Normalize the sender IDs by making them sorted.
678 std::vector<std::string> normalized_sender_ids = sender_ids; 570 std::vector<std::string> normalized_sender_ids = sender_ids;
679 std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end()); 571 std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end());
680 572
681 // If the same sender ids is provided, return the cached registration ID
682 // directly.
683 RegistrationInfoMap::const_iterator registration_info_iter =
684 registration_info_map_.find(app_id);
685 if (registration_info_iter != registration_info_map_.end() &&
686 registration_info_iter->second.sender_ids == normalized_sender_ids) {
687 RegisterCallback callback = callback_iter->second;
688 register_callbacks_.erase(callback_iter);
689 callback.Run(registration_info_iter->second.registration_id,
690 GCMClient::SUCCESS);
691 return;
692 }
693
694 // Cache the sender IDs. The registration ID will be filled when the
695 // registration completes.
696 RegistrationInfo registration_info;
697 registration_info.sender_ids = normalized_sender_ids;
698 registration_info_map_[app_id] = registration_info;
699
700 // Save the IDs of all registered apps such that we know what to remove from
701 // the the app's state store when the profile is signed out.
702 WriteRegisteredAppIDs();
703
704 content::BrowserThread::PostTask( 573 content::BrowserThread::PostTask(
705 content::BrowserThread::IO, 574 content::BrowserThread::IO,
706 FROM_HERE, 575 FROM_HERE,
707 base::Bind(&GCMProfileService::IOWorker::Register, 576 base::Bind(&GCMProfileService::IOWorker::Register,
708 io_worker_, 577 io_worker_,
709 app_id, 578 app_id,
710 normalized_sender_ids)); 579 normalized_sender_ids));
711 } 580 }
712 581
713 void GCMProfileService::Unregister(const std::string& app_id, 582 void GCMProfileService::Unregister(const std::string& app_id,
714 UnregisterCallback callback) { 583 UnregisterCallback callback) {
715 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 584 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
716 DCHECK(!app_id.empty() && !callback.is_null()); 585 DCHECK(!app_id.empty() && !callback.is_null());
717 586
718 GCMClient::Result result = EnsureAppReady(app_id); 587 GCMClient::Result result = EnsureAppReady(app_id);
719 if (result != GCMClient::SUCCESS) { 588 if (result != GCMClient::SUCCESS) {
720 callback.Run(result); 589 callback.Run(result);
721 return; 590 return;
722 } 591 }
723 592
724 // If previous un/register operation is still in progress, bail out. 593 // If previous un/register operation is still in progress, bail out.
725 if (IsAsyncOperationPending(app_id)) { 594 if (IsAsyncOperationPending(app_id)) {
726 callback.Run(GCMClient::ASYNC_OPERATION_PENDING); 595 callback.Run(GCMClient::ASYNC_OPERATION_PENDING);
727 return; 596 return;
728 } 597 }
729 598
730 unregister_callbacks_[app_id] = callback; 599 unregister_callbacks_[app_id] = callback;
731 600
732 // Delay the unregister operation until GCMClient is ready. 601 // Delay the unregister operation until GCMClient is ready.
733 if (!delayed_task_controller_->CanRunTaskWithoutDelay(app_id)) { 602 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
734 delayed_task_controller_->AddTask( 603 delayed_task_controller_->AddTask(
735 app_id,
736 base::Bind(&GCMProfileService::DoUnregister, 604 base::Bind(&GCMProfileService::DoUnregister,
737 weak_ptr_factory_.GetWeakPtr(), 605 weak_ptr_factory_.GetWeakPtr(),
738 app_id)); 606 app_id));
739 return; 607 return;
740 } 608 }
741 609
742 DoUnregister(app_id); 610 DoUnregister(app_id);
743 } 611 }
744 612
745 void GCMProfileService::DoUnregister(const std::string& app_id) { 613 void GCMProfileService::DoUnregister(const std::string& app_id) {
746 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 614 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
747 615
748 // Unregister might be triggered in response to a message that is missing
749 // recipient and in that case there will not be an entry in the map.
750 RegistrationInfoMap::iterator registration_info_iter =
751 registration_info_map_.find(app_id);
752 if (registration_info_iter != registration_info_map_.end()) {
753 registration_info_map_.erase(registration_info_iter);
754
755 // Update the persisted IDs of registered apps.
756 WriteRegisteredAppIDs();
757
758 // Remove the persisted registration info.
759 DeleteRegistrationInfo(app_id);
760
761 // No need to track the app any more.
762 delayed_task_controller_->RemoveApp(app_id);
763 }
764
765 // Ask the server to unregister it. There could be a small chance that the 616 // Ask the server to unregister it. There could be a small chance that the
766 // unregister request fails. If this occurs, it does not bring any harm since 617 // unregister request fails. If this occurs, it does not bring any harm since
767 // we simply reject the messages/events received from the server. 618 // we simply reject the messages/events received from the server.
768 content::BrowserThread::PostTask( 619 content::BrowserThread::PostTask(
769 content::BrowserThread::IO, 620 content::BrowserThread::IO,
770 FROM_HERE, 621 FROM_HERE,
771 base::Bind(&GCMProfileService::IOWorker::Unregister, 622 base::Bind(&GCMProfileService::IOWorker::Unregister,
772 io_worker_, 623 io_worker_,
773 app_id)); 624 app_id));
774 } 625 }
(...skipping 14 matching lines...) Expand all
789 // If the message with send ID is still in progress, bail out. 640 // If the message with send ID is still in progress, bail out.
790 std::pair<std::string, std::string> key(app_id, message.id); 641 std::pair<std::string, std::string> key(app_id, message.id);
791 if (send_callbacks_.find(key) != send_callbacks_.end()) { 642 if (send_callbacks_.find(key) != send_callbacks_.end()) {
792 callback.Run(message.id, GCMClient::INVALID_PARAMETER); 643 callback.Run(message.id, GCMClient::INVALID_PARAMETER);
793 return; 644 return;
794 } 645 }
795 646
796 send_callbacks_[key] = callback; 647 send_callbacks_[key] = callback;
797 648
798 // Delay the send operation until all GCMClient is ready. 649 // Delay the send operation until all GCMClient is ready.
799 if (!delayed_task_controller_->CanRunTaskWithoutDelay(app_id)) { 650 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
800 delayed_task_controller_->AddTask( 651 delayed_task_controller_->AddTask(
801 app_id,
802 base::Bind(&GCMProfileService::DoSend, 652 base::Bind(&GCMProfileService::DoSend,
803 weak_ptr_factory_.GetWeakPtr(), 653 weak_ptr_factory_.GetWeakPtr(),
804 app_id, 654 app_id,
805 receiver_id, 655 receiver_id,
806 message)); 656 message));
807 return; 657 return;
808 } 658 }
809 659
810 DoSend(app_id, receiver_id, message); 660 DoSend(app_id, receiver_id, message);
811 } 661 }
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
883 // CheckIn could be called more than once when: 733 // CheckIn could be called more than once when:
884 // 1) The password changes. 734 // 1) The password changes.
885 // 2) Register/send function calls it to ensure CheckIn is done. 735 // 2) Register/send function calls it to ensure CheckIn is done.
886 if (username_ == username) 736 if (username_ == username)
887 return; 737 return;
888 username_ = username; 738 username_ = username;
889 739
890 DCHECK(!delayed_task_controller_); 740 DCHECK(!delayed_task_controller_);
891 delayed_task_controller_.reset(new DelayedTaskController); 741 delayed_task_controller_.reset(new DelayedTaskController);
892 742
893 // Load all the registered apps.
894 ReadRegisteredAppIDs();
895
896 // This will load the data from the gcm store and trigger the check-in if 743 // This will load the data from the gcm store and trigger the check-in if
897 // the persisted check-in info is not found. 744 // the persisted check-in info is not found.
898 // Note that we need to pass weak pointer again since the existing weak 745 // Note that we need to pass weak pointer again since the existing weak
899 // pointer in IOWorker might have been invalidated when check-out occurs. 746 // pointer in IOWorker might have been invalidated when check-out occurs.
900 content::BrowserThread::PostTask( 747 content::BrowserThread::PostTask(
901 content::BrowserThread::IO, 748 content::BrowserThread::IO,
902 FROM_HERE, 749 FROM_HERE,
903 base::Bind(&GCMProfileService::IOWorker::Load, 750 base::Bind(&GCMProfileService::IOWorker::Load,
904 io_worker_, 751 io_worker_,
905 weak_ptr_factory_.GetWeakPtr())); 752 weak_ptr_factory_.GetWeakPtr()));
906 } 753 }
907 754
908 void GCMProfileService::RemoveCachedData() { 755 void GCMProfileService::RemoveCachedData() {
909 // Remove all the queued tasks since they no longer make sense after 756 // Remove all the queued tasks since they no longer make sense after
910 // GCM service is stopped. 757 // GCM service is stopped.
911 weak_ptr_factory_.InvalidateWeakPtrs(); 758 weak_ptr_factory_.InvalidateWeakPtrs();
912 759
913 username_.clear(); 760 username_.clear();
914 gcm_client_ready_ = false; 761 gcm_client_ready_ = false;
915 delayed_task_controller_.reset(); 762 delayed_task_controller_.reset();
916 register_callbacks_.clear(); 763 register_callbacks_.clear();
917 send_callbacks_.clear(); 764 send_callbacks_.clear();
918 registration_info_map_.clear();
919 }
920
921 void GCMProfileService::RemovePersistedData() {
922 // Remove persisted data from app's state store.
923 for (RegistrationInfoMap::const_iterator iter =
924 registration_info_map_.begin();
925 iter != registration_info_map_.end(); ++iter) {
926 DeleteRegistrationInfo(iter->first);
927 }
928
929 // Remove persisted data from prefs store.
930 profile_->GetPrefs()->ClearPref(prefs::kGCMRegisteredAppIDs);
931 } 765 }
932 766
933 void GCMProfileService::CheckOut() { 767 void GCMProfileService::CheckOut() {
934 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 768 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
935 769
936 // We still proceed with the check-out logic even if the check-in is not 770 // We still proceed with the check-out logic even if the check-in is not
937 // initiated in the current session. This will make sure that all the 771 // initiated in the current session. This will make sure that all the
938 // persisted data written previously will get purged. 772 // persisted data written previously will get purged.
939 773
940 // This has to be done before removing the cached data since we need to do
941 // the lookup based on the cached data.
942 RemovePersistedData();
943
944 RemoveCachedData(); 774 RemoveCachedData();
945 775
946 content::BrowserThread::PostTask( 776 content::BrowserThread::PostTask(
947 content::BrowserThread::IO, 777 content::BrowserThread::IO,
948 FROM_HERE, 778 FROM_HERE,
949 base::Bind(&GCMProfileService::IOWorker::CheckOut, io_worker_)); 779 base::Bind(&GCMProfileService::IOWorker::CheckOut, io_worker_));
950 } 780 }
951 781
952 void GCMProfileService::ResetGCMClient() { 782 void GCMProfileService::ResetGCMClient() {
953 content::BrowserThread::PostTask( 783 content::BrowserThread::PostTask(
954 content::BrowserThread::IO, 784 content::BrowserThread::IO,
955 FROM_HERE, 785 FROM_HERE,
956 base::Bind(&GCMProfileService::IOWorker::Reset, io_worker_)); 786 base::Bind(&GCMProfileService::IOWorker::Reset, io_worker_));
957 } 787 }
958 788
959 GCMClient::Result GCMProfileService::EnsureAppReady(const std::string& app_id) { 789 GCMClient::Result GCMProfileService::EnsureAppReady(const std::string& app_id) {
960 // Ensure that check-in has been done. 790 // Ensure that check-in has been done.
961 EnsureLoaded(); 791 EnsureLoaded();
962 792
963 // If the profile was not signed in, bail out. 793 // If the profile was not signed in, bail out.
964 if (username_.empty()) 794 if (username_.empty())
965 return GCMClient::NOT_SIGNED_IN; 795 return GCMClient::NOT_SIGNED_IN;
966 796
967 // Ensure that app registration information was read.
968 if (!delayed_task_controller_->IsAppTracked(app_id))
969 ReadRegistrationInfo(app_id);
970
971 return GCMClient::SUCCESS; 797 return GCMClient::SUCCESS;
972 } 798 }
973 799
974 bool GCMProfileService::IsAsyncOperationPending( 800 bool GCMProfileService::IsAsyncOperationPending(
975 const std::string& app_id) const { 801 const std::string& app_id) const {
976 return register_callbacks_.find(app_id) != register_callbacks_.end() || 802 return register_callbacks_.find(app_id) != register_callbacks_.end() ||
977 unregister_callbacks_.find(app_id) != unregister_callbacks_.end(); 803 unregister_callbacks_.find(app_id) != unregister_callbacks_.end();
978 } 804 }
979 805
980 void GCMProfileService::RegisterFinished(const std::string& app_id, 806 void GCMProfileService::RegisterFinished(const std::string& app_id,
981 const std::string& registration_id, 807 const std::string& registration_id,
982 GCMClient::Result result) { 808 GCMClient::Result result) {
983 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 809 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
984 810
985 std::map<std::string, RegisterCallback>::iterator callback_iter = 811 std::map<std::string, RegisterCallback>::iterator callback_iter =
986 register_callbacks_.find(app_id); 812 register_callbacks_.find(app_id);
987 if (callback_iter == register_callbacks_.end()) { 813 if (callback_iter == register_callbacks_.end()) {
988 // The callback could have been removed when the app is uninstalled. 814 // The callback could have been removed when the app is uninstalled.
989 return; 815 return;
990 } 816 }
991 817
992 // Cache the registration ID if the registration succeeds. Otherwise,
993 // removed the cached info.
994 RegistrationInfoMap::iterator registration_info_iter =
995 registration_info_map_.find(app_id);
996 // This is unlikely to happen because the app will not be uninstalled before
997 // the asynchronous extension function completes.
998 DCHECK(registration_info_iter != registration_info_map_.end());
999 if (result == GCMClient::SUCCESS) {
1000 registration_info_iter->second.registration_id = registration_id;
1001 WriteRegistrationInfo(app_id);
1002 } else {
1003 registration_info_map_.erase(registration_info_iter);
1004 }
1005
1006 RegisterCallback callback = callback_iter->second; 818 RegisterCallback callback = callback_iter->second;
1007 register_callbacks_.erase(callback_iter); 819 register_callbacks_.erase(callback_iter);
1008 callback.Run(registration_id, result); 820 callback.Run(registration_id, result);
1009 } 821 }
1010 822
1011 void GCMProfileService::UnregisterFinished(const std::string& app_id, 823 void GCMProfileService::UnregisterFinished(const std::string& app_id,
1012 GCMClient::Result result) { 824 GCMClient::Result result) {
1013 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 825 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
1014 826
1015 std::map<std::string, UnregisterCallback>::iterator callback_iter = 827 std::map<std::string, UnregisterCallback>::iterator callback_iter =
(...skipping 25 matching lines...) Expand all
1041 } 853 }
1042 854
1043 void GCMProfileService::MessageReceived(const std::string& app_id, 855 void GCMProfileService::MessageReceived(const std::string& app_id,
1044 GCMClient::IncomingMessage message) { 856 GCMClient::IncomingMessage message) {
1045 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 857 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
1046 858
1047 // Drop the event if signed out. 859 // Drop the event if signed out.
1048 if (username_.empty()) 860 if (username_.empty())
1049 return; 861 return;
1050 862
1051 // Dropping the message when application does not have a registration entry
1052 // or the app is not registered for the sender of the message.
1053 RegistrationInfoMap::iterator iter = registration_info_map_.find(app_id);
1054 if (iter == registration_info_map_.end() ||
1055 std::find(iter->second.sender_ids.begin(),
1056 iter->second.sender_ids.end(),
1057 message.sender_id) == iter->second.sender_ids.end()) {
1058 return;
1059 }
1060
1061 GetAppHandler(app_id)->OnMessage(app_id, message); 863 GetAppHandler(app_id)->OnMessage(app_id, message);
1062 } 864 }
1063 865
1064 void GCMProfileService::MessagesDeleted(const std::string& app_id) { 866 void GCMProfileService::MessagesDeleted(const std::string& app_id) {
1065 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 867 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
1066 868
1067 // Drop the event if signed out. 869 // Drop the event if signed out.
1068 if (username_.empty()) 870 if (username_.empty())
1069 return; 871 return;
1070 872
(...skipping 12 matching lines...) Expand all
1083 GetAppHandler(app_id)->OnSendError(app_id, send_error_details); 885 GetAppHandler(app_id)->OnSendError(app_id, send_error_details);
1084 } 886 }
1085 887
1086 void GCMProfileService::GCMClientReady() { 888 void GCMProfileService::GCMClientReady() {
1087 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 889 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
1088 890
1089 if (gcm_client_ready_) 891 if (gcm_client_ready_)
1090 return; 892 return;
1091 gcm_client_ready_ = true; 893 gcm_client_ready_ = true;
1092 894
1093 delayed_task_controller_->SetGCMReady(); 895 delayed_task_controller_->SetReady();
1094 } 896 }
1095 897
1096 GCMAppHandler* GCMProfileService::GetAppHandler(const std::string& app_id) { 898 GCMAppHandler* GCMProfileService::GetAppHandler(const std::string& app_id) {
1097 std::map<std::string, GCMAppHandler*>::const_iterator iter = 899 std::map<std::string, GCMAppHandler*>::const_iterator iter =
1098 app_handlers_.find(app_id); 900 app_handlers_.find(app_id);
1099 return iter == app_handlers_.end() ? &default_app_handler_ : iter->second; 901 return iter == app_handlers_.end() ? &default_app_handler_ : iter->second;
1100 } 902 }
1101 903
1102 void GCMProfileService::ReadRegisteredAppIDs() {
1103 const base::ListValue* app_id_list =
1104 profile_->GetPrefs()->GetList(prefs::kGCMRegisteredAppIDs);
1105 for (size_t i = 0; i < app_id_list->GetSize(); ++i) {
1106 std::string app_id;
1107 if (!app_id_list->GetString(i, &app_id))
1108 continue;
1109 ReadRegistrationInfo(app_id);
1110 }
1111 }
1112
1113 void GCMProfileService::WriteRegisteredAppIDs() {
1114 base::ListValue apps;
1115 for (RegistrationInfoMap::const_iterator iter =
1116 registration_info_map_.begin();
1117 iter != registration_info_map_.end(); ++iter) {
1118 apps.Append(new base::StringValue(iter->first));
1119 }
1120 profile_->GetPrefs()->Set(prefs::kGCMRegisteredAppIDs, apps);
1121 }
1122
1123 void GCMProfileService::DeleteRegistrationInfo(const std::string& app_id) {
1124 extensions::StateStore* storage =
1125 extensions::ExtensionSystem::Get(profile_)->state_store();
1126 DCHECK(storage);
1127
1128 storage->RemoveExtensionValue(app_id, kRegistrationKey);
1129 }
1130
1131 void GCMProfileService::WriteRegistrationInfo(const std::string& app_id) {
1132 extensions::StateStore* storage =
1133 extensions::ExtensionSystem::Get(profile_)->state_store();
1134 DCHECK(storage);
1135
1136 RegistrationInfoMap::const_iterator registration_info_iter =
1137 registration_info_map_.find(app_id);
1138 if (registration_info_iter == registration_info_map_.end())
1139 return;
1140 const RegistrationInfo& registration_info = registration_info_iter->second;
1141
1142 scoped_ptr<base::ListValue> senders_list(new base::ListValue());
1143 for (std::vector<std::string>::const_iterator senders_iter =
1144 registration_info.sender_ids.begin();
1145 senders_iter != registration_info.sender_ids.end();
1146 ++senders_iter) {
1147 senders_list->AppendString(*senders_iter);
1148 }
1149
1150 scoped_ptr<base::DictionaryValue> registration_info_dict(
1151 new base::DictionaryValue());
1152 registration_info_dict->Set(kSendersKey, senders_list.release());
1153 registration_info_dict->SetString(kRegistrationIDKey,
1154 registration_info.registration_id);
1155
1156 storage->SetExtensionValue(
1157 app_id, kRegistrationKey, registration_info_dict.PassAs<base::Value>());
1158 }
1159
1160 void GCMProfileService::ReadRegistrationInfo(const std::string& app_id) {
1161 delayed_task_controller_->AddApp(app_id);
1162
1163 extensions::StateStore* storage =
1164 extensions::ExtensionSystem::Get(profile_)->state_store();
1165 DCHECK(storage);
1166 storage->GetExtensionValue(
1167 app_id,
1168 kRegistrationKey,
1169 base::Bind(
1170 &GCMProfileService::ReadRegistrationInfoFinished,
1171 weak_ptr_factory_.GetWeakPtr(),
1172 app_id));
1173 }
1174
1175 void GCMProfileService::ReadRegistrationInfoFinished(
1176 const std::string& app_id,
1177 scoped_ptr<base::Value> value) {
1178 RegistrationInfo registration_info;
1179 if (value &&
1180 !ParsePersistedRegistrationInfo(value.Pass(), &registration_info)) {
1181 // Delete the persisted data if it is corrupted.
1182 DeleteRegistrationInfo(app_id);
1183 }
1184
1185 if (registration_info.IsValid())
1186 registration_info_map_[app_id] = registration_info;
1187
1188 delayed_task_controller_->SetAppReady(app_id);
1189 }
1190
1191 bool GCMProfileService::ParsePersistedRegistrationInfo(
1192 scoped_ptr<base::Value> value,
1193 RegistrationInfo* registration_info) {
1194 base::DictionaryValue* dict = NULL;
1195 if (!value.get() || !value->GetAsDictionary(&dict))
1196 return false;
1197
1198 if (!dict->GetString(kRegistrationIDKey, &registration_info->registration_id))
1199 return false;
1200
1201 const base::ListValue* senders_list = NULL;
1202 if (!dict->GetList(kSendersKey, &senders_list) || !senders_list->GetSize())
1203 return false;
1204 for (size_t i = 0; i < senders_list->GetSize(); ++i) {
1205 std::string sender;
1206 if (!senders_list->GetString(i, &sender))
1207 return false;
1208 registration_info->sender_ids.push_back(sender);
1209 }
1210
1211 return true;
1212 }
1213
1214 void GCMProfileService::RequestGCMStatisticsFinished( 904 void GCMProfileService::RequestGCMStatisticsFinished(
1215 GCMClient::GCMStatistics stats) { 905 GCMClient::GCMStatistics stats) {
1216 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 906 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
1217 907
1218 request_gcm_statistics_callback_.Run(stats); 908 request_gcm_statistics_callback_.Run(stats);
1219 } 909 }
1220 910
1221 // static
1222 const char* GCMProfileService::GetPersistentRegisterKeyForTesting() {
1223 return kRegistrationKey;
1224 }
1225
1226 } // namespace gcm 911 } // namespace gcm
OLDNEW
« no previous file with comments | « chrome/browser/services/gcm/gcm_profile_service.h ('k') | chrome/browser/services/gcm/gcm_profile_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698