Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/gcm_profile_service.h" | 5 #include "chrome/browser/services/gcm/gcm_profile_service.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/base64.h" | 10 #include "base/base64.h" |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 39 #include "google_apis/gcm/protocol/android_checkin.pb.h" | 39 #include "google_apis/gcm/protocol/android_checkin.pb.h" |
| 40 #include "net/url_request/url_request_context_getter.h" | 40 #include "net/url_request/url_request_context_getter.h" |
| 41 | 41 |
| 42 using extensions::Extension; | 42 using extensions::Extension; |
| 43 | 43 |
| 44 namespace gcm { | 44 namespace gcm { |
| 45 | 45 |
| 46 namespace { | 46 namespace { |
| 47 | 47 |
| 48 const char kRegistrationKey[] = "gcm.registration"; | 48 const char kRegistrationKey[] = "gcm.registration"; |
| 49 const char kSendersKey[] = "senders"; | |
| 50 const char kRegistrationIDKey[] = "reg_id"; | |
| 51 | 49 |
| 52 checkin_proto::ChromeBuildProto_Platform GetPlatform() { | 50 checkin_proto::ChromeBuildProto_Platform GetPlatform() { |
| 53 #if defined(OS_WIN) | 51 #if defined(OS_WIN) |
| 54 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_WIN; | 52 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_WIN; |
| 55 #elif defined(OS_MACOSX) | 53 #elif defined(OS_MACOSX) |
| 56 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_MAC; | 54 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_MAC; |
| 57 #elif defined(OS_CHROMEOS) | 55 #elif defined(OS_CHROMEOS) |
| 58 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_CROS; | 56 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_CROS; |
| 59 #elif defined(OS_LINUX) | 57 #elif defined(OS_LINUX) |
| 60 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_LINUX; | 58 return checkin_proto::ChromeBuildProto_Platform_PLATFORM_LINUX; |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 260 // Called on IO thread. | 258 // Called on IO thread. |
| 261 void Initialize(scoped_ptr<GCMClientFactory> gcm_client_factory, | 259 void Initialize(scoped_ptr<GCMClientFactory> gcm_client_factory, |
| 262 const base::FilePath& store_path, | 260 const base::FilePath& store_path, |
| 263 const std::vector<std::string>& account_ids, | 261 const std::vector<std::string>& account_ids, |
| 264 const scoped_refptr<net::URLRequestContextGetter>& | 262 const scoped_refptr<net::URLRequestContextGetter>& |
| 265 url_request_context_getter); | 263 url_request_context_getter); |
| 266 void Reset(); | 264 void Reset(); |
| 267 void Load(const base::WeakPtr<GCMProfileService>& service); | 265 void Load(const base::WeakPtr<GCMProfileService>& service); |
| 268 void CheckOut(); | 266 void CheckOut(); |
| 269 void Register(const std::string& app_id, | 267 void Register(const std::string& app_id, |
| 270 const std::vector<std::string>& sender_ids, | 268 const std::string& sender_id, |
| 271 const std::string& cert); | 269 const std::string& cert); |
| 272 void Unregister(const std::string& app_id); | 270 void Unregister(const std::string& app_id); |
| 273 void Send(const std::string& app_id, | 271 void Send(const std::string& app_id, |
| 274 const std::string& receiver_id, | 272 const std::string& receiver_id, |
| 275 const GCMClient::OutgoingMessage& message); | 273 const GCMClient::OutgoingMessage& message); |
| 276 | 274 |
| 277 // For testing purpose. Can be called from UI thread. Use with care. | 275 // For testing purpose. Can be called from UI thread. Use with care. |
| 278 GCMClient* gcm_client_for_testing() const { return gcm_client_.get(); } | 276 GCMClient* gcm_client_for_testing() const { return gcm_client_.get(); } |
| 279 | 277 |
| 280 private: | 278 private: |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 430 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 428 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
| 431 | 429 |
| 432 gcm_client_->CheckOut(); | 430 gcm_client_->CheckOut(); |
| 433 | 431 |
| 434 // Note that we still need to keep GCMClient instance alive since the profile | 432 // Note that we still need to keep GCMClient instance alive since the profile |
| 435 // might be signed in again. | 433 // might be signed in again. |
| 436 } | 434 } |
| 437 | 435 |
| 438 void GCMProfileService::IOWorker::Register( | 436 void GCMProfileService::IOWorker::Register( |
| 439 const std::string& app_id, | 437 const std::string& app_id, |
| 440 const std::vector<std::string>& sender_ids, | 438 const std::string& sender_id, |
| 441 const std::string& cert) { | 439 const std::string& cert) { |
| 442 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 440 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
| 443 | 441 |
| 444 gcm_client_->Register(app_id, cert, sender_ids); | 442 gcm_client_->Register(app_id, cert, sender_id); |
| 445 } | 443 } |
| 446 | 444 |
| 447 void GCMProfileService::IOWorker::Unregister(const std::string& app_id) { | 445 void GCMProfileService::IOWorker::Unregister(const std::string& app_id) { |
| 448 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 446 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
| 449 | 447 |
| 450 gcm_client_->Unregister(app_id); | 448 gcm_client_->Unregister(app_id); |
| 451 } | 449 } |
| 452 | 450 |
| 453 void GCMProfileService::IOWorker::Send( | 451 void GCMProfileService::IOWorker::Send( |
| 454 const std::string& app_id, | 452 const std::string& app_id, |
| 455 const std::string& receiver_id, | 453 const std::string& receiver_id, |
| 456 const GCMClient::OutgoingMessage& message) { | 454 const GCMClient::OutgoingMessage& message) { |
| 457 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 455 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
| 458 | 456 |
| 459 gcm_client_->Send(app_id, receiver_id, message); | 457 gcm_client_->Send(app_id, receiver_id, message); |
| 460 } | 458 } |
| 461 | 459 |
| 462 GCMProfileService::RegistrationInfo::RegistrationInfo() { | 460 GCMProfileService::RegistrationInfo::RegistrationInfo() { |
| 463 } | 461 } |
| 464 | 462 |
| 465 GCMProfileService::RegistrationInfo::~RegistrationInfo() { | 463 GCMProfileService::RegistrationInfo::~RegistrationInfo() { |
| 466 } | 464 } |
| 467 | 465 |
| 468 bool GCMProfileService::RegistrationInfo::IsValid() const { | 466 bool GCMProfileService::RegistrationInfo::IsValid() const { |
| 469 return !sender_ids.empty() && !registration_id.empty(); | 467 return !sender_id.empty() && !registration_id.empty(); |
| 470 } | 468 } |
| 471 | 469 |
| 472 // static | 470 // static |
| 473 GCMProfileService::GCMEnabledState GCMProfileService::GetGCMEnabledState( | 471 GCMProfileService::GCMEnabledState GCMProfileService::GetGCMEnabledState( |
| 474 Profile* profile) { | 472 Profile* profile) { |
| 475 const base::Value* gcm_enabled_value = | 473 const base::Value* gcm_enabled_value = |
| 476 profile->GetPrefs()->GetUserPrefValue(prefs::kGCMChannelEnabled); | 474 profile->GetPrefs()->GetUserPrefValue(prefs::kGCMChannelEnabled); |
| 477 if (!gcm_enabled_value) | 475 if (!gcm_enabled_value) |
| 478 return ENABLED_FOR_APPS; | 476 return ENABLED_FOR_APPS; |
| 479 | 477 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 553 account_ids, | 551 account_ids, |
| 554 url_request_context_getter)); | 552 url_request_context_getter)); |
| 555 | 553 |
| 556 // Load from the GCM store and initiate the GCM check-in if the rollout signal | 554 // Load from the GCM store and initiate the GCM check-in if the rollout signal |
| 557 // indicates yes. | 555 // indicates yes. |
| 558 if (GetGCMEnabledState(profile_) == ALWAYS_ENABLED) | 556 if (GetGCMEnabledState(profile_) == ALWAYS_ENABLED) |
| 559 EnsureLoaded(); | 557 EnsureLoaded(); |
| 560 } | 558 } |
| 561 | 559 |
| 562 void GCMProfileService::Register(const std::string& app_id, | 560 void GCMProfileService::Register(const std::string& app_id, |
| 563 const std::vector<std::string>& sender_ids, | 561 const std::string& sender_id, |
| 564 const std::string& cert, | 562 const std::string& cert, |
| 565 RegisterCallback callback) { | 563 RegisterCallback callback) { |
| 566 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 564 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 567 DCHECK(!app_id.empty() && !sender_ids.empty() && !callback.is_null()); | 565 DCHECK(!app_id.empty() && !sender_id.empty() && !callback.is_null()); |
| 568 | 566 |
| 569 // Ensure that check-in has been done. | 567 // Ensure that check-in has been done. |
| 570 EnsureLoaded(); | 568 EnsureLoaded(); |
| 571 | 569 |
| 572 // If the profile was not signed in, bail out. | 570 // If the profile was not signed in, bail out. |
| 573 if (username_.empty()) { | 571 if (username_.empty()) { |
| 574 callback.Run(std::string(), GCMClient::NOT_SIGNED_IN); | 572 callback.Run(std::string(), GCMClient::NOT_SIGNED_IN); |
| 575 return; | 573 return; |
| 576 } | 574 } |
| 577 | 575 |
| 578 // If previous register operation is still in progress, bail out. | 576 // If previous register operation is still in progress, bail out. |
| 579 if (register_callbacks_.find(app_id) != register_callbacks_.end()) { | 577 if (register_callbacks_.find(app_id) != register_callbacks_.end()) { |
| 580 callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING); | 578 callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING); |
| 581 return; | 579 return; |
| 582 } | 580 } |
| 583 | 581 |
| 584 register_callbacks_[app_id] = callback; | 582 register_callbacks_[app_id] = callback; |
| 585 | 583 |
| 586 EnsureAppReady(app_id); | 584 EnsureAppReady(app_id); |
| 587 | 585 |
| 588 // Delay the register operation until GCMClient is ready. | 586 // Delay the register operation until GCMClient is ready. |
| 589 if (!delayed_task_controller_->CanRunTaskWithoutDelay(app_id)) { | 587 if (!delayed_task_controller_->CanRunTaskWithoutDelay(app_id)) { |
| 590 delayed_task_controller_->AddTask( | 588 delayed_task_controller_->AddTask( |
| 591 app_id, | 589 app_id, |
| 592 base::Bind(&GCMProfileService::DoRegister, | 590 base::Bind(&GCMProfileService::DoRegister, |
| 593 weak_ptr_factory_.GetWeakPtr(), | 591 weak_ptr_factory_.GetWeakPtr(), |
| 594 app_id, | 592 app_id, |
| 595 sender_ids, | 593 sender_id, |
| 596 cert)); | 594 cert)); |
| 597 return; | 595 return; |
| 598 } | 596 } |
| 599 | 597 |
| 600 DoRegister(app_id, sender_ids, cert); | 598 DoRegister(app_id, sender_id, cert); |
| 601 } | 599 } |
| 602 | 600 |
| 603 void GCMProfileService::DoRegister(const std::string& app_id, | 601 void GCMProfileService::DoRegister(const std::string& app_id, |
| 604 const std::vector<std::string>& sender_ids, | 602 const std::string& sender_id, |
| 605 const std::string& cert) { | 603 const std::string& cert) { |
| 606 std::map<std::string, RegisterCallback>::iterator callback_iter = | 604 std::map<std::string, RegisterCallback>::iterator callback_iter = |
| 607 register_callbacks_.find(app_id); | 605 register_callbacks_.find(app_id); |
| 608 if (callback_iter == register_callbacks_.end()) { | 606 if (callback_iter == register_callbacks_.end()) { |
| 609 // The callback could have been removed when the app is uninstalled. | 607 // The callback could have been removed when the app is uninstalled. |
| 610 return; | 608 return; |
| 611 } | 609 } |
| 612 | 610 |
| 613 // Normalize the sender IDs by making them sorted. | |
| 614 std::vector<std::string> normalized_sender_ids = sender_ids; | |
| 615 std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end()); | |
| 616 | |
| 617 // If the same sender ids is provided, return the cached registration ID | 611 // If the same sender ids is provided, return the cached registration ID |
| 618 // directly. | 612 // directly. |
| 619 RegistrationInfoMap::const_iterator registration_info_iter = | 613 RegistrationInfoMap::const_iterator registration_info_iter = |
| 620 registration_info_map_.find(app_id); | 614 registration_info_map_.find(app_id); |
| 621 if (registration_info_iter != registration_info_map_.end() && | 615 if (registration_info_iter != registration_info_map_.end() && |
| 622 registration_info_iter->second.sender_ids == normalized_sender_ids) { | 616 registration_info_iter->second.sender_id == sender_id) { |
| 623 RegisterCallback callback = callback_iter->second; | 617 RegisterCallback callback = callback_iter->second; |
| 624 register_callbacks_.erase(callback_iter); | 618 register_callbacks_.erase(callback_iter); |
| 625 callback.Run(registration_info_iter->second.registration_id, | 619 callback.Run(registration_info_iter->second.registration_id, |
| 626 GCMClient::SUCCESS); | 620 GCMClient::SUCCESS); |
| 627 return; | 621 return; |
| 628 } | 622 } |
| 629 | 623 |
| 630 // Cache the sender IDs. The registration ID will be filled when the | 624 // Cache the sender IDs. The registration ID will be filled when the |
| 631 // registration completes. | 625 // registration completes. |
| 632 RegistrationInfo registration_info; | 626 RegistrationInfo registration_info; |
| 633 registration_info.sender_ids = normalized_sender_ids; | 627 registration_info.sender_id = sender_id; |
| 634 registration_info_map_[app_id] = registration_info; | 628 registration_info_map_[app_id] = registration_info; |
| 635 | 629 |
| 636 // Save the IDs of all registered apps such that we know what to remove from | 630 // Save the IDs of all registered apps such that we know what to remove from |
| 637 // the the app's state store when the profile is signed out. | 631 // the the app's state store when the profile is signed out. |
| 638 WriteRegisteredAppIDs(); | 632 WriteRegisteredAppIDs(); |
| 639 | 633 |
| 640 content::BrowserThread::PostTask( | 634 content::BrowserThread::PostTask( |
| 641 content::BrowserThread::IO, | 635 content::BrowserThread::IO, |
| 642 FROM_HERE, | 636 FROM_HERE, |
| 643 base::Bind(&GCMProfileService::IOWorker::Register, | 637 base::Bind(&GCMProfileService::IOWorker::Register, |
| 644 io_worker_, | 638 io_worker_, |
| 645 app_id, | 639 app_id, |
| 646 normalized_sender_ids, | 640 sender_id, |
| 647 cert)); | 641 cert)); |
| 648 } | 642 } |
| 649 | 643 |
| 650 void GCMProfileService::Send(const std::string& app_id, | 644 void GCMProfileService::Send(const std::string& app_id, |
| 651 const std::string& receiver_id, | 645 const std::string& receiver_id, |
| 652 const GCMClient::OutgoingMessage& message, | 646 const GCMClient::OutgoingMessage& message, |
| 653 SendCallback callback) { | 647 SendCallback callback) { |
| 654 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 648 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 655 DCHECK(!app_id.empty() && !receiver_id.empty() && !callback.is_null()); | 649 DCHECK(!app_id.empty() && !receiver_id.empty() && !callback.is_null()); |
| 656 | 650 |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 989 | 983 |
| 990 void GCMProfileService::WriteRegistrationInfo(const std::string& app_id) { | 984 void GCMProfileService::WriteRegistrationInfo(const std::string& app_id) { |
| 991 extensions::StateStore* storage = | 985 extensions::StateStore* storage = |
| 992 extensions::ExtensionSystem::Get(profile_)->state_store(); | 986 extensions::ExtensionSystem::Get(profile_)->state_store(); |
| 993 DCHECK(storage); | 987 DCHECK(storage); |
| 994 | 988 |
| 995 RegistrationInfoMap::const_iterator registration_info_iter = | 989 RegistrationInfoMap::const_iterator registration_info_iter = |
| 996 registration_info_map_.find(app_id); | 990 registration_info_map_.find(app_id); |
| 997 if (registration_info_iter == registration_info_map_.end()) | 991 if (registration_info_iter == registration_info_map_.end()) |
| 998 return; | 992 return; |
| 993 | |
| 999 const RegistrationInfo& registration_info = registration_info_iter->second; | 994 const RegistrationInfo& registration_info = registration_info_iter->second; |
| 1000 | |
| 1001 scoped_ptr<base::ListValue> senders_list(new base::ListValue()); | |
| 1002 for (std::vector<std::string>::const_iterator senders_iter = | |
| 1003 registration_info.sender_ids.begin(); | |
| 1004 senders_iter != registration_info.sender_ids.end(); | |
| 1005 ++senders_iter) { | |
| 1006 senders_list->AppendString(*senders_iter); | |
| 1007 } | |
| 1008 | |
| 1009 scoped_ptr<base::DictionaryValue> registration_info_dict( | 995 scoped_ptr<base::DictionaryValue> registration_info_dict( |
| 1010 new base::DictionaryValue()); | 996 new base::DictionaryValue()); |
| 1011 registration_info_dict->Set(kSendersKey, senders_list.release()); | 997 registration_info_dict->SetString(registration_info.sender_id, |
| 1012 registration_info_dict->SetString(kRegistrationIDKey, | |
| 1013 registration_info.registration_id); | 998 registration_info.registration_id); |
| 1014 | 999 |
| 1015 storage->SetExtensionValue( | 1000 storage->SetExtensionValue( |
| 1016 app_id, kRegistrationKey, registration_info_dict.PassAs<base::Value>()); | 1001 app_id, kRegistrationKey, registration_info_dict.PassAs<base::Value>()); |
| 1017 } | 1002 } |
| 1018 | 1003 |
| 1019 void GCMProfileService::ReadRegistrationInfo(const std::string& app_id) { | 1004 void GCMProfileService::ReadRegistrationInfo(const std::string& app_id) { |
| 1020 delayed_task_controller_->AddApp(app_id); | 1005 delayed_task_controller_->AddApp(app_id); |
| 1021 | 1006 |
| 1022 extensions::StateStore* storage = | 1007 extensions::StateStore* storage = |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 1047 delayed_task_controller_->SetAppReady(app_id); | 1032 delayed_task_controller_->SetAppReady(app_id); |
| 1048 } | 1033 } |
| 1049 | 1034 |
| 1050 bool GCMProfileService::ParsePersistedRegistrationInfo( | 1035 bool GCMProfileService::ParsePersistedRegistrationInfo( |
| 1051 scoped_ptr<base::Value> value, | 1036 scoped_ptr<base::Value> value, |
| 1052 RegistrationInfo* registration_info) { | 1037 RegistrationInfo* registration_info) { |
| 1053 base::DictionaryValue* dict = NULL; | 1038 base::DictionaryValue* dict = NULL; |
| 1054 if (!value.get() || !value->GetAsDictionary(&dict)) | 1039 if (!value.get() || !value->GetAsDictionary(&dict)) |
| 1055 return false; | 1040 return false; |
| 1056 | 1041 |
| 1057 if (!dict->GetString(kRegistrationIDKey, ®istration_info->registration_id)) | 1042 // TODO(fgorski): Remove a DCHECK when more than a single sender is allowed. |
| 1058 return false; | 1043 DCHECK_LE(dict->size(), 1UL); |
| 1059 | 1044 |
| 1060 const base::ListValue* senders_list = NULL; | 1045 for (base::DictionaryValue::Iterator iter(*dict); |
| 1061 if (!dict->GetList(kSendersKey, &senders_list) || !senders_list->GetSize()) | 1046 !iter.IsAtEnd(); |
| 1062 return false; | 1047 iter.Advance()) { |
| 1063 for (size_t i = 0; i < senders_list->GetSize(); ++i) { | 1048 registration_info->sender_id = iter.key(); |
| 1064 std::string sender; | 1049 if (iter.value().GetAsString(®istration_info->registration_id)) |
| 1065 if (!senders_list->GetString(i, &sender)) | 1050 return true; |
| 1066 return false; | |
| 1067 registration_info->sender_ids.push_back(sender); | |
| 1068 } | 1051 } |
| 1069 | 1052 |
| 1070 return true; | 1053 // TODO(fgorski): Switch the return statements when multiple sendres are |
|
jianli
2014/03/04 01:13:53
Probably you only need to add one TODO comment at
| |
| 1054 // allowed. | |
| 1055 return false; | |
| 1071 } | 1056 } |
| 1072 | 1057 |
| 1073 // static | 1058 // static |
| 1074 const char* GCMProfileService::GetPersistentRegisterKeyForTesting() { | 1059 const char* GCMProfileService::GetPersistentRegisterKeyForTesting() { |
| 1075 return kRegistrationKey; | 1060 return kRegistrationKey; |
| 1076 } | 1061 } |
| 1077 | 1062 |
| 1078 } // namespace gcm | 1063 } // namespace gcm |
| OLD | NEW |