Home | History | Annotate | Download | only in webui
      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 "chrome/browser/ui/webui/gcm_internals_ui.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/format_macros.h"
     12 #include "base/memory/weak_ptr.h"
     13 #include "base/strings/string_util.h"
     14 #include "base/strings/stringprintf.h"
     15 #include "base/values.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "chrome/browser/services/gcm/gcm_profile_service.h"
     18 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
     19 #include "chrome/common/url_constants.h"
     20 #include "components/gcm_driver/gcm_client.h"
     21 #include "components/gcm_driver/gcm_driver.h"
     22 #include "content/public/browser/web_ui.h"
     23 #include "content/public/browser/web_ui_controller.h"
     24 #include "content/public/browser/web_ui_data_source.h"
     25 #include "content/public/browser/web_ui_message_handler.h"
     26 #include "grit/browser_resources.h"
     27 
     28 namespace {
     29 
     30 void SetCheckinInfo(
     31     const std::vector<gcm::CheckinActivity>& checkins,
     32     base::ListValue* checkin_info) {
     33   std::vector<gcm::CheckinActivity>::const_iterator it = checkins.begin();
     34   for (; it < checkins.end(); ++it) {
     35     base::ListValue* row = new base::ListValue();
     36     checkin_info->Append(row);
     37 
     38     row->AppendDouble(it->time.ToJsTime());
     39     row->AppendString(it->event);
     40     row->AppendString(it->details);
     41   }
     42 }
     43 
     44 void SetConnectionInfo(
     45     const std::vector<gcm::ConnectionActivity>& connections,
     46     base::ListValue* connection_info) {
     47   std::vector<gcm::ConnectionActivity>::const_iterator it = connections.begin();
     48   for (; it < connections.end(); ++it) {
     49     base::ListValue* row = new base::ListValue();
     50     connection_info->Append(row);
     51 
     52     row->AppendDouble(it->time.ToJsTime());
     53     row->AppendString(it->event);
     54     row->AppendString(it->details);
     55   }
     56 }
     57 
     58 void SetRegistrationInfo(
     59     const std::vector<gcm::RegistrationActivity>& registrations,
     60     base::ListValue* registration_info) {
     61   std::vector<gcm::RegistrationActivity>::const_iterator it =
     62       registrations.begin();
     63   for (; it < registrations.end(); ++it) {
     64     base::ListValue* row = new base::ListValue();
     65     registration_info->Append(row);
     66 
     67     row->AppendDouble(it->time.ToJsTime());
     68     row->AppendString(it->app_id);
     69     row->AppendString(it->sender_ids);
     70     row->AppendString(it->event);
     71     row->AppendString(it->details);
     72   }
     73 }
     74 
     75 void SetReceivingInfo(
     76     const std::vector<gcm::ReceivingActivity>& receives,
     77     base::ListValue* receive_info) {
     78   std::vector<gcm::ReceivingActivity>::const_iterator it = receives.begin();
     79   for (; it < receives.end(); ++it) {
     80     base::ListValue* row = new base::ListValue();
     81     receive_info->Append(row);
     82 
     83     row->AppendDouble(it->time.ToJsTime());
     84     row->AppendString(it->app_id);
     85     row->AppendString(it->from);
     86     row->AppendString(base::StringPrintf("%d", it->message_byte_size));
     87     row->AppendString(it->event);
     88     row->AppendString(it->details);
     89   }
     90 }
     91 
     92 void SetSendingInfo(
     93     const std::vector<gcm::SendingActivity>& sends,
     94     base::ListValue* send_info) {
     95   std::vector<gcm::SendingActivity>::const_iterator it = sends.begin();
     96   for (; it < sends.end(); ++it) {
     97     base::ListValue* row = new base::ListValue();
     98     send_info->Append(row);
     99 
    100     row->AppendDouble(it->time.ToJsTime());
    101     row->AppendString(it->app_id);
    102     row->AppendString(it->receiver_id);
    103     row->AppendString(it->message_id);
    104     row->AppendString(it->event);
    105     row->AppendString(it->details);
    106   }
    107 }
    108 
    109 // Class acting as a controller of the chrome://gcm-internals WebUI.
    110 class GcmInternalsUIMessageHandler : public content::WebUIMessageHandler {
    111  public:
    112   GcmInternalsUIMessageHandler();
    113   virtual ~GcmInternalsUIMessageHandler();
    114 
    115   // WebUIMessageHandler implementation.
    116   virtual void RegisterMessages() OVERRIDE;
    117 
    118  private:
    119   // Return all of the GCM related infos to the gcm-internals page by calling
    120   // Javascript callback function
    121   // |gcm-internals.returnInfo()|.
    122   void ReturnResults(Profile* profile, gcm::GCMProfileService* profile_service,
    123                      const gcm::GCMClient::GCMStatistics* stats) const;
    124 
    125   // Request all of the GCM related infos through gcm profile service.
    126   void RequestAllInfo(const base::ListValue* args);
    127 
    128   // Enables/disables GCM activity recording through gcm profile service.
    129   void SetRecording(const base::ListValue* args);
    130 
    131   // Callback function of the request for all gcm related infos.
    132   void RequestGCMStatisticsFinished(
    133       const gcm::GCMClient::GCMStatistics& args) const;
    134 
    135   // Factory for creating references in callbacks.
    136   base::WeakPtrFactory<GcmInternalsUIMessageHandler> weak_ptr_factory_;
    137 
    138   DISALLOW_COPY_AND_ASSIGN(GcmInternalsUIMessageHandler);
    139 };
    140 
    141 GcmInternalsUIMessageHandler::GcmInternalsUIMessageHandler()
    142     : weak_ptr_factory_(this) {}
    143 
    144 GcmInternalsUIMessageHandler::~GcmInternalsUIMessageHandler() {}
    145 
    146 void GcmInternalsUIMessageHandler::ReturnResults(
    147     Profile* profile,
    148     gcm::GCMProfileService* profile_service,
    149     const gcm::GCMClient::GCMStatistics* stats) const {
    150   base::DictionaryValue results;
    151   base::DictionaryValue* device_info = new base::DictionaryValue();
    152   results.Set("deviceInfo", device_info);
    153 
    154   device_info->SetBoolean("profileServiceCreated", profile_service != NULL);
    155   device_info->SetBoolean("gcmEnabled",
    156                           gcm::GCMProfileService::IsGCMEnabled(profile));
    157   if (profile_service) {
    158     device_info->SetString("signedInUserName",
    159                            profile_service->SignedInUserName());
    160   }
    161   if (stats) {
    162     results.SetBoolean("isRecording", stats->is_recording);
    163     device_info->SetBoolean("gcmClientCreated", stats->gcm_client_created);
    164     device_info->SetString("gcmClientState", stats->gcm_client_state);
    165     device_info->SetBoolean("connectionClientCreated",
    166                             stats->connection_client_created);
    167     device_info->SetString("registeredAppIds",
    168                            JoinString(stats->registered_app_ids, ","));
    169     if (stats->connection_client_created)
    170       device_info->SetString("connectionState", stats->connection_state);
    171     if (stats->android_id > 0) {
    172       device_info->SetString("androidId",
    173           base::StringPrintf("0x%" PRIx64, stats->android_id));
    174     }
    175     device_info->SetInteger("sendQueueSize", stats->send_queue_size);
    176     device_info->SetInteger("resendQueueSize", stats->resend_queue_size);
    177 
    178     if (stats->recorded_activities.checkin_activities.size() > 0) {
    179       base::ListValue* checkin_info = new base::ListValue();
    180       results.Set("checkinInfo", checkin_info);
    181       SetCheckinInfo(stats->recorded_activities.checkin_activities,
    182                      checkin_info);
    183     }
    184     if (stats->recorded_activities.connection_activities.size() > 0) {
    185       base::ListValue* connection_info = new base::ListValue();
    186       results.Set("connectionInfo", connection_info);
    187       SetConnectionInfo(stats->recorded_activities.connection_activities,
    188                         connection_info);
    189     }
    190     if (stats->recorded_activities.registration_activities.size() > 0) {
    191       base::ListValue* registration_info = new base::ListValue();
    192       results.Set("registrationInfo", registration_info);
    193       SetRegistrationInfo(stats->recorded_activities.registration_activities,
    194                           registration_info);
    195     }
    196     if (stats->recorded_activities.receiving_activities.size() > 0) {
    197       base::ListValue* receive_info = new base::ListValue();
    198       results.Set("receiveInfo", receive_info);
    199       SetReceivingInfo(stats->recorded_activities.receiving_activities,
    200                        receive_info);
    201     }
    202     if (stats->recorded_activities.sending_activities.size() > 0) {
    203       base::ListValue* send_info = new base::ListValue();
    204       results.Set("sendInfo", send_info);
    205       SetSendingInfo(stats->recorded_activities.sending_activities, send_info);
    206     }
    207   }
    208   web_ui()->CallJavascriptFunction("gcmInternals.setGcmInternalsInfo",
    209                                    results);
    210 }
    211 
    212 void GcmInternalsUIMessageHandler::RequestAllInfo(
    213     const base::ListValue* args) {
    214   if (args->GetSize() != 1) {
    215     NOTREACHED();
    216     return;
    217   }
    218   bool clear_logs = false;
    219   if (!args->GetBoolean(0, &clear_logs)) {
    220     NOTREACHED();
    221     return;
    222   }
    223 
    224   Profile* profile = Profile::FromWebUI(web_ui());
    225   gcm::GCMProfileService* profile_service =
    226     gcm::GCMProfileServiceFactory::GetForProfile(profile);
    227 
    228   if (!profile_service) {
    229     ReturnResults(profile, NULL, NULL);
    230   } else if (profile_service->SignedInUserName().empty()) {
    231     ReturnResults(profile, profile_service, NULL);
    232   } else {
    233     profile_service->driver()->GetGCMStatistics(
    234         base::Bind(&GcmInternalsUIMessageHandler::RequestGCMStatisticsFinished,
    235                    weak_ptr_factory_.GetWeakPtr()),
    236         clear_logs);
    237   }
    238 }
    239 
    240 void GcmInternalsUIMessageHandler::SetRecording(const base::ListValue* args) {
    241   if (args->GetSize() != 1) {
    242     NOTREACHED();
    243     return;
    244   }
    245   bool recording = false;
    246   if (!args->GetBoolean(0, &recording)) {
    247     NOTREACHED();
    248     return;
    249   }
    250 
    251   Profile* profile = Profile::FromWebUI(web_ui());
    252   gcm::GCMProfileService* profile_service =
    253       gcm::GCMProfileServiceFactory::GetForProfile(profile);
    254 
    255   if (!profile_service) {
    256     ReturnResults(profile, NULL, NULL);
    257     return;
    258   }
    259   if (profile_service->SignedInUserName().empty()) {
    260     ReturnResults(profile, profile_service, NULL);
    261     return;
    262   }
    263   // Get fresh stats after changing recording setting.
    264   profile_service->driver()->SetGCMRecording(
    265       base::Bind(
    266           &GcmInternalsUIMessageHandler::RequestGCMStatisticsFinished,
    267           weak_ptr_factory_.GetWeakPtr()),
    268       recording);
    269 }
    270 
    271 void GcmInternalsUIMessageHandler::RequestGCMStatisticsFinished(
    272     const gcm::GCMClient::GCMStatistics& stats) const {
    273   Profile* profile = Profile::FromWebUI(web_ui());
    274   DCHECK(profile);
    275   gcm::GCMProfileService* profile_service =
    276       gcm::GCMProfileServiceFactory::GetForProfile(profile);
    277   DCHECK(profile_service);
    278   ReturnResults(profile, profile_service, &stats);
    279 }
    280 
    281 void GcmInternalsUIMessageHandler::RegisterMessages() {
    282   web_ui()->RegisterMessageCallback(
    283       "getGcmInternalsInfo",
    284       base::Bind(&GcmInternalsUIMessageHandler::RequestAllInfo,
    285                  weak_ptr_factory_.GetWeakPtr()));
    286   web_ui()->RegisterMessageCallback(
    287       "setGcmInternalsRecording",
    288       base::Bind(&GcmInternalsUIMessageHandler::SetRecording,
    289                  weak_ptr_factory_.GetWeakPtr()));
    290 }
    291 
    292 }  // namespace
    293 
    294 GCMInternalsUI::GCMInternalsUI(content::WebUI* web_ui)
    295     : content::WebUIController(web_ui) {
    296   // Set up the chrome://gcm-internals source.
    297   content::WebUIDataSource* html_source =
    298       content::WebUIDataSource::Create(chrome::kChromeUIGCMInternalsHost);
    299   html_source->SetUseJsonJSFormatV2();
    300 
    301   html_source->SetJsonPath("strings.js");
    302 
    303   // Add required resources.
    304   html_source->AddResourcePath("gcm_internals.css", IDR_GCM_INTERNALS_CSS);
    305   html_source->AddResourcePath("gcm_internals.js", IDR_GCM_INTERNALS_JS);
    306   html_source->SetDefaultResource(IDR_GCM_INTERNALS_HTML);
    307 
    308   Profile* profile = Profile::FromWebUI(web_ui);
    309   content::WebUIDataSource::Add(profile, html_source);
    310 
    311   web_ui->AddMessageHandler(new GcmInternalsUIMessageHandler());
    312 }
    313 
    314 GCMInternalsUI::~GCMInternalsUI() {}
    315