Revert of Componentize TemplateURLService (https://codereview.chromium.org/367023002/)
[chromium-blink-merge.git] / components / gcm_driver / gcm_driver_desktop.cc
blob61f9cb122998ac50b7756d9f74e4d22085bec9ab
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/sequenced_task_runner.h"
15 #include "base/threading/sequenced_worker_pool.h"
16 #include "components/gcm_driver/gcm_app_handler.h"
17 #include "components/gcm_driver/gcm_client_factory.h"
18 #include "components/gcm_driver/system_encryptor.h"
19 #include "net/base/ip_endpoint.h"
20 #include "net/url_request/url_request_context_getter.h"
22 namespace gcm {
24 namespace {
26 // Empty string is reserved for the default app handler.
27 const char kDefaultAppHandler[] = "";
29 } // namespace
31 // Helper class to save tasks to run until we're ready to execute them.
32 class GCMDriverDesktop::DelayedTaskController {
33 public:
34 DelayedTaskController();
35 ~DelayedTaskController();
37 // Adds a task that will be invoked once we're ready.
38 void AddTask(const base::Closure& task);
40 // Sets ready status. It is ready only when check-in is completed and
41 // the GCMClient is fully initialized.
42 void SetReady();
44 // Returns true if it is ready to perform tasks.
45 bool CanRunTaskWithoutDelay() const;
47 private:
48 void RunTasks();
50 // Flag that indicates that GCM is ready.
51 bool ready_;
53 std::vector<base::Closure> delayed_tasks_;
55 DISALLOW_COPY_AND_ASSIGN(DelayedTaskController);
58 GCMDriverDesktop::DelayedTaskController::DelayedTaskController()
59 : ready_(false) {
62 GCMDriverDesktop::DelayedTaskController::~DelayedTaskController() {
65 void GCMDriverDesktop::DelayedTaskController::AddTask(
66 const base::Closure& task) {
67 delayed_tasks_.push_back(task);
70 void GCMDriverDesktop::DelayedTaskController::SetReady() {
71 ready_ = true;
72 RunTasks();
75 bool GCMDriverDesktop::DelayedTaskController::CanRunTaskWithoutDelay() const {
76 return ready_;
79 void GCMDriverDesktop::DelayedTaskController::RunTasks() {
80 DCHECK(ready_);
82 for (size_t i = 0; i < delayed_tasks_.size(); ++i)
83 delayed_tasks_[i].Run();
84 delayed_tasks_.clear();
87 class GCMDriverDesktop::IOWorker : public GCMClient::Delegate {
88 public:
89 // Called on UI thread.
90 IOWorker(const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
91 const scoped_refptr<base::SequencedTaskRunner>& io_thread);
92 virtual ~IOWorker();
94 // Overridden from GCMClient::Delegate:
95 // Called on IO thread.
96 virtual void OnRegisterFinished(const std::string& app_id,
97 const std::string& registration_id,
98 GCMClient::Result result) OVERRIDE;
99 virtual void OnUnregisterFinished(const std::string& app_id,
100 GCMClient::Result result) OVERRIDE;
101 virtual void OnSendFinished(const std::string& app_id,
102 const std::string& message_id,
103 GCMClient::Result result) OVERRIDE;
104 virtual void OnMessageReceived(
105 const std::string& app_id,
106 const GCMClient::IncomingMessage& message) OVERRIDE;
107 virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE;
108 virtual void OnMessageSendError(
109 const std::string& app_id,
110 const GCMClient::SendErrorDetails& send_error_details) OVERRIDE;
111 virtual void OnGCMReady() OVERRIDE;
112 virtual void OnActivityRecorded() OVERRIDE;
113 virtual void OnConnected(const net::IPEndPoint& ip_endpoint) OVERRIDE;
114 virtual void OnDisconnected() OVERRIDE;
116 // Called on IO thread.
117 void 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 void Start(const base::WeakPtr<GCMDriverDesktop>& service);
124 void Stop();
125 void CheckOut();
126 void Register(const std::string& app_id,
127 const std::vector<std::string>& sender_ids);
128 void Unregister(const std::string& app_id);
129 void Send(const std::string& app_id,
130 const std::string& receiver_id,
131 const GCMClient::OutgoingMessage& message);
132 void GetGCMStatistics(bool clear_logs);
133 void SetGCMRecording(bool recording);
135 // For testing purpose. Can be called from UI thread. Use with care.
136 GCMClient* gcm_client_for_testing() const { return gcm_client_.get(); }
138 private:
139 scoped_refptr<base::SequencedTaskRunner> ui_thread_;
140 scoped_refptr<base::SequencedTaskRunner> io_thread_;
142 base::WeakPtr<GCMDriverDesktop> service_;
144 scoped_ptr<GCMClient> gcm_client_;
146 DISALLOW_COPY_AND_ASSIGN(IOWorker);
149 GCMDriverDesktop::IOWorker::IOWorker(
150 const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
151 const scoped_refptr<base::SequencedTaskRunner>& io_thread)
152 : ui_thread_(ui_thread),
153 io_thread_(io_thread) {
154 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
157 GCMDriverDesktop::IOWorker::~IOWorker() {
158 DCHECK(io_thread_->RunsTasksOnCurrentThread());
161 void GCMDriverDesktop::IOWorker::Initialize(
162 scoped_ptr<GCMClientFactory> gcm_client_factory,
163 const GCMClient::ChromeBuildInfo& chrome_build_info,
164 const base::FilePath& store_path,
165 const scoped_refptr<net::URLRequestContextGetter>& request_context,
166 const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) {
167 DCHECK(io_thread_->RunsTasksOnCurrentThread());
169 gcm_client_ = gcm_client_factory->BuildInstance();
171 gcm_client_->Initialize(chrome_build_info,
172 store_path,
173 blocking_task_runner,
174 request_context,
175 make_scoped_ptr<Encryptor>(new SystemEncryptor),
176 this);
179 void GCMDriverDesktop::IOWorker::OnRegisterFinished(
180 const std::string& app_id,
181 const std::string& registration_id,
182 GCMClient::Result result) {
183 DCHECK(io_thread_->RunsTasksOnCurrentThread());
185 ui_thread_->PostTask(
186 FROM_HERE,
187 base::Bind(&GCMDriverDesktop::RegisterFinished, service_, app_id,
188 registration_id, result));
191 void GCMDriverDesktop::IOWorker::OnUnregisterFinished(
192 const std::string& app_id,
193 GCMClient::Result result) {
194 DCHECK(io_thread_->RunsTasksOnCurrentThread());
196 ui_thread_->PostTask(FROM_HERE,
197 base::Bind(&GCMDriverDesktop::UnregisterFinished,
198 service_,
199 app_id,
200 result));
203 void GCMDriverDesktop::IOWorker::OnSendFinished(const std::string& app_id,
204 const std::string& message_id,
205 GCMClient::Result result) {
206 DCHECK(io_thread_->RunsTasksOnCurrentThread());
208 ui_thread_->PostTask(
209 FROM_HERE,
210 base::Bind(&GCMDriverDesktop::SendFinished, service_, app_id, message_id,
211 result));
214 void GCMDriverDesktop::IOWorker::OnMessageReceived(
215 const std::string& app_id,
216 const GCMClient::IncomingMessage& message) {
217 DCHECK(io_thread_->RunsTasksOnCurrentThread());
219 ui_thread_->PostTask(
220 FROM_HERE,
221 base::Bind(&GCMDriverDesktop::MessageReceived,
222 service_,
223 app_id,
224 message));
227 void GCMDriverDesktop::IOWorker::OnMessagesDeleted(const std::string& app_id) {
228 DCHECK(io_thread_->RunsTasksOnCurrentThread());
230 ui_thread_->PostTask(
231 FROM_HERE,
232 base::Bind(&GCMDriverDesktop::MessagesDeleted, service_, app_id));
235 void GCMDriverDesktop::IOWorker::OnMessageSendError(
236 const std::string& app_id,
237 const GCMClient::SendErrorDetails& send_error_details) {
238 DCHECK(io_thread_->RunsTasksOnCurrentThread());
240 ui_thread_->PostTask(
241 FROM_HERE,
242 base::Bind(&GCMDriverDesktop::MessageSendError, service_, app_id,
243 send_error_details));
246 void GCMDriverDesktop::IOWorker::OnGCMReady() {
247 ui_thread_->PostTask(
248 FROM_HERE,
249 base::Bind(&GCMDriverDesktop::GCMClientReady, service_));
252 void GCMDriverDesktop::IOWorker::OnActivityRecorded() {
253 DCHECK(io_thread_->RunsTasksOnCurrentThread());
254 // When an activity is recorded, get all the stats and refresh the UI of
255 // gcm-internals page.
256 GetGCMStatistics(false);
259 void GCMDriverDesktop::IOWorker::OnConnected(
260 const net::IPEndPoint& ip_endpoint) {
261 ui_thread_->PostTask(FROM_HERE,
262 base::Bind(&GCMDriverDesktop::OnConnected,
263 service_,
264 ip_endpoint));
267 void GCMDriverDesktop::IOWorker::OnDisconnected() {
268 ui_thread_->PostTask(FROM_HERE,
269 base::Bind(&GCMDriverDesktop::OnDisconnected, service_));
272 void GCMDriverDesktop::IOWorker::Start(
273 const base::WeakPtr<GCMDriverDesktop>& service) {
274 DCHECK(io_thread_->RunsTasksOnCurrentThread());
276 service_ = service;
277 gcm_client_->Start();
280 void GCMDriverDesktop::IOWorker::Stop() {
281 DCHECK(io_thread_->RunsTasksOnCurrentThread());
283 gcm_client_->Stop();
286 void GCMDriverDesktop::IOWorker::CheckOut() {
287 DCHECK(io_thread_->RunsTasksOnCurrentThread());
289 gcm_client_->CheckOut();
291 // Note that we still need to keep GCMClient instance alive since the
292 // GCMDriverDesktop may check in again.
295 void GCMDriverDesktop::IOWorker::Register(
296 const std::string& app_id,
297 const std::vector<std::string>& sender_ids) {
298 DCHECK(io_thread_->RunsTasksOnCurrentThread());
300 gcm_client_->Register(app_id, sender_ids);
303 void GCMDriverDesktop::IOWorker::Unregister(const std::string& app_id) {
304 DCHECK(io_thread_->RunsTasksOnCurrentThread());
306 gcm_client_->Unregister(app_id);
309 void GCMDriverDesktop::IOWorker::Send(
310 const std::string& app_id,
311 const std::string& receiver_id,
312 const GCMClient::OutgoingMessage& message) {
313 DCHECK(io_thread_->RunsTasksOnCurrentThread());
315 gcm_client_->Send(app_id, receiver_id, message);
318 void GCMDriverDesktop::IOWorker::GetGCMStatistics(bool clear_logs) {
319 DCHECK(io_thread_->RunsTasksOnCurrentThread());
320 gcm::GCMClient::GCMStatistics stats;
322 if (gcm_client_.get()) {
323 if (clear_logs)
324 gcm_client_->ClearActivityLogs();
325 stats = gcm_client_->GetStatistics();
328 ui_thread_->PostTask(
329 FROM_HERE,
330 base::Bind(&GCMDriverDesktop::GetGCMStatisticsFinished, service_, stats));
333 void GCMDriverDesktop::IOWorker::SetGCMRecording(bool recording) {
334 DCHECK(io_thread_->RunsTasksOnCurrentThread());
335 gcm::GCMClient::GCMStatistics stats;
337 if (gcm_client_.get()) {
338 gcm_client_->SetRecording(recording);
339 stats = gcm_client_->GetStatistics();
340 stats.gcm_client_created = true;
343 ui_thread_->PostTask(
344 FROM_HERE,
345 base::Bind(&GCMDriverDesktop::GetGCMStatisticsFinished, service_, stats));
348 GCMDriverDesktop::GCMDriverDesktop(
349 scoped_ptr<GCMClientFactory> gcm_client_factory,
350 const GCMClient::ChromeBuildInfo& chrome_build_info,
351 const base::FilePath& store_path,
352 const scoped_refptr<net::URLRequestContextGetter>& request_context,
353 const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
354 const scoped_refptr<base::SequencedTaskRunner>& io_thread,
355 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
356 : signed_in_(false),
357 gcm_started_(false),
358 gcm_enabled_(true),
359 connected_(false),
360 ui_thread_(ui_thread),
361 io_thread_(io_thread),
362 weak_ptr_factory_(this) {
363 // Create and initialize the GCMClient. Note that this does not initiate the
364 // GCM check-in.
365 io_worker_.reset(new IOWorker(ui_thread, io_thread));
366 io_thread_->PostTask(
367 FROM_HERE,
368 base::Bind(&GCMDriverDesktop::IOWorker::Initialize,
369 base::Unretained(io_worker_.get()),
370 base::Passed(&gcm_client_factory),
371 chrome_build_info,
372 store_path,
373 request_context,
374 blocking_task_runner));
377 GCMDriverDesktop::~GCMDriverDesktop() {
380 void GCMDriverDesktop::Shutdown() {
381 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
382 GCMDriver::Shutdown();
383 io_thread_->DeleteSoon(FROM_HERE, io_worker_.release());
386 void GCMDriverDesktop::OnSignedIn() {
387 signed_in_ = true;
388 EnsureStarted();
391 void GCMDriverDesktop::Purge() {
392 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
394 // We still proceed with the check-out logic even if the check-in is not
395 // initiated in the current session. This will make sure that all the
396 // persisted data written previously will get purged.
397 signed_in_ = false;
398 RemoveCachedData();
400 io_thread_->PostTask(FROM_HERE,
401 base::Bind(&GCMDriverDesktop::IOWorker::CheckOut,
402 base::Unretained(io_worker_.get())));
405 void GCMDriverDesktop::AddAppHandler(const std::string& app_id,
406 GCMAppHandler* handler) {
407 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
408 GCMDriver::AddAppHandler(app_id, handler);
410 // Ensures that the GCM service is started when there is an interest.
411 EnsureStarted();
414 void GCMDriverDesktop::RemoveAppHandler(const std::string& app_id) {
415 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
416 GCMDriver::RemoveAppHandler(app_id);
418 // Stops the GCM service when no app intends to consume it.
419 if (app_handlers().empty())
420 Stop();
423 void GCMDriverDesktop::Enable() {
424 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
426 if (gcm_enabled_)
427 return;
428 gcm_enabled_ = true;
430 EnsureStarted();
433 void GCMDriverDesktop::Disable() {
434 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
436 if (!gcm_enabled_)
437 return;
438 gcm_enabled_ = false;
440 Stop();
443 void GCMDriverDesktop::Stop() {
444 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
446 // No need to stop GCM service if not started yet.
447 if (!gcm_started_)
448 return;
450 RemoveCachedData();
452 io_thread_->PostTask(
453 FROM_HERE,
454 base::Bind(&GCMDriverDesktop::IOWorker::Stop,
455 base::Unretained(io_worker_.get())));
458 void GCMDriverDesktop::RegisterImpl(
459 const std::string& app_id,
460 const std::vector<std::string>& sender_ids) {
461 // Delay the register operation until GCMClient is ready.
462 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
463 delayed_task_controller_->AddTask(base::Bind(&GCMDriverDesktop::DoRegister,
464 weak_ptr_factory_.GetWeakPtr(),
465 app_id,
466 sender_ids));
467 return;
470 DoRegister(app_id, sender_ids);
473 void GCMDriverDesktop::DoRegister(const std::string& app_id,
474 const std::vector<std::string>& sender_ids) {
475 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
476 if (!HasRegisterCallback(app_id)) {
477 // The callback could have been removed when the app is uninstalled.
478 return;
481 io_thread_->PostTask(
482 FROM_HERE,
483 base::Bind(&GCMDriverDesktop::IOWorker::Register,
484 base::Unretained(io_worker_.get()),
485 app_id,
486 sender_ids));
489 void GCMDriverDesktop::UnregisterImpl(const std::string& app_id) {
490 // Delay the unregister operation until GCMClient is ready.
491 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
492 delayed_task_controller_->AddTask(
493 base::Bind(&GCMDriverDesktop::DoUnregister,
494 weak_ptr_factory_.GetWeakPtr(),
495 app_id));
496 return;
499 DoUnregister(app_id);
502 void GCMDriverDesktop::DoUnregister(const std::string& app_id) {
503 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
505 // Ask the server to unregister it. There could be a small chance that the
506 // unregister request fails. If this occurs, it does not bring any harm since
507 // we simply reject the messages/events received from the server.
508 io_thread_->PostTask(
509 FROM_HERE,
510 base::Bind(&GCMDriverDesktop::IOWorker::Unregister,
511 base::Unretained(io_worker_.get()),
512 app_id));
515 void GCMDriverDesktop::SendImpl(const std::string& app_id,
516 const std::string& receiver_id,
517 const GCMClient::OutgoingMessage& message) {
518 // Delay the send operation until all GCMClient is ready.
519 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
520 delayed_task_controller_->AddTask(base::Bind(&GCMDriverDesktop::DoSend,
521 weak_ptr_factory_.GetWeakPtr(),
522 app_id,
523 receiver_id,
524 message));
525 return;
528 DoSend(app_id, receiver_id, message);
531 void GCMDriverDesktop::DoSend(const std::string& app_id,
532 const std::string& receiver_id,
533 const GCMClient::OutgoingMessage& message) {
534 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
535 io_thread_->PostTask(
536 FROM_HERE,
537 base::Bind(&GCMDriverDesktop::IOWorker::Send,
538 base::Unretained(io_worker_.get()),
539 app_id,
540 receiver_id,
541 message));
544 GCMClient* GCMDriverDesktop::GetGCMClientForTesting() const {
545 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
546 return io_worker_ ? io_worker_->gcm_client_for_testing() : NULL;
549 bool GCMDriverDesktop::IsStarted() const {
550 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
551 return gcm_started_;
554 bool GCMDriverDesktop::IsConnected() const {
555 return connected_;
558 void GCMDriverDesktop::GetGCMStatistics(
559 const GetGCMStatisticsCallback& callback,
560 bool clear_logs) {
561 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
562 DCHECK(!callback.is_null());
564 request_gcm_statistics_callback_ = callback;
565 io_thread_->PostTask(
566 FROM_HERE,
567 base::Bind(&GCMDriverDesktop::IOWorker::GetGCMStatistics,
568 base::Unretained(io_worker_.get()),
569 clear_logs));
572 void GCMDriverDesktop::SetGCMRecording(const GetGCMStatisticsCallback& callback,
573 bool recording) {
574 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
576 request_gcm_statistics_callback_ = callback;
577 io_thread_->PostTask(
578 FROM_HERE,
579 base::Bind(&GCMDriverDesktop::IOWorker::SetGCMRecording,
580 base::Unretained(io_worker_.get()),
581 recording));
584 GCMClient::Result GCMDriverDesktop::EnsureStarted() {
585 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
587 if (gcm_started_)
588 return GCMClient::SUCCESS;
590 if (!gcm_enabled_)
591 return GCMClient::GCM_DISABLED;
593 // Have any app requested the service?
594 if (app_handlers().empty())
595 return GCMClient::UNKNOWN_ERROR;
597 // TODO(jianli): To be removed when sign-in enforcement is dropped.
598 if (!signed_in_ && !GCMDriver::IsAllowedForAllUsers())
599 return GCMClient::NOT_SIGNED_IN;
601 DCHECK(!delayed_task_controller_);
602 delayed_task_controller_.reset(new DelayedTaskController);
604 // Note that we need to pass weak pointer again since the existing weak
605 // pointer in IOWorker might have been invalidated when check-out occurs.
606 io_thread_->PostTask(
607 FROM_HERE,
608 base::Bind(&GCMDriverDesktop::IOWorker::Start,
609 base::Unretained(io_worker_.get()),
610 weak_ptr_factory_.GetWeakPtr()));
612 gcm_started_ = true;
613 return GCMClient::SUCCESS;
616 void GCMDriverDesktop::RemoveCachedData() {
617 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
618 // Remove all the queued tasks since they no longer make sense after
619 // GCM service is stopped.
620 weak_ptr_factory_.InvalidateWeakPtrs();
622 gcm_started_ = false;
623 delayed_task_controller_.reset();
624 ClearCallbacks();
627 void GCMDriverDesktop::MessageReceived(
628 const std::string& app_id,
629 const GCMClient::IncomingMessage& message) {
630 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
632 // Drop the event if the service has been stopped.
633 if (!gcm_started_)
634 return;
636 GetAppHandler(app_id)->OnMessage(app_id, message);
639 void GCMDriverDesktop::MessagesDeleted(const std::string& app_id) {
640 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
642 // Drop the event if the service has been stopped.
643 if (!gcm_started_)
644 return;
646 GetAppHandler(app_id)->OnMessagesDeleted(app_id);
649 void GCMDriverDesktop::MessageSendError(
650 const std::string& app_id,
651 const GCMClient::SendErrorDetails& send_error_details) {
652 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
654 // Drop the event if the service has been stopped.
655 if (!gcm_started_)
656 return;
658 GetAppHandler(app_id)->OnSendError(app_id, send_error_details);
661 void GCMDriverDesktop::GCMClientReady() {
662 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
664 delayed_task_controller_->SetReady();
667 void GCMDriverDesktop::OnConnected(const net::IPEndPoint& ip_endpoint) {
668 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
670 connected_ = true;
672 // Drop the event if the service has been stopped.
673 if (!gcm_started_)
674 return;
676 const GCMAppHandlerMap& app_handler_map = app_handlers();
677 for (GCMAppHandlerMap::const_iterator iter = app_handler_map.begin();
678 iter != app_handler_map.end(); ++iter) {
679 iter->second->OnConnected(ip_endpoint);
682 GetAppHandler(kDefaultAppHandler)->OnConnected(ip_endpoint);
685 void GCMDriverDesktop::OnDisconnected() {
686 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
688 connected_ = false;
690 // Drop the event if the service has been stopped.
691 if (!gcm_started_)
692 return;
694 const GCMAppHandlerMap& app_handler_map = app_handlers();
695 for (GCMAppHandlerMap::const_iterator iter = app_handler_map.begin();
696 iter != app_handler_map.end(); ++iter) {
697 iter->second->OnDisconnected();
700 GetAppHandler(kDefaultAppHandler)->OnDisconnected();
703 void GCMDriverDesktop::GetGCMStatisticsFinished(
704 const GCMClient::GCMStatistics& stats) {
705 DCHECK(ui_thread_->RunsTasksOnCurrentThread());
707 // Normally request_gcm_statistics_callback_ would not be null.
708 if (!request_gcm_statistics_callback_.is_null())
709 request_gcm_statistics_callback_.Run(stats);
710 else
711 LOG(WARNING) << "request_gcm_statistics_callback_ is NULL.";
714 } // namespace gcm