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