blob: 11ba0ede62d7ebe264a02ee55c31af1eefa1bf5d [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef EXTENSIONS_BROWSER_EXTENSION_REGISTRAR_H_
#define EXTENSIONS_BROWSER_EXTENSION_REGISTRAR_H_
#include <memory>
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "extensions/browser/process_manager.h"
#include "extensions/browser/process_manager_observer.h"
#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_id.h"
namespace base {
class FilePath;
} // namespace base
namespace content {
class BrowserContext;
class DevToolsAgentHost;
} // namespace content
namespace extensions {
class Extension;
class ExtensionHost;
class ExtensionPrefs;
class ExtensionRegistry;
class ExtensionSystem;
class RendererStartupHelper;
// ExtensionRegistrar drives the stages of registering and unregistering
// extensions for a BrowserContext. It uses the ExtensionRegistry to track
// extension states. Other classes may query the ExtensionRegistry directly,
// but eventually only ExtensionRegistrar will be able to make changes to it.
class ExtensionRegistrar : public ProcessManagerObserver {
public:
// How to surface an extension load error, e.g. showing an error dialog. The
// actual behavior is up to the embedder.
enum class LoadErrorBehavior {
kQuiet = 0, // Just log the error.
kNoisy, // Show an error dialog.
};
// Delegate for embedder-specific functionality like policy and permissions.
class Delegate {
public:
Delegate() = default;
Delegate(const Delegate&) = delete;
Delegate& operator=(const Delegate&) = delete;
virtual ~Delegate() = default;
// Called before |extension| is added. |old_extension| is the extension
// being replaced, in the case of a reload or upgrade.
virtual void PreAddExtension(const Extension* extension,
const Extension* old_extension) = 0;
// Handles updating the browser context when an extension is activated
// (becomes enabled).
virtual void PostActivateExtension(
scoped_refptr<const Extension> extension) = 0;
// Handles updating the browser context when an enabled extension is
// deactivated (whether disabled or removed).
virtual void PostDeactivateExtension(
scoped_refptr<const Extension> extension) = 0;
// Given an extension ID and/or path, loads that extension as a reload.
virtual void LoadExtensionForReload(
const ExtensionId& extension_id,
const base::FilePath& path,
LoadErrorBehavior load_error_behavior) = 0;
// Returns true if the extension is allowed to be enabled or disabled,
// respectively.
virtual bool CanEnableExtension(const Extension* extension) = 0;
virtual bool CanDisableExtension(const Extension* extension) = 0;
// Returns true if the extension should be blocked.
virtual bool ShouldBlockExtension(const Extension* extension) = 0;
};
// The provided Delegate should outlive this object.
ExtensionRegistrar(content::BrowserContext* browser_context,
Delegate* delegate);
ExtensionRegistrar(const ExtensionRegistrar&) = delete;
ExtensionRegistrar& operator=(const ExtensionRegistrar&) = delete;
~ExtensionRegistrar() override;
// Adds the extension to the ExtensionRegistry. The extension will be added to
// the enabled, disabled, blocklisted or blocked set. If the extension is
// added as enabled, it will be activated.
void AddExtension(scoped_refptr<const Extension> extension);
// Removes |extension| from the extension system by deactivating it if it is
// enabled and removing references to it from the ExtensionRegistry's
// enabled, disabled or terminated sets.
// Note: Extensions will not be removed from other sets (blocklisted or
// blocked). ExtensionService handles that, since it also adds it to those
// sets. TODO(michaelpg): Make ExtensionRegistrar the sole mutator of
// ExtensionRegsitry to simplify this usage.
void RemoveExtension(const ExtensionId& extension_id,
UnloadedExtensionReason reason);
// If the extension is disabled, marks it as enabled and activates it for use.
// Otherwise, simply updates the ExtensionPrefs. (Blocklisted or blocked
// extensions cannot be enabled.)
void EnableExtension(const ExtensionId& extension_id);
// Marks |extension| as disabled and deactivates it. The ExtensionRegistry
// retains a reference to it, so it can be enabled later.
void DisableExtension(const ExtensionId& extension_id, int disable_reasons);
// Attempts to reload the specified extension by disabling it if it is enabled
// and requesting the Delegate load it again.
// NOTE: Reloading an extension can invalidate |extension_id| and Extension
// pointers for the given extension. Consider making a copy of |extension_id|
// first and retrieving a new Extension pointer afterwards.
void ReloadExtension(const ExtensionId extension_id,
LoadErrorBehavior load_error_behavior);
// TODO(michaelpg): Add methods for blocklisting and blocking extensions.
// Deactivates the extension, adding its id to the list of terminated
// extensions.
void TerminateExtension(const ExtensionId& extension_id);
// Removes the extension from the terminated list. TODO(michaelpg): Make a
// private implementation detail when no longer called from ExtensionService.
void UntrackTerminatedExtension(const ExtensionId& extension_id);
// Returns true if the extension is enabled (including terminated), or if it
// is not loaded but isn't explicitly disabled in preferences.
bool IsExtensionEnabled(const ExtensionId& extension_id) const;
// Called after the renderer main frame for the background page with the
// associated host is created.
void DidCreateMainFrameForBackgroundPage(ExtensionHost* host);
void OnUnpackedExtensionReloadFailed(const base::FilePath& path);
private:
// Adds the extension to the appropriate registry set, based on ExtensionPrefs
// and our |delegate_|. Activates the extension if it's added to the enabled
// set.
void AddNewExtension(scoped_refptr<const Extension> extension);
// Activates |extension| by marking it enabled and notifying other components
// about it.
void ActivateExtension(const Extension* extension, bool is_newly_added);
// Triggers the unloaded notifications to deactivate an extension.
void DeactivateExtension(const Extension* extension,
UnloadedExtensionReason reason);
// Given an extension that was disabled for reloading, completes the reload
// by replacing the old extension with the new version and enabling it.
// Returns true on success.
bool ReplaceReloadedExtension(scoped_refptr<const Extension> extension);
// Marks the extension ready after URLRequestContexts have been updated on
// the IO thread.
void OnExtensionRegisteredWithRequestContexts(
scoped_refptr<const Extension> extension);
// Upon reloading an extension, spins up its context if necessary.
void MaybeSpinUpLazyContext(const Extension* extension, bool is_newly_added);
// ProcessManagerObserver overrides
void OnServiceWorkerRegistered(const WorkerId& worker_id) override;
content::BrowserContext* const browser_context_;
// Delegate provided in the constructor. Should outlive this object.
Delegate* const delegate_;
// Keyed services we depend on. Cached here for repeated access.
ExtensionSystem* const extension_system_;
ExtensionPrefs* const extension_prefs_;
ExtensionRegistry* const registry_;
RendererStartupHelper* const renderer_helper_;
// Map of DevToolsAgentHost instances that are detached,
// waiting for an extension to be reloaded.
using OrphanedDevTools =
std::map<std::string,
std::vector<scoped_refptr<content::DevToolsAgentHost>>>;
OrphanedDevTools orphaned_dev_tools_;
// Map unloaded extensions' ids to their paths. When a temporarily loaded
// extension is unloaded, we lose the information about it and don't have
// any in the extension preferences file.
using UnloadedExtensionPathMap = std::map<ExtensionId, base::FilePath>;
UnloadedExtensionPathMap unloaded_extension_paths_;
// Store the ids of reloading extensions. We use this to re-enable extensions
// which were disabled for a reload.
ExtensionIdSet reloading_extensions_;
// Store the paths of extensions that failed to reload. We use this to retry
// reload.
std::set<base::FilePath> failed_to_reload_unpacked_extensions_;
base::ScopedObservation<ProcessManager, ProcessManagerObserver>
process_manager_observation_{this};
base::WeakPtrFactory<ExtensionRegistrar> weak_factory_{this};
};
} // namespace extensions
#endif // EXTENSIONS_BROWSER_EXTENSION_REGISTRAR_H_