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.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/system_encryptor.h"
24 #include "google_apis/gcm/engine/account_mapping.h"
25 #include "net/base/ip_endpoint.h"
26 #include "net/url_request/url_request_context_getter.h"
28 #if defined(OS_CHROMEOS)
29 #include "components/timers/alarm_timer_chromeos.h"
34 class GCMDriverDesktop::IOWorker
: public GCMClient::Delegate
{
36 // Called on UI thread.
37 IOWorker(const scoped_refptr
<base::SequencedTaskRunner
>& ui_thread
,
38 const scoped_refptr
<base::SequencedTaskRunner
>& io_thread
);
41 // Overridden from GCMClient::Delegate:
42 // Called on IO thread.
43 void OnRegisterFinished(const std::string
& app_id
,
44 const std::string
& registration_id
,
45 GCMClient::Result result
) override
;
46 void OnUnregisterFinished(const std::string
& app_id
,
47 GCMClient::Result result
) override
;
48 void OnSendFinished(const std::string
& app_id
,
49 const std::string
& message_id
,
50 GCMClient::Result result
) override
;
51 void OnMessageReceived(const std::string
& app_id
,
52 const GCMClient::IncomingMessage
& message
) override
;
53 void OnMessagesDeleted(const std::string
& app_id
) override
;
54 void OnMessageSendError(
55 const std::string
& app_id
,
56 const GCMClient::SendErrorDetails
& send_error_details
) override
;
57 void OnSendAcknowledged(const std::string
& app_id
,
58 const std::string
& message_id
) override
;
59 void OnGCMReady(const std::vector
<AccountMapping
>& account_mappings
,
60 const base::Time
& last_token_fetch_time
) override
;
61 void OnActivityRecorded() override
;
62 void OnConnected(const net::IPEndPoint
& ip_endpoint
) override
;
63 void OnDisconnected() override
;
65 // Called on IO thread.
67 scoped_ptr
<GCMClientFactory
> gcm_client_factory
,
68 const GCMClient::ChromeBuildInfo
& chrome_build_info
,
69 const base::FilePath
& store_path
,
70 const scoped_refptr
<net::URLRequestContextGetter
>& request_context
,
71 const scoped_refptr
<base::SequencedTaskRunner
> blocking_task_runner
);
72 void Start(GCMClient::StartMode start_mode
,
73 const base::WeakPtr
<GCMDriverDesktop
>& service
);
75 void Register(const std::string
& app_id
,
76 const std::vector
<std::string
>& sender_ids
);
77 void Unregister(const std::string
& app_id
);
78 void Send(const std::string
& app_id
,
79 const std::string
& receiver_id
,
80 const GCMClient::OutgoingMessage
& message
);
81 void GetGCMStatistics(bool clear_logs
);
82 void SetGCMRecording(bool recording
);
84 void SetAccountTokens(
85 const std::vector
<GCMClient::AccountTokenInfo
>& account_tokens
);
86 void UpdateAccountMapping(const AccountMapping
& account_mapping
);
87 void RemoveAccountMapping(const std::string
& account_id
);
88 void SetLastTokenFetchTime(const base::Time
& time
);
89 void WakeFromSuspendForHeartbeat(bool wake
);
91 // For testing purpose. Can be called from UI thread. Use with care.
92 GCMClient
* gcm_client_for_testing() const { return gcm_client_
.get(); }
95 scoped_refptr
<base::SequencedTaskRunner
> ui_thread_
;
96 scoped_refptr
<base::SequencedTaskRunner
> io_thread_
;
98 base::WeakPtr
<GCMDriverDesktop
> service_
;
100 scoped_ptr
<GCMClient
> gcm_client_
;
102 DISALLOW_COPY_AND_ASSIGN(IOWorker
);
105 GCMDriverDesktop::IOWorker::IOWorker(
106 const scoped_refptr
<base::SequencedTaskRunner
>& ui_thread
,
107 const scoped_refptr
<base::SequencedTaskRunner
>& io_thread
)
108 : ui_thread_(ui_thread
),
109 io_thread_(io_thread
) {
110 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
113 GCMDriverDesktop::IOWorker::~IOWorker() {
114 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
117 void GCMDriverDesktop::IOWorker::Initialize(
118 scoped_ptr
<GCMClientFactory
> gcm_client_factory
,
119 const GCMClient::ChromeBuildInfo
& chrome_build_info
,
120 const base::FilePath
& store_path
,
121 const scoped_refptr
<net::URLRequestContextGetter
>& request_context
,
122 const scoped_refptr
<base::SequencedTaskRunner
> blocking_task_runner
) {
123 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
124 tracked_objects::ScopedTracker
tracking_profile(
125 FROM_HERE_WITH_EXPLICIT_FUNCTION(
126 "477117 GCMDriverDesktop::IOWorker::Initialize"));
127 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
129 gcm_client_
= gcm_client_factory
->BuildInstance();
131 gcm_client_
->Initialize(chrome_build_info
,
133 blocking_task_runner
,
135 make_scoped_ptr
<Encryptor
>(new SystemEncryptor
),
139 void GCMDriverDesktop::IOWorker::OnRegisterFinished(
140 const std::string
& app_id
,
141 const std::string
& registration_id
,
142 GCMClient::Result result
) {
143 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
145 ui_thread_
->PostTask(
147 base::Bind(&GCMDriverDesktop::RegisterFinished
, service_
, app_id
,
148 registration_id
, result
));
151 void GCMDriverDesktop::IOWorker::OnUnregisterFinished(
152 const std::string
& app_id
,
153 GCMClient::Result result
) {
154 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
156 ui_thread_
->PostTask(FROM_HERE
,
157 base::Bind(&GCMDriverDesktop::UnregisterFinished
,
163 void GCMDriverDesktop::IOWorker::OnSendFinished(const std::string
& app_id
,
164 const std::string
& message_id
,
165 GCMClient::Result result
) {
166 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
168 ui_thread_
->PostTask(
170 base::Bind(&GCMDriverDesktop::SendFinished
, service_
, app_id
, message_id
,
174 void GCMDriverDesktop::IOWorker::OnMessageReceived(
175 const std::string
& app_id
,
176 const GCMClient::IncomingMessage
& message
) {
177 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
179 ui_thread_
->PostTask(
181 base::Bind(&GCMDriverDesktop::MessageReceived
,
187 void GCMDriverDesktop::IOWorker::OnMessagesDeleted(const std::string
& app_id
) {
188 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
190 ui_thread_
->PostTask(
192 base::Bind(&GCMDriverDesktop::MessagesDeleted
, service_
, app_id
));
195 void GCMDriverDesktop::IOWorker::OnMessageSendError(
196 const std::string
& app_id
,
197 const GCMClient::SendErrorDetails
& send_error_details
) {
198 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
200 ui_thread_
->PostTask(
202 base::Bind(&GCMDriverDesktop::MessageSendError
, service_
, app_id
,
203 send_error_details
));
206 void GCMDriverDesktop::IOWorker::OnSendAcknowledged(
207 const std::string
& app_id
,
208 const std::string
& message_id
) {
209 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
211 ui_thread_
->PostTask(
214 &GCMDriverDesktop::SendAcknowledged
, service_
, app_id
, message_id
));
217 void GCMDriverDesktop::IOWorker::OnGCMReady(
218 const std::vector
<AccountMapping
>& account_mappings
,
219 const base::Time
& last_token_fetch_time
) {
220 ui_thread_
->PostTask(FROM_HERE
,
221 base::Bind(&GCMDriverDesktop::GCMClientReady
,
224 last_token_fetch_time
));
227 void GCMDriverDesktop::IOWorker::OnActivityRecorded() {
228 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
229 // When an activity is recorded, get all the stats and refresh the UI of
230 // gcm-internals page.
231 GetGCMStatistics(false);
234 void GCMDriverDesktop::IOWorker::OnConnected(
235 const net::IPEndPoint
& ip_endpoint
) {
236 ui_thread_
->PostTask(FROM_HERE
,
237 base::Bind(&GCMDriverDesktop::OnConnected
,
242 void GCMDriverDesktop::IOWorker::OnDisconnected() {
243 ui_thread_
->PostTask(FROM_HERE
,
244 base::Bind(&GCMDriverDesktop::OnDisconnected
, service_
));
247 void GCMDriverDesktop::IOWorker::Start(
248 GCMClient::StartMode start_mode
,
249 const base::WeakPtr
<GCMDriverDesktop
>& service
) {
250 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
253 gcm_client_
->Start(start_mode
);
256 void GCMDriverDesktop::IOWorker::Stop() {
257 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
262 void GCMDriverDesktop::IOWorker::Register(
263 const std::string
& app_id
,
264 const std::vector
<std::string
>& sender_ids
) {
265 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
267 gcm_client_
->Register(app_id
, sender_ids
);
270 void GCMDriverDesktop::IOWorker::Unregister(const std::string
& app_id
) {
271 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
273 gcm_client_
->Unregister(app_id
);
276 void GCMDriverDesktop::IOWorker::Send(
277 const std::string
& app_id
,
278 const std::string
& receiver_id
,
279 const GCMClient::OutgoingMessage
& message
) {
280 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
282 gcm_client_
->Send(app_id
, receiver_id
, message
);
285 void GCMDriverDesktop::IOWorker::GetGCMStatistics(bool clear_logs
) {
286 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
287 gcm::GCMClient::GCMStatistics stats
;
289 if (gcm_client_
.get()) {
291 gcm_client_
->ClearActivityLogs();
292 stats
= gcm_client_
->GetStatistics();
295 ui_thread_
->PostTask(
297 base::Bind(&GCMDriverDesktop::GetGCMStatisticsFinished
, service_
, stats
));
300 void GCMDriverDesktop::IOWorker::SetGCMRecording(bool recording
) {
301 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
302 gcm::GCMClient::GCMStatistics stats
;
304 if (gcm_client_
.get()) {
305 gcm_client_
->SetRecording(recording
);
306 stats
= gcm_client_
->GetStatistics();
307 stats
.gcm_client_created
= true;
310 ui_thread_
->PostTask(
312 base::Bind(&GCMDriverDesktop::GetGCMStatisticsFinished
, service_
, stats
));
315 void GCMDriverDesktop::IOWorker::SetAccountTokens(
316 const std::vector
<GCMClient::AccountTokenInfo
>& account_tokens
) {
317 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
319 if (gcm_client_
.get())
320 gcm_client_
->SetAccountTokens(account_tokens
);
323 void GCMDriverDesktop::IOWorker::UpdateAccountMapping(
324 const AccountMapping
& account_mapping
) {
325 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
327 if (gcm_client_
.get())
328 gcm_client_
->UpdateAccountMapping(account_mapping
);
331 void GCMDriverDesktop::IOWorker::RemoveAccountMapping(
332 const std::string
& account_id
) {
333 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
335 if (gcm_client_
.get())
336 gcm_client_
->RemoveAccountMapping(account_id
);
339 void GCMDriverDesktop::IOWorker::SetLastTokenFetchTime(const base::Time
& time
) {
340 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
342 if (gcm_client_
.get())
343 gcm_client_
->SetLastTokenFetchTime(time
);
346 void GCMDriverDesktop::IOWorker::WakeFromSuspendForHeartbeat(bool wake
) {
347 #if defined(OS_CHROMEOS)
348 DCHECK(io_thread_
->RunsTasksOnCurrentThread());
350 scoped_ptr
<base::Timer
> timer
;
352 timer
.reset(new timers::SimpleAlarmTimer());
354 timer
.reset(new base::Timer(true, false));
356 gcm_client_
->UpdateHeartbeatTimer(timer
.Pass());
360 GCMDriverDesktop::GCMDriverDesktop(
361 scoped_ptr
<GCMClientFactory
> gcm_client_factory
,
362 const GCMClient::ChromeBuildInfo
& chrome_build_info
,
363 const std::string
& channel_status_request_url
,
364 const std::string
& user_agent
,
366 const base::FilePath
& store_path
,
367 const scoped_refptr
<net::URLRequestContextGetter
>& request_context
,
368 const scoped_refptr
<base::SequencedTaskRunner
>& ui_thread
,
369 const scoped_refptr
<base::SequencedTaskRunner
>& io_thread
,
370 const scoped_refptr
<base::SequencedTaskRunner
>& blocking_task_runner
)
371 : gcm_channel_status_syncer_(
372 new GCMChannelStatusSyncer(this,
374 channel_status_request_url
,
381 account_mapper_(new GCMAccountMapper(this)),
382 // Setting to max, to make sure it does not prompt for token reporting
383 // Before reading a reasonable value from the DB, which might be never,
384 // in which case the fetching will be triggered.
385 last_token_fetch_time_(base::Time::Max()),
386 ui_thread_(ui_thread
),
387 io_thread_(io_thread
),
388 wake_from_suspend_enabled_(false),
389 weak_ptr_factory_(this) {
390 gcm_enabled_
= gcm_channel_status_syncer_
->gcm_enabled();
392 // Create and initialize the GCMClient. Note that this does not initiate the
394 io_worker_
.reset(new IOWorker(ui_thread
, io_thread
));
395 io_thread_
->PostTask(
397 base::Bind(&GCMDriverDesktop::IOWorker::Initialize
,
398 base::Unretained(io_worker_
.get()),
399 base::Passed(&gcm_client_factory
),
403 blocking_task_runner
));
406 GCMDriverDesktop::~GCMDriverDesktop() {
409 void GCMDriverDesktop::Shutdown() {
410 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
413 GCMDriver::Shutdown();
415 // Dispose the syncer in order to release the reference to
416 // URLRequestContextGetter that needs to be done before IOThread gets
418 gcm_channel_status_syncer_
.reset();
420 io_thread_
->DeleteSoon(FROM_HERE
, io_worker_
.release());
423 void GCMDriverDesktop::OnSignedIn() {
427 void GCMDriverDesktop::OnSignedOut() {
431 void GCMDriverDesktop::AddAppHandler(const std::string
& app_id
,
432 GCMAppHandler
* handler
) {
433 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
434 GCMDriver::AddAppHandler(app_id
, handler
);
436 // Ensures that the GCM service is started when there is an interest.
437 EnsureStarted(GCMClient::DELAYED_START
);
440 void GCMDriverDesktop::RemoveAppHandler(const std::string
& app_id
) {
441 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
442 GCMDriver::RemoveAppHandler(app_id
);
444 // Stops the GCM service when no app intends to consume it. Stop function will
445 // remove the last app handler - account mapper.
446 if (app_handlers().size() == 1) {
448 gcm_channel_status_syncer_
->Stop();
452 void GCMDriverDesktop::AddConnectionObserver(GCMConnectionObserver
* observer
) {
453 connection_observer_list_
.AddObserver(observer
);
456 void GCMDriverDesktop::RemoveConnectionObserver(
457 GCMConnectionObserver
* observer
) {
458 connection_observer_list_
.RemoveObserver(observer
);
461 void GCMDriverDesktop::Enable() {
462 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
468 EnsureStarted(GCMClient::DELAYED_START
);
471 void GCMDriverDesktop::Disable() {
472 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
476 gcm_enabled_
= false;
481 void GCMDriverDesktop::Stop() {
482 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
484 // No need to stop GCM service if not started yet.
488 account_mapper_
->ShutdownHandler();
489 GCMDriver::RemoveAppHandler(kGCMAccountMapperAppId
);
493 io_thread_
->PostTask(
495 base::Bind(&GCMDriverDesktop::IOWorker::Stop
,
496 base::Unretained(io_worker_
.get())));
499 void GCMDriverDesktop::RegisterImpl(
500 const std::string
& app_id
,
501 const std::vector
<std::string
>& sender_ids
) {
502 // Delay the register operation until GCMClient is ready.
503 if (!delayed_task_controller_
->CanRunTaskWithoutDelay()) {
504 delayed_task_controller_
->AddTask(base::Bind(&GCMDriverDesktop::DoRegister
,
505 weak_ptr_factory_
.GetWeakPtr(),
511 DoRegister(app_id
, sender_ids
);
514 void GCMDriverDesktop::DoRegister(const std::string
& app_id
,
515 const std::vector
<std::string
>& sender_ids
) {
516 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
517 if (!HasRegisterCallback(app_id
)) {
518 // The callback could have been removed when the app is uninstalled.
522 io_thread_
->PostTask(
524 base::Bind(&GCMDriverDesktop::IOWorker::Register
,
525 base::Unretained(io_worker_
.get()),
530 void GCMDriverDesktop::UnregisterImpl(const std::string
& app_id
) {
531 // Delay the unregister operation until GCMClient is ready.
532 if (!delayed_task_controller_
->CanRunTaskWithoutDelay()) {
533 delayed_task_controller_
->AddTask(
534 base::Bind(&GCMDriverDesktop::DoUnregister
,
535 weak_ptr_factory_
.GetWeakPtr(),
540 DoUnregister(app_id
);
543 void GCMDriverDesktop::DoUnregister(const std::string
& app_id
) {
544 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
546 // Ask the server to unregister it. There could be a small chance that the
547 // unregister request fails. If this occurs, it does not bring any harm since
548 // we simply reject the messages/events received from the server.
549 io_thread_
->PostTask(
551 base::Bind(&GCMDriverDesktop::IOWorker::Unregister
,
552 base::Unretained(io_worker_
.get()),
556 void GCMDriverDesktop::SendImpl(const std::string
& app_id
,
557 const std::string
& receiver_id
,
558 const GCMClient::OutgoingMessage
& message
) {
559 // Delay the send operation until all GCMClient is ready.
560 if (!delayed_task_controller_
->CanRunTaskWithoutDelay()) {
561 delayed_task_controller_
->AddTask(base::Bind(&GCMDriverDesktop::DoSend
,
562 weak_ptr_factory_
.GetWeakPtr(),
569 DoSend(app_id
, receiver_id
, message
);
572 void GCMDriverDesktop::DoSend(const std::string
& app_id
,
573 const std::string
& receiver_id
,
574 const GCMClient::OutgoingMessage
& message
) {
575 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
576 io_thread_
->PostTask(
578 base::Bind(&GCMDriverDesktop::IOWorker::Send
,
579 base::Unretained(io_worker_
.get()),
585 GCMClient
* GCMDriverDesktop::GetGCMClientForTesting() const {
586 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
587 return io_worker_
? io_worker_
->gcm_client_for_testing() : NULL
;
590 bool GCMDriverDesktop::IsStarted() const {
591 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
595 bool GCMDriverDesktop::IsConnected() const {
599 void GCMDriverDesktop::GetGCMStatistics(
600 const GetGCMStatisticsCallback
& callback
,
602 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
603 DCHECK(!callback
.is_null());
605 request_gcm_statistics_callback_
= callback
;
606 io_thread_
->PostTask(
608 base::Bind(&GCMDriverDesktop::IOWorker::GetGCMStatistics
,
609 base::Unretained(io_worker_
.get()),
613 void GCMDriverDesktop::SetGCMRecording(const GetGCMStatisticsCallback
& callback
,
615 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
617 request_gcm_statistics_callback_
= callback
;
618 io_thread_
->PostTask(
620 base::Bind(&GCMDriverDesktop::IOWorker::SetGCMRecording
,
621 base::Unretained(io_worker_
.get()),
625 void GCMDriverDesktop::UpdateAccountMapping(
626 const AccountMapping
& account_mapping
) {
627 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
629 io_thread_
->PostTask(
631 base::Bind(&GCMDriverDesktop::IOWorker::UpdateAccountMapping
,
632 base::Unretained(io_worker_
.get()),
636 void GCMDriverDesktop::RemoveAccountMapping(const std::string
& account_id
) {
637 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
639 io_thread_
->PostTask(
641 base::Bind(&GCMDriverDesktop::IOWorker::RemoveAccountMapping
,
642 base::Unretained(io_worker_
.get()),
646 base::Time
GCMDriverDesktop::GetLastTokenFetchTime() {
647 return last_token_fetch_time_
;
650 void GCMDriverDesktop::SetLastTokenFetchTime(const base::Time
& time
) {
651 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
653 last_token_fetch_time_
= time
;
655 io_thread_
->PostTask(
657 base::Bind(&GCMDriverDesktop::IOWorker::SetLastTokenFetchTime
,
658 base::Unretained(io_worker_
.get()),
662 void GCMDriverDesktop::WakeFromSuspendForHeartbeat(bool wake
) {
663 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
665 wake_from_suspend_enabled_
= wake
;
667 // The GCM service has not been initialized.
668 if (!delayed_task_controller_
)
671 if (!delayed_task_controller_
->CanRunTaskWithoutDelay()) {
672 // The GCM service was initialized but has not started yet.
673 delayed_task_controller_
->AddTask(
674 base::Bind(&GCMDriverDesktop::WakeFromSuspendForHeartbeat
,
675 weak_ptr_factory_
.GetWeakPtr(),
676 wake_from_suspend_enabled_
));
680 // The GCMClient is ready so we can go ahead and post this task to the
682 io_thread_
->PostTask(
684 base::Bind(&GCMDriverDesktop::IOWorker::WakeFromSuspendForHeartbeat
,
685 base::Unretained(io_worker_
.get()),
686 wake_from_suspend_enabled_
));
689 void GCMDriverDesktop::SetAccountTokens(
690 const std::vector
<GCMClient::AccountTokenInfo
>& account_tokens
) {
691 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
693 account_mapper_
->SetAccountTokens(account_tokens
);
695 io_thread_
->PostTask(
697 base::Bind(&GCMDriverDesktop::IOWorker::SetAccountTokens
,
698 base::Unretained(io_worker_
.get()),
702 GCMClient::Result
GCMDriverDesktop::EnsureStarted(
703 GCMClient::StartMode start_mode
) {
704 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
707 return GCMClient::SUCCESS
;
709 // Have any app requested the service?
710 if (app_handlers().empty())
711 return GCMClient::UNKNOWN_ERROR
;
713 // Polling for channel status should be invoked when GCM is being requested,
714 // no matter whether GCM is enabled or nor.
715 gcm_channel_status_syncer_
->EnsureStarted();
718 return GCMClient::GCM_DISABLED
;
720 if (!delayed_task_controller_
)
721 delayed_task_controller_
.reset(new GCMDelayedTaskController
);
723 // Note that we need to pass weak pointer again since the existing weak
724 // pointer in IOWorker might have been invalidated when GCM is stopped.
725 io_thread_
->PostTask(
727 base::Bind(&GCMDriverDesktop::IOWorker::Start
,
728 base::Unretained(io_worker_
.get()),
730 weak_ptr_factory_
.GetWeakPtr()));
732 return GCMClient::SUCCESS
;
735 void GCMDriverDesktop::RemoveCachedData() {
736 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
737 // Remove all the queued tasks since they no longer make sense after
738 // GCM service is stopped.
739 weak_ptr_factory_
.InvalidateWeakPtrs();
741 gcm_started_
= false;
742 delayed_task_controller_
.reset();
746 void GCMDriverDesktop::MessageReceived(
747 const std::string
& app_id
,
748 const GCMClient::IncomingMessage
& message
) {
749 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
751 // Drop the event if the service has been stopped.
755 GetAppHandler(app_id
)->OnMessage(app_id
, message
);
758 void GCMDriverDesktop::MessagesDeleted(const std::string
& app_id
) {
759 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
761 // Drop the event if the service has been stopped.
765 GetAppHandler(app_id
)->OnMessagesDeleted(app_id
);
768 void GCMDriverDesktop::MessageSendError(
769 const std::string
& app_id
,
770 const GCMClient::SendErrorDetails
& send_error_details
) {
771 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
773 // Drop the event if the service has been stopped.
777 GetAppHandler(app_id
)->OnSendError(app_id
, send_error_details
);
780 void GCMDriverDesktop::SendAcknowledged(const std::string
& app_id
,
781 const std::string
& message_id
) {
782 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
784 // Drop the event if the service has been stopped.
788 GetAppHandler(app_id
)->OnSendAcknowledged(app_id
, message_id
);
791 void GCMDriverDesktop::GCMClientReady(
792 const std::vector
<AccountMapping
>& account_mappings
,
793 const base::Time
& last_token_fetch_time
) {
794 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
796 UMA_HISTOGRAM_BOOLEAN("GCM.UserSignedIn", signed_in_
);
799 if (wake_from_suspend_enabled_
)
800 WakeFromSuspendForHeartbeat(wake_from_suspend_enabled_
);
802 last_token_fetch_time_
= last_token_fetch_time
;
804 GCMDriver::AddAppHandler(kGCMAccountMapperAppId
, account_mapper_
.get());
805 account_mapper_
->Initialize(account_mappings
,
806 base::Bind(&GCMDriverDesktop::MessageReceived
,
807 weak_ptr_factory_
.GetWeakPtr()));
809 delayed_task_controller_
->SetReady();
812 void GCMDriverDesktop::OnConnected(const net::IPEndPoint
& ip_endpoint
) {
813 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
817 // Drop the event if the service has been stopped.
821 FOR_EACH_OBSERVER(GCMConnectionObserver
,
822 connection_observer_list_
,
823 OnConnected(ip_endpoint
));
826 void GCMDriverDesktop::OnDisconnected() {
827 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
831 // Drop the event if the service has been stopped.
836 GCMConnectionObserver
, connection_observer_list_
, OnDisconnected());
839 void GCMDriverDesktop::GetGCMStatisticsFinished(
840 const GCMClient::GCMStatistics
& stats
) {
841 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
843 // Normally request_gcm_statistics_callback_ would not be null.
844 if (!request_gcm_statistics_callback_
.is_null())
845 request_gcm_statistics_callback_
.Run(stats
);
847 LOG(WARNING
) << "request_gcm_statistics_callback_ is NULL.";