blob: 009e6b6d7ed15c8cba4991b48609580070d78edc [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/browser/delayed_install_manager.h"
#include <string>
#include <vector>
#include "base/check.h"
#include "base/trace_event/trace_event.h"
#include "extensions/browser/delayed_install_manager_factory.h"
#include "extensions/browser/extension_registrar.h"
#include "extensions/browser/install_gate.h"
namespace extensions {
DelayedInstallManager::DelayedInstallManager(content::BrowserContext* context)
: extension_prefs_(ExtensionPrefs::Get(context)),
extension_registrar_(ExtensionRegistrar::Get(context)) {}
DelayedInstallManager::~DelayedInstallManager() = default;
// static
DelayedInstallManager* DelayedInstallManager::Get(
content::BrowserContext* context) {
return DelayedInstallManagerFactory::GetForBrowserContext(context);
}
void DelayedInstallManager::Shutdown() {
// Avoids dangling pointers during keyed service two-phase shutdown.
extension_prefs_ = nullptr;
extension_registrar_ = nullptr;
}
bool DelayedInstallManager::Contains(const ExtensionId& id) const {
return delayed_installs_.Contains(id);
}
void DelayedInstallManager::Insert(scoped_refptr<const Extension> extension) {
delayed_installs_.Insert(extension);
}
void DelayedInstallManager::Remove(const ExtensionId& id) {
delayed_installs_.Remove(id);
}
const Extension* DelayedInstallManager::GetPendingExtensionUpdate(
const ExtensionId& id) const {
return delayed_installs_.GetByID(id);
}
void DelayedInstallManager::FinishInstallationsDelayedByShutdown() {
TRACE_EVENT0("browser,startup",
"DelayedInstallManager::FinishInstallationsDelayedByShutdown");
const ExtensionPrefs::ExtensionsInfo delayed_info =
extension_prefs_->GetAllDelayedInstallInfo();
for (const auto& info : delayed_info) {
scoped_refptr<const Extension> extension;
if (info.extension_manifest) {
std::string error;
extension = Extension::Create(
info.extension_path, info.extension_location,
*info.extension_manifest,
extension_prefs_->GetDelayedInstallCreationFlags(info.extension_id),
info.extension_id, &error);
if (extension.get()) {
delayed_installs_.Insert(extension);
}
}
}
MaybeFinishDelayedInstallations();
}
void DelayedInstallManager::MaybeFinishDelayedInstallations() {
std::vector<std::string> to_be_installed;
for (const auto& extension : delayed_installs_) {
to_be_installed.push_back(extension->id());
}
for (const auto& extension_id : to_be_installed) {
FinishDelayedInstallationIfReady(extension_id,
/*install_immediately=*/false);
}
}
bool DelayedInstallManager::FinishDelayedInstallationIfReady(
const std::string& extension_id,
bool install_immediately) {
// Check if the extension already got installed.
const Extension* extension = delayed_installs_.GetByID(extension_id);
if (!extension) {
return false;
}
ExtensionPrefs::DelayReason reason;
const InstallGate::Action action =
ShouldDelayExtensionInstall(extension, install_immediately, &reason);
switch (action) {
case InstallGate::INSTALL:
break;
case InstallGate::DELAY:
// Bail out and continue to delay the install.
return false;
case InstallGate::ABORT:
delayed_installs_.Remove(extension_id);
// Make sure no version of the extension is actually installed, (i.e.,
// that this delayed install was not an update).
CHECK(!extension_prefs_->GetInstalledExtensionInfo(extension_id));
extension_prefs_->DeleteExtensionPrefs(extension_id);
return false;
}
scoped_refptr<const Extension> delayed_install =
GetPendingExtensionUpdate(extension_id);
CHECK(delayed_install.get());
delayed_installs_.Remove(extension_id);
if (!extension_prefs_->FinishDelayedInstallInfo(extension_id)) {
NOTREACHED();
}
extension_registrar_->FinishInstallation(delayed_install.get());
return true;
}
void DelayedInstallManager::RegisterInstallGate(
ExtensionPrefs::DelayReason reason,
InstallGate* install_delayer) {
DCHECK(install_delayer_registry_.end() ==
install_delayer_registry_.find(reason));
install_delayer_registry_[reason] = install_delayer;
}
void DelayedInstallManager::UnregisterInstallGate(
InstallGate* install_delayer) {
std::erase_if(install_delayer_registry_, [&](const auto& pair) {
return pair.second == install_delayer;
});
}
InstallGate::Action DelayedInstallManager::ShouldDelayExtensionInstall(
const Extension* extension,
bool install_immediately,
ExtensionPrefs::DelayReason* reason) const {
for (const auto& entry : install_delayer_registry_) {
InstallGate* const delayer = entry.second;
InstallGate::Action action =
delayer->ShouldDelay(extension, install_immediately);
if (action != InstallGate::INSTALL) {
*reason = entry.first;
return action;
}
}
return InstallGate::INSTALL;
}
} // namespace extensions