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"
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"
35 class GCMDriverDesktop::IOWorker
: public GCMClient::Delegate
{
37 // Called on UI thread.
38 IOWorker(const scoped_refptr
<base::SequencedTaskRunner
>& ui_thread
,
39 const scoped_refptr
<base::SequencedTaskRunner
>& io_thread
);
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.
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
);
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(); }
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
,
150 blocking_task_runner
,
152 make_scoped_ptr
<Encryptor
>(new SystemEncryptor
),
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(
167 base::Bind(&GCMDriverDesktop::RegisterFinished
,
169 gcm_registration_info
->app_id
,
174 const InstanceIDTokenInfo
* instance_id_token_info
=
175 InstanceIDTokenInfo::FromRegistrationInfo(registration_info
.get());
176 if (instance_id_token_info
) {
177 ui_thread_
->PostTask(
179 base::Bind(&GCMDriverDesktop::GetTokenFinished
,
181 instance_id_token_info
->app_id
,
182 instance_id_token_info
->authorized_entity
,
183 instance_id_token_info
->scope
,
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(
199 base::Bind(&GCMDriverDesktop::UnregisterFinished
,
201 gcm_registration_info
->app_id
,
205 const InstanceIDTokenInfo
* instance_id_token_info
=
206 InstanceIDTokenInfo::FromRegistrationInfo(registration_info
.get());
207 if (instance_id_token_info
) {
208 ui_thread_
->PostTask(
210 base::Bind(&GCMDriverDesktop::DeleteTokenFinished
,
212 instance_id_token_info
->app_id
,
213 instance_id_token_info
->authorized_entity
,
214 instance_id_token_info
->scope
,
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(
226 base::Bind(&GCMDriverDesktop::SendFinished
, service_
, app_id
, message_id
,
230 void GCMDriverDesktop::IOWorker::OnMessageReceived(
231 const std::string
& app_id
,
232 const IncomingMessage
& message
) {
233 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
235 ui_thread_
->PostTask(
237 base::Bind(&GCMDriverDesktop::MessageReceived
,
243 void GCMDriverDesktop::IOWorker::OnMessagesDeleted(const std::string
& app_id
) {
244 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
246 ui_thread_
->PostTask(
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(
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(
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
,
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
,
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());
309 gcm_client_
->Start(start_mode
);
312 void GCMDriverDesktop::IOWorker::Stop() {
313 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
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()) {
352 gcm_client_
->ClearActivityLogs();
353 stats
= gcm_client_
->GetStatistics();
356 ui_thread_
->PostTask(
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(
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(
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
;
476 timer
.reset(new timers::SimpleAlarmTimer());
478 timer
.reset(new base::Timer(true, false));
480 gcm_client_
->UpdateHeartbeatTimer(timer
.Pass());
484 void GCMDriverDesktop::IOWorker::AddHeartbeatInterval(const std::string
& scope
,
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
,
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,
511 channel_status_request_url
,
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
531 io_worker_
.reset(new IOWorker(ui_thread
, io_thread
));
532 io_thread_
->PostTask(
534 base::Bind(&GCMDriverDesktop::IOWorker::Initialize
,
535 base::Unretained(io_worker_
.get()),
536 base::Passed(&gcm_client_factory
),
540 blocking_task_runner
));
543 GCMDriverDesktop::~GCMDriverDesktop() {
546 void GCMDriverDesktop::Shutdown() {
547 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
550 GCMDriver::Shutdown();
552 // Dispose the syncer in order to release the reference to
553 // URLRequestContextGetter that needs to be done before IOThread gets
555 gcm_channel_status_syncer_
.reset();
557 io_thread_
->DeleteSoon(FROM_HERE
, io_worker_
.release());
560 void GCMDriverDesktop::OnSignedIn() {
564 void GCMDriverDesktop::OnSignedOut() {
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) {
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());
605 EnsureStarted(GCMClient::DELAYED_START
);
608 void GCMDriverDesktop::Disable() {
609 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
613 gcm_enabled_
= false;
618 void GCMDriverDesktop::Stop() {
619 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
621 // No need to stop GCM service if not started yet.
625 account_mapper_
->ShutdownHandler();
626 GCMDriver::RemoveAppHandler(kGCMAccountMapperAppId
);
630 io_thread_
->PostTask(
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(),
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.
659 io_thread_
->PostTask(
661 base::Bind(&GCMDriverDesktop::IOWorker::Register
,
662 base::Unretained(io_worker_
.get()),
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(),
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(
688 base::Bind(&GCMDriverDesktop::IOWorker::Unregister
,
689 base::Unretained(io_worker_
.get()),
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(),
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(
715 base::Bind(&GCMDriverDesktop::IOWorker::Send
,
716 base::Unretained(io_worker_
.get()),
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());
732 bool GCMDriverDesktop::IsConnected() const {
736 void GCMDriverDesktop::GetGCMStatistics(
737 const GetGCMStatisticsCallback
& callback
,
739 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
740 DCHECK(!callback
.is_null());
742 request_gcm_statistics_callback_
= callback
;
743 io_thread_
->PostTask(
745 base::Bind(&GCMDriverDesktop::IOWorker::GetGCMStatistics
,
746 base::Unretained(io_worker_
.get()),
750 void GCMDriverDesktop::SetGCMRecording(const GetGCMStatisticsCallback
& callback
,
752 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
754 request_gcm_statistics_callback_
= callback
;
755 io_thread_
->PostTask(
757 base::Bind(&GCMDriverDesktop::IOWorker::SetGCMRecording
,
758 base::Unretained(io_worker_
.get()),
762 void GCMDriverDesktop::UpdateAccountMapping(
763 const AccountMapping
& account_mapping
) {
764 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
766 io_thread_
->PostTask(
768 base::Bind(&GCMDriverDesktop::IOWorker::UpdateAccountMapping
,
769 base::Unretained(io_worker_
.get()),
773 void GCMDriverDesktop::RemoveAccountMapping(const std::string
& account_id
) {
774 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
776 io_thread_
->PostTask(
778 base::Bind(&GCMDriverDesktop::IOWorker::RemoveAccountMapping
,
779 base::Unretained(io_worker_
.get()),
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(
794 base::Bind(&GCMDriverDesktop::IOWorker::SetLastTokenFetchTime
,
795 base::Unretained(io_worker_
.get()),
799 InstanceIDHandler
* GCMDriverDesktop::GetInstanceIDHandler() {
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
);
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
);
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(),
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.
859 io_thread_
->PostTask(
861 base::Bind(&GCMDriverDesktop::IOWorker::GetToken
,
862 base::Unretained(io_worker_
.get()),
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
);
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
);
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(),
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(
916 base::Bind(&GCMDriverDesktop::IOWorker::DeleteToken
,
917 base::Unretained(io_worker_
.get()),
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
)
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(),
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(
953 base::Bind(&GCMDriverDesktop::IOWorker::AddInstanceIDData
,
954 base::Unretained(io_worker_
.get()),
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
)
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(),
976 DoRemoveInstanceIDData(app_id
);
979 void GCMDriverDesktop::DoRemoveInstanceIDData(const std::string
& app_id
) {
980 io_thread_
->PostTask(
982 base::Bind(&GCMDriverDesktop::IOWorker::RemoveInstanceIDData
,
983 base::Unretained(io_worker_
.get()),
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());
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(),
1010 DoGetInstanceIDData(app_id
);
1013 void GCMDriverDesktop::DoGetInstanceIDData(const std::string
& app_id
) {
1014 io_thread_
->PostTask(
1016 base::Bind(&GCMDriverDesktop::IOWorker::GetInstanceIDData
,
1017 base::Unretained(io_worker_
.get()),
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.
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.
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_
)
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_
));
1081 // The GCMClient is ready so we can go ahead and post this task to the
1083 io_thread_
->PostTask(
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
,
1092 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
1094 // The GCM service has not been initialized.
1095 if (!delayed_task_controller_
)
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
));
1106 io_thread_
->PostTask(
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_
)
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
));
1127 io_thread_
->PostTask(
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(
1141 base::Bind(&GCMDriverDesktop::IOWorker::SetAccountTokens
,
1142 base::Unretained(io_worker_
.get()),
1146 GCMClient::Result
GCMDriverDesktop::EnsureStarted(
1147 GCMClient::StartMode start_mode
) {
1148 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
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();
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(
1171 base::Bind(&GCMDriverDesktop::IOWorker::Start
,
1172 base::Unretained(io_worker_
.get()),
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();
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.
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.
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.
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.
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());
1260 // Drop the event if the service has been stopped.
1264 FOR_EACH_OBSERVER(GCMConnectionObserver
,
1265 connection_observer_list_
,
1266 OnConnected(ip_endpoint
));
1269 void GCMDriverDesktop::OnDisconnected() {
1270 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
1274 // Drop the event if the service has been stopped.
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
))
1296 if (base::get
<0>(a
) > base::get
<0>(b
))
1299 if (base::get
<1>(a
) < base::get
<1>(b
))
1301 if (base::get
<1>(a
) > base::get
<1>(b
))
1304 return base::get
<2>(a
) < base::get
<2>(b
);