[DIPS] Add ability to check the state of the DIPS feature in Devtools

This CL adds a chrome devtools protocol implementation of a method to
check the state of a feature flag.

The method currently supports checking that the DIPS feature is enabled,
its `delete` param is set to true, and its `triggering_action` param is
not set to `none`. If used to check an unsupported feature's state, it
falls through to the content/ version of the method.

This CL also renames the `SystemInfoHandler` defined in
//chrome/browser/ui/webui/system_info_ui.cc to `SystemInfoUIHandler` to
avoid naming collisions.

Bug: 1432303
Change-Id: I0ba0614cfd88f13e33acfef31cef5c0d949c0abf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4514036
Reviewed-by: Andrey Kosyakov <[email protected]>
Reviewed-by: John Lee <[email protected]>
Commit-Queue: Joshua Hood <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1141831}
diff --git a/chrome/browser/devtools/BUILD.gn b/chrome/browser/devtools/BUILD.gn
index c7fb2ad..3259afa2 100644
--- a/chrome/browser/devtools/BUILD.gn
+++ b/chrome/browser/devtools/BUILD.gn
@@ -32,6 +32,8 @@
     "protocol/security.h",
     "protocol/storage.cc",
     "protocol/storage.h",
+    "protocol/system_info.cc",
+    "protocol/system_info.h",
     "protocol/target.cc",
     "protocol/target.h",
   ]
@@ -269,6 +271,8 @@
       "protocol/security_handler.h",
       "protocol/storage_handler.cc",
       "protocol/storage_handler.h",
+      "protocol/system_info_handler.cc",
+      "protocol/system_info_handler.h",
       "protocol/target_handler.cc",
       "protocol/target_handler.h",
     ]
diff --git a/chrome/browser/devtools/chrome_devtools_session.cc b/chrome/browser/devtools/chrome_devtools_session.cc
index ebc1362..68a5ce0 100644
--- a/chrome/browser/devtools/chrome_devtools_session.cc
+++ b/chrome/browser/devtools/chrome_devtools_session.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/devtools/protocol/page_handler.h"
 #include "chrome/browser/devtools/protocol/security_handler.h"
 #include "chrome/browser/devtools/protocol/storage_handler.h"
+#include "chrome/browser/devtools/protocol/system_info_handler.h"
 #include "chrome/browser/devtools/protocol/target_handler.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/devtools_agent_host_client.h"
@@ -86,6 +87,10 @@
     browser_handler_ =
         std::make_unique<BrowserHandler>(&dispatcher_, agent_host->GetId());
   }
+  if (IsDomainAvailableToUntrustedClient<SystemInfoHandler>() ||
+      channel->GetClient()->IsTrusted()) {
+    system_info_handler_ = std::make_unique<SystemInfoHandler>(&dispatcher_);
+  }
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   window_manager_handler_ =
       std::make_unique<WindowManagerHandler>(&dispatcher_);
diff --git a/chrome/browser/devtools/chrome_devtools_session.h b/chrome/browser/devtools/chrome_devtools_session.h
index 08b642a..1c7370c 100644
--- a/chrome/browser/devtools/chrome_devtools_session.h
+++ b/chrome/browser/devtools/chrome_devtools_session.h
@@ -25,6 +25,7 @@
 class PageHandler;
 class SecurityHandler;
 class StorageHandler;
+class SystemInfoHandler;
 class TargetHandler;
 class WindowManagerHandler;
 
@@ -67,6 +68,7 @@
   std::unique_ptr<PageHandler> page_handler_;
   std::unique_ptr<SecurityHandler> security_handler_;
   std::unique_ptr<StorageHandler> storage_handler_;
+  std::unique_ptr<SystemInfoHandler> system_info_handler_;
   std::unique_ptr<TargetHandler> target_handler_;
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   std::unique_ptr<WindowManagerHandler> window_manager_handler_;
diff --git a/chrome/browser/devtools/inspector_protocol_config.json b/chrome/browser/devtools/inspector_protocol_config.json
index 4e211a38..8370400 100644
--- a/chrome/browser/devtools/inspector_protocol_config.json
+++ b/chrome/browser/devtools/inspector_protocol_config.json
@@ -42,7 +42,12 @@
                 "domain": "Storage",
                 "include": ["runBounceTrackingMitigations"],
                 "async": ["runBounceTrackingMitigations"]
-            }, {
+            },
+            {
+                "domain": "SystemInfo",
+                "include": ["getFeatureState"]
+            },
+            {
                 "domain": "Autofill",
                 "async": [ "trigger" ]
             }
diff --git a/chrome/browser/devtools/protocol/devtools_protocol_browsertest.cc b/chrome/browser/devtools/protocol/devtools_protocol_browsertest.cc
index 2cc120c..c091f59 100644
--- a/chrome/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/chrome/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -384,6 +384,63 @@
   EXPECT_THAT(deleted_sites, testing::ElementsAre("example.test"));
 }
 
+class DIPSStatusDevToolsProtocolTest
+    : public DevToolsProtocolTest,
+      public testing::WithParamInterface<std::tuple<bool, bool, std::string>> {
+  // The fields of `GetParam()` indicate/control the following:
+  //   `std::get<0>(GetParam())` => `dips::kFeature`
+  //   `std::get<1>(GetParam())` => `dips::kDeletionEnabled`
+  //   `std::get<2>(GetParam())` => `dips::kTriggeringAction`
+  //
+  // In order for Bounce Tracking Mitigations to take effect, `kFeature` must
+  // be true/enabled, `kDeletionEnabled` must be true, and `kTriggeringAction`
+  // must NOT be `none`.
+  //
+  // Note: Bounce Tracking Mitigations issues only report sites that would
+  // be affected when `kTriggeringAction` is set to 'stateful_bounce'.
+
+ protected:
+  void SetUp() override {
+    if (std::get<0>(GetParam())) {
+      scoped_feature_list_.InitAndEnableFeatureWithParameters(
+          dips::kFeature,
+          {{"delete", (std::get<1>(GetParam()) ? "true" : "false")},
+           {"triggering_action", std::get<2>(GetParam())}});
+    } else {
+      scoped_feature_list_.InitAndDisableFeature(dips::kFeature);
+    }
+
+    DevToolsProtocolTest::SetUp();
+  }
+
+  bool ShouldBeEnabled() {
+    return (std::get<0>(GetParam()) && std::get<1>(GetParam()) &&
+            (std::get<2>(GetParam()) != "none"));
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_P(DIPSStatusDevToolsProtocolTest,
+                       TrueWhenEnabledAndDeleting) {
+  AttachToBrowserTarget();
+
+  base::Value::Dict paramsDIPS;
+  paramsDIPS.Set("featureState", "DIPS");
+
+  SendCommand("SystemInfo.getFeatureState", std::move(paramsDIPS));
+  EXPECT_EQ(result()->FindBool("featureEnabled"), ShouldBeEnabled());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    DIPSStatusDevToolsProtocolTest,
+    ::testing::Combine(
+        ::testing::Bool(),
+        ::testing::Bool(),
+        ::testing::Values("none", "storage", "bounce", "stateful_bounce")));
+
 using DevToolsProtocolTest_AppId = DevToolsProtocolTest;
 
 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest_AppId, ReturnsManifestAppId) {
diff --git a/chrome/browser/devtools/protocol/system_info_handler.cc b/chrome/browser/devtools/protocol/system_info_handler.cc
new file mode 100644
index 0000000..8788073
--- /dev/null
+++ b/chrome/browser/devtools/protocol/system_info_handler.cc
@@ -0,0 +1,30 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/devtools/protocol/system_info_handler.h"
+
+#include "chrome/browser/dips/dips_features.h"
+#include "chrome/browser/dips/dips_utils.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
+
+SystemInfoHandler::SystemInfoHandler(protocol::UberDispatcher* dispatcher) {
+  protocol::SystemInfo::Dispatcher::wire(dispatcher, this);
+}
+
+SystemInfoHandler::~SystemInfoHandler() = default;
+
+protocol::Response SystemInfoHandler::GetFeatureState(
+    const std::string& in_featureState,
+    bool* featureEnabled) {
+  if (in_featureState == "DIPS") {
+    *featureEnabled =
+        base::FeatureList::IsEnabled(dips::kFeature) &&
+        dips::kDeletionEnabled.Get() &&
+        (dips::kTriggeringAction.Get() != DIPSTriggeringAction::kNone);
+    return protocol::Response::Success();
+  }
+
+  return protocol::Response::FallThrough();
+}
diff --git a/chrome/browser/devtools/protocol/system_info_handler.h b/chrome/browser/devtools/protocol/system_info_handler.h
new file mode 100644
index 0000000..448ff2f5
--- /dev/null
+++ b/chrome/browser/devtools/protocol/system_info_handler.h
@@ -0,0 +1,28 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_DEVTOOLS_PROTOCOL_SYSTEM_INFO_HANDLER_H_
+#define CHROME_BROWSER_DEVTOOLS_PROTOCOL_SYSTEM_INFO_HANDLER_H_
+
+#include "chrome/browser/devtools/protocol/system_info.h"
+
+namespace content {
+class protocol;
+}  // namespace content
+
+class SystemInfoHandler : public protocol::SystemInfo::Backend {
+ public:
+  explicit SystemInfoHandler(protocol::UberDispatcher* dispatcher);
+
+  SystemInfoHandler(const SystemInfoHandler&) = delete;
+  SystemInfoHandler& operator=(const SystemInfoHandler&) = delete;
+
+  ~SystemInfoHandler() override;
+
+ private:
+  protocol::Response GetFeatureState(const std::string& in_featureState,
+                                     bool* featureEnabled) override;
+};
+
+#endif  // CHROME_BROWSER_DEVTOOLS_PROTOCOL_SYSTEM_INFO_HANDLER_H_
diff --git a/chrome/browser/ui/webui/system_info_ui.cc b/chrome/browser/ui/webui/system_info_ui.cc
index 09421df..dd3a898 100644
--- a/chrome/browser/ui/webui/system_info_ui.cc
+++ b/chrome/browser/ui/webui/system_info_ui.cc
@@ -72,14 +72,14 @@
 }  // namespace
 
 // The handler for Javascript messages related to the "system" view.
-class SystemInfoHandler : public WebUIMessageHandler {
+class SystemInfoUIHandler : public WebUIMessageHandler {
  public:
-  SystemInfoHandler();
+  SystemInfoUIHandler();
 
-  SystemInfoHandler(const SystemInfoHandler&) = delete;
-  SystemInfoHandler& operator=(const SystemInfoHandler&) = delete;
+  SystemInfoUIHandler(const SystemInfoUIHandler&) = delete;
+  SystemInfoUIHandler& operator=(const SystemInfoUIHandler&) = delete;
 
-  ~SystemInfoHandler() override;
+  ~SystemInfoUIHandler() override;
 
   // WebUIMessageHandler implementation.
   void RegisterMessages() override;
@@ -93,41 +93,42 @@
 
  private:
   std::string callback_id_;
-  base::WeakPtrFactory<SystemInfoHandler> weak_ptr_factory_{this};
+  base::WeakPtrFactory<SystemInfoUIHandler> weak_ptr_factory_{this};
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //
-// SystemInfoHandler
+// SystemInfoUIHandler
 //
 ////////////////////////////////////////////////////////////////////////////////
-SystemInfoHandler::SystemInfoHandler() {}
+SystemInfoUIHandler::SystemInfoUIHandler() {}
 
-SystemInfoHandler::~SystemInfoHandler() {}
+SystemInfoUIHandler::~SystemInfoUIHandler() {}
 
-void SystemInfoHandler::OnJavascriptDisallowed() {
+void SystemInfoUIHandler::OnJavascriptDisallowed() {
   weak_ptr_factory_.InvalidateWeakPtrs();
   callback_id_.clear();
 }
 
-void SystemInfoHandler::RegisterMessages() {
+void SystemInfoUIHandler::RegisterMessages() {
   web_ui()->RegisterMessageCallback(
       "requestSystemInfo",
-      base::BindRepeating(&SystemInfoHandler::HandleRequestSystemInfo,
+      base::BindRepeating(&SystemInfoUIHandler::HandleRequestSystemInfo,
                           base::Unretained(this)));
 }
 
-void SystemInfoHandler::HandleRequestSystemInfo(const base::Value::List& args) {
+void SystemInfoUIHandler::HandleRequestSystemInfo(
+    const base::Value::List& args) {
   AllowJavascript();
   callback_id_ = args[0].GetString();
 
   system_logs::SystemLogsFetcher* fetcher =
       system_logs::BuildAboutSystemLogsFetcher();
-  fetcher->Fetch(base::BindOnce(&SystemInfoHandler::OnSystemInfo,
+  fetcher->Fetch(base::BindOnce(&SystemInfoUIHandler::OnSystemInfo,
                                 weak_ptr_factory_.GetWeakPtr()));
 }
 
-void SystemInfoHandler::OnSystemInfo(
+void SystemInfoUIHandler::OnSystemInfo(
     std::unique_ptr<SystemLogsResponse> sys_info) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (!sys_info)
@@ -151,7 +152,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 SystemInfoUI::SystemInfoUI(content::WebUI* web_ui) : WebUIController(web_ui) {
-  web_ui->AddMessageHandler(std::make_unique<SystemInfoHandler>());
+  web_ui->AddMessageHandler(std::make_unique<SystemInfoUIHandler>());
 
   // Set up the chrome://system/ source.
   CreateAndAddSystemInfoUIDataSource(Profile::FromWebUI(web_ui));