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 || !profile_service->driver()) { 229 ReturnResults(profile, NULL, NULL); 230 } else { 231 profile_service->driver()->GetGCMStatistics( 232 base::Bind(&GcmInternalsUIMessageHandler::RequestGCMStatisticsFinished, 233 weak_ptr_factory_.GetWeakPtr()), 234 clear_logs); 235 } 236 } 237 238 void GcmInternalsUIMessageHandler::SetRecording(const base::ListValue* args) { 239 if (args->GetSize() != 1) { 240 NOTREACHED(); 241 return; 242 } 243 bool recording = false; 244 if (!args->GetBoolean(0, &recording)) { 245 NOTREACHED(); 246 return; 247 } 248 249 Profile* profile = Profile::FromWebUI(web_ui()); 250 gcm::GCMProfileService* profile_service = 251 gcm::GCMProfileServiceFactory::GetForProfile(profile); 252 253 if (!profile_service) { 254 ReturnResults(profile, NULL, NULL); 255 return; 256 } 257 if (profile_service->SignedInUserName().empty()) { 258 ReturnResults(profile, profile_service, NULL); 259 return; 260 } 261 // Get fresh stats after changing recording setting. 262 profile_service->driver()->SetGCMRecording( 263 base::Bind( 264 &GcmInternalsUIMessageHandler::RequestGCMStatisticsFinished, 265 weak_ptr_factory_.GetWeakPtr()), 266 recording); 267 } 268 269 void GcmInternalsUIMessageHandler::RequestGCMStatisticsFinished( 270 const gcm::GCMClient::GCMStatistics& stats) const { 271 Profile* profile = Profile::FromWebUI(web_ui()); 272 DCHECK(profile); 273 gcm::GCMProfileService* profile_service = 274 gcm::GCMProfileServiceFactory::GetForProfile(profile); 275 DCHECK(profile_service); 276 ReturnResults(profile, profile_service, &stats); 277 } 278 279 void GcmInternalsUIMessageHandler::RegisterMessages() { 280 web_ui()->RegisterMessageCallback( 281 "getGcmInternalsInfo", 282 base::Bind(&GcmInternalsUIMessageHandler::RequestAllInfo, 283 weak_ptr_factory_.GetWeakPtr())); 284 web_ui()->RegisterMessageCallback( 285 "setGcmInternalsRecording", 286 base::Bind(&GcmInternalsUIMessageHandler::SetRecording, 287 weak_ptr_factory_.GetWeakPtr())); 288 } 289 290 } // namespace 291 292 GCMInternalsUI::GCMInternalsUI(content::WebUI* web_ui) 293 : content::WebUIController(web_ui) { 294 // Set up the chrome://gcm-internals source. 295 content::WebUIDataSource* html_source = 296 content::WebUIDataSource::Create(chrome::kChromeUIGCMInternalsHost); 297 html_source->SetUseJsonJSFormatV2(); 298 299 html_source->SetJsonPath("strings.js"); 300 301 // Add required resources. 302 html_source->AddResourcePath("gcm_internals.css", IDR_GCM_INTERNALS_CSS); 303 html_source->AddResourcePath("gcm_internals.js", IDR_GCM_INTERNALS_JS); 304 html_source->SetDefaultResource(IDR_GCM_INTERNALS_HTML); 305 306 Profile* profile = Profile::FromWebUI(web_ui); 307 content::WebUIDataSource::Add(profile, html_source); 308 309 web_ui->AddMessageHandler(new GcmInternalsUIMessageHandler()); 310 } 311 312 GCMInternalsUI::~GCMInternalsUI() {} 313