• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SetCheckinInfo(const std::vector<gcm::CheckinActivity> & checkins,base::ListValue * checkin_info)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 
SetConnectionInfo(const std::vector<gcm::ConnectionActivity> & connections,base::ListValue * connection_info)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 
SetRegistrationInfo(const std::vector<gcm::RegistrationActivity> & registrations,base::ListValue * registration_info)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 
SetReceivingInfo(const std::vector<gcm::ReceivingActivity> & receives,base::ListValue * receive_info)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 
SetSendingInfo(const std::vector<gcm::SendingActivity> & sends,base::ListValue * send_info)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 
GcmInternalsUIMessageHandler()141 GcmInternalsUIMessageHandler::GcmInternalsUIMessageHandler()
142     : weak_ptr_factory_(this) {}
143 
~GcmInternalsUIMessageHandler()144 GcmInternalsUIMessageHandler::~GcmInternalsUIMessageHandler() {}
145 
ReturnResults(Profile * profile,gcm::GCMProfileService * profile_service,const gcm::GCMClient::GCMStatistics * stats) const146 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 
RequestAllInfo(const base::ListValue * args)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 
SetRecording(const base::ListValue * args)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 
RequestGCMStatisticsFinished(const gcm::GCMClient::GCMStatistics & stats) const269 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 
RegisterMessages()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 
GCMInternalsUI(content::WebUI * web_ui)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 
~GCMInternalsUI()312 GCMInternalsUI::~GCMInternalsUI() {}
313