| 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/push_messaging/push_messaging_service_impl.h" | 5 #include "chrome/browser/push_messaging/push_messaging_service_impl.h" |
| 6 | 6 |
| 7 #include <bitset> | 7 #include <bitset> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/barrier_closure.h" | 10 #include "base/barrier_closure.h" |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 // Shutdown() should come before and it removes us from the list of app | 177 // Shutdown() should come before and it removes us from the list of app |
| 178 // handlers of gcm::GCMDriver so this shouldn't ever been called. | 178 // handlers of gcm::GCMDriver so this shouldn't ever been called. |
| 179 NOTREACHED(); | 179 NOTREACHED(); |
| 180 } | 180 } |
| 181 | 181 |
| 182 // OnMessage methods ----------------------------------------------------------- | 182 // OnMessage methods ----------------------------------------------------------- |
| 183 | 183 |
| 184 void PushMessagingServiceImpl::OnMessage( | 184 void PushMessagingServiceImpl::OnMessage( |
| 185 const std::string& app_id, | 185 const std::string& app_id, |
| 186 const gcm::GCMClient::IncomingMessage& message) { | 186 const gcm::GCMClient::IncomingMessage& message) { |
| 187 base::Closure message_handled_closure = |
| 188 message_callback_for_testing_.is_null() ? base::Bind(&base::DoNothing) |
| 189 : message_callback_for_testing_; |
| 187 PushMessagingApplicationId application_id = | 190 PushMessagingApplicationId application_id = |
| 188 PushMessagingApplicationId::Get(profile_, app_id); | 191 PushMessagingApplicationId::Get(profile_, app_id); |
| 189 // Drop message and unregister if app id was unknown (maybe recently deleted). | 192 // Drop message and unregister if app id was unknown (maybe recently deleted). |
| 190 if (!application_id.IsValid()) { | 193 if (!application_id.IsValid()) { |
| 191 DeliverMessageCallback(app_id, GURL::EmptyGURL(), -1, message, | 194 DeliverMessageCallback(app_id, GURL::EmptyGURL(), -1, message, |
| 195 message_handled_closure, |
| 192 content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID); | 196 content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID); |
| 193 return; | 197 return; |
| 194 } | 198 } |
| 195 // Drop message and unregister if |origin| has lost push permission. | 199 // Drop message and unregister if |origin| has lost push permission. |
| 196 if (!HasPermission(application_id.origin())) { | 200 if (!HasPermission(application_id.origin())) { |
| 197 DeliverMessageCallback(app_id, application_id.origin(), | 201 DeliverMessageCallback(app_id, application_id.origin(), |
| 198 application_id.service_worker_registration_id(), | 202 application_id.service_worker_registration_id(), |
| 199 message, | 203 message, message_handled_closure, |
| 200 content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED); | 204 content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED); |
| 201 return; | 205 return; |
| 202 } | 206 } |
| 203 | 207 |
| 204 rappor::SampleDomainAndRegistryFromGURL( | 208 rappor::SampleDomainAndRegistryFromGURL( |
| 205 g_browser_process->rappor_service(), | 209 g_browser_process->rappor_service(), |
| 206 "PushMessaging.MessageReceived.Origin", | 210 "PushMessaging.MessageReceived.Origin", |
| 207 application_id.origin()); | 211 application_id.origin()); |
| 208 | 212 |
| 209 // The Push API only exposes a single string of data in the push event fired | 213 // The Push API only exposes a single string of data in the push event fired |
| (...skipping 21 matching lines...) Expand all Loading... |
| 231 } | 235 } |
| 232 | 236 |
| 233 content::BrowserContext::DeliverPushMessage( | 237 content::BrowserContext::DeliverPushMessage( |
| 234 profile_, | 238 profile_, |
| 235 application_id.origin(), | 239 application_id.origin(), |
| 236 application_id.service_worker_registration_id(), | 240 application_id.service_worker_registration_id(), |
| 237 data, | 241 data, |
| 238 base::Bind(&PushMessagingServiceImpl::DeliverMessageCallback, | 242 base::Bind(&PushMessagingServiceImpl::DeliverMessageCallback, |
| 239 weak_factory_.GetWeakPtr(), | 243 weak_factory_.GetWeakPtr(), |
| 240 application_id.app_id_guid(), application_id.origin(), | 244 application_id.app_id_guid(), application_id.origin(), |
| 241 application_id.service_worker_registration_id(), message)); | 245 application_id.service_worker_registration_id(), message, |
| 246 message_handled_closure)); |
| 242 } | 247 } |
| 243 | 248 |
| 244 void PushMessagingServiceImpl::DeliverMessageCallback( | 249 void PushMessagingServiceImpl::DeliverMessageCallback( |
| 245 const std::string& app_id_guid, | 250 const std::string& app_id_guid, |
| 246 const GURL& requesting_origin, | 251 const GURL& requesting_origin, |
| 247 int64 service_worker_registration_id, | 252 int64 service_worker_registration_id, |
| 248 const gcm::GCMClient::IncomingMessage& message, | 253 const gcm::GCMClient::IncomingMessage& message, |
| 254 const base::Closure& message_handled_closure, |
| 249 content::PushDeliveryStatus status) { | 255 content::PushDeliveryStatus status) { |
| 250 // TODO(mvanouwerkerk): Show a warning in the developer console of the | 256 // TODO(mvanouwerkerk): Show a warning in the developer console of the |
| 251 // Service Worker corresponding to app_id (and/or on an internals page). | 257 // Service Worker corresponding to app_id (and/or on an internals page). |
| 252 // TODO(mvanouwerkerk): Is there a way to recover from failure? | 258 // TODO(mvanouwerkerk): Is there a way to recover from failure? |
| 253 switch (status) { | 259 switch (status) { |
| 254 // Call RequireUserVisibleUX if the message was delivered to the Service | 260 // Call RequireUserVisibleUX if the message was delivered to the Service |
| 255 // Worker JS, even if the website's event handler failed (to prevent sites | 261 // Worker JS, even if the website's event handler failed (to prevent sites |
| 256 // deliberately failing in order to avoid having to show notifications). | 262 // deliberately failing in order to avoid having to show notifications). |
| 257 case content::PUSH_DELIVERY_STATUS_SUCCESS: | 263 case content::PUSH_DELIVERY_STATUS_SUCCESS: |
| 258 case content::PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED: | 264 case content::PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED: |
| 259 RequireUserVisibleUX(requesting_origin, service_worker_registration_id); | 265 RequireUserVisibleUX(requesting_origin, service_worker_registration_id, |
| 266 message_handled_closure); |
| 260 break; | 267 break; |
| 261 case content::PUSH_DELIVERY_STATUS_INVALID_MESSAGE: | 268 case content::PUSH_DELIVERY_STATUS_INVALID_MESSAGE: |
| 262 case content::PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR: | 269 case content::PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR: |
| 270 message_handled_closure.Run(); |
| 263 break; | 271 break; |
| 264 case content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID: | 272 case content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID: |
| 265 case content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED: | 273 case content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED: |
| 266 case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER: | 274 case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER: |
| 267 Unregister(app_id_guid, message.sender_id, UnregisterCallback()); | 275 Unregister(app_id_guid, message.sender_id, |
| 276 base::Bind(&UnregisterCallbackToClosure, |
| 277 message_handled_closure)); |
| 268 break; | 278 break; |
| 269 } | 279 } |
| 270 RecordDeliveryStatus(status); | 280 RecordDeliveryStatus(status); |
| 271 } | 281 } |
| 272 | 282 |
| 273 void PushMessagingServiceImpl::RequireUserVisibleUX( | 283 void PushMessagingServiceImpl::RequireUserVisibleUX( |
| 274 const GURL& requesting_origin, int64 service_worker_registration_id) { | 284 const GURL& requesting_origin, int64 service_worker_registration_id, |
| 285 const base::Closure& message_handled_closure) { |
| 275 #if defined(ENABLE_NOTIFICATIONS) | 286 #if defined(ENABLE_NOTIFICATIONS) |
| 276 // TODO(johnme): Relax this heuristic slightly. | 287 // TODO(johnme): Relax this heuristic slightly. |
| 277 PlatformNotificationServiceImpl* notification_service = | 288 PlatformNotificationServiceImpl* notification_service = |
| 278 PlatformNotificationServiceImpl::GetInstance(); | 289 PlatformNotificationServiceImpl::GetInstance(); |
| 279 // Can't use g_browser_process->notification_ui_manager(), since the test uses | 290 // Can't use g_browser_process->notification_ui_manager(), since the test uses |
| 280 // PlatformNotificationServiceImpl::SetNotificationUIManagerForTesting. | 291 // PlatformNotificationServiceImpl::SetNotificationUIManagerForTesting. |
| 281 // TODO(peter): Remove the need to use both APIs here once Notification.get() | 292 // TODO(peter): Remove the need to use both APIs here once Notification.get() |
| 282 // is supported. | 293 // is supported. |
| 283 int notification_count = notification_service->GetNotificationUIManager()-> | 294 int notification_count = notification_service->GetNotificationUIManager()-> |
| 284 GetAllIdsByProfileAndSourceOrigin(profile_, requesting_origin).size(); | 295 GetAllIdsByProfileAndSourceOrigin(profile_, requesting_origin).size(); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 if (notification_shown || notification_needed) { | 346 if (notification_shown || notification_needed) { |
| 336 content::ServiceWorkerContext* service_worker_context = | 347 content::ServiceWorkerContext* service_worker_context = |
| 337 content::BrowserContext::GetStoragePartitionForSite( | 348 content::BrowserContext::GetStoragePartitionForSite( |
| 338 profile_, requesting_origin)->GetServiceWorkerContext(); | 349 profile_, requesting_origin)->GetServiceWorkerContext(); |
| 339 | 350 |
| 340 GetNotificationsShownByLastFewPushes( | 351 GetNotificationsShownByLastFewPushes( |
| 341 service_worker_context, service_worker_registration_id, | 352 service_worker_context, service_worker_registration_id, |
| 342 base::Bind(&PushMessagingServiceImpl::DidGetNotificationsShown, | 353 base::Bind(&PushMessagingServiceImpl::DidGetNotificationsShown, |
| 343 weak_factory_.GetWeakPtr(), | 354 weak_factory_.GetWeakPtr(), |
| 344 requesting_origin, service_worker_registration_id, | 355 requesting_origin, service_worker_registration_id, |
| 345 notification_shown, notification_needed)); | 356 notification_shown, notification_needed, |
| 357 message_handled_closure)); |
| 346 } else { | 358 } else { |
| 347 RecordUserVisibleStatus( | 359 RecordUserVisibleStatus( |
| 348 content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_AND_NOT_SHOWN); | 360 content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_AND_NOT_SHOWN); |
| 361 message_handled_closure.Run(); |
| 349 } | 362 } |
| 363 #else |
| 364 message_handled_closure.Run(); |
| 350 #endif // defined(ENABLE_NOTIFICATIONS) | 365 #endif // defined(ENABLE_NOTIFICATIONS) |
| 351 } | 366 } |
| 352 | 367 |
| 353 static void IgnoreResult(bool unused) { | 368 static void IgnoreResult(bool unused) { |
| 354 } | 369 } |
| 355 | 370 |
| 356 void PushMessagingServiceImpl::DidGetNotificationsShown( | 371 void PushMessagingServiceImpl::DidGetNotificationsShown( |
| 357 const GURL& requesting_origin, int64 service_worker_registration_id, | 372 const GURL& requesting_origin, int64 service_worker_registration_id, |
| 358 bool notification_shown, bool notification_needed, | 373 bool notification_shown, bool notification_needed, |
| 374 const base::Closure& message_handled_closure, |
| 359 const std::string& data, bool success, bool not_found) { | 375 const std::string& data, bool success, bool not_found) { |
| 360 content::ServiceWorkerContext* service_worker_context = | 376 content::ServiceWorkerContext* service_worker_context = |
| 361 content::BrowserContext::GetStoragePartitionForSite( | 377 content::BrowserContext::GetStoragePartitionForSite( |
| 362 profile_, requesting_origin)->GetServiceWorkerContext(); | 378 profile_, requesting_origin)->GetServiceWorkerContext(); |
| 363 | 379 |
| 364 // We remember whether the last (up to) 10 pushes showed notifications. | 380 // We remember whether the last (up to) 10 pushes showed notifications. |
| 365 const size_t MISSED_NOTIFICATIONS_LENGTH = 10; | 381 const size_t MISSED_NOTIFICATIONS_LENGTH = 10; |
| 366 // data is a string like "0001000", where '0' means shown, and '1' means | 382 // data is a string like "0001000", where '0' means shown, and '1' means |
| 367 // needed but not shown. We manipulate it in bitset form. | 383 // needed but not shown. We manipulate it in bitset form. |
| 368 std::bitset<MISSED_NOTIFICATIONS_LENGTH> missed_notifications(data); | 384 std::bitset<MISSED_NOTIFICATIONS_LENGTH> missed_notifications(data); |
| 369 | 385 |
| 370 bool needed_but_not_shown = notification_needed && !notification_shown; | 386 bool needed_but_not_shown = notification_needed && !notification_shown; |
| 371 | 387 |
| 372 // New entries go at the end, and old ones are shifted off the beginning once | 388 // New entries go at the end, and old ones are shifted off the beginning once |
| 373 // the history length is exceeded. | 389 // the history length is exceeded. |
| 374 missed_notifications <<= 1; | 390 missed_notifications <<= 1; |
| 375 missed_notifications[0] = needed_but_not_shown; | 391 missed_notifications[0] = needed_but_not_shown; |
| 376 std::string updated_data(missed_notifications. | 392 std::string updated_data(missed_notifications. |
| 377 to_string<char, std::string::traits_type, std::string::allocator_type>()); | 393 to_string<char, std::string::traits_type, std::string::allocator_type>()); |
| 378 SetNotificationsShownByLastFewPushes( | 394 SetNotificationsShownByLastFewPushes( |
| 379 service_worker_context, service_worker_registration_id, | 395 service_worker_context, service_worker_registration_id, |
| 380 requesting_origin, updated_data, | 396 requesting_origin, updated_data, |
| 381 base::Bind(&IgnoreResult)); // This is a heuristic; ignore failure. | 397 base::Bind(&IgnoreResult)); // This is a heuristic; ignore failure. |
| 382 | 398 |
| 383 if (notification_shown) { | 399 if (notification_shown) { |
| 384 RecordUserVisibleStatus( | 400 RecordUserVisibleStatus( |
| 385 notification_needed | 401 notification_needed |
| 386 ? content::PUSH_USER_VISIBLE_STATUS_REQUIRED_AND_SHOWN | 402 ? content::PUSH_USER_VISIBLE_STATUS_REQUIRED_AND_SHOWN |
| 387 : content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_BUT_SHOWN); | 403 : content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_BUT_SHOWN); |
| 404 message_handled_closure.Run(); |
| 388 return; | 405 return; |
| 389 } | 406 } |
| 390 if (needed_but_not_shown) { | 407 if (needed_but_not_shown) { |
| 391 if (missed_notifications.count() <= 1) { // apply grace | 408 if (missed_notifications.count() <= 1) { // apply grace |
| 392 RecordUserVisibleStatus( | 409 RecordUserVisibleStatus( |
| 393 content::PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_USED_GRACE); | 410 content::PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_USED_GRACE); |
| 411 message_handled_closure.Run(); |
| 394 return; | 412 return; |
| 395 } | 413 } |
| 396 RecordUserVisibleStatus( | 414 RecordUserVisibleStatus( |
| 397 content:: | 415 content:: |
| 398 PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_GRACE_EXCEEDED); | 416 PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_GRACE_EXCEEDED); |
| 399 rappor::SampleDomainAndRegistryFromGURL( | 417 rappor::SampleDomainAndRegistryFromGURL( |
| 400 g_browser_process->rappor_service(), | 418 g_browser_process->rappor_service(), |
| 401 "PushMessaging.GenericNotificationShown.Origin", | 419 "PushMessaging.GenericNotificationShown.Origin", |
| 402 requesting_origin); | 420 requesting_origin); |
| 403 // The site failed to show a notification when one was needed, and they have | 421 // The site failed to show a notification when one was needed, and they have |
| (...skipping 12 matching lines...) Expand all Loading... |
| 416 notification_data.icon = GURL(); // TODO(johnme): Better icon? | 434 notification_data.icon = GURL(); // TODO(johnme): Better icon? |
| 417 notification_data.silent = true; | 435 notification_data.silent = true; |
| 418 PlatformNotificationServiceImpl* notification_service = | 436 PlatformNotificationServiceImpl* notification_service = |
| 419 PlatformNotificationServiceImpl::GetInstance(); | 437 PlatformNotificationServiceImpl::GetInstance(); |
| 420 notification_service->DisplayPersistentNotification( | 438 notification_service->DisplayPersistentNotification( |
| 421 profile_, | 439 profile_, |
| 422 service_worker_registration_id, | 440 service_worker_registration_id, |
| 423 requesting_origin, | 441 requesting_origin, |
| 424 SkBitmap() /* icon */, | 442 SkBitmap() /* icon */, |
| 425 notification_data); | 443 notification_data); |
| 444 message_handled_closure.Run(); |
| 426 } | 445 } |
| 427 } | 446 } |
| 428 | 447 |
| 448 void PushMessagingServiceImpl::SetMessageCallbackForTesting( |
| 449 const base::Closure& callback) { |
| 450 message_callback_for_testing_ = callback; |
| 451 } |
| 452 |
| 429 // Other gcm::GCMAppHandler methods ------------------------------------------- | 453 // Other gcm::GCMAppHandler methods ------------------------------------------- |
| 430 | 454 |
| 431 void PushMessagingServiceImpl::OnMessagesDeleted(const std::string& app_id) { | 455 void PushMessagingServiceImpl::OnMessagesDeleted(const std::string& app_id) { |
| 432 // TODO(mvanouwerkerk): Fire push error event on the Service Worker | 456 // TODO(mvanouwerkerk): Fire push error event on the Service Worker |
| 433 // corresponding to app_id. | 457 // corresponding to app_id. |
| 434 } | 458 } |
| 435 | 459 |
| 436 void PushMessagingServiceImpl::OnSendError( | 460 void PushMessagingServiceImpl::OnSendError( |
| 437 const std::string& app_id, | 461 const std::string& app_id, |
| 438 const gcm::GCMClient::SendErrorDetails& send_error_details) { | 462 const gcm::GCMClient::SendErrorDetails& send_error_details) { |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 796 CONTENT_SETTING_ALLOW; | 820 CONTENT_SETTING_ALLOW; |
| 797 } | 821 } |
| 798 | 822 |
| 799 gcm::GCMDriver* PushMessagingServiceImpl::GetGCMDriver() const { | 823 gcm::GCMDriver* PushMessagingServiceImpl::GetGCMDriver() const { |
| 800 gcm::GCMProfileService* gcm_profile_service = | 824 gcm::GCMProfileService* gcm_profile_service = |
| 801 gcm::GCMProfileServiceFactory::GetForProfile(profile_); | 825 gcm::GCMProfileServiceFactory::GetForProfile(profile_); |
| 802 CHECK(gcm_profile_service); | 826 CHECK(gcm_profile_service); |
| 803 CHECK(gcm_profile_service->driver()); | 827 CHECK(gcm_profile_service->driver()); |
| 804 return gcm_profile_service->driver(); | 828 return gcm_profile_service->driver(); |
| 805 } | 829 } |
| OLD | NEW |