Commit 26fefaa1 authored by Moe Ahmadi's avatar Moe Ahmadi Committed by Commit Bot

[IOS][UKM] Modifies UKM internals page (chrome://ukm) to use WebUI.

- Modifies iOS implementation of chrome://ukm to use WebUI.
- Refactors HTML/JS resources to be used in iOS.
- Removes method in ukm::UkmDebugDataExtractor that returns HTML debug data.
- Adds helper methods to resolve/reject Promises to WebUIIOS.

Bug: 843181
Cq-Include-Trybots: luci.chromium.try:ios-simulator-full-configs;master.tryserver.chromium.mac:ios-simulator-cronet
Change-Id: I008ce1beb8d35dd9d4a7fc482990f06e3095f16a
Reviewed-on: https://chromium-review.googlesource.com/1147241
Commit-Queue: Moe Ahmadi <mahmadi@chromium.org>
Reviewed-by: default avatarPeter Lee <pkl@chromium.org>
Reviewed-by: default avatarBernhard Bauer <bauerb@chromium.org>
Reviewed-by: default avatarAlexei Svitkine <asvitkine@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577569}
parent 0be56f3a
......@@ -143,8 +143,8 @@
<include name="IDR_DOWNLOAD_INTERNALS_JS" file="resources\download_internals\download_internals.js" type="BINDATA" compress="gzip" />
<include name="IDR_DOWNLOAD_INTERNALS_BROWSER_PROXY_JS" file="resources\download_internals\download_internals_browser_proxy.js" type="BINDATA" compress="gzip" />
<include name="IDR_DOWNLOAD_INTERNALS_VISUALS_JS" file="resources\download_internals\download_internals_visuals.js" type="BINDATA" compress="gzip" />
<include name="IDR_UKM_INTERNALS_HTML" file="resources/ukm/ukm_internals.html" flattenhtml="true" allowexternalscript="true" compress="gzip" type="BINDATA" />
<include name="IDR_UKM_INTERNALS_JS" file="resources/ukm/ukm_internals.js" flattenhtml="true" compress="gzip" type="BINDATA" />
<include name="IDR_UKM_INTERNALS_HTML" file="../../components/ukm/debug/ukm_internals.html" flattenhtml="true" allowexternalscript="true" compress="gzip" type="BINDATA" />
<include name="IDR_UKM_INTERNALS_JS" file="../../components/ukm/debug/ukm_internals.js" flattenhtml="true" compress="gzip" type="BINDATA" />
<if expr="not is_android">
<include name="IDR_MD_DOWNLOADS_1X_INCOGNITO_MARKER_PNG" file="resources\md_downloads\1x\incognito_marker.png" type="BINDATA" />
<include name="IDR_MD_DOWNLOADS_2X_INCOGNITO_MARKER_PNG" file="resources\md_downloads\2x\incognito_marker.png" type="BINDATA" />
......
# Copyright 2018 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.
import("//third_party/closure_compiler/compile_js.gni")
js_type_check("closure_compile") {
deps = [
":ukm_internals",
]
}
js_library("ukm_internals") {
deps = [
"//ui/webui/resources/js:cr",
"//ui/webui/resources/js:util",
]
}
......@@ -85,6 +85,8 @@ void UkmMessageHandler::RegisterMessages() {
} // namespace
// Changes to this class should be in sync with its iOS equivalent
// ios/chrome/browser/ui/webui/ukm_internals_ui.cc
UkmInternalsUI::UkmInternalsUI(content::WebUI* web_ui)
: content::WebUIController(web_ui) {
ukm::UkmService* ukm_service =
......
......@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//third_party/closure_compiler/compile_js.gni")
source_set("util") {
sources = [
"ukm_debug_data_extractor.cc",
......@@ -13,3 +15,16 @@ source_set("util") {
"//services/metrics/public/cpp:ukm_builders",
]
}
js_type_check("closure_compile") {
deps = [
":ukm_internals",
]
}
js_library("ukm_internals") {
deps = [
"//ui/webui/resources/js:cr",
"//ui/webui/resources/js:util",
]
}
......@@ -114,74 +114,5 @@ base::Value UkmDebugDataExtractor::GetStructuredData(
return std::move(ukm_data);
}
// static
std::string UkmDebugDataExtractor::GetHTMLData(const UkmService* ukm_service) {
std::string output;
output.append(R"""(<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy"
content="object-src 'none'; script-src 'none'">
<title>UKM Debug</title>
</head>
<body>
<h1>UKM Debug page</h1>
)""");
if (ukm_service) {
output.append(
// 'id' attribute set so tests can extract this element.
base::StringPrintf("<p>IsEnabled:<span id='state'>%s</span></p>",
ukm_service->recording_enabled_ ? "True" : "False"));
output.append(base::StringPrintf("<p>ClientId:<span id='clientid'>%" PRIu64
"</span></p>",
ukm_service->client_id_));
output.append(
base::StringPrintf("<p>SessionId:%d</p>", ukm_service->session_id_));
const auto& decode_map = ukm_service->decode_map_;
std::map<SourceId, SourceData> source_data;
for (const auto& kv : ukm_service->recordings_.sources) {
source_data[kv.first].source = kv.second.get();
}
for (const auto& v : ukm_service->recordings_.entries) {
source_data[v->source_id].entries.push_back(v.get());
}
output.append("<h2>Sources</h2>");
for (const auto& kv : source_data) {
const auto* src = kv.second.source;
if (src) {
output.append(base::StringPrintf("<h3>Id:%" PRId64 " Url:%s</h3>",
src->id(), src->url().spec().c_str()));
} else {
output.append(base::StringPrintf("<h3>Id:%" PRId64 "</h3>", kv.first));
}
for (auto* entry : kv.second.entries) {
const auto it = decode_map.find(entry->event_hash);
if (it == decode_map.end()) {
output.append(base::StringPrintf(
"<h4>Entry: Unknown %" PRIu64 "</h4>", entry->event_hash));
continue;
}
output.append(base::StringPrintf("<h4>Entry:%s</h4>", it->second.name));
for (const auto& metric : entry->metrics) {
output.append(base::StringPrintf(
"<h5>Metric:%s Value:%" PRId64 "</h5>",
GetName(it->second, metric.first).c_str(), metric.second));
}
}
}
}
output.append(R"""(
</body>
</html>
)""");
return output;
}
} // namespace debug
} // namespace ukm
......@@ -26,10 +26,6 @@ class UkmDebugDataExtractor {
// Returns UKM data structured in a DictionaryValue.
static base::Value GetStructuredData(const UkmService* ukm_service);
// Returns UKM data as an HTML page.
// TODO(etiennep): Use GetStructuredData() instead.
static std::string GetHTMLData(const UkmService* ukm_service);
private:
DISALLOW_COPY_AND_ASSIGN(UkmDebugDataExtractor);
};
......
......@@ -2,18 +2,54 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @typedef {{
* name: string,
* value: string
* }}
*/
var Metric;
/**
* @typedef {{
* name: string,
* metrics: !Array<!Metric>
* }}
*/
var UkmEntry;
/**
* @typedef {{
* url: string,
* id: string,
* entries: !Array<UkmEntry>,
* }}
*/
var UkmDataSource;
/**
* The Ukm data sent from the browser.
* @typedef {{
* state: boolean,
* client_id: string,
* session_id: string,
* sources: !Array<!UkmDataSource>,
* }}
*/
var UkmData;
/**
* Fetches data from the Ukm service and updates the DOM to display it as a
* list.
*/
function updateUkmData() {
cr.sendWithPromise('requestUkmData').then((ukmData) => {
$('state').innerText = ukmData.state ? 'True' : 'False';
$('clientid').innerText = ukmData.client_id;
$('sessionid').innerText = ukmData.session_id;
cr.sendWithPromise('requestUkmData').then((/** @type {UkmData} */ data) => {
$('state').innerText = data.state ? 'True' : 'False';
$('clientid').innerText = data.client_id;
$('sessionid').innerText = data.session_id;
sourceDiv = $('sources');
for (const source of ukmData.sources) {
let sourceDiv = $('sources');
for (const source of data.sources) {
const sourceElement = document.createElement('h3');
if (source.url !== undefined)
sourceElement.innerText = `Id: ${source.id} Url: ${source.url}`;
......
......@@ -11,6 +11,8 @@
<include name="IDR_IOS_OMAHA_HTML" file="omaha/omaha.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" />
<include name="IDR_IOS_OMAHA_JS" file="omaha/omaha.js" type="BINDATA" compress="gzip" />
<include name="IDR_CHROME_BROWSER_MANIFEST_OVERLAY" file="${root_gen_dir}/ios/chrome/app/chrome_browser_manifest_overlay.json" use_base_dir="false" type="BINDATA" />
<include name="IDR_IOS_UKM_INTERNALS_HTML" file="../../../../components/ukm/debug/ukm_internals.html" flattenhtml="true" allowexternalscript="true" compress="gzip" type="BINDATA" />
<include name="IDR_IOS_UKM_INTERNALS_JS" file="../../../../components/ukm/debug/ukm_internals.js" flattenhtml="true" compress="gzip" type="BINDATA" />
</includes>
</release>
</grit>
......@@ -20,8 +20,8 @@ source_set("webui") {
"suggestions_ui.h",
"terms_ui.h",
"terms_ui.mm",
"url_keyed_metrics_ui.cc",
"url_keyed_metrics_ui.h",
"ukm_internals_ui.cc",
"ukm_internals_ui.h",
"version_handler.cc",
"version_handler.h",
"version_ui.h",
......@@ -46,6 +46,7 @@ source_set("webui") {
"//components/version_info",
"//components/version_ui",
"//google_apis",
"//ios/chrome/app/resources:ios_resources",
"//ios/chrome/app/strings",
"//ios/chrome/browser",
"//ios/chrome/browser/browser_state",
......
......@@ -20,7 +20,7 @@
#include "ios/chrome/browser/ui/webui/suggestions_ui.h"
#include "ios/chrome/browser/ui/webui/sync_internals/sync_internals_ui.h"
#include "ios/chrome/browser/ui/webui/terms_ui.h"
#include "ios/chrome/browser/ui/webui/url_keyed_metrics_ui.h"
#include "ios/chrome/browser/ui/webui/ukm_internals_ui.h"
#include "ios/chrome/browser/ui/webui/version_ui.h"
#include "url/gurl.h"
......@@ -91,7 +91,7 @@ WebUIIOSFactoryFunction GetWebUIIOSFactoryFunction(WebUIIOS* web_ui,
if (url_host == kChromeUIFlagsHost)
return &NewWebUIIOS<FlagsUI>;
if (url_host == kChromeUIURLKeyedMetricsHost)
return &NewWebUIIOSWithHost<URLKeyedMetricsUI>;
return &NewWebUIIOS<UkmInternalsUI>;
return nullptr;
}
......
// Copyright 2018 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 "ios/chrome/browser/ui/webui/ukm_internals_ui.h"
#include <string>
#include "base/memory/ref_counted_memory.h"
#include "components/metrics_services_manager/metrics_services_manager.h"
#include "components/ukm/debug/ukm_debug_data_extractor.h"
#include "components/ukm/ukm_service.h"
#include "ios/chrome/browser/application_context.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/chrome_url_constants.h"
#include "ios/chrome/grit/ios_resources.h"
#include "ios/web/public/url_data_source_ios.h"
#include "ios/web/public/web_ui_ios_data_source.h"
#include "ios/web/public/webui/web_ui_ios.h"
#include "ios/web/public/webui/web_ui_ios_message_handler.h"
namespace {
web::WebUIIOSDataSource* CreateUkmInternalsUIHTMLSource() {
web::WebUIIOSDataSource* source =
web::WebUIIOSDataSource::Create(kChromeUIURLKeyedMetricsHost);
source->AddResourcePath("ukm_internals.js", IDR_IOS_UKM_INTERNALS_JS);
source->SetDefaultResource(IDR_IOS_UKM_INTERNALS_HTML);
source->UseGzip();
return source;
}
// The handler for Javascript messages for the chrome://ukm/ page.
class UkmMessageHandler : public web::WebUIIOSMessageHandler {
public:
explicit UkmMessageHandler(const ukm::UkmService* ukm_service);
~UkmMessageHandler() override;
// web::WebUIIOSMessageHandler implementation.
void RegisterMessages() override;
private:
void HandleRequestUkmData(const base::ListValue* args);
const ukm::UkmService* ukm_service_;
DISALLOW_COPY_AND_ASSIGN(UkmMessageHandler);
};
UkmMessageHandler::UkmMessageHandler(const ukm::UkmService* ukm_service)
: ukm_service_(ukm_service) {}
UkmMessageHandler::~UkmMessageHandler() {}
void UkmMessageHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback(
"requestUkmData",
base::BindRepeating(&UkmMessageHandler::HandleRequestUkmData,
base::Unretained(this)));
}
void UkmMessageHandler::HandleRequestUkmData(const base::ListValue* args) {
base::Value ukm_debug_data =
ukm::debug::UkmDebugDataExtractor::GetStructuredData(ukm_service_);
std::string callback_id;
args->GetString(0, &callback_id);
web_ui()->ResolveJavascriptCallback(base::Value(callback_id),
std::move(ukm_debug_data));
}
} // namespace
// Changes to this class should be in sync with its non-iOS equivalent
// chrome/browser/ui/webui/ukm/ukm_internals_ui.cc
UkmInternalsUI::UkmInternalsUI(web::WebUIIOS* web_ui)
: web::WebUIIOSController(web_ui) {
ukm::UkmService* ukm_service =
GetApplicationContext()->GetMetricsServicesManager()->GetUkmService();
web_ui->AddMessageHandler(std::make_unique<UkmMessageHandler>(ukm_service));
// Set up the chrome://ukm/ source.
web::WebUIIOSDataSource::Add(ios::ChromeBrowserState::FromWebUIIOS(web_ui),
CreateUkmInternalsUIHTMLSource());
}
UkmInternalsUI::~UkmInternalsUI() {}
......@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_WEBUI_URL_KEYED_METRICS_UI_H_
#define IOS_CHROME_BROWSER_UI_WEBUI_URL_KEYED_METRICS_UI_H_
#ifndef IOS_CHROME_BROWSER_UI_WEBUI_UKM_INTERNALS_UI_H_
#define IOS_CHROME_BROWSER_UI_WEBUI_UKM_INTERNALS_UI_H_
#include "base/macros.h"
#include "ios/web/public/webui/web_ui_ios_controller.h"
......@@ -13,13 +13,13 @@ class WebUIIOS;
}
// The WebUI controller for chrome://ukm.
class URLKeyedMetricsUI : public web::WebUIIOSController {
class UkmInternalsUI : public web::WebUIIOSController {
public:
URLKeyedMetricsUI(web::WebUIIOS* web_ui, const std::string& name);
~URLKeyedMetricsUI() override;
explicit UkmInternalsUI(web::WebUIIOS* web_ui);
~UkmInternalsUI() override;
private:
DISALLOW_COPY_AND_ASSIGN(URLKeyedMetricsUI);
DISALLOW_COPY_AND_ASSIGN(UkmInternalsUI);
};
#endif // IOS_CHROME_BROWSER_UI_WEBUI_URL_KEYED_METRICS_UI_H_
#endif // IOS_CHROME_BROWSER_UI_WEBUI_UKM_INTERNALS_UI_H_
// Copyright 2018 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 "ios/chrome/browser/ui/webui/url_keyed_metrics_ui.h"
#include <string>
#include "base/memory/ref_counted_memory.h"
#include "components/metrics_services_manager/metrics_services_manager.h"
#include "components/ukm/debug/ukm_debug_data_extractor.h"
#include "components/ukm/ukm_service.h"
#include "ios/chrome/browser/application_context.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/web/public/url_data_source_ios.h"
namespace {
class URLKeyedMetricsUIHTMLSource : public web::URLDataSourceIOS {
public:
// Construct a data source for the specified |source_name|.
explicit URLKeyedMetricsUIHTMLSource(const std::string& source_name);
// web::URLDataSourceIOS implementation.
std::string GetSource() const override;
void StartDataRequest(
const std::string& path,
const web::URLDataSourceIOS::GotDataCallback& callback) override;
std::string GetMimeType(const std::string& path) const override;
bool ShouldDenyXFrameOptions() const override;
private:
~URLKeyedMetricsUIHTMLSource() override;
ukm::UkmService* GetUkmService();
std::string source_name_;
DISALLOW_IMPLICIT_CONSTRUCTORS(URLKeyedMetricsUIHTMLSource);
};
} // namespace
// URLKeyedMetricsUIHTMLSource -------------------------------------------------
URLKeyedMetricsUIHTMLSource::URLKeyedMetricsUIHTMLSource(
const std::string& source_name)
: source_name_(source_name) {}
URLKeyedMetricsUIHTMLSource::~URLKeyedMetricsUIHTMLSource() {}
std::string URLKeyedMetricsUIHTMLSource::GetSource() const {
return source_name_;
}
void URLKeyedMetricsUIHTMLSource::StartDataRequest(
const std::string& path,
const web::URLDataSourceIOS::GotDataCallback& callback) {
// TODO(crbug.com/843181): Use GetStructuredData() instead.
std::string data =
ukm::debug::UkmDebugDataExtractor::GetHTMLData(GetUkmService());
callback.Run(base::RefCountedString::TakeString(&data));
}
std::string URLKeyedMetricsUIHTMLSource::GetMimeType(
const std::string& path) const {
return "text/html";
}
bool URLKeyedMetricsUIHTMLSource::ShouldDenyXFrameOptions() const {
return web::URLDataSourceIOS::ShouldDenyXFrameOptions();
}
ukm::UkmService* URLKeyedMetricsUIHTMLSource::GetUkmService() {
return GetApplicationContext()->GetMetricsServicesManager()->GetUkmService();
}
// URLKeyedMetricsUI -----------------------------------------------------------
URLKeyedMetricsUI::URLKeyedMetricsUI(web::WebUIIOS* web_ui,
const std::string& name)
: web::WebUIIOSController(web_ui) {
web::URLDataSourceIOS::Add(ios::ChromeBrowserState::FromWebUIIOS(web_ui),
new URLKeyedMetricsUIHTMLSource(name));
}
URLKeyedMetricsUI::~URLKeyedMetricsUI() {}
......@@ -81,6 +81,18 @@ class WebUIIOS {
virtual void CallJavascriptFunction(
const std::string& function_name,
const std::vector<const base::Value*>& args) = 0;
// Helper method for responding to Javascript requests initiated with
// cr.sendWithPromise() (defined in cr.js) for the case where the returned
// promise should be resolved (request succeeded).
virtual void ResolveJavascriptCallback(const base::Value& callback_id,
const base::Value& response) = 0;
// Helper method for responding to Javascript requests initiated with
// cr.sendWithPromise() (defined in cr.js), for the case where the returned
// promise should be rejected (request failed).
virtual void RejectJavascriptCallback(const base::Value& callback_id,
const base::Value& response) = 0;
};
} // namespace web
......
......@@ -56,6 +56,10 @@ class WebUIIOSImpl : public web::WebUIIOS,
void CallJavascriptFunction(
const std::string& function_name,
const std::vector<const base::Value*>& args) override;
void ResolveJavascriptCallback(const base::Value& callback_id,
const base::Value& response) override;
void RejectJavascriptCallback(const base::Value& callback_id,
const base::Value& response) override;
private:
// Executes JavaScript asynchronously on the page.
......
......@@ -121,6 +121,20 @@ void WebUIIOSImpl::CallJavascriptFunction(
ExecuteJavascript(GetJavascriptCall(function_name, args));
}
void WebUIIOSImpl::ResolveJavascriptCallback(const base::Value& callback_id,
const base::Value& response) {
// cr.webUIResponse is a global JS function exposed from cr.js.
CallJavascriptFunction("cr.webUIResponse", callback_id, base::Value(true),
response);
}
void WebUIIOSImpl::RejectJavascriptCallback(const base::Value& callback_id,
const base::Value& response) {
// cr.webUIResponse is a global JS function exposed from cr.js.
CallJavascriptFunction("cr.webUIResponse", callback_id, base::Value(false),
response);
}
void WebUIIOSImpl::RegisterMessageCallback(const std::string& message,
const MessageCallback& callback) {
message_callbacks_.insert(std::make_pair(message, callback));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment