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 |