| // 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/gcm_driver_desktop.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/files/file_path.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/profiler/scoped_tracker.h" |
| #include "base/sequenced_task_runner.h" |
| #include "base/threading/sequenced_worker_pool.h" |
| #include "build/build_config.h" |
| #include "components/gcm_driver/gcm_account_mapper.h" |
| #include "components/gcm_driver/gcm_app_handler.h" |
| #include "components/gcm_driver/gcm_channel_status_syncer.h" |
| #include "components/gcm_driver/gcm_client_factory.h" |
| #include "components/gcm_driver/gcm_delayed_task_controller.h" |
| #include "components/gcm_driver/instance_id/instance_id_impl.h" |
| #include "components/gcm_driver/system_encryptor.h" |
| #include "google_apis/gcm/engine/account_mapping.h" |
| #include "net/base/ip_endpoint.h" |
| #include "net/url_request/url_request_context_getter.h" |
| |
| #if defined(OS_CHROMEOS) |
| #include "components/timers/alarm_timer_chromeos.h" |
| #endif |
| |
| namespace gcm { |
| |
| class GCMDriverDesktop::IOWorker : public GCMClient::Delegate { |
| public: |
| // Called on UI thread. |
| IOWorker(const scoped_refptr<base::SequencedTaskRunner>& ui_thread, |
| const scoped_refptr<base::SequencedTaskRunner>& io_thread); |
| virtual ~IOWorker(); |
| |
| // Overridden from GCMClient::Delegate: |
| // Called on IO thread. |
| void OnRegisterFinished(const linked_ptr<RegistrationInfo>& registration_info, |
| const std::string& registration_id, |
| GCMClient::Result result) override; |
| void OnUnregisterFinished( |
| const linked_ptr<RegistrationInfo>& registration_info, |
| GCMClient::Result result) override; |
| void OnSendFinished(const std::string& app_id, |
| const std::string& message_id, |
| GCMClient::Result result) override; |
| void OnMessageReceived(const std::string& app_id, |
| const IncomingMessage& message) override; |
| void OnMessagesDeleted(const std::string& app_id) override; |
| void OnMessageSendError( |
| const std::string& app_id, |
| const GCMClient::SendErrorDetails& send_error_details) override; |
| void OnSendAcknowledged(const std::string& app_id, |
| const std::string& message_id) override; |
| void OnGCMReady(const std::vector<AccountMapping>& account_mappings, |
| const base::Time& last_token_fetch_time) override; |
| void OnActivityRecorded() override; |
| void OnConnected(const net::IPEndPoint& ip_endpoint) override; |
| void OnDisconnected() override; |
| void OnStoreReset() override; |
| |
| // Called on IO thread. |
| void Initialize( |
| std::unique_ptr<GCMClientFactory> gcm_client_factory, |
| const GCMClient::ChromeBuildInfo& chrome_build_info, |
| const base::FilePath& store_path, |
| const scoped_refptr<net::URLRequestContextGetter>& request_context, |
| const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner); |
| void Start(GCMClient::StartMode start_mode, |
| const base::WeakPtr<GCMDriverDesktop>& service); |
| void Stop(); |
| void Register(const std::string& app_id, |
| const std::vector<std::string>& sender_ids); |
| void Unregister(const std::string& app_id); |
| void Send(const std::string& app_id, |
| const std::string& receiver_id, |
| const OutgoingMessage& message); |
| void GetGCMStatistics(GCMDriver::ClearActivityLogs clear_logs); |
| void SetGCMRecording(bool recording); |
| |
| void SetAccountTokens( |
| const std::vector<GCMClient::AccountTokenInfo>& account_tokens); |
| void UpdateAccountMapping(const AccountMapping& account_mapping); |
| void RemoveAccountMapping(const std::string& account_id); |
| void SetLastTokenFetchTime(const base::Time& time); |
| void WakeFromSuspendForHeartbeat(bool wake); |
| void AddHeartbeatInterval(const std::string& scope, int interval_ms); |
| void RemoveHeartbeatInterval(const std::string& scope); |
| |
| void AddInstanceIDData(const std::string& app_id, |
| const std::string& instance_id, |
| const std::string& extra_data); |
| void RemoveInstanceIDData(const std::string& app_id); |
| void GetInstanceIDData(const std::string& app_id); |
| void GetToken(const std::string& app_id, |
| const std::string& authorized_entity, |
| const std::string& scope, |
| const std::map<std::string, std::string>& options); |
| void DeleteToken(const std::string& app_id, |
| const std::string& authorized_entity, |
| const std::string& scope); |
| |
| void RecordDecryptionFailure(const std::string& app_id, |
| GCMEncryptionProvider::DecryptionResult result); |
| |
| // For testing purpose. Can be called from UI thread. Use with care. |
| GCMClient* gcm_client_for_testing() const { return gcm_client_.get(); } |
| |
| private: |
| scoped_refptr<base::SequencedTaskRunner> ui_thread_; |
| scoped_refptr<base::SequencedTaskRunner> io_thread_; |
| |
| base::WeakPtr<GCMDriverDesktop> service_; |
| |
| std::unique_ptr<GCMClient> gcm_client_; |
| |
| DISALLOW_COPY_AND_ASSIGN(IOWorker); |
| }; |
| |
| GCMDriverDesktop::IOWorker::IOWorker( |
| const scoped_refptr<base::SequencedTaskRunner>& ui_thread, |
| const scoped_refptr<base::SequencedTaskRunner>& io_thread) |
| : ui_thread_(ui_thread), |
| io_thread_(io_thread) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| } |
| |
| GCMDriverDesktop::IOWorker::~IOWorker() { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| } |
| |
| void GCMDriverDesktop::IOWorker::Initialize( |
| std::unique_ptr<GCMClientFactory> gcm_client_factory, |
| const GCMClient::ChromeBuildInfo& chrome_build_info, |
| const base::FilePath& store_path, |
| const scoped_refptr<net::URLRequestContextGetter>& request_context, |
| const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) { |
| // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed. |
| tracked_objects::ScopedTracker tracking_profile( |
| FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| "477117 GCMDriverDesktop::IOWorker::Initialize")); |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| gcm_client_ = gcm_client_factory->BuildInstance(); |
| |
| gcm_client_->Initialize( |
| chrome_build_info, store_path, blocking_task_runner, request_context, |
| base::WrapUnique<Encryptor>(new SystemEncryptor), this); |
| } |
| |
| void GCMDriverDesktop::IOWorker::OnRegisterFinished( |
| const linked_ptr<RegistrationInfo>& registration_info, |
| const std::string& registration_id, |
| GCMClient::Result result) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| const GCMRegistrationInfo* gcm_registration_info = |
| GCMRegistrationInfo::FromRegistrationInfo(registration_info.get()); |
| if (gcm_registration_info) { |
| ui_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::RegisterFinished, |
| service_, |
| gcm_registration_info->app_id, |
| registration_id, |
| result)); |
| } |
| |
| const InstanceIDTokenInfo* instance_id_token_info = |
| InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get()); |
| if (instance_id_token_info) { |
| ui_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::GetTokenFinished, |
| service_, |
| instance_id_token_info->app_id, |
| instance_id_token_info->authorized_entity, |
| instance_id_token_info->scope, |
| registration_id, |
| result)); |
| } |
| } |
| |
| void GCMDriverDesktop::IOWorker::OnUnregisterFinished( |
| const linked_ptr<RegistrationInfo>& registration_info, |
| GCMClient::Result result) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| const GCMRegistrationInfo* gcm_registration_info = |
| GCMRegistrationInfo::FromRegistrationInfo(registration_info.get()); |
| if (gcm_registration_info) { |
| ui_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::RemoveEncryptionInfoAfterUnregister, |
| service_, |
| gcm_registration_info->app_id, |
| result)); |
| } |
| |
| const InstanceIDTokenInfo* instance_id_token_info = |
| InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get()); |
| if (instance_id_token_info) { |
| ui_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::DeleteTokenFinished, |
| service_, |
| instance_id_token_info->app_id, |
| instance_id_token_info->authorized_entity, |
| instance_id_token_info->scope, |
| result)); |
| } |
| } |
| |
| void GCMDriverDesktop::IOWorker::OnSendFinished(const std::string& app_id, |
| const std::string& message_id, |
| GCMClient::Result result) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| ui_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::SendFinished, service_, app_id, message_id, |
| result)); |
| } |
| |
| void GCMDriverDesktop::IOWorker::OnMessageReceived( |
| const std::string& app_id, |
| const IncomingMessage& message) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| ui_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::MessageReceived, |
| service_, |
| app_id, |
| message)); |
| } |
| |
| void GCMDriverDesktop::IOWorker::OnMessagesDeleted(const std::string& app_id) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| ui_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::MessagesDeleted, service_, app_id)); |
| } |
| |
| void GCMDriverDesktop::IOWorker::OnMessageSendError( |
| const std::string& app_id, |
| const GCMClient::SendErrorDetails& send_error_details) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| ui_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::MessageSendError, service_, app_id, |
| send_error_details)); |
| } |
| |
| void GCMDriverDesktop::IOWorker::OnSendAcknowledged( |
| const std::string& app_id, |
| const std::string& message_id) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| ui_thread_->PostTask( |
| FROM_HERE, |
| base::Bind( |
| &GCMDriverDesktop::SendAcknowledged, service_, app_id, message_id)); |
| } |
| |
| void GCMDriverDesktop::IOWorker::OnGCMReady( |
| const std::vector<AccountMapping>& account_mappings, |
| const base::Time& last_token_fetch_time) { |
| ui_thread_->PostTask(FROM_HERE, |
| base::Bind(&GCMDriverDesktop::GCMClientReady, |
| service_, |
| account_mappings, |
| last_token_fetch_time)); |
| } |
| |
| void GCMDriverDesktop::IOWorker::OnActivityRecorded() { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| // When an activity is recorded, get all the stats and refresh the UI of |
| // gcm-internals page. |
| GetGCMStatistics(GCMDriver::KEEP_LOGS); |
| } |
| |
| void GCMDriverDesktop::IOWorker::OnConnected( |
| const net::IPEndPoint& ip_endpoint) { |
| ui_thread_->PostTask(FROM_HERE, |
| base::Bind(&GCMDriverDesktop::OnConnected, |
| service_, |
| ip_endpoint)); |
| } |
| |
| void GCMDriverDesktop::IOWorker::OnDisconnected() { |
| ui_thread_->PostTask(FROM_HERE, |
| base::Bind(&GCMDriverDesktop::OnDisconnected, service_)); |
| } |
| |
| void GCMDriverDesktop::IOWorker::OnStoreReset() { |
| ui_thread_->PostTask(FROM_HERE, |
| base::Bind(&GCMDriverDesktop::OnStoreReset, service_)); |
| } |
| |
| void GCMDriverDesktop::IOWorker::Start( |
| GCMClient::StartMode start_mode, |
| const base::WeakPtr<GCMDriverDesktop>& service) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| service_ = service; |
| gcm_client_->Start(start_mode); |
| } |
| |
| void GCMDriverDesktop::IOWorker::Stop() { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| gcm_client_->Stop(); |
| } |
| |
| void GCMDriverDesktop::IOWorker::Register( |
| const std::string& app_id, |
| const std::vector<std::string>& sender_ids) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| std::unique_ptr<GCMRegistrationInfo> gcm_info(new GCMRegistrationInfo); |
| gcm_info->app_id = app_id; |
| gcm_info->sender_ids = sender_ids; |
| gcm_client_->Register(make_linked_ptr<RegistrationInfo>(gcm_info.release())); |
| } |
| |
| void GCMDriverDesktop::IOWorker::Unregister(const std::string& app_id) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| std::unique_ptr<GCMRegistrationInfo> gcm_info(new GCMRegistrationInfo); |
| gcm_info->app_id = app_id; |
| gcm_client_->Unregister( |
| make_linked_ptr<RegistrationInfo>(gcm_info.release())); |
| } |
| |
| void GCMDriverDesktop::IOWorker::Send(const std::string& app_id, |
| const std::string& receiver_id, |
| const OutgoingMessage& message) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| gcm_client_->Send(app_id, receiver_id, message); |
| } |
| |
| void GCMDriverDesktop::IOWorker::GetGCMStatistics( |
| ClearActivityLogs clear_logs) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| gcm::GCMClient::GCMStatistics stats; |
| |
| if (gcm_client_.get()) { |
| if (clear_logs == GCMDriver::CLEAR_LOGS) |
| gcm_client_->ClearActivityLogs(); |
| stats = gcm_client_->GetStatistics(); |
| } |
| |
| ui_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::GetGCMStatisticsFinished, service_, stats)); |
| } |
| |
| void GCMDriverDesktop::IOWorker::SetGCMRecording(bool recording) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| gcm::GCMClient::GCMStatistics stats; |
| |
| if (gcm_client_.get()) { |
| gcm_client_->SetRecording(recording); |
| stats = gcm_client_->GetStatistics(); |
| stats.gcm_client_created = true; |
| } |
| |
| ui_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::GetGCMStatisticsFinished, service_, stats)); |
| } |
| |
| void GCMDriverDesktop::IOWorker::SetAccountTokens( |
| const std::vector<GCMClient::AccountTokenInfo>& account_tokens) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| if (gcm_client_.get()) |
| gcm_client_->SetAccountTokens(account_tokens); |
| } |
| |
| void GCMDriverDesktop::IOWorker::UpdateAccountMapping( |
| const AccountMapping& account_mapping) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| if (gcm_client_.get()) |
| gcm_client_->UpdateAccountMapping(account_mapping); |
| } |
| |
| void GCMDriverDesktop::IOWorker::RemoveAccountMapping( |
| const std::string& account_id) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| if (gcm_client_.get()) |
| gcm_client_->RemoveAccountMapping(account_id); |
| } |
| |
| void GCMDriverDesktop::IOWorker::SetLastTokenFetchTime(const base::Time& time) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| if (gcm_client_.get()) |
| gcm_client_->SetLastTokenFetchTime(time); |
| } |
| |
| void GCMDriverDesktop::IOWorker::AddInstanceIDData( |
| const std::string& app_id, |
| const std::string& instance_id, |
| const std::string& extra_data) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| if (gcm_client_.get()) |
| gcm_client_->AddInstanceIDData(app_id, instance_id, extra_data); |
| } |
| |
| void GCMDriverDesktop::IOWorker::RemoveInstanceIDData( |
| const std::string& app_id) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| if (gcm_client_.get()) |
| gcm_client_->RemoveInstanceIDData(app_id); |
| } |
| |
| void GCMDriverDesktop::IOWorker::GetInstanceIDData( |
| const std::string& app_id) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| std::string instance_id; |
| std::string extra_data; |
| if (gcm_client_.get()) |
| gcm_client_->GetInstanceIDData(app_id, &instance_id, &extra_data); |
| |
| ui_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::GetInstanceIDDataFinished, |
| service_, app_id, instance_id, extra_data)); |
| } |
| |
| void GCMDriverDesktop::IOWorker::GetToken( |
| const std::string& app_id, |
| const std::string& authorized_entity, |
| const std::string& scope, |
| const std::map<std::string, std::string>& options) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| std::unique_ptr<InstanceIDTokenInfo> instance_id_token_info( |
| new InstanceIDTokenInfo); |
| instance_id_token_info->app_id = app_id; |
| instance_id_token_info->authorized_entity = authorized_entity; |
| instance_id_token_info->scope = scope; |
| instance_id_token_info->options = options; |
| gcm_client_->Register( |
| make_linked_ptr<RegistrationInfo>(instance_id_token_info.release())); |
| } |
| |
| void GCMDriverDesktop::IOWorker::DeleteToken( |
| const std::string& app_id, |
| const std::string& authorized_entity, |
| const std::string& scope) { |
| std::unique_ptr<InstanceIDTokenInfo> instance_id_token_info( |
| new InstanceIDTokenInfo); |
| instance_id_token_info->app_id = app_id; |
| instance_id_token_info->authorized_entity = authorized_entity; |
| instance_id_token_info->scope = scope; |
| gcm_client_->Unregister( |
| make_linked_ptr<RegistrationInfo>(instance_id_token_info.release())); |
| } |
| |
| void GCMDriverDesktop::IOWorker::WakeFromSuspendForHeartbeat(bool wake) { |
| #if defined(OS_CHROMEOS) |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| |
| std::unique_ptr<base::Timer> timer; |
| if (wake) |
| timer.reset(new timers::SimpleAlarmTimer()); |
| else |
| timer.reset(new base::Timer(true, false)); |
| |
| gcm_client_->UpdateHeartbeatTimer(std::move(timer)); |
| #endif |
| } |
| |
| void GCMDriverDesktop::IOWorker::AddHeartbeatInterval(const std::string& scope, |
| int interval_ms) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| gcm_client_->AddHeartbeatInterval(scope, interval_ms); |
| } |
| |
| void GCMDriverDesktop::IOWorker::RemoveHeartbeatInterval( |
| const std::string& scope) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| gcm_client_->RemoveHeartbeatInterval(scope); |
| } |
| |
| void GCMDriverDesktop::IOWorker::RecordDecryptionFailure( |
| const std::string& app_id, |
| GCMEncryptionProvider::DecryptionResult result) { |
| DCHECK(io_thread_->RunsTasksOnCurrentThread()); |
| gcm_client_->RecordDecryptionFailure(app_id, result); |
| } |
| |
| GCMDriverDesktop::GCMDriverDesktop( |
| std::unique_ptr<GCMClientFactory> gcm_client_factory, |
| const GCMClient::ChromeBuildInfo& chrome_build_info, |
| const std::string& channel_status_request_url, |
| const std::string& user_agent, |
| PrefService* prefs, |
| const base::FilePath& store_path, |
| const scoped_refptr<net::URLRequestContextGetter>& request_context, |
| const scoped_refptr<base::SequencedTaskRunner>& ui_thread, |
| const scoped_refptr<base::SequencedTaskRunner>& io_thread, |
| const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner) |
| : GCMDriver(store_path, blocking_task_runner), |
| gcm_channel_status_syncer_( |
| new GCMChannelStatusSyncer(this, |
| prefs, |
| channel_status_request_url, |
| user_agent, |
| request_context)), |
| signed_in_(false), |
| gcm_started_(false), |
| gcm_enabled_(true), |
| connected_(false), |
| account_mapper_(new GCMAccountMapper(this)), |
| // Setting to max, to make sure it does not prompt for token reporting |
| // Before reading a reasonable value from the DB, which might be never, |
| // in which case the fetching will be triggered. |
| last_token_fetch_time_(base::Time::Max()), |
| ui_thread_(ui_thread), |
| io_thread_(io_thread), |
| wake_from_suspend_enabled_(false), |
| weak_ptr_factory_(this) { |
| gcm_enabled_ = gcm_channel_status_syncer_->gcm_enabled(); |
| |
| // Create and initialize the GCMClient. Note that this does not initiate the |
| // GCM check-in. |
| io_worker_.reset(new IOWorker(ui_thread, io_thread)); |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::Initialize, |
| base::Unretained(io_worker_.get()), |
| base::Passed(&gcm_client_factory), |
| chrome_build_info, |
| store_path, |
| request_context, |
| blocking_task_runner)); |
| } |
| |
| GCMDriverDesktop::~GCMDriverDesktop() { |
| } |
| |
| void GCMDriverDesktop::Shutdown() { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| Stop(); |
| GCMDriver::Shutdown(); |
| |
| // Dispose the syncer in order to release the reference to |
| // URLRequestContextGetter that needs to be done before IOThread gets |
| // deleted. |
| gcm_channel_status_syncer_.reset(); |
| |
| io_thread_->DeleteSoon(FROM_HERE, io_worker_.release()); |
| } |
| |
| void GCMDriverDesktop::OnSignedIn() { |
| signed_in_ = true; |
| } |
| |
| void GCMDriverDesktop::OnSignedOut() { |
| signed_in_ = false; |
| } |
| |
| void GCMDriverDesktop::AddAppHandler(const std::string& app_id, |
| GCMAppHandler* handler) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| GCMDriver::AddAppHandler(app_id, handler); |
| |
| // Ensures that the GCM service is started when there is an interest. |
| EnsureStarted(GCMClient::DELAYED_START); |
| } |
| |
| void GCMDriverDesktop::RemoveAppHandler(const std::string& app_id) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| GCMDriver::RemoveAppHandler(app_id); |
| |
| // Stops the GCM service when no app intends to consume it. Stop function will |
| // remove the last app handler - account mapper. |
| if (app_handlers().size() == 1) { |
| Stop(); |
| gcm_channel_status_syncer_->Stop(); |
| } |
| } |
| |
| void GCMDriverDesktop::AddConnectionObserver(GCMConnectionObserver* observer) { |
| connection_observer_list_.AddObserver(observer); |
| } |
| |
| void GCMDriverDesktop::RemoveConnectionObserver( |
| GCMConnectionObserver* observer) { |
| connection_observer_list_.RemoveObserver(observer); |
| } |
| |
| void GCMDriverDesktop::Enable() { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| if (gcm_enabled_) |
| return; |
| gcm_enabled_ = true; |
| |
| EnsureStarted(GCMClient::DELAYED_START); |
| } |
| |
| void GCMDriverDesktop::Disable() { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| if (!gcm_enabled_) |
| return; |
| gcm_enabled_ = false; |
| |
| Stop(); |
| } |
| |
| void GCMDriverDesktop::Stop() { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| // No need to stop GCM service if not started yet. |
| if (!gcm_started_) |
| return; |
| |
| account_mapper_->ShutdownHandler(); |
| GCMDriver::RemoveAppHandler(kGCMAccountMapperAppId); |
| |
| RemoveCachedData(); |
| |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::Stop, |
| base::Unretained(io_worker_.get()))); |
| } |
| |
| void GCMDriverDesktop::RegisterImpl( |
| const std::string& app_id, |
| const std::vector<std::string>& sender_ids) { |
| // Delay the register operation until GCMClient is ready. |
| if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { |
| delayed_task_controller_->AddTask(base::Bind(&GCMDriverDesktop::DoRegister, |
| weak_ptr_factory_.GetWeakPtr(), |
| app_id, |
| sender_ids)); |
| return; |
| } |
| |
| DoRegister(app_id, sender_ids); |
| } |
| |
| void GCMDriverDesktop::DoRegister(const std::string& app_id, |
| const std::vector<std::string>& sender_ids) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| if (!HasRegisterCallback(app_id)) { |
| // The callback could have been removed when the app is uninstalled. |
| return; |
| } |
| |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::Register, |
| base::Unretained(io_worker_.get()), |
| app_id, |
| sender_ids)); |
| } |
| |
| void GCMDriverDesktop::UnregisterImpl(const std::string& app_id) { |
| // Delay the unregister operation until GCMClient is ready. |
| if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { |
| delayed_task_controller_->AddTask( |
| base::Bind(&GCMDriverDesktop::DoUnregister, |
| weak_ptr_factory_.GetWeakPtr(), |
| app_id)); |
| return; |
| } |
| |
| DoUnregister(app_id); |
| } |
| |
| void GCMDriverDesktop::DoUnregister(const std::string& app_id) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| // Ask the server to unregister it. There could be a small chance that the |
| // unregister request fails. If this occurs, it does not bring any harm since |
| // we simply reject the messages/events received from the server. |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::Unregister, |
| base::Unretained(io_worker_.get()), |
| app_id)); |
| } |
| |
| void GCMDriverDesktop::SendImpl(const std::string& app_id, |
| const std::string& receiver_id, |
| const OutgoingMessage& message) { |
| // Delay the send operation until all GCMClient is ready. |
| if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { |
| delayed_task_controller_->AddTask(base::Bind(&GCMDriverDesktop::DoSend, |
| weak_ptr_factory_.GetWeakPtr(), |
| app_id, |
| receiver_id, |
| message)); |
| return; |
| } |
| |
| DoSend(app_id, receiver_id, message); |
| } |
| |
| void GCMDriverDesktop::DoSend(const std::string& app_id, |
| const std::string& receiver_id, |
| const OutgoingMessage& message) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::Send, |
| base::Unretained(io_worker_.get()), |
| app_id, |
| receiver_id, |
| message)); |
| } |
| |
| void GCMDriverDesktop::RecordDecryptionFailure( |
| const std::string& app_id, |
| GCMEncryptionProvider::DecryptionResult result) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::RecordDecryptionFailure, |
| base::Unretained(io_worker_.get()), |
| app_id, result)); |
| } |
| |
| GCMClient* GCMDriverDesktop::GetGCMClientForTesting() const { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| return io_worker_ ? io_worker_->gcm_client_for_testing() : NULL; |
| } |
| |
| bool GCMDriverDesktop::IsStarted() const { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| return gcm_started_; |
| } |
| |
| bool GCMDriverDesktop::IsConnected() const { |
| return connected_; |
| } |
| |
| void GCMDriverDesktop::GetGCMStatistics( |
| const GetGCMStatisticsCallback& callback, |
| ClearActivityLogs clear_logs) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| DCHECK(!callback.is_null()); |
| |
| request_gcm_statistics_callback_ = callback; |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::GetGCMStatistics, |
| base::Unretained(io_worker_.get()), |
| clear_logs)); |
| } |
| |
| void GCMDriverDesktop::SetGCMRecording(const GetGCMStatisticsCallback& callback, |
| bool recording) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| request_gcm_statistics_callback_ = callback; |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::SetGCMRecording, |
| base::Unretained(io_worker_.get()), |
| recording)); |
| } |
| |
| void GCMDriverDesktop::UpdateAccountMapping( |
| const AccountMapping& account_mapping) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::UpdateAccountMapping, |
| base::Unretained(io_worker_.get()), |
| account_mapping)); |
| } |
| |
| void GCMDriverDesktop::RemoveAccountMapping(const std::string& account_id) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::RemoveAccountMapping, |
| base::Unretained(io_worker_.get()), |
| account_id)); |
| } |
| |
| base::Time GCMDriverDesktop::GetLastTokenFetchTime() { |
| return last_token_fetch_time_; |
| } |
| |
| void GCMDriverDesktop::SetLastTokenFetchTime(const base::Time& time) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| last_token_fetch_time_ = time; |
| |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::SetLastTokenFetchTime, |
| base::Unretained(io_worker_.get()), |
| time)); |
| } |
| |
| InstanceIDHandler* GCMDriverDesktop::GetInstanceIDHandlerInternal() { |
| return this; |
| } |
| |
| void GCMDriverDesktop::GetToken( |
| const std::string& app_id, |
| const std::string& authorized_entity, |
| const std::string& scope, |
| const std::map<std::string, std::string>& options, |
| const GetTokenCallback& callback) { |
| DCHECK(!app_id.empty()); |
| DCHECK(!authorized_entity.empty()); |
| DCHECK(!scope.empty()); |
| DCHECK(!callback.is_null()); |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START); |
| if (result != GCMClient::SUCCESS) { |
| callback.Run(std::string(), result); |
| return; |
| } |
| |
| // If previous GetToken operation is still in progress, bail out. |
| TokenTuple tuple_key(app_id, authorized_entity, scope); |
| if (get_token_callbacks_.find(tuple_key) != get_token_callbacks_.end()) { |
| callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING); |
| return; |
| } |
| |
| get_token_callbacks_[tuple_key] = callback; |
| |
| // Delay the GetToken operation until GCMClient is ready. |
| if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { |
| delayed_task_controller_->AddTask( |
| base::Bind(&GCMDriverDesktop::DoGetToken, |
| weak_ptr_factory_.GetWeakPtr(), |
| app_id, |
| authorized_entity, |
| scope, |
| options)); |
| return; |
| } |
| |
| DoGetToken(app_id, authorized_entity, scope, options); |
| } |
| |
| void GCMDriverDesktop::DoGetToken( |
| const std::string& app_id, |
| const std::string& authorized_entity, |
| const std::string& scope, |
| const std::map<std::string, std::string>& options) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| TokenTuple tuple_key(app_id, authorized_entity, scope); |
| auto callback_iter = get_token_callbacks_.find(tuple_key); |
| if (callback_iter == get_token_callbacks_.end()) { |
| // The callback could have been removed when the app is uninstalled. |
| return; |
| } |
| |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::GetToken, |
| base::Unretained(io_worker_.get()), |
| app_id, |
| authorized_entity, |
| scope, |
| options)); |
| } |
| |
| void GCMDriverDesktop::DeleteToken(const std::string& app_id, |
| const std::string& authorized_entity, |
| const std::string& scope, |
| const DeleteTokenCallback& callback) { |
| DCHECK(!app_id.empty()); |
| DCHECK(!authorized_entity.empty()); |
| DCHECK(!scope.empty()); |
| DCHECK(!callback.is_null()); |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START); |
| if (result != GCMClient::SUCCESS) { |
| callback.Run(result); |
| return; |
| } |
| |
| // If previous GetToken operation is still in progress, bail out. |
| TokenTuple tuple_key(app_id, authorized_entity, scope); |
| if (delete_token_callbacks_.find(tuple_key) != |
| delete_token_callbacks_.end()) { |
| callback.Run(GCMClient::ASYNC_OPERATION_PENDING); |
| return; |
| } |
| |
| delete_token_callbacks_[tuple_key] = callback; |
| |
| // Delay the DeleteToken operation until GCMClient is ready. |
| if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { |
| delayed_task_controller_->AddTask( |
| base::Bind(&GCMDriverDesktop::DoDeleteToken, |
| weak_ptr_factory_.GetWeakPtr(), |
| app_id, |
| authorized_entity, |
| scope)); |
| return; |
| } |
| |
| DoDeleteToken(app_id, authorized_entity, scope); |
| } |
| |
| void GCMDriverDesktop::DoDeleteToken(const std::string& app_id, |
| const std::string& authorized_entity, |
| const std::string& scope) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::DeleteToken, |
| base::Unretained(io_worker_.get()), |
| app_id, |
| authorized_entity, |
| scope)); |
| } |
| |
| void GCMDriverDesktop::AddInstanceIDData( |
| const std::string& app_id, |
| const std::string& instance_id, |
| const std::string& extra_data) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START); |
| if (result != GCMClient::SUCCESS) |
| return; |
| |
| // Delay the operation until GCMClient is ready. |
| if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { |
| delayed_task_controller_->AddTask( |
| base::Bind(&GCMDriverDesktop::DoAddInstanceIDData, |
| weak_ptr_factory_.GetWeakPtr(), |
| app_id, |
| instance_id, |
| extra_data)); |
| return; |
| } |
| |
| DoAddInstanceIDData(app_id, instance_id, extra_data); |
| } |
| |
| void GCMDriverDesktop::DoAddInstanceIDData( |
| const std::string& app_id, |
| const std::string& instance_id, |
| const std::string& extra_data) { |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::AddInstanceIDData, |
| base::Unretained(io_worker_.get()), |
| app_id, |
| instance_id, |
| extra_data)); |
| } |
| |
| void GCMDriverDesktop::RemoveInstanceIDData(const std::string& app_id) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START); |
| if (result != GCMClient::SUCCESS) |
| return; |
| |
| // Delay the operation until GCMClient is ready. |
| if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { |
| delayed_task_controller_->AddTask( |
| base::Bind(&GCMDriverDesktop::DoRemoveInstanceIDData, |
| weak_ptr_factory_.GetWeakPtr(), |
| app_id)); |
| return; |
| } |
| |
| DoRemoveInstanceIDData(app_id); |
| } |
| |
| void GCMDriverDesktop::DoRemoveInstanceIDData(const std::string& app_id) { |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::RemoveInstanceIDData, |
| base::Unretained(io_worker_.get()), |
| app_id)); |
| } |
| |
| void GCMDriverDesktop::GetInstanceIDData( |
| const std::string& app_id, |
| const GetInstanceIDDataCallback& callback) { |
| DCHECK(!get_instance_id_data_callbacks_.count(app_id)); |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START); |
| if (result != GCMClient::SUCCESS) { |
| callback.Run(std::string(), std::string()); |
| return; |
| } |
| |
| get_instance_id_data_callbacks_[app_id] = callback; |
| |
| // Delay the operation until GCMClient is ready. |
| if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { |
| delayed_task_controller_->AddTask( |
| base::Bind(&GCMDriverDesktop::DoGetInstanceIDData, |
| weak_ptr_factory_.GetWeakPtr(), |
| app_id)); |
| return; |
| } |
| |
| DoGetInstanceIDData(app_id); |
| } |
| |
| void GCMDriverDesktop::DoGetInstanceIDData(const std::string& app_id) { |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::GetInstanceIDData, |
| base::Unretained(io_worker_.get()), |
| app_id)); |
| } |
| |
| void GCMDriverDesktop::GetInstanceIDDataFinished( |
| const std::string& app_id, |
| const std::string& instance_id, |
| const std::string& extra_data) { |
| DCHECK(get_instance_id_data_callbacks_.count(app_id)); |
| get_instance_id_data_callbacks_[app_id].Run(instance_id, extra_data); |
| get_instance_id_data_callbacks_.erase(app_id); |
| } |
| |
| void GCMDriverDesktop::GetTokenFinished(const std::string& app_id, |
| const std::string& authorized_entity, |
| const std::string& scope, |
| const std::string& token, |
| GCMClient::Result result) { |
| TokenTuple tuple_key(app_id, authorized_entity, scope); |
| auto callback_iter = get_token_callbacks_.find(tuple_key); |
| if (callback_iter == get_token_callbacks_.end()) { |
| // The callback could have been removed when the app is uninstalled. |
| return; |
| } |
| |
| GetTokenCallback callback = callback_iter->second; |
| get_token_callbacks_.erase(callback_iter); |
| callback.Run(token, result); |
| } |
| |
| void GCMDriverDesktop::DeleteTokenFinished(const std::string& app_id, |
| const std::string& authorized_entity, |
| const std::string& scope, |
| GCMClient::Result result) { |
| TokenTuple tuple_key(app_id, authorized_entity, scope); |
| auto callback_iter = delete_token_callbacks_.find(tuple_key); |
| if (callback_iter == delete_token_callbacks_.end()) { |
| // The callback could have been removed when the app is uninstalled. |
| return; |
| } |
| |
| DeleteTokenCallback callback = callback_iter->second; |
| delete_token_callbacks_.erase(callback_iter); |
| callback.Run(result); |
| } |
| |
| void GCMDriverDesktop::WakeFromSuspendForHeartbeat(bool wake) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| wake_from_suspend_enabled_ = wake; |
| |
| // The GCM service has not been initialized. |
| if (!delayed_task_controller_) |
| return; |
| |
| if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { |
| // The GCM service was initialized but has not started yet. |
| delayed_task_controller_->AddTask( |
| base::Bind(&GCMDriverDesktop::WakeFromSuspendForHeartbeat, |
| weak_ptr_factory_.GetWeakPtr(), |
| wake_from_suspend_enabled_)); |
| return; |
| } |
| |
| // The GCMClient is ready so we can go ahead and post this task to the |
| // IOWorker. |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::WakeFromSuspendForHeartbeat, |
| base::Unretained(io_worker_.get()), |
| wake_from_suspend_enabled_)); |
| } |
| |
| void GCMDriverDesktop::AddHeartbeatInterval(const std::string& scope, |
| int interval_ms) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| // The GCM service has not been initialized. |
| if (!delayed_task_controller_) |
| return; |
| |
| if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { |
| // The GCM service was initialized but has not started yet. |
| delayed_task_controller_->AddTask( |
| base::Bind(&GCMDriverDesktop::AddHeartbeatInterval, |
| weak_ptr_factory_.GetWeakPtr(), scope, interval_ms)); |
| return; |
| } |
| |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::AddHeartbeatInterval, |
| base::Unretained(io_worker_.get()), scope, interval_ms)); |
| } |
| |
| void GCMDriverDesktop::RemoveHeartbeatInterval(const std::string& scope) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| // The GCM service has not been initialized. |
| if (!delayed_task_controller_) |
| return; |
| |
| if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { |
| // The GCM service was initialized but has not started yet. |
| delayed_task_controller_->AddTask( |
| base::Bind(&GCMDriverDesktop::RemoveHeartbeatInterval, |
| weak_ptr_factory_.GetWeakPtr(), scope)); |
| return; |
| } |
| |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::RemoveHeartbeatInterval, |
| base::Unretained(io_worker_.get()), scope)); |
| } |
| |
| void GCMDriverDesktop::SetAccountTokens( |
| const std::vector<GCMClient::AccountTokenInfo>& account_tokens) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| account_mapper_->SetAccountTokens(account_tokens); |
| |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::SetAccountTokens, |
| base::Unretained(io_worker_.get()), |
| account_tokens)); |
| } |
| |
| GCMClient::Result GCMDriverDesktop::EnsureStarted( |
| GCMClient::StartMode start_mode) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| if (gcm_started_) |
| return GCMClient::SUCCESS; |
| |
| // Have any app requested the service? |
| if (app_handlers().empty()) |
| return GCMClient::UNKNOWN_ERROR; |
| |
| // Polling for channel status should be invoked when GCM is being requested, |
| // no matter whether GCM is enabled or nor. |
| gcm_channel_status_syncer_->EnsureStarted(); |
| |
| if (!gcm_enabled_) |
| return GCMClient::GCM_DISABLED; |
| |
| if (!delayed_task_controller_) |
| delayed_task_controller_.reset(new GCMDelayedTaskController); |
| |
| // Note that we need to pass weak pointer again since the existing weak |
| // pointer in IOWorker might have been invalidated when GCM is stopped. |
| io_thread_->PostTask( |
| FROM_HERE, |
| base::Bind(&GCMDriverDesktop::IOWorker::Start, |
| base::Unretained(io_worker_.get()), |
| start_mode, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| return GCMClient::SUCCESS; |
| } |
| |
| void GCMDriverDesktop::RemoveCachedData() { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| // Remove all the queued tasks since they no longer make sense after |
| // GCM service is stopped. |
| weak_ptr_factory_.InvalidateWeakPtrs(); |
| |
| gcm_started_ = false; |
| delayed_task_controller_.reset(); |
| ClearCallbacks(); |
| } |
| |
| void GCMDriverDesktop::MessageReceived(const std::string& app_id, |
| const IncomingMessage& message) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| // Drop the event if the service has been stopped. |
| if (!gcm_started_) |
| return; |
| |
| DispatchMessage(app_id, message); |
| } |
| |
| void GCMDriverDesktop::MessagesDeleted(const std::string& app_id) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| // Drop the event if the service has been stopped. |
| if (!gcm_started_) |
| return; |
| |
| GetAppHandler(app_id)->OnMessagesDeleted(app_id); |
| } |
| |
| void GCMDriverDesktop::MessageSendError( |
| const std::string& app_id, |
| const GCMClient::SendErrorDetails& send_error_details) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| // Drop the event if the service has been stopped. |
| if (!gcm_started_) |
| return; |
| |
| GetAppHandler(app_id)->OnSendError(app_id, send_error_details); |
| } |
| |
| void GCMDriverDesktop::SendAcknowledged(const std::string& app_id, |
| const std::string& message_id) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| // Drop the event if the service has been stopped. |
| if (!gcm_started_) |
| return; |
| |
| GetAppHandler(app_id)->OnSendAcknowledged(app_id, message_id); |
| } |
| |
| void GCMDriverDesktop::GCMClientReady( |
| const std::vector<AccountMapping>& account_mappings, |
| const base::Time& last_token_fetch_time) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| UMA_HISTOGRAM_BOOLEAN("GCM.UserSignedIn", signed_in_); |
| |
| gcm_started_ = true; |
| if (wake_from_suspend_enabled_) |
| WakeFromSuspendForHeartbeat(wake_from_suspend_enabled_); |
| |
| last_token_fetch_time_ = last_token_fetch_time; |
| |
| GCMDriver::AddAppHandler(kGCMAccountMapperAppId, account_mapper_.get()); |
| account_mapper_->Initialize(account_mappings, |
| base::Bind(&GCMDriverDesktop::MessageReceived, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| delayed_task_controller_->SetReady(); |
| } |
| |
| void GCMDriverDesktop::OnConnected(const net::IPEndPoint& ip_endpoint) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| connected_ = true; |
| |
| // Drop the event if the service has been stopped. |
| if (!gcm_started_) |
| return; |
| |
| for (GCMConnectionObserver& observer : connection_observer_list_) |
| observer.OnConnected(ip_endpoint); |
| } |
| |
| void GCMDriverDesktop::OnDisconnected() { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| connected_ = false; |
| |
| // Drop the event if the service has been stopped. |
| if (!gcm_started_) |
| return; |
| |
| for (GCMConnectionObserver& observer : connection_observer_list_) |
| observer.OnDisconnected(); |
| } |
| |
| void GCMDriverDesktop::OnStoreReset() { |
| // Defensive copy in case OnStoreReset calls Add/RemoveAppHandler. |
| std::vector<GCMAppHandler*> app_handler_values; |
| for (const auto& key_value : app_handlers()) |
| app_handler_values.push_back(key_value.second); |
| for (GCMAppHandler* app_handler : app_handler_values) { |
| app_handler->OnStoreReset(); |
| // app_handler might now have been deleted. |
| } |
| } |
| |
| void GCMDriverDesktop::GetGCMStatisticsFinished( |
| const GCMClient::GCMStatistics& stats) { |
| DCHECK(ui_thread_->RunsTasksOnCurrentThread()); |
| |
| // request_gcm_statistics_callback_ could be null when an activity, i.e. |
| // network activity, is triggered while gcm-intenals page is not open. |
| if (!request_gcm_statistics_callback_.is_null()) |
| request_gcm_statistics_callback_.Run(stats); |
| } |
| |
| bool GCMDriverDesktop::TokenTupleComparer::operator()( |
| const TokenTuple& a, const TokenTuple& b) const { |
| if (std::get<0>(a) < std::get<0>(b)) |
| return true; |
| if (std::get<0>(a) > std::get<0>(b)) |
| return false; |
| |
| if (std::get<1>(a) < std::get<1>(b)) |
| return true; |
| if (std::get<1>(a) > std::get<1>(b)) |
| return false; |
| |
| return std::get<2>(a) < std::get<2>(b); |
| } |
| |
| } // namespace gcm |