Home | History | Annotate | Download | only in gcm_driver
      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.
      4 
      5 #include "components/gcm_driver/gcm_driver_desktop.h"
      6 
      7 #include <utility>
      8 
      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.h"
     15 #include "base/sequenced_task_runner.h"
     16 #include "base/threading/sequenced_worker_pool.h"
     17 #include "components/gcm_driver/gcm_app_handler.h"
     18 #include "components/gcm_driver/gcm_channel_status_syncer.h"
     19 #include "components/gcm_driver/gcm_client_factory.h"
     20 #include "components/gcm_driver/gcm_delayed_task_controller.h"
     21 #include "components/gcm_driver/system_encryptor.h"
     22 #include "google_apis/gcm/engine/account_mapping.h"
     23 #include "net/base/ip_endpoint.h"
     24 #include "net/url_request/url_request_context_getter.h"
     25 
     26 namespace gcm {
     27 
     28 class GCMDriverDesktop::IOWorker : public GCMClient::Delegate {
     29  public:
     30   // Called on UI thread.
     31   IOWorker(const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
     32            const scoped_refptr<base::SequencedTaskRunner>& io_thread);
     33   virtual ~IOWorker();
     34 
     35   // Overridden from GCMClient::Delegate:
     36   // Called on IO thread.
     37   virtual void OnRegisterFinished(const std::string& app_id,
     38                                   const std::string& registration_id,
     39                                   GCMClient::Result result) OVERRIDE;
     40   virtual void OnUnregisterFinished(const std::string& app_id,
     41                                     GCMClient::Result result) OVERRIDE;
     42   virtual void OnSendFinished(const std::string& app_id,
     43                               const std::string& message_id,
     44                               GCMClient::Result result) OVERRIDE;
     45   virtual void OnMessageReceived(
     46       const std::string& app_id,
     47       const GCMClient::IncomingMessage& message) OVERRIDE;
     48   virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE;
     49   virtual void OnMessageSendError(
     50       const std::string& app_id,
     51       const GCMClient::SendErrorDetails& send_error_details) OVERRIDE;
     52   virtual void OnSendAcknowledged(const std::string& app_id,
     53                                   const std::string& message_id) OVERRIDE;
     54   virtual void OnGCMReady(
     55       const std::vector<AccountMapping>& account_mappings) OVERRIDE;
     56   virtual void OnActivityRecorded() OVERRIDE;
     57   virtual void OnConnected(const net::IPEndPoint& ip_endpoint) OVERRIDE;
     58   virtual void OnDisconnected() OVERRIDE;
     59 
     60   // Called on IO thread.
     61   void Initialize(
     62       scoped_ptr<GCMClientFactory> gcm_client_factory,
     63       const GCMClient::ChromeBuildInfo& chrome_build_info,
     64       const base::FilePath& store_path,
     65       const scoped_refptr<net::URLRequestContextGetter>& request_context,
     66       const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
     67   void Start(const base::WeakPtr<GCMDriverDesktop>& service);
     68   void Stop();
     69   void CheckOut();
     70   void Register(const std::string& app_id,
     71                 const std::vector<std::string>& sender_ids);
     72   void Unregister(const std::string& app_id);
     73   void Send(const std::string& app_id,
     74             const std::string& receiver_id,
     75             const GCMClient::OutgoingMessage& message);
     76   void GetGCMStatistics(bool clear_logs);
     77   void SetGCMRecording(bool recording);
     78 
     79   void SetAccountsForCheckin(
     80       const std::map<std::string, std::string>& account_tokens);
     81   void UpdateAccountMapping(const AccountMapping& account_mapping);
     82   void RemoveAccountMapping(const std::string& account_id);
     83 
     84   // For testing purpose. Can be called from UI thread. Use with care.
     85   GCMClient* gcm_client_for_testing() const { return gcm_client_.get(); }
     86 
     87  private:
     88   scoped_refptr<base::SequencedTaskRunner> ui_thread_;
     89   scoped_refptr<base::SequencedTaskRunner> io_thread_;
     90 
     91   base::WeakPtr<GCMDriverDesktop> service_;
     92 
     93   scoped_ptr<GCMClient> gcm_client_;
     94 
     95   DISALLOW_COPY_AND_ASSIGN(IOWorker);
     96 };
     97 
     98 GCMDriverDesktop::IOWorker::IOWorker(
     99     const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
    100     const scoped_refptr<base::SequencedTaskRunner>& io_thread)
    101     : ui_thread_(ui_thread),
    102       io_thread_(io_thread) {
    103   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    104 }
    105 
    106 GCMDriverDesktop::IOWorker::~IOWorker() {
    107   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    108 }
    109 
    110 void GCMDriverDesktop::IOWorker::Initialize(
    111     scoped_ptr<GCMClientFactory> gcm_client_factory,
    112     const GCMClient::ChromeBuildInfo& chrome_build_info,
    113     const base::FilePath& store_path,
    114     const scoped_refptr<net::URLRequestContextGetter>& request_context,
    115     const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) {
    116   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    117 
    118   gcm_client_ = gcm_client_factory->BuildInstance();
    119 
    120   gcm_client_->Initialize(chrome_build_info,
    121                           store_path,
    122                           blocking_task_runner,
    123                           request_context,
    124                           make_scoped_ptr<Encryptor>(new SystemEncryptor),
    125                           this);
    126 }
    127 
    128 void GCMDriverDesktop::IOWorker::OnRegisterFinished(
    129     const std::string& app_id,
    130     const std::string& registration_id,
    131     GCMClient::Result result) {
    132   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    133 
    134   ui_thread_->PostTask(
    135       FROM_HERE,
    136       base::Bind(&GCMDriverDesktop::RegisterFinished, service_, app_id,
    137                  registration_id, result));
    138 }
    139 
    140 void GCMDriverDesktop::IOWorker::OnUnregisterFinished(
    141     const std::string& app_id,
    142     GCMClient::Result result) {
    143   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    144 
    145   ui_thread_->PostTask(FROM_HERE,
    146                        base::Bind(&GCMDriverDesktop::UnregisterFinished,
    147                                   service_,
    148                                   app_id,
    149                                   result));
    150 }
    151 
    152 void GCMDriverDesktop::IOWorker::OnSendFinished(const std::string& app_id,
    153                                                 const std::string& message_id,
    154                                                 GCMClient::Result result) {
    155   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    156 
    157   ui_thread_->PostTask(
    158       FROM_HERE,
    159       base::Bind(&GCMDriverDesktop::SendFinished, service_, app_id, message_id,
    160                  result));
    161 }
    162 
    163 void GCMDriverDesktop::IOWorker::OnMessageReceived(
    164     const std::string& app_id,
    165     const GCMClient::IncomingMessage& message) {
    166   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    167 
    168   ui_thread_->PostTask(
    169       FROM_HERE,
    170       base::Bind(&GCMDriverDesktop::MessageReceived,
    171                  service_,
    172                  app_id,
    173                  message));
    174 }
    175 
    176 void GCMDriverDesktop::IOWorker::OnMessagesDeleted(const std::string& app_id) {
    177   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    178 
    179   ui_thread_->PostTask(
    180       FROM_HERE,
    181       base::Bind(&GCMDriverDesktop::MessagesDeleted, service_, app_id));
    182 }
    183 
    184 void GCMDriverDesktop::IOWorker::OnMessageSendError(
    185     const std::string& app_id,
    186     const GCMClient::SendErrorDetails& send_error_details) {
    187   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    188 
    189   ui_thread_->PostTask(
    190       FROM_HERE,
    191       base::Bind(&GCMDriverDesktop::MessageSendError, service_, app_id,
    192                  send_error_details));
    193 }
    194 
    195 void GCMDriverDesktop::IOWorker::OnSendAcknowledged(
    196     const std::string& app_id,
    197     const std::string& message_id) {
    198   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    199 
    200   ui_thread_->PostTask(
    201       FROM_HERE,
    202       base::Bind(
    203           &GCMDriverDesktop::SendAcknowledged, service_, app_id, message_id));
    204 }
    205 
    206 void GCMDriverDesktop::IOWorker::OnGCMReady(
    207     const std::vector<AccountMapping>& account_mappings) {
    208   ui_thread_->PostTask(
    209       FROM_HERE,
    210       base::Bind(
    211           &GCMDriverDesktop::GCMClientReady, service_, account_mappings));
    212 }
    213 
    214 void GCMDriverDesktop::IOWorker::OnActivityRecorded() {
    215   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    216   // When an activity is recorded, get all the stats and refresh the UI of
    217   // gcm-internals page.
    218   GetGCMStatistics(false);
    219 }
    220 
    221 void GCMDriverDesktop::IOWorker::OnConnected(
    222     const net::IPEndPoint& ip_endpoint) {
    223   ui_thread_->PostTask(FROM_HERE,
    224                        base::Bind(&GCMDriverDesktop::OnConnected,
    225                                   service_,
    226                                   ip_endpoint));
    227 }
    228 
    229 void GCMDriverDesktop::IOWorker::OnDisconnected() {
    230   ui_thread_->PostTask(FROM_HERE,
    231                        base::Bind(&GCMDriverDesktop::OnDisconnected, service_));
    232 }
    233 
    234 void GCMDriverDesktop::IOWorker::Start(
    235     const base::WeakPtr<GCMDriverDesktop>& service) {
    236   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    237 
    238   service_ = service;
    239   gcm_client_->Start();
    240 }
    241 
    242 void GCMDriverDesktop::IOWorker::Stop() {
    243   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    244 
    245   gcm_client_->Stop();
    246 }
    247 
    248 void GCMDriverDesktop::IOWorker::CheckOut() {
    249   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    250 
    251   gcm_client_->CheckOut();
    252 
    253   // Note that we still need to keep GCMClient instance alive since the
    254   // GCMDriverDesktop may check in again.
    255 }
    256 
    257 void GCMDriverDesktop::IOWorker::Register(
    258     const std::string& app_id,
    259     const std::vector<std::string>& sender_ids) {
    260   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    261 
    262   gcm_client_->Register(app_id, sender_ids);
    263 }
    264 
    265 void GCMDriverDesktop::IOWorker::Unregister(const std::string& app_id) {
    266   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    267 
    268   gcm_client_->Unregister(app_id);
    269 }
    270 
    271 void GCMDriverDesktop::IOWorker::Send(
    272     const std::string& app_id,
    273     const std::string& receiver_id,
    274     const GCMClient::OutgoingMessage& message) {
    275   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    276 
    277   gcm_client_->Send(app_id, receiver_id, message);
    278 }
    279 
    280 void GCMDriverDesktop::IOWorker::GetGCMStatistics(bool clear_logs) {
    281   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    282   gcm::GCMClient::GCMStatistics stats;
    283 
    284   if (gcm_client_.get()) {
    285     if (clear_logs)
    286       gcm_client_->ClearActivityLogs();
    287     stats = gcm_client_->GetStatistics();
    288   }
    289 
    290   ui_thread_->PostTask(
    291       FROM_HERE,
    292       base::Bind(&GCMDriverDesktop::GetGCMStatisticsFinished, service_, stats));
    293 }
    294 
    295 void GCMDriverDesktop::IOWorker::SetGCMRecording(bool recording) {
    296   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    297   gcm::GCMClient::GCMStatistics stats;
    298 
    299   if (gcm_client_.get()) {
    300     gcm_client_->SetRecording(recording);
    301     stats = gcm_client_->GetStatistics();
    302     stats.gcm_client_created = true;
    303   }
    304 
    305   ui_thread_->PostTask(
    306       FROM_HERE,
    307       base::Bind(&GCMDriverDesktop::GetGCMStatisticsFinished, service_, stats));
    308 }
    309 
    310 void GCMDriverDesktop::IOWorker::SetAccountsForCheckin(
    311     const std::map<std::string, std::string>& account_tokens) {
    312   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    313 
    314   if (gcm_client_.get())
    315     gcm_client_->SetAccountsForCheckin(account_tokens);
    316 }
    317 
    318 void GCMDriverDesktop::IOWorker::UpdateAccountMapping(
    319     const AccountMapping& account_mapping) {
    320   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    321 
    322   if (gcm_client_.get())
    323     gcm_client_->UpdateAccountMapping(account_mapping);
    324 }
    325 
    326 void GCMDriverDesktop::IOWorker::RemoveAccountMapping(
    327     const std::string& account_id) {
    328   DCHECK(io_thread_->RunsTasksOnCurrentThread());
    329 
    330   if (gcm_client_.get())
    331     gcm_client_->RemoveAccountMapping(account_id);
    332 }
    333 
    334 GCMDriverDesktop::GCMDriverDesktop(
    335     scoped_ptr<GCMClientFactory> gcm_client_factory,
    336     const GCMClient::ChromeBuildInfo& chrome_build_info,
    337     const std::string& channel_status_request_url,
    338     const std::string& user_agent,
    339     PrefService* prefs,
    340     const base::FilePath& store_path,
    341     const scoped_refptr<net::URLRequestContextGetter>& request_context,
    342     const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
    343     const scoped_refptr<base::SequencedTaskRunner>& io_thread,
    344     const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
    345     : gcm_channel_status_syncer_(
    346           new GCMChannelStatusSyncer(this,
    347                                      prefs,
    348                                      channel_status_request_url,
    349                                      user_agent,
    350                                      request_context)),
    351       signed_in_(false),
    352       gcm_started_(false),
    353       gcm_enabled_(true),
    354       connected_(false),
    355       ui_thread_(ui_thread),
    356       io_thread_(io_thread),
    357       weak_ptr_factory_(this) {
    358   gcm_enabled_ = gcm_channel_status_syncer_->gcm_enabled();
    359 
    360   // Create and initialize the GCMClient. Note that this does not initiate the
    361   // GCM check-in.
    362   io_worker_.reset(new IOWorker(ui_thread, io_thread));
    363   io_thread_->PostTask(
    364       FROM_HERE,
    365       base::Bind(&GCMDriverDesktop::IOWorker::Initialize,
    366                  base::Unretained(io_worker_.get()),
    367                  base::Passed(&gcm_client_factory),
    368                  chrome_build_info,
    369                  store_path,
    370                  request_context,
    371                  blocking_task_runner));
    372 }
    373 
    374 GCMDriverDesktop::~GCMDriverDesktop() {
    375 }
    376 
    377 void GCMDriverDesktop::Shutdown() {
    378   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    379   GCMDriver::Shutdown();
    380 
    381   // Dispose the syncer in order to release the reference to
    382   // URLRequestContextGetter that needs to be done before IOThread gets
    383   // deleted.
    384   gcm_channel_status_syncer_.reset();
    385 
    386   io_thread_->DeleteSoon(FROM_HERE, io_worker_.release());
    387 }
    388 
    389 void GCMDriverDesktop::OnSignedIn() {
    390   signed_in_ = true;
    391   EnsureStarted();
    392 }
    393 
    394 void GCMDriverDesktop::OnSignedOut() {
    395   signed_in_ = false;
    396 
    397   // When sign-in enforcement is not dropped, we will stop the GCM connection
    398   // when the user signs out.
    399   if (!GCMDriver::IsAllowedForAllUsers())
    400     Stop();
    401 }
    402 
    403 void GCMDriverDesktop::Purge() {
    404   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    405 
    406   RemoveCachedData();
    407 
    408   io_thread_->PostTask(FROM_HERE,
    409                        base::Bind(&GCMDriverDesktop::IOWorker::CheckOut,
    410                        base::Unretained(io_worker_.get())));
    411 }
    412 
    413 void GCMDriverDesktop::AddAppHandler(const std::string& app_id,
    414                                      GCMAppHandler* handler) {
    415   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    416   GCMDriver::AddAppHandler(app_id, handler);
    417 
    418    // Ensures that the GCM service is started when there is an interest.
    419   EnsureStarted();
    420 }
    421 
    422 void GCMDriverDesktop::RemoveAppHandler(const std::string& app_id) {
    423   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    424   GCMDriver::RemoveAppHandler(app_id);
    425 
    426   // Stops the GCM service when no app intends to consume it.
    427   if (app_handlers().empty()) {
    428     Stop();
    429     gcm_channel_status_syncer_->Stop();
    430   }
    431 }
    432 
    433 void GCMDriverDesktop::AddConnectionObserver(GCMConnectionObserver* observer) {
    434   connection_observer_list_.AddObserver(observer);
    435 }
    436 
    437 void GCMDriverDesktop::RemoveConnectionObserver(
    438     GCMConnectionObserver* observer) {
    439   connection_observer_list_.RemoveObserver(observer);
    440 }
    441 
    442 void GCMDriverDesktop::Enable() {
    443   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    444 
    445   if (gcm_enabled_)
    446     return;
    447   gcm_enabled_ = true;
    448 
    449   EnsureStarted();
    450 }
    451 
    452 void GCMDriverDesktop::Disable() {
    453   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    454 
    455   if (!gcm_enabled_)
    456     return;
    457   gcm_enabled_ = false;
    458 
    459   Stop();
    460 }
    461 
    462 void GCMDriverDesktop::Stop() {
    463   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    464 
    465   // No need to stop GCM service if not started yet.
    466   if (!gcm_started_)
    467     return;
    468 
    469   RemoveCachedData();
    470 
    471   io_thread_->PostTask(
    472       FROM_HERE,
    473       base::Bind(&GCMDriverDesktop::IOWorker::Stop,
    474                  base::Unretained(io_worker_.get())));
    475 }
    476 
    477 void GCMDriverDesktop::RegisterImpl(
    478     const std::string& app_id,
    479     const std::vector<std::string>& sender_ids) {
    480   // Delay the register operation until GCMClient is ready.
    481   if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
    482     delayed_task_controller_->AddTask(base::Bind(&GCMDriverDesktop::DoRegister,
    483                                                  weak_ptr_factory_.GetWeakPtr(),
    484                                                  app_id,
    485                                                  sender_ids));
    486     return;
    487   }
    488 
    489   DoRegister(app_id, sender_ids);
    490 }
    491 
    492 void GCMDriverDesktop::DoRegister(const std::string& app_id,
    493                                   const std::vector<std::string>& sender_ids) {
    494   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    495   if (!HasRegisterCallback(app_id)) {
    496     // The callback could have been removed when the app is uninstalled.
    497     return;
    498   }
    499 
    500   io_thread_->PostTask(
    501       FROM_HERE,
    502       base::Bind(&GCMDriverDesktop::IOWorker::Register,
    503                  base::Unretained(io_worker_.get()),
    504                  app_id,
    505                  sender_ids));
    506 }
    507 
    508 void GCMDriverDesktop::UnregisterImpl(const std::string& app_id) {
    509   // Delay the unregister operation until GCMClient is ready.
    510   if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
    511     delayed_task_controller_->AddTask(
    512         base::Bind(&GCMDriverDesktop::DoUnregister,
    513                    weak_ptr_factory_.GetWeakPtr(),
    514                    app_id));
    515     return;
    516   }
    517 
    518   DoUnregister(app_id);
    519 }
    520 
    521 void GCMDriverDesktop::DoUnregister(const std::string& app_id) {
    522   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    523 
    524   // Ask the server to unregister it. There could be a small chance that the
    525   // unregister request fails. If this occurs, it does not bring any harm since
    526   // we simply reject the messages/events received from the server.
    527   io_thread_->PostTask(
    528       FROM_HERE,
    529       base::Bind(&GCMDriverDesktop::IOWorker::Unregister,
    530                  base::Unretained(io_worker_.get()),
    531                  app_id));
    532 }
    533 
    534 void GCMDriverDesktop::SendImpl(const std::string& app_id,
    535                                 const std::string& receiver_id,
    536                                 const GCMClient::OutgoingMessage& message) {
    537   // Delay the send operation until all GCMClient is ready.
    538   if (!delayed_task_controller_->CanRunTaskWithoutDelay()) {
    539     delayed_task_controller_->AddTask(base::Bind(&GCMDriverDesktop::DoSend,
    540                                                  weak_ptr_factory_.GetWeakPtr(),
    541                                                  app_id,
    542                                                  receiver_id,
    543                                                  message));
    544     return;
    545   }
    546 
    547   DoSend(app_id, receiver_id, message);
    548 }
    549 
    550 void GCMDriverDesktop::DoSend(const std::string& app_id,
    551                               const std::string& receiver_id,
    552                               const GCMClient::OutgoingMessage& message) {
    553   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    554   io_thread_->PostTask(
    555       FROM_HERE,
    556       base::Bind(&GCMDriverDesktop::IOWorker::Send,
    557                  base::Unretained(io_worker_.get()),
    558                  app_id,
    559                  receiver_id,
    560                  message));
    561 }
    562 
    563 GCMClient* GCMDriverDesktop::GetGCMClientForTesting() const {
    564   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    565   return io_worker_ ? io_worker_->gcm_client_for_testing() : NULL;
    566 }
    567 
    568 bool GCMDriverDesktop::IsStarted() const {
    569   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    570   return gcm_started_;
    571 }
    572 
    573 bool GCMDriverDesktop::IsConnected() const {
    574   return connected_;
    575 }
    576 
    577 void GCMDriverDesktop::GetGCMStatistics(
    578     const GetGCMStatisticsCallback& callback,
    579     bool clear_logs) {
    580   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    581   DCHECK(!callback.is_null());
    582 
    583   request_gcm_statistics_callback_ = callback;
    584   io_thread_->PostTask(
    585       FROM_HERE,
    586       base::Bind(&GCMDriverDesktop::IOWorker::GetGCMStatistics,
    587                  base::Unretained(io_worker_.get()),
    588                  clear_logs));
    589 }
    590 
    591 void GCMDriverDesktop::SetGCMRecording(const GetGCMStatisticsCallback& callback,
    592                                        bool recording) {
    593   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    594 
    595   request_gcm_statistics_callback_ = callback;
    596   io_thread_->PostTask(
    597       FROM_HERE,
    598       base::Bind(&GCMDriverDesktop::IOWorker::SetGCMRecording,
    599                  base::Unretained(io_worker_.get()),
    600                  recording));
    601 }
    602 
    603 void GCMDriverDesktop::UpdateAccountMapping(
    604     const AccountMapping& account_mapping) {
    605   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    606 
    607   io_thread_->PostTask(
    608       FROM_HERE,
    609       base::Bind(&GCMDriverDesktop::IOWorker::UpdateAccountMapping,
    610                  base::Unretained(io_worker_.get()),
    611                  account_mapping));
    612 }
    613 
    614 void GCMDriverDesktop::RemoveAccountMapping(const std::string& account_id) {
    615   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    616 
    617   io_thread_->PostTask(
    618       FROM_HERE,
    619       base::Bind(&GCMDriverDesktop::IOWorker::RemoveAccountMapping,
    620                  base::Unretained(io_worker_.get()),
    621                  account_id));
    622 }
    623 
    624 void GCMDriverDesktop::SetAccountsForCheckin(
    625     const std::map<std::string, std::string>& account_tokens) {
    626   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    627 
    628   io_thread_->PostTask(
    629       FROM_HERE,
    630       base::Bind(&GCMDriverDesktop::IOWorker::SetAccountsForCheckin,
    631                  base::Unretained(io_worker_.get()),
    632                  account_tokens));
    633 }
    634 
    635 GCMClient::Result GCMDriverDesktop::EnsureStarted() {
    636   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    637 
    638   if (gcm_started_)
    639     return GCMClient::SUCCESS;
    640 
    641   if (!gcm_enabled_) {
    642     // Poll for channel status in order to find out when it is re-enabled when
    643     // GCM is currently disabled.
    644     if (GCMDriver::IsAllowedForAllUsers())
    645       gcm_channel_status_syncer_->EnsureStarted();
    646 
    647     return GCMClient::GCM_DISABLED;
    648   }
    649 
    650   // Have any app requested the service?
    651   if (app_handlers().empty())
    652     return GCMClient::UNKNOWN_ERROR;
    653 
    654   // TODO(jianli): To be removed when sign-in enforcement is dropped.
    655   if (!signed_in_ && !GCMDriver::IsAllowedForAllUsers())
    656     return GCMClient::NOT_SIGNED_IN;
    657 
    658   DCHECK(!delayed_task_controller_);
    659   delayed_task_controller_.reset(new GCMDelayedTaskController);
    660 
    661   // Polling for channel status is only needed when GCM is supported for all
    662   // users.
    663   if (GCMDriver::IsAllowedForAllUsers())
    664     gcm_channel_status_syncer_->EnsureStarted();
    665 
    666   UMA_HISTOGRAM_BOOLEAN("GCM.UserSignedIn", signed_in_);
    667 
    668   // Note that we need to pass weak pointer again since the existing weak
    669   // pointer in IOWorker might have been invalidated when check-out occurs.
    670   io_thread_->PostTask(
    671       FROM_HERE,
    672       base::Bind(&GCMDriverDesktop::IOWorker::Start,
    673                  base::Unretained(io_worker_.get()),
    674                  weak_ptr_factory_.GetWeakPtr()));
    675 
    676   gcm_started_ = true;
    677   return GCMClient::SUCCESS;
    678 }
    679 
    680 void GCMDriverDesktop::RemoveCachedData() {
    681   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    682   // Remove all the queued tasks since they no longer make sense after
    683   // GCM service is stopped.
    684   weak_ptr_factory_.InvalidateWeakPtrs();
    685 
    686   gcm_started_ = false;
    687   delayed_task_controller_.reset();
    688   ClearCallbacks();
    689 }
    690 
    691 void GCMDriverDesktop::MessageReceived(
    692     const std::string& app_id,
    693     const GCMClient::IncomingMessage& message) {
    694   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    695 
    696   // Drop the event if the service has been stopped.
    697   if (!gcm_started_)
    698     return;
    699 
    700   GetAppHandler(app_id)->OnMessage(app_id, message);
    701 }
    702 
    703 void GCMDriverDesktop::MessagesDeleted(const std::string& app_id) {
    704   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    705 
    706   // Drop the event if the service has been stopped.
    707   if (!gcm_started_)
    708     return;
    709 
    710   GetAppHandler(app_id)->OnMessagesDeleted(app_id);
    711 }
    712 
    713 void GCMDriverDesktop::MessageSendError(
    714     const std::string& app_id,
    715     const GCMClient::SendErrorDetails& send_error_details) {
    716   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    717 
    718   // Drop the event if the service has been stopped.
    719   if (!gcm_started_)
    720     return;
    721 
    722   GetAppHandler(app_id)->OnSendError(app_id, send_error_details);
    723 }
    724 
    725 void GCMDriverDesktop::SendAcknowledged(const std::string& app_id,
    726                                         const std::string& message_id) {
    727   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    728 
    729   // Drop the event if the service has been stopped.
    730   if (!gcm_started_)
    731     return;
    732 
    733   GetAppHandler(app_id)->OnSendAcknowledged(app_id, message_id);
    734 }
    735 
    736 void GCMDriverDesktop::GCMClientReady(
    737     const std::vector<AccountMapping>& account_mappings) {
    738   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    739 
    740   delayed_task_controller_->SetReady();
    741 }
    742 
    743 void GCMDriverDesktop::OnConnected(const net::IPEndPoint& ip_endpoint) {
    744   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    745 
    746   connected_ = true;
    747 
    748   // Drop the event if the service has been stopped.
    749   if (!gcm_started_)
    750     return;
    751 
    752   FOR_EACH_OBSERVER(GCMConnectionObserver,
    753                     connection_observer_list_,
    754                     OnConnected(ip_endpoint));
    755 }
    756 
    757 void GCMDriverDesktop::OnDisconnected() {
    758   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    759 
    760   connected_ = false;
    761 
    762   // Drop the event if the service has been stopped.
    763   if (!gcm_started_)
    764     return;
    765 
    766   FOR_EACH_OBSERVER(
    767       GCMConnectionObserver, connection_observer_list_, OnDisconnected());
    768 }
    769 
    770 void GCMDriverDesktop::GetGCMStatisticsFinished(
    771     const GCMClient::GCMStatistics& stats) {
    772   DCHECK(ui_thread_->RunsTasksOnCurrentThread());
    773 
    774   // Normally request_gcm_statistics_callback_ would not be null.
    775   if (!request_gcm_statistics_callback_.is_null())
    776     request_gcm_statistics_callback_.Run(stats);
    777   else
    778     LOG(WARNING) << "request_gcm_statistics_callback_ is NULL.";
    779 }
    780 
    781 }  // namespace gcm
    782 
    783