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 "components/gcm_driver/gcm_client_impl.h" | 5 #include "components/gcm_driver/gcm_client_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
11 #include "base/message_loop/message_loop.h" | 11 #include "base/message_loop/message_loop.h" |
12 #include "base/metrics/histogram_macros.h" | 12 #include "base/metrics/histogram_macros.h" |
13 #include "base/sequenced_task_runner.h" | 13 #include "base/sequenced_task_runner.h" |
14 #include "base/stl_util.h" | 14 #include "base/stl_util.h" |
15 #include "base/strings/string_number_conversions.h" | 15 #include "base/strings/string_number_conversions.h" |
16 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
17 #include "base/time/default_clock.h" | 17 #include "base/time/default_clock.h" |
18 #include "base/timer/timer.h" | 18 #include "base/timer/timer.h" |
19 #include "components/gcm_driver/gcm_account_mapper.h" | 19 #include "components/gcm_driver/gcm_account_mapper.h" |
20 #include "components/gcm_driver/gcm_backoff_policy.h" | 20 #include "components/gcm_driver/gcm_backoff_policy.h" |
21 #include "google_apis/gcm/base/encryptor.h" | 21 #include "google_apis/gcm/base/encryptor.h" |
22 #include "google_apis/gcm/base/mcs_message.h" | 22 #include "google_apis/gcm/base/mcs_message.h" |
23 #include "google_apis/gcm/base/mcs_util.h" | 23 #include "google_apis/gcm/base/mcs_util.h" |
24 #include "google_apis/gcm/engine/checkin_request.h" | 24 #include "google_apis/gcm/engine/checkin_request.h" |
25 #include "google_apis/gcm/engine/connection_factory_impl.h" | 25 #include "google_apis/gcm/engine/connection_factory_impl.h" |
| 26 #include "google_apis/gcm/engine/gcm_registration_request.h" |
26 #include "google_apis/gcm/engine/gcm_store_impl.h" | 27 #include "google_apis/gcm/engine/gcm_store_impl.h" |
| 28 #include "google_apis/gcm/engine/gcm_unregistration_request.h" |
| 29 #include "google_apis/gcm/engine/instance_id_delete_token_request.h" |
| 30 #include "google_apis/gcm/engine/instance_id_get_token_request.h" |
27 #include "google_apis/gcm/monitoring/gcm_stats_recorder.h" | 31 #include "google_apis/gcm/monitoring/gcm_stats_recorder.h" |
28 #include "google_apis/gcm/protocol/checkin.pb.h" | 32 #include "google_apis/gcm/protocol/checkin.pb.h" |
29 #include "google_apis/gcm/protocol/mcs.pb.h" | 33 #include "google_apis/gcm/protocol/mcs.pb.h" |
30 #include "net/http/http_network_session.h" | 34 #include "net/http/http_network_session.h" |
31 #include "net/http/http_transaction_factory.h" | 35 #include "net/http/http_transaction_factory.h" |
32 #include "net/url_request/url_request_context.h" | 36 #include "net/url_request/url_request_context.h" |
33 #include "url/gurl.h" | 37 #include "url/gurl.h" |
34 | 38 |
35 namespace gcm { | 39 namespace gcm { |
36 | 40 |
(...skipping 23 matching lines...) Expand all Loading... |
60 | 64 |
61 enum ResetStoreError { | 65 enum ResetStoreError { |
62 DESTROYING_STORE_FAILED, | 66 DESTROYING_STORE_FAILED, |
63 INFINITE_STORE_RESET, | 67 INFINITE_STORE_RESET, |
64 // NOTE: always keep this entry at the end. Add new value only immediately | 68 // NOTE: always keep this entry at the end. Add new value only immediately |
65 // above this line. Make sure to update the corresponding histogram enum | 69 // above this line. Make sure to update the corresponding histogram enum |
66 // accordingly. | 70 // accordingly. |
67 RESET_STORE_ERROR_COUNT | 71 RESET_STORE_ERROR_COUNT |
68 }; | 72 }; |
69 | 73 |
| 74 const char kGCMScope[] = "GCM"; |
70 const int kMaxRegistrationRetries = 5; | 75 const int kMaxRegistrationRetries = 5; |
71 const char kMessageTypeDataMessage[] = "gcm"; | 76 const char kMessageTypeDataMessage[] = "gcm"; |
72 const char kMessageTypeDeletedMessagesKey[] = "deleted_messages"; | 77 const char kMessageTypeDeletedMessagesKey[] = "deleted_messages"; |
73 const char kMessageTypeKey[] = "message_type"; | 78 const char kMessageTypeKey[] = "message_type"; |
74 const char kMessageTypeSendErrorKey[] = "send_error"; | 79 const char kMessageTypeSendErrorKey[] = "send_error"; |
75 const char kSendErrorMessageIdKey[] = "google.message_id"; | 80 const char kSendErrorMessageIdKey[] = "google.message_id"; |
76 const char kSendMessageFromValue[] = "gcm@chrome.com"; | 81 const char kSendMessageFromValue[] = "gcm@chrome.com"; |
77 const int64 kDefaultUserSerialNumber = 0LL; | 82 const int64 kDefaultUserSerialNumber = 0LL; |
78 | 83 |
79 GCMClient::Result ToGCMClientResult(MCSClient::MessageSendStatus status) { | 84 GCMClient::Result ToGCMClientResult(MCSClient::MessageSendStatus status) { |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
162 MessageType DecodeMessageType(const std::string& value) { | 167 MessageType DecodeMessageType(const std::string& value) { |
163 if (kMessageTypeDeletedMessagesKey == value) | 168 if (kMessageTypeDeletedMessagesKey == value) |
164 return DELETED_MESSAGES; | 169 return DELETED_MESSAGES; |
165 if (kMessageTypeSendErrorKey == value) | 170 if (kMessageTypeSendErrorKey == value) |
166 return SEND_ERROR; | 171 return SEND_ERROR; |
167 if (kMessageTypeDataMessage == value) | 172 if (kMessageTypeDataMessage == value) |
168 return DATA_MESSAGE; | 173 return DATA_MESSAGE; |
169 return UNKNOWN; | 174 return UNKNOWN; |
170 } | 175 } |
171 | 176 |
| 177 int ConstructGCMVersion(const std::string& chrome_version) { |
| 178 // Major Chrome version is passed as GCM version. |
| 179 size_t pos = chrome_version.find('.'); |
| 180 if (pos == std::string::npos) { |
| 181 NOTREACHED(); |
| 182 return 0; |
| 183 } |
| 184 |
| 185 int gcm_version = 0; |
| 186 base::StringToInt( |
| 187 base::StringPiece(chrome_version.c_str(), pos), &gcm_version); |
| 188 return gcm_version; |
| 189 } |
| 190 |
| 191 std::string SerializeInstanceIDData(const std::string& instance_id, |
| 192 const std::string& extra_data) { |
| 193 DCHECK(!instance_id.empty() && !extra_data.empty()); |
| 194 DCHECK(instance_id.find(',') == std::string::npos); |
| 195 return instance_id + "," + extra_data; |
| 196 } |
| 197 |
| 198 bool DeserializeInstanceIDData(const std::string& serialized_data, |
| 199 std::string* instance_id, |
| 200 std::string* extra_data) { |
| 201 DCHECK(instance_id && extra_data); |
| 202 std::size_t pos = serialized_data.find(','); |
| 203 if (pos == std::string::npos) |
| 204 return false; |
| 205 *instance_id = serialized_data.substr(0, pos); |
| 206 *extra_data = serialized_data.substr(pos + 1); |
| 207 return !instance_id->empty() && !extra_data->empty(); |
| 208 } |
| 209 |
172 void RecordOutgoingMessageToUMA( | 210 void RecordOutgoingMessageToUMA( |
173 const gcm::GCMClient::OutgoingMessage& message) { | 211 const gcm::GCMClient::OutgoingMessage& message) { |
174 OutgoingMessageTTLCategory ttl_category; | 212 OutgoingMessageTTLCategory ttl_category; |
175 if (message.time_to_live == 0) | 213 if (message.time_to_live == 0) |
176 ttl_category = TTL_ZERO; | 214 ttl_category = TTL_ZERO; |
177 else if (message.time_to_live <= 60 ) | 215 else if (message.time_to_live <= 60 ) |
178 ttl_category = TTL_LESS_THAN_OR_EQUAL_TO_ONE_MINUTE; | 216 ttl_category = TTL_LESS_THAN_OR_EQUAL_TO_ONE_MINUTE; |
179 else if (message.time_to_live <= 60 * 60) | 217 else if (message.time_to_live <= 60 * 60) |
180 ttl_category = TTL_LESS_THAN_OR_EQUAL_TO_ONE_HOUR; | 218 ttl_category = TTL_LESS_THAN_OR_EQUAL_TO_ONE_HOUR; |
181 else if (message.time_to_live <= 24 * 60 * 60) | 219 else if (message.time_to_live <= 24 * 60 * 60) |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 | 366 |
329 void GCMClientImpl::OnLoadCompleted(scoped_ptr<GCMStore::LoadResult> result) { | 367 void GCMClientImpl::OnLoadCompleted(scoped_ptr<GCMStore::LoadResult> result) { |
330 DCHECK_EQ(LOADING, state_); | 368 DCHECK_EQ(LOADING, state_); |
331 | 369 |
332 if (!result->success) { | 370 if (!result->success) { |
333 ResetStore(); | 371 ResetStore(); |
334 return; | 372 return; |
335 } | 373 } |
336 gcm_store_reset_ = false; | 374 gcm_store_reset_ = false; |
337 | 375 |
338 registrations_ = result->registrations; | |
339 device_checkin_info_.android_id = result->device_android_id; | 376 device_checkin_info_.android_id = result->device_android_id; |
340 device_checkin_info_.secret = result->device_security_token; | 377 device_checkin_info_.secret = result->device_security_token; |
341 device_checkin_info_.last_checkin_accounts = result->last_checkin_accounts; | 378 device_checkin_info_.last_checkin_accounts = result->last_checkin_accounts; |
342 // A case where there were previously no accounts reported with checkin is | 379 // A case where there were previously no accounts reported with checkin is |
343 // considered to be the same as when the list of accounts is empty. It enables | 380 // considered to be the same as when the list of accounts is empty. It enables |
344 // scheduling a periodic checkin for devices with no signed in users | 381 // scheduling a periodic checkin for devices with no signed in users |
345 // immediately after restart, while keeping |accounts_set == false| delays the | 382 // immediately after restart, while keeping |accounts_set == false| delays the |
346 // checkin until the list of accounts is set explicitly. | 383 // checkin until the list of accounts is set explicitly. |
347 if (result->last_checkin_accounts.size() == 0) | 384 if (result->last_checkin_accounts.size() == 0) |
348 device_checkin_info_.accounts_set = true; | 385 device_checkin_info_.accounts_set = true; |
349 last_checkin_time_ = result->last_checkin_time; | 386 last_checkin_time_ = result->last_checkin_time; |
350 gservices_settings_.UpdateFromLoadResult(*result); | 387 gservices_settings_.UpdateFromLoadResult(*result); |
351 instance_id_data_ = result->instance_id_data; | 388 |
| 389 for (auto iter = result->registrations.begin(); |
| 390 iter != result->registrations.end(); |
| 391 ++iter) { |
| 392 std::string registration_id; |
| 393 scoped_ptr<RegistrationInfo> registration = |
| 394 RegistrationInfo::BuildFromString( |
| 395 iter->first, iter->second, ®istration_id); |
| 396 // TODO(jianli): Add UMA to track the error case. |
| 397 if (registration.get()) |
| 398 registrations_[make_linked_ptr(registration.release())] = registration_id; |
| 399 } |
| 400 |
| 401 for (auto iter = result->instance_id_data.begin(); |
| 402 iter != result->instance_id_data.end(); |
| 403 ++iter) { |
| 404 std::string instance_id; |
| 405 std::string extra_data; |
| 406 if (DeserializeInstanceIDData(iter->second, &instance_id, &extra_data)) |
| 407 instance_id_data_[iter->first] = std::make_pair(instance_id, extra_data); |
| 408 } |
| 409 |
352 load_result_ = result.Pass(); | 410 load_result_ = result.Pass(); |
353 state_ = LOADED; | 411 state_ = LOADED; |
354 | 412 |
355 // Don't initiate the GCM connection when GCM is in delayed start mode and | 413 // Don't initiate the GCM connection when GCM is in delayed start mode and |
356 // not any standalone app has registered GCM yet. | 414 // not any standalone app has registered GCM yet. |
357 if (start_mode_ == DELAYED_START && !HasStandaloneRegisteredApp()) | 415 if (start_mode_ == DELAYED_START && !HasStandaloneRegisteredApp()) |
358 return; | 416 return; |
359 | 417 |
360 StartGCM(); | 418 StartGCM(); |
361 } | 419 } |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
525 base::Bind(&GCMClientImpl::IgnoreWriteResultCallback, | 583 base::Bind(&GCMClientImpl::IgnoreWriteResultCallback, |
526 weak_ptr_factory_.GetWeakPtr())); | 584 weak_ptr_factory_.GetWeakPtr())); |
527 } | 585 } |
528 | 586 |
529 void GCMClientImpl::UpdateHeartbeatTimer(scoped_ptr<base::Timer> timer) { | 587 void GCMClientImpl::UpdateHeartbeatTimer(scoped_ptr<base::Timer> timer) { |
530 DCHECK(mcs_client_); | 588 DCHECK(mcs_client_); |
531 mcs_client_->UpdateHeartbeatTimer(timer.Pass()); | 589 mcs_client_->UpdateHeartbeatTimer(timer.Pass()); |
532 } | 590 } |
533 | 591 |
534 void GCMClientImpl::AddInstanceIDData(const std::string& app_id, | 592 void GCMClientImpl::AddInstanceIDData(const std::string& app_id, |
535 const std::string& instance_id_data) { | 593 const std::string& instance_id, |
536 instance_id_data_[app_id] = instance_id_data; | 594 const std::string& extra_data) { |
| 595 instance_id_data_[app_id] = std::make_pair(instance_id, extra_data); |
537 gcm_store_->AddInstanceIDData( | 596 gcm_store_->AddInstanceIDData( |
538 app_id, | 597 app_id, |
539 instance_id_data, | 598 SerializeInstanceIDData(instance_id, extra_data), |
540 base::Bind(&GCMClientImpl::IgnoreWriteResultCallback, | 599 base::Bind(&GCMClientImpl::IgnoreWriteResultCallback, |
541 weak_ptr_factory_.GetWeakPtr())); | 600 weak_ptr_factory_.GetWeakPtr())); |
542 } | 601 } |
543 | 602 |
544 void GCMClientImpl::RemoveInstanceIDData(const std::string& app_id) { | 603 void GCMClientImpl::RemoveInstanceIDData(const std::string& app_id) { |
545 instance_id_data_.erase(app_id); | 604 instance_id_data_.erase(app_id); |
546 gcm_store_->RemoveInstanceIDData( | 605 gcm_store_->RemoveInstanceIDData( |
547 app_id, | 606 app_id, |
548 base::Bind(&GCMClientImpl::IgnoreWriteResultCallback, | 607 base::Bind(&GCMClientImpl::IgnoreWriteResultCallback, |
549 weak_ptr_factory_.GetWeakPtr())); | 608 weak_ptr_factory_.GetWeakPtr())); |
550 } | 609 } |
551 | 610 |
552 std::string GCMClientImpl::GetInstanceIDData(const std::string& app_id) { | 611 void GCMClientImpl::GetInstanceIDData(const std::string& app_id, |
| 612 std::string* instance_id, |
| 613 std::string* extra_data) { |
| 614 DCHECK(instance_id && extra_data); |
| 615 |
553 auto iter = instance_id_data_.find(app_id); | 616 auto iter = instance_id_data_.find(app_id); |
554 if (iter == instance_id_data_.end()) | 617 if (iter == instance_id_data_.end()) |
555 return std::string(); | 618 return; |
556 return iter->second; | 619 *instance_id = iter->second.first; |
| 620 *extra_data = iter->second.second; |
557 } | 621 } |
558 | 622 |
559 void GCMClientImpl::AddHeartbeatInterval(const std::string& scope, | 623 void GCMClientImpl::AddHeartbeatInterval(const std::string& scope, |
560 int interval_ms) { | 624 int interval_ms) { |
561 DCHECK(mcs_client_); | 625 DCHECK(mcs_client_); |
562 mcs_client_->AddHeartbeatInterval(scope, interval_ms); | 626 mcs_client_->AddHeartbeatInterval(scope, interval_ms); |
563 } | 627 } |
564 | 628 |
565 void GCMClientImpl::RemoveHeartbeatInterval(const std::string& scope) { | 629 void GCMClientImpl::RemoveHeartbeatInterval(const std::string& scope) { |
566 DCHECK(mcs_client_); | 630 DCHECK(mcs_client_); |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
714 delegate_->OnDisconnected(); | 778 delegate_->OnDisconnected(); |
715 mcs_client_.reset(); | 779 mcs_client_.reset(); |
716 checkin_request_.reset(); | 780 checkin_request_.reset(); |
717 // Delete all of the pending registration and unregistration requests. | 781 // Delete all of the pending registration and unregistration requests. |
718 STLDeleteValues(&pending_registration_requests_); | 782 STLDeleteValues(&pending_registration_requests_); |
719 STLDeleteValues(&pending_unregistration_requests_); | 783 STLDeleteValues(&pending_unregistration_requests_); |
720 state_ = INITIALIZED; | 784 state_ = INITIALIZED; |
721 gcm_store_->Close(); | 785 gcm_store_->Close(); |
722 } | 786 } |
723 | 787 |
724 void GCMClientImpl::Register(const std::string& app_id, | 788 void GCMClientImpl::Register( |
725 const std::vector<std::string>& sender_ids) { | 789 const linked_ptr<RegistrationInfo>& registration_info) { |
726 DCHECK_EQ(state_, READY); | 790 DCHECK_EQ(state_, READY); |
727 | 791 |
728 // If the same sender ids is provided, return the cached registration ID | 792 // Find and use the cached registration ID. |
729 // directly. | |
730 RegistrationInfoMap::const_iterator registrations_iter = | 793 RegistrationInfoMap::const_iterator registrations_iter = |
731 registrations_.find(app_id); | 794 registrations_.find(registration_info); |
732 if (registrations_iter != registrations_.end() && | 795 if (registrations_iter != registrations_.end()) { |
733 registrations_iter->second->sender_ids == sender_ids) { | 796 bool matched = true; |
734 delegate_->OnRegisterFinished( | 797 |
735 app_id, registrations_iter->second->registration_id, SUCCESS); | 798 // For GCM registration, we also match the sender IDs since multiple |
736 return; | 799 // registrations are not supported. |
| 800 const GCMRegistrationInfo* gcm_registration_info = |
| 801 GCMRegistrationInfo::FromRegistrationInfo(registration_info.get()); |
| 802 if (gcm_registration_info) { |
| 803 const GCMRegistrationInfo* cached_gcm_registration_info = |
| 804 GCMRegistrationInfo::FromRegistrationInfo( |
| 805 registrations_iter->first.get()); |
| 806 DCHECK(cached_gcm_registration_info); |
| 807 if (cached_gcm_registration_info && |
| 808 gcm_registration_info->sender_ids != |
| 809 cached_gcm_registration_info->sender_ids) { |
| 810 matched = false; |
| 811 } |
| 812 } |
| 813 |
| 814 if (matched) { |
| 815 delegate_->OnRegisterFinished( |
| 816 registration_info, registrations_iter->second, SUCCESS); |
| 817 return; |
| 818 } |
737 } | 819 } |
738 | 820 |
739 RegistrationRequest::RequestInfo request_info( | 821 RegistrationRequest::RequestInfo request_info( |
740 device_checkin_info_.android_id, | 822 device_checkin_info_.android_id, |
741 device_checkin_info_.secret, | 823 device_checkin_info_.secret, |
742 app_id, | 824 registration_info->app_id); |
743 sender_ids); | |
744 DCHECK_EQ(0u, pending_registration_requests_.count(app_id)); | |
745 | 825 |
746 RegistrationRequest* registration_request = | 826 RegistrationRequest* registration_request = NULL; |
747 new RegistrationRequest(gservices_settings_.GetRegistrationURL(), | 827 |
748 request_info, | 828 const GCMRegistrationInfo* gcm_registration_info = |
749 GetGCMBackoffPolicy(), | 829 GCMRegistrationInfo::FromRegistrationInfo(registration_info.get()); |
750 base::Bind(&GCMClientImpl::OnRegisterCompleted, | 830 if (gcm_registration_info) { |
751 weak_ptr_factory_.GetWeakPtr(), | 831 GCMRegistrationRequest::ExtraRequestInfo extra_request_info( |
752 app_id, | 832 gcm_registration_info->sender_ids); |
753 sender_ids), | 833 |
754 kMaxRegistrationRetries, | 834 registration_request = new GCMRegistrationRequest( |
755 url_request_context_getter_, | 835 gservices_settings_.GetRegistrationURL(), |
756 &recorder_); | 836 request_info, |
757 pending_registration_requests_[app_id] = registration_request; | 837 extra_request_info, |
| 838 GetGCMBackoffPolicy(), |
| 839 base::Bind(&GCMClientImpl::OnRegisterCompleted, |
| 840 weak_ptr_factory_.GetWeakPtr(), |
| 841 registration_info), |
| 842 kMaxRegistrationRetries, |
| 843 url_request_context_getter_, |
| 844 &recorder_); |
| 845 } |
| 846 |
| 847 const InstanceIDTokenInfo* instance_id_token_info = |
| 848 InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get()); |
| 849 if (instance_id_token_info) { |
| 850 auto instance_id_iter = instance_id_data_.find(registration_info->app_id); |
| 851 DCHECK(instance_id_iter != instance_id_data_.end()); |
| 852 |
| 853 InstanceIDGetTokenRequest::ExtraRequestInfo extra_request_info( |
| 854 instance_id_iter->second.first, |
| 855 instance_id_token_info->authorized_entity, |
| 856 instance_id_token_info->scope, |
| 857 ConstructGCMVersion(chrome_build_info_.version), |
| 858 instance_id_token_info->options); |
| 859 registration_request = new InstanceIDGetTokenRequest( |
| 860 gservices_settings_.GetRegistrationURL(), |
| 861 request_info, |
| 862 extra_request_info, |
| 863 GetGCMBackoffPolicy(), |
| 864 base::Bind(&GCMClientImpl::OnRegisterCompleted, |
| 865 weak_ptr_factory_.GetWeakPtr(), |
| 866 registration_info), |
| 867 kMaxRegistrationRetries, |
| 868 url_request_context_getter_, |
| 869 &recorder_); |
| 870 } |
| 871 |
| 872 DCHECK(registration_request); |
| 873 pending_registration_requests_[registration_info] = registration_request; |
758 registration_request->Start(); | 874 registration_request->Start(); |
759 } | 875 } |
760 | 876 |
761 void GCMClientImpl::OnRegisterCompleted( | 877 void GCMClientImpl::OnRegisterCompleted( |
762 const std::string& app_id, | 878 const linked_ptr<RegistrationInfo>& registration_info, |
763 const std::vector<std::string>& sender_ids, | |
764 RegistrationRequest::Status status, | 879 RegistrationRequest::Status status, |
765 const std::string& registration_id) { | 880 const std::string& registration_id) { |
766 DCHECK(delegate_); | 881 DCHECK(delegate_); |
767 | 882 |
768 Result result; | 883 Result result; |
769 PendingRegistrationRequests::iterator iter = | 884 PendingRegistrationRequests::iterator iter = |
770 pending_registration_requests_.find(app_id); | 885 pending_registration_requests_.find(registration_info); |
771 if (iter == pending_registration_requests_.end()) | 886 if (iter == pending_registration_requests_.end()) |
772 result = UNKNOWN_ERROR; | 887 result = UNKNOWN_ERROR; |
773 else if (status == RegistrationRequest::INVALID_SENDER) | 888 else if (status == RegistrationRequest::INVALID_SENDER) |
774 result = INVALID_PARAMETER; | 889 result = INVALID_PARAMETER; |
775 else if (registration_id.empty()) | 890 else if (registration_id.empty()) |
776 result = SERVER_ERROR; | 891 result = SERVER_ERROR; |
777 else | 892 else |
778 result = SUCCESS; | 893 result = SUCCESS; |
779 | 894 |
780 if (result == SUCCESS) { | 895 if (result == SUCCESS) { |
781 // Cache it. | 896 // Cache it. |
782 linked_ptr<RegistrationInfo> registration(new RegistrationInfo); | 897 registrations_[registration_info] = registration_id; |
783 registration->sender_ids = sender_ids; | |
784 registration->registration_id = registration_id; | |
785 registrations_[app_id] = registration; | |
786 | 898 |
787 // Save it in the persistent store. | 899 // Save it in the persistent store. |
788 gcm_store_->AddRegistration( | 900 gcm_store_->AddRegistration( |
789 app_id, | 901 registration_info->GetSerializedKey(), |
790 registration, | 902 registration_info->GetSerializedValue(registration_id), |
791 base::Bind(&GCMClientImpl::UpdateRegistrationCallback, | 903 base::Bind(&GCMClientImpl::UpdateRegistrationCallback, |
792 weak_ptr_factory_.GetWeakPtr())); | 904 weak_ptr_factory_.GetWeakPtr())); |
793 } | 905 } |
794 | 906 |
795 delegate_->OnRegisterFinished( | 907 delegate_->OnRegisterFinished( |
796 app_id, result == SUCCESS ? registration_id : std::string(), result); | 908 registration_info, |
| 909 result == SUCCESS ? registration_id : std::string(), |
| 910 result); |
797 | 911 |
798 if (iter != pending_registration_requests_.end()) { | 912 if (iter != pending_registration_requests_.end()) { |
799 delete iter->second; | 913 delete iter->second; |
800 pending_registration_requests_.erase(iter); | 914 pending_registration_requests_.erase(iter); |
801 } | 915 } |
802 } | 916 } |
803 | 917 |
804 void GCMClientImpl::Unregister(const std::string& app_id) { | 918 void GCMClientImpl::Unregister( |
| 919 const linked_ptr<RegistrationInfo>& registration_info) { |
805 DCHECK_EQ(state_, READY); | 920 DCHECK_EQ(state_, READY); |
806 if (pending_unregistration_requests_.count(app_id) == 1) | 921 if (pending_unregistration_requests_.count(registration_info) == 1) |
807 return; | 922 return; |
808 | 923 |
809 // Remove from the cache and persistent store. | 924 // Remove from the cache and persistent store. |
810 registrations_.erase(app_id); | 925 registrations_.erase(registration_info); |
811 gcm_store_->RemoveRegistration( | 926 gcm_store_->RemoveRegistration( |
812 app_id, | 927 registration_info->GetSerializedKey(), |
813 base::Bind(&GCMClientImpl::UpdateRegistrationCallback, | 928 base::Bind(&GCMClientImpl::UpdateRegistrationCallback, |
814 weak_ptr_factory_.GetWeakPtr())); | 929 weak_ptr_factory_.GetWeakPtr())); |
815 | 930 |
816 UnregistrationRequest::RequestInfo request_info( | 931 UnregistrationRequest::RequestInfo request_info( |
817 device_checkin_info_.android_id, | 932 device_checkin_info_.android_id, |
818 device_checkin_info_.secret, | 933 device_checkin_info_.secret, |
819 app_id); | 934 registration_info->app_id); |
820 | 935 |
821 UnregistrationRequest* unregistration_request = new UnregistrationRequest( | 936 UnregistrationRequest* unregistration_request = NULL; |
822 gservices_settings_.GetRegistrationURL(), | 937 |
823 request_info, | 938 const GCMRegistrationInfo* gcm_registration_info = |
824 GetGCMBackoffPolicy(), | 939 GCMRegistrationInfo::FromRegistrationInfo(registration_info.get()); |
825 base::Bind(&GCMClientImpl::OnUnregisterCompleted, | 940 if (gcm_registration_info) { |
826 weak_ptr_factory_.GetWeakPtr(), | 941 unregistration_request = new GCMUnregistrationRequest( |
827 app_id), | 942 gservices_settings_.GetRegistrationURL(), |
828 url_request_context_getter_, | 943 request_info, |
829 &recorder_); | 944 GetGCMBackoffPolicy(), |
830 pending_unregistration_requests_[app_id] = unregistration_request; | 945 base::Bind(&GCMClientImpl::OnUnregisterCompleted, |
| 946 weak_ptr_factory_.GetWeakPtr(), |
| 947 registration_info), |
| 948 url_request_context_getter_, |
| 949 &recorder_); |
| 950 } |
| 951 |
| 952 const InstanceIDTokenInfo* instance_id_token_info = |
| 953 InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get()); |
| 954 if (instance_id_token_info) { |
| 955 auto instance_id_iter = instance_id_data_.find(registration_info->app_id); |
| 956 DCHECK(instance_id_iter != instance_id_data_.end()); |
| 957 |
| 958 InstanceIDDeleteTokenRequest::ExtraRequestInfo extra_request_info( |
| 959 instance_id_iter->second.first, |
| 960 instance_id_token_info->authorized_entity, |
| 961 instance_id_token_info->scope, |
| 962 ConstructGCMVersion(chrome_build_info_.version)); |
| 963 unregistration_request = new InstanceIDDeleteTokenRequest( |
| 964 gservices_settings_.GetRegistrationURL(), |
| 965 request_info, |
| 966 extra_request_info, |
| 967 GetGCMBackoffPolicy(), |
| 968 base::Bind(&GCMClientImpl::OnUnregisterCompleted, |
| 969 weak_ptr_factory_.GetWeakPtr(), |
| 970 registration_info), |
| 971 url_request_context_getter_, |
| 972 &recorder_); |
| 973 } |
| 974 |
| 975 DCHECK(unregistration_request); |
| 976 pending_unregistration_requests_[registration_info] = unregistration_request; |
831 unregistration_request->Start(); | 977 unregistration_request->Start(); |
832 } | 978 } |
833 | 979 |
834 void GCMClientImpl::OnUnregisterCompleted( | 980 void GCMClientImpl::OnUnregisterCompleted( |
835 const std::string& app_id, | 981 const linked_ptr<RegistrationInfo>& registration_info, |
836 UnregistrationRequest::Status status) { | 982 UnregistrationRequest::Status status) { |
837 DVLOG(1) << "Unregister completed for app: " << app_id | 983 DVLOG(1) << "Unregister completed for app: " << registration_info->app_id |
838 << " with " << (status ? "success." : "failure."); | 984 << " with " << (status ? "success." : "failure."); |
839 delegate_->OnUnregisterFinished( | 985 delegate_->OnUnregisterFinished( |
840 app_id, | 986 registration_info, |
841 status == UnregistrationRequest::SUCCESS ? SUCCESS : SERVER_ERROR); | 987 status == UnregistrationRequest::SUCCESS ? SUCCESS : SERVER_ERROR); |
842 | 988 |
843 PendingUnregistrationRequests::iterator iter = | 989 PendingUnregistrationRequests::iterator iter = |
844 pending_unregistration_requests_.find(app_id); | 990 pending_unregistration_requests_.find(registration_info); |
845 if (iter == pending_unregistration_requests_.end()) | 991 if (iter == pending_unregistration_requests_.end()) |
846 return; | 992 return; |
847 | 993 |
848 delete iter->second; | 994 delete iter->second; |
849 pending_unregistration_requests_.erase(iter); | 995 pending_unregistration_requests_.erase(iter); |
850 } | 996 } |
851 | 997 |
852 void GCMClientImpl::OnGCMStoreDestroyed(bool success) { | 998 void GCMClientImpl::OnGCMStoreDestroyed(bool success) { |
853 DLOG_IF(ERROR, !success) << "GCM store failed to be destroyed!"; | 999 DLOG_IF(ERROR, !success) << "GCM store failed to be destroyed!"; |
854 UMA_HISTOGRAM_BOOLEAN("GCM.StoreDestroySucceeded", success); | 1000 UMA_HISTOGRAM_BOOLEAN("GCM.StoreDestroySucceeded", success); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
922 if (mcs_client_.get()) { | 1068 if (mcs_client_.get()) { |
923 stats.send_queue_size = mcs_client_->GetSendQueueSize(); | 1069 stats.send_queue_size = mcs_client_->GetSendQueueSize(); |
924 stats.resend_queue_size = mcs_client_->GetResendQueueSize(); | 1070 stats.resend_queue_size = mcs_client_->GetResendQueueSize(); |
925 } | 1071 } |
926 if (device_checkin_info_.android_id > 0) | 1072 if (device_checkin_info_.android_id > 0) |
927 stats.android_id = device_checkin_info_.android_id; | 1073 stats.android_id = device_checkin_info_.android_id; |
928 recorder_.CollectActivities(&stats.recorded_activities); | 1074 recorder_.CollectActivities(&stats.recorded_activities); |
929 | 1075 |
930 for (RegistrationInfoMap::const_iterator it = registrations_.begin(); | 1076 for (RegistrationInfoMap::const_iterator it = registrations_.begin(); |
931 it != registrations_.end(); ++it) { | 1077 it != registrations_.end(); ++it) { |
932 stats.registered_app_ids.push_back(it->first); | 1078 stats.registered_app_ids.push_back(it->first->app_id); |
933 } | 1079 } |
934 return stats; | 1080 return stats; |
935 } | 1081 } |
936 | 1082 |
937 void GCMClientImpl::OnActivityRecorded() { | 1083 void GCMClientImpl::OnActivityRecorded() { |
938 delegate_->OnActivityRecorded(); | 1084 delegate_->OnActivityRecorded(); |
939 } | 1085 } |
940 | 1086 |
941 void GCMClientImpl::OnConnected(const GURL& current_server, | 1087 void GCMClientImpl::OnConnected(const GURL& current_server, |
942 const net::IPEndPoint& ip_endpoint) { | 1088 const net::IPEndPoint& ip_endpoint) { |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1040 DVLOG(1) << "Unknown message_type received. Message ignored. " | 1186 DVLOG(1) << "Unknown message_type received. Message ignored. " |
1041 << "App ID: " << data_message_stanza.category() << "."; | 1187 << "App ID: " << data_message_stanza.category() << "."; |
1042 break; | 1188 break; |
1043 } | 1189 } |
1044 } | 1190 } |
1045 | 1191 |
1046 void GCMClientImpl::HandleIncomingDataMessage( | 1192 void GCMClientImpl::HandleIncomingDataMessage( |
1047 const mcs_proto::DataMessageStanza& data_message_stanza, | 1193 const mcs_proto::DataMessageStanza& data_message_stanza, |
1048 MessageData& message_data) { | 1194 MessageData& message_data) { |
1049 std::string app_id = data_message_stanza.category(); | 1195 std::string app_id = data_message_stanza.category(); |
| 1196 std::string sender = data_message_stanza.from(); |
1050 | 1197 |
1051 // Drop the message when the app is not registered for the sender of the | 1198 // Drop the message when the app is not registered for the sender of the |
1052 // message. | 1199 // message. |
1053 RegistrationInfoMap::iterator iter = registrations_.find(app_id); | 1200 bool registered = false; |
1054 bool not_registered = | 1201 |
1055 iter == registrations_.end() || | 1202 // First, find among all GCM registrations. |
1056 std::find(iter->second->sender_ids.begin(), | 1203 scoped_ptr<GCMRegistrationInfo> gcm_registration(new GCMRegistrationInfo); |
1057 iter->second->sender_ids.end(), | 1204 gcm_registration->app_id = app_id; |
1058 data_message_stanza.from()) == iter->second->sender_ids.end(); | 1205 auto gcm_registration_iter = registrations_.find( |
1059 recorder_.RecordDataMessageReceived(app_id, data_message_stanza.from(), | 1206 make_linked_ptr<RegistrationInfo>(gcm_registration.release())); |
1060 data_message_stanza.ByteSize(), !not_registered, | 1207 if (gcm_registration_iter != registrations_.end()) { |
| 1208 GCMRegistrationInfo* cached_gcm_registration = |
| 1209 GCMRegistrationInfo::FromRegistrationInfo( |
| 1210 gcm_registration_iter->first.get()); |
| 1211 if (cached_gcm_registration && |
| 1212 std::find(cached_gcm_registration->sender_ids.begin(), |
| 1213 cached_gcm_registration->sender_ids.end(), |
| 1214 sender) != cached_gcm_registration->sender_ids.end()) { |
| 1215 registered = true; |
| 1216 } |
| 1217 } |
| 1218 |
| 1219 // Then, find among all InstanceID registrations. |
| 1220 if (!registered) { |
| 1221 scoped_ptr<InstanceIDTokenInfo> instance_id_token(new InstanceIDTokenInfo); |
| 1222 instance_id_token->app_id = app_id; |
| 1223 instance_id_token->authorized_entity = sender; |
| 1224 instance_id_token->scope = kGCMScope; |
| 1225 auto instance_id_token_iter = registrations_.find( |
| 1226 make_linked_ptr<RegistrationInfo>(instance_id_token.release())); |
| 1227 if (instance_id_token_iter != registrations_.end()) |
| 1228 registered = true; |
| 1229 } |
| 1230 |
| 1231 recorder_.RecordDataMessageReceived(app_id, sender, |
| 1232 data_message_stanza.ByteSize(), registered, |
1061 GCMStatsRecorder::DATA_MESSAGE); | 1233 GCMStatsRecorder::DATA_MESSAGE); |
1062 if (not_registered) { | 1234 if (!registered) |
1063 return; | 1235 return; |
1064 } | |
1065 | 1236 |
1066 IncomingMessage incoming_message; | 1237 IncomingMessage incoming_message; |
1067 incoming_message.sender_id = data_message_stanza.from(); | 1238 incoming_message.sender_id = data_message_stanza.from(); |
1068 if (data_message_stanza.has_token()) | 1239 if (data_message_stanza.has_token()) |
1069 incoming_message.collapse_key = data_message_stanza.token(); | 1240 incoming_message.collapse_key = data_message_stanza.token(); |
1070 incoming_message.data = message_data; | 1241 incoming_message.data = message_data; |
1071 delegate_->OnMessageReceived(app_id, incoming_message); | 1242 delegate_->OnMessageReceived(app_id, incoming_message); |
1072 } | 1243 } |
1073 | 1244 |
1074 void GCMClientImpl::HandleIncomingSendError( | 1245 void GCMClientImpl::HandleIncomingSendError( |
(...skipping 17 matching lines...) Expand all Loading... |
1092 delegate_->OnMessageSendError(data_message_stanza.category(), | 1263 delegate_->OnMessageSendError(data_message_stanza.category(), |
1093 send_error_details); | 1264 send_error_details); |
1094 } | 1265 } |
1095 | 1266 |
1096 bool GCMClientImpl::HasStandaloneRegisteredApp() const { | 1267 bool GCMClientImpl::HasStandaloneRegisteredApp() const { |
1097 if (registrations_.empty()) | 1268 if (registrations_.empty()) |
1098 return false; | 1269 return false; |
1099 // Note that account mapper is not counted as a standalone app since it is | 1270 // Note that account mapper is not counted as a standalone app since it is |
1100 // automatically started when other app uses GCM. | 1271 // automatically started when other app uses GCM. |
1101 return registrations_.size() > 1 || | 1272 return registrations_.size() > 1 || |
1102 !registrations_.count(kGCMAccountMapperAppId); | 1273 !ExistsGCMRegistrationInMap(registrations_, kGCMAccountMapperAppId); |
1103 } | 1274 } |
1104 | 1275 |
1105 } // namespace gcm | 1276 } // namespace gcm |
OLD | NEW |