1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef EXTENSIONS_BROWSER_EXTENSION_REGISTRAR_H_
6 #define EXTENSIONS_BROWSER_EXTENSION_REGISTRAR_H_
7 
8 #include <memory>
9 
10 #include "base/macros.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/memory/weak_ptr.h"
13 #include "extensions/browser/unloaded_extension_reason.h"
14 #include "extensions/common/extension.h"
15 #include "extensions/common/extension_id.h"
16 
17 namespace base {
18 class FilePath;
19 }  // namespace base
20 
21 namespace content {
22 class BrowserContext;
23 class DevToolsAgentHost;
24 }  // namespace content
25 
26 namespace extensions {
27 
28 class Extension;
29 class ExtensionHost;
30 class ExtensionPrefs;
31 class ExtensionRegistry;
32 class ExtensionSystem;
33 class RendererStartupHelper;
34 
35 // ExtensionRegistrar drives the stages of registering and unregistering
36 // extensions for a BrowserContext. It uses the ExtensionRegistry to track
37 // extension states. Other classes may query the ExtensionRegistry directly,
38 // but eventually only ExtensionRegistrar will be able to make changes to it.
39 class ExtensionRegistrar {
40  public:
41   // How to surface an extension load error, e.g. showing an error dialog. The
42   // actual behavior is up to the embedder.
43   enum class LoadErrorBehavior {
44     kQuiet = 0,  // Just log the error.
45     kNoisy,      // Show an error dialog.
46   };
47 
48   // Delegate for embedder-specific functionality like policy and permissions.
49   class Delegate {
50    public:
51     Delegate() = default;
52     virtual ~Delegate() = default;
53 
54     // Called before |extension| is added. |old_extension| is the extension
55     // being replaced, in the case of a reload or upgrade.
56     virtual void PreAddExtension(const Extension* extension,
57                                  const Extension* old_extension) = 0;
58 
59     // Handles updating the browser context when an extension is activated
60     // (becomes enabled).
61     virtual void PostActivateExtension(
62         scoped_refptr<const Extension> extension) = 0;
63 
64     // Handles updating the browser context when an enabled extension is
65     // deactivated (whether disabled or removed).
66     virtual void PostDeactivateExtension(
67         scoped_refptr<const Extension> extension) = 0;
68 
69     // Given an extension ID and/or path, loads that extension as a reload.
70     virtual void LoadExtensionForReload(
71         const ExtensionId& extension_id,
72         const base::FilePath& path,
73         LoadErrorBehavior load_error_behavior) = 0;
74 
75     // Returns true if the extension is allowed to be enabled or disabled,
76     // respectively.
77     virtual bool CanEnableExtension(const Extension* extension) = 0;
78     virtual bool CanDisableExtension(const Extension* extension) = 0;
79 
80     // Returns true if the extension should be blocked.
81     virtual bool ShouldBlockExtension(const Extension* extension) = 0;
82 
83    private:
84     DISALLOW_COPY_AND_ASSIGN(Delegate);
85   };
86 
87   // The provided Delegate should outlive this object.
88   ExtensionRegistrar(content::BrowserContext* browser_context,
89                      Delegate* delegate);
90   virtual ~ExtensionRegistrar();
91 
92   // Adds the extension to the ExtensionRegistry. The extension will be added to
93   // the enabled, disabled, blocklisted or blocked set. If the extension is
94   // added as enabled, it will be activated.
95   void AddExtension(scoped_refptr<const Extension> extension);
96 
97   // Removes |extension| from the extension system by deactivating it if it is
98   // enabled and removing references to it from the ExtensionRegistry's
99   // enabled or disabled sets.
100   // Note: Extensions will not be removed from other sets (terminated,
101   // blocklisted or blocked). ExtensionService handles that, since it also adds
102   // it to those sets. TODO(michaelpg): Make ExtensionRegistrar the sole mutator
103   // of ExtensionRegsitry to simplify this usage.
104   void RemoveExtension(const ExtensionId& extension_id,
105                        UnloadedExtensionReason reason);
106 
107   // If the extension is disabled, marks it as enabled and activates it for use.
108   // Otherwise, simply updates the ExtensionPrefs. (Blocklisted or blocked
109   // extensions cannot be enabled.)
110   void EnableExtension(const ExtensionId& extension_id);
111 
112   // Marks |extension| as disabled and deactivates it. The ExtensionRegistry
113   // retains a reference to it, so it can be enabled later.
114   void DisableExtension(const ExtensionId& extension_id, int disable_reasons);
115 
116   // Attempts to reload the specified extension by disabling it if it is enabled
117   // and requesting the Delegate load it again.
118   // NOTE: Reloading an extension can invalidate |extension_id| and Extension
119   // pointers for the given extension. Consider making a copy of |extension_id|
120   // first and retrieving a new Extension pointer afterwards.
121   void ReloadExtension(const ExtensionId extension_id,
122                        LoadErrorBehavior load_error_behavior);
123 
124   // TODO(michaelpg): Add methods for blocklisting and blocking extensions.
125 
126   // Deactivates the extension, adding its id to the list of terminated
127   // extensions.
128   void TerminateExtension(const ExtensionId& extension_id);
129 
130   // Removes the extension from the terminated list. TODO(michaelpg): Make a
131   // private implementation detail when no longer called from ExtensionService.
132   void UntrackTerminatedExtension(const ExtensionId& extension_id);
133 
134   // Returns true if the extension is enabled (including terminated), or if it
135   // is not loaded but isn't explicitly disabled in preferences.
136   bool IsExtensionEnabled(const ExtensionId& extension_id) const;
137 
138   // Called after the render view for the background page with the associated
139   // host is created.
140   void DidCreateRenderViewForBackgroundPage(ExtensionHost* host);
141 
142   void OnUnpackedExtensionReloadFailed(const base::FilePath& path);
143 
144  private:
145   // Adds the extension to the appropriate registry set, based on ExtensionPrefs
146   // and our |delegate_|. Activates the extension if it's added to the enabled
147   // set.
148   void AddNewExtension(scoped_refptr<const Extension> extension);
149 
150   // Activates |extension| by marking it enabled and notifying other components
151   // about it.
152   void ActivateExtension(const Extension* extension, bool is_newly_added);
153 
154   // Triggers the unloaded notifications to deactivate an extension.
155   void DeactivateExtension(const Extension* extension,
156                            UnloadedExtensionReason reason);
157 
158   // Given an extension that was disabled for reloading, completes the reload
159   // by replacing the old extension with the new version and enabling it.
160   // Returns true on success.
161   bool ReplaceReloadedExtension(scoped_refptr<const Extension> extension);
162 
163   // Marks the extension ready after URLRequestContexts have been updated on
164   // the IO thread.
165   void OnExtensionRegisteredWithRequestContexts(
166       scoped_refptr<const Extension> extension);
167 
168   // Upon reloading an extension, spins up its lazy background page if
169   // necessary.
170   void MaybeSpinUpLazyBackgroundPage(const Extension* extension);
171 
172   content::BrowserContext* const browser_context_;
173 
174   // Delegate provided in the constructor. Should outlive this object.
175   Delegate* const delegate_;
176 
177   // Keyed services we depend on. Cached here for repeated access.
178   ExtensionSystem* const extension_system_;
179   ExtensionPrefs* const extension_prefs_;
180   ExtensionRegistry* const registry_;
181   RendererStartupHelper* const renderer_helper_;
182 
183   // Map of DevToolsAgentHost instances that are detached,
184   // waiting for an extension to be reloaded.
185   using OrphanedDevTools =
186       std::map<std::string, scoped_refptr<content::DevToolsAgentHost>>;
187   OrphanedDevTools orphaned_dev_tools_;
188 
189   // Map unloaded extensions' ids to their paths. When a temporarily loaded
190   // extension is unloaded, we lose the information about it and don't have
191   // any in the extension preferences file.
192   using UnloadedExtensionPathMap = std::map<ExtensionId, base::FilePath>;
193   UnloadedExtensionPathMap unloaded_extension_paths_;
194 
195   // Store the ids of reloading extensions. We use this to re-enable extensions
196   // which were disabled for a reload.
197   ExtensionIdSet reloading_extensions_;
198 
199   // Store the paths of extensions that failed to reload. We use this to retry
200   // reload.
201   std::set<base::FilePath> failed_to_reload_unpacked_extensions_;
202 
203   base::WeakPtrFactory<ExtensionRegistrar> weak_factory_{this};
204 
205   DISALLOW_COPY_AND_ASSIGN(ExtensionRegistrar);
206 };
207 
208 }  // namespace extensions
209 
210 #endif  // EXTENSIONS_BROWSER_EXTENSION_REGISTRAR_H_
211