[email protected] | c333e79 | 2012-01-06 16:57:39 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | 6014d67 | 2008-12-05 00:38:25 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | eaa7dd18 | 2010-12-14 11:09:00 | [diff] [blame] | 5 | #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_H_ |
| 6 | #define CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_H_ |
[email protected] | 6014d67 | 2008-12-05 00:38:25 | [diff] [blame] | 7 | |
[email protected] | da50530a | 2009-06-15 17:43:01 | [diff] [blame] | 8 | #include <map> |
asargent | 56282ab7 | 2016-09-09 16:58:03 | [diff] [blame] | 9 | #include <memory> |
[email protected] | 31bb5ee6 | 2012-09-12 22:58:40 | [diff] [blame] | 10 | #include <set> |
[email protected] | b0beaa66 | 2009-02-26 00:04:15 | [diff] [blame] | 11 | #include <string> |
[email protected] | 6014d67 | 2008-12-05 00:38:25 | [diff] [blame] | 12 | #include <vector> |
| 13 | |
[email protected] | e078590 | 2011-05-19 23:34:17 | [diff] [blame] | 14 | #include "base/compiler_specific.h" |
[email protected] | 5799981 | 2013-02-24 05:40:52 | [diff] [blame] | 15 | #include "base/files/file_path.h" |
[email protected] | a918f87 | 2010-06-01 14:30:51 | [diff] [blame] | 16 | #include "base/gtest_prod_util.h" |
avi | a2f4804a | 2015-12-24 23:11:13 | [diff] [blame] | 17 | #include "base/macros.h" |
[email protected] | 3b63f8f4 | 2011-03-28 01:54:15 | [diff] [blame] | 18 | #include "base/memory/ref_counted.h" |
[email protected] | 14908b7 | 2011-04-20 06:54:36 | [diff] [blame] | 19 | #include "base/memory/weak_ptr.h" |
Karandeep Bhatia | a893065 | 2017-10-11 17:41:12 | [diff] [blame] | 20 | #include "base/optional.h" |
Evan Stade | d89e11c | 2019-09-05 18:08:56 | [diff] [blame] | 21 | #include "base/scoped_observer.h" |
[email protected] | 00e7bef | 2013-06-10 20:35:17 | [diff] [blame] | 22 | #include "base/strings/string16.h" |
[email protected] | fdd679b | 2012-11-15 20:49:39 | [diff] [blame] | 23 | #include "chrome/browser/extensions/blacklist.h" |
binjin | 1569c9b | 2014-09-05 13:33:18 | [diff] [blame] | 24 | #include "chrome/browser/extensions/extension_management.h" |
Sergey Poromov | 0360b9e7 | 2018-04-19 17:37:29 | [diff] [blame] | 25 | #include "chrome/browser/extensions/forced_extensions/installation_tracker.h" |
xiyuan | f6a4c6a6 | 2016-04-19 18:14:54 | [diff] [blame] | 26 | #include "chrome/browser/extensions/install_gate.h" |
[email protected] | f3d3b38 | 2014-03-14 21:19:28 | [diff] [blame] | 27 | #include "chrome/browser/extensions/pending_extension_manager.h" |
Evan Stade | d89e11c | 2019-09-05 18:08:56 | [diff] [blame] | 28 | #include "chrome/browser/profiles/profile_manager.h" |
| 29 | #include "chrome/browser/profiles/profile_manager_observer.h" |
Greg Thompson | 8bcd799b | 2018-08-10 09:49:33 | [diff] [blame] | 30 | #include "chrome/browser/upgrade_detector/upgrade_observer.h" |
skym | 7160384 | 2016-10-10 18:17:31 | [diff] [blame] | 31 | #include "components/sync/model/string_ordinal.h" |
[email protected] | 6c2381d | 2011-10-19 02:52:53 | [diff] [blame] | 32 | #include "content/public/browser/notification_observer.h" |
| 33 | #include "content/public/browser/notification_registrar.h" |
ginkage | 553af320 | 2015-02-04 12:39:09 | [diff] [blame] | 34 | #include "extensions/browser/crx_file_info.h" |
Ivan Sandrk | 4a55dc2 | 2018-05-17 18:14:48 | [diff] [blame] | 35 | #include "extensions/browser/disable_reason.h" |
xiyuan | f6a4c6a6 | 2016-04-19 18:14:54 | [diff] [blame] | 36 | #include "extensions/browser/extension_prefs.h" |
Devlin Cronin | 5b35a08 | 2017-10-05 20:44:36 | [diff] [blame] | 37 | #include "extensions/browser/extension_registrar.h" |
[email protected] | 301116c6 | 2013-11-26 10:37:45 | [diff] [blame] | 38 | #include "extensions/browser/external_provider_interface.h" |
[email protected] | 4a1d9c0d | 2014-06-13 12:50:11 | [diff] [blame] | 39 | #include "extensions/browser/install_flag.h" |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 40 | #include "extensions/browser/process_manager.h" |
[email protected] | e43c61f | 2014-07-20 21:46:34 | [diff] [blame] | 41 | #include "extensions/browser/uninstall_reason.h" |
Scott Violet | c8240b0 | 2018-03-08 22:03:59 | [diff] [blame] | 42 | #include "extensions/buildflags/buildflags.h" |
[email protected] | e4452d3 | 2013-11-15 23:07:41 | [diff] [blame] | 43 | #include "extensions/common/extension.h" |
Devlin Cronin | 06087655 | 2020-01-06 22:20:39 | [diff] [blame] | 44 | #include "extensions/common/extension_id.h" |
[email protected] | 289c44b | 2013-12-17 03:26:57 | [diff] [blame] | 45 | #include "extensions/common/extension_set.h" |
[email protected] | d42c1115 | 2013-08-22 19:36:32 | [diff] [blame] | 46 | #include "extensions/common/manifest.h" |
[email protected] | 6014d67 | 2008-12-05 00:38:25 | [diff] [blame] | 47 | |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 48 | #if !BUILDFLAG(ENABLE_EXTENSIONS) |
thestig | 44b9ce2 | 2014-10-17 03:19:28 | [diff] [blame] | 49 | #error "Extensions must be enabled" |
| 50 | #endif |
| 51 | |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 52 | class BlacklistedExtensionSyncServiceTest; |
mukai | 87a8d40 | 2014-09-15 20:15:09 | [diff] [blame] | 53 | class HostContentSettingsMap; |
[email protected] | 81e6378 | 2009-02-27 19:35:09 | [diff] [blame] | 54 | class Profile; |
[email protected] | aa14270 | 2010-03-26 01:26:33 | [diff] [blame] | 55 | |
[email protected] | 7f8f24f | 2012-11-15 19:40:14 | [diff] [blame] | 56 | namespace base { |
[email protected] | 2f3b1cc | 2014-03-17 23:07:15 | [diff] [blame] | 57 | class CommandLine; |
Christopher Lam | ebb9020 | 2019-04-04 03:42:36 | [diff] [blame] | 58 | class OneShotEvent; |
[email protected] | 7f8f24f | 2012-11-15 19:40:14 | [diff] [blame] | 59 | } |
| 60 | |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 61 | FORWARD_DECLARE_TEST(BlacklistedExtensionSyncServiceTest, |
| 62 | SyncBlacklistedExtension); |
| 63 | |
[email protected] | 9c70e0d9 | 2012-07-16 08:39:44 | [diff] [blame] | 64 | namespace extensions { |
ryanackley | 48bedbd | 2015-01-27 23:12:14 | [diff] [blame] | 65 | class AppDataMigrator; |
[email protected] | d8c8f25f | 2011-11-02 18:18:01 | [diff] [blame] | 66 | class ComponentLoader; |
[email protected] | bf3d9df | 2012-07-24 23:20:27 | [diff] [blame] | 67 | class CrxInstaller; |
[email protected] | c77f235 | 2012-08-08 22:07:58 | [diff] [blame] | 68 | class ExtensionActionStorageManager; |
[email protected] | 373daf97 | 2014-04-10 01:50:44 | [diff] [blame] | 69 | class ExtensionErrorController; |
[email protected] | bb1bc9b3 | 2013-12-21 03:09:14 | [diff] [blame] | 70 | class ExtensionRegistry; |
[email protected] | bd30672 | 2012-07-11 20:43:59 | [diff] [blame] | 71 | class ExtensionSystem; |
[email protected] | 42a0816 | 2012-03-16 18:09:11 | [diff] [blame] | 72 | class ExtensionUpdater; |
[email protected] | 2894a51 | 2014-06-26 19:03:56 | [diff] [blame] | 73 | class ExternalInstallManager; |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 74 | class SharedModuleService; |
[email protected] | a9aa62b31 | 2013-11-29 05:35:06 | [diff] [blame] | 75 | class UpdateObserver; |
Devlin Cronin | c9c4efe | 2020-01-07 21:04:05 | [diff] [blame] | 76 | enum class UnloadedExtensionReason; |
[email protected] | 163ed19 | 2012-07-24 19:31:07 | [diff] [blame] | 77 | |
[email protected] | d1ca0ed1 | 2009-07-01 18:24:32 | [diff] [blame] | 78 | // This is an interface class to encapsulate the dependencies that |
[email protected] | 2859946f | 2011-04-04 18:18:06 | [diff] [blame] | 79 | // various classes have on ExtensionService. This allows easy mocking. |
[email protected] | f8aefb13 | 2013-10-30 09:29:52 | [diff] [blame] | 80 | class ExtensionServiceInterface |
| 81 | : public base::SupportsWeakPtr<ExtensionServiceInterface> { |
[email protected] | d1ca0ed1 | 2009-07-01 18:24:32 | [diff] [blame] | 82 | public: |
[email protected] | 2859946f | 2011-04-04 18:18:06 | [diff] [blame] | 83 | virtual ~ExtensionServiceInterface() {} |
[email protected] | ca97594 | 2014-01-07 12:06:47 | [diff] [blame] | 84 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 85 | // Gets the object managing the set of pending extensions. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 86 | virtual PendingExtensionManager* pending_extension_manager() = 0; |
[email protected] | 420a0ec | 2011-06-01 01:07:03 | [diff] [blame] | 87 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 88 | // Installs an update with the contents from |extension_path|. Returns true if |
| 89 | // the install can be started. Sets |out_crx_installer| to the installer if |
| 90 | // one was started. |
| 91 | // TODO(aa): This method can be removed. ExtensionUpdater could use |
| 92 | // CrxInstaller directly instead. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 93 | virtual bool UpdateExtension(const CRXFileInfo& file, |
| 94 | bool file_ownership_passed, |
| 95 | CrxInstaller** out_crx_installer) = 0; |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 96 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 97 | // Returns an update for an extension with the specified id, if installation |
| 98 | // of that update was previously delayed because the extension was in use. If |
| 99 | // no updates are pending for the extension returns NULL. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 100 | virtual const Extension* GetPendingExtensionUpdate( |
[email protected] | 76b6544 | 2012-11-17 14:11:48 | [diff] [blame] | 101 | const std::string& extension_id) const = 0; |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 102 | |
Toni Barzic | 667db0d3 | 2018-01-09 18:00:19 | [diff] [blame] | 103 | // Attempts finishing installation of an update for an extension with the |
| 104 | // specified id, when installation of that extension was previously delayed. |
| 105 | // |install_immediately| - Whether the extension should be installed if it's |
| 106 | // currently in use. |
| 107 | // Returns whether the extension installation was finished. |
| 108 | virtual bool FinishDelayedInstallationIfReady(const std::string& extension_id, |
| 109 | bool install_immediately) = 0; |
[email protected] | 76b6544 | 2012-11-17 14:11:48 | [diff] [blame] | 110 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 111 | // Returns true if the extension with the given |extension_id| is enabled. |
mfoltz | 96f329c | 2016-01-13 18:16:58 | [diff] [blame] | 112 | // This will only return a valid answer for installed extensions (regardless |
| 113 | // of whether it is currently loaded or not). Loaded extensions return true |
| 114 | // if they are currently loaded or terminated. Unloaded extensions will |
| 115 | // return true if they are not blocked, disabled, blacklisted or uninstalled |
| 116 | // (for external extensions). |
[email protected] | c3cfb01 | 2011-04-06 22:07:35 | [diff] [blame] | 117 | virtual bool IsExtensionEnabled(const std::string& extension_id) const = 0; |
[email protected] | 2859946f | 2011-04-04 18:18:06 | [diff] [blame] | 118 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 119 | // Go through each extension and unload those that are not allowed to run by |
| 120 | // management policy providers (ie. network admin and Google-managed |
| 121 | // blacklist). |
[email protected] | 4ee07c6 | 2012-08-21 12:40:42 | [diff] [blame] | 122 | virtual void CheckManagementPolicy() = 0; |
[email protected] | 5ef47ec | 2010-01-28 05:58:05 | [diff] [blame] | 123 | |
[email protected] | 3120660 | 2011-04-13 23:07:32 | [diff] [blame] | 124 | // Safe to call multiple times in a row. |
| 125 | // |
[email protected] | 90310d9 | 2011-04-17 07:35:04 | [diff] [blame] | 126 | // TODO(akalin): Remove this method (and others) once we refactor |
| 127 | // themes sync to not use it directly. |
[email protected] | 3120660 | 2011-04-13 23:07:32 | [diff] [blame] | 128 | virtual void CheckForUpdatesSoon() = 0; |
[email protected] | 25ae015 | 2011-11-18 14:40:02 | [diff] [blame] | 129 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 130 | // Adds |extension| to this ExtensionService and notifies observers that the |
Michael Giuffrida | 023e353 | 2017-09-28 23:21:21 | [diff] [blame] | 131 | // extension has been loaded. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 132 | virtual void AddExtension(const Extension* extension) = 0; |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 133 | |
| 134 | // Check if we have preferences for the component extension and, if not or if |
| 135 | // the stored version differs, install the extension (without requirements |
| 136 | // checking) before calling AddExtension. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 137 | virtual void AddComponentExtension(const Extension* extension) = 0; |
[email protected] | 25ae015 | 2011-11-18 14:40:02 | [diff] [blame] | 138 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 139 | // Unload the specified extension. |
limasdf | 0deef204 | 2017-05-03 19:17:17 | [diff] [blame] | 140 | virtual void UnloadExtension(const std::string& extension_id, |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 141 | UnloadedExtensionReason reason) = 0; |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 142 | |
| 143 | // Remove the specified component extension. |
[email protected] | 8b1ec20 | 2013-09-05 02:09:50 | [diff] [blame] | 144 | virtual void RemoveComponentExtension(const std::string& extension_id) = 0; |
[email protected] | 25ae015 | 2011-11-18 14:40:02 | [diff] [blame] | 145 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 146 | // Whether the extension service is ready. |
[email protected] | 25ae015 | 2011-11-18 14:40:02 | [diff] [blame] | 147 | virtual bool is_ready() = 0; |
[email protected] | d1ca0ed1 | 2009-07-01 18:24:32 | [diff] [blame] | 148 | }; |
[email protected] | fbcc4030 | 2009-06-12 20:45:45 | [diff] [blame] | 149 | |
[email protected] | fafdc84 | 2014-01-17 18:09:08 | [diff] [blame] | 150 | // Manages installed and running Chromium extensions. An instance is shared |
| 151 | // between normal and incognito profiles. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 152 | class ExtensionService : public ExtensionServiceInterface, |
| 153 | public ExternalProviderInterface::VisitorInterface, |
| 154 | public content::NotificationObserver, |
| 155 | public Blacklist::Observer, |
| 156 | public ExtensionManagement::Observer, |
| 157 | public UpgradeObserver, |
Evan Stade | d89e11c | 2019-09-05 18:08:56 | [diff] [blame] | 158 | public ExtensionRegistrar::Delegate, |
| 159 | public ProfileManagerObserver { |
[email protected] | 4f313d5 | 2009-05-21 00:42:29 | [diff] [blame] | 160 | public: |
[email protected] | 73c4793 | 2010-12-06 18:13:43 | [diff] [blame] | 161 | // Constructor stores pointers to |profile| and |extension_prefs| but |
| 162 | // ownership remains at caller. |
[email protected] | eaa7dd18 | 2010-12-14 11:09:00 | [diff] [blame] | 163 | ExtensionService(Profile* profile, |
[email protected] | 2f3b1cc | 2014-03-17 23:07:15 | [diff] [blame] | 164 | const base::CommandLine* command_line, |
[email protected] | 650b2d5 | 2013-02-10 03:41:45 | [diff] [blame] | 165 | const base::FilePath& install_directory, |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 166 | ExtensionPrefs* extension_prefs, |
| 167 | Blacklist* blacklist, |
[email protected] | 0436b10 | 2011-04-15 18:30:03 | [diff] [blame] | 168 | bool autoupdate_enabled, |
[email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 169 | bool extensions_enabled, |
Christopher Lam | ebb9020 | 2019-04-04 03:42:36 | [diff] [blame] | 170 | base::OneShotEvent* ready); |
[email protected] | 6014d67 | 2008-12-05 00:38:25 | [diff] [blame] | 171 | |
dcheng | ae36a4a | 2014-10-21 12:36:36 | [diff] [blame] | 172 | ~ExtensionService() override; |
[email protected] | 14908b7 | 2011-04-20 06:54:36 | [diff] [blame] | 173 | |
[email protected] | eb24538 | 2014-07-28 22:23:14 | [diff] [blame] | 174 | // ExtensionServiceInterface implementation. |
| 175 | // |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 176 | PendingExtensionManager* pending_extension_manager() override; |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 177 | bool UpdateExtension(const CRXFileInfo& file, |
dcheng | ae36a4a | 2014-10-21 12:36:36 | [diff] [blame] | 178 | bool file_ownership_passed, |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 179 | CrxInstaller** out_crx_installer) override; |
dcheng | ae36a4a | 2014-10-21 12:36:36 | [diff] [blame] | 180 | bool IsExtensionEnabled(const std::string& extension_id) const override; |
limasdf | 0deef204 | 2017-05-03 19:17:17 | [diff] [blame] | 181 | void UnloadExtension(const std::string& extension_id, |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 182 | UnloadedExtensionReason reason) override; |
dcheng | ae36a4a | 2014-10-21 12:36:36 | [diff] [blame] | 183 | void RemoveComponentExtension(const std::string& extension_id) override; |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 184 | void AddExtension(const Extension* extension) override; |
| 185 | void AddComponentExtension(const Extension* extension) override; |
| 186 | const Extension* GetPendingExtensionUpdate( |
mostynb | a15bee1 | 2014-10-04 00:40:32 | [diff] [blame] | 187 | const std::string& extension_id) const override; |
Toni Barzic | 667db0d3 | 2018-01-09 18:00:19 | [diff] [blame] | 188 | bool FinishDelayedInstallationIfReady(const std::string& extension_id, |
| 189 | bool install_immediately) override; |
dcheng | ae36a4a | 2014-10-21 12:36:36 | [diff] [blame] | 190 | void CheckManagementPolicy() override; |
| 191 | void CheckForUpdatesSoon() override; |
| 192 | bool is_ready() override; |
[email protected] | aa14270 | 2010-03-26 01:26:33 | [diff] [blame] | 193 | |
lazyboy | e863417 | 2016-01-28 00:10:48 | [diff] [blame] | 194 | // ExternalProvider::VisitorInterface implementation. |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 195 | // Exposed for testing. |
lazyboy | e863417 | 2016-01-28 00:10:48 | [diff] [blame] | 196 | bool OnExternalExtensionFileFound( |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 197 | const ExternalInstallInfoFile& info) override; |
dcheng | ae36a4a | 2014-10-21 12:36:36 | [diff] [blame] | 198 | bool OnExternalExtensionUpdateUrlFound( |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 199 | const ExternalInstallInfoUpdateUrl& info, |
lazyboy | e863417 | 2016-01-28 00:10:48 | [diff] [blame] | 200 | bool is_initial_load) override; |
dcheng | ae36a4a | 2014-10-21 12:36:36 | [diff] [blame] | 201 | void OnExternalProviderReady( |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 202 | const ExternalProviderInterface* provider) override; |
lazyboy | e863417 | 2016-01-28 00:10:48 | [diff] [blame] | 203 | void OnExternalProviderUpdateComplete( |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 204 | const ExternalProviderInterface* provider, |
| 205 | const std::vector<ExternalInstallInfoUpdateUrl>& |
lazyboy | e863417 | 2016-01-28 00:10:48 | [diff] [blame] | 206 | external_update_url_extensions, |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 207 | const std::vector<ExternalInstallInfoFile>& external_file_extensions, |
lazyboy | e863417 | 2016-01-28 00:10:48 | [diff] [blame] | 208 | const std::set<std::string>& removed_extensions) override; |
[email protected] | ec5b50d | 2010-10-09 16:35:18 | [diff] [blame] | 209 | |
binjin | 1569c9b | 2014-09-05 13:33:18 | [diff] [blame] | 210 | // ExtensionManagement::Observer implementation: |
dcheng | ae36a4a | 2014-10-21 12:36:36 | [diff] [blame] | 211 | void OnExtensionManagementSettingsChanged() override; |
binjin | 1569c9b | 2014-09-05 13:33:18 | [diff] [blame] | 212 | |
[email protected] | 6014d67 | 2008-12-05 00:38:25 | [diff] [blame] | 213 | // Initialize and start all installed extensions. |
[email protected] | 9f1087e | 2009-06-15 17:29:32 | [diff] [blame] | 214 | void Init(); |
[email protected] | 6014d67 | 2008-12-05 00:38:25 | [diff] [blame] | 215 | |
[email protected] | 47b89656 | 2012-08-22 23:55:15 | [diff] [blame] | 216 | // Called when the associated Profile is going to be destroyed. |
| 217 | void Shutdown(); |
| 218 | |
[email protected] | 2380c6b | 2013-01-09 02:33:13 | [diff] [blame] | 219 | // Reloads the specified extension, sending the onLaunched() event to it if it |
| 220 | // currently has any window showing. |
[email protected] | bca4b83 | 2014-07-17 20:22:34 | [diff] [blame] | 221 | // Allows noisy failures. |
thestig | 7b4bd93 | 2014-09-09 22:44:31 | [diff] [blame] | 222 | // NOTE: Reloading an extension can invalidate |extension_id| and Extension |
| 223 | // pointers for the given extension. Consider making a copy of |extension_id| |
| 224 | // first and retrieving a new Extension pointer afterwards. |
[email protected] | 757d60a | 2014-05-23 00:11:44 | [diff] [blame] | 225 | void ReloadExtension(const std::string& extension_id); |
[email protected] | 9cddd470 | 2009-07-27 22:09:40 | [diff] [blame] | 226 | |
[email protected] | bca4b83 | 2014-07-17 20:22:34 | [diff] [blame] | 227 | // Suppresses noisy failures. |
| 228 | void ReloadExtensionWithQuietFailure(const std::string& extension_id); |
| 229 | |
[email protected] | 631cf82 | 2009-05-15 07:01:25 | [diff] [blame] | 230 | // Uninstalls the specified extension. Callers should only call this method |
[email protected] | cc2f55c | 2014-07-08 02:19:04 | [diff] [blame] | 231 | // with extensions that exist. |reason| lets the caller specify why the |
| 232 | // extension is uninstalled. |
Devlin Cronin | 218df7f | 2017-11-21 21:41:31 | [diff] [blame] | 233 | // Note: this method synchronously removes the extension from the |
| 234 | // set of installed extensions stored in the ExtensionRegistry, but will |
| 235 | // asynchronously remove site-related data and the files stored on disk. |
| 236 | // Returns true if an uninstall was successfully triggered; this can fail if |
| 237 | // the extension cannot be uninstalled (such as a policy force-installed |
| 238 | // extension). |
Devlin Cronin | ad24e5b | 2017-11-29 00:54:43 | [diff] [blame] | 239 | bool UninstallExtension(const std::string& extension_id, |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 240 | UninstallReason reason, |
Devlin Cronin | ad24e5b | 2017-11-29 00:54:43 | [diff] [blame] | 241 | base::string16* error); |
[email protected] | 631cf82 | 2009-05-15 07:01:25 | [diff] [blame] | 242 | |
[email protected] | 06f9256 | 2011-04-29 19:27:31 | [diff] [blame] | 243 | // Enables the extension. If the extension is already enabled, does |
| 244 | // nothing. |
Devlin Cronin | ad24e5b | 2017-11-29 00:54:43 | [diff] [blame] | 245 | void EnableExtension(const std::string& extension_id); |
[email protected] | 06f9256 | 2011-04-29 19:27:31 | [diff] [blame] | 246 | |
treib | c119232 | 2015-05-20 12:56:07 | [diff] [blame] | 247 | // Disables the extension. If the extension is already disabled, just adds |
Minh X. Nguyen | 4547901 | 2017-08-18 21:35:36 | [diff] [blame] | 248 | // the |disable_reasons| (a bitmask of disable_reason::DisableReason - there |
| 249 | // can be multiple DisableReasons e.g. when an extension comes in disabled |
| 250 | // from Sync). If the extension cannot be disabled (due to policy), does |
| 251 | // nothing. |
Devlin Cronin | ad24e5b | 2017-11-29 00:54:43 | [diff] [blame] | 252 | void DisableExtension(const std::string& extension_id, int disable_reasons); |
[email protected] | 0c6da50 | 2009-08-14 22:32:39 | [diff] [blame] | 253 | |
Ivan Sandrk | 4a55dc2 | 2018-05-17 18:14:48 | [diff] [blame] | 254 | // Same as |DisableExtension|, but assumes that the request to disable |
| 255 | // |extension_id| originates from |source_extension| when evaluating whether |
| 256 | // the extension can be disabled. Please see |ExtensionMayModifySettings| |
| 257 | // for details. |
| 258 | void DisableExtensionWithSource( |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 259 | const Extension* source_extension, |
Ivan Sandrk | 4a55dc2 | 2018-05-17 18:14:48 | [diff] [blame] | 260 | const std::string& extension_id, |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 261 | disable_reason::DisableReason disable_reasons); |
Ivan Sandrk | 4a55dc2 | 2018-05-17 18:14:48 | [diff] [blame] | 262 | |
[email protected] | 3082fe3 | 2013-08-06 11:12:38 | [diff] [blame] | 263 | // Disable non-default and non-managed extensions with ids not in |
| 264 | // |except_ids|. Default extensions are those from the Web Store with |
| 265 | // |was_installed_by_default| flag. |
mtomasz | 294bb3e | 2017-01-24 02:17:52 | [diff] [blame] | 266 | void DisableUserExtensionsExcept(const std::vector<std::string>& except_ids); |
[email protected] | e516e4c | 2013-06-12 17:41:14 | [diff] [blame] | 267 | |
mlerman | 6a37b6a4 | 2014-11-26 22:10:53 | [diff] [blame] | 268 | // Puts all extensions in a blocked state: Unloading every extension, and |
| 269 | // preventing them from ever loading until UnblockAllExtensions is called. |
| 270 | // This state is stored in preferences, so persists until Chrome restarts. |
| 271 | // |
| 272 | // Component, external component and whitelisted policy installed extensions |
Michael Giuffrida | 6397c59 | 2017-10-09 20:46:53 | [diff] [blame] | 273 | // are exempt from being Blocked (see CanBlockExtension in .cc file). |
mlerman | 6a37b6a4 | 2014-11-26 22:10:53 | [diff] [blame] | 274 | void BlockAllExtensions(); |
| 275 | |
| 276 | // All blocked extensions are reverted to their previous state, and are |
| 277 | // reloaded. Newly added extensions are no longer automatically blocked. |
| 278 | void UnblockAllExtensions(); |
| 279 | |
[email protected] | 8d888c1 | 2010-11-30 00:00:25 | [diff] [blame] | 280 | // Updates the |extension|'s granted permissions lists to include all |
[email protected] | 8d888c1 | 2010-11-30 00:00:25 | [diff] [blame] | 281 | // permissions in the |extension|'s manifest and re-enables the |
| 282 | // extension. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 283 | void GrantPermissionsAndEnableExtension(const Extension* extension); |
[email protected] | 8d888c1 | 2010-11-30 00:00:25 | [diff] [blame] | 284 | |
[email protected] | be08386 | 2012-09-01 03:53:45 | [diff] [blame] | 285 | // Updates the |extension|'s granted permissions lists to include all |
| 286 | // permissions in the |extensions|'s manifest. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 287 | void GrantPermissions(const Extension* extension); |
[email protected] | be08386 | 2012-09-01 03:53:45 | [diff] [blame] | 288 | |
[email protected] | 9f1087e | 2009-06-15 17:29:32 | [diff] [blame] | 289 | // Check for updates (or potentially new extensions from external providers) |
[email protected] | 93fd78f4 | 2009-07-10 16:43:17 | [diff] [blame] | 290 | void CheckForExternalUpdates(); |
[email protected] | 9f1087e | 2009-06-15 17:29:32 | [diff] [blame] | 291 | |
[email protected] | bc151cf9 | 2013-02-12 04:57:26 | [diff] [blame] | 292 | // Informs the service that an extension's files are in place for loading. |
| 293 | // |
Karandeep Bhatia | a893065 | 2017-10-11 17:41:12 | [diff] [blame] | 294 | // |extension| the extension |
| 295 | // |page_ordinal| the location of the extension in the app launcher |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 296 | // |install_flags| a bitmask of InstallFlags |
Karandeep Bhatia | a893065 | 2017-10-11 17:41:12 | [diff] [blame] | 297 | // |dnr_ruleset_checksum| Checksum of the indexed ruleset for the Declarative |
| 298 | // Net Request API. |
| 299 | void OnExtensionInstalled( |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 300 | const Extension* extension, |
Karandeep Bhatia | a893065 | 2017-10-11 17:41:12 | [diff] [blame] | 301 | const syncer::StringOrdinal& page_ordinal, |
| 302 | int install_flags, |
| 303 | const base::Optional<int>& dnr_ruleset_checksum = base::nullopt); |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 304 | void OnExtensionInstalled(const Extension* extension, |
[email protected] | 4a1d9c0d | 2014-06-13 12:50:11 | [diff] [blame] | 305 | const syncer::StringOrdinal& page_ordinal) { |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 306 | OnExtensionInstalled(extension, page_ordinal, |
| 307 | static_cast<int>(kInstallFlagNone)); |
[email protected] | 4a1d9c0d | 2014-06-13 12:50:11 | [diff] [blame] | 308 | } |
[email protected] | 0db124b0 | 2012-11-07 04:55:05 | [diff] [blame] | 309 | |
[email protected] | 9f4e4f08 | 2013-06-21 07:11:19 | [diff] [blame] | 310 | // Checks for delayed installation for all pending installs. |
| 311 | void MaybeFinishDelayedInstallations(); |
| 312 | |
[email protected] | 406027c0 | 2010-09-27 08:03:18 | [diff] [blame] | 313 | // ExtensionHost of background page calls this method right after its render |
| 314 | // view has been created. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 315 | void DidCreateRenderViewForBackgroundPage(ExtensionHost* host); |
[email protected] | 406027c0 | 2010-09-27 08:03:18 | [diff] [blame] | 316 | |
[email protected] | fe2dd774 | 2011-04-19 22:52:49 | [diff] [blame] | 317 | // Record a histogram using the PermissionMessage enum values for each |
| 318 | // permission in |e|. |
| 319 | // NOTE: If this is ever called with high frequency, the implementation may |
| 320 | // need to be made more efficient. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 321 | static void RecordPermissionMessagesHistogram(const Extension* extension, |
| 322 | const char* histogram); |
[email protected] | fe2dd774 | 2011-04-19 22:52:49 | [diff] [blame] | 323 | |
Michael Giuffrida | fcb42036 | 2017-10-11 21:50:26 | [diff] [blame] | 324 | // Unloads the given extension and marks the extension as terminated. This |
[email protected] | e9d7496e | 2014-04-18 01:25:46 | [diff] [blame] | 325 | // doesn't notify the user that the extension was terminated, if such a |
| 326 | // notification is desired the calling code is responsible for doing that. |
| 327 | void TerminateExtension(const std::string& extension_id); |
| 328 | |
mukai | 87a8d40 | 2014-09-15 20:15:09 | [diff] [blame] | 329 | // Register self and content settings API with the specified map. |
mmenke | ad5094ab | 2017-05-15 19:01:14 | [diff] [blame] | 330 | static void RegisterContentSettings( |
| 331 | HostContentSettingsMap* host_content_settings_map, |
| 332 | Profile* profile); |
mukai | 87a8d40 | 2014-09-15 20:15:09 | [diff] [blame] | 333 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 334 | // Adds/Removes update observers. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 335 | void AddUpdateObserver(UpdateObserver* observer); |
| 336 | void RemoveUpdateObserver(UpdateObserver* observer); |
[email protected] | a51c9e9 | 2012-12-09 09:19:20 | [diff] [blame] | 337 | |
xiyuan | f6a4c6a6 | 2016-04-19 18:14:54 | [diff] [blame] | 338 | // Register/unregister an InstallGate with the service. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 339 | void RegisterInstallGate(ExtensionPrefs::DelayReason reason, |
| 340 | InstallGate* install_delayer); |
| 341 | void UnregisterInstallGate(InstallGate* install_delayer); |
xiyuan | f6a4c6a6 | 2016-04-19 18:14:54 | [diff] [blame] | 342 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 343 | ////////////////////////////////////////////////////////////////////////////// |
| 344 | // Simple Accessors |
[email protected] | fa2416f | 2011-05-03 08:41:20 | [diff] [blame] | 345 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 346 | // Returns a WeakPtr to the ExtensionService. |
[email protected] | 77e4dc088 | 2012-06-20 18:53:50 | [diff] [blame] | 347 | base::WeakPtr<ExtensionService> AsWeakPtr() { return base::AsWeakPtr(this); } |
| 348 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 349 | // Returns profile_ as a BrowserContext. |
| 350 | content::BrowserContext* GetBrowserContext() const; |
| 351 | |
| 352 | bool extensions_enabled() const { return extensions_enabled_; } |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 353 | |
| 354 | const base::FilePath& install_directory() const { return install_directory_; } |
| 355 | |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 356 | const ExtensionSet* delayed_installs() const { return &delayed_installs_; } |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 357 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 358 | Profile* profile() { return profile_; } |
| 359 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 360 | // Note that this may return NULL if autoupdate is not turned on. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 361 | ExtensionUpdater* updater() { return updater_.get(); } |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 362 | |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 363 | ComponentLoader* component_loader() { return component_loader_.get(); } |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 364 | |
[email protected] | 3c4abc8 | 2012-10-22 22:25:54 | [diff] [blame] | 365 | bool browser_terminating() const { return browser_terminating_; } |
| 366 | |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 367 | SharedModuleService* shared_module_service() { |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 368 | return shared_module_service_.get(); |
| 369 | } |
| 370 | |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 371 | ExternalInstallManager* external_install_manager() { |
[email protected] | 2894a51 | 2014-06-26 19:03:56 | [diff] [blame] | 372 | return external_install_manager_.get(); |
| 373 | } |
| 374 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 375 | ////////////////////////////////////////////////////////////////////////////// |
| 376 | // For Testing |
| 377 | |
| 378 | // Unload all extensions. Does not send notifications. |
| 379 | void UnloadAllExtensionsForTest(); |
| 380 | |
| 381 | // Reloads all extensions. Does not notify that extensions are ready. |
| 382 | void ReloadExtensionsForTest(); |
| 383 | |
| 384 | // Clear all ExternalProviders. |
| 385 | void ClearProvidersForTesting(); |
| 386 | |
| 387 | // Adds an ExternalProviderInterface for the service to use during testing. |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 388 | void AddProviderForTesting( |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 389 | std::unique_ptr<ExternalProviderInterface> test_provider); |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 390 | |
[email protected] | 8f959f52 | 2014-08-06 06:26:28 | [diff] [blame] | 391 | // Simulate an extension being blacklisted for tests. |
| 392 | void BlacklistExtensionForTest(const std::string& extension_id); |
| 393 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 394 | #if defined(UNIT_TEST) |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 395 | void FinishInstallationForTest(const Extension* extension) { |
benwells | 1dd4acd | 2015-12-09 02:20:24 | [diff] [blame] | 396 | FinishInstallation(extension); |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 397 | } |
Takumi Fujimoto | 43c8c00f | 2017-07-26 22:48:56 | [diff] [blame] | 398 | |
| 399 | void UninstallMigratedExtensionsForTest() { UninstallMigratedExtensions(); } |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 400 | #endif |
| 401 | |
[email protected] | 3c4abc8 | 2012-10-22 22:25:54 | [diff] [blame] | 402 | void set_browser_terminating_for_test(bool value) { |
| 403 | browser_terminating_ = value; |
| 404 | } |
| 405 | |
[email protected] | 4e9b59d | 2013-12-18 06:47:14 | [diff] [blame] | 406 | // Set a callback to be called when all external providers are ready and their |
| 407 | // extensions have been installed. |
| 408 | void set_external_updates_finished_callback_for_test( |
| 409 | const base::Closure& callback) { |
| 410 | external_updates_finished_callback_ = callback; |
| 411 | } |
| 412 | |
lazyboy | 77214d3c | 2017-04-04 16:46:12 | [diff] [blame] | 413 | void set_external_updates_disabled_for_test(bool value) { |
| 414 | external_updates_disabled_for_test_ = value; |
| 415 | } |
| 416 | |
[email protected] | 14908b7 | 2011-04-20 06:54:36 | [diff] [blame] | 417 | private: |
catmullings | 98cd194 | 2016-08-30 22:31:59 | [diff] [blame] | 418 | // Loads extensions specified via a command line flag/switch. |
| 419 | void LoadExtensionsFromCommandLineFlag(const char* switch_name); |
| 420 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 421 | // content::NotificationObserver implementation: |
dcheng | ae36a4a | 2014-10-21 12:36:36 | [diff] [blame] | 422 | void Observe(int type, |
| 423 | const content::NotificationSource& source, |
| 424 | const content::NotificationDetails& details) override; |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 425 | |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 426 | // Blacklist::Observer implementation. |
dcheng | ae36a4a | 2014-10-21 12:36:36 | [diff] [blame] | 427 | void OnBlacklistUpdated() override; |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 428 | |
weidongg | 0469523 | 2017-06-09 00:01:05 | [diff] [blame] | 429 | // UpgradeObserver implementation. |
| 430 | void OnUpgradeRecommended() override; |
| 431 | |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 432 | // ExtensionRegistrar::Delegate implementation. |
| 433 | void PreAddExtension(const Extension* extension, |
| 434 | const Extension* old_extension) override; |
| 435 | void PostActivateExtension(scoped_refptr<const Extension> extension) override; |
Michael Giuffrida | 6397c59 | 2017-10-09 20:46:53 | [diff] [blame] | 436 | void PostDeactivateExtension( |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 437 | scoped_refptr<const Extension> extension) override; |
| 438 | void LoadExtensionForReload( |
| 439 | const ExtensionId& extension_id, |
| 440 | const base::FilePath& path, |
| 441 | ExtensionRegistrar::LoadErrorBehavior load_error_behavior) override; |
| 442 | bool CanEnableExtension(const Extension* extension) override; |
| 443 | bool CanDisableExtension(const Extension* extension) override; |
| 444 | bool ShouldBlockExtension(const Extension* extension) override; |
Michael Giuffrida | 6397c59 | 2017-10-09 20:46:53 | [diff] [blame] | 445 | |
Evan Stade | d89e11c | 2019-09-05 18:08:56 | [diff] [blame] | 446 | // ProfileManagerObserver implementation. |
| 447 | void OnProfileMarkedForPermanentDeletion(Profile* profile) override; |
| 448 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 449 | // For the extension in |version_path| with |id|, check to see if it's an |
| 450 | // externally managed extension. If so, uninstall it. |
| 451 | void CheckExternalUninstall(const std::string& id); |
| 452 | |
rkaplow | a8fd8d3 | 2015-02-25 21:27:56 | [diff] [blame] | 453 | // Attempt to enable all disabled extensions which the only disabled reason is |
| 454 | // reloading. |
| 455 | void EnabledReloadableExtensions(); |
| 456 | |
| 457 | // Finish install (if possible) of extensions that were still delayed while |
| 458 | // the browser was shut down. |
| 459 | void MaybeFinishShutdownDelayed(); |
| 460 | |
[email protected] | 2d19eb6e | 2014-01-27 17:30:00 | [diff] [blame] | 461 | // Populates greylist_. |
| 462 | void LoadGreylistFromPrefs(); |
| 463 | |
[email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 464 | // Signals *ready_ and sends a notification to the listeners. |
[email protected] | 820d9bd | 2013-04-03 03:46:03 | [diff] [blame] | 465 | void SetReadyAndNotifyListeners(); |
| 466 | |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 467 | // Returns true if all the external extension providers are ready. |
| 468 | bool AreAllExternalProvidersReady() const; |
| 469 | |
| 470 | // Called once all external providers are ready. Checks for unclaimed |
| 471 | // external extensions. |
| 472 | void OnAllExternalProvidersReady(); |
| 473 | |
[email protected] | 8c484b74 | 2012-11-29 06:05:36 | [diff] [blame] | 474 | // Update preferences for a new or updated extension; notify observers that |
| 475 | // the extension is installed, e.g., to update event handlers on background |
| 476 | // pages; and perform other extension install tasks before calling |
| 477 | // AddExtension. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 478 | // |install_flags| is a bitmask of InstallFlags. |
Karandeep Bhatia | a893065 | 2017-10-11 17:41:12 | [diff] [blame] | 479 | void AddNewOrUpdatedExtension( |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 480 | const Extension* extension, |
| 481 | Extension::State initial_state, |
Karandeep Bhatia | a893065 | 2017-10-11 17:41:12 | [diff] [blame] | 482 | int install_flags, |
| 483 | const syncer::StringOrdinal& page_ordinal, |
| 484 | const std::string& install_parameter, |
| 485 | const base::Optional<int>& dnr_ruleset_checksum); |
[email protected] | 8c484b74 | 2012-11-29 06:05:36 | [diff] [blame] | 486 | |
benwells | 1dd4acd | 2015-12-09 02:20:24 | [diff] [blame] | 487 | // Common helper to finish installing the given extension. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 488 | void FinishInstallation(const Extension* extension); |
[email protected] | 6f610183 | 2012-11-27 22:10:48 | [diff] [blame] | 489 | |
Marc Grimme | efba8d2 | 2020-01-09 07:57:25 | [diff] [blame] | 490 | // Sets the policy settings for the extension basically |
| 491 | // by delegating this to the permission_data_updater. |
| 492 | // Holds for default and policy settings. |
| 493 | void SetPolicySettingsForExtension(const Extension* extension); |
| 494 | |
[email protected] | b914e295 | 2013-04-26 07:10:03 | [diff] [blame] | 495 | // Disables the extension if the privilege level has increased |
| 496 | // (e.g., due to an upgrade). |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 497 | void CheckPermissionsIncrease(const Extension* extension, |
treib | 6e51bca | 2016-06-15 10:26:03 | [diff] [blame] | 498 | bool is_extension_loaded); |
[email protected] | b914e295 | 2013-04-26 07:10:03 | [diff] [blame] | 499 | |
[email protected] | aab98a5 | 2009-12-02 03:22:35 | [diff] [blame] | 500 | // Helper that updates the active extension list used for crash reporting. |
| 501 | void UpdateActiveExtensionsInCrashReporter(); |
| 502 | |
binjin | 47947f84 | 2014-11-18 12:10:24 | [diff] [blame] | 503 | // Helper to get the disable reasons for an installed (or upgraded) extension. |
Minh X. Nguyen | 4547901 | 2017-08-18 21:35:36 | [diff] [blame] | 504 | // A return value of disable_reason::DISABLE_NONE indicates that we should |
| 505 | // enable this extension initially. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 506 | int GetDisableReasonsOnInstalled(const Extension* extension); |
[email protected] | 612a1cb1 | 2012-10-17 13:18:03 | [diff] [blame] | 507 | |
mlerman | 6a37b6a4 | 2014-11-26 22:10:53 | [diff] [blame] | 508 | // Helper method to determine if an extension can be blocked. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 509 | bool CanBlockExtension(const Extension* extension) const; |
mlerman | 6a37b6a4 | 2014-11-26 22:10:53 | [diff] [blame] | 510 | |
xiyuan | f6a4c6a6 | 2016-04-19 18:14:54 | [diff] [blame] | 511 | // Helper to determine if installing an extensions should proceed immediately, |
| 512 | // or if we should delay the install until further notice, or if the install |
| 513 | // should be aborted. A pending install is delayed or aborted when any of the |
| 514 | // delayers say so and only proceeds when all delayers return INSTALL. |
| 515 | // |extension| is the extension to be installed. |install_immediately| is the |
| 516 | // install flag set with the install. |reason| is the reason associated with |
| 517 | // the install delayer that wants to defer or abort the install. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 518 | InstallGate::Action ShouldDelayExtensionInstall( |
| 519 | const Extension* extension, |
xiyuan | f6a4c6a6 | 2016-04-19 18:14:54 | [diff] [blame] | 520 | bool install_immediately, |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 521 | ExtensionPrefs::DelayReason* reason) const; |
[email protected] | e7aa7b7e | 2012-11-27 04:51:22 | [diff] [blame] | 522 | |
[email protected] | 695b571 | 2012-12-06 23:55:28 | [diff] [blame] | 523 | // Manages the blacklisted extensions, intended as callback from |
| 524 | // Blacklist::GetBlacklistedIDs. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 525 | void ManageBlacklist(const Blacklist::BlacklistStateMap& blacklisted_ids); |
[email protected] | 2d19eb6e | 2014-01-27 17:30:00 | [diff] [blame] | 526 | |
mlerman | 6a37b6a4 | 2014-11-26 22:10:53 | [diff] [blame] | 527 | // Add extensions in |blacklisted| to blacklisted_extensions, remove |
| 528 | // extensions that are neither in |blacklisted|, nor in |unchanged|. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 529 | void UpdateBlacklistedExtensions(const ExtensionIdSet& to_blacklist, |
| 530 | const ExtensionIdSet& unchanged); |
[email protected] | 2d19eb6e | 2014-01-27 17:30:00 | [diff] [blame] | 531 | |
| 532 | void UpdateGreylistedExtensions( |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 533 | const ExtensionIdSet& greylist, |
| 534 | const ExtensionIdSet& unchanged, |
| 535 | const Blacklist::BlacklistStateMap& state_map); |
[email protected] | 695b571 | 2012-12-06 23:55:28 | [diff] [blame] | 536 | |
[email protected] | bb1bc9b3 | 2013-12-21 03:09:14 | [diff] [blame] | 537 | // Used only by test code. |
| 538 | void UnloadAllExtensionsInternal(); |
| 539 | |
[email protected] | ebe0777 | 2014-05-22 04:16:06 | [diff] [blame] | 540 | // Disable apps & extensions now to stop them from running after a profile |
| 541 | // has been conceptually deleted. Don't wait for full browser shutdown and |
| 542 | // the actual profile objects to be destroyed. |
| 543 | void OnProfileDestructionStarted(); |
| 544 | |
[email protected] | 5a145e8 | 2014-05-29 22:19:07 | [diff] [blame] | 545 | // Called on file task runner thread to uninstall extension. |
| 546 | static void UninstallExtensionOnFileThread( |
| 547 | const std::string& id, |
| 548 | Profile* profile, |
| 549 | const base::FilePath& install_dir, |
| 550 | const base::FilePath& extension_path); |
| 551 | |
rdevlin.cronin | f2e1cb01 | 2017-05-27 01:27:59 | [diff] [blame] | 552 | // Called when the initial extensions load has completed. |
| 553 | void OnInstalledExtensionsLoaded(); |
| 554 | |
Takumi Fujimoto | 43c8c00f | 2017-07-26 22:48:56 | [diff] [blame] | 555 | // Uninstall extensions that have been migrated to component extensions. |
| 556 | void UninstallMigratedExtensions(); |
| 557 | |
catmullings | 98cd194 | 2016-08-30 22:31:59 | [diff] [blame] | 558 | const base::CommandLine* command_line_ = nullptr; |
| 559 | |
[email protected] | 31d8f5f2 | 2012-04-02 15:22:08 | [diff] [blame] | 560 | // The normal profile associated with this ExtensionService. |
achuith | 2f5578b | 2016-02-26 21:57:13 | [diff] [blame] | 561 | Profile* profile_ = nullptr; |
[email protected] | 6ef635e4 | 2009-07-26 06:16:12 | [diff] [blame] | 562 | |
[email protected] | 31d8f5f2 | 2012-04-02 15:22:08 | [diff] [blame] | 563 | // The ExtensionSystem for the profile above. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 564 | ExtensionSystem* system_ = nullptr; |
[email protected] | 31d8f5f2 | 2012-04-02 15:22:08 | [diff] [blame] | 565 | |
[email protected] | 695b571 | 2012-12-06 23:55:28 | [diff] [blame] | 566 | // Preferences for the owning profile. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 567 | ExtensionPrefs* extension_prefs_ = nullptr; |
[email protected] | 894bb50 | 2009-05-21 22:39:57 | [diff] [blame] | 568 | |
[email protected] | 695b571 | 2012-12-06 23:55:28 | [diff] [blame] | 569 | // Blacklist for the owning profile. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 570 | Blacklist* blacklist_ = nullptr; |
[email protected] | 695b571 | 2012-12-06 23:55:28 | [diff] [blame] | 571 | |
[email protected] | 5fdfa56 | 2013-12-27 17:43:59 | [diff] [blame] | 572 | // Sets of enabled/disabled/terminated/blacklisted extensions. Not owned. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 573 | ExtensionRegistry* registry_ = nullptr; |
[email protected] | 695b571 | 2012-12-06 23:55:28 | [diff] [blame] | 574 | |
[email protected] | 2d19eb6e | 2014-01-27 17:30:00 | [diff] [blame] | 575 | // Set of greylisted extensions. These extensions are disabled if they are |
| 576 | // already installed in Chromium at the time when they are added to |
| 577 | // the greylist. Unlike blacklisted extensions, greylisted ones are visible |
| 578 | // to the user and if user re-enables such an extension, they remain enabled. |
| 579 | // |
| 580 | // These extensions should appear in registry_. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 581 | ExtensionSet greylist_; |
[email protected] | 2d19eb6e | 2014-01-27 17:30:00 | [diff] [blame] | 582 | |
catmullings | 98cd194 | 2016-08-30 22:31:59 | [diff] [blame] | 583 | // Set of whitelisted enabled extensions loaded from the |
| 584 | // --disable-extensions-except command line flag. |
| 585 | std::set<std::string> disable_flag_exempted_extensions_; |
| 586 | |
[email protected] | 9f4e4f08 | 2013-06-21 07:11:19 | [diff] [blame] | 587 | // The list of extension installs delayed for various reasons. The reason |
[email protected] | bb1bc9b3 | 2013-12-21 03:09:14 | [diff] [blame] | 588 | // for delayed install is stored in ExtensionPrefs. These are not part of |
| 589 | // ExtensionRegistry because they are not yet installed. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 590 | ExtensionSet delayed_installs_; |
[email protected] | 0db124b0 | 2012-11-07 04:55:05 | [diff] [blame] | 591 | |
[email protected] | b2907fd | 2011-03-25 16:43:37 | [diff] [blame] | 592 | // Hold the set of pending extensions. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 593 | PendingExtensionManager pending_extension_manager_; |
[email protected] | aa14270 | 2010-03-26 01:26:33 | [diff] [blame] | 594 | |
[email protected] | 6014d67 | 2008-12-05 00:38:25 | [diff] [blame] | 595 | // The full path to the directory where extensions are installed. |
[email protected] | 650b2d5 | 2013-02-10 03:41:45 | [diff] [blame] | 596 | base::FilePath install_directory_; |
[email protected] | 6014d67 | 2008-12-05 00:38:25 | [diff] [blame] | 597 | |
[email protected] | e2eb4311 | 2009-05-29 21:19:54 | [diff] [blame] | 598 | // Whether or not extensions are enabled. |
achuith | 2f5578b | 2016-02-26 21:57:13 | [diff] [blame] | 599 | bool extensions_enabled_ = true; |
[email protected] | e2eb4311 | 2009-05-29 21:19:54 | [diff] [blame] | 600 | |
[email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 601 | // Signaled when all extensions are loaded. |
Christopher Lam | ebb9020 | 2019-04-04 03:42:36 | [diff] [blame] | 602 | base::OneShotEvent* const ready_; |
[email protected] | e81dba3 | 2009-06-19 20:19:13 | [diff] [blame] | 603 | |
[email protected] | 93fd78f4 | 2009-07-10 16:43:17 | [diff] [blame] | 604 | // Our extension updater, if updates are turned on. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 605 | std::unique_ptr<ExtensionUpdater> updater_; |
[email protected] | 93fd78f4 | 2009-07-10 16:43:17 | [diff] [blame] | 606 | |
[email protected] | 6c2381d | 2011-10-19 02:52:53 | [diff] [blame] | 607 | content::NotificationRegistrar registrar_; |
[email protected] | 4814b51 | 2009-11-07 00:12:29 | [diff] [blame] | 608 | |
[email protected] | d8c8f25f | 2011-11-02 18:18:01 | [diff] [blame] | 609 | // Keeps track of loading and unloading component extensions. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 610 | std::unique_ptr<ComponentLoader> component_loader_; |
[email protected] | d8c8f25f | 2011-11-02 18:18:01 | [diff] [blame] | 611 | |
[email protected] | 8e4560b6 | 2011-01-14 10:09:14 | [diff] [blame] | 612 | // A collection of external extension providers. Each provider reads |
| 613 | // a source of external extension information. Examples include the |
| 614 | // windows registry and external_extensions.json. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 615 | ProviderCollection external_extension_providers_; |
[email protected] | 8e4560b6 | 2011-01-14 10:09:14 | [diff] [blame] | 616 | |
| 617 | // Set to true by OnExternalExtensionUpdateUrlFound() when an external |
[email protected] | 94fde23 | 2012-04-27 10:22:30 | [diff] [blame] | 618 | // extension URL is found, and by CheckForUpdatesSoon() when an update check |
| 619 | // has to wait for the external providers. Used in |
| 620 | // OnAllExternalProvidersReady() to determine if an update check is needed to |
| 621 | // install pending extensions. |
achuith | 2f5578b | 2016-02-26 21:57:13 | [diff] [blame] | 622 | bool update_once_all_providers_are_ready_ = false; |
[email protected] | 8e4560b6 | 2011-01-14 10:09:14 | [diff] [blame] | 623 | |
[email protected] | 4e9b59d | 2013-12-18 06:47:14 | [diff] [blame] | 624 | // A callback to be called when all external providers are ready and their |
| 625 | // extensions have been installed. Normally this is a null callback, but |
| 626 | // is used in external provider related tests. |
Minh X. Nguyen | 722b968 | 2018-04-25 21:46:48 | [diff] [blame] | 627 | // TODO(mxnguyen): Change |external_updates_finished_callback_| to |
| 628 | // OnceClosure. |
[email protected] | 4e9b59d | 2013-12-18 06:47:14 | [diff] [blame] | 629 | base::Closure external_updates_finished_callback_; |
| 630 | |
[email protected] | 3c4abc8 | 2012-10-22 22:25:54 | [diff] [blame] | 631 | // Set when the browser is terminating. Prevents us from installing or |
| 632 | // updating additional extensions and allows in-progress installations to |
| 633 | // decide to abort. |
achuith | 2f5578b | 2016-02-26 21:57:13 | [diff] [blame] | 634 | bool browser_terminating_ = false; |
[email protected] | 3c4abc8 | 2012-10-22 22:25:54 | [diff] [blame] | 635 | |
lazyboy | 77214d3c | 2017-04-04 16:46:12 | [diff] [blame] | 636 | // If set, call to CheckForExternalUpdates() will bail out. |
| 637 | bool external_updates_disabled_for_test_ = false; |
| 638 | |
[email protected] | 460c671 | 2013-04-24 07:20:01 | [diff] [blame] | 639 | // Set to true if this is the first time this ExtensionService has run. |
| 640 | // Used for specially handling external extensions that are installed the |
| 641 | // first time. |
achuith | 2f5578b | 2016-02-26 21:57:13 | [diff] [blame] | 642 | bool is_first_run_ = false; |
[email protected] | 460c671 | 2013-04-24 07:20:01 | [diff] [blame] | 643 | |
mlerman | 6a37b6a4 | 2014-11-26 22:10:53 | [diff] [blame] | 644 | // Set to true if extensions are all to be blocked. |
achuith | 2f5578b | 2016-02-26 21:57:13 | [diff] [blame] | 645 | bool block_extensions_ = false; |
mlerman | 6a37b6a4 | 2014-11-26 22:10:53 | [diff] [blame] | 646 | |
[email protected] | 373daf97 | 2014-04-10 01:50:44 | [diff] [blame] | 647 | // The controller for the UI that alerts the user about any blacklisted |
| 648 | // extensions. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 649 | std::unique_ptr<ExtensionErrorController> error_controller_; |
[email protected] | 373daf97 | 2014-04-10 01:50:44 | [diff] [blame] | 650 | |
[email protected] | 2894a51 | 2014-06-26 19:03:56 | [diff] [blame] | 651 | // The manager for extensions that were externally installed that is |
| 652 | // responsible for prompting the user about suspicious extensions. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 653 | std::unique_ptr<ExternalInstallManager> external_install_manager_; |
[email protected] | 2894a51 | 2014-06-26 19:03:56 | [diff] [blame] | 654 | |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 655 | std::unique_ptr<ExtensionActionStorageManager> |
[email protected] | c77f235 | 2012-08-08 22:07:58 | [diff] [blame] | 656 | extension_action_storage_manager_; |
| 657 | |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 658 | // The SharedModuleService used to check for import dependencies. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 659 | std::unique_ptr<SharedModuleService> shared_module_service_; |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 660 | |
Trent Apted | a250ec3ab | 2018-08-19 08:52:19 | [diff] [blame] | 661 | base::ObserverList<UpdateObserver, true>::Unchecked update_observers_; |
[email protected] | efdb7f1a | 2014-03-28 20:43:38 | [diff] [blame] | 662 | |
ryanackley | 48bedbd | 2015-01-27 23:12:14 | [diff] [blame] | 663 | // Migrates app data when upgrading a legacy packaged app to a platform app |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 664 | std::unique_ptr<AppDataMigrator> app_data_migrator_; |
ryanackley | 48bedbd | 2015-01-27 23:12:14 | [diff] [blame] | 665 | |
Michael Giuffrida | 023e353 | 2017-09-28 23:21:21 | [diff] [blame] | 666 | // Helper to register and unregister extensions. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 667 | ExtensionRegistrar extension_registrar_; |
Michael Giuffrida | 023e353 | 2017-09-28 23:21:21 | [diff] [blame] | 668 | |
Sergey Poromov | 0360b9e7 | 2018-04-19 17:37:29 | [diff] [blame] | 669 | // Tracker of enterprise policy forced installation. |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 670 | InstallationTracker forced_extensions_tracker_; |
Sergey Poromov | 0360b9e7 | 2018-04-19 17:37:29 | [diff] [blame] | 671 | |
Evan Stade | d89e11c | 2019-09-05 18:08:56 | [diff] [blame] | 672 | ScopedObserver<ProfileManager, ProfileManagerObserver> |
| 673 | profile_manager_observer_{this}; |
| 674 | |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 675 | using InstallGateRegistry = |
| 676 | std::map<ExtensionPrefs::DelayReason, InstallGate*>; |
xiyuan | f6a4c6a6 | 2016-04-19 18:14:54 | [diff] [blame] | 677 | InstallGateRegistry install_delayer_registry_; |
| 678 | |
[email protected] | eaa7dd18 | 2010-12-14 11:09:00 | [diff] [blame] | 679 | FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 680 | DestroyingProfileClearsExtensions); |
[email protected] | f71b582c | 2014-01-10 17:03:15 | [diff] [blame] | 681 | FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, SetUnsetBlacklistInPrefs); |
| 682 | FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, |
| 683 | BlacklistedExtensionWillNotInstall); |
| 684 | FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, |
| 685 | UnloadBlacklistedExtensionPolicy); |
| 686 | FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, |
| 687 | WillNotLoadBlacklistedExtensionsFromDirectory); |
[email protected] | 757d60a | 2014-05-23 00:11:44 | [diff] [blame] | 688 | FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, ReloadBlacklistedExtension); |
atuchin | 6dc7c44 | 2016-07-20 07:04:34 | [diff] [blame] | 689 | FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, |
| 690 | RemoveExtensionFromBlacklist); |
[email protected] | 757d60a | 2014-05-23 00:11:44 | [diff] [blame] | 691 | FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, BlacklistedInPrefsFromStartup); |
[email protected] | 2d19eb6e | 2014-01-27 17:30:00 | [diff] [blame] | 692 | FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, |
| 693 | GreylistedExtensionDisabled); |
| 694 | FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, |
| 695 | GreylistDontEnableManuallyDisabled); |
| 696 | FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, |
| 697 | GreylistUnknownDontChange); |
binjin | 47947f84 | 2014-11-18 12:10:24 | [diff] [blame] | 698 | FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, |
| 699 | ManagementPolicyProhibitsEnableOnInstalled); |
mlerman | 6a37b6a4 | 2014-11-26 22:10:53 | [diff] [blame] | 700 | FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, |
| 701 | BlockAndUnblockBlacklistedExtension); |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 702 | FRIEND_TEST_ALL_PREFIXES(::BlacklistedExtensionSyncServiceTest, |
proberge | 901ecab | 2017-08-31 19:24:28 | [diff] [blame] | 703 | SyncBlacklistedExtension); |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 704 | friend class ::BlacklistedExtensionSyncServiceTest; |
[email protected] | dccba4f8 | 2014-05-29 00:52:56 | [diff] [blame] | 705 | |
[email protected] | eaa7dd18 | 2010-12-14 11:09:00 | [diff] [blame] | 706 | DISALLOW_COPY_AND_ASSIGN(ExtensionService); |
[email protected] | 6014d67 | 2008-12-05 00:38:25 | [diff] [blame] | 707 | }; |
| 708 | |
Devlin Cronin | eea1b7a | 2018-05-26 02:46:21 | [diff] [blame] | 709 | } // namespace extensions |
| 710 | |
[email protected] | eaa7dd18 | 2010-12-14 11:09:00 | [diff] [blame] | 711 | #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_H_ |