Add chrome://process-internals WebUI

This CL adds barebones implementation of chrome://process-internals
WebUI, which only shows the current Site Isolation mode and list
of origins isolated by policy or command line.

Bug: 850087
Change-Id: I14b8e20bc763488e8b4ea433599125c96c5ba8d3
Reviewed-on: https://chromium-review.googlesource.com/1091167
Commit-Queue: Nasko Oskov <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Cr-Commit-Position: refs/heads/master@{#566638}
diff --git a/content/BUILD.gn b/content/BUILD.gn
index 8ec381e..835bd6d 100644
--- a/content/BUILD.gn
+++ b/content/BUILD.gn
@@ -121,6 +121,7 @@
     "root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir),
   ]
   deps = [
+    "//content/browser/process_internals:mojo_bindings_js",
     "//content/public/app:browser_manifest",
     "//content/public/app:gpu_manifest",
     "//content/public/app:packaged_services_manifest",
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 7888e5f..3a8d5273 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -77,6 +77,7 @@
     "//content/browser/dom_storage:local_storage_proto",
     "//content/browser/notifications:notification_proto",
     "//content/browser/payments:payment_app_proto",
+    "//content/browser/process_internals:mojo_bindings",
     "//content/browser/service_worker:service_worker_proto",
     "//content/browser/speech/proto",
     "//content/common",
@@ -1218,6 +1219,10 @@
     "picture_in_picture/picture_in_picture_window_controller_impl.h",
     "presentation/presentation_service_impl.cc",
     "presentation/presentation_service_impl.h",
+    "process_internals/process_internals_handler_impl.cc",
+    "process_internals/process_internals_handler_impl.h",
+    "process_internals/process_internals_ui.cc",
+    "process_internals/process_internals_ui.h",
     "push_messaging/push_messaging_context.cc",
     "push_messaging/push_messaging_context.h",
     "push_messaging/push_messaging_manager.cc",
diff --git a/content/browser/process_internals/BUILD.gn b/content/browser/process_internals/BUILD.gn
new file mode 100644
index 0000000..fedd9d960
--- /dev/null
+++ b/content/browser/process_internals/BUILD.gn
@@ -0,0 +1,11 @@
+# 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("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojo_bindings") {
+  sources = [
+    "process_internals.mojom",
+  ]
+}
diff --git a/content/browser/process_internals/OWNERS b/content/browser/process_internals/OWNERS
new file mode 100644
index 0000000..08850f4
--- /dev/null
+++ b/content/browser/process_internals/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/content/browser/process_internals/process_internals.mojom b/content/browser/process_internals/process_internals.mojom
new file mode 100644
index 0000000..da65f0ff
--- /dev/null
+++ b/content/browser/process_internals/process_internals.mojom
@@ -0,0 +1,17 @@
+// 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.
+
+module mojom;
+
+// Interface used by chrome://process-internals to query data from the
+// browser process.
+interface ProcessInternalsHandler {
+
+  // Returns a string containing the currently active isolation modes.
+  GetIsolationMode() => (string mode);
+
+  // Returns a list of isolated origins in their serialized to string
+  // format. This avoids duplicating serialization code to JavaScript.
+  GetIsolatedOrigins() => (array<string> isolated_origins);
+};
diff --git a/content/browser/process_internals/process_internals_handler_impl.cc b/content/browser/process_internals/process_internals_handler_impl.cc
new file mode 100644
index 0000000..ae4fc6d
--- /dev/null
+++ b/content/browser/process_internals/process_internals_handler_impl.cc
@@ -0,0 +1,44 @@
+// 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 "content/browser/process_internals/process_internals_handler_impl.h"
+
+#include "content/browser/process_internals/process_internals.mojom.h"
+#include "content/public/browser/site_isolation_policy.h"
+#include "content/public/browser/web_contents.h"
+
+namespace content {
+
+ProcessInternalsHandlerImpl::ProcessInternalsHandlerImpl(
+    mojo::InterfaceRequest<::mojom::ProcessInternalsHandler> request)
+    : binding_(this, std::move(request)) {}
+
+ProcessInternalsHandlerImpl::~ProcessInternalsHandlerImpl() = default;
+
+void ProcessInternalsHandlerImpl::GetIsolationMode(
+    GetIsolationModeCallback callback) {
+  std::vector<base::StringPiece> modes;
+  if (SiteIsolationPolicy::UseDedicatedProcessesForAllSites())
+    modes.push_back("Site Per Process");
+  if (SiteIsolationPolicy::IsTopDocumentIsolationEnabled())
+    modes.push_back("Top Document Isolation");
+  if (SiteIsolationPolicy::AreIsolatedOriginsEnabled())
+    modes.push_back("Isolate Origins");
+
+  std::move(callback).Run(modes.empty() ? "Disabled"
+                                        : base::JoinString(modes, ", "));
+}
+
+void ProcessInternalsHandlerImpl::GetIsolatedOrigins(
+    GetIsolatedOriginsCallback callback) {
+  std::vector<url::Origin> origins_list =
+      SiteIsolationPolicy::GetIsolatedOrigins();
+  std::vector<std::string> origins;
+  for (size_t i = 0; i < origins_list.size(); ++i)
+    origins.push_back(origins_list[i].Serialize());
+
+  std::move(callback).Run(origins);
+}
+
+}  // namespace content
diff --git a/content/browser/process_internals/process_internals_handler_impl.h b/content/browser/process_internals/process_internals_handler_impl.h
new file mode 100644
index 0000000..3a8ee50
--- /dev/null
+++ b/content/browser/process_internals/process_internals_handler_impl.h
@@ -0,0 +1,35 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_PROCESS_INTERNALS_PROCESS_INTERNALS_HANDLER_IMPL_H_
+#define CONTENT_BROWSER_PROCESS_INTERNALS_PROCESS_INTERNALS_HANDLER_IMPL_H_
+
+#include "content/browser/process_internals/process_internals.mojom.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace content {
+
+// Implementation of the ProcessInternalsHandler interface, which is used to
+// communicate between the chrome://process-internals/ WebUI and the browser
+// process.
+class ProcessInternalsHandlerImpl : public ::mojom::ProcessInternalsHandler {
+ public:
+  ProcessInternalsHandlerImpl(
+      mojo::InterfaceRequest<::mojom::ProcessInternalsHandler> request);
+  ~ProcessInternalsHandlerImpl() override;
+
+  // mojom::ProcessInternalsHandler overrides:
+  void GetIsolationMode(GetIsolationModeCallback callback) override;
+  void GetIsolatedOrigins(GetIsolatedOriginsCallback callback) override;
+
+ private:
+  mojo::Binding<::mojom::ProcessInternalsHandler> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessInternalsHandlerImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_PROCESS_INTERNALS_PROCESS_INTERNALS_HANDLER_IMPL_H_
diff --git a/content/browser/process_internals/process_internals_ui.cc b/content/browser/process_internals/process_internals_ui.cc
new file mode 100644
index 0000000..8c3558c
--- /dev/null
+++ b/content/browser/process_internals/process_internals_ui.cc
@@ -0,0 +1,73 @@
+// 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 "content/browser/process_internals/process_internals_ui.h"
+
+#include <memory>
+
+#include "base/macros.h"
+#include "content/grit/content_resources.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "content/public/browser/web_ui_message_handler.h"
+#include "content/public/common/bindings_policy.h"
+#include "content/public/common/url_constants.h"
+
+#include "content/browser/process_internals/process_internals.mojom.h"
+#include "content/browser/process_internals/process_internals_handler_impl.h"
+
+#include "content/public/common/bindings_policy.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace content {
+
+ProcessInternalsUI::ProcessInternalsUI(WebUI* web_ui)
+    : WebUIController(web_ui), WebContentsObserver(web_ui->GetWebContents()) {
+  // Grant only Mojo WebUI bindings, since this WebUI will not use
+  // chrome.send().
+  web_ui->SetBindings(content::BINDINGS_POLICY_MOJO_WEB_UI);
+
+  // Create a WebUIDataSource to serve the HTML/JS files to the WebUI.
+  WebUIDataSource* source =
+      WebUIDataSource::Create(kChromeUIProcessInternalsHost);
+
+  source->AddResourcePath("process_internals.js", IDR_PROCESS_INTERNALS_JS);
+  source->AddResourcePath("process_internals.mojom.js",
+                          IDR_PROCESS_INTERNALS_MOJO_JS);
+  source->SetDefaultResource(IDR_PROCESS_INTERNALS_HTML);
+  source->UseGzip();
+
+  WebUIDataSource::Add(web_contents()->GetBrowserContext(), source);
+
+  AddHandlerToRegistry(
+      base::BindRepeating(&ProcessInternalsUI::BindProcessInternalsHandler,
+                          base::Unretained(this)));
+}
+
+ProcessInternalsUI::~ProcessInternalsUI() = default;
+
+void ProcessInternalsUI::BindProcessInternalsHandler(
+    ::mojom::ProcessInternalsHandlerRequest request) {
+  ui_handler_ =
+      std::make_unique<ProcessInternalsHandlerImpl>(std::move(request));
+}
+
+void ProcessInternalsUI::OnInterfaceRequestFromFrame(
+    content::RenderFrameHost* render_frame_host,
+    const std::string& interface_name,
+    mojo::ScopedMessagePipeHandle* interface_pipe) {
+  // This should not be requested by subframes, so terminate the renderer if
+  // it issues such a request.
+  if (render_frame_host->GetParent()) {
+    render_frame_host->GetProcess()->ShutdownForBadMessage(
+        content::RenderProcessHost::CrashReportMode::GENERATE_CRASH_DUMP);
+    return;
+  }
+
+  registry_.TryBindInterface(interface_name, interface_pipe);
+}
+
+}  // namespace content
diff --git a/content/browser/process_internals/process_internals_ui.h b/content/browser/process_internals/process_internals_ui.h
new file mode 100644
index 0000000..8c760bcf
--- /dev/null
+++ b/content/browser/process_internals/process_internals_ui.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_PROCESS_INTERNALS_PROCESS_INTERNALS_UI_H_
+#define CONTENT_BROWSER_PROCESS_INTERNALS_PROCESS_INTERNALS_UI_H_
+
+#include "content/browser/process_internals/process_internals.mojom.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_ui_controller.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+
+namespace content {
+
+// WebUI which handles serving the chrome://process-internals page.
+// TODO(nasko): Change the inheritance of this class to be from
+// MojoWebUIController, so the registry_ can be removed and properly
+// inherited from common base class for Mojo WebUIs.
+class ProcessInternalsUI : public WebUIController, public WebContentsObserver {
+ public:
+  explicit ProcessInternalsUI(WebUI* web_ui);
+  ~ProcessInternalsUI() override;
+
+  // content::WebContentsObserver implementation.
+  void OnInterfaceRequestFromFrame(
+      content::RenderFrameHost* render_frame_host,
+      const std::string& interface_name,
+      mojo::ScopedMessagePipeHandle* interface_pipe) override;
+
+  template <typename Binder>
+  void AddHandlerToRegistry(Binder binder) {
+    registry_.AddInterface(std::move(binder));
+  }
+  void BindProcessInternalsHandler(
+      ::mojom::ProcessInternalsHandlerRequest request);
+
+ private:
+  std::unique_ptr<::mojom::ProcessInternalsHandler> ui_handler_;
+  service_manager::BinderRegistry registry_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessInternalsUI);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_PROCESS_INTERNALS_PROCESS_INTERNALS_UI_H_
diff --git a/content/browser/resources/process/process_internals.html b/content/browser/resources/process/process_internals.html
new file mode 100644
index 0000000..9e5acb2
--- /dev/null
+++ b/content/browser/resources/process/process_internals.html
@@ -0,0 +1,16 @@
+<!-- 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.-->
+<!doctype html>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
+<head>
+  <meta charset="utf-8">
+  <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+  <script src="chrome://resources/js/mojo_bindings.js"></script>
+  <script src="process_internals.mojom.js"></script>
+  <script src='process_internals.js'></script>
+  <title>Process Model Internals</title>
+</head>
+<div id="site-isolation-mode">Site Isolation mode: <span id='isolation-mode'>unknown</span></div>
+<div id="isolated-origins-container">Isolated origins: <span id='isolated-origins'></span></div>
+</html>
diff --git a/content/browser/resources/process/process_internals.js b/content/browser/resources/process/process_internals.js
new file mode 100644
index 0000000..a745e29
--- /dev/null
+++ b/content/browser/resources/process/process_internals.js
@@ -0,0 +1,33 @@
+// 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.
+
+console.log('process internals initializing');
+
+(function() {
+'use strict';
+
+/**
+ * Reference to the backend.
+ * @type {mojom.ProcessInternalsHandlerPtr}
+ */
+var uiHandler = null;
+
+document.addEventListener('DOMContentLoaded', function() {
+  // Setup Mojo interface to the backend.
+  uiHandler = new mojom.ProcessInternalsHandlerPtr;
+  Mojo.bindInterface(
+      mojom.ProcessInternalsHandler.name,
+      mojo.makeRequest(uiHandler).handle);
+
+  // Get the Site Isolation mode and populate it.
+  uiHandler.getIsolationMode().then((response) => {
+    document.getElementById('isolation-mode').innerText = response.mode;
+  });
+  uiHandler.getIsolatedOrigins().then((response) => {
+    document.getElementById('isolated-origins').innerText =
+        response.isolatedOrigins.join(', ');
+  });
+});
+
+})();
diff --git a/content/browser/webui/content_web_ui_controller_factory.cc b/content/browser/webui/content_web_ui_controller_factory.cc
index ef2d46d..5fd3c07 100644
--- a/content/browser/webui/content_web_ui_controller_factory.cc
+++ b/content/browser/webui/content_web_ui_controller_factory.cc
@@ -12,6 +12,7 @@
 #include "content/browser/indexed_db/indexed_db_internals_ui.h"
 #include "content/browser/media/media_internals_ui.h"
 #include "content/browser/net/network_errors_listing_ui.h"
+#include "content/browser/process_internals/process_internals_ui.h"
 #include "content/browser/service_worker/service_worker_internals_ui.h"
 #include "content/browser/tracing/tracing_ui.h"
 #include "content/browser/webrtc/webrtc_internals_ui.h"
@@ -39,7 +40,8 @@
       url.host_piece() == kChromeUIServiceWorkerInternalsHost ||
       url.host_piece() == kChromeUIAccessibilityHost ||
       url.host_piece() == kChromeUIAppCacheInternalsHost ||
-      url.host_piece() == kChromeUINetworkErrorsListingHost) {
+      url.host_piece() == kChromeUINetworkErrorsListingHost ||
+      url.host_piece() == kChromeUIProcessInternalsHost) {
     return const_cast<ContentWebUIControllerFactory*>(this);
   }
   return WebUI::kNoWebUI;
@@ -84,6 +86,8 @@
 #endif
   if (url.host_piece() == kChromeUIWebRTCInternalsHost)
     return std::make_unique<WebRTCInternalsUI>(web_ui);
+  if (url.host_piece() == kChromeUIProcessInternalsHost)
+    return std::make_unique<ProcessInternalsUI>(web_ui);
 
   return nullptr;
 }
diff --git a/content/content_resources.grd b/content/content_resources.grd
index 962620e6..5c3268a 100644
--- a/content/content_resources.grd
+++ b/content/content_resources.grd
@@ -39,6 +39,9 @@
       <include name="IDR_NETWORK_ERROR_LISTING_HTML" file="browser/resources/net/network_errors_listing.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_NETWORK_ERROR_LISTING_JS" file="browser/resources/net/network_errors_listing.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_NETWORK_ERROR_LISTING_CSS" file="browser/resources/net/network_errors_listing.css" flattenhtml="true" type="BINDATA" />
+      <include name="IDR_PROCESS_INTERNALS_HTML" file="browser/resources/process/process_internals.html" flattenhtml="true" allowexternalscript="true" compress="gzip" type="BINDATA" />
+      <include name="IDR_PROCESS_INTERNALS_MOJO_JS" file="${root_gen_dir}/content/browser/process_internals/process_internals.mojom.js" use_base_dir="false" type="BINDATA" compress="gzip" />
+      <include name="IDR_PROCESS_INTERNALS_JS" file="browser/resources/process/process_internals.js" flattenhtml="true" compress="gzip" type="BINDATA" />
       <include name="IDR_SERVICE_WORKER_INTERNALS_HTML" file="browser/resources/service_worker/serviceworker_internals.html" flattenhtml="true" allowexternalscript="true" compress="gzip" type="BINDATA" />
       <include name="IDR_SERVICE_WORKER_INTERNALS_JS" file="browser/resources/service_worker/serviceworker_internals.js" flattenhtml="true" compress="gzip" type="BINDATA" />
       <include name="IDR_SERVICE_WORKER_INTERNALS_CSS" file="browser/resources/service_worker/serviceworker_internals.css" flattenhtml="true" compress="gzip" type="BINDATA" />
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index 9d840576..e146e6e 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -193,6 +193,7 @@
           "media.mojom.MediaMetricsProvider",
           "media.mojom.RemoterFactory",
           "media.mojom.Renderer",
+          "mojom.ProcessInternalsHandler",
           "network.mojom.RestrictedCookieManager",
           "network.mojom.WebSocket",
           "password_manager.mojom.CredentialManager",
diff --git a/content/public/common/url_constants.cc b/content/public/common/url_constants.cc
index ece77d538..e85d54e 100644
--- a/content/public/common/url_constants.cc
+++ b/content/public/common/url_constants.cc
@@ -32,6 +32,7 @@
 const char kChromeUIMemoryExhaustHost[] = "memory-exhaust";
 const char kChromeUINetworkErrorHost[] = "network-error";
 const char kChromeUINetworkErrorsListingHost[] = "network-errors";
+const char kChromeUIProcessInternalsHost[] = "process-internals";
 const char kChromeUIResourcesHost[] = "resources";
 const char kChromeUIServiceWorkerInternalsHost[] = "serviceworker-internals";
 const char kChromeUITracingHost[] = "tracing";
@@ -54,6 +55,7 @@
 const char kChromeUINetworkErrorsListingURL[] = "chrome://network-errors/";
 const char kChromeUIPpapiFlashCrashURL[] = "chrome://ppapiflashcrash/";
 const char kChromeUIPpapiFlashHangURL[] = "chrome://ppapiflashhang/";
+const char kChromeUIProcessInternalsURL[] = "chrome://process-internals";
 #if defined(OS_ANDROID)
 const char kChromeUIGpuJavaCrashURL[] = "chrome://gpu-java-crash/";
 #endif
diff --git a/content/public/common/url_constants.h b/content/public/common/url_constants.h
index 67009bed..0da500f 100644
--- a/content/public/common/url_constants.h
+++ b/content/public/common/url_constants.h
@@ -41,6 +41,7 @@
 CONTENT_EXPORT extern const char kChromeUIMemoryExhaustHost[];
 CONTENT_EXPORT extern const char kChromeUINetworkErrorHost[];
 CONTENT_EXPORT extern const char kChromeUINetworkErrorsListingHost[];
+CONTENT_EXPORT extern const char kChromeUIProcessInternalsHost[];
 CONTENT_EXPORT extern const char kChromeUIResourcesHost[];
 CONTENT_EXPORT extern const char kChromeUIServiceWorkerInternalsHost[];
 CONTENT_EXPORT extern const char kChromeUITracingHost[];
@@ -64,6 +65,7 @@
 CONTENT_EXPORT extern const char kChromeUINetworkErrorURL[];
 CONTENT_EXPORT extern const char kChromeUIPpapiFlashCrashURL[];
 CONTENT_EXPORT extern const char kChromeUIPpapiFlashHangURL[];
+CONTENT_EXPORT extern const char kChromeUIProcessInternalsURL[];
 #if defined(OS_ANDROID)
 CONTENT_EXPORT extern const char kChromeUIGpuJavaCrashURL[];
 #endif