Chromium Code Reviews| 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 <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <utility> | 10 #include <utility> |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 79 }; | 79 }; |
| 80 | 80 |
| 81 const char kGCMScope[] = "GCM"; | 81 const char kGCMScope[] = "GCM"; |
| 82 const int kMaxRegistrationRetries = 5; | 82 const int kMaxRegistrationRetries = 5; |
| 83 const int kMaxUnregistrationRetries = 5; | 83 const int kMaxUnregistrationRetries = 5; |
| 84 const char kMessageTypeDataMessage[] = "gcm"; | 84 const char kMessageTypeDataMessage[] = "gcm"; |
| 85 const char kMessageTypeDeletedMessagesKey[] = "deleted_messages"; | 85 const char kMessageTypeDeletedMessagesKey[] = "deleted_messages"; |
| 86 const char kMessageTypeKey[] = "message_type"; | 86 const char kMessageTypeKey[] = "message_type"; |
| 87 const char kMessageTypeSendErrorKey[] = "send_error"; | 87 const char kMessageTypeSendErrorKey[] = "send_error"; |
| 88 const char kSendErrorMessageIdKey[] = "google.message_id"; | 88 const char kSendErrorMessageIdKey[] = "google.message_id"; |
| 89 const char kSubtypeKey[] = "subtype"; | |
| 89 const char kSendMessageFromValue[] = "gcm@chrome.com"; | 90 const char kSendMessageFromValue[] = "gcm@chrome.com"; |
| 90 const int64_t kDefaultUserSerialNumber = 0LL; | 91 const int64_t kDefaultUserSerialNumber = 0LL; |
| 91 const int kDestroyGCMStoreDelayMS = 5 * 60 * 1000; // 5 minutes. | 92 const int kDestroyGCMStoreDelayMS = 5 * 60 * 1000; // 5 minutes. |
| 92 | 93 |
| 93 GCMClient::Result ToGCMClientResult(MCSClient::MessageSendStatus status) { | 94 GCMClient::Result ToGCMClientResult(MCSClient::MessageSendStatus status) { |
| 94 switch (status) { | 95 switch (status) { |
| 95 case MCSClient::QUEUED: | 96 case MCSClient::QUEUED: |
| 96 return GCMClient::SUCCESS; | 97 return GCMClient::SUCCESS; |
| 97 case MCSClient::QUEUE_SIZE_LIMIT_REACHED: | 98 case MCSClient::QUEUE_SIZE_LIMIT_REACHED: |
| 98 return GCMClient::NETWORK_ERROR; | 99 return GCMClient::NETWORK_ERROR; |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 231 | 232 |
| 232 UMA_HISTOGRAM_ENUMERATION("GCM.OutgoingMessageTTL", | 233 UMA_HISTOGRAM_ENUMERATION("GCM.OutgoingMessageTTL", |
| 233 ttl_category, | 234 ttl_category, |
| 234 TTL_CATEGORY_COUNT); | 235 TTL_CATEGORY_COUNT); |
| 235 } | 236 } |
| 236 | 237 |
| 237 void RecordResetStoreErrorToUMA(ResetStoreError error) { | 238 void RecordResetStoreErrorToUMA(ResetStoreError error) { |
| 238 UMA_HISTOGRAM_ENUMERATION("GCM.ResetStore", error, RESET_STORE_ERROR_COUNT); | 239 UMA_HISTOGRAM_ENUMERATION("GCM.ResetStore", error, RESET_STORE_ERROR_COUNT); |
| 239 } | 240 } |
| 240 | 241 |
| 242 // Helper method for DCHECKs that prevent requesting the same token both with | |
| 243 // and without subtypes. | |
| 244 bool InstanceIDsDifferOnlyInUseSubtype( | |
| 245 const RegistrationInfo* registration_info_a, | |
| 246 const RegistrationInfo* registration_info_b) { | |
| 247 const InstanceIDTokenInfo* token_a = | |
| 248 InstanceIDTokenInfo::FromRegistrationInfo(registration_info_a); | |
| 249 const InstanceIDTokenInfo* token_b = | |
| 250 InstanceIDTokenInfo::FromRegistrationInfo(registration_info_b); | |
| 251 return token_a && token_b && token_a->use_subtype != token_b->use_subtype && | |
| 252 token_a->app_id == token_b->app_id && | |
| 253 token_a->authorized_entity == token_b->authorized_entity && | |
| 254 token_a->scope == token_b->scope; | |
| 255 } | |
| 256 | |
| 241 } // namespace | 257 } // namespace |
| 242 | 258 |
| 243 GCMInternalsBuilder::GCMInternalsBuilder() {} | 259 GCMInternalsBuilder::GCMInternalsBuilder() {} |
| 244 GCMInternalsBuilder::~GCMInternalsBuilder() {} | 260 GCMInternalsBuilder::~GCMInternalsBuilder() {} |
| 245 | 261 |
| 246 std::unique_ptr<base::Clock> GCMInternalsBuilder::BuildClock() { | 262 std::unique_ptr<base::Clock> GCMInternalsBuilder::BuildClock() { |
| 247 return base::WrapUnique<base::Clock>(new base::DefaultClock()); | 263 return base::WrapUnique<base::Clock>(new base::DefaultClock()); |
| 248 } | 264 } |
| 249 | 265 |
| 250 std::unique_ptr<MCSClient> GCMInternalsBuilder::BuildMCSClient( | 266 std::unique_ptr<MCSClient> GCMInternalsBuilder::BuildMCSClient( |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 658 std::string* extra_data) { | 674 std::string* extra_data) { |
| 659 DCHECK(instance_id && extra_data); | 675 DCHECK(instance_id && extra_data); |
| 660 | 676 |
| 661 auto iter = instance_id_data_.find(app_id); | 677 auto iter = instance_id_data_.find(app_id); |
| 662 if (iter == instance_id_data_.end()) | 678 if (iter == instance_id_data_.end()) |
| 663 return; | 679 return; |
| 664 *instance_id = iter->second.first; | 680 *instance_id = iter->second.first; |
| 665 *extra_data = iter->second.second; | 681 *extra_data = iter->second.second; |
| 666 } | 682 } |
| 667 | 683 |
| 684 bool GCMClientImpl::CategoryHasSubtype(const std::string& category) { | |
| 685 // SECURITY NOTE: Subtypes that we receive from GCM *cannot* be trusted for | |
| 686 // registrations without a subtype (as the sender can pass any subtype they | |
| 687 // want). They can however be trusted for registrations that are known to have | |
| 688 // a subtype (as GCM overwrites anything passed by the sender). | |
| 689 // | |
| 690 // So a given Chrome profile always passes the same string (e.g. | |
| 691 // "com.chrome.stable.macosx") as the category when registering with a | |
| 692 // subtypes, and incoming subtypes are only trusted for that category. | |
| 693 // | |
| 694 // (On Android, all registrations made by Chrome on behalf of third-party | |
| 695 // apps/extensions/websites have always had a subtype, so we don't need such a | |
| 696 // check, indeed we cannot, since category is fixed to the true package name). | |
| 697 | |
| 698 return category == chrome_build_info_.category_for_subtypes; | |
| 699 } | |
| 700 | |
| 668 void GCMClientImpl::AddHeartbeatInterval(const std::string& scope, | 701 void GCMClientImpl::AddHeartbeatInterval(const std::string& scope, |
| 669 int interval_ms) { | 702 int interval_ms) { |
| 670 DCHECK(mcs_client_); | 703 DCHECK(mcs_client_); |
| 671 mcs_client_->AddHeartbeatInterval(scope, interval_ms); | 704 mcs_client_->AddHeartbeatInterval(scope, interval_ms); |
| 672 } | 705 } |
| 673 | 706 |
| 674 void GCMClientImpl::RemoveHeartbeatInterval(const std::string& scope) { | 707 void GCMClientImpl::RemoveHeartbeatInterval(const std::string& scope) { |
| 675 DCHECK(mcs_client_); | 708 DCHECK(mcs_client_); |
| 676 mcs_client_->RemoveHeartbeatInterval(scope); | 709 mcs_client_->RemoveHeartbeatInterval(scope); |
| 677 } | 710 } |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 843 checkin_request_.reset(); | 876 checkin_request_.reset(); |
| 844 // Delete all of the pending registration and unregistration requests. | 877 // Delete all of the pending registration and unregistration requests. |
| 845 pending_registration_requests_.clear(); | 878 pending_registration_requests_.clear(); |
| 846 pending_unregistration_requests_.clear(); | 879 pending_unregistration_requests_.clear(); |
| 847 } | 880 } |
| 848 | 881 |
| 849 void GCMClientImpl::Register( | 882 void GCMClientImpl::Register( |
| 850 const linked_ptr<RegistrationInfo>& registration_info) { | 883 const linked_ptr<RegistrationInfo>& registration_info) { |
| 851 DCHECK_EQ(state_, READY); | 884 DCHECK_EQ(state_, READY); |
| 852 | 885 |
| 886 // Registrations should never pass as an app_id the special category used | |
| 887 // internally when registering with a subtype. See security note in | |
| 888 // GCMClient::CategoryHasSubtype. | |
| 889 CHECK(!CategoryHasSubtype(registration_info->app_id)); | |
| 890 | |
| 853 // Find and use the cached registration ID. | 891 // Find and use the cached registration ID. |
| 854 RegistrationInfoMap::const_iterator registrations_iter = | 892 RegistrationInfoMap::const_iterator registrations_iter = |
| 855 registrations_.find(registration_info); | 893 registrations_.find(registration_info); |
| 856 if (registrations_iter != registrations_.end()) { | 894 if (registrations_iter != registrations_.end()) { |
| 857 bool matched = true; | 895 bool matched = true; |
| 858 | 896 |
| 859 // For GCM registration, we also match the sender IDs since multiple | 897 // For GCM registration, we also match the sender IDs since multiple |
| 860 // registrations are not supported. | 898 // registrations are not supported. |
| 861 const GCMRegistrationInfo* gcm_registration_info = | 899 const GCMRegistrationInfo* gcm_registration_info = |
| 862 GCMRegistrationInfo::FromRegistrationInfo(registration_info.get()); | 900 GCMRegistrationInfo::FromRegistrationInfo(registration_info.get()); |
| 863 if (gcm_registration_info) { | 901 if (gcm_registration_info) { |
| 864 const GCMRegistrationInfo* cached_gcm_registration_info = | 902 const GCMRegistrationInfo* cached_gcm_registration_info = |
| 865 GCMRegistrationInfo::FromRegistrationInfo( | 903 GCMRegistrationInfo::FromRegistrationInfo( |
| 866 registrations_iter->first.get()); | 904 registrations_iter->first.get()); |
| 867 DCHECK(cached_gcm_registration_info); | 905 DCHECK(cached_gcm_registration_info); |
| 868 if (cached_gcm_registration_info && | 906 if (cached_gcm_registration_info && |
| 869 gcm_registration_info->sender_ids != | 907 gcm_registration_info->sender_ids != |
| 870 cached_gcm_registration_info->sender_ids) { | 908 cached_gcm_registration_info->sender_ids) { |
| 871 matched = false; | 909 matched = false; |
| 872 } | 910 } |
| 911 } else { | |
| 912 DCHECK(!InstanceIDsDifferOnlyInUseSubtype( | |
| 913 registration_info.get(), registrations_iter->first.get())) | |
| 914 << "Registering the same Instance ID token both with and without " | |
| 915 "subtypes is not supported"; | |
| 873 } | 916 } |
| 874 | 917 |
| 875 if (matched) { | 918 if (matched) { |
| 876 delegate_->OnRegisterFinished( | 919 delegate_->OnRegisterFinished( |
| 877 registration_info, registrations_iter->second, SUCCESS); | 920 registration_info, registrations_iter->second, SUCCESS); |
| 878 return; | 921 return; |
| 879 } | 922 } |
| 880 } | 923 } |
| 881 | 924 |
| 882 std::unique_ptr<RegistrationRequest::CustomRequestHandler> request_handler; | 925 std::unique_ptr<RegistrationRequest::CustomRequestHandler> request_handler; |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 910 instance_id_iter->second.first, | 953 instance_id_iter->second.first, |
| 911 instance_id_token_info->authorized_entity, | 954 instance_id_token_info->authorized_entity, |
| 912 instance_id_token_info->scope, | 955 instance_id_token_info->scope, |
| 913 ConstructGCMVersion(chrome_build_info_.version), | 956 ConstructGCMVersion(chrome_build_info_.version), |
| 914 instance_id_token_info->options)); | 957 instance_id_token_info->options)); |
| 915 source_to_record = instance_id_token_info->authorized_entity + "/" + | 958 source_to_record = instance_id_token_info->authorized_entity + "/" + |
| 916 instance_id_token_info->scope; | 959 instance_id_token_info->scope; |
| 917 } | 960 } |
| 918 | 961 |
| 919 RegistrationRequest::RequestInfo request_info( | 962 RegistrationRequest::RequestInfo request_info( |
| 920 device_checkin_info_.android_id, | 963 device_checkin_info_.android_id, device_checkin_info_.secret, |
| 921 device_checkin_info_.secret, | 964 registration_info->app_id, |
| 922 registration_info->app_id); | 965 instance_id_token_info && instance_id_token_info->use_subtype, |
|
Peter Beverloo
2016/07/22 12:17:03
nit: extract to a local bool w/ an appropriate nam
johnme
2016/07/26 17:11:55
Done.
| |
| 966 chrome_build_info_.category_for_subtypes); | |
| 923 | 967 |
| 924 std::unique_ptr<RegistrationRequest> registration_request( | 968 std::unique_ptr<RegistrationRequest> registration_request( |
| 925 new RegistrationRequest( | 969 new RegistrationRequest( |
| 926 gservices_settings_.GetRegistrationURL(), request_info, | 970 gservices_settings_.GetRegistrationURL(), request_info, |
| 927 std::move(request_handler), GetGCMBackoffPolicy(), | 971 std::move(request_handler), GetGCMBackoffPolicy(), |
| 928 base::Bind(&GCMClientImpl::OnRegisterCompleted, | 972 base::Bind(&GCMClientImpl::OnRegisterCompleted, |
| 929 weak_ptr_factory_.GetWeakPtr(), registration_info), | 973 weak_ptr_factory_.GetWeakPtr(), registration_info), |
| 930 kMaxRegistrationRetries, url_request_context_getter_, &recorder_, | 974 kMaxRegistrationRetries, url_request_context_getter_, &recorder_, |
| 931 source_to_record)); | 975 source_to_record)); |
| 932 registration_request->Start(); | 976 registration_request->Start(); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 995 const InstanceIDTokenInfo* instance_id_token_info = | 1039 const InstanceIDTokenInfo* instance_id_token_info = |
| 996 InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get()); | 1040 InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get()); |
| 997 if (instance_id_token_info) { | 1041 if (instance_id_token_info) { |
| 998 auto instance_id_iter = instance_id_data_.find(registration_info->app_id); | 1042 auto instance_id_iter = instance_id_data_.find(registration_info->app_id); |
| 999 if (instance_id_iter == instance_id_data_.end()) { | 1043 if (instance_id_iter == instance_id_data_.end()) { |
| 1000 // This should not be reached since we should not delete tokens when | 1044 // This should not be reached since we should not delete tokens when |
| 1001 // an InstanceID has not been created yet. | 1045 // an InstanceID has not been created yet. |
| 1002 NOTREACHED(); | 1046 NOTREACHED(); |
| 1003 return; | 1047 return; |
| 1004 } | 1048 } |
| 1049 | |
| 1005 request_handler.reset(new InstanceIDDeleteTokenRequestHandler( | 1050 request_handler.reset(new InstanceIDDeleteTokenRequestHandler( |
| 1006 instance_id_iter->second.first, | 1051 instance_id_iter->second.first, |
| 1007 instance_id_token_info->authorized_entity, | 1052 instance_id_token_info->authorized_entity, |
| 1008 instance_id_token_info->scope, | 1053 instance_id_token_info->scope, |
| 1009 ConstructGCMVersion(chrome_build_info_.version))); | 1054 ConstructGCMVersion(chrome_build_info_.version))); |
| 1010 source_to_record = instance_id_token_info->authorized_entity + "/" + | 1055 source_to_record = instance_id_token_info->authorized_entity + "/" + |
| 1011 instance_id_token_info->scope; | 1056 instance_id_token_info->scope; |
| 1012 } | 1057 } |
| 1013 | 1058 |
| 1014 // Remove the registration/token(s) from the cache and the store. | 1059 // Remove the registration/token(s) from the cache and the store. |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 1042 OnUnregisterCompleted(registration_info, | 1087 OnUnregisterCompleted(registration_info, |
| 1043 UnregistrationRequest::SUCCESS); | 1088 UnregistrationRequest::SUCCESS); |
| 1044 return; | 1089 return; |
| 1045 } | 1090 } |
| 1046 } else { | 1091 } else { |
| 1047 auto iter = registrations_.find(registration_info); | 1092 auto iter = registrations_.find(registration_info); |
| 1048 if (iter == registrations_.end()) { | 1093 if (iter == registrations_.end()) { |
| 1049 delegate_->OnUnregisterFinished(registration_info, INVALID_PARAMETER); | 1094 delegate_->OnUnregisterFinished(registration_info, INVALID_PARAMETER); |
| 1050 return; | 1095 return; |
| 1051 } | 1096 } |
| 1097 DCHECK(!InstanceIDsDifferOnlyInUseSubtype(registration_info.get(), | |
| 1098 iter->first.get())); | |
| 1052 registrations_.erase(iter); | 1099 registrations_.erase(iter); |
| 1053 | 1100 |
| 1054 gcm_store_->RemoveRegistration( | 1101 gcm_store_->RemoveRegistration( |
| 1055 registration_info->GetSerializedKey(), | 1102 registration_info->GetSerializedKey(), |
| 1056 base::Bind(&GCMClientImpl::UpdateRegistrationCallback, | 1103 base::Bind(&GCMClientImpl::UpdateRegistrationCallback, |
| 1057 weak_ptr_factory_.GetWeakPtr())); | 1104 weak_ptr_factory_.GetWeakPtr())); |
| 1058 } | 1105 } |
| 1059 | 1106 |
| 1060 UnregistrationRequest::RequestInfo request_info( | 1107 UnregistrationRequest::RequestInfo request_info( |
| 1061 device_checkin_info_.android_id, | 1108 device_checkin_info_.android_id, device_checkin_info_.secret, |
| 1062 device_checkin_info_.secret, | 1109 registration_info->app_id, |
| 1063 registration_info->app_id); | 1110 instance_id_token_info && instance_id_token_info->use_subtype, |
|
Peter Beverloo
2016/07/22 12:17:03
nit: extract to a local bool w/ an appropriate nam
johnme
2016/07/26 17:11:55
Done.
| |
| 1111 chrome_build_info_.category_for_subtypes); | |
| 1064 | 1112 |
| 1065 std::unique_ptr<UnregistrationRequest> unregistration_request( | 1113 std::unique_ptr<UnregistrationRequest> unregistration_request( |
| 1066 new UnregistrationRequest( | 1114 new UnregistrationRequest( |
| 1067 gservices_settings_.GetRegistrationURL(), request_info, | 1115 gservices_settings_.GetRegistrationURL(), request_info, |
| 1068 std::move(request_handler), GetGCMBackoffPolicy(), | 1116 std::move(request_handler), GetGCMBackoffPolicy(), |
| 1069 base::Bind(&GCMClientImpl::OnUnregisterCompleted, | 1117 base::Bind(&GCMClientImpl::OnUnregisterCompleted, |
| 1070 weak_ptr_factory_.GetWeakPtr(), registration_info), | 1118 weak_ptr_factory_.GetWeakPtr(), registration_info), |
| 1071 kMaxUnregistrationRetries, url_request_context_getter_, &recorder_, | 1119 kMaxUnregistrationRetries, url_request_context_getter_, &recorder_, |
| 1072 source_to_record)); | 1120 source_to_record)); |
| 1073 unregistration_request->Start(); | 1121 unregistration_request->Start(); |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1253 } | 1301 } |
| 1254 | 1302 |
| 1255 void GCMClientImpl::HandleIncomingMessage(const gcm::MCSMessage& message) { | 1303 void GCMClientImpl::HandleIncomingMessage(const gcm::MCSMessage& message) { |
| 1256 DCHECK(delegate_); | 1304 DCHECK(delegate_); |
| 1257 | 1305 |
| 1258 const mcs_proto::DataMessageStanza& data_message_stanza = | 1306 const mcs_proto::DataMessageStanza& data_message_stanza = |
| 1259 reinterpret_cast<const mcs_proto::DataMessageStanza&>( | 1307 reinterpret_cast<const mcs_proto::DataMessageStanza&>( |
| 1260 message.GetProtobuf()); | 1308 message.GetProtobuf()); |
| 1261 DCHECK_EQ(data_message_stanza.device_user_id(), kDefaultUserSerialNumber); | 1309 DCHECK_EQ(data_message_stanza.device_user_id(), kDefaultUserSerialNumber); |
| 1262 | 1310 |
| 1263 // Copying all the data from the stanza to a MessageData object. When present, | 1311 // Copy all the data from the stanza to a MessageData object. When present, |
| 1264 // keys like kMessageTypeKey or kSendErrorMessageIdKey will be filtered out | 1312 // keys like kSubtypeKey, kMessageTypeKey or kSendErrorMessageIdKey will be |
| 1265 // later. | 1313 // filtered out later. |
| 1266 MessageData message_data; | 1314 MessageData message_data; |
| 1267 for (int i = 0; i < data_message_stanza.app_data_size(); ++i) { | 1315 for (int i = 0; i < data_message_stanza.app_data_size(); ++i) { |
| 1268 std::string key = data_message_stanza.app_data(i).key(); | 1316 std::string key = data_message_stanza.app_data(i).key(); |
| 1269 message_data[key] = data_message_stanza.app_data(i).value(); | 1317 message_data[key] = data_message_stanza.app_data(i).value(); |
| 1270 } | 1318 } |
| 1271 | 1319 |
| 1320 std::string subtype = ""; | |
|
Peter Beverloo
2016/07/22 12:17:03
nit: no init
johnme
2016/07/26 17:11:55
Done.
| |
| 1321 auto subtype_iter = message_data.find(kSubtypeKey); | |
|
Peter Beverloo
2016/07/22 12:17:03
This is using "subtype", which is potentially untr
johnme
2016/07/26 17:11:55
Added TODO.
| |
| 1322 if (subtype_iter != message_data.end()) { | |
| 1323 subtype = subtype_iter->second; | |
| 1324 message_data.erase(subtype_iter); | |
| 1325 } | |
| 1326 | |
| 1327 // If CategoryHasSubtype returns false, the subtype is untrusted input set by | |
| 1328 // the sender, and we should ignore it. | |
| 1329 bool use_subtype = | |
| 1330 !subtype.empty() && CategoryHasSubtype(data_message_stanza.category()); | |
| 1331 std::string app_id = use_subtype ? subtype : data_message_stanza.category(); | |
| 1332 | |
| 1272 MessageType message_type = DATA_MESSAGE; | 1333 MessageType message_type = DATA_MESSAGE; |
| 1273 MessageData::iterator iter = message_data.find(kMessageTypeKey); | 1334 MessageData::iterator type_iter = message_data.find(kMessageTypeKey); |
| 1274 if (iter != message_data.end()) { | 1335 if (type_iter != message_data.end()) { |
| 1275 message_type = DecodeMessageType(iter->second); | 1336 message_type = DecodeMessageType(type_iter->second); |
| 1276 message_data.erase(iter); | 1337 message_data.erase(type_iter); |
| 1277 } | 1338 } |
| 1278 | 1339 |
| 1279 switch (message_type) { | 1340 switch (message_type) { |
| 1280 case DATA_MESSAGE: | 1341 case DATA_MESSAGE: |
| 1281 HandleIncomingDataMessage(data_message_stanza, message_data); | 1342 HandleIncomingDataMessage(app_id, use_subtype, data_message_stanza, |
| 1343 message_data); | |
| 1282 break; | 1344 break; |
| 1283 case DELETED_MESSAGES: | 1345 case DELETED_MESSAGES: |
| 1284 recorder_.RecordDataMessageReceived(data_message_stanza.category(), | 1346 recorder_.RecordDataMessageReceived(app_id, data_message_stanza.from(), |
| 1285 data_message_stanza.from(), | 1347 data_message_stanza.ByteSize(), true, |
| 1286 data_message_stanza.ByteSize(), | |
| 1287 true, | |
| 1288 GCMStatsRecorder::DELETED_MESSAGES); | 1348 GCMStatsRecorder::DELETED_MESSAGES); |
| 1289 delegate_->OnMessagesDeleted(data_message_stanza.category()); | 1349 delegate_->OnMessagesDeleted(app_id); |
| 1290 break; | 1350 break; |
| 1291 case SEND_ERROR: | 1351 case SEND_ERROR: |
| 1292 HandleIncomingSendError(data_message_stanza, message_data); | 1352 HandleIncomingSendError(app_id, data_message_stanza, message_data); |
| 1293 break; | 1353 break; |
| 1294 case UNKNOWN: | 1354 case UNKNOWN: |
| 1295 default: // Treat default the same as UNKNOWN. | 1355 default: // Treat default the same as UNKNOWN. |
| 1296 DVLOG(1) << "Unknown message_type received. Message ignored. " | 1356 DVLOG(1) << "Unknown message_type received. Message ignored. " |
| 1297 << "App ID: " << data_message_stanza.category() << "."; | 1357 << "App ID: " << app_id << "."; |
| 1298 break; | 1358 break; |
| 1299 } | 1359 } |
| 1300 } | 1360 } |
| 1301 | 1361 |
| 1302 void GCMClientImpl::HandleIncomingDataMessage( | 1362 void GCMClientImpl::HandleIncomingDataMessage( |
| 1363 const std::string& app_id, | |
| 1364 bool use_subtype, | |
| 1303 const mcs_proto::DataMessageStanza& data_message_stanza, | 1365 const mcs_proto::DataMessageStanza& data_message_stanza, |
| 1304 MessageData& message_data) { | 1366 MessageData& message_data) { |
| 1305 std::string app_id = data_message_stanza.category(); | |
| 1306 std::string sender = data_message_stanza.from(); | 1367 std::string sender = data_message_stanza.from(); |
| 1307 | 1368 |
| 1308 // Drop the message when the app is not registered for the sender of the | 1369 // Drop the message when the app is not registered for the sender of the |
| 1309 // message. | 1370 // message. |
| 1310 bool registered = false; | 1371 bool registered = false; |
| 1311 | 1372 |
| 1312 // First, find among all GCM registrations. | 1373 // First, find among all GCM registrations. |
| 1313 std::unique_ptr<GCMRegistrationInfo> gcm_registration( | 1374 std::unique_ptr<GCMRegistrationInfo> gcm_registration( |
| 1314 new GCMRegistrationInfo); | 1375 new GCMRegistrationInfo); |
| 1315 gcm_registration->app_id = app_id; | 1376 gcm_registration->app_id = app_id; |
| 1316 auto gcm_registration_iter = registrations_.find( | 1377 auto gcm_registration_iter = registrations_.find( |
| 1317 make_linked_ptr<RegistrationInfo>(gcm_registration.release())); | 1378 make_linked_ptr<RegistrationInfo>(gcm_registration.release())); |
| 1318 if (gcm_registration_iter != registrations_.end()) { | 1379 if (gcm_registration_iter != registrations_.end()) { |
| 1319 GCMRegistrationInfo* cached_gcm_registration = | 1380 GCMRegistrationInfo* cached_gcm_registration = |
| 1320 GCMRegistrationInfo::FromRegistrationInfo( | 1381 GCMRegistrationInfo::FromRegistrationInfo( |
| 1321 gcm_registration_iter->first.get()); | 1382 gcm_registration_iter->first.get()); |
| 1322 if (cached_gcm_registration && | 1383 if (cached_gcm_registration && |
| 1323 std::find(cached_gcm_registration->sender_ids.begin(), | 1384 std::find(cached_gcm_registration->sender_ids.begin(), |
| 1324 cached_gcm_registration->sender_ids.end(), | 1385 cached_gcm_registration->sender_ids.end(), |
| 1325 sender) != cached_gcm_registration->sender_ids.end()) { | 1386 sender) != cached_gcm_registration->sender_ids.end()) { |
| 1326 registered = true; | 1387 registered = true; |
| 1327 } | 1388 } |
| 1328 } | 1389 } |
| 1329 | 1390 |
| 1330 // Then, find among all InstanceID registrations. | 1391 // Then, find among all InstanceID registrations. |
| 1331 if (!registered) { | 1392 if (!registered) { |
| 1332 std::unique_ptr<InstanceIDTokenInfo> instance_id_token( | 1393 linked_ptr<InstanceIDTokenInfo> instance_id_token(new InstanceIDTokenInfo); |
| 1333 new InstanceIDTokenInfo); | |
| 1334 instance_id_token->app_id = app_id; | 1394 instance_id_token->app_id = app_id; |
| 1395 instance_id_token->use_subtype = use_subtype; | |
| 1335 instance_id_token->authorized_entity = sender; | 1396 instance_id_token->authorized_entity = sender; |
| 1336 instance_id_token->scope = kGCMScope; | 1397 instance_id_token->scope = kGCMScope; |
| 1337 auto instance_id_token_iter = registrations_.find( | 1398 |
| 1338 make_linked_ptr<RegistrationInfo>(instance_id_token.release())); | 1399 auto instance_id_token_iter = registrations_.find(instance_id_token); |
| 1339 if (instance_id_token_iter != registrations_.end()) | 1400 if (instance_id_token_iter != registrations_.end()) { |
| 1340 registered = true; | 1401 if (InstanceIDsDifferOnlyInUseSubtype( |
| 1402 instance_id_token.get(), instance_id_token_iter->first.get())) { | |
| 1403 DLOG(ERROR) << "Incoming GCM message for " << app_id | |
|
Peter Beverloo
2016/07/22 12:17:03
Is this DLOG necessary? It would only happen when
johnme
2016/07/26 17:11:55
a) it's most likely to happen if the value of use_
| |
| 1404 << " had use_subtype = " << use_subtype | |
| 1405 << " which conflicts with stored registration"; | |
| 1406 } else { | |
| 1407 registered = true; | |
| 1408 } | |
| 1409 } | |
| 1341 } | 1410 } |
| 1342 | 1411 |
| 1343 recorder_.RecordDataMessageReceived(app_id, sender, | 1412 recorder_.RecordDataMessageReceived(app_id, sender, |
| 1344 data_message_stanza.ByteSize(), registered, | 1413 data_message_stanza.ByteSize(), registered, |
| 1345 GCMStatsRecorder::DATA_MESSAGE); | 1414 GCMStatsRecorder::DATA_MESSAGE); |
| 1346 if (!registered) | 1415 if (!registered) |
| 1347 return; | 1416 return; |
| 1348 | 1417 |
| 1349 IncomingMessage incoming_message; | 1418 IncomingMessage incoming_message; |
| 1350 incoming_message.sender_id = data_message_stanza.from(); | 1419 incoming_message.sender_id = data_message_stanza.from(); |
| 1351 if (data_message_stanza.has_token()) | 1420 if (data_message_stanza.has_token()) |
| 1352 incoming_message.collapse_key = data_message_stanza.token(); | 1421 incoming_message.collapse_key = data_message_stanza.token(); |
| 1353 incoming_message.data = message_data; | 1422 incoming_message.data = message_data; |
| 1354 incoming_message.raw_data = data_message_stanza.raw_data(); | 1423 incoming_message.raw_data = data_message_stanza.raw_data(); |
| 1355 | 1424 |
| 1356 delegate_->OnMessageReceived(app_id, incoming_message); | 1425 delegate_->OnMessageReceived(app_id, incoming_message); |
| 1357 } | 1426 } |
| 1358 | 1427 |
| 1359 void GCMClientImpl::HandleIncomingSendError( | 1428 void GCMClientImpl::HandleIncomingSendError( |
| 1429 const std::string& app_id, | |
| 1360 const mcs_proto::DataMessageStanza& data_message_stanza, | 1430 const mcs_proto::DataMessageStanza& data_message_stanza, |
| 1361 MessageData& message_data) { | 1431 MessageData& message_data) { |
| 1362 SendErrorDetails send_error_details; | 1432 SendErrorDetails send_error_details; |
| 1363 send_error_details.additional_data = message_data; | 1433 send_error_details.additional_data = message_data; |
| 1364 send_error_details.result = SERVER_ERROR; | 1434 send_error_details.result = SERVER_ERROR; |
| 1365 | 1435 |
| 1366 MessageData::iterator iter = | 1436 MessageData::iterator iter = |
| 1367 send_error_details.additional_data.find(kSendErrorMessageIdKey); | 1437 send_error_details.additional_data.find(kSendErrorMessageIdKey); |
| 1368 if (iter != send_error_details.additional_data.end()) { | 1438 if (iter != send_error_details.additional_data.end()) { |
| 1369 send_error_details.message_id = iter->second; | 1439 send_error_details.message_id = iter->second; |
| 1370 send_error_details.additional_data.erase(iter); | 1440 send_error_details.additional_data.erase(iter); |
| 1371 } | 1441 } |
| 1372 | 1442 |
| 1373 recorder_.RecordIncomingSendError( | 1443 recorder_.RecordIncomingSendError(app_id, data_message_stanza.to(), |
| 1374 data_message_stanza.category(), | 1444 data_message_stanza.id()); |
| 1375 data_message_stanza.to(), | 1445 delegate_->OnMessageSendError(app_id, send_error_details); |
| 1376 data_message_stanza.id()); | |
| 1377 delegate_->OnMessageSendError(data_message_stanza.category(), | |
| 1378 send_error_details); | |
| 1379 } | 1446 } |
| 1380 | 1447 |
| 1381 bool GCMClientImpl::HasStandaloneRegisteredApp() const { | 1448 bool GCMClientImpl::HasStandaloneRegisteredApp() const { |
| 1382 if (registrations_.empty()) | 1449 if (registrations_.empty()) |
| 1383 return false; | 1450 return false; |
| 1384 // Note that account mapper is not counted as a standalone app since it is | 1451 // Note that account mapper is not counted as a standalone app since it is |
| 1385 // automatically started when other app uses GCM. | 1452 // automatically started when other app uses GCM. |
| 1386 return registrations_.size() > 1 || | 1453 return registrations_.size() > 1 || |
| 1387 !ExistsGCMRegistrationInMap(registrations_, kGCMAccountMapperAppId); | 1454 !ExistsGCMRegistrationInMap(registrations_, kGCMAccountMapperAppId); |
| 1388 } | 1455 } |
| 1389 | 1456 |
| 1390 } // namespace gcm | 1457 } // namespace gcm |
| OLD | NEW |