blob: 88539464303446b8f62ef0005bf4db0fed96cbba [file] [log] [blame]
// Copyright 2024 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/extensions/manifest_v2_experiment_manager.h"
#include "chrome/browser/extensions/extension_management.h"
#include "chrome/browser/extensions/mv2_experiment_stage.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_prefs_factory.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/pref_types.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_features.h"
namespace extensions {
namespace {
// Stores the bit for whether the user has acknowledged the MV2 deprecation
// warning for a given extension.
constexpr PrefMap kMV2DeprecationExtensionWarningAcknowledgedPref = {
"mv2_deprecation_warning_ack", PrefType::kBool,
PrefScope::kExtensionSpecific};
class ManifestV2ExperimentManagerFactory
: public BrowserContextKeyedServiceFactory {
public:
ManifestV2ExperimentManagerFactory();
ManifestV2ExperimentManagerFactory(
const ManifestV2ExperimentManagerFactory&) = delete;
ManifestV2ExperimentManagerFactory& operator=(
const ManifestV2ExperimentManagerFactory&) = delete;
~ManifestV2ExperimentManagerFactory() override = default;
ManifestV2ExperimentManager* GetForBrowserContext(
content::BrowserContext* context);
private:
// BrowserContextKeyedServiceFactory:
content::BrowserContext* GetBrowserContextToUse(
content::BrowserContext* context) const override;
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* context) const override;
};
ManifestV2ExperimentManagerFactory::ManifestV2ExperimentManagerFactory()
: BrowserContextKeyedServiceFactory(
"ManifestV2ExperimentManager",
BrowserContextDependencyManager::GetInstance()) {
DependsOn(ExtensionManagementFactory::GetInstance());
DependsOn(ExtensionPrefsFactory::GetInstance());
}
ManifestV2ExperimentManager*
ManifestV2ExperimentManagerFactory::GetForBrowserContext(
content::BrowserContext* browser_context) {
return static_cast<ManifestV2ExperimentManager*>(
GetServiceForBrowserContext(browser_context, /*create=*/true));
}
content::BrowserContext*
ManifestV2ExperimentManagerFactory::GetBrowserContextToUse(
content::BrowserContext* context) const {
// Shared instance between incognito and regular profiles. This matches the
// rest of the core extension services, such as ExtensionService.
return ExtensionsBrowserClient::Get()->GetContextRedirectedToOriginal(
context, /*force_guest_profile=*/true);
}
KeyedService* ManifestV2ExperimentManagerFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
return new ManifestV2ExperimentManager(context);
}
MV2ExperimentStage CalculateCurrentExperimentStage() {
if (base::FeatureList::IsEnabled(
extensions_features::kExtensionManifestV2DeprecationWarning)) {
return MV2ExperimentStage::kWarning;
}
return MV2ExperimentStage::kNone;
}
} // namespace
ManifestV2ExperimentManager::ManifestV2ExperimentManager(
content::BrowserContext* browser_context)
: experiment_stage_(CalculateCurrentExperimentStage()),
// Note: passing `ExtensionManagement` is safe and guaranteed to outlive
// the `impact_checker_` because this class is a KeyedService that depends
// on `ExtensionManagement`.
impact_checker_(
experiment_stage_,
ExtensionManagementFactory::GetForBrowserContext(browser_context)),
extension_prefs_(ExtensionPrefs::Get(browser_context)) {}
ManifestV2ExperimentManager::~ManifestV2ExperimentManager() = default;
// static
ManifestV2ExperimentManager* ManifestV2ExperimentManager::Get(
content::BrowserContext* browser_context) {
return static_cast<ManifestV2ExperimentManagerFactory*>(GetFactory())
->GetForBrowserContext(browser_context);
}
// static
BrowserContextKeyedServiceFactory* ManifestV2ExperimentManager::GetFactory() {
static base::NoDestructor<ManifestV2ExperimentManagerFactory> g_factory;
return g_factory.get();
}
MV2ExperimentStage ManifestV2ExperimentManager::GetCurrentExperimentStage() {
return experiment_stage_;
}
bool ManifestV2ExperimentManager::IsExtensionAffected(
const Extension& extension) {
return impact_checker_.IsExtensionAffected(extension);
}
bool ManifestV2ExperimentManager::DidUserAcknowledgeWarning(
const ExtensionId& extension_id) {
bool acknowledged = false;
return extension_prefs_->ReadPrefAsBoolean(
extension_id, kMV2DeprecationExtensionWarningAcknowledgedPref,
&acknowledged) &&
acknowledged;
}
void ManifestV2ExperimentManager::MarkWarningAsAcknowledged(
const ExtensionId& extension_id) {
extension_prefs_->SetBooleanPref(
extension_id, kMV2DeprecationExtensionWarningAcknowledgedPref, true);
}
bool ManifestV2ExperimentManager::DidUserAcknowledgeWarningGlobally() {
return extension_prefs_->GetPrefAsBoolean(
kMV2DeprecationWarningAcknowledgedGloballyPref);
}
void ManifestV2ExperimentManager::MarkWarningAsAcknowledgedGlobally() {
extension_prefs_->SetBooleanPref(
kMV2DeprecationWarningAcknowledgedGloballyPref, true);
}
} // namespace extensions