Add enterprise policy for IntensiveWakeUpThrottling feature.

This allows enterprise admins to force-enable or force-disable
the feature.

BUG=1075553

Change-Id: I1ca1a6373945100f92f0a84f2e27d323000154a3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2232772
Reviewed-by: Julian Pastarmov <[email protected]>
Reviewed-by: Jeremy Roman <[email protected]>
Reviewed-by: François Doray <[email protected]>
Reviewed-by: Alexander Timin <[email protected]>
Reviewed-by: Gabriel Charette <[email protected]>
Commit-Queue: Chris Hamilton <[email protected]>
Cr-Commit-Position: refs/heads/master@{#776922}
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 2c4018b..6f09702a 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -224,6 +224,7 @@
 #include "components/permissions/quota_permission_context_impl.h"
 #include "components/policy/content/policy_blacklist_navigation_throttle.h"
 #include "components/policy/content/policy_blacklist_service.h"
+#include "components/policy/core/common/policy_pref_names.h"
 #include "components/policy/core/common/policy_service.h"
 #include "components/policy/policy_constants.h"
 #include "components/pref_registry/pref_registry_syncable.h"
@@ -346,6 +347,7 @@
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/loader/url_loader_throttle.h"
+#include "third_party/blink/public/common/switches.h"
 #include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
 #include "third_party/blink/public/mojom/site_engagement/site_engagement.mojom.h"
 #include "third_party/blink/public/mojom/user_agent/user_agent_metadata.mojom.h"
@@ -2286,6 +2288,22 @@
           prefs->GetBoolean(prefs::kAppCacheForceEnabled)) {
         command_line->AppendSwitch(switches::kAppCacheForceEnabled);
       }
+
+      // The IntensiveWakeUpThrottling feature is typically managed via a
+      // base::Feature, but it has a managed policy override. The override is
+      // communicated to blink via a custom command-line flag. See
+      // PageSchedulerImpl for the other half of related logic.
+      PrefService* local_state = g_browser_process->local_state();
+      const PrefService::Preference* pref = local_state->FindPreference(
+          policy::policy_prefs::kIntensiveWakeUpThrottlingEnabled);
+      if (pref && pref->IsManaged()) {
+        command_line->AppendSwitchASCII(
+            blink::switches::kIntensiveWakeUpThrottlingPolicy,
+            pref->GetValue()->GetBool()
+                ? blink::switches::kIntensiveWakeUpThrottlingPolicy_ForceEnable
+                : blink::switches::
+                      kIntensiveWakeUpThrottlingPolicy_ForceDisable);
+      }
     }
 
     if (IsAutoReloadEnabled())
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index fb65b9e1..5bfbd25e 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1288,6 +1288,9 @@
   { key::kAppCacheForceEnabled,
     prefs::kAppCacheForceEnabled,
     base::Value::Type::BOOLEAN },
+  { key::kIntensiveWakeUpThrottlingEnabled,
+    policy::policy_prefs::kIntensiveWakeUpThrottlingEnabled,
+    base::Value::Type::BOOLEAN },
 };
 // clang-format on
 
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index e5f9fd62..e7159953 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -655,7 +655,9 @@
 }  // namespace
 
 void RegisterLocalState(PrefRegistrySimple* registry) {
-  // Please keep this list alphabetized.
+  // Call outs to individual subsystems that register Local State (browser-wide)
+  // prefs en masse. See RegisterProfilePrefs for per-profile prefs. Please
+  // keep this list alphabetized.
   browser_shutdown::RegisterPrefs(registry);
   data_reduction_proxy::RegisterPrefs(registry);
   data_use_measurement::ChromeDataUseMeasurement::RegisterPrefs(registry);
@@ -693,6 +695,19 @@
   update_client::RegisterPrefs(registry);
   variations::VariationsService::RegisterPrefs(registry);
 
+  // Individual preferences. If you have multiple preferences that should
+  // clearly be grouped together, please group them together into a helper
+  // function called above. Please keep this list alphabetized.
+  registry->RegisterBooleanPref(
+      policy::policy_prefs::kIntensiveWakeUpThrottlingEnabled, false);
+  registry->RegisterInt64Pref(kLastStartupTimestamp, 0);
+  registry->RegisterStringPref(kLastStartupVersion, std::string());
+  registry->RegisterIntegerPref(kSameVersionStartupCount, 0);
+
+  // Below this point is for platform-specific and compile-time conditional
+  // calls. Please follow the helper-function-first-then-direct-calls pattern
+  // established above, and keep things alphabetized.
+
 #if BUILDFLAG(ENABLE_BACKGROUND_MODE)
   BackgroundModeManager::RegisterPrefs(registry);
 #endif
@@ -714,6 +729,8 @@
   StartupBrowserCreator::RegisterLocalStatePrefs(registry);
   task_manager::TaskManagerInterface::RegisterPrefs(registry);
   UpgradeDetector::RegisterPrefs(registry);
+
+  registry->RegisterBooleanPref(kNtpActivateHideShortcutsFieldTrial, false);
 #endif  // !defined(OS_ANDROID)
 
 #if defined(OS_CHROMEOS)
@@ -795,9 +812,6 @@
 
 #if defined(OS_WIN)
   OSCrypt::RegisterLocalPrefs(registry);
-#endif
-
-#if defined(OS_WIN)
   registry->RegisterBooleanPref(prefs::kRendererCodeIntegrityEnabled, true);
   registry->RegisterBooleanPref(
       policy::policy_prefs::kNativeWindowOcclusionEnabled, true);
@@ -815,17 +829,11 @@
   DeviceOAuth2TokenStoreDesktop::RegisterPrefs(registry);
 #endif
 
-#if !defined(OS_ANDROID)
-  registry->RegisterBooleanPref(kNtpActivateHideShortcutsFieldTrial, false);
-#endif  // !defined(OS_ANDROID)
-  registry->RegisterInt64Pref(kLastStartupTimestamp, 0);
-  registry->RegisterStringPref(kLastStartupVersion, std::string());
-  registry->RegisterIntegerPref(kSameVersionStartupCount, 0);
-
 #if defined(TOOLKIT_VIEWS)
   RegisterBrowserViewLocalPrefs(registry);
 #endif
 
+  // This is intentionally last.
   RegisterLocalStatePrefsForMigration(registry);
 }
 
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index ca7809e..934d437 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -7306,5 +7306,19 @@
         }
       }
     ]
+  },
+  "IntensiveWakeUpThrottlingEnabled": {
+    "os": ["win", "linux", "mac", "chromeos", "android"],
+    "policy_pref_mapping_test": [
+      {
+        "policies": { "IntensiveWakeUpThrottlingEnabled": true },
+        "prefs": {
+          "policy.intensive_wake_up_throttling_enabled": {
+            "local_state":  true,
+            "value": true
+          }
+        }
+      }
+    ]
   }
 }
diff --git a/components/policy/core/common/policy_pref_names.cc b/components/policy/core/common/policy_pref_names.cc
index 68b94ed..2613443 100644
--- a/components/policy/core/common/policy_pref_names.cc
+++ b/components/policy/core/common/policy_pref_names.cc
@@ -44,5 +44,10 @@
 const char kNativeWindowOcclusionEnabled[] =
     "policy.native_window_occlusion_enabled";
 
+// Boolean policy preference for force enabling or disabling the
+// IntensiveWakeUpThrottling web feature. Only applied if the policy is managed.
+const char kIntensiveWakeUpThrottlingEnabled[] =
+    "policy.intensive_wake_up_throttling_enabled";
+
 }  // namespace policy_prefs
 }  // namespace policy
diff --git a/components/policy/core/common/policy_pref_names.h b/components/policy/core/common/policy_pref_names.h
index f5bc2481f..0d4986a 100644
--- a/components/policy/core/common/policy_pref_names.h
+++ b/components/policy/core/common/policy_pref_names.h
@@ -19,6 +19,7 @@
 POLICY_EXPORT extern const char kUrlBlacklist[];
 POLICY_EXPORT extern const char kUrlWhitelist[];
 POLICY_EXPORT extern const char kUserPolicyRefreshRate[];
+POLICY_EXPORT extern const char kIntensiveWakeUpThrottlingEnabled[];
 
 }  // namespace policy_prefs
 }  // namespace policy
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 294be902..4252fd3 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -21256,6 +21256,43 @@
 
           If you set this policy, users cannot change or override it.''',
     },
+    {
+      'name': 'IntensiveWakeUpThrottlingEnabled',
+      'owners': ['file://components/performance_manager/OWNERS', '[email protected]'],
+      'type': 'main',
+      'schema': { 'type': 'boolean' },
+      'supported_on': ['chrome_os:85-', 'chrome.*:85-', 'android:85-'],
+      'features': {
+        'per_profile': False,
+        'dynamic_refresh': True,
+      },
+      'example_value': True,
+      'id': 713,
+      'caption': '''Control the <ph name="PRODUCT_NAME">IntensiveWakeUpThrottling</ph> feature.''',
+      'tags': [],
+      'desc': '''When enabled the <ph name="PRODUCT_NAME">IntensiveWakeUpThrottling</ph> feature causes Javascript timers in background tabs to be aggressively throttled and coalesced, running no more than once per minute after a page has been backgrounded for 5 minutes or more.
+
+          This is a web standards compliant feature, but it may break functionality
+          on some websites by causing certain actions to be delayed by up to a
+          minute. However, it results in significant CPU and battery savings when
+          enabled. See https://bit.ly/30b1XR4 for more details.
+
+          If this policy is set to enabled then the feature will be force enabled, and
+          users will not be able to override this.
+
+          If this policy is set to disabled then the feature will be force disabled, and
+          users will not be able to override this.
+
+          If this policy is left unset then the feature will be controlled by its
+          own internal logic, which can be manually configured by users.
+
+          Note that the policy is applied per renderer process, with the most recent
+          value of the policy setting in force when a renderer process starts. A full
+          restart is required to ensure that all loaded tabs receive a consistent
+          policy setting. It is harmless for processes to be running with different
+          values of this policy.
+          ''',
+    },
   ],
 
   'messages': {
@@ -22119,6 +22156,6 @@
   ],
   'placeholders': [],
   'deleted_policy_ids': [412, 476, 546, 562, 569, 578],
-  'highest_id_currently_used': 712,
+  'highest_id_currently_used': 713,
   'highest_atomic_group_id_currently_used': 38
 }
diff --git a/third_party/blink/common/switches.cc b/third_party/blink/common/switches.cc
index fde00dd1..6b685ba 100644
--- a/third_party/blink/common/switches.cc
+++ b/third_party/blink/common/switches.cc
@@ -12,5 +12,15 @@
 // involving a command line switch.
 const char kAllowPreCommitInput[] = "allow-pre-commit-input";
 
+// Used to communicate managed policy for the IntensiveWakeUpThrottling feature.
+// This feature is typically controlled by base::Feature (see
+// renderer/platform/scheduler/common/features.*) but requires an enterprise
+// policy override. This is implicitly a tri-state, and can be either unset, or
+// set to "1" for force enable, or "0" for force disable.
+extern const char kIntensiveWakeUpThrottlingPolicy[] =
+    "intensive-wake-up-throttling-policy";
+extern const char kIntensiveWakeUpThrottlingPolicy_ForceDisable[] = "0";
+extern const char kIntensiveWakeUpThrottlingPolicy_ForceEnable[] = "1";
+
 }  // namespace switches
 }  // namespace blink
diff --git a/third_party/blink/public/common/switches.h b/third_party/blink/public/common/switches.h
index a75bd04..ebb3454a 100644
--- a/third_party/blink/public/common/switches.h
+++ b/third_party/blink/public/common/switches.h
@@ -15,6 +15,11 @@
 // All switches in alphabetical order. The switches should be documented
 // alongside the definition of their values in the .cc file.
 BLINK_COMMON_EXPORT extern const char kAllowPreCommitInput[];
+BLINK_COMMON_EXPORT extern const char kIntensiveWakeUpThrottlingPolicy[];
+BLINK_COMMON_EXPORT extern const char
+    kIntensiveWakeUpThrottlingPolicy_ForceDisable[];
+BLINK_COMMON_EXPORT extern const char
+    kIntensiveWakeUpThrottlingPolicy_ForceEnable[];
 
 }  // namespace switches
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/common/features.cc b/third_party/blink/renderer/platform/scheduler/common/features.cc
index c33dfeec..95a4baa2 100644
--- a/third_party/blink/renderer/platform/scheduler/common/features.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/features.cc
@@ -4,16 +4,96 @@
 
 #include "third_party/blink/renderer/platform/scheduler/common/features.h"
 
+#include "base/command_line.h"
+#include "third_party/blink/public/common/switches.h"
+
 namespace blink {
 namespace scheduler {
 
+namespace {
+
+enum class PolicyOverride { NO_OVERRIDE, FORCE_DISABLE, FORCE_ENABLE };
+
+bool g_intensive_wake_up_throttling_policy_override_cached_ = false;
+
+// Returns the IntensiveWakeUpThrottling policy settings. This is checked once
+// on first access and cached. Note that that this is *not* thread-safe!
+PolicyOverride GetIntensiveWakeUpThrottlingPolicyOverride() {
+  static PolicyOverride policy = PolicyOverride::NO_OVERRIDE;
+  if (g_intensive_wake_up_throttling_policy_override_cached_)
+    return policy;
+
+  // Otherwise, check the command-line. Only values of "0" and "1" are valid,
+  // anything else is ignored (and allows the base::Feature to control the
+  // feature). This slow path will only be hit once per renderer process.
+  g_intensive_wake_up_throttling_policy_override_cached_ = true;
+  std::string value =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kIntensiveWakeUpThrottlingPolicy);
+  if (value == switches::kIntensiveWakeUpThrottlingPolicy_ForceEnable) {
+    policy = PolicyOverride::FORCE_ENABLE;
+  } else if (value == switches::kIntensiveWakeUpThrottlingPolicy_ForceDisable) {
+    policy = PolicyOverride::FORCE_DISABLE;
+  } else {
+    // Necessary in testing configurations, as the policy can be parsed
+    // repeatedly.
+    policy = PolicyOverride::NO_OVERRIDE;
+  }
+
+  return policy;
+}
+
+}  // namespace
+
 const base::Feature kIntensiveWakeUpThrottling{
     "IntensiveWakeUpThrottling", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::FeatureParam<int>
     kIntensiveWakeUpThrottling_DurationBetweenWakeUpsSeconds{
-        &kIntensiveWakeUpThrottling, "duration_between_wake_ups_seconds", 60};
+        &kIntensiveWakeUpThrottling, "duration_between_wake_ups_seconds",
+        kIntensiveWakeUpThrottling_DurationBetweenWakeUpsSeconds_Default};
+
 const base::FeatureParam<int> kIntensiveWakeUpThrottling_GracePeriodSeconds{
-    &kIntensiveWakeUpThrottling, "grace_period_seconds", 5 * 60};
+    &kIntensiveWakeUpThrottling, "grace_period_seconds",
+    kIntensiveWakeUpThrottling_GracePeriodSeconds_Default};
+
+void ClearIntensiveWakeUpThrottlingPolicyOverrideCacheForTesting() {
+  g_intensive_wake_up_throttling_policy_override_cached_ = false;
+}
+
+bool IsIntensiveWakeUpThrottlingEnabled() {
+  // If policy is present then respect it.
+  auto policy = GetIntensiveWakeUpThrottlingPolicyOverride();
+  if (policy != PolicyOverride::NO_OVERRIDE)
+    return policy == PolicyOverride::FORCE_ENABLE;
+  // Otherwise respect the base::Feature.
+  return base::FeatureList::IsEnabled(kIntensiveWakeUpThrottling);
+}
+
+// If a policy override is specified then stick to the published defaults so
+// that admins get consistent behaviour that clients can't override. Otherwise
+// use the base::FeatureParams.
+
+base::TimeDelta GetIntensiveWakeUpThrottlingDurationBetweenWakeUps() {
+  DCHECK(IsIntensiveWakeUpThrottlingEnabled());
+  int seconds =
+      kIntensiveWakeUpThrottling_DurationBetweenWakeUpsSeconds_Default;
+  if (GetIntensiveWakeUpThrottlingPolicyOverride() ==
+      PolicyOverride::NO_OVERRIDE) {
+    seconds = kIntensiveWakeUpThrottling_DurationBetweenWakeUpsSeconds.Get();
+  }
+  return base::TimeDelta::FromSeconds(seconds);
+}
+
+base::TimeDelta GetIntensiveWakeUpThrottlingGracePeriod() {
+  DCHECK(IsIntensiveWakeUpThrottlingEnabled());
+  int seconds = kIntensiveWakeUpThrottling_GracePeriodSeconds_Default;
+  if (GetIntensiveWakeUpThrottlingPolicyOverride() ==
+      PolicyOverride::NO_OVERRIDE) {
+    seconds = kIntensiveWakeUpThrottling_GracePeriodSeconds.Get();
+  }
+  return base::TimeDelta::FromSeconds(seconds);
+}
 
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/common/features.h b/third_party/blink/renderer/platform/scheduler/common/features.h
index db39fb9..5a3d7a8d 100644
--- a/third_party/blink/renderer/platform/scheduler/common/features.h
+++ b/third_party/blink/renderer/platform/scheduler/common/features.h
@@ -191,17 +191,31 @@
 //  - 1% CPU time in a page that has been backgrounded for 10 seconds
 //
 // Feature tracking bug: https://crbug.com/1075553
+//
+// Note that the base::Feature and base::FeatureParams should not be read from;
+// rather the provided accessors should be used, which also take into account
+// the managed policy override of the feature.
 PLATFORM_EXPORT extern const base::Feature kIntensiveWakeUpThrottling;
-
-// Duration between wake ups in seconds. For the kIntensiveWakeUpThrottling
-// feature.
 PLATFORM_EXPORT extern const base::FeatureParam<int>
     kIntensiveWakeUpThrottling_DurationBetweenWakeUpsSeconds;
-
-// Grace period after backgrounding a page during which there is no intensive
-// wake up throttling, in seconds. For the kIntensiveWakeUpThrottling feature.
 PLATFORM_EXPORT extern const base::FeatureParam<int>
     kIntensiveWakeUpThrottling_GracePeriodSeconds;
+// Default parameter values, exposed for testing.
+constexpr int kIntensiveWakeUpThrottling_DurationBetweenWakeUpsSeconds_Default =
+    60;
+constexpr int kIntensiveWakeUpThrottling_GracePeriodSeconds_Default = 5 * 60;
+// Exposed so that multiple tests can tinker with the policy override.
+PLATFORM_EXPORT void
+ClearIntensiveWakeUpThrottlingPolicyOverrideCacheForTesting();
+// Determines if the feature is enabled, taking into account base::Feature
+// settings and policy overrides.
+PLATFORM_EXPORT bool IsIntensiveWakeUpThrottlingEnabled();
+// Duration between wake ups for the kIntensiveWakeUpThrottling feature.
+PLATFORM_EXPORT base::TimeDelta
+GetIntensiveWakeUpThrottlingDurationBetweenWakeUps();
+// Grace period after backgrounding a page during which there is no intensive
+// wake up throttling for the kIntensiveWakeUpThrottling feature.
+PLATFORM_EXPORT base::TimeDelta GetIntensiveWakeUpThrottlingGracePeriod();
 
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
index a8b3848..15224a7 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -15,12 +15,14 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/run_loop.h"
 #include "base/task/sequence_manager/test/sequence_manager_for_test.h"
+#include "base/test/scoped_command_line.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/unguessable_token.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/common/switches.h"
 #include "third_party/blink/renderer/platform/scheduler/common/features.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
@@ -462,6 +464,8 @@
 class FrameSchedulerImplTestWithIntensiveWakeUpThrottling
     : public FrameSchedulerImplTest {
  public:
+  using Super = FrameSchedulerImplTest;
+
   FrameSchedulerImplTestWithIntensiveWakeUpThrottling()
       : FrameSchedulerImplTest(
             {{kIntensiveWakeUpThrottling,
@@ -469,6 +473,34 @@
                // the grace period for freezing, because freezing hides the
                // effect of intensive throttling.
                {kIntensiveWakeUpThrottling_GracePeriodSeconds.name, "60"}}}}) {}
+
+  void SetUp() override {
+    Super::SetUp();
+    ClearIntensiveWakeUpThrottlingPolicyOverrideCacheForTesting();
+  }
+
+  void TearDown() override {
+    ClearIntensiveWakeUpThrottlingPolicyOverrideCacheForTesting();
+    Super::TearDown();
+  }
+};
+
+class FrameSchedulerImplTestWithIntensiveWakeUpThrottlingPolicyOverride
+    : public FrameSchedulerImplTestWithIntensiveWakeUpThrottling {
+ public:
+  // This should only be called once per test, and prior to the
+  // PageSchedulerImpl logic actually parsing the policy switch.
+  void SetPolicyOverride(bool enabled) {
+    DCHECK(!scoped_command_line_.GetProcessCommandLine()->HasSwitch(
+        switches::kIntensiveWakeUpThrottlingPolicy));
+    scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII(
+        switches::kIntensiveWakeUpThrottlingPolicy,
+        enabled ? switches::kIntensiveWakeUpThrottlingPolicy_ForceEnable
+                : switches::kIntensiveWakeUpThrottlingPolicy_ForceDisable);
+  }
+
+ private:
+  base::test::ScopedCommandLine scoped_command_line_;
 };
 
 }  // namespace
@@ -2492,10 +2524,10 @@
 TEST_F(FrameSchedulerImplTestWithIntensiveWakeUpThrottling, TaskExecution) {
   constexpr int kNumTasks = 5;
   constexpr base::TimeDelta kShortDelay = base::TimeDelta::FromSeconds(1);
-  const base::TimeDelta kGracePeriod = base::TimeDelta::FromSeconds(
-      kIntensiveWakeUpThrottling_GracePeriodSeconds.Get());
-  const base::TimeDelta kDurationBetweenWakeUps = base::TimeDelta::FromSeconds(
-      kIntensiveWakeUpThrottling_DurationBetweenWakeUpsSeconds.Get());
+  const base::TimeDelta kGracePeriod =
+      GetIntensiveWakeUpThrottlingGracePeriod();
+  const base::TimeDelta kDurationBetweenWakeUps =
+      GetIntensiveWakeUpThrottlingDurationBetweenWakeUps();
   const scoped_refptr<base::SingleThreadTaskRunner> task_runner =
       frame_scheduler_->GetTaskRunner(TaskType::kJavascriptTimer);
 
@@ -2565,6 +2597,28 @@
   }
 }
 
+TEST_F(FrameSchedulerImplTestWithIntensiveWakeUpThrottlingPolicyOverride,
+       PolicyForceEnable) {
+  SetPolicyOverride(/* enabled = */ true);
+  EXPECT_TRUE(IsIntensiveWakeUpThrottlingEnabled());
+
+  // The parameters should be the defaults, even though they were changed by the
+  // ScopedFeatureList.
+  EXPECT_EQ(base::TimeDelta::FromSeconds(
+                kIntensiveWakeUpThrottling_GracePeriodSeconds_Default),
+            GetIntensiveWakeUpThrottlingGracePeriod());
+  EXPECT_EQ(
+      base::TimeDelta::FromSeconds(
+          kIntensiveWakeUpThrottling_DurationBetweenWakeUpsSeconds_Default),
+      GetIntensiveWakeUpThrottlingDurationBetweenWakeUps());
+}
+
+TEST_F(FrameSchedulerImplTestWithIntensiveWakeUpThrottlingPolicyOverride,
+       PolicyForceDisable) {
+  SetPolicyOverride(/* enabled = */ false);
+  EXPECT_FALSE(IsIntensiveWakeUpThrottlingEnabled());
+}
+
 }  // namespace frame_scheduler_impl_unittest
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
index f2ee651b..0dac5ed 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
@@ -13,6 +13,7 @@
 #include "base/optional.h"
 #include "base/strings/string_number_conversions.h"
 #include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/common/switches.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/scheduler/common/features.h"
@@ -645,12 +646,10 @@
           FROM_HERE, do_throttle_cpu_time_callback_.GetCallback(),
           kThrottlingDelayAfterBackgrounding);
     }
-    if (wake_up_budget_pool_ &&
-        base::FeatureList::IsEnabled(kIntensiveWakeUpThrottling)) {
+    if (wake_up_budget_pool_ && IsIntensiveWakeUpThrottlingEnabled()) {
       main_thread_scheduler_->ControlTaskRunner()->PostDelayedTask(
           FROM_HERE, do_intensively_throttle_wake_ups_callback_.GetCallback(),
-          base::TimeDelta::FromSeconds(
-              kIntensiveWakeUpThrottling_GracePeriodSeconds.Get()));
+          GetIntensiveWakeUpThrottlingGracePeriod());
     }
   }
   if (notification_policy == NotificationPolicy::kNotifyFrames)
@@ -668,7 +667,7 @@
 }
 
 void PageSchedulerImpl::DoIntensivelyThrottleWakeUps() {
-  DCHECK(base::FeatureList::IsEnabled(kIntensiveWakeUpThrottling));
+  DCHECK(IsIntensiveWakeUpThrottlingEnabled());
 
   do_intensively_throttle_wake_ups_callback_.Cancel();
   are_wake_ups_intensively_throttled_ = true;
@@ -699,9 +698,7 @@
   if (are_wake_ups_intensively_throttled_ &&
       !opted_out_from_aggressive_throttling_) {
     wake_up_budget_pool_->SetWakeUpInterval(
-        lazy_now->Now(),
-        base::TimeDelta::FromSeconds(
-            kIntensiveWakeUpThrottling_DurationBetweenWakeUpsSeconds.Get()));
+        lazy_now->Now(), GetIntensiveWakeUpThrottlingDurationBetweenWakeUps());
   } else {
     wake_up_budget_pool_->SetWakeUpInterval(lazy_now->Now(),
                                             kDefaultThrottledWakeUpInterval);
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 92c7ec9e..c6e1e24 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -20479,6 +20479,7 @@
   <int value="710" label="ReportDeviceVpdInfo"/>
   <int value="711" label="EnableExperimentalPolicies"/>
   <int value="712" label="PluginVmDataCollectionAllowed"/>
+  <int value="713" label="IntensiveWakeUpThrottlingEnabled"/>
 </enum>
 
 <enum name="EnterprisePolicyDeviceIdValidity">