Make |context| passed to queryRequiredElement optional
[chromium-blink-merge.git] / components / gcm_driver / gcm_driver_desktop.cc
blob8910e4bd277b6b27b87203f98b28edf4154396f0
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
3 // found in the LICENSE file.
5 #include "components/gcm_driver/gcm_driver_desktop.h"
7 #include <utility>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/files/file_path.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/profiler/scoped_tracker.h"
16 #include "base/sequenced_task_runner.h"
17 #include "base/threading/sequenced_worker_pool.h"
18 #include "components/gcm_driver/gcm_account_mapper.h"
19 #include "components/gcm_driver/gcm_app_handler.h"
20 #include "components/gcm_driver/gcm_channel_status_syncer.h"
21 #include "components/gcm_driver/gcm_client_factory.h"
22 #include "components/gcm_driver/gcm_delayed_task_controller.h"
23 #include "components/gcm_driver/instance_id/instance_id_impl.h"
24 #include "components/gcm_driver/system_encryptor.h"
25 #include "google_apis/gcm/engine/account_mapping.h"
26 #include "net/base/ip_endpoint.h"
27 #include "net/url_request/url_request_context_getter.h"
29 #if defined(OS_CHROMEOS)
30 #include "components/timers/alarm_timer_chromeos.h"
31 #endif
33 namespace gcm {
35 class GCMDriverDesktop::IOWorker : public GCMClient::Delegate {
36 public:
37 // Called on UI thread.
38 IOWorker(const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
39 const scoped_refptr<base::SequencedTaskRunner>& io_thread);
40 virtual ~IOWorker();
42 // Overridden from GCMClient::Delegate:
43 // Called on IO thread.
44 void OnRegisterFinished(const linked_ptr<RegistrationInfo>& registration_info,
45 const std::string& registration_id,
46 GCMClient::Result result) override;
47 void OnUnregisterFinished(
48 const linked_ptr<RegistrationInfo>& registration_info,
49 GCMClient::Result result) override;
50 void OnSendFinished(const std::string& app_id,
51 const std::string& message_id,
52 GCMClient::Result result) override;
53 void OnMessageReceived(const std::string& app_id,
54 const IncomingMessage& message) override;
55 void OnMessagesDeleted(const std::string& app_id) override;
56 void OnMessageSendError(
57 const std::string& app_id,
58 const GCMClient::SendErrorDetails& send_error_details) override;
59 void OnSendAcknowledged(const std::string& app_id,
60 const std::string& message_id) override;
61 void OnGCMReady(const std::vector<AccountMapping>& account_mappings,
62 const base::Time& last_token_fetch_time) override;
63 void OnActivityRecorded() override;
64 void OnConnected(const net::IPEndPoint& ip_endpoint) override;
65 void OnDisconnected() override;
67 // Called on IO thread.
68 void Initialize(
69 scoped_ptr<GCMClientFactory> gcm_client_factory,
70 const GCMClient::ChromeBuildInfo& chrome_build_info,
71 const base::FilePath& store_path,
72 const scoped_refptr<net::URLRequestContextGetter>& request_context,
73 const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
74 void Start(GCMClient::StartMode start_mode,
75 const base::WeakPtr<GCMDriverDesktop>& service);
76 void Stop();
77 void Register(const std::string& app_id,
78 const std::vector<std::string>& sender_ids);
79 void Unregister(const std::string& app_id);
80 void Send(const std::string& app_id,
81 const std::string& receiver_id,
82 const OutgoingMessage& message);
83 void GetGCMStatistics(bool clear_logs);
84 void SetGCMRecording(bool recording);
86 void SetAccountTokens(
87 const std::vector<GCMClient::AccountTokenInfo>& account_tokens);
88 void UpdateAccountMapping(const AccountMapping& account_mapping);
89 void RemoveAccountMapping(const std::string& account_id);
90 void SetLastTokenFetchTime(const base::Time& time);
91 void WakeFromSuspendForHeartbeat(bool wake);
92 void AddHeartbeatInterval(const std::string& scope, int interval_ms);
93 void RemoveHeartbeatInterval(const std::string& scope);
95 void AddInstanceIDData(const std::string& app_id,
96 const std::string& instance_id,
97 const std::string& extra_data);
98 void RemoveInstanceIDData(const std::string& app_id);
99 void GetInstanceIDData(const std::string& app_id);
100 void GetToken(const std::string& app_id,
101 const std::string& authorized_entity,
102 const std::string& scope,
103 const std::map<std::string, std::string>& options);
104 void DeleteToken(const std::string& app_id,
105 const std::string& authorized_entity,
106 const std::string& scope);
108 // For testing purpose. Can be called from UI thread. Use with care.
109 GCMClient* gcm_client_for_testing() const { return gcm_client_.get(); }
111 private:
112 scoped_refptr<base::SequencedTaskRunner> ui_thread_;
113 scoped_refptr<base::SequencedTaskRunner> io_thread_;
115 base::WeakPtr<GCMDriverDesktop> service_;
117 scoped_ptr<GCMClient> gcm_client_;
119 DISALLOW_COPY_AND_ASSIGN(IOWorker);
122 GCMDriverDesktop::IOWorker::IOWorker(
123 const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
124 const scoped_refptr<base::SequencedTaskRunner>& io_thread)
125 : ui_thread_(ui_thread),
126 io_thread_(io_thread) {
127 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
130 GCMDriverDesktop::IOWorker::~IOWorker() {
131 DCHECK(io_thread_->RunsTasksOnCurrentThread());
134 void GCMDriverDesktop::IOWorker::Initialize(
135 scoped_ptr<GCMClientFactory> gcm_client_factory,
136 const GCMClient::ChromeBuildInfo& chrome_build_info,
137 const base::FilePath& store_path,
138 const scoped_refptr<net::URLRequestContextGetter>& request_context,
139 const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) {
140 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
141 tracked_objects::ScopedTracker tracking_profile(
142 FROM_HERE_WITH_EXPLICIT_FUNCTION(
143 "477117 GCMDriverDesktop::IOWorker::Initialize"));
144 DCHECK(io_thread_->RunsTasksOnCurrentThread());
146 gcm_client_ = gcm_client_factory->BuildInstance();
148 gcm_client_->Initialize(chrome_build_info,
149 store_path,
150 blocking_task_runner,
151 request_context,
152 make_scoped_ptr<Encryptor>(new SystemEncryptor),
153 this);
156 void GCMDriverDesktop::IOWorker::OnRegisterFinished(
157 const linked_ptr<RegistrationInfo>& registration_info,
158 const std::string& registration_id,
159 GCMClient::Result result) {
160 DCHECK(io_thread_->RunsTasksOnCurrentThread());
162 const GCMRegistrationInfo* gcm_registration_info =
163 GCMRegistrationInfo::FromRegistrationInfo(registration_info.get());
164 if (gcm_registration_info) {
165 ui_thread_->PostTask(
166 FROM_HERE,
167 base::Bind(&GCMDriverDesktop::RegisterFinished,
168 service_,
169 gcm_registration_info->app_id,
170 registration_id,
171 result));
174 const InstanceIDTokenInfo* instance_id_token_info =
175 InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get());
176 if (instance_id_token_info) {
177 ui_thread_->PostTask(
178 FROM_HERE,
179 base::Bind(&GCMDriverDesktop::GetTokenFinished,
180 service_,
181 instance_id_token_info->app_id,
182 instance_id_token_info->authorized_entity,
183 instance_id_token_info->scope,
184 registration_id,
185 result));
189 void GCMDriverDesktop::IOWorker::OnUnregisterFinished(
190 const linked_ptr<RegistrationInfo>& registration_info,
191 GCMClient::Result result) {
192 DCHECK(io_thread_->RunsTasksOnCurrentThread());
194 const GCMRegistrationInfo* gcm_registration_info =
195 GCMRegistrationInfo::FromRegistrationInfo(registration_info.get());
196 if (gcm_registration_info) {
197 ui_thread_->PostTask(
198 FROM_HERE,
199 base::Bind(&GCMDriverDesktop::UnregisterFinished,
200 service_,
201 gcm_registration_info->app_id,
202 result));
205 const InstanceIDTokenInfo* instance_id_token_info =
206 InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get());
207 if (instance_id_token_info) {
208 ui_thread_->PostTask(
209 FROM_HERE,
210 base::Bind(&GCMDriverDesktop::DeleteTokenFinished,
211 service_,
212 instance_id_token_info->app_id,
213 instance_id_token_info->authorized_entity,
214 instance_id_token_info->scope,
215 result));
219 void GCMDriverDesktop::IOWorker::OnSendFinished(const std::string& app_id,
220 const std::string& message_id,
221 GCMClient::Result result) {
222 DCHECK(io_thread_->RunsTasksOnCurrentThread());
224 ui_thread_->PostTask(
225 FROM_HERE,
226 base::Bind(&GCMDriverDesktop::SendFinished, service_, app_id, message_id,
227 result));
230 void GCMDriverDesktop::IOWorker::OnMessageReceived(
231 const std::string& app_id,
232 const IncomingMessage& message) {
233 DCHECK(io_thread_->RunsTasksOnCurrentThread());
235 ui_thread_->PostTask(
236 FROM_HERE,
237 base::Bind(&GCMDriverDesktop::MessageReceived,
238 service_,
239 app_id,
240 message));
243 void GCMDriverDesktop::IOWorker::OnMessagesDeleted(const std::string& app_id) {
244 DCHECK(io_thread_->RunsTasksOnCurrentThread());
246 ui_thread_->PostTask(
247 FROM_HERE,
248 base::Bind(&GCMDriverDesktop::MessagesDeleted, service_, app_id));
251 void GCMDriverDesktop::IOWorker::OnMessageSendError(
252 const std::string& app_id,
253 const GCMClient::SendErrorDetails& send_error_details) {
254 DCHECK(io_thread_->RunsTasksOnCurrentThread());
256 ui_thread_->PostTask(
257 FROM_HERE,
258 base::Bind(&GCMDriverDesktop::MessageSendError, service_, app_id,
259 send_error_details));
262 void GCMDriverDesktop::IOWorker::OnSendAcknowledged(
263 const std::string& app_id,
264 const std::string& message_id) {
265 DCHECK(io_thread_->RunsTasksOnCurrentThread());
267 ui_thread_->PostTask(
268 FROM_HERE,
269 base::Bind(
270 &GCMDriverDesktop::SendAcknowledged, service_, app_id, message_id));
273 void GCMDriverDesktop::IOWorker::OnGCMReady(
274 const std::vector<AccountMapping>& account_mappings,
275 const base::Time& last_token_fetch_time) {
276 ui_thread_->PostTask(FROM_HERE,
277 base::Bind(&GCMDriverDesktop::GCMClientReady,
278 service_,
279 account_mappings,
280 last_token_fetch_time));
283 void GCMDriverDesktop::IOWorker::OnActivityRecorded() {
284 DCHECK(io_thread_->RunsTasksOnCurrentThread());
285 // When an activity is recorded, get all the stats and refresh the UI of
286 // gcm-internals page.
287 GetGCMStatistics(false);
290 void GCMDriverDesktop::IOWorker::OnConnected(
291 const net::IPEndPoint& ip_endpoint) {
292 ui_thread_->PostTask(FROM_HERE,
293 base::Bind(&GCMDriverDesktop::OnConnected,
294 service_,
295 ip_endpoint));
298 void GCMDriverDesktop::IOWorker::OnDisconnected() {
299 ui_thread_->PostTask(FROM_HERE,
300 base::Bind(&GCMDriverDesktop::OnDisconnected, service_));
303 void GCMDriverDesktop::IOWorker::Start(
304 GCMClient::StartMode start_mode,
305 const base::WeakPtr<GCMDriverDesktop>& service) {
306 DCHECK(io_thread_->RunsTasksOnCurrentThread());
308 service_ = service;
309 gcm_client_->Start(start_mode);
312 void GCMDriverDesktop::IOWorker::Stop() {
313 DCHECK(io_thread_->RunsTasksOnCurrentThread());
315 gcm_client_->Stop();
318 void GCMDriverDesktop::IOWorker::Register(
319 const std::string& app_id,
320 const std::vector<std::string>& sender_ids) {
321 DCHECK(io_thread_->RunsTasksOnCurrentThread());
323 scoped_ptr<GCMRegistrationInfo> gcm_info(new GCMRegistrationInfo);
324 gcm_info->app_id = app_id;
325 gcm_info->sender_ids = sender_ids;
326 gcm_client_->Register(make_linked_ptr<RegistrationInfo>(gcm_info.release()));
329 void GCMDriverDesktop::IOWorker::Unregister(const std::string& app_id) {
330 DCHECK(io_thread_->RunsTasksOnCurrentThread());
332 scoped_ptr<GCMRegistrationInfo> gcm_info(new GCMRegistrationInfo);
333 gcm_info->app_id = app_id;
334 gcm_client_->Unregister(
335 make_linked_ptr<RegistrationInfo>(gcm_info.release()));
338 void GCMDriverDesktop::IOWorker::Send(const std::string& app_id,
339 const std::string& receiver_id,
340 const OutgoingMessage& message) {
341 DCHECK(io_thread_->RunsTasksOnCurrentThread());
343 gcm_client_->Send(app_id, receiver_id, message);
346 void GCMDriverDesktop::IOWorker::GetGCMStatistics(bool clear_logs) {
347 DCHECK(io_thread_->RunsTasksOnCurrentThread());
348 gcm::GCMClient::GCMStatistics stats;
350 if (gcm_client_.get()) {
351 if (clear_logs)
352 gcm_client_->ClearActivityLogs();
353 stats = gcm_client_->GetStatistics();
356 ui_thread_->PostTask(
357 FROM_HERE,
358 base::Bind(&GCMDriverDesktop::GetGCMStatisticsFinished, service_, stats));
361 void GCMDriverDesktop::IOWorker::SetGCMRecording(bool recording) {
362 DCHECK(io_thread_->RunsTasksOnCurrentThread());
363 gcm::GCMClient::GCMStatistics stats;
365 if (gcm_client_.get()) {
366 gcm_client_->SetRecording(recording);
367 stats = gcm_client_->GetStatistics();
368 stats.gcm_client_created = true;
371 ui_thread_->PostTask(
372 FROM_HERE,
373 base::Bind(&GCMDriverDesktop::GetGCMStatisticsFinished, service_, stats));
376 void GCMDriverDesktop::IOWorker::SetAccountTokens(
377 const std::vector<GCMClient::AccountTokenInfo>& account_tokens) {
378 DCHECK(io_thread_->RunsTasksOnCurrentThread());
380 if (gcm_client_.get())
381 gcm_client_->SetAccountTokens(account_tokens);
384 void GCMDriverDesktop::IOWorker::UpdateAccountMapping(
385 const AccountMapping& account_mapping) {
386 DCHECK(io_thread_->RunsTasksOnCurrentThread());
388 if (gcm_client_.get())
389 gcm_client_->UpdateAccountMapping(account_mapping);
392 void GCMDriverDesktop::IOWorker::RemoveAccountMapping(
393 const std::string& account_id) {
394 DCHECK(io_thread_->RunsTasksOnCurrentThread());
396 if (gcm_client_.get())
397 gcm_client_->RemoveAccountMapping(account_id);
400 void GCMDriverDesktop::IOWorker::SetLastTokenFetchTime(const base::Time& time) {
401 DCHECK(io_thread_->RunsTasksOnCurrentThread());
403 if (gcm_client_.get())
404 gcm_client_->SetLastTokenFetchTime(time);
407 void GCMDriverDesktop::IOWorker::AddInstanceIDData(
408 const std::string& app_id,
409 const std::string& instance_id,
410 const std::string& extra_data) {
411 DCHECK(io_thread_->RunsTasksOnCurrentThread());
413 if (gcm_client_.get())
414 gcm_client_->AddInstanceIDData(app_id, instance_id, extra_data);
417 void GCMDriverDesktop::IOWorker::RemoveInstanceIDData(
418 const std::string& app_id) {
419 DCHECK(io_thread_->RunsTasksOnCurrentThread());
421 if (gcm_client_.get())
422 gcm_client_->RemoveInstanceIDData(app_id);
425 void GCMDriverDesktop::IOWorker::GetInstanceIDData(
426 const std::string& app_id) {
427 DCHECK(io_thread_->RunsTasksOnCurrentThread());
429 std::string instance_id;
430 std::string extra_data;
431 if (gcm_client_.get())
432 gcm_client_->GetInstanceIDData(app_id, &instance_id, &extra_data);
434 ui_thread_->PostTask(
435 FROM_HERE,
436 base::Bind(&GCMDriverDesktop::GetInstanceIDDataFinished,
437 service_, app_id, instance_id, extra_data));
440 void GCMDriverDesktop::IOWorker::GetToken(
441 const std::string& app_id,
442 const std::string& authorized_entity,
443 const std::string& scope,
444 const std::map<std::string, std::string>& options) {
445 DCHECK(io_thread_->RunsTasksOnCurrentThread());
447 scoped_ptr<InstanceIDTokenInfo> instance_id_token_info(
448 new InstanceIDTokenInfo);
449 instance_id_token_info->app_id = app_id;
450 instance_id_token_info->authorized_entity = authorized_entity;
451 instance_id_token_info->scope = scope;
452 instance_id_token_info->options = options;
453 gcm_client_->Register(
454 make_linked_ptr<RegistrationInfo>(instance_id_token_info.release()));
457 void GCMDriverDesktop::IOWorker::DeleteToken(
458 const std::string& app_id,
459 const std::string& authorized_entity,
460 const std::string& scope) {
461 scoped_ptr<InstanceIDTokenInfo> instance_id_token_info(
462 new InstanceIDTokenInfo);
463 instance_id_token_info->app_id = app_id;
464 instance_id_token_info->authorized_entity = authorized_entity;
465 instance_id_token_info->scope = scope;
466 gcm_client_->Unregister(
467 make_linked_ptr<RegistrationInfo>(instance_id_token_info.release()));
470 void GCMDriverDesktop::IOWorker::WakeFromSuspendForHeartbeat(bool wake) {
471 #if defined(OS_CHROMEOS)
472 DCHECK(io_thread_->RunsTasksOnCurrentThread());
474 scoped_ptr<base::Timer> timer;
475 if (wake)
476 timer.reset(new timers::SimpleAlarmTimer());
477 else
478 timer.reset(new base::Timer(true, false));
480 gcm_client_->UpdateHeartbeatTimer(timer.Pass());
481 #endif
484 void GCMDriverDesktop::IOWorker::AddHeartbeatInterval(const std::string& scope,
485 int interval_ms) {
486 DCHECK(io_thread_->RunsTasksOnCurrentThread());
487 gcm_client_->AddHeartbeatInterval(scope, interval_ms);
490 void GCMDriverDesktop::IOWorker::RemoveHeartbeatInterval(
491 const std::string& scope) {
492 DCHECK(io_thread_->RunsTasksOnCurrentThread());
493 gcm_client_->RemoveHeartbeatInterval(scope);
496 GCMDriverDesktop::GCMDriverDesktop(
497 scoped_ptr<GCMClientFactory> gcm_client_factory,
498 const GCMClient::ChromeBuildInfo& chrome_build_info,
499 const std::string& channel_status_request_url,
500 const std::string& user_agent,
501 PrefService* prefs,
502 const base::FilePath& store_path,
503 const scoped_refptr<net::URLRequestContextGetter>& request_context,
504 const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
505 const scoped_refptr<base::SequencedTaskRunner>& io_thread,
506 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
507 : GCMDriver(store_path, blocking_task_runner),
508 gcm_channel_status_syncer_(
509 new GCMChannelStatusSyncer(this,
510 prefs,
511 channel_status_request_url,
512 user_agent,
513 request_context)),
514 signed_in_(false),
515 gcm_started_(false),
516 gcm_enabled_(true),
517 connected_(false),
518 account_mapper_(new GCMAccountMapper(this)),
519 // Setting to max, to make sure it does not prompt for token reporting
520 // Before reading a reasonable value from the DB, which might be never,
521 // in which case the fetching will be triggered.
522 last_token_fetch_time_(base::Time::Max()),
523 ui_thread_(ui_thread),
524 io_thread_(io_thread),
525 wake_from_suspend_enabled_(false),
526 weak_ptr_factory_(this) {
527 gcm_enabled_ = gcm_channel_status_syncer_->gcm_enabled();
529 // Create and initialize the GCMClient. Note that this does not initiate the
530 // GCM check-in.
531 io_worker_.reset(new IOWorker(ui_thread, io_thread));
532 io_thread_->PostTask(
533 FROM_HERE,
534 base::Bind(&GCMDriverDesktop::IOWorker::Initialize,
535 base::Unretained(io_worker_.get()),
536 base::Passed(&gcm_client_factory),
537 chrome_build_info,
538 store_path,
539 request_context,
540 blocking_task_runner));
543 GCMDriverDesktop::~GCMDriverDesktop() {
546 void GCMDriverDesktop::Shutdown() {
547 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
549 Stop();
550 GCMDriver::Shutdown();
552 // Dispose the syncer in order to release the reference to
553 // URLRequestContextGetter that needs to be done before IOThread gets
554 // deleted.
555 gcm_channel_status_syncer_.reset();
557 io_thread_->DeleteSoon(FROM_HERE, io_worker_.release());
560 void GCMDriverDesktop::OnSignedIn() {
561 signed_in_ = true;
564 void GCMDriverDesktop::OnSignedOut() {
565 signed_in_ = false;
568 void GCMDriverDesktop::AddAppHandler(const std::string& app_id,
569 GCMAppHandler* handler) {
570 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
571 GCMDriver::AddAppHandler(app_id, handler);
573 // Ensures that the GCM service is started when there is an interest.
574 EnsureStarted(GCMClient::DELAYED_START);
577 void GCMDriverDesktop::RemoveAppHandler(const std::string& app_id) {
578 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
579 GCMDriver::RemoveAppHandler(app_id);
581 // Stops the GCM service when no app intends to consume it. Stop function will
582 // remove the last app handler - account mapper.
583 if (app_handlers().size() == 1) {
584 Stop();
585 gcm_channel_status_syncer_->Stop();
589 void GCMDriverDesktop::AddConnectionObserver(GCMConnectionObserver* observer) {
590 connection_observer_list_.AddObserver(observer);
593 void GCMDriverDesktop::RemoveConnectionObserver(
594 GCMConnectionObserver* observer) {
595 connection_observer_list_.RemoveObserver(observer);
598 void GCMDriverDesktop::Enable() {
599 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
601 if (gcm_enabled_)
602 return;
603 gcm_enabled_ = true;
605 EnsureStarted(GCMClient::DELAYED_START);
608 void GCMDriverDesktop::Disable() {
609 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
611 if (!gcm_enabled_)
612 return;
613 gcm_enabled_ = false;
615 Stop();
618 void GCMDriverDesktop::Stop() {
619 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
621 // No need to stop GCM service if not started yet.
622 if (!gcm_started_)
623 return;
625 account_mapper_->ShutdownHandler();
626 GCMDriver::RemoveAppHandler(kGCMAccountMapperAppId);
628 RemoveCachedData();
630 io_thread_->PostTask(
631 FROM_HERE,
632 base::Bind(&GCMDriverDesktop::IOWorker::Stop,
633 base::Unretained(io_worker_.get())));
636 void GCMDriverDesktop::RegisterImpl(
637 const std::string& app_id,
638 const std::vector<std::string>& sender_ids) {
639 // Delay the register operation until GCMClient is ready.
640 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
641 delayed_task_controller_->AddTask(base::Bind(&GCMDriverDesktop::DoRegister,
642 weak_ptr_factory_.GetWeakPtr(),
643 app_id,
644 sender_ids));
645 return;
648 DoRegister(app_id, sender_ids);
651 void GCMDriverDesktop::DoRegister(const std::string& app_id,
652 const std::vector<std::string>& sender_ids) {
653 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
654 if (!HasRegisterCallback(app_id)) {
655 // The callback could have been removed when the app is uninstalled.
656 return;
659 io_thread_->PostTask(
660 FROM_HERE,
661 base::Bind(&GCMDriverDesktop::IOWorker::Register,
662 base::Unretained(io_worker_.get()),
663 app_id,
664 sender_ids));
667 void GCMDriverDesktop::UnregisterImpl(const std::string& app_id) {
668 // Delay the unregister operation until GCMClient is ready.
669 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
670 delayed_task_controller_->AddTask(
671 base::Bind(&GCMDriverDesktop::DoUnregister,
672 weak_ptr_factory_.GetWeakPtr(),
673 app_id));
674 return;
677 DoUnregister(app_id);
680 void GCMDriverDesktop::DoUnregister(const std::string& app_id) {
681 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
683 // Ask the server to unregister it. There could be a small chance that the
684 // unregister request fails. If this occurs, it does not bring any harm since
685 // we simply reject the messages/events received from the server.
686 io_thread_->PostTask(
687 FROM_HERE,
688 base::Bind(&GCMDriverDesktop::IOWorker::Unregister,
689 base::Unretained(io_worker_.get()),
690 app_id));
693 void GCMDriverDesktop::SendImpl(const std::string& app_id,
694 const std::string& receiver_id,
695 const OutgoingMessage& message) {
696 // Delay the send operation until all GCMClient is ready.
697 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
698 delayed_task_controller_->AddTask(base::Bind(&GCMDriverDesktop::DoSend,
699 weak_ptr_factory_.GetWeakPtr(),
700 app_id,
701 receiver_id,
702 message));
703 return;
706 DoSend(app_id, receiver_id, message);
709 void GCMDriverDesktop::DoSend(const std::string& app_id,
710 const std::string& receiver_id,
711 const OutgoingMessage& message) {
712 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
713 io_thread_->PostTask(
714 FROM_HERE,
715 base::Bind(&GCMDriverDesktop::IOWorker::Send,
716 base::Unretained(io_worker_.get()),
717 app_id,
718 receiver_id,
719 message));
722 GCMClient* GCMDriverDesktop::GetGCMClientForTesting() const {
723 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
724 return io_worker_ ? io_worker_->gcm_client_for_testing() : NULL;
727 bool GCMDriverDesktop::IsStarted() const {
728 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
729 return gcm_started_;
732 bool GCMDriverDesktop::IsConnected() const {
733 return connected_;
736 void GCMDriverDesktop::GetGCMStatistics(
737 const GetGCMStatisticsCallback& callback,
738 bool clear_logs) {
739 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
740 DCHECK(!callback.is_null());
742 request_gcm_statistics_callback_ = callback;
743 io_thread_->PostTask(
744 FROM_HERE,
745 base::Bind(&GCMDriverDesktop::IOWorker::GetGCMStatistics,
746 base::Unretained(io_worker_.get()),
747 clear_logs));
750 void GCMDriverDesktop::SetGCMRecording(const GetGCMStatisticsCallback& callback,
751 bool recording) {
752 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
754 request_gcm_statistics_callback_ = callback;
755 io_thread_->PostTask(
756 FROM_HERE,
757 base::Bind(&GCMDriverDesktop::IOWorker::SetGCMRecording,
758 base::Unretained(io_worker_.get()),
759 recording));
762 void GCMDriverDesktop::UpdateAccountMapping(
763 const AccountMapping& account_mapping) {
764 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
766 io_thread_->PostTask(
767 FROM_HERE,
768 base::Bind(&GCMDriverDesktop::IOWorker::UpdateAccountMapping,
769 base::Unretained(io_worker_.get()),
770 account_mapping));
773 void GCMDriverDesktop::RemoveAccountMapping(const std::string& account_id) {
774 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
776 io_thread_->PostTask(
777 FROM_HERE,
778 base::Bind(&GCMDriverDesktop::IOWorker::RemoveAccountMapping,
779 base::Unretained(io_worker_.get()),
780 account_id));
783 base::Time GCMDriverDesktop::GetLastTokenFetchTime() {
784 return last_token_fetch_time_;
787 void GCMDriverDesktop::SetLastTokenFetchTime(const base::Time& time) {
788 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
790 last_token_fetch_time_ = time;
792 io_thread_->PostTask(
793 FROM_HERE,
794 base::Bind(&GCMDriverDesktop::IOWorker::SetLastTokenFetchTime,
795 base::Unretained(io_worker_.get()),
796 time));
799 InstanceIDHandler* GCMDriverDesktop::GetInstanceIDHandler() {
800 return this;
803 void GCMDriverDesktop::GetToken(
804 const std::string& app_id,
805 const std::string& authorized_entity,
806 const std::string& scope,
807 const std::map<std::string, std::string>& options,
808 const GetTokenCallback& callback) {
809 DCHECK(!app_id.empty());
810 DCHECK(!authorized_entity.empty());
811 DCHECK(!scope.empty());
812 DCHECK(!callback.is_null());
813 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
815 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
816 if (result != GCMClient::SUCCESS) {
817 callback.Run(std::string(), result);
818 return;
821 // If previous GetToken operation is still in progress, bail out.
822 TokenTuple tuple_key(app_id, authorized_entity, scope);
823 if (get_token_callbacks_.find(tuple_key) != get_token_callbacks_.end()) {
824 callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING);
825 return;
828 get_token_callbacks_[tuple_key] = callback;
830 // Delay the GetToken operation until GCMClient is ready.
831 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
832 delayed_task_controller_->AddTask(
833 base::Bind(&GCMDriverDesktop::DoGetToken,
834 weak_ptr_factory_.GetWeakPtr(),
835 app_id,
836 authorized_entity,
837 scope,
838 options));
839 return;
842 DoGetToken(app_id, authorized_entity, scope, options);
845 void GCMDriverDesktop::DoGetToken(
846 const std::string& app_id,
847 const std::string& authorized_entity,
848 const std::string& scope,
849 const std::map<std::string, std::string>& options) {
850 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
852 TokenTuple tuple_key(app_id, authorized_entity, scope);
853 auto callback_iter = get_token_callbacks_.find(tuple_key);
854 if (callback_iter == get_token_callbacks_.end()) {
855 // The callback could have been removed when the app is uninstalled.
856 return;
859 io_thread_->PostTask(
860 FROM_HERE,
861 base::Bind(&GCMDriverDesktop::IOWorker::GetToken,
862 base::Unretained(io_worker_.get()),
863 app_id,
864 authorized_entity,
865 scope,
866 options));
869 void GCMDriverDesktop::DeleteToken(const std::string& app_id,
870 const std::string& authorized_entity,
871 const std::string& scope,
872 const DeleteTokenCallback& callback) {
873 DCHECK(!app_id.empty());
874 DCHECK(!authorized_entity.empty());
875 DCHECK(!scope.empty());
876 DCHECK(!callback.is_null());
877 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
879 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
880 if (result != GCMClient::SUCCESS) {
881 callback.Run(result);
882 return;
885 // If previous GetToken operation is still in progress, bail out.
886 TokenTuple tuple_key(app_id, authorized_entity, scope);
887 if (delete_token_callbacks_.find(tuple_key) !=
888 delete_token_callbacks_.end()) {
889 callback.Run(GCMClient::ASYNC_OPERATION_PENDING);
890 return;
893 delete_token_callbacks_[tuple_key] = callback;
895 // Delay the DeleteToken operation until GCMClient is ready.
896 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
897 delayed_task_controller_->AddTask(
898 base::Bind(&GCMDriverDesktop::DoDeleteToken,
899 weak_ptr_factory_.GetWeakPtr(),
900 app_id,
901 authorized_entity,
902 scope));
903 return;
906 DoDeleteToken(app_id, authorized_entity, scope);
909 void GCMDriverDesktop::DoDeleteToken(const std::string& app_id,
910 const std::string& authorized_entity,
911 const std::string& scope) {
912 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
914 io_thread_->PostTask(
915 FROM_HERE,
916 base::Bind(&GCMDriverDesktop::IOWorker::DeleteToken,
917 base::Unretained(io_worker_.get()),
918 app_id,
919 authorized_entity,
920 scope));
923 void GCMDriverDesktop::AddInstanceIDData(
924 const std::string& app_id,
925 const std::string& instance_id,
926 const std::string& extra_data) {
927 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
929 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
930 if (result != GCMClient::SUCCESS)
931 return;
933 // Delay the operation until GCMClient is ready.
934 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
935 delayed_task_controller_->AddTask(
936 base::Bind(&GCMDriverDesktop::DoAddInstanceIDData,
937 weak_ptr_factory_.GetWeakPtr(),
938 app_id,
939 instance_id,
940 extra_data));
941 return;
944 DoAddInstanceIDData(app_id, instance_id, extra_data);
947 void GCMDriverDesktop::DoAddInstanceIDData(
948 const std::string& app_id,
949 const std::string& instance_id,
950 const std::string& extra_data) {
951 io_thread_->PostTask(
952 FROM_HERE,
953 base::Bind(&GCMDriverDesktop::IOWorker::AddInstanceIDData,
954 base::Unretained(io_worker_.get()),
955 app_id,
956 instance_id,
957 extra_data));
960 void GCMDriverDesktop::RemoveInstanceIDData(const std::string& app_id) {
961 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
963 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
964 if (result != GCMClient::SUCCESS)
965 return;
967 // Delay the operation until GCMClient is ready.
968 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
969 delayed_task_controller_->AddTask(
970 base::Bind(&GCMDriverDesktop::DoRemoveInstanceIDData,
971 weak_ptr_factory_.GetWeakPtr(),
972 app_id));
973 return;
976 DoRemoveInstanceIDData(app_id);
979 void GCMDriverDesktop::DoRemoveInstanceIDData(const std::string& app_id) {
980 io_thread_->PostTask(
981 FROM_HERE,
982 base::Bind(&GCMDriverDesktop::IOWorker::RemoveInstanceIDData,
983 base::Unretained(io_worker_.get()),
984 app_id));
987 void GCMDriverDesktop::GetInstanceIDData(
988 const std::string& app_id,
989 const GetInstanceIDDataCallback& callback) {
990 DCHECK(!get_instance_id_data_callbacks_.count(app_id));
991 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
993 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
994 if (result != GCMClient::SUCCESS) {
995 callback.Run(std::string(), std::string());
996 return;
999 get_instance_id_data_callbacks_[app_id] = callback;
1001 // Delay the operation until GCMClient is ready.
1002 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
1003 delayed_task_controller_->AddTask(
1004 base::Bind(&GCMDriverDesktop::DoGetInstanceIDData,
1005 weak_ptr_factory_.GetWeakPtr(),
1006 app_id));
1007 return;
1010 DoGetInstanceIDData(app_id);
1013 void GCMDriverDesktop::DoGetInstanceIDData(const std::string& app_id) {
1014 io_thread_->PostTask(
1015 FROM_HERE,
1016 base::Bind(&GCMDriverDesktop::IOWorker::GetInstanceIDData,
1017 base::Unretained(io_worker_.get()),
1018 app_id));
1021 void GCMDriverDesktop::GetInstanceIDDataFinished(
1022 const std::string& app_id,
1023 const std::string& instance_id,
1024 const std::string& extra_data) {
1025 DCHECK(get_instance_id_data_callbacks_.count(app_id));
1026 get_instance_id_data_callbacks_[app_id].Run(instance_id, extra_data);
1027 get_instance_id_data_callbacks_.erase(app_id);
1030 void GCMDriverDesktop::GetTokenFinished(const std::string& app_id,
1031 const std::string& authorized_entity,
1032 const std::string& scope,
1033 const std::string& token,
1034 GCMClient::Result result) {
1035 TokenTuple tuple_key(app_id, authorized_entity, scope);
1036 auto callback_iter = get_token_callbacks_.find(tuple_key);
1037 if (callback_iter == get_token_callbacks_.end()) {
1038 // The callback could have been removed when the app is uninstalled.
1039 return;
1042 GetTokenCallback callback = callback_iter->second;
1043 get_token_callbacks_.erase(callback_iter);
1044 callback.Run(token, result);
1047 void GCMDriverDesktop::DeleteTokenFinished(const std::string& app_id,
1048 const std::string& authorized_entity,
1049 const std::string& scope,
1050 GCMClient::Result result) {
1051 TokenTuple tuple_key(app_id, authorized_entity, scope);
1052 auto callback_iter = delete_token_callbacks_.find(tuple_key);
1053 if (callback_iter == delete_token_callbacks_.end()) {
1054 // The callback could have been removed when the app is uninstalled.
1055 return;
1058 DeleteTokenCallback callback = callback_iter->second;
1059 delete_token_callbacks_.erase(callback_iter);
1060 callback.Run(result);
1063 void GCMDriverDesktop::WakeFromSuspendForHeartbeat(bool wake) {
1064 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1066 wake_from_suspend_enabled_ = wake;
1068 // The GCM service has not been initialized.
1069 if (!delayed_task_controller_)
1070 return;
1072 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
1073 // The GCM service was initialized but has not started yet.
1074 delayed_task_controller_->AddTask(
1075 base::Bind(&GCMDriverDesktop::WakeFromSuspendForHeartbeat,
1076 weak_ptr_factory_.GetWeakPtr(),
1077 wake_from_suspend_enabled_));
1078 return;
1081 // The GCMClient is ready so we can go ahead and post this task to the
1082 // IOWorker.
1083 io_thread_->PostTask(
1084 FROM_HERE,
1085 base::Bind(&GCMDriverDesktop::IOWorker::WakeFromSuspendForHeartbeat,
1086 base::Unretained(io_worker_.get()),
1087 wake_from_suspend_enabled_));
1090 void GCMDriverDesktop::AddHeartbeatInterval(const std::string& scope,
1091 int interval_ms) {
1092 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1094 // The GCM service has not been initialized.
1095 if (!delayed_task_controller_)
1096 return;
1098 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
1099 // The GCM service was initialized but has not started yet.
1100 delayed_task_controller_->AddTask(
1101 base::Bind(&GCMDriverDesktop::AddHeartbeatInterval,
1102 weak_ptr_factory_.GetWeakPtr(), scope, interval_ms));
1103 return;
1106 io_thread_->PostTask(
1107 FROM_HERE,
1108 base::Bind(&GCMDriverDesktop::IOWorker::AddHeartbeatInterval,
1109 base::Unretained(io_worker_.get()), scope, interval_ms));
1112 void GCMDriverDesktop::RemoveHeartbeatInterval(const std::string& scope) {
1113 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1115 // The GCM service has not been initialized.
1116 if (!delayed_task_controller_)
1117 return;
1119 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
1120 // The GCM service was initialized but has not started yet.
1121 delayed_task_controller_->AddTask(
1122 base::Bind(&GCMDriverDesktop::RemoveHeartbeatInterval,
1123 weak_ptr_factory_.GetWeakPtr(), scope));
1124 return;
1127 io_thread_->PostTask(
1128 FROM_HERE,
1129 base::Bind(&GCMDriverDesktop::IOWorker::RemoveHeartbeatInterval,
1130 base::Unretained(io_worker_.get()), scope));
1133 void GCMDriverDesktop::SetAccountTokens(
1134 const std::vector<GCMClient::AccountTokenInfo>& account_tokens) {
1135 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1137 account_mapper_->SetAccountTokens(account_tokens);
1139 io_thread_->PostTask(
1140 FROM_HERE,
1141 base::Bind(&GCMDriverDesktop::IOWorker::SetAccountTokens,
1142 base::Unretained(io_worker_.get()),
1143 account_tokens));
1146 GCMClient::Result GCMDriverDesktop::EnsureStarted(
1147 GCMClient::StartMode start_mode) {
1148 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1150 if (gcm_started_)
1151 return GCMClient::SUCCESS;
1153 // Have any app requested the service?
1154 if (app_handlers().empty())
1155 return GCMClient::UNKNOWN_ERROR;
1157 // Polling for channel status should be invoked when GCM is being requested,
1158 // no matter whether GCM is enabled or nor.
1159 gcm_channel_status_syncer_->EnsureStarted();
1161 if (!gcm_enabled_)
1162 return GCMClient::GCM_DISABLED;
1164 if (!delayed_task_controller_)
1165 delayed_task_controller_.reset(new GCMDelayedTaskController);
1167 // Note that we need to pass weak pointer again since the existing weak
1168 // pointer in IOWorker might have been invalidated when GCM is stopped.
1169 io_thread_->PostTask(
1170 FROM_HERE,
1171 base::Bind(&GCMDriverDesktop::IOWorker::Start,
1172 base::Unretained(io_worker_.get()),
1173 start_mode,
1174 weak_ptr_factory_.GetWeakPtr()));
1176 return GCMClient::SUCCESS;
1179 void GCMDriverDesktop::RemoveCachedData() {
1180 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1181 // Remove all the queued tasks since they no longer make sense after
1182 // GCM service is stopped.
1183 weak_ptr_factory_.InvalidateWeakPtrs();
1185 gcm_started_ = false;
1186 delayed_task_controller_.reset();
1187 ClearCallbacks();
1190 void GCMDriverDesktop::MessageReceived(const std::string& app_id,
1191 const IncomingMessage& message) {
1192 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1194 // Drop the event if the service has been stopped.
1195 if (!gcm_started_)
1196 return;
1198 GetAppHandler(app_id)->OnMessage(app_id, message);
1201 void GCMDriverDesktop::MessagesDeleted(const std::string& app_id) {
1202 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1204 // Drop the event if the service has been stopped.
1205 if (!gcm_started_)
1206 return;
1208 GetAppHandler(app_id)->OnMessagesDeleted(app_id);
1211 void GCMDriverDesktop::MessageSendError(
1212 const std::string& app_id,
1213 const GCMClient::SendErrorDetails& send_error_details) {
1214 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1216 // Drop the event if the service has been stopped.
1217 if (!gcm_started_)
1218 return;
1220 GetAppHandler(app_id)->OnSendError(app_id, send_error_details);
1223 void GCMDriverDesktop::SendAcknowledged(const std::string& app_id,
1224 const std::string& message_id) {
1225 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1227 // Drop the event if the service has been stopped.
1228 if (!gcm_started_)
1229 return;
1231 GetAppHandler(app_id)->OnSendAcknowledged(app_id, message_id);
1234 void GCMDriverDesktop::GCMClientReady(
1235 const std::vector<AccountMapping>& account_mappings,
1236 const base::Time& last_token_fetch_time) {
1237 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1239 UMA_HISTOGRAM_BOOLEAN("GCM.UserSignedIn", signed_in_);
1241 gcm_started_ = true;
1242 if (wake_from_suspend_enabled_)
1243 WakeFromSuspendForHeartbeat(wake_from_suspend_enabled_);
1245 last_token_fetch_time_ = last_token_fetch_time;
1247 GCMDriver::AddAppHandler(kGCMAccountMapperAppId, account_mapper_.get());
1248 account_mapper_->Initialize(account_mappings,
1249 base::Bind(&GCMDriverDesktop::MessageReceived,
1250 weak_ptr_factory_.GetWeakPtr()));
1252 delayed_task_controller_->SetReady();
1255 void GCMDriverDesktop::OnConnected(const net::IPEndPoint& ip_endpoint) {
1256 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1258 connected_ = true;
1260 // Drop the event if the service has been stopped.
1261 if (!gcm_started_)
1262 return;
1264 FOR_EACH_OBSERVER(GCMConnectionObserver,
1265 connection_observer_list_,
1266 OnConnected(ip_endpoint));
1269 void GCMDriverDesktop::OnDisconnected() {
1270 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1272 connected_ = false;
1274 // Drop the event if the service has been stopped.
1275 if (!gcm_started_)
1276 return;
1278 FOR_EACH_OBSERVER(
1279 GCMConnectionObserver, connection_observer_list_, OnDisconnected());
1282 void GCMDriverDesktop::GetGCMStatisticsFinished(
1283 const GCMClient::GCMStatistics& stats) {
1284 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1286 // request_gcm_statistics_callback_ could be null when an activity, i.e.
1287 // network activity, is triggered while gcm-intenals page is not open.
1288 if (!request_gcm_statistics_callback_.is_null())
1289 request_gcm_statistics_callback_.Run(stats);
1292 bool GCMDriverDesktop::TokenTupleComparer::operator()(
1293 const TokenTuple& a, const TokenTuple& b) const {
1294 if (base::get<0>(a) < base::get<0>(b))
1295 return true;
1296 if (base::get<0>(a) > base::get<0>(b))
1297 return false;
1299 if (base::get<1>(a) < base::get<1>(b))
1300 return true;
1301 if (base::get<1>(a) > base::get<1>(b))
1302 return false;
1304 return base::get<2>(a) < base::get<2>(b);
1307 } // namespace gcm