| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/webui/gcm_internals_ui.h" |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/callback_helpers.h" |
| #include "base/macros.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/values.h" |
| #include "chrome/browser/gcm/gcm_profile_service_factory.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/url_constants.h" |
| #include "components/gcm_driver/gcm_client.h" |
| #include "components/gcm_driver/gcm_driver.h" |
| #include "components/gcm_driver/gcm_internals_constants.h" |
| #include "components/gcm_driver/gcm_internals_helper.h" |
| #include "components/gcm_driver/gcm_profile_service.h" |
| #include "components/grit/dev_ui_components_resources.h" |
| #include "content/public/browser/web_ui.h" |
| #include "content/public/browser/web_ui_controller.h" |
| #include "content/public/browser/web_ui_data_source.h" |
| #include "content/public/browser/web_ui_message_handler.h" |
| |
| namespace { |
| |
| // Class acting as a controller of the chrome://gcm-internals WebUI. |
| class GcmInternalsUIMessageHandler : public content::WebUIMessageHandler { |
| public: |
| GcmInternalsUIMessageHandler(); |
| |
| GcmInternalsUIMessageHandler(const GcmInternalsUIMessageHandler&) = delete; |
| GcmInternalsUIMessageHandler& operator=(const GcmInternalsUIMessageHandler&) = |
| delete; |
| |
| ~GcmInternalsUIMessageHandler() override; |
| |
| // WebUIMessageHandler implementation. |
| void RegisterMessages() override; |
| void OnJavascriptDisallowed() override; |
| |
| private: |
| // Return all of the GCM related infos to the gcm-internals page by calling |
| // Javascript callback function |
| // |gcm-internals.returnInfo()|. |
| void ReturnResults(Profile* profile, |
| gcm::GCMProfileService* profile_service, |
| const gcm::GCMClient::GCMStatistics* stats); |
| |
| // Request all of the GCM related infos through gcm profile service. |
| void RequestAllInfo(const base::ListValue* args); |
| |
| // Enables/disables GCM activity recording through gcm profile service. |
| void SetRecording(const base::ListValue* args); |
| |
| // Callback function of the request for all gcm related infos. |
| void RequestGCMStatisticsFinished(const gcm::GCMClient::GCMStatistics& args); |
| |
| // Factory for creating references in callbacks. |
| base::WeakPtrFactory<GcmInternalsUIMessageHandler> weak_ptr_factory_{this}; |
| }; |
| |
| GcmInternalsUIMessageHandler::GcmInternalsUIMessageHandler() {} |
| |
| GcmInternalsUIMessageHandler::~GcmInternalsUIMessageHandler() {} |
| |
| void GcmInternalsUIMessageHandler::ReturnResults( |
| Profile* profile, |
| gcm::GCMProfileService* profile_service, |
| const gcm::GCMClient::GCMStatistics* stats) { |
| base::DictionaryValue results; |
| gcm_driver::SetGCMInternalsInfo(stats, profile_service, profile->GetPrefs(), |
| &results); |
| FireWebUIListener(gcm_driver::kSetGcmInternalsInfo, results); |
| } |
| |
| void GcmInternalsUIMessageHandler::RequestAllInfo( |
| const base::ListValue* args) { |
| AllowJavascript(); |
| if (args->GetList().size() != 1) { |
| NOTREACHED(); |
| return; |
| } |
| bool clear_logs = false; |
| if (!args->GetBoolean(0, &clear_logs)) { |
| NOTREACHED(); |
| return; |
| } |
| |
| gcm::GCMDriver::ClearActivityLogs clear_activity_logs = |
| clear_logs ? gcm::GCMDriver::CLEAR_LOGS : gcm::GCMDriver::KEEP_LOGS; |
| |
| Profile* profile = Profile::FromWebUI(web_ui()); |
| gcm::GCMProfileService* profile_service = |
| gcm::GCMProfileServiceFactory::GetForProfile(profile); |
| |
| if (!profile_service || !profile_service->driver()) { |
| ReturnResults(profile, NULL, NULL); |
| } else { |
| profile_service->driver()->GetGCMStatistics( |
| base::BindOnce( |
| &GcmInternalsUIMessageHandler::RequestGCMStatisticsFinished, |
| weak_ptr_factory_.GetWeakPtr()), |
| clear_activity_logs); |
| } |
| } |
| |
| void GcmInternalsUIMessageHandler::SetRecording(const base::ListValue* args) { |
| if (args->GetList().size() != 1) { |
| NOTREACHED(); |
| return; |
| } |
| bool recording = false; |
| if (!args->GetBoolean(0, &recording)) { |
| NOTREACHED(); |
| return; |
| } |
| |
| Profile* profile = Profile::FromWebUI(web_ui()); |
| gcm::GCMProfileService* profile_service = |
| gcm::GCMProfileServiceFactory::GetForProfile(profile); |
| |
| if (!profile_service) { |
| ReturnResults(profile, NULL, NULL); |
| return; |
| } |
| // Get fresh stats after changing recording setting. |
| profile_service->driver()->SetGCMRecording( |
| base::BindRepeating( |
| &GcmInternalsUIMessageHandler::RequestGCMStatisticsFinished, |
| weak_ptr_factory_.GetWeakPtr()), |
| recording); |
| } |
| |
| void GcmInternalsUIMessageHandler::RequestGCMStatisticsFinished( |
| const gcm::GCMClient::GCMStatistics& stats) { |
| Profile* profile = Profile::FromWebUI(web_ui()); |
| DCHECK(profile); |
| gcm::GCMProfileService* profile_service = |
| gcm::GCMProfileServiceFactory::GetForProfile(profile); |
| DCHECK(profile_service); |
| ReturnResults(profile, profile_service, &stats); |
| } |
| |
| void GcmInternalsUIMessageHandler::RegisterMessages() { |
| // It is safe to use base::Unretained here, since web_ui owns this message |
| // handler. |
| web_ui()->RegisterDeprecatedMessageCallback( |
| gcm_driver::kGetGcmInternalsInfo, |
| base::BindRepeating(&GcmInternalsUIMessageHandler::RequestAllInfo, |
| base::Unretained(this))); |
| web_ui()->RegisterDeprecatedMessageCallback( |
| gcm_driver::kSetGcmInternalsRecording, |
| base::BindRepeating(&GcmInternalsUIMessageHandler::SetRecording, |
| base::Unretained(this))); |
| } |
| |
| void GcmInternalsUIMessageHandler::OnJavascriptDisallowed() { |
| // Invalidate weak ptrs in order to cancel callbacks from the |
| // GCMProfileServiceFactory. If the page is being navigated away from, this |
| // prevents such callbacks from triggering a CHECK by trying to run JS code |
| // on some other page. If the page is refreshed, this prevents the callbacks |
| // from triggering a CHECK by trying to run JS code on the refreshed page when |
| // the JS side is not yet ready, which can lead to a broken UI experience. |
| weak_ptr_factory_.InvalidateWeakPtrs(); |
| } |
| |
| } // namespace |
| |
| GCMInternalsUI::GCMInternalsUI(content::WebUI* web_ui) |
| : content::WebUIController(web_ui) { |
| // Set up the chrome://gcm-internals source. |
| content::WebUIDataSource* html_source = |
| content::WebUIDataSource::Create(chrome::kChromeUIGCMInternalsHost); |
| |
| html_source->UseStringsJs(); |
| |
| // Add required resources. |
| html_source->AddResourcePath(gcm_driver::kGcmInternalsCSS, |
| IDR_GCM_DRIVER_GCM_INTERNALS_CSS); |
| html_source->AddResourcePath(gcm_driver::kGcmInternalsJS, |
| IDR_GCM_DRIVER_GCM_INTERNALS_JS); |
| html_source->SetDefaultResource(IDR_GCM_DRIVER_GCM_INTERNALS_HTML); |
| |
| Profile* profile = Profile::FromWebUI(web_ui); |
| content::WebUIDataSource::Add(profile, html_source); |
| |
| web_ui->AddMessageHandler(std::make_unique<GcmInternalsUIMessageHandler>()); |
| } |
| |
| GCMInternalsUI::~GCMInternalsUI() {} |