910e62b5创建于 1月15日历史提交
// 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::u16string 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