Allow users to disable extension updates via brave://flags (#35301)

* Create a new feature for toggling extension updates

Also creates an entry on brave://flags

Fixes https://github.com/brave/brave-browser/issues/7200

* Wire up the extension update check to the feature

* Update browser/about_flags.cc

Co-authored-by: Shivan <shivankaulsahib@gmail.com>

---------

Co-authored-by: Shivan <shivankaulsahib@gmail.com>
This commit is contained in:
Brian Clifton
2026-04-10 13:40:20 -07:00
committed by GitHub
co-authored by Shivan
parent b7ef1d5d4e
commit d7cee10cab
8 changed files with 172 additions and 2 deletions
+16
View File
@@ -89,6 +89,7 @@
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "brave/browser/extensions/manifest_v2/features.h"
#include "brave/browser/extensions/updater/features.h"
#endif
#if BUILDFLAG(ENABLE_BRAVE_EDUCATION)
@@ -710,6 +711,20 @@ constexpr flags_ui::FeatureEntry::Choice kVerticalTabCollapseDelayChoices[] = {
FEATURE_VALUE_TYPE(extensions_mv2::features::kExtensionsManifestV2), \
}))
#define BRAVE_EXTENSION_AUTO_UPDATE_FEATURE_ENTRY \
IF_BUILDFLAG( \
ENABLE_EXTENSIONS, \
EXPAND_FEATURE_ENTRIES({ \
"brave-user-extension-auto-update", \
"Automatically Update Extensions", \
"Automatically update user-installed Web extensions. When " \
"disabled, extensions will not update in the background. Folks can " \
"still update them manually from the brave://extensions page.", \
kOsWin | kOsLinux | kOsMac, \
FEATURE_VALUE_TYPE( \
extensions::features::kBraveAutoUpdateExtensions), \
}))
#if BUILDFLAG(ENABLE_BRAVE_EDUCATION)
#define BRAVE_EDUCATION_FEATURE_ENTRIES \
EXPAND_FEATURE_ENTRIES({ \
@@ -1328,6 +1343,7 @@ constexpr flags_ui::FeatureEntry::Choice kVerticalTabCollapseDelayChoices[] = {
BRAVE_FORCE_CONTEXT_MENU_ON_SHIFT_RIGHT_CLICK_FEATURE_ENTRY \
BRAVE_UPGRADE_WHEN_IDLE_FEATURE_ENTRY \
BRAVE_EXTENSIONS_MANIFEST_V2 \
BRAVE_EXTENSION_AUTO_UPDATE_FEATURE_ENTRY \
BRAVE_WORKAROUND_NEW_WINDOW_FLASH \
BRAVE_WEBASSEMBLY_JITLESS_FEATURE_ENTRY \
BRAVE_EDUCATION_FEATURE_ENTRIES \
+3 -1
View File
@@ -84,12 +84,13 @@ source_set("extensions") {
"brave_extensions_browser_client_impl.h",
"updater/brave_update_client_config.cc",
"updater/brave_update_client_config.h",
"updater/features.cc",
"updater/features.h",
]
deps = [
":brave_prefs_util_impl",
":resources",
"//base",
"//brave/app:brave_generated_resources_grit",
"//brave/browser:browser_process",
"//brave/browser/brave_search",
@@ -137,6 +138,7 @@ source_set("extensions") {
public_deps = [
":component_loader",
"//base",
"//extensions/browser",
]
+17
View File
@@ -0,0 +1,17 @@
// Copyright (c) 2026 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
#include "brave/browser/extensions/updater/features.h"
namespace extensions::features {
// When enabled (default), user installed extensions are automatically updated
// via component updater on a regular frequency.
//
// Can be disabled to prevent automatic extension updates. Folks can still
// update them manually from the brave://extensions page.
BASE_FEATURE(kBraveAutoUpdateExtensions, base::FEATURE_ENABLED_BY_DEFAULT);
} // namespace extensions::features
+17
View File
@@ -0,0 +1,17 @@
// Copyright (c) 2026 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
#ifndef BRAVE_BROWSER_EXTENSIONS_UPDATER_FEATURES_H_
#define BRAVE_BROWSER_EXTENSIONS_UPDATER_FEATURES_H_
#include "base/feature_list.h"
namespace extensions::features {
BASE_DECLARE_FEATURE(kBraveAutoUpdateExtensions);
} // namespace extensions::features
#endif // BRAVE_BROWSER_EXTENSIONS_UPDATER_FEATURES_H_
@@ -0,0 +1,24 @@
// Copyright (c) 2026 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
#include "brave/browser/extensions/updater/features.h"
// Guards automated extension update checks behind the
// `kBraveAutoUpdateExtensions` feature flag. A check for this flag gets patched
// into two methods inside `extension_updater.cc`:
// 1. ExtensionUpdater::Start() - skips the startup check and periodic
// scheduling when auto-updates are disabled.
// 2. ExtensionUpdater::NextCheck() - skips individual scheduled update
// checks and their rescheduling when auto-updates are disabled.
// Manually initiated updates (ex: CheckNow() via the Update button in
// brave://extensions) are unaffected and continue to work normally.
#define BRAVE_EXTENSION_UPDATER_SCHEDULED_CHECK_GUARD \
if (!base::FeatureList::IsEnabled( \
extensions::features::kBraveAutoUpdateExtensions)) \
return;
#include <chrome/browser/extensions/updater/extension_updater.cc>
#undef BRAVE_EXTENSION_UPDATER_SCHEDULED_CHECK_GUARD
@@ -0,0 +1,70 @@
// Copyright (c) 2026 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
#include "base/test/scoped_feature_list.h"
#include "brave/browser/extensions/updater/features.h"
#include <chrome/browser/extensions/updater/extension_updater_unittest.cc>
// `kBraveAutoUpdateExtensions` is enabled by default but can be disabled via
// CLI using --disable-features=BraveAutoUpdateExtensions or by toggling:
// brave://flags/#brave-user-extension-auto-update
//
// These tests checking the two methods that we patch to allow disabling.
// Manually initiated updates (ex: CheckNow) are unaffected.
namespace extensions {
// When the feature is disabled, Start() must not schedule any update checks.
// Specifically, CheckSoon() must not be called, and no update should start.
TEST_F(ExtensionUpdaterTest, BraveExtensionAutoUpdateDisabledStart) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(features::kBraveAutoUpdateExtensions);
ExtensionDownloaderTestHelper helper;
TestDownloaderFactory factory(helper.url_loader_factory());
TestCrxInstallerFactory crx_installer_factory;
ExtensionUpdater updater(profile());
updater.InitAndEnable(extension_prefs(), pref_service(), kUpdateFrequency,
nullptr, factory.GetDownloaderFactory());
updater.set_crx_installer_factory_for_test(&crx_installer_factory);
NiceMock<MockUpdateService> update_service;
OverrideUpdateService(&updater, &update_service);
EXPECT_CALL(update_service, StartUpdateCheck(_, _, _)).Times(0);
updater.Start();
EXPECT_FALSE(updater.WillCheckSoon());
}
// When the feature is disabled, NextCheck() must not trigger CheckNow() or
// reschedule itself. SimulateTimerFired() calls NextCheck() directly, as if
// the scheduler fired, so Start() need only set alive_ = true.
TEST_F(ExtensionUpdaterTest, BraveExtensionAutoUpdateDisabledNextCheck) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(features::kBraveAutoUpdateExtensions);
ExtensionDownloaderTestHelper helper;
TestDownloaderFactory factory(helper.url_loader_factory());
TestCrxInstallerFactory crx_installer_factory;
ExtensionUpdater updater(profile());
updater.InitAndEnable(extension_prefs(), pref_service(), kUpdateFrequency,
nullptr, factory.GetDownloaderFactory());
updater.set_crx_installer_factory_for_test(&crx_installer_factory);
NiceMock<MockUpdateService> update_service;
OverrideUpdateService(&updater, &update_service);
EXPECT_CALL(update_service, StartUpdateCheck(_, _, _)).Times(0);
// Start() sets alive_ = true before the feature guard fires, so NextCheck()
// will get past the alive_ check and hit the feature guard.
updater.Start();
// Simulate the scheduler calling NextCheck() directly.
SimulateTimerFired(&updater);
}
} // namespace extensions
@@ -0,0 +1,20 @@
diff --git a/chrome/browser/extensions/updater/extension_updater.cc b/chrome/browser/extensions/updater/extension_updater.cc
index 0c6620892582a44fe5e5e951af120a4ae70c67f5..ce6ec8c55829861dac97aa1485e05a1d76d4ad5e 100644
--- a/chrome/browser/extensions/updater/extension_updater.cc
+++ b/chrome/browser/extensions/updater/extension_updater.cc
@@ -231,6 +231,7 @@ void ExtensionUpdater::Start() {
alive_ = true;
// Check soon, and set up the first delayed check.
if (!g_skip_scheduled_checks_for_tests) {
+ BRAVE_EXTENSION_UPDATER_SCHEDULED_CHECK_GUARD
CheckSoon();
ScheduleNextCheck();
}
@@ -271,6 +272,7 @@ void ExtensionUpdater::NextCheck() {
if (!alive_) {
return;
}
+ BRAVE_EXTENSION_UPDATER_SCHEDULED_CHECK_GUARD
CheckNow(CheckParams());
ScheduleNextCheck();
}
+5 -1
View File
@@ -806,6 +806,11 @@
# This test fails because we disable installing the Captcha Provider component
-CaptchaProviderComponentInstallerPolicyTest.ComponentRegistered
# ExtensionUpdaterTest.* was previously disabled. When adding more tests with
# https://github.com/brave/brave-core/pull/35301, it seems most of the tests
# pass. This is the only one remaining with a failure.
-ExtensionUpdaterTest.TestProfileDestruction
# Tests below this point have not been diagnosed or had issues created yet.
-AboutFlagsHistogramTest.*
-AboutFlagsTest.EveryFlagHasMetadata
@@ -860,7 +865,6 @@
-ExtensionSyncTypeTest.UserScriptNoUpdateUrl
-ExtensionTelemetryServiceSystemTimeTest.PersistsReportsWithUnspecifiedManagementAuthorityOnShutdown
-ExtensionTelemetryServiceTest.*
-ExtensionUpdaterTest.*
-FullStreamUIPolicyTest.*
-GCMProfileServiceTest.*
-GetUserPopulationForProfileTest.PopulatesPopulation