| OLD | NEW |
| 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 "chrome/browser/services/gcm/push_messaging_service_impl.h" | 5 #include "chrome/browser/services/gcm/push_messaging_service_impl.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 11 #include "base/prefs/pref_service.h" | 11 #include "base/prefs/pref_service.h" |
| 12 #include "base/strings/string_util.h" | |
| 13 #include "chrome/browser/profiles/profile.h" | 12 #include "chrome/browser/profiles/profile.h" |
| 14 #include "chrome/browser/services/gcm/gcm_profile_service.h" | 13 #include "chrome/browser/services/gcm/gcm_profile_service.h" |
| 15 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h" | 14 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h" |
| 16 #include "chrome/common/chrome_switches.h" | 15 #include "chrome/common/chrome_switches.h" |
| 17 #include "chrome/common/pref_names.h" | 16 #include "chrome/common/pref_names.h" |
| 18 #include "components/gcm_driver/gcm_driver.h" | 17 #include "components/gcm_driver/gcm_driver.h" |
| 19 #include "components/pref_registry/pref_registry_syncable.h" | 18 #include "components/pref_registry/pref_registry_syncable.h" |
| 19 #include "content/browser/service_worker/service_worker_context_wrapper.h" |
| 20 #include "content/browser/service_worker/service_worker_registration.h" |
| 21 #include "content/public/browser/browser_thread.h" |
| 22 #include "content/public/browser/push_messaging_application_id.h" |
| 23 #include "content/public/browser/storage_partition.h" |
| 24 |
| 25 using content::BrowserContext; |
| 26 using content::BrowserThread; |
| 27 using content::PushMessagingApplicationId; |
| 28 using content::ServiceWorkerContextWrapper; |
| 20 | 29 |
| 21 namespace gcm { | 30 namespace gcm { |
| 22 | 31 |
| 23 namespace { | 32 namespace { |
| 24 const char kAppIdPrefix[] = "push:"; | 33 // TODO(mvanouwerkerk): Move this to a public shared place. |
| 34 const char kAppIdPrefix[] = "push"; |
| 25 const int kMaxRegistrations = 1000000; | 35 const int kMaxRegistrations = 1000000; |
| 26 } // namespace | 36 } // namespace |
| 27 | 37 |
| 28 // static | 38 // static |
| 29 void PushMessagingServiceImpl::RegisterProfilePrefs( | 39 void PushMessagingServiceImpl::RegisterProfilePrefs( |
| 30 user_prefs::PrefRegistrySyncable* registry) { | 40 user_prefs::PrefRegistrySyncable* registry) { |
| 31 registry->RegisterIntegerPref( | 41 registry->RegisterIntegerPref( |
| 32 prefs::kPushMessagingRegistrationCount, | 42 prefs::kPushMessagingRegistrationCount, |
| 33 0, | 43 0, |
| 34 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 44 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 profile_(profile), | 78 profile_(profile), |
| 69 weak_factory_(this) { | 79 weak_factory_(this) { |
| 70 } | 80 } |
| 71 | 81 |
| 72 PushMessagingServiceImpl::~PushMessagingServiceImpl() { | 82 PushMessagingServiceImpl::~PushMessagingServiceImpl() { |
| 73 // TODO(johnme): If it's possible for this to be destroyed before GCMDriver, | 83 // TODO(johnme): If it's possible for this to be destroyed before GCMDriver, |
| 74 // then we should call RemoveAppHandler. | 84 // then we should call RemoveAppHandler. |
| 75 } | 85 } |
| 76 | 86 |
| 77 bool PushMessagingServiceImpl::CanHandle(const std::string& app_id) const { | 87 bool PushMessagingServiceImpl::CanHandle(const std::string& app_id) const { |
| 78 // TODO(mvanouwerkerk): Finalize and centralize format of Push API app_id. | 88 return PushMessagingApplicationId::IsValid(app_id); |
| 79 return StartsWithASCII(app_id, kAppIdPrefix, true); | |
| 80 } | 89 } |
| 81 | 90 |
| 82 void PushMessagingServiceImpl::ShutdownHandler() { | 91 void PushMessagingServiceImpl::ShutdownHandler() { |
| 83 // TODO(johnme): Do any necessary cleanup. | 92 // TODO(johnme): Do any necessary cleanup. |
| 84 } | 93 } |
| 85 | 94 |
| 86 void PushMessagingServiceImpl::OnMessage( | 95 void PushMessagingServiceImpl::OnMessage( |
| 87 const std::string& app_id, | 96 const std::string& app_id, |
| 88 const GCMClient::IncomingMessage& message) { | 97 const GCMClient::IncomingMessage& message) { |
| 98 LOG(WARNING) << "app_id: " << app_id; |
| 99 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 89 // The Push API only exposes a single string of data in the push event fired | 100 // The Push API only exposes a single string of data in the push event fired |
| 90 // on the Service Worker. When developers send messages using GCM to the Push | 101 // on the Service Worker. When developers send messages using GCM to the Push |
| 91 // API, they must pass a single key-value pair, where the key is "data" and | 102 // API, they must pass a single key-value pair, where the key is "data" and |
| 92 // the value is the string they want to be passed to their Service Worker. | 103 // the value is the string they want to be passed to their Service Worker. |
| 93 // For example, they could send the following JSON using the HTTPS GCM API: | 104 // For example, they could send the following JSON using the HTTPS GCM API: |
| 94 // { | 105 // { |
| 95 // "registration_ids": ["FOO", "BAR"], | 106 // "registration_ids": ["FOO", "BAR"], |
| 96 // "data": { | 107 // "data": { |
| 97 // "data": "BAZ", | 108 // "data": "BAZ", |
| 98 // }, | 109 // }, |
| 99 // "delay_while_idle": true, | 110 // "delay_while_idle": true, |
| 100 // } | 111 // } |
| 101 // TODO(johnme): Make sure this is clearly documented for developers. | 112 // TODO(johnme): Make sure this is clearly documented for developers. |
| 113 PushMessagingApplicationId id = PushMessagingApplicationId::Parse(app_id); |
| 114 DCHECK(id.is_valid()); |
| 102 GCMClient::MessageData::const_iterator it = message.data.find("data"); | 115 GCMClient::MessageData::const_iterator it = message.data.find("data"); |
| 103 if (it != message.data.end()) { | 116 if (id.is_valid() && it != message.data.end()) { |
| 104 const std::string& data ALLOW_UNUSED = it->second; | 117 const std::string& data = it->second; |
| 105 // TODO(mvanouwerkerk): Fire push event with data on the Service Worker | 118 content::StoragePartition* partition = |
| 106 // corresponding to app_id (and remove ALLOW_UNUSED above). | 119 BrowserContext::GetStoragePartitionForSite(profile_, id.origin); |
| 120 scoped_refptr<ServiceWorkerContextWrapper> worker_context = |
| 121 static_cast<ServiceWorkerContextWrapper*>( |
| 122 partition->GetServiceWorkerContext()); |
| 123 BrowserThread::PostTask(BrowserThread::IO, |
| 124 FROM_HERE, |
| 125 base::Bind(&PushMessagingServiceImpl::SendMessage, |
| 126 weak_factory_.GetWeakPtr(), |
| 127 id, |
| 128 data, |
| 129 worker_context)); |
| 107 } else { | 130 } else { |
| 131 LOG(WARNING) << "Dropping the message."; |
| 108 // Drop the message, as it is invalid. | 132 // Drop the message, as it is invalid. |
| 109 // TODO(mvanouwerkerk): Show a warning in the developer console of the | 133 // TODO(mvanouwerkerk): Show a warning in the developer console of the |
| 110 // Service Worker corresponding to app_id. | 134 // Service Worker corresponding to app_id. |
| 111 // TODO(johnme): Add diagnostic observers (e.g. UMA and an internals page) | 135 // TODO(johnme): Add diagnostic observers (e.g. UMA and an internals page) |
| 112 // to know when bad things happen. | 136 // to know when bad things happen. |
| 113 } | 137 } |
| 114 } | 138 } |
| 115 | 139 |
| 140 void PushMessagingServiceImpl::SendMessage( |
| 141 const PushMessagingApplicationId& id, |
| 142 const std::string& data, |
| 143 scoped_refptr<ServiceWorkerContextWrapper> worker_context) { |
| 144 LOG(WARNING) << "data: " << data; |
| 145 // TODO(mvanouwerkerk): Can this method live in content::PushMessagingService? |
| 146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 147 content::ServiceWorkerRegistration* worker_registration = |
| 148 worker_context->context()->GetLiveRegistration(id.worker_registration_id); |
| 149 if (worker_registration) { |
| 150 base::Callback<void(ServiceWorkerStatusCode)> callback = |
| 151 base::Bind(&PushMessagingServiceImpl::SendMessageCallback, |
| 152 weak_factory_.GetWeakPtr()); |
| 153 worker_registration->active_version()->DispatchPushEvent(callback, data); |
| 154 } else { |
| 155 // TODO(mvanouwerkerk): UMA logging. Can we recover from failure? |
| 156 LOG(WARNING) << "Could not find ServiceWorkerRegistration."; |
| 157 } |
| 158 } |
| 159 |
| 160 void PushMessagingServiceImpl::SendMessageCallback( |
| 161 ServiceWorkerStatusCode status) { |
| 162 // TODO(mvanouwerkerk): UMA logging. Can we recover from failures? |
| 163 LOG(WARNING) << "ServiceWorkerStatusCode: " << status; |
| 164 } |
| 165 |
| 116 void PushMessagingServiceImpl::OnMessagesDeleted(const std::string& app_id) { | 166 void PushMessagingServiceImpl::OnMessagesDeleted(const std::string& app_id) { |
| 117 // TODO(mvanouwerkerk): Fire push error event on the Service Worker | 167 // TODO(mvanouwerkerk): Fire push error event on the Service Worker |
| 118 // corresponding to app_id. | 168 // corresponding to app_id. |
| 119 } | 169 } |
| 120 | 170 |
| 121 void PushMessagingServiceImpl::OnSendError( | 171 void PushMessagingServiceImpl::OnSendError( |
| 122 const std::string& app_id, | 172 const std::string& app_id, |
| 123 const GCMClient::SendErrorDetails& send_error_details) { | 173 const GCMClient::SendErrorDetails& send_error_details) { |
| 124 NOTREACHED() << "The Push API shouldn't have sent messages upstream"; | 174 NOTREACHED() << "The Push API shouldn't have sent messages upstream"; |
| 125 } | 175 } |
| 126 | 176 |
| 127 void PushMessagingServiceImpl::Register( | 177 void PushMessagingServiceImpl::Register( |
| 128 const std::string& app_id, | 178 const std::string& app_id, |
| 129 const std::string& sender_id, | 179 const std::string& sender_id, |
| 130 const content::PushMessagingService::RegisterCallback& callback) { | 180 const content::PushMessagingService::RegisterCallback& callback) { |
| 181 LOG(WARNING) << "app_id: " << app_id; |
| 131 if (!gcm_profile_service_->driver()) { | 182 if (!gcm_profile_service_->driver()) { |
| 132 NOTREACHED() << "There is no GCMDriver. Has GCMProfileService shut down?"; | 183 NOTREACHED() << "There is no GCMDriver. Has GCMProfileService shut down?"; |
| 133 } | 184 } |
| 134 | 185 |
| 135 if (profile_->GetPrefs()->GetInteger( | 186 if (profile_->GetPrefs()->GetInteger( |
| 136 prefs::kPushMessagingRegistrationCount) >= kMaxRegistrations) { | 187 prefs::kPushMessagingRegistrationCount) >= kMaxRegistrations) { |
| 188 LOG(WARNING) << "Registration limit has been reached."; |
| 137 DidRegister(app_id, callback, "", GCMClient::UNKNOWN_ERROR); | 189 DidRegister(app_id, callback, "", GCMClient::UNKNOWN_ERROR); |
| 138 return; | 190 return; |
| 139 } | 191 } |
| 140 | 192 |
| 141 // If this is registering for the first time then the driver does not have | 193 // If this is registering for the first time then the driver does not have |
| 142 // this as an app handler and registration would fail. | 194 // this as an app handler and registration would fail. |
| 143 if (gcm_profile_service_->driver()->GetAppHandler(kAppIdPrefix) != this) | 195 if (gcm_profile_service_->driver()->GetAppHandler(kAppIdPrefix) != this) |
| 144 gcm_profile_service_->driver()->AddAppHandler(kAppIdPrefix, this); | 196 gcm_profile_service_->driver()->AddAppHandler(kAppIdPrefix, this); |
| 145 | 197 |
| 146 std::vector<std::string> sender_ids(1, sender_id); | 198 std::vector<std::string> sender_ids(1, sender_id); |
| 147 gcm_profile_service_->driver()->Register( | 199 gcm_profile_service_->driver()->Register( |
| 148 app_id, | 200 app_id, |
| 149 sender_ids, | 201 sender_ids, |
| 150 base::Bind(&PushMessagingServiceImpl::DidRegister, | 202 base::Bind(&PushMessagingServiceImpl::DidRegister, |
| 151 weak_factory_.GetWeakPtr(), | 203 weak_factory_.GetWeakPtr(), |
| 152 app_id, | 204 app_id, |
| 153 callback)); | 205 callback)); |
| 154 } | 206 } |
| 155 | 207 |
| 156 void PushMessagingServiceImpl::DidRegister( | 208 void PushMessagingServiceImpl::DidRegister( |
| 157 const std::string& app_id, | 209 const std::string& app_id, |
| 158 const content::PushMessagingService::RegisterCallback& callback, | 210 const content::PushMessagingService::RegisterCallback& callback, |
| 159 const std::string& registration_id, | 211 const std::string& registration_id, |
| 160 GCMClient::Result result) { | 212 GCMClient::Result result) { |
| 213 LOG(WARNING) << "result: " << result; |
| 161 GURL endpoint = GURL("https://android.googleapis.com/gcm/send"); | 214 GURL endpoint = GURL("https://android.googleapis.com/gcm/send"); |
| 162 bool success = (result == GCMClient::SUCCESS); | 215 bool success = (result == GCMClient::SUCCESS); |
| 163 callback.Run(endpoint, registration_id, success); | 216 callback.Run(endpoint, registration_id, success); |
| 164 if (success) { | 217 if (success) { |
| 165 // TODO(johnme): Make sure the pref doesn't get out of sync after crashes. | 218 // TODO(johnme): Make sure the pref doesn't get out of sync after crashes. |
| 166 int registration_count = profile_->GetPrefs()->GetInteger( | 219 int registration_count = profile_->GetPrefs()->GetInteger( |
| 167 prefs::kPushMessagingRegistrationCount); | 220 prefs::kPushMessagingRegistrationCount); |
| 168 profile_->GetPrefs()->SetInteger(prefs::kPushMessagingRegistrationCount, | 221 profile_->GetPrefs()->SetInteger(prefs::kPushMessagingRegistrationCount, |
| 169 registration_count + 1); | 222 registration_count + 1); |
| 170 } | 223 } |
| 171 } | 224 } |
| 172 | 225 |
| 173 // TODO(johnme): Unregister should decrement the pref, and call | 226 // TODO(johnme): Unregister should decrement the pref, and call |
| 174 // RemoveAppHandler if the count drops to zero. | 227 // RemoveAppHandler if the count drops to zero. |
| 175 | 228 |
| 176 } // namespace gcm | 229 } // namespace gcm |
| OLD | NEW |