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