| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/gcm_driver/fake_gcm_client.h" |
| |
| #include <stddef.h> |
| |
| #include <algorithm> |
| |
| #include "base/bind.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| #include "base/sequenced_task_runner.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/sys_byteorder.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "base/timer/timer.h" |
| #include "google_apis/gcm/base/encryptor.h" |
| #include "google_apis/gcm/engine/account_mapping.h" |
| #include "net/base/ip_endpoint.h" |
| |
| namespace gcm { |
| |
| // static |
| std::string FakeGCMClient::GenerateGCMRegistrationID( |
| const std::vector<std::string>& sender_ids) { |
| // GCMService normalizes the sender IDs by making them sorted. |
| std::vector<std::string> normalized_sender_ids = sender_ids; |
| std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end()); |
| |
| // Simulate the registration_id by concaternating all sender IDs. |
| // Set registration_id to empty to denote an error if sender_ids contains a |
| // hint. |
| std::string registration_id; |
| if (sender_ids.size() != 1 || |
| sender_ids[0].find("error") == std::string::npos) { |
| for (size_t i = 0; i < normalized_sender_ids.size(); ++i) { |
| if (i > 0) |
| registration_id += ","; |
| registration_id += normalized_sender_ids[i]; |
| } |
| } |
| return registration_id; |
| } |
| |
| // static |
| std::string FakeGCMClient::GenerateInstanceIDToken( |
| const std::string& authorized_entity, const std::string& scope) { |
| if (authorized_entity.find("error") != std::string::npos) |
| return ""; |
| std::string token(authorized_entity); |
| token += ","; |
| token += scope; |
| return token; |
| } |
| |
| FakeGCMClient::FakeGCMClient( |
| const scoped_refptr<base::SequencedTaskRunner>& ui_thread, |
| const scoped_refptr<base::SequencedTaskRunner>& io_thread) |
| : delegate_(nullptr), |
| started_(false), |
| start_mode_(DELAYED_START), |
| start_mode_overridding_(RESPECT_START_MODE), |
| ui_thread_(ui_thread), |
| io_thread_(io_thread), |
| weak_ptr_factory_(this) {} |
| |
| FakeGCMClient::~FakeGCMClient() { |
| } |
| |
| void FakeGCMClient::Initialize( |
| const ChromeBuildInfo& chrome_build_info, |
| const base::FilePath& store_path, |
| const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, |
| const scoped_refptr<net::URLRequestContextGetter>& |
| url_request_context_getter, |
| std::unique_ptr<Encryptor> encryptor, |
| Delegate* delegate) { |
| product_category_for_subtypes_ = |
| chrome_build_info.product_category_for_subtypes; |
| delegate_ = delegate; |
| } |
| |
| void FakeGCMClient::Start(StartMode start_mode) { |
| DCHECK(io_thread_->RunsTasksInCurrentSequence()); |
| |
| if (started_) |
| return; |
| |
| if (start_mode == IMMEDIATE_START) |
| start_mode_ = IMMEDIATE_START; |
| if (start_mode_ == DELAYED_START || |
| start_mode_overridding_ == FORCE_TO_ALWAYS_DELAY_START_GCM) { |
| return; |
| } |
| |
| DoStart(); |
| } |
| |
| void FakeGCMClient::DoStart() { |
| started_ = true; |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, |
| base::Bind(&FakeGCMClient::Started, weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void FakeGCMClient::Stop() { |
| DCHECK(io_thread_->RunsTasksInCurrentSequence()); |
| started_ = false; |
| delegate_->OnDisconnected(); |
| } |
| |
| void FakeGCMClient::Register( |
| const linked_ptr<RegistrationInfo>& registration_info) { |
| DCHECK(io_thread_->RunsTasksInCurrentSequence()); |
| |
| std::string registration_id; |
| |
| GCMRegistrationInfo* gcm_registration_info = |
| GCMRegistrationInfo::FromRegistrationInfo(registration_info.get()); |
| if (gcm_registration_info) { |
| registration_id = GenerateGCMRegistrationID( |
| gcm_registration_info->sender_ids); |
| } |
| |
| InstanceIDTokenInfo* instance_id_token_info = |
| InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get()); |
| if (instance_id_token_info) { |
| registration_id = GenerateInstanceIDToken( |
| instance_id_token_info->authorized_entity, |
| instance_id_token_info->scope); |
| } |
| |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::Bind(&FakeGCMClient::RegisterFinished, |
| weak_ptr_factory_.GetWeakPtr(), registration_info, |
| registration_id)); |
| } |
| |
| bool FakeGCMClient::ValidateRegistration( |
| const linked_ptr<RegistrationInfo>& registration_info, |
| const std::string& registration_id) { |
| return true; |
| } |
| |
| void FakeGCMClient::Unregister( |
| const linked_ptr<RegistrationInfo>& registration_info) { |
| DCHECK(io_thread_->RunsTasksInCurrentSequence()); |
| |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::Bind(&FakeGCMClient::UnregisterFinished, |
| weak_ptr_factory_.GetWeakPtr(), registration_info)); |
| } |
| |
| void FakeGCMClient::Send(const std::string& app_id, |
| const std::string& receiver_id, |
| const OutgoingMessage& message) { |
| DCHECK(io_thread_->RunsTasksInCurrentSequence()); |
| |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::Bind(&FakeGCMClient::SendFinished, |
| weak_ptr_factory_.GetWeakPtr(), app_id, message)); |
| } |
| |
| void FakeGCMClient::RecordDecryptionFailure(const std::string& app_id, |
| GCMDecryptionResult result) { |
| recorder_.RecordDecryptionFailure(app_id, result); |
| } |
| |
| void FakeGCMClient::SetRecording(bool recording) { |
| recorder_.set_is_recording(recording); |
| } |
| |
| void FakeGCMClient::ClearActivityLogs() { |
| recorder_.Clear(); |
| } |
| |
| GCMClient::GCMStatistics FakeGCMClient::GetStatistics() const { |
| GCMClient::GCMStatistics statistics; |
| statistics.is_recording = recorder_.is_recording(); |
| |
| recorder_.CollectActivities(&statistics.recorded_activities); |
| return statistics; |
| } |
| |
| void FakeGCMClient::SetAccountTokens( |
| const std::vector<AccountTokenInfo>& account_tokens) { |
| } |
| |
| void FakeGCMClient::UpdateAccountMapping( |
| const AccountMapping& account_mapping) { |
| } |
| |
| void FakeGCMClient::RemoveAccountMapping(const std::string& account_id) { |
| } |
| |
| void FakeGCMClient::SetLastTokenFetchTime(const base::Time& time) { |
| } |
| |
| void FakeGCMClient::UpdateHeartbeatTimer(std::unique_ptr<base::Timer> timer) {} |
| |
| void FakeGCMClient::AddInstanceIDData(const std::string& app_id, |
| const std::string& instance_id, |
| const std::string& extra_data) { |
| instance_id_data_[app_id] = make_pair(instance_id, extra_data); |
| } |
| |
| void FakeGCMClient::RemoveInstanceIDData(const std::string& app_id) { |
| instance_id_data_.erase(app_id); |
| } |
| |
| void FakeGCMClient::GetInstanceIDData(const std::string& app_id, |
| std::string* instance_id, |
| std::string* extra_data) { |
| auto iter = instance_id_data_.find(app_id); |
| if (iter == instance_id_data_.end()) { |
| instance_id->clear(); |
| extra_data->clear(); |
| return; |
| } |
| |
| *instance_id = iter->second.first; |
| *extra_data = iter->second.second; |
| } |
| |
| void FakeGCMClient::AddHeartbeatInterval(const std::string& scope, |
| int interval_ms) { |
| } |
| |
| void FakeGCMClient::RemoveHeartbeatInterval(const std::string& scope) { |
| } |
| |
| void FakeGCMClient::PerformDelayedStart() { |
| DCHECK(ui_thread_->RunsTasksInCurrentSequence()); |
| |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&FakeGCMClient::DoStart, weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void FakeGCMClient::ReceiveMessage(const std::string& app_id, |
| const IncomingMessage& message) { |
| DCHECK(ui_thread_->RunsTasksInCurrentSequence()); |
| |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&FakeGCMClient::MessageReceived, |
| weak_ptr_factory_.GetWeakPtr(), |
| app_id, |
| message)); |
| } |
| |
| void FakeGCMClient::DeleteMessages(const std::string& app_id) { |
| DCHECK(ui_thread_->RunsTasksInCurrentSequence()); |
| |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&FakeGCMClient::MessagesDeleted, |
| weak_ptr_factory_.GetWeakPtr(), |
| app_id)); |
| } |
| |
| void FakeGCMClient::Started() { |
| delegate_->OnGCMReady(std::vector<AccountMapping>(), base::Time()); |
| delegate_->OnConnected(net::IPEndPoint()); |
| } |
| |
| void FakeGCMClient::RegisterFinished( |
| const linked_ptr<RegistrationInfo>& registration_info, |
| const std::string& registrion_id) { |
| delegate_->OnRegisterFinished( |
| registration_info, |
| registrion_id, |
| registrion_id.empty() ? SERVER_ERROR : SUCCESS); |
| } |
| |
| void FakeGCMClient::UnregisterFinished( |
| const linked_ptr<RegistrationInfo>& registration_info) { |
| delegate_->OnUnregisterFinished(registration_info, GCMClient::SUCCESS); |
| } |
| |
| void FakeGCMClient::SendFinished(const std::string& app_id, |
| const OutgoingMessage& message) { |
| delegate_->OnSendFinished(app_id, message.id, SUCCESS); |
| |
| // Simulate send error if message id contains a hint. |
| if (message.id.find("error") != std::string::npos) { |
| SendErrorDetails send_error_details; |
| send_error_details.message_id = message.id; |
| send_error_details.result = NETWORK_ERROR; |
| send_error_details.additional_data = message.data; |
| base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| FROM_HERE, |
| base::Bind(&FakeGCMClient::MessageSendError, |
| weak_ptr_factory_.GetWeakPtr(), app_id, send_error_details), |
| base::TimeDelta::FromMilliseconds(200)); |
| } else if(message.id.find("ack") != std::string::npos) { |
| base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| FROM_HERE, |
| base::Bind(&FakeGCMClient::SendAcknowledgement, |
| weak_ptr_factory_.GetWeakPtr(), app_id, message.id), |
| base::TimeDelta::FromMilliseconds(200)); |
| } |
| } |
| |
| void FakeGCMClient::MessageReceived(const std::string& app_id, |
| const IncomingMessage& message) { |
| if (delegate_) |
| delegate_->OnMessageReceived(app_id, message); |
| } |
| |
| void FakeGCMClient::MessagesDeleted(const std::string& app_id) { |
| if (delegate_) |
| delegate_->OnMessagesDeleted(app_id); |
| } |
| |
| void FakeGCMClient::MessageSendError( |
| const std::string& app_id, |
| const GCMClient::SendErrorDetails& send_error_details) { |
| if (delegate_) |
| delegate_->OnMessageSendError(app_id, send_error_details); |
| } |
| |
| void FakeGCMClient::SendAcknowledgement(const std::string& app_id, |
| const std::string& message_id) { |
| if (delegate_) |
| delegate_->OnSendAcknowledged(app_id, message_id); |
| } |
| |
| } // namespace gcm |