1 // Copyright 2015 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 "ios/chrome/browser/ui/webui/gcm/gcm_internals_ui.h"
6 
7 #include <memory>
8 #include <vector>
9 
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/macros.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/values.h"
15 #include "components/gcm_driver/gcm_client.h"
16 #include "components/gcm_driver/gcm_driver.h"
17 #include "components/gcm_driver/gcm_internals_constants.h"
18 #include "components/gcm_driver/gcm_internals_helper.h"
19 #include "components/gcm_driver/gcm_profile_service.h"
20 #include "components/grit/dev_ui_components_resources.h"
21 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
22 #include "ios/chrome/browser/chrome_url_constants.h"
23 #include "ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.h"
24 #include "ios/web/public/webui/web_ui_ios.h"
25 #include "ios/web/public/webui/web_ui_ios_data_source.h"
26 #include "ios/web/public/webui/web_ui_ios_message_handler.h"
27 
28 namespace {
29 
30 // Class acting as a controller of the chrome://gcm-internals WebUI.
31 class GcmInternalsUIMessageHandler : public web::WebUIIOSMessageHandler {
32  public:
33   GcmInternalsUIMessageHandler();
34   ~GcmInternalsUIMessageHandler() override;
35 
36   // WebUIMessageHandler implementation.
37   void RegisterMessages() override;
38 
39  private:
40   // Return all of the GCM related infos to the gcm-internals page by calling
41   // Javascript callback function |gcm-internals.returnInfo()|.
42   void ReturnResults(PrefService* prefs,
43                      gcm::GCMProfileService* profile_service,
44                      const gcm::GCMClient::GCMStatistics* stats) const;
45 
46   // Request all of the GCM related infos through gcm profile service.
47   void RequestAllInfo(const base::ListValue* args);
48 
49   // Enables/disables GCM activity recording through gcm profile service.
50   void SetRecording(const base::ListValue* args);
51 
52   // Callback function of the request for all gcm related infos.
53   void RequestGCMStatisticsFinished(
54       const gcm::GCMClient::GCMStatistics& args) const;
55 
56   // Factory for creating references in callbacks.
57   base::WeakPtrFactory<GcmInternalsUIMessageHandler> weak_ptr_factory_;
58 
59   DISALLOW_COPY_AND_ASSIGN(GcmInternalsUIMessageHandler);
60 };
61 
GcmInternalsUIMessageHandler()62 GcmInternalsUIMessageHandler::GcmInternalsUIMessageHandler()
63     : weak_ptr_factory_(this) {}
64 
~GcmInternalsUIMessageHandler()65 GcmInternalsUIMessageHandler::~GcmInternalsUIMessageHandler() {}
66 
ReturnResults(PrefService * prefs,gcm::GCMProfileService * profile_service,const gcm::GCMClient::GCMStatistics * stats) const67 void GcmInternalsUIMessageHandler::ReturnResults(
68     PrefService* prefs,
69     gcm::GCMProfileService* profile_service,
70     const gcm::GCMClient::GCMStatistics* stats) const {
71   base::DictionaryValue results;
72   gcm_driver::SetGCMInternalsInfo(stats, profile_service, prefs, &results);
73 
74   std::vector<const base::Value*> args{&results};
75   web_ui()->CallJavascriptFunction(gcm_driver::kSetGcmInternalsInfo, args);
76 }
77 
RequestAllInfo(const base::ListValue * args)78 void GcmInternalsUIMessageHandler::RequestAllInfo(const base::ListValue* args) {
79   if (args->GetSize() != 1) {
80     NOTREACHED();
81     return;
82   }
83   bool clear_logs = false;
84   if (!args->GetBoolean(0, &clear_logs)) {
85     NOTREACHED();
86     return;
87   }
88 
89   gcm::GCMDriver::ClearActivityLogs clear_activity_logs =
90       clear_logs ? gcm::GCMDriver::CLEAR_LOGS : gcm::GCMDriver::KEEP_LOGS;
91 
92   ChromeBrowserState* browser_state =
93       ChromeBrowserState::FromWebUIIOS(web_ui());
94   gcm::GCMProfileService* profile_service =
95       IOSChromeGCMProfileServiceFactory::GetForBrowserState(browser_state);
96 
97   if (!profile_service || !profile_service->driver()) {
98     ReturnResults(browser_state->GetPrefs(), nullptr, nullptr);
99   } else {
100     profile_service->driver()->GetGCMStatistics(
101         base::BindOnce(
102             &GcmInternalsUIMessageHandler::RequestGCMStatisticsFinished,
103             weak_ptr_factory_.GetWeakPtr()),
104         clear_activity_logs);
105   }
106 }
107 
SetRecording(const base::ListValue * args)108 void GcmInternalsUIMessageHandler::SetRecording(const base::ListValue* args) {
109   if (args->GetSize() != 1) {
110     NOTREACHED();
111     return;
112   }
113   bool recording = false;
114   if (!args->GetBoolean(0, &recording)) {
115     NOTREACHED();
116     return;
117   }
118 
119   ChromeBrowserState* browser_state =
120       ChromeBrowserState::FromWebUIIOS(web_ui());
121   gcm::GCMProfileService* profile_service =
122       IOSChromeGCMProfileServiceFactory::GetForBrowserState(browser_state);
123 
124   if (!profile_service) {
125     ReturnResults(browser_state->GetPrefs(), nullptr, nullptr);
126     return;
127   }
128   // Get fresh stats after changing recording setting.
129   profile_service->driver()->SetGCMRecording(
130       base::BindRepeating(
131           &GcmInternalsUIMessageHandler::RequestGCMStatisticsFinished,
132           weak_ptr_factory_.GetWeakPtr()),
133       recording);
134 }
135 
RequestGCMStatisticsFinished(const gcm::GCMClient::GCMStatistics & stats) const136 void GcmInternalsUIMessageHandler::RequestGCMStatisticsFinished(
137     const gcm::GCMClient::GCMStatistics& stats) const {
138   ChromeBrowserState* browser_state =
139       ChromeBrowserState::FromWebUIIOS(web_ui());
140   DCHECK(browser_state);
141   gcm::GCMProfileService* profile_service =
142       IOSChromeGCMProfileServiceFactory::GetForBrowserState(browser_state);
143 
144   DCHECK(profile_service);
145   ReturnResults(browser_state->GetPrefs(), profile_service, &stats);
146 }
147 
RegisterMessages()148 void GcmInternalsUIMessageHandler::RegisterMessages() {
149   web_ui()->RegisterMessageCallback(
150       gcm_driver::kGetGcmInternalsInfo,
151       base::BindRepeating(&GcmInternalsUIMessageHandler::RequestAllInfo,
152                           weak_ptr_factory_.GetWeakPtr()));
153   web_ui()->RegisterMessageCallback(
154       gcm_driver::kSetGcmInternalsRecording,
155       base::BindRepeating(&GcmInternalsUIMessageHandler::SetRecording,
156                           weak_ptr_factory_.GetWeakPtr()));
157 }
158 
159 }  // namespace
160 
GCMInternalsUI(web::WebUIIOS * web_ui,const std::string & host)161 GCMInternalsUI::GCMInternalsUI(web::WebUIIOS* web_ui, const std::string& host)
162     : web::WebUIIOSController(web_ui, host) {
163   // Set up the chrome://gcm-internals source.
164   web::WebUIIOSDataSource* html_source =
165       web::WebUIIOSDataSource::Create(kChromeUIGCMInternalsHost);
166 
167   html_source->UseStringsJs();
168 
169   // Add required resources.
170   html_source->AddResourcePath(gcm_driver::kGcmInternalsCSS,
171                                IDR_GCM_DRIVER_GCM_INTERNALS_CSS);
172   html_source->AddResourcePath(gcm_driver::kGcmInternalsJS,
173                                IDR_GCM_DRIVER_GCM_INTERNALS_JS);
174   html_source->SetDefaultResource(IDR_GCM_DRIVER_GCM_INTERNALS_HTML);
175 
176   web::WebUIIOSDataSource::Add(ChromeBrowserState::FromWebUIIOS(web_ui),
177                                html_source);
178 
179   web_ui->AddMessageHandler(std::make_unique<GcmInternalsUIMessageHandler>());
180 }
181 
~GCMInternalsUI()182 GCMInternalsUI::~GCMInternalsUI() {}
183