Implements RLZTrackerDelegate on iOS.
[chromium-blink-merge.git] / components / gcm_driver / gcm_driver_desktop.cc
blob6864ed2ef7fe8faa903b8807df77fb7a0fdf19ac
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 : gcm_channel_status_syncer_(
508 new GCMChannelStatusSyncer(this,
509 prefs,
510 channel_status_request_url,
511 user_agent,
512 request_context)),
513 signed_in_(false),
514 gcm_started_(false),
515 gcm_enabled_(true),
516 connected_(false),
517 account_mapper_(new GCMAccountMapper(this)),
518 // Setting to max, to make sure it does not prompt for token reporting
519 // Before reading a reasonable value from the DB, which might be never,
520 // in which case the fetching will be triggered.
521 last_token_fetch_time_(base::Time::Max()),
522 ui_thread_(ui_thread),
523 io_thread_(io_thread),
524 wake_from_suspend_enabled_(false),
525 weak_ptr_factory_(this) {
526 gcm_enabled_ = gcm_channel_status_syncer_->gcm_enabled();
528 // Create and initialize the GCMClient. Note that this does not initiate the
529 // GCM check-in.
530 io_worker_.reset(new IOWorker(ui_thread, io_thread));
531 io_thread_->PostTask(
532 FROM_HERE,
533 base::Bind(&GCMDriverDesktop::IOWorker::Initialize,
534 base::Unretained(io_worker_.get()),
535 base::Passed(&gcm_client_factory),
536 chrome_build_info,
537 store_path,
538 request_context,
539 blocking_task_runner));
542 GCMDriverDesktop::~GCMDriverDesktop() {
545 void GCMDriverDesktop::Shutdown() {
546 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
548 Stop();
549 GCMDriver::Shutdown();
551 // Dispose the syncer in order to release the reference to
552 // URLRequestContextGetter that needs to be done before IOThread gets
553 // deleted.
554 gcm_channel_status_syncer_.reset();
556 io_thread_->DeleteSoon(FROM_HERE, io_worker_.release());
559 void GCMDriverDesktop::OnSignedIn() {
560 signed_in_ = true;
563 void GCMDriverDesktop::OnSignedOut() {
564 signed_in_ = false;
567 void GCMDriverDesktop::AddAppHandler(const std::string& app_id,
568 GCMAppHandler* handler) {
569 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
570 GCMDriver::AddAppHandler(app_id, handler);
572 // Ensures that the GCM service is started when there is an interest.
573 EnsureStarted(GCMClient::DELAYED_START);
576 void GCMDriverDesktop::RemoveAppHandler(const std::string& app_id) {
577 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
578 GCMDriver::RemoveAppHandler(app_id);
580 // Stops the GCM service when no app intends to consume it. Stop function will
581 // remove the last app handler - account mapper.
582 if (app_handlers().size() == 1) {
583 Stop();
584 gcm_channel_status_syncer_->Stop();
588 void GCMDriverDesktop::AddConnectionObserver(GCMConnectionObserver* observer) {
589 connection_observer_list_.AddObserver(observer);
592 void GCMDriverDesktop::RemoveConnectionObserver(
593 GCMConnectionObserver* observer) {
594 connection_observer_list_.RemoveObserver(observer);
597 void GCMDriverDesktop::Enable() {
598 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
600 if (gcm_enabled_)
601 return;
602 gcm_enabled_ = true;
604 EnsureStarted(GCMClient::DELAYED_START);
607 void GCMDriverDesktop::Disable() {
608 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
610 if (!gcm_enabled_)
611 return;
612 gcm_enabled_ = false;
614 Stop();
617 void GCMDriverDesktop::Stop() {
618 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
620 // No need to stop GCM service if not started yet.
621 if (!gcm_started_)
622 return;
624 account_mapper_->ShutdownHandler();
625 GCMDriver::RemoveAppHandler(kGCMAccountMapperAppId);
627 RemoveCachedData();
629 io_thread_->PostTask(
630 FROM_HERE,
631 base::Bind(&GCMDriverDesktop::IOWorker::Stop,
632 base::Unretained(io_worker_.get())));
635 void GCMDriverDesktop::RegisterImpl(
636 const std::string& app_id,
637 const std::vector<std::string>& sender_ids) {
638 // Delay the register operation until GCMClient is ready.
639 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
640 delayed_task_controller_->AddTask(base::Bind(&GCMDriverDesktop::DoRegister,
641 weak_ptr_factory_.GetWeakPtr(),
642 app_id,
643 sender_ids));
644 return;
647 DoRegister(app_id, sender_ids);
650 void GCMDriverDesktop::DoRegister(const std::string& app_id,
651 const std::vector<std::string>& sender_ids) {
652 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
653 if (!HasRegisterCallback(app_id)) {
654 // The callback could have been removed when the app is uninstalled.
655 return;
658 io_thread_->PostTask(
659 FROM_HERE,
660 base::Bind(&GCMDriverDesktop::IOWorker::Register,
661 base::Unretained(io_worker_.get()),
662 app_id,
663 sender_ids));
666 void GCMDriverDesktop::UnregisterImpl(const std::string& app_id) {
667 // Delay the unregister operation until GCMClient is ready.
668 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
669 delayed_task_controller_->AddTask(
670 base::Bind(&GCMDriverDesktop::DoUnregister,
671 weak_ptr_factory_.GetWeakPtr(),
672 app_id));
673 return;
676 DoUnregister(app_id);
679 void GCMDriverDesktop::DoUnregister(const std::string& app_id) {
680 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
682 // Ask the server to unregister it. There could be a small chance that the
683 // unregister request fails. If this occurs, it does not bring any harm since
684 // we simply reject the messages/events received from the server.
685 io_thread_->PostTask(
686 FROM_HERE,
687 base::Bind(&GCMDriverDesktop::IOWorker::Unregister,
688 base::Unretained(io_worker_.get()),
689 app_id));
692 void GCMDriverDesktop::SendImpl(const std::string& app_id,
693 const std::string& receiver_id,
694 const OutgoingMessage& message) {
695 // Delay the send operation until all GCMClient is ready.
696 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
697 delayed_task_controller_->AddTask(base::Bind(&GCMDriverDesktop::DoSend,
698 weak_ptr_factory_.GetWeakPtr(),
699 app_id,
700 receiver_id,
701 message));
702 return;
705 DoSend(app_id, receiver_id, message);
708 void GCMDriverDesktop::DoSend(const std::string& app_id,
709 const std::string& receiver_id,
710 const OutgoingMessage& message) {
711 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
712 io_thread_->PostTask(
713 FROM_HERE,
714 base::Bind(&GCMDriverDesktop::IOWorker::Send,
715 base::Unretained(io_worker_.get()),
716 app_id,
717 receiver_id,
718 message));
721 GCMClient* GCMDriverDesktop::GetGCMClientForTesting() const {
722 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
723 return io_worker_ ? io_worker_->gcm_client_for_testing() : NULL;
726 bool GCMDriverDesktop::IsStarted() const {
727 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
728 return gcm_started_;
731 bool GCMDriverDesktop::IsConnected() const {
732 return connected_;
735 void GCMDriverDesktop::GetGCMStatistics(
736 const GetGCMStatisticsCallback& callback,
737 bool clear_logs) {
738 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
739 DCHECK(!callback.is_null());
741 request_gcm_statistics_callback_ = callback;
742 io_thread_->PostTask(
743 FROM_HERE,
744 base::Bind(&GCMDriverDesktop::IOWorker::GetGCMStatistics,
745 base::Unretained(io_worker_.get()),
746 clear_logs));
749 void GCMDriverDesktop::SetGCMRecording(const GetGCMStatisticsCallback& callback,
750 bool recording) {
751 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
753 request_gcm_statistics_callback_ = callback;
754 io_thread_->PostTask(
755 FROM_HERE,
756 base::Bind(&GCMDriverDesktop::IOWorker::SetGCMRecording,
757 base::Unretained(io_worker_.get()),
758 recording));
761 void GCMDriverDesktop::UpdateAccountMapping(
762 const AccountMapping& account_mapping) {
763 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
765 io_thread_->PostTask(
766 FROM_HERE,
767 base::Bind(&GCMDriverDesktop::IOWorker::UpdateAccountMapping,
768 base::Unretained(io_worker_.get()),
769 account_mapping));
772 void GCMDriverDesktop::RemoveAccountMapping(const std::string& account_id) {
773 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
775 io_thread_->PostTask(
776 FROM_HERE,
777 base::Bind(&GCMDriverDesktop::IOWorker::RemoveAccountMapping,
778 base::Unretained(io_worker_.get()),
779 account_id));
782 base::Time GCMDriverDesktop::GetLastTokenFetchTime() {
783 return last_token_fetch_time_;
786 void GCMDriverDesktop::SetLastTokenFetchTime(const base::Time& time) {
787 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
789 last_token_fetch_time_ = time;
791 io_thread_->PostTask(
792 FROM_HERE,
793 base::Bind(&GCMDriverDesktop::IOWorker::SetLastTokenFetchTime,
794 base::Unretained(io_worker_.get()),
795 time));
798 InstanceIDHandler* GCMDriverDesktop::GetInstanceIDHandler() {
799 return this;
802 void GCMDriverDesktop::GetToken(
803 const std::string& app_id,
804 const std::string& authorized_entity,
805 const std::string& scope,
806 const std::map<std::string, std::string>& options,
807 const GetTokenCallback& callback) {
808 DCHECK(!app_id.empty());
809 DCHECK(!authorized_entity.empty());
810 DCHECK(!scope.empty());
811 DCHECK(!callback.is_null());
812 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
814 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
815 if (result != GCMClient::SUCCESS) {
816 callback.Run(std::string(), result);
817 return;
820 // If previous GetToken operation is still in progress, bail out.
821 TokenTuple tuple_key(app_id, authorized_entity, scope);
822 if (get_token_callbacks_.find(tuple_key) != get_token_callbacks_.end()) {
823 callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING);
824 return;
827 get_token_callbacks_[tuple_key] = callback;
829 // Delay the GetToken operation until GCMClient is ready.
830 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
831 delayed_task_controller_->AddTask(
832 base::Bind(&GCMDriverDesktop::DoGetToken,
833 weak_ptr_factory_.GetWeakPtr(),
834 app_id,
835 authorized_entity,
836 scope,
837 options));
838 return;
841 DoGetToken(app_id, authorized_entity, scope, options);
844 void GCMDriverDesktop::DoGetToken(
845 const std::string& app_id,
846 const std::string& authorized_entity,
847 const std::string& scope,
848 const std::map<std::string, std::string>& options) {
849 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
851 TokenTuple tuple_key(app_id, authorized_entity, scope);
852 auto callback_iter = get_token_callbacks_.find(tuple_key);
853 if (callback_iter == get_token_callbacks_.end()) {
854 // The callback could have been removed when the app is uninstalled.
855 return;
858 io_thread_->PostTask(
859 FROM_HERE,
860 base::Bind(&GCMDriverDesktop::IOWorker::GetToken,
861 base::Unretained(io_worker_.get()),
862 app_id,
863 authorized_entity,
864 scope,
865 options));
868 void GCMDriverDesktop::DeleteToken(const std::string& app_id,
869 const std::string& authorized_entity,
870 const std::string& scope,
871 const DeleteTokenCallback& callback) {
872 DCHECK(!app_id.empty());
873 DCHECK(!authorized_entity.empty());
874 DCHECK(!scope.empty());
875 DCHECK(!callback.is_null());
876 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
878 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
879 if (result != GCMClient::SUCCESS) {
880 callback.Run(result);
881 return;
884 // If previous GetToken operation is still in progress, bail out.
885 TokenTuple tuple_key(app_id, authorized_entity, scope);
886 if (delete_token_callbacks_.find(tuple_key) !=
887 delete_token_callbacks_.end()) {
888 callback.Run(GCMClient::ASYNC_OPERATION_PENDING);
889 return;
892 delete_token_callbacks_[tuple_key] = callback;
894 // Delay the DeleteToken operation until GCMClient is ready.
895 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
896 delayed_task_controller_->AddTask(
897 base::Bind(&GCMDriverDesktop::DoDeleteToken,
898 weak_ptr_factory_.GetWeakPtr(),
899 app_id,
900 authorized_entity,
901 scope));
902 return;
905 DoDeleteToken(app_id, authorized_entity, scope);
908 void GCMDriverDesktop::DoDeleteToken(const std::string& app_id,
909 const std::string& authorized_entity,
910 const std::string& scope) {
911 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
913 io_thread_->PostTask(
914 FROM_HERE,
915 base::Bind(&GCMDriverDesktop::IOWorker::DeleteToken,
916 base::Unretained(io_worker_.get()),
917 app_id,
918 authorized_entity,
919 scope));
922 void GCMDriverDesktop::AddInstanceIDData(
923 const std::string& app_id,
924 const std::string& instance_id,
925 const std::string& extra_data) {
926 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
928 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
929 if (result != GCMClient::SUCCESS)
930 return;
932 // Delay the operation until GCMClient is ready.
933 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
934 delayed_task_controller_->AddTask(
935 base::Bind(&GCMDriverDesktop::DoAddInstanceIDData,
936 weak_ptr_factory_.GetWeakPtr(),
937 app_id,
938 instance_id,
939 extra_data));
940 return;
943 DoAddInstanceIDData(app_id, instance_id, extra_data);
946 void GCMDriverDesktop::DoAddInstanceIDData(
947 const std::string& app_id,
948 const std::string& instance_id,
949 const std::string& extra_data) {
950 io_thread_->PostTask(
951 FROM_HERE,
952 base::Bind(&GCMDriverDesktop::IOWorker::AddInstanceIDData,
953 base::Unretained(io_worker_.get()),
954 app_id,
955 instance_id,
956 extra_data));
959 void GCMDriverDesktop::RemoveInstanceIDData(const std::string& app_id) {
960 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
962 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
963 if (result != GCMClient::SUCCESS)
964 return;
966 // Delay the operation until GCMClient is ready.
967 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
968 delayed_task_controller_->AddTask(
969 base::Bind(&GCMDriverDesktop::DoRemoveInstanceIDData,
970 weak_ptr_factory_.GetWeakPtr(),
971 app_id));
972 return;
975 DoRemoveInstanceIDData(app_id);
978 void GCMDriverDesktop::DoRemoveInstanceIDData(const std::string& app_id) {
979 io_thread_->PostTask(
980 FROM_HERE,
981 base::Bind(&GCMDriverDesktop::IOWorker::RemoveInstanceIDData,
982 base::Unretained(io_worker_.get()),
983 app_id));
986 void GCMDriverDesktop::GetInstanceIDData(
987 const std::string& app_id,
988 const GetInstanceIDDataCallback& callback) {
989 DCHECK(!get_instance_id_data_callbacks_.count(app_id));
990 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
992 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
993 if (result != GCMClient::SUCCESS) {
994 callback.Run(std::string(), std::string());
995 return;
998 get_instance_id_data_callbacks_[app_id] = callback;
1000 // Delay the operation until GCMClient is ready.
1001 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
1002 delayed_task_controller_->AddTask(
1003 base::Bind(&GCMDriverDesktop::DoGetInstanceIDData,
1004 weak_ptr_factory_.GetWeakPtr(),
1005 app_id));
1006 return;
1009 DoGetInstanceIDData(app_id);
1012 void GCMDriverDesktop::DoGetInstanceIDData(const std::string& app_id) {
1013 io_thread_->PostTask(
1014 FROM_HERE,
1015 base::Bind(&GCMDriverDesktop::IOWorker::GetInstanceIDData,
1016 base::Unretained(io_worker_.get()),
1017 app_id));
1020 void GCMDriverDesktop::GetInstanceIDDataFinished(
1021 const std::string& app_id,
1022 const std::string& instance_id,
1023 const std::string& extra_data) {
1024 DCHECK(get_instance_id_data_callbacks_.count(app_id));
1025 get_instance_id_data_callbacks_[app_id].Run(instance_id, extra_data);
1026 get_instance_id_data_callbacks_.erase(app_id);
1029 void GCMDriverDesktop::GetTokenFinished(const std::string& app_id,
1030 const std::string& authorized_entity,
1031 const std::string& scope,
1032 const std::string& token,
1033 GCMClient::Result result) {
1034 TokenTuple tuple_key(app_id, authorized_entity, scope);
1035 auto callback_iter = get_token_callbacks_.find(tuple_key);
1036 if (callback_iter == get_token_callbacks_.end()) {
1037 // The callback could have been removed when the app is uninstalled.
1038 return;
1041 GetTokenCallback callback = callback_iter->second;
1042 get_token_callbacks_.erase(callback_iter);
1043 callback.Run(token, result);
1046 void GCMDriverDesktop::DeleteTokenFinished(const std::string& app_id,
1047 const std::string& authorized_entity,
1048 const std::string& scope,
1049 GCMClient::Result result) {
1050 TokenTuple tuple_key(app_id, authorized_entity, scope);
1051 auto callback_iter = delete_token_callbacks_.find(tuple_key);
1052 if (callback_iter == delete_token_callbacks_.end()) {
1053 // The callback could have been removed when the app is uninstalled.
1054 return;
1057 DeleteTokenCallback callback = callback_iter->second;
1058 delete_token_callbacks_.erase(callback_iter);
1059 callback.Run(result);
1062 void GCMDriverDesktop::WakeFromSuspendForHeartbeat(bool wake) {
1063 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1065 wake_from_suspend_enabled_ = wake;
1067 // The GCM service has not been initialized.
1068 if (!delayed_task_controller_)
1069 return;
1071 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
1072 // The GCM service was initialized but has not started yet.
1073 delayed_task_controller_->AddTask(
1074 base::Bind(&GCMDriverDesktop::WakeFromSuspendForHeartbeat,
1075 weak_ptr_factory_.GetWeakPtr(),
1076 wake_from_suspend_enabled_));
1077 return;
1080 // The GCMClient is ready so we can go ahead and post this task to the
1081 // IOWorker.
1082 io_thread_->PostTask(
1083 FROM_HERE,
1084 base::Bind(&GCMDriverDesktop::IOWorker::WakeFromSuspendForHeartbeat,
1085 base::Unretained(io_worker_.get()),
1086 wake_from_suspend_enabled_));
1089 void GCMDriverDesktop::AddHeartbeatInterval(const std::string& scope,
1090 int interval_ms) {
1091 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1093 // The GCM service has not been initialized.
1094 if (!delayed_task_controller_)
1095 return;
1097 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
1098 // The GCM service was initialized but has not started yet.
1099 delayed_task_controller_->AddTask(
1100 base::Bind(&GCMDriverDesktop::AddHeartbeatInterval,
1101 weak_ptr_factory_.GetWeakPtr(), scope, interval_ms));
1102 return;
1105 io_thread_->PostTask(
1106 FROM_HERE,
1107 base::Bind(&GCMDriverDesktop::IOWorker::AddHeartbeatInterval,
1108 base::Unretained(io_worker_.get()), scope, interval_ms));
1111 void GCMDriverDesktop::RemoveHeartbeatInterval(const std::string& scope) {
1112 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1114 // The GCM service has not been initialized.
1115 if (!delayed_task_controller_)
1116 return;
1118 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
1119 // The GCM service was initialized but has not started yet.
1120 delayed_task_controller_->AddTask(
1121 base::Bind(&GCMDriverDesktop::RemoveHeartbeatInterval,
1122 weak_ptr_factory_.GetWeakPtr(), scope));
1123 return;
1126 io_thread_->PostTask(
1127 FROM_HERE,
1128 base::Bind(&GCMDriverDesktop::IOWorker::RemoveHeartbeatInterval,
1129 base::Unretained(io_worker_.get()), scope));
1132 void GCMDriverDesktop::SetAccountTokens(
1133 const std::vector<GCMClient::AccountTokenInfo>& account_tokens) {
1134 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1136 account_mapper_->SetAccountTokens(account_tokens);
1138 io_thread_->PostTask(
1139 FROM_HERE,
1140 base::Bind(&GCMDriverDesktop::IOWorker::SetAccountTokens,
1141 base::Unretained(io_worker_.get()),
1142 account_tokens));
1145 GCMClient::Result GCMDriverDesktop::EnsureStarted(
1146 GCMClient::StartMode start_mode) {
1147 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1149 if (gcm_started_)
1150 return GCMClient::SUCCESS;
1152 // Have any app requested the service?
1153 if (app_handlers().empty())
1154 return GCMClient::UNKNOWN_ERROR;
1156 // Polling for channel status should be invoked when GCM is being requested,
1157 // no matter whether GCM is enabled or nor.
1158 gcm_channel_status_syncer_->EnsureStarted();
1160 if (!gcm_enabled_)
1161 return GCMClient::GCM_DISABLED;
1163 if (!delayed_task_controller_)
1164 delayed_task_controller_.reset(new GCMDelayedTaskController);
1166 // Note that we need to pass weak pointer again since the existing weak
1167 // pointer in IOWorker might have been invalidated when GCM is stopped.
1168 io_thread_->PostTask(
1169 FROM_HERE,
1170 base::Bind(&GCMDriverDesktop::IOWorker::Start,
1171 base::Unretained(io_worker_.get()),
1172 start_mode,
1173 weak_ptr_factory_.GetWeakPtr()));
1175 return GCMClient::SUCCESS;
1178 void GCMDriverDesktop::RemoveCachedData() {
1179 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1180 // Remove all the queued tasks since they no longer make sense after
1181 // GCM service is stopped.
1182 weak_ptr_factory_.InvalidateWeakPtrs();
1184 gcm_started_ = false;
1185 delayed_task_controller_.reset();
1186 ClearCallbacks();
1189 void GCMDriverDesktop::MessageReceived(const std::string& app_id,
1190 const IncomingMessage& message) {
1191 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1193 // Drop the event if the service has been stopped.
1194 if (!gcm_started_)
1195 return;
1197 GetAppHandler(app_id)->OnMessage(app_id, message);
1200 void GCMDriverDesktop::MessagesDeleted(const std::string& app_id) {
1201 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1203 // Drop the event if the service has been stopped.
1204 if (!gcm_started_)
1205 return;
1207 GetAppHandler(app_id)->OnMessagesDeleted(app_id);
1210 void GCMDriverDesktop::MessageSendError(
1211 const std::string& app_id,
1212 const GCMClient::SendErrorDetails& send_error_details) {
1213 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1215 // Drop the event if the service has been stopped.
1216 if (!gcm_started_)
1217 return;
1219 GetAppHandler(app_id)->OnSendError(app_id, send_error_details);
1222 void GCMDriverDesktop::SendAcknowledged(const std::string& app_id,
1223 const std::string& message_id) {
1224 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1226 // Drop the event if the service has been stopped.
1227 if (!gcm_started_)
1228 return;
1230 GetAppHandler(app_id)->OnSendAcknowledged(app_id, message_id);
1233 void GCMDriverDesktop::GCMClientReady(
1234 const std::vector<AccountMapping>& account_mappings,
1235 const base::Time& last_token_fetch_time) {
1236 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1238 UMA_HISTOGRAM_BOOLEAN("GCM.UserSignedIn", signed_in_);
1240 gcm_started_ = true;
1241 if (wake_from_suspend_enabled_)
1242 WakeFromSuspendForHeartbeat(wake_from_suspend_enabled_);
1244 last_token_fetch_time_ = last_token_fetch_time;
1246 GCMDriver::AddAppHandler(kGCMAccountMapperAppId, account_mapper_.get());
1247 account_mapper_->Initialize(account_mappings,
1248 base::Bind(&GCMDriverDesktop::MessageReceived,
1249 weak_ptr_factory_.GetWeakPtr()));
1251 delayed_task_controller_->SetReady();
1254 void GCMDriverDesktop::OnConnected(const net::IPEndPoint& ip_endpoint) {
1255 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1257 connected_ = true;
1259 // Drop the event if the service has been stopped.
1260 if (!gcm_started_)
1261 return;
1263 FOR_EACH_OBSERVER(GCMConnectionObserver,
1264 connection_observer_list_,
1265 OnConnected(ip_endpoint));
1268 void GCMDriverDesktop::OnDisconnected() {
1269 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1271 connected_ = false;
1273 // Drop the event if the service has been stopped.
1274 if (!gcm_started_)
1275 return;
1277 FOR_EACH_OBSERVER(
1278 GCMConnectionObserver, connection_observer_list_, OnDisconnected());
1281 void GCMDriverDesktop::GetGCMStatisticsFinished(
1282 const GCMClient::GCMStatistics& stats) {
1283 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
1285 // request_gcm_statistics_callback_ could be null when an activity, i.e.
1286 // network activity, is triggered while gcm-intenals page is not open.
1287 if (!request_gcm_statistics_callback_.is_null())
1288 request_gcm_statistics_callback_.Run(stats);
1291 bool GCMDriverDesktop::TokenTupleComparer::operator()(
1292 const TokenTuple& a, const TokenTuple& b) const {
1293 if (base::get<0>(a) < base::get<0>(b))
1294 return true;
1295 if (base::get<0>(a) > base::get<0>(b))
1296 return false;
1298 if (base::get<1>(a) < base::get<1>(b))
1299 return true;
1300 if (base::get<1>(a) > base::get<1>(b))
1301 return false;
1303 return base::get<2>(a) < base::get<2>(b);
1306 } // namespace gcm