OLD | NEW |
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 "base/base64.h" | 7 #include "base/base64.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/prefs/pref_service.h" | 9 #include "base/prefs/pref_service.h" |
10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
(...skipping 20 matching lines...) Expand all Loading... |
31 const char kRegistrationKey[] = "gcm.registration"; | 31 const char kRegistrationKey[] = "gcm.registration"; |
32 const char kSendersKey[] = "senders"; | 32 const char kSendersKey[] = "senders"; |
33 const char kRegistrationIDKey[] = "reg_id"; | 33 const char kRegistrationIDKey[] = "reg_id"; |
34 | 34 |
35 // Helper class to save tasks to run until we're ready to execute them. | 35 // Helper class to save tasks to run until we're ready to execute them. |
36 class GCMProfileService::DelayedTaskController { | 36 class GCMProfileService::DelayedTaskController { |
37 public: | 37 public: |
38 DelayedTaskController(); | 38 DelayedTaskController(); |
39 ~DelayedTaskController(); | 39 ~DelayedTaskController(); |
40 | 40 |
41 // Adds an app to non-ready list that queue all tasks to invoke until ready. | 41 // Adds an app to the tracking list. It will be first marked as not ready. |
| 42 // Tasks will be queued for delay execution until the app is marked as ready. |
42 void AddApp(const std::string& app_id); | 43 void AddApp(const std::string& app_id); |
43 | 44 |
| 45 // Removes the app from the tracking list. |
| 46 void RemoveApp(const std::string& app_id); |
| 47 |
44 // Adds a task that will be invoked once we're ready. | 48 // Adds a task that will be invoked once we're ready. |
45 void AddTask(const std::string& app_id, base::Closure task); | 49 void AddTask(const std::string& app_id, base::Closure task); |
46 | 50 |
47 // Marks that GCMClient is ready. | 51 // Marks that GCMClient is ready. |
48 void SetGCMClientReady(); | 52 void SetGCMClientReady(); |
49 | 53 |
50 // Marks that the app is ready to have operations performed. | 54 // Marks that the app is ready to have operations performed. |
51 void SetAppReady(const std::string& app_id); | 55 void SetAppReady(const std::string& app_id); |
52 | 56 |
53 // Returns true if it is ready to perform operations for an app. | 57 // Returns true if it is ready to perform operations for an app. |
54 bool CanRunTaskWithoutDelay(const std::string& app_id) const; | 58 bool CanRunTaskWithoutDelay(const std::string& app_id) const; |
55 | 59 |
| 60 // Returns true if the app has been tracked for readiness. |
| 61 bool IsAppTracked(const std::string& app_id) const; |
| 62 |
56 private: | 63 private: |
57 struct AppTaskQueue { | 64 struct AppTaskQueue { |
58 AppTaskQueue(); | 65 AppTaskQueue(); |
59 ~AppTaskQueue(); | 66 ~AppTaskQueue(); |
60 | 67 |
61 // The flag that indicates if GCMProfileService completes loading the | 68 // The flag that indicates if GCMProfileService completes loading the |
62 // persistent data for the app. | 69 // persistent data for the app. |
63 bool ready; | 70 bool ready; |
64 | 71 |
65 // Tasks to be invoked upon ready. | 72 // Tasks to be invoked upon ready. |
(...skipping 27 matching lines...) Expand all Loading... |
93 delete iter->second; | 100 delete iter->second; |
94 } | 101 } |
95 } | 102 } |
96 | 103 |
97 void GCMProfileService::DelayedTaskController::AddApp( | 104 void GCMProfileService::DelayedTaskController::AddApp( |
98 const std::string& app_id) { | 105 const std::string& app_id) { |
99 DCHECK(delayed_task_map_.find(app_id) == delayed_task_map_.end()); | 106 DCHECK(delayed_task_map_.find(app_id) == delayed_task_map_.end()); |
100 delayed_task_map_[app_id] = new AppTaskQueue; | 107 delayed_task_map_[app_id] = new AppTaskQueue; |
101 } | 108 } |
102 | 109 |
| 110 void GCMProfileService::DelayedTaskController::RemoveApp( |
| 111 const std::string& app_id) { |
| 112 delayed_task_map_.erase(app_id); |
| 113 } |
| 114 |
103 void GCMProfileService::DelayedTaskController::AddTask( | 115 void GCMProfileService::DelayedTaskController::AddTask( |
104 const std::string& app_id, base::Closure task) { | 116 const std::string& app_id, base::Closure task) { |
105 DelayedTaskMap::const_iterator iter = delayed_task_map_.find(app_id); | 117 DelayedTaskMap::const_iterator iter = delayed_task_map_.find(app_id); |
106 DCHECK(iter != delayed_task_map_.end()); | 118 DCHECK(iter != delayed_task_map_.end()); |
107 iter->second->tasks.push_back(task); | 119 iter->second->tasks.push_back(task); |
108 } | 120 } |
109 | 121 |
110 void GCMProfileService::DelayedTaskController::SetGCMClientReady() { | 122 void GCMProfileService::DelayedTaskController::SetGCMClientReady() { |
111 gcm_client_ready_ = true; | 123 gcm_client_ready_ = true; |
112 | 124 |
(...skipping 29 matching lines...) Expand all Loading... |
142 bool GCMProfileService::DelayedTaskController::CanRunTaskWithoutDelay( | 154 bool GCMProfileService::DelayedTaskController::CanRunTaskWithoutDelay( |
143 const std::string& app_id) const { | 155 const std::string& app_id) const { |
144 if (!gcm_client_ready_) | 156 if (!gcm_client_ready_) |
145 return false; | 157 return false; |
146 DelayedTaskMap::const_iterator iter = delayed_task_map_.find(app_id); | 158 DelayedTaskMap::const_iterator iter = delayed_task_map_.find(app_id); |
147 if (iter == delayed_task_map_.end()) | 159 if (iter == delayed_task_map_.end()) |
148 return true; | 160 return true; |
149 return iter->second->ready; | 161 return iter->second->ready; |
150 } | 162 } |
151 | 163 |
| 164 bool GCMProfileService::DelayedTaskController::IsAppTracked( |
| 165 const std::string& app_id) const { |
| 166 return delayed_task_map_.find(app_id) != delayed_task_map_.end(); |
| 167 } |
| 168 |
152 void GCMProfileService::DelayedTaskController::RunTasks( | 169 void GCMProfileService::DelayedTaskController::RunTasks( |
153 AppTaskQueue* task_queue) { | 170 AppTaskQueue* task_queue) { |
154 DCHECK(gcm_client_ready_ && task_queue->ready); | 171 DCHECK(gcm_client_ready_ && task_queue->ready); |
155 | 172 |
156 for (size_t i = 0; i < task_queue->tasks.size(); ++i) | 173 for (size_t i = 0; i < task_queue->tasks.size(); ++i) |
157 task_queue->tasks[i].Run(); | 174 task_queue->tasks[i].Run(); |
158 task_queue->tasks.clear(); | 175 task_queue->tasks.clear(); |
159 } | 176 } |
160 | 177 |
161 class GCMProfileService::IOWorker | 178 class GCMProfileService::IOWorker |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
408 GCMProfileService::RegistrationInfo::~RegistrationInfo() { | 425 GCMProfileService::RegistrationInfo::~RegistrationInfo() { |
409 } | 426 } |
410 | 427 |
411 bool GCMProfileService::RegistrationInfo::IsValid() const { | 428 bool GCMProfileService::RegistrationInfo::IsValid() const { |
412 return !sender_ids.empty() && !registration_id.empty(); | 429 return !sender_ids.empty() && !registration_id.empty(); |
413 } | 430 } |
414 | 431 |
415 bool GCMProfileService::enable_gcm_for_testing_ = false; | 432 bool GCMProfileService::enable_gcm_for_testing_ = false; |
416 | 433 |
417 // static | 434 // static |
418 bool GCMProfileService::IsGCMEnabled() { | 435 bool GCMProfileService::IsGCMEnabled(Profile* profile) { |
| 436 // GCM is not enabled in incognito mode. |
| 437 if (profile->IsOffTheRecord()) |
| 438 return false; |
| 439 |
419 if (enable_gcm_for_testing_) | 440 if (enable_gcm_for_testing_) |
420 return true; | 441 return true; |
421 | 442 |
422 // GCM support is only enabled for Canary/Dev builds. | 443 // GCM support is only enabled for Canary/Dev builds. |
423 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); | 444 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); |
424 return channel == chrome::VersionInfo::CHANNEL_UNKNOWN || | 445 return channel == chrome::VersionInfo::CHANNEL_UNKNOWN || |
425 channel == chrome::VersionInfo::CHANNEL_CANARY || | 446 channel == chrome::VersionInfo::CHANNEL_CANARY || |
426 channel == chrome::VersionInfo::CHANNEL_DEV; | 447 channel == chrome::VersionInfo::CHANNEL_DEV; |
427 } | 448 } |
428 | 449 |
429 // static | 450 // static |
430 void GCMProfileService::RegisterProfilePrefs( | 451 void GCMProfileService::RegisterProfilePrefs( |
431 user_prefs::PrefRegistrySyncable* registry) { | 452 user_prefs::PrefRegistrySyncable* registry) { |
432 registry->RegisterUint64Pref( | 453 registry->RegisterUint64Pref( |
433 prefs::kGCMUserAccountID, | 454 prefs::kGCMUserAccountID, |
434 0, | 455 0, |
435 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 456 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
436 registry->RegisterStringPref( | 457 registry->RegisterStringPref( |
437 prefs::kGCMUserToken, | 458 prefs::kGCMUserToken, |
438 "", | 459 "", |
439 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 460 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
440 } | 461 } |
441 | 462 |
442 GCMProfileService::GCMProfileService(Profile* profile) | 463 GCMProfileService::GCMProfileService(Profile* profile) |
443 : profile_(profile), | 464 : profile_(profile), |
444 testing_delegate_(NULL), | 465 testing_delegate_(NULL), |
445 weak_ptr_factory_(this) { | 466 weak_ptr_factory_(this) { |
| 467 DCHECK(!profile->IsOffTheRecord()); |
446 Init(); | 468 Init(); |
447 } | 469 } |
448 | 470 |
449 GCMProfileService::GCMProfileService(Profile* profile, | 471 GCMProfileService::GCMProfileService(Profile* profile, |
450 TestingDelegate* testing_delegate) | 472 TestingDelegate* testing_delegate) |
451 : profile_(profile), | 473 : profile_(profile), |
452 testing_delegate_(testing_delegate), | 474 testing_delegate_(testing_delegate), |
453 weak_ptr_factory_(this) { | 475 weak_ptr_factory_(this) { |
454 Init(); | 476 Init(); |
455 } | 477 } |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
718 // ask the server to unregister it. | 740 // ask the server to unregister it. |
719 RegistrationInfoMap::iterator registration_info_iter = | 741 RegistrationInfoMap::iterator registration_info_iter = |
720 registration_info_map_.find(app_id); | 742 registration_info_map_.find(app_id); |
721 if (registration_info_iter == registration_info_map_.end()) | 743 if (registration_info_iter == registration_info_map_.end()) |
722 return; | 744 return; |
723 registration_info_map_.erase(registration_info_iter); | 745 registration_info_map_.erase(registration_info_iter); |
724 | 746 |
725 // Remove the persisted registration info. | 747 // Remove the persisted registration info. |
726 DeleteRegistrationInfo(app_id); | 748 DeleteRegistrationInfo(app_id); |
727 | 749 |
| 750 // No need to track the app any more. |
| 751 delayed_task_controller_->RemoveApp(app_id); |
| 752 |
728 // Ask the server to unregister it. There could be a small chance that the | 753 // Ask the server to unregister it. There could be a small chance that the |
729 // unregister request fails. If this occurs, it does not bring any harm since | 754 // unregister request fails. If this occurs, it does not bring any harm since |
730 // we simply reject the messages/events received from the server. | 755 // we simply reject the messages/events received from the server. |
731 content::BrowserThread::PostTask( | 756 content::BrowserThread::PostTask( |
732 content::BrowserThread::IO, | 757 content::BrowserThread::IO, |
733 FROM_HERE, | 758 FROM_HERE, |
734 base::Bind(&GCMProfileService::IOWorker::Unregister, | 759 base::Bind(&GCMProfileService::IOWorker::Unregister, |
735 io_worker_, | 760 io_worker_, |
736 app_id)); | 761 app_id)); |
737 } | 762 } |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
880 new base::DictionaryValue()); | 905 new base::DictionaryValue()); |
881 registration_info_dict->Set(kSendersKey, senders_list.release()); | 906 registration_info_dict->Set(kSendersKey, senders_list.release()); |
882 registration_info_dict->SetString(kRegistrationIDKey, | 907 registration_info_dict->SetString(kRegistrationIDKey, |
883 registration_info.registration_id); | 908 registration_info.registration_id); |
884 | 909 |
885 storage->SetExtensionValue( | 910 storage->SetExtensionValue( |
886 app_id, kRegistrationKey, registration_info_dict.PassAs<base::Value>()); | 911 app_id, kRegistrationKey, registration_info_dict.PassAs<base::Value>()); |
887 } | 912 } |
888 | 913 |
889 void GCMProfileService::ReadRegistrationInfo(const std::string& app_id) { | 914 void GCMProfileService::ReadRegistrationInfo(const std::string& app_id) { |
| 915 // This function can be called more than once when the app is allowed in |
| 916 // incognito and the extension service reloads the app. |
| 917 if (delayed_task_controller_->IsAppTracked(app_id)) |
| 918 return; |
| 919 |
| 920 delayed_task_controller_->AddApp(app_id); |
| 921 |
890 extensions::StateStore* storage = | 922 extensions::StateStore* storage = |
891 extensions::ExtensionSystem::Get(profile_)->state_store(); | 923 extensions::ExtensionSystem::Get(profile_)->state_store(); |
892 DCHECK(storage); | 924 DCHECK(storage); |
893 | |
894 delayed_task_controller_->AddApp(app_id); | |
895 | |
896 storage->GetExtensionValue( | 925 storage->GetExtensionValue( |
897 app_id, | 926 app_id, |
898 kRegistrationKey, | 927 kRegistrationKey, |
899 base::Bind( | 928 base::Bind( |
900 &GCMProfileService::ReadRegistrationInfoFinished, | 929 &GCMProfileService::ReadRegistrationInfoFinished, |
901 weak_ptr_factory_.GetWeakPtr(), | 930 weak_ptr_factory_.GetWeakPtr(), |
902 app_id)); | 931 app_id)); |
903 } | 932 } |
904 | 933 |
905 void GCMProfileService::ReadRegistrationInfoFinished( | 934 void GCMProfileService::ReadRegistrationInfoFinished( |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
940 | 969 |
941 return true; | 970 return true; |
942 } | 971 } |
943 | 972 |
944 // static | 973 // static |
945 const char* GCMProfileService::GetPersistentRegisterKeyForTesting() { | 974 const char* GCMProfileService::GetPersistentRegisterKeyForTesting() { |
946 return kRegistrationKey; | 975 return kRegistrationKey; |
947 } | 976 } |
948 | 977 |
949 } // namespace gcm | 978 } // namespace gcm |
OLD | NEW |