blob: 9d16ef79bacd3bd78fa924ae1dc87e88f59c2402 [file] [log] [blame]
[email protected]a12ce8b22012-01-17 18:40:531// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]8e4560b62011-01-14 10:09:142// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]5df038b2012-07-16 19:03:275#include "chrome/browser/extensions/external_provider_impl.h"
[email protected]8e4560b62011-01-14 10:09:146
avia2f4804a2015-12-24 23:11:137#include <stddef.h>
8
Toni Barzic87026682018-01-08 23:21:049#include <memory>
[email protected]8a839a02013-03-07 05:23:3310#include <set>
Toni Barzic87026682018-01-08 23:21:0411#include <utility>
[email protected]8a839a02013-03-07 05:23:3312#include <vector>
13
[email protected]83b59325a2011-10-14 15:58:0714#include "base/command_line.h"
[email protected]57999812013-02-24 05:40:5215#include "base/files/file_path.h"
[email protected]8e4560b62011-01-14 10:09:1416#include "base/logging.h"
[email protected]51a7a9d2011-09-27 17:21:4117#include "base/metrics/field_trial.h"
chakshu.ac20f38782016-04-06 09:58:0818#include "base/stl_util.h"
[email protected]46acbf12013-06-10 18:43:4219#include "base/strings/string_util.h"
rkaplowdd66a1342015-03-05 00:31:4920#include "base/trace_event/trace_event.h"
[email protected]8e4560b62011-01-14 10:09:1421#include "base/values.h"
22#include "base/version.h"
avia2f4804a2015-12-24 23:11:1323#include "build/build_config.h"
[email protected]8a839a02013-03-07 05:23:3324#include "chrome/browser/app_mode/app_mode_utils.h"
[email protected]e601e822011-10-05 19:25:3725#include "chrome/browser/browser_process.h"
pbond43ddd4f2015-09-08 16:39:1926#include "chrome/browser/browser_process_platform_part.h"
binjin30301062014-09-08 20:27:3427#include "chrome/browser/extensions/extension_management.h"
xiyuan65b68ab12015-06-26 19:00:1828#include "chrome/browser/extensions/extension_migrator.h"
[email protected]51a7a9d2011-09-27 17:21:4129#include "chrome/browser/extensions/extension_service.h"
[email protected]8aa50c7752013-05-23 12:57:5030#include "chrome/browser/extensions/external_component_loader.h"
[email protected]5df038b2012-07-16 19:03:2731#include "chrome/browser/extensions/external_policy_loader.h"
32#include "chrome/browser/extensions/external_pref_loader.h"
dpolukhin1687ef32015-06-22 11:12:3733#include "chrome/browser/policy/profile_policy_connector.h"
34#include "chrome/browser/policy/profile_policy_connector_factory.h"
[email protected]8e4560b62011-01-14 10:09:1435#include "chrome/browser/profiles/profile.h"
[email protected]f0841cd2011-01-19 15:07:2436#include "chrome/common/chrome_paths.h"
[email protected]83b59325a2011-10-14 15:58:0737#include "chrome/common/chrome_switches.h"
xiyuan65b68ab12015-06-26 19:00:1838#include "chrome/common/extensions/extension_constants.h"
dpolukhin2c6ef2932015-05-12 16:06:1339#include "chrome/common/pref_names.h"
[email protected]fdd28372014-08-21 02:27:2640#include "components/crx_file/id_util.h"
brettwb1fc1b82016-02-02 00:19:0841#include "components/prefs/pref_service.h"
[email protected]c38831a12011-10-28 12:44:4942#include "content/public/browser/browser_thread.h"
[email protected]59b0e602014-01-30 00:41:2443#include "extensions/browser/extension_system.h"
lazyboye8634172016-01-28 00:10:4844#include "extensions/browser/external_install_info.h"
[email protected]301116c62013-11-26 10:37:4545#include "extensions/browser/external_provider_interface.h"
[email protected]e4452d32013-11-15 23:07:4146#include "extensions/common/extension.h"
[email protected]d42c11152013-08-22 19:36:3247#include "extensions/common/manifest.h"
[email protected]9d32ded072011-10-11 16:31:0548#include "ui/base/l10n/l10n_util.h"
[email protected]8e4560b62011-01-14 10:09:1449
[email protected]944dfa82012-03-20 02:07:5150#if defined(OS_CHROMEOS)
Toni Barzic87026682018-01-08 23:21:0451#include "chrome/browser/chromeos/app_mode/kiosk_app_external_loader.h"
Satoru Takabayashi876d4e62014-12-03 04:52:2452#include "chrome/browser/chromeos/customization/customization_document.h"
[email protected]af984882013-10-21 21:08:5153#include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h"
Toni Barzicdff51562018-07-24 19:55:4654#include "chrome/browser/chromeos/login/demo_mode/demo_extensions_external_loader.h"
[email protected]97275822014-01-21 19:30:3655#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
[email protected]af984882013-10-21 21:08:5156#include "chrome/browser/chromeos/policy/device_local_account.h"
57#include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
[email protected]052e3ac2014-06-30 14:22:4758#include "chrome/browser/chromeos/profiles/profile_helper.h"
Ahmed Fakhry9ef29e042017-09-01 16:32:0059#include "components/arc/arc_util.h"
[email protected]b39d25712013-03-14 09:53:4060#else
[email protected]86c6b9e32011-10-25 17:09:1061#include "chrome/browser/extensions/default_apps.h"
62#endif
63
[email protected]8e4560b62011-01-14 10:09:1464#if defined(OS_WIN)
[email protected]5df038b2012-07-16 19:03:2765#include "chrome/browser/extensions/external_registry_loader_win.h"
[email protected]8e4560b62011-01-14 10:09:1466#endif
67
[email protected]631bb742011-11-02 11:29:3968using content::BrowserThread;
[email protected]5df038b2012-07-16 19:03:2769
70namespace extensions {
[email protected]631bb742011-11-02 11:29:3971
Ahmed Fakhry9ef29e042017-09-01 16:32:0072namespace {
73
74#if defined(OS_CHROMEOS)
75
76// Certain default extensions are no longer needed on ARC devices as they were
77// replaced by their ARC counterparts.
78bool ShouldUninstallExtensionReplacedByArcApp(const std::string& extension_id) {
Alex Newcomerf8c542f2018-08-13 23:48:5079 if (!arc::IsArcAvailable())
Ahmed Fakhry9ef29e042017-09-01 16:32:0080 return false;
81
82 if (extension_id == extension_misc::kGooglePlayBooksAppId ||
83 extension_id == extension_misc::kGooglePlayMoviesAppId ||
84 extension_id == extension_misc::kGooglePlayMusicAppId) {
85 return true;
86 }
87
88 return false;
89}
90
91#endif // defined(OS_CHROMEOS)
92
93} // namespace
94
[email protected]8e4560b62011-01-14 10:09:1495// Constants for keeping track of extension preferences in a dictionary.
[email protected]d8fd0fd2014-03-24 13:16:0696const char ExternalProviderImpl::kInstallParam[] = "install_parameter";
[email protected]5df038b2012-07-16 19:03:2797const char ExternalProviderImpl::kExternalCrx[] = "external_crx";
[email protected]7425d7df2012-11-28 14:35:4298const char ExternalProviderImpl::kExternalVersion[] = "external_version";
99const char ExternalProviderImpl::kExternalUpdateUrl[] = "external_update_url";
[email protected]7425d7df2012-11-28 14:35:42100const char ExternalProviderImpl::kIsBookmarkApp[] = "is_bookmark_app";
101const char ExternalProviderImpl::kIsFromWebstore[] = "is_from_webstore";
[email protected]19eac6d2013-05-30 06:51:03102const char ExternalProviderImpl::kKeepIfPresent[] = "keep_if_present";
[email protected]bf9fd5ae2014-04-09 22:50:06103const char ExternalProviderImpl::kWasInstalledByOem[] = "was_installed_by_oem";
104const char ExternalProviderImpl::kSupportedLocales[] = "supported_locales";
[email protected]2b6a5802014-08-16 07:58:08105const char ExternalProviderImpl::kMayBeUntrusted[] = "may_be_untrusted";
dpolukhin2c6ef2932015-05-12 16:06:13106const char ExternalProviderImpl::kMinProfileCreatedByVersion[] =
107 "min_profile_created_by_version";
dpolukhin1687ef32015-06-22 11:12:37108const char ExternalProviderImpl::kDoNotInstallForEnterprise[] =
109 "do_not_install_for_enterprise";
[email protected]8e4560b62011-01-14 10:09:14110
[email protected]af984882013-10-21 21:08:51111ExternalProviderImpl::ExternalProviderImpl(
112 VisitorInterface* service,
113 const scoped_refptr<ExternalLoader>& loader,
114 Profile* profile,
115 Manifest::Location crx_location,
116 Manifest::Location download_location,
117 int creation_flags)
[email protected]4b4c0132013-06-12 17:58:55118 : crx_location_(crx_location),
119 download_location_(download_location),
120 service_(service),
[email protected]4b4c0132013-06-12 17:58:55121 loader_(loader),
122 profile_(profile),
Toni Barzic87026682018-01-08 23:21:04123 creation_flags_(creation_flags) {
[email protected]8e4560b62011-01-14 10:09:14124 loader_->Init(this);
125}
126
[email protected]5df038b2012-07-16 19:03:27127ExternalProviderImpl::~ExternalProviderImpl() {
Istiaque Ahmedf6e72622017-09-08 23:14:17128 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]8e4560b62011-01-14 10:09:14129 loader_->OwnerShutdown();
130}
131
[email protected]5df038b2012-07-16 19:03:27132void ExternalProviderImpl::VisitRegisteredExtension() {
[email protected]8e4560b62011-01-14 10:09:14133 // The loader will call back to SetPrefs.
134 loader_->StartLoading();
135}
136
Istiaque Ahmeda7431b32017-08-20 18:33:37137void ExternalProviderImpl::SetPrefs(
138 std::unique_ptr<base::DictionaryValue> prefs) {
Istiaque Ahmedf6e72622017-09-08 23:14:17139 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]8e4560b62011-01-14 10:09:14140
[email protected]47fc70c2011-12-06 07:29:51141 // Check if the service is still alive. It is possible that it went
[email protected]8e4560b62011-01-14 10:09:14142 // away while |loader_| was working on the FILE thread.
143 if (!service_) return;
144
Istiaque Ahmeda7431b32017-08-20 18:33:37145 prefs_ = std::move(prefs);
[email protected]8a839a02013-03-07 05:23:33146 ready_ = true; // Queries for extensions are allowed from this point.
[email protected]8e4560b62011-01-14 10:09:14147
Devlin Cronin19f70b6a2017-10-01 04:14:05148 std::vector<ExternalInstallInfoUpdateUrl> external_update_url_extensions;
149 std::vector<ExternalInstallInfoFile> external_file_extensions;
lazyboye8634172016-01-28 00:10:48150
151 RetrieveExtensionsFromPrefs(&external_update_url_extensions,
152 &external_file_extensions);
lazyboy4aeef202016-09-07 21:28:59153 for (const auto& extension : external_update_url_extensions)
Devlin Cronin19f70b6a2017-10-01 04:14:05154 service_->OnExternalExtensionUpdateUrlFound(extension, true);
lazyboye8634172016-01-28 00:10:48155
lazyboy4aeef202016-09-07 21:28:59156 for (const auto& extension : external_file_extensions)
Devlin Cronin19f70b6a2017-10-01 04:14:05157 service_->OnExternalExtensionFileFound(extension);
lazyboye8634172016-01-28 00:10:48158
159 service_->OnExternalProviderReady(this);
160}
161
Istiaque Ahmeda7431b32017-08-20 18:33:37162void ExternalProviderImpl::UpdatePrefs(
163 std::unique_ptr<base::DictionaryValue> prefs) {
Istiaque Ahmedf6e72622017-09-08 23:14:17164 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Toni Barzic87026682018-01-08 23:21:04165 CHECK(allow_updates_);
lazyboye8634172016-01-28 00:10:48166
167 // Check if the service is still alive. It is possible that it went
168 // away while |loader_| was working on the FILE thread.
169 if (!service_)
170 return;
171
172 std::set<std::string> removed_extensions;
173 // Find extensions that were removed by this ExternalProvider.
174 for (base::DictionaryValue::Iterator i(*prefs_); !i.IsAtEnd(); i.Advance()) {
175 const std::string& extension_id = i.key();
176 // Don't bother about invalid ids.
177 if (!crx_file::id_util::IdIsValid(extension_id))
178 continue;
179 if (!prefs->HasKey(extension_id))
180 removed_extensions.insert(extension_id);
181 }
182
Istiaque Ahmeda7431b32017-08-20 18:33:37183 prefs_ = std::move(prefs);
lazyboye8634172016-01-28 00:10:48184
Devlin Cronin19f70b6a2017-10-01 04:14:05185 std::vector<ExternalInstallInfoUpdateUrl> external_update_url_extensions;
186 std::vector<ExternalInstallInfoFile> external_file_extensions;
lazyboye8634172016-01-28 00:10:48187 RetrieveExtensionsFromPrefs(&external_update_url_extensions,
188 &external_file_extensions);
189
190 // Notify ExtensionService about completion of finding incremental updates
191 // from this provider.
192 // Provide the list of added and removed extensions.
193 service_->OnExternalProviderUpdateComplete(
194 this, external_update_url_extensions, external_file_extensions,
195 removed_extensions);
196}
197
198void ExternalProviderImpl::RetrieveExtensionsFromPrefs(
Devlin Cronin19f70b6a2017-10-01 04:14:05199 std::vector<ExternalInstallInfoUpdateUrl>* external_update_url_extensions,
200 std::vector<ExternalInstallInfoFile>* external_file_extensions) {
[email protected]9d32ded072011-10-11 16:31:05201 // Set of unsupported extensions that need to be deleted from prefs_.
202 std::set<std::string> unsupported_extensions;
203
lazyboye8634172016-01-28 00:10:48204 // Discover all the extensions this provider has.
[email protected]aeca23f2013-06-21 22:34:41205 for (base::DictionaryValue::Iterator i(*prefs_); !i.IsAtEnd(); i.Advance()) {
[email protected]02d9b272013-03-06 12:54:56206 const std::string& extension_id = i.key();
[email protected]aeca23f2013-06-21 22:34:41207 const base::DictionaryValue* extension = NULL;
[email protected]ab22ba42011-01-14 16:36:38208
Ahmed Fakhry9ef29e042017-09-01 16:32:00209#if defined(OS_CHROMEOS)
210 if (ShouldUninstallExtensionReplacedByArcApp(extension_id)) {
211 VLOG(1) << "Extension with key: " << extension_id << " was replaced "
212 << "by a default ARC app, and will be uninstalled.";
213 unsupported_extensions.emplace(extension_id);
214 continue;
215 }
216#endif // defined(OS_CHROMEOS)
217
[email protected]fdd28372014-08-21 02:27:26218 if (!crx_file::id_util::IdIsValid(extension_id)) {
[email protected]ab22ba42011-01-14 16:36:38219 LOG(WARNING) << "Malformed extension dictionary: key "
220 << extension_id.c_str() << " is not a valid id.";
[email protected]8e4560b62011-01-14 10:09:14221 continue;
[email protected]ab22ba42011-01-14 16:36:38222 }
223
[email protected]02d9b272013-03-06 12:54:56224 if (!i.value().GetAsDictionary(&extension)) {
[email protected]ab22ba42011-01-14 16:36:38225 LOG(WARNING) << "Malformed extension dictionary: key "
226 << extension_id.c_str()
227 << " has a value that is not a dictionary.";
228 continue;
229 }
[email protected]8e4560b62011-01-14 10:09:14230
[email protected]650b2d52013-02-10 03:41:45231 base::FilePath::StringType external_crx;
[email protected]cb1078de2013-12-23 20:04:22232 const base::Value* external_version_value = NULL;
[email protected]8e4560b62011-01-14 10:09:14233 std::string external_version;
234 std::string external_update_url;
235
236 bool has_external_crx = extension->GetString(kExternalCrx, &external_crx);
[email protected]0d461c52012-07-03 19:29:41237
238 bool has_external_version = false;
239 if (extension->Get(kExternalVersion, &external_version_value)) {
jdoerrie1f536b22017-10-23 17:15:11240 if (external_version_value->is_string()) {
[email protected]0d461c52012-07-03 19:29:41241 external_version_value->GetAsString(&external_version);
242 has_external_version = true;
243 } else {
244 LOG(WARNING) << "Malformed extension dictionary for extension: "
245 << extension_id.c_str() << ". " << kExternalVersion
246 << " value must be a string.";
247 continue;
248 }
249 }
250
[email protected]8e4560b62011-01-14 10:09:14251 bool has_external_update_url = extension->GetString(kExternalUpdateUrl,
252 &external_update_url);
253 if (has_external_crx != has_external_version) {
254 LOG(WARNING) << "Malformed extension dictionary for extension: "
255 << extension_id.c_str() << ". " << kExternalCrx
256 << " and " << kExternalVersion << " must be used together.";
257 continue;
258 }
259
260 if (has_external_crx == has_external_update_url) {
261 LOG(WARNING) << "Malformed extension dictionary for extension: "
262 << extension_id.c_str() << ". Exactly one of the "
263 << "followng keys should be used: " << kExternalCrx
264 << ", " << kExternalUpdateUrl << ".";
265 continue;
266 }
267
[email protected]9d32ded072011-10-11 16:31:05268 // Check that extension supports current browser locale.
[email protected]aeca23f2013-06-21 22:34:41269 const base::ListValue* supported_locales = NULL;
[email protected]9d32ded072011-10-11 16:31:05270 if (extension->GetList(kSupportedLocales, &supported_locales)) {
271 std::vector<std::string> browser_locales;
272 l10n_util::GetParentLocales(g_browser_process->GetApplicationLocale(),
273 &browser_locales);
274
275 size_t num_locales = supported_locales->GetSize();
276 bool locale_supported = false;
277 for (size_t j = 0; j < num_locales; j++) {
278 std::string current_locale;
279 if (supported_locales->GetString(j, &current_locale) &&
280 l10n_util::IsValidLocaleSyntax(current_locale)) {
281 current_locale = l10n_util::NormalizeLocale(current_locale);
skyostil32fa6b3f92016-08-12 13:15:43282 if (base::ContainsValue(browser_locales, current_locale)) {
[email protected]9d32ded072011-10-11 16:31:05283 locale_supported = true;
284 break;
285 }
286 } else {
287 LOG(WARNING) << "Unrecognized locale '" << current_locale
288 << "' found as supported locale for extension: "
289 << extension_id;
290 }
291 }
292
293 if (!locale_supported) {
294 unsupported_extensions.insert(extension_id);
[email protected]19eac6d2013-05-30 06:51:03295 VLOG(1) << "Skip installing (or uninstall) external extension: "
296 << extension_id << " because the extension doesn't support "
297 << "the browser locale.";
[email protected]9d32ded072011-10-11 16:31:05298 continue;
299 }
300 }
301
[email protected]f121003b2012-05-04 21:57:47302 int creation_flags = creation_flags_;
303 bool is_bookmark_app;
304 if (extension->GetBoolean(kIsBookmarkApp, &is_bookmark_app) &&
305 is_bookmark_app) {
306 creation_flags |= Extension::FROM_BOOKMARK;
307 }
[email protected]2b6a5802014-08-16 07:58:08308 bool is_from_webstore = false;
[email protected]7425d7df2012-11-28 14:35:42309 if (extension->GetBoolean(kIsFromWebstore, &is_from_webstore) &&
310 is_from_webstore) {
311 creation_flags |= Extension::FROM_WEBSTORE;
312 }
[email protected]2b6a5802014-08-16 07:58:08313 bool keep_if_present = false;
[email protected]19eac6d2013-05-30 06:51:03314 if (extension->GetBoolean(kKeepIfPresent, &keep_if_present) &&
315 keep_if_present && profile_) {
316 ExtensionServiceInterface* extension_service =
317 ExtensionSystem::Get(profile_)->extension_service();
318 const Extension* extension = extension_service ?
319 extension_service->GetExtensionById(extension_id, true) : NULL;
320 if (!extension) {
dpolukhin2c6ef2932015-05-12 16:06:13321 unsupported_extensions.insert(extension_id);
[email protected]19eac6d2013-05-30 06:51:03322 VLOG(1) << "Skip installing (or uninstall) external extension: "
323 << extension_id << " because the extension should be kept "
324 << "only if it is already installed.";
325 continue;
326 }
327 }
dpolukhind0be494a2015-05-28 09:43:17328 bool was_installed_by_oem = false;
329 if (extension->GetBoolean(kWasInstalledByOem, &was_installed_by_oem) &&
330 was_installed_by_oem) {
331 creation_flags |= Extension::WAS_INSTALLED_BY_OEM;
332 }
[email protected]2b6a5802014-08-16 07:58:08333 bool may_be_untrusted = false;
334 if (extension->GetBoolean(kMayBeUntrusted, &may_be_untrusted) &&
335 may_be_untrusted) {
336 creation_flags |= Extension::MAY_BE_UNTRUSTED;
337 }
[email protected]f121003b2012-05-04 21:57:47338
dpolukhin1687ef32015-06-22 11:12:37339 if (!HandleMinProfileVersion(extension, extension_id,
340 &unsupported_extensions)) {
dpolukhin2c6ef2932015-05-12 16:06:13341 continue;
dpolukhin1687ef32015-06-22 11:12:37342 }
343
344 if (!HandleDoNotInstallForEnterprise(extension, extension_id,
345 &unsupported_extensions)) {
346 continue;
347 }
dpolukhin2c6ef2932015-05-12 16:06:13348
[email protected]d8fd0fd2014-03-24 13:16:06349 std::string install_parameter;
350 extension->GetString(kInstallParam, &install_parameter);
351
[email protected]8e4560b62011-01-14 10:09:14352 if (has_external_crx) {
[email protected]1d5e58b2013-01-31 08:41:40353 if (crx_location_ == Manifest::INVALID_LOCATION) {
[email protected]8e4560b62011-01-14 10:09:14354 LOG(WARNING) << "This provider does not support installing external "
355 << "extensions from crx files.";
356 continue;
357 }
[email protected]650b2d52013-02-10 03:41:45358 if (external_crx.find(base::FilePath::kParentDirectory) !=
[email protected]8e4560b62011-01-14 10:09:14359 base::StringPiece::npos) {
360 LOG(WARNING) << "Path traversal not allowed in path: "
361 << external_crx.c_str();
362 continue;
363 }
364
[email protected]f0841cd2011-01-19 15:07:24365 // If the path is relative, and the provider has a base path,
366 // build the absolute path to the crx file.
[email protected]650b2d52013-02-10 03:41:45367 base::FilePath path(external_crx);
[email protected]8e4560b62011-01-14 10:09:14368 if (!path.IsAbsolute()) {
[email protected]650b2d52013-02-10 03:41:45369 base::FilePath base_path = loader_->GetBaseCrxFilePath();
[email protected]f0841cd2011-01-19 15:07:24370 if (base_path.empty()) {
371 LOG(WARNING) << "File path " << external_crx.c_str()
372 << " is relative. An absolute path is required.";
373 continue;
374 }
[email protected]8e4560b62011-01-14 10:09:14375 path = base_path.Append(external_crx);
376 }
377
Devlin Cronind4c2a8f32017-09-29 17:08:30378 base::Version version(external_version);
379 if (!version.IsValid()) {
[email protected]8e4560b62011-01-14 10:09:14380 LOG(WARNING) << "Malformed extension dictionary for extension: "
381 << extension_id.c_str() << ". Invalid version string \""
382 << external_version << "\".";
383 continue;
384 }
Devlin Cronin19f70b6a2017-10-01 04:14:05385 external_file_extensions->emplace_back(
386 extension_id, version, path, crx_location_, creation_flags,
387 auto_acknowledge_, install_immediately_);
[email protected]8a839a02013-03-07 05:23:33388 } else { // if (has_external_update_url)
[email protected]8e4560b62011-01-14 10:09:14389 CHECK(has_external_update_url); // Checking of keys above ensures this.
[email protected]1d5e58b2013-01-31 08:41:40390 if (download_location_ == Manifest::INVALID_LOCATION) {
[email protected]8e4560b62011-01-14 10:09:14391 LOG(WARNING) << "This provider does not support installing external "
392 << "extensions from update URLs.";
393 continue;
394 }
Devlin Cronind4c2a8f32017-09-29 17:08:30395 GURL update_url(external_update_url);
396 if (!update_url.is_valid()) {
[email protected]8e4560b62011-01-14 10:09:14397 LOG(WARNING) << "Malformed extension dictionary for extension: "
[email protected]ab22ba42011-01-14 16:36:38398 << extension_id.c_str() << ". Key " << kExternalUpdateUrl
399 << " has value \"" << external_update_url
400 << "\", which is not a valid URL.";
[email protected]8e4560b62011-01-14 10:09:14401 continue;
402 }
Devlin Cronin19f70b6a2017-10-01 04:14:05403 external_update_url_extensions->emplace_back(
404 extension_id, install_parameter, std::move(update_url),
405 download_location_, creation_flags, auto_acknowledge_);
[email protected]8e4560b62011-01-14 10:09:14406 }
407 }
408
[email protected]9d32ded072011-10-11 16:31:05409 for (std::set<std::string>::iterator it = unsupported_extensions.begin();
410 it != unsupported_extensions.end(); ++it) {
411 // Remove extension for the list of know external extensions. The extension
412 // will be uninstalled later because provider doesn't provide it anymore.
413 prefs_->Remove(*it, NULL);
414 }
[email protected]8e4560b62011-01-14 10:09:14415}
416
[email protected]5df038b2012-07-16 19:03:27417void ExternalProviderImpl::ServiceShutdown() {
[email protected]8e4560b62011-01-14 10:09:14418 service_ = NULL;
419}
420
[email protected]5df038b2012-07-16 19:03:27421bool ExternalProviderImpl::IsReady() const {
[email protected]8e4560b62011-01-14 10:09:14422 return ready_;
423}
424
[email protected]5df038b2012-07-16 19:03:27425bool ExternalProviderImpl::HasExtension(
[email protected]8e4560b62011-01-14 10:09:14426 const std::string& id) const {
Istiaque Ahmedf6e72622017-09-08 23:14:17427 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]8e4560b62011-01-14 10:09:14428 CHECK(prefs_.get());
429 CHECK(ready_);
430 return prefs_->HasKey(id);
431}
432
[email protected]5df038b2012-07-16 19:03:27433bool ExternalProviderImpl::GetExtensionDetails(
dchengc963c7142016-04-08 03:55:22434 const std::string& id,
435 Manifest::Location* location,
pwnallcbd73192016-08-22 18:59:17436 std::unique_ptr<base::Version>* version) const {
Istiaque Ahmedf6e72622017-09-08 23:14:17437 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]8e4560b62011-01-14 10:09:14438 CHECK(prefs_.get());
439 CHECK(ready_);
[email protected]aeca23f2013-06-21 22:34:41440 base::DictionaryValue* extension = NULL;
[email protected]8e4560b62011-01-14 10:09:14441 if (!prefs_->GetDictionary(id, &extension))
442 return false;
443
[email protected]1d5e58b2013-01-31 08:41:40444 Manifest::Location loc = Manifest::INVALID_LOCATION;
[email protected]8e4560b62011-01-14 10:09:14445 if (extension->HasKey(kExternalUpdateUrl)) {
446 loc = download_location_;
447
448 } else if (extension->HasKey(kExternalCrx)) {
449 loc = crx_location_;
450
451 std::string external_version;
452 if (!extension->GetString(kExternalVersion, &external_version))
453 return false;
454
455 if (version)
pwnallcbd73192016-08-22 18:59:17456 version->reset(new base::Version(external_version));
[email protected]8e4560b62011-01-14 10:09:14457
458 } else {
459 NOTREACHED(); // Chrome should not allow prefs to get into this state.
460 return false;
461 }
462
463 if (location)
464 *location = loc;
465
466 return true;
467}
468
dpolukhin2c6ef2932015-05-12 16:06:13469bool ExternalProviderImpl::HandleMinProfileVersion(
470 const base::DictionaryValue* extension,
471 const std::string& extension_id,
472 std::set<std::string>* unsupported_extensions) {
473 std::string min_profile_created_by_version;
474 if (profile_ &&
475 extension->GetString(kMinProfileCreatedByVersion,
476 &min_profile_created_by_version)) {
pwnallcbd73192016-08-22 18:59:17477 base::Version profile_version(
dpolukhin2c6ef2932015-05-12 16:06:13478 profile_->GetPrefs()->GetString(prefs::kProfileCreatedByVersion));
pwnallcbd73192016-08-22 18:59:17479 base::Version min_version(min_profile_created_by_version);
dpolukhin2c6ef2932015-05-12 16:06:13480 if (min_version.IsValid() && profile_version.CompareTo(min_version) < 0) {
481 unsupported_extensions->insert(extension_id);
482 VLOG(1) << "Skip installing (or uninstall) external extension: "
483 << extension_id
484 << " profile.created_by_version: " << profile_version.GetString()
485 << " min_profile_created_by_version: "
486 << min_profile_created_by_version;
487 return false;
488 }
489 }
490 return true;
491}
492
dpolukhin1687ef32015-06-22 11:12:37493bool ExternalProviderImpl::HandleDoNotInstallForEnterprise(
494 const base::DictionaryValue* extension,
495 const std::string& extension_id,
496 std::set<std::string>* unsupported_extensions) {
497 bool do_not_install_for_enterprise = false;
498 if (extension->GetBoolean(kDoNotInstallForEnterprise,
499 &do_not_install_for_enterprise) &&
500 do_not_install_for_enterprise) {
501 const policy::ProfilePolicyConnector* const connector =
502 policy::ProfilePolicyConnectorFactory::GetForBrowserContext(profile_);
503 if (connector->IsManaged()) {
504 unsupported_extensions->insert(extension_id);
505 VLOG(1) << "Skip installing (or uninstall) external extension "
506 << extension_id << " restricted for managed user";
507 return false;
508 }
509 }
510 return true;
511}
512
[email protected]8e4560b62011-01-14 10:09:14513// static
[email protected]5df038b2012-07-16 19:03:27514void ExternalProviderImpl::CreateExternalProviders(
[email protected]8e4560b62011-01-14 10:09:14515 VisitorInterface* service,
516 Profile* profile,
517 ProviderCollection* provider_list) {
rkaplowdd66a1342015-03-05 00:31:49518 TRACE_EVENT0("browser,startup",
519 "ExternalProviderImpl::CreateExternalProviders");
[email protected]af984882013-10-21 21:08:51520 scoped_refptr<ExternalLoader> external_loader;
binjincccacef2014-10-13 19:00:20521 scoped_refptr<ExternalLoader> external_recommended_loader;
[email protected]af984882013-10-21 21:08:51522 extensions::Manifest::Location crx_location = Manifest::INVALID_LOCATION;
achuithd3da4f02017-03-23 20:05:29523
[email protected]af984882013-10-21 21:08:51524#if defined(OS_CHROMEOS)
achuithd3da4f02017-03-23 20:05:29525 if (chromeos::ProfileHelper::IsSigninProfile(profile)) {
526 // Download apps installed by policy in the login profile. Flags
527 // FROM_WEBSTORE/WAS_INSTALLED_BY_DEFAULT are applied because these apps are
528 // downloaded from the webstore, and we want to treat them as built-in
529 // extensions.
530 external_loader = new ExternalPolicyLoader(
531 ExtensionManagementFactory::GetForBrowserContext(profile),
532 ExternalPolicyLoader::FORCED);
Jinho Bangb5216cec2018-01-17 19:43:11533 auto signin_profile_provider = std::make_unique<ExternalProviderImpl>(
achuithd3da4f02017-03-23 20:05:29534 service, external_loader, profile, crx_location,
535 Manifest::EXTERNAL_POLICY_DOWNLOAD,
Toni Barzic87026682018-01-08 23:21:04536 Extension::FROM_WEBSTORE | Extension::WAS_INSTALLED_BY_DEFAULT);
537 signin_profile_provider->set_allow_updates(true);
538 provider_list->push_back(std::move(signin_profile_provider));
achuithd3da4f02017-03-23 20:05:29539 return;
540 }
541
[email protected]97275822014-01-21 19:30:36542 policy::BrowserPolicyConnectorChromeOS* connector =
543 g_browser_process->platform_part()->browser_policy_connector_chromeos();
[email protected]2d4cfed2014-01-14 13:59:57544 bool is_chrome_os_public_session = false;
[email protected]2fda9972014-07-23 14:51:59545 const user_manager::User* user =
[email protected]052e3ac2014-06-30 14:22:47546 chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
[email protected]2d4cfed2014-01-14 13:59:57547 policy::DeviceLocalAccount::Type account_type;
alemate909aa58a2016-11-03 22:49:07548 if (user && connector->IsEnterpriseManaged() &&
549 policy::IsDeviceLocalAccountUser(user->GetAccountId().GetUserEmail(),
550 &account_type)) {
[email protected]2d4cfed2014-01-14 13:59:57551 if (account_type == policy::DeviceLocalAccount::TYPE_PUBLIC_SESSION)
552 is_chrome_os_public_session = true;
[email protected]af984882013-10-21 21:08:51553 policy::DeviceLocalAccountPolicyBroker* broker =
[email protected]97275822014-01-21 19:30:36554 connector->GetDeviceLocalAccountPolicyService()->GetBrokerForUser(
alemate909aa58a2016-11-03 22:49:07555 user->GetAccountId().GetUserEmail());
[email protected]af984882013-10-21 21:08:51556 if (broker) {
557 external_loader = broker->extension_loader();
558 crx_location = Manifest::EXTERNAL_POLICY;
559 } else {
560 NOTREACHED();
561 }
562 } else {
binjin30301062014-09-08 20:27:34563 external_loader = new ExternalPolicyLoader(
binjincccacef2014-10-13 19:00:20564 ExtensionManagementFactory::GetForBrowserContext(profile),
565 ExternalPolicyLoader::FORCED);
566 external_recommended_loader = new ExternalPolicyLoader(
567 ExtensionManagementFactory::GetForBrowserContext(profile),
568 ExternalPolicyLoader::RECOMMENDED);
[email protected]af984882013-10-21 21:08:51569 }
570#else
binjin30301062014-09-08 20:27:34571 external_loader = new ExternalPolicyLoader(
binjincccacef2014-10-13 19:00:20572 ExtensionManagementFactory::GetForBrowserContext(profile),
573 ExternalPolicyLoader::FORCED);
574 external_recommended_loader = new ExternalPolicyLoader(
575 ExtensionManagementFactory::GetForBrowserContext(profile),
576 ExternalPolicyLoader::RECOMMENDED);
[email protected]af984882013-10-21 21:08:51577#endif
578
[email protected]b9f4fe52012-11-09 21:40:59579 // Policies are mandatory so they can't be skipped with command line flag.
dchengc7047942014-08-26 05:05:31580 if (external_loader.get()) {
Jinho Bangb5216cec2018-01-17 19:43:11581 auto policy_provider = std::make_unique<ExternalProviderImpl>(
lazyboyf33109d2016-08-31 00:37:08582 service, external_loader, profile, crx_location,
Toni Barzic87026682018-01-08 23:21:04583 Manifest::EXTERNAL_POLICY_DOWNLOAD, Extension::NO_FLAGS);
584 policy_provider->set_allow_updates(true);
585 provider_list->push_back(std::move(policy_provider));
[email protected]af984882013-10-21 21:08:51586 }
[email protected]b9f4fe52012-11-09 21:40:59587
[email protected]ee3da0552014-07-16 05:27:31588 // Load the KioskAppExternalProvider when running in kiosk mode.
589 if (chrome::IsRunningInForcedAppMode()) {
590#if defined(OS_CHROMEOS)
jennyz26b7f432015-09-03 20:59:27591 // Kiosk primary app external provider.
Toni Barzic87026682018-01-08 23:21:04592 // For enterprise managed kiosk apps, change the location to
593 // "force-installed by policy".
594 policy::BrowserPolicyConnectorChromeOS* const connector =
595 g_browser_process->platform_part()->browser_policy_connector_chromeos();
596 Manifest::Location location = Manifest::EXTERNAL_PREF;
597 if (connector && connector->IsEnterpriseManaged())
598 location = Manifest::EXTERNAL_POLICY;
pbond43ddd4f2015-09-08 16:39:19599
Toni Barzic87026682018-01-08 23:21:04600 std::unique_ptr<ExternalProviderImpl> kiosk_app_provider(
601 new ExternalProviderImpl(
602 service,
603 base::MakeRefCounted<chromeos::KioskAppExternalLoader>(
604 chromeos::KioskAppExternalLoader::AppClass::kPrimary),
605 profile, location, Manifest::INVALID_LOCATION,
606 Extension::NO_FLAGS));
607 kiosk_app_provider->set_auto_acknowledge(true);
608 kiosk_app_provider->set_install_immediately(true);
609 kiosk_app_provider->set_allow_updates(true);
610 provider_list->push_back(std::move(kiosk_app_provider));
jennyz26b7f432015-09-03 20:59:27611
612 // Kiosk secondary app external provider.
Toni Barzic87026682018-01-08 23:21:04613 std::unique_ptr<ExternalProviderImpl> secondary_kiosk_app_provider(
614 new ExternalProviderImpl(
615 service,
616 base::MakeRefCounted<chromeos::KioskAppExternalLoader>(
617 chromeos::KioskAppExternalLoader::AppClass::kSecondary),
618 profile, Manifest::EXTERNAL_PREF, Manifest::EXTERNAL_PREF_DOWNLOAD,
619 Extension::NO_FLAGS));
620 secondary_kiosk_app_provider->set_auto_acknowledge(true);
621 secondary_kiosk_app_provider->set_install_immediately(true);
622 secondary_kiosk_app_provider->set_allow_updates(true);
623 provider_list->push_back(std::move(secondary_kiosk_app_provider));
[email protected]ee3da0552014-07-16 05:27:31624#endif
625 return;
626 }
627
binjincccacef2014-10-13 19:00:20628 // Extensions provided by recommended policies.
629 if (external_recommended_loader.get()) {
Jinho Bangb5216cec2018-01-17 19:43:11630 provider_list->push_back(std::make_unique<ExternalProviderImpl>(
lazyboyf33109d2016-08-31 00:37:08631 service, external_recommended_loader, profile, crx_location,
632 Manifest::EXTERNAL_PREF_DOWNLOAD, Extension::NO_FLAGS));
binjincccacef2014-10-13 19:00:20633 }
634
[email protected]b9f4fe52012-11-09 21:40:59635 // In tests don't install extensions from default external sources.
636 // It would only slowdown tests and make them flaky.
avi3ef9ec9e2014-12-22 22:50:17637 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
Oscar Johansson7f4c1b932018-06-12 06:11:58638 ::switches::kDisableDefaultApps))
[email protected]b9f4fe52012-11-09 21:40:59639 return;
[email protected]73e4c362011-09-22 14:47:18640
641 // On Mac OS, items in /Library/... should be written by the superuser.
642 // Check that all components of the path are writable by root only.
[email protected]5df038b2012-07-16 19:03:27643 ExternalPrefLoader::Options check_admin_permissions_on_mac;
[email protected]73e4c362011-09-22 14:47:18644#if defined(OS_MACOSX)
[email protected]0edc55412011-11-07 16:47:33645 check_admin_permissions_on_mac =
[email protected]5df038b2012-07-16 19:03:27646 ExternalPrefLoader::ENSURE_PATH_CONTROLLED_BY_ADMIN;
[email protected]73e4c362011-09-22 14:47:18647#else
[email protected]5df038b2012-07-16 19:03:27648 check_admin_permissions_on_mac = ExternalPrefLoader::NONE;
[email protected]73e4c362011-09-22 14:47:18649#endif
650
Peter Kastingbe940e92014-11-20 23:14:08651#if !defined(OS_WIN)
[email protected]d6f7b102012-05-04 13:59:05652 int bundled_extension_creation_flags = Extension::NO_FLAGS;
Peter Kastingbe940e92014-11-20 23:14:08653#endif
[email protected]03d3ba012012-04-02 22:36:13654#if defined(OS_CHROMEOS)
[email protected]5861bcd2012-10-16 21:40:19655 bundled_extension_creation_flags = Extension::FROM_WEBSTORE |
656 Extension::WAS_INSTALLED_BY_DEFAULT;
[email protected]a4567732013-07-25 21:01:20657
rkcb526cd6b2014-12-18 16:54:37658 if (!is_chrome_os_public_session) {
khmelcb892d52018-01-06 03:01:40659 std::vector<int> external_apps_path_ids;
660 if (profile->IsChild()) {
661 external_apps_path_ids.push_back(chrome::DIR_CHILD_USERS_DEFAULT_APPS);
662 } else if (profile->IsSupervised()) {
663 external_apps_path_ids.push_back(
664 chrome::DIR_SUPERVISED_USERS_DEFAULT_APPS);
665 } else {
666 external_apps_path_ids.push_back(
667 chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS);
668 external_apps_path_ids.push_back(chrome::DIR_CHILD_USERS_DEFAULT_APPS);
669 }
670 const ExternalPrefLoader::Options pref_load_flags =
ginkagef66fae522015-03-03 16:38:16671 profile->IsNewProfile()
672 ? ExternalPrefLoader::DELAY_LOAD_UNTIL_PRIORITY_SYNC
673 : ExternalPrefLoader::NONE;
khmelcb892d52018-01-06 03:01:40674 for (const auto external_apps_path_id : external_apps_path_ids) {
Jinho Bangb5216cec2018-01-17 19:43:11675 provider_list->push_back(std::make_unique<ExternalProviderImpl>(
khmelcb892d52018-01-06 03:01:40676 service,
677 new ExternalPrefLoader(external_apps_path_id, pref_load_flags,
678 profile),
679 profile, Manifest::EXTERNAL_PREF, Manifest::EXTERNAL_PREF_DOWNLOAD,
680 bundled_extension_creation_flags));
681 }
[email protected]d0b28892014-03-05 18:56:31682
683 // OEM default apps.
[email protected]acc3c7c22014-03-19 06:23:39684 int oem_extension_creation_flags =
685 bundled_extension_creation_flags | Extension::WAS_INSTALLED_BY_OEM;
[email protected]d0b28892014-03-05 18:56:31686 chromeos::ServicesCustomizationDocument* customization =
687 chromeos::ServicesCustomizationDocument::GetInstance();
Jinho Bangb5216cec2018-01-17 19:43:11688 provider_list->push_back(std::make_unique<ExternalProviderImpl>(
lazyboyf33109d2016-08-31 00:37:08689 service, customization->CreateExternalLoader(profile), profile,
690 Manifest::EXTERNAL_PREF, Manifest::EXTERNAL_PREF_DOWNLOAD,
691 oem_extension_creation_flags));
[email protected]ebb489f2013-09-19 22:08:52692 }
Toni Barzicdff51562018-07-24 19:55:46693
694 // For Chrome OS demo sessions, add pre-installed demo extensions and apps.
695 if (chromeos::DemoExtensionsExternalLoader::SupportedForProfile(profile)) {
696 std::unique_ptr<ExternalProviderImpl> demo_apps_provider =
697 std::make_unique<ExternalProviderImpl>(
698 service,
699 base::MakeRefCounted<chromeos::DemoExtensionsExternalLoader>(),
700 profile, Manifest::EXTERNAL_PREF, Manifest::INVALID_LOCATION,
701 Extension::NO_FLAGS);
702 demo_apps_provider->set_auto_acknowledge(true);
703 demo_apps_provider->set_install_immediately(true);
704 provider_list->push_back(std::move(demo_apps_provider));
705 }
706
Peter Kastingbe940e92014-11-20 23:14:08707#elif defined(OS_LINUX)
treibcc82ab82015-03-02 09:41:49708 if (!profile->IsLegacySupervised()) {
Jinho Bangb5216cec2018-01-17 19:43:11709 provider_list->push_back(std::make_unique<ExternalProviderImpl>(
lazyboyf33109d2016-08-31 00:37:08710 service,
711 new ExternalPrefLoader(chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS,
712 ExternalPrefLoader::NONE, nullptr),
713 profile, Manifest::EXTERNAL_PREF, Manifest::EXTERNAL_PREF_DOWNLOAD,
714 bundled_extension_creation_flags));
Peter Kastingbe940e92014-11-20 23:14:08715 }
[email protected]5bed2ec32013-08-29 22:55:46716#endif
717
treibcc82ab82015-03-02 09:41:49718 if (!profile->IsLegacySupervised()) {
Peter Kastingbe940e92014-11-20 23:14:08719#if defined(OS_WIN)
Jinho Bangb5216cec2018-01-17 19:43:11720 auto registry_provider = std::make_unique<ExternalProviderImpl>(
lazyboyf33109d2016-08-31 00:37:08721 service, new ExternalRegistryLoader, profile,
722 Manifest::EXTERNAL_REGISTRY, Manifest::EXTERNAL_PREF_DOWNLOAD,
Toni Barzic87026682018-01-08 23:21:04723 Extension::NO_FLAGS);
724 registry_provider->set_allow_updates(true);
725 provider_list->push_back(std::move(registry_provider));
Peter Kastingbe940e92014-11-20 23:14:08726#else
Jinho Bangb5216cec2018-01-17 19:43:11727 provider_list->push_back(std::make_unique<ExternalProviderImpl>(
lazyboyf33109d2016-08-31 00:37:08728 service,
729 new ExternalPrefLoader(chrome::DIR_EXTERNAL_EXTENSIONS,
730 check_admin_permissions_on_mac, nullptr),
731 profile, Manifest::EXTERNAL_PREF, Manifest::EXTERNAL_PREF_DOWNLOAD,
732 bundled_extension_creation_flags));
[email protected]5bed2ec32013-08-29 22:55:46733
[email protected]7da12212013-02-14 10:53:49734 // Define a per-user source of external extensions.
sydlie21e153d2015-07-30 19:57:56735#if defined(OS_MACOSX) || (defined(OS_LINUX) && defined(CHROMIUM_BUILD))
Jinho Bangb5216cec2018-01-17 19:43:11736 provider_list->push_back(std::make_unique<ExternalProviderImpl>(
737 service,
738 new ExternalPrefLoader(chrome::DIR_USER_EXTERNAL_EXTENSIONS,
739 ExternalPrefLoader::NONE, nullptr),
lazyboyf33109d2016-08-31 00:37:08740 profile, Manifest::EXTERNAL_PREF, Manifest::EXTERNAL_PREF_DOWNLOAD,
741 Extension::NO_FLAGS));
[email protected]a29a517a2011-01-21 21:11:12742#endif
[email protected]8e4560b62011-01-14 10:09:14743#endif
[email protected]ed7bbb52012-05-02 11:07:29744
[email protected]98b4aca62011-09-28 01:27:23745#if !defined(OS_CHROMEOS)
[email protected]7da12212013-02-14 10:53:49746 // The default apps are installed as INTERNAL but use the external
747 // extension installer codeflow.
Jinho Bangb5216cec2018-01-17 19:43:11748 provider_list->push_back(std::make_unique<default_apps::Provider>(
lazyboyf33109d2016-08-31 00:37:08749 profile, service,
750 new ExternalPrefLoader(chrome::DIR_DEFAULT_APPS,
751 ExternalPrefLoader::NONE, nullptr),
752 Manifest::INTERNAL, Manifest::INTERNAL,
753 Extension::FROM_WEBSTORE | Extension::WAS_INSTALLED_BY_DEFAULT));
[email protected]98b4aca62011-09-28 01:27:23754#endif
xiyuan65b68ab12015-06-26 19:00:18755
dchengc963c7142016-04-08 03:55:22756 std::unique_ptr<ExternalProviderImpl> drive_migration_provider(
xiyuan196e25dd2015-07-08 21:56:14757 new ExternalProviderImpl(
758 service,
dchengc963c7142016-04-08 03:55:22759 new ExtensionMigrator(profile, extension_misc::kDriveHostedAppId,
xiyuan196e25dd2015-07-08 21:56:14760 extension_misc::kDriveExtensionId),
dchengc963c7142016-04-08 03:55:22761 profile, Manifest::EXTERNAL_PREF, Manifest::EXTERNAL_PREF_DOWNLOAD,
762 Extension::FROM_WEBSTORE | Extension::WAS_INSTALLED_BY_DEFAULT));
xiyuan196e25dd2015-07-08 21:56:14763 drive_migration_provider->set_auto_acknowledge(true);
lazyboyf33109d2016-08-31 00:37:08764 provider_list->push_back(std::move(drive_migration_provider));
[email protected]5bed2ec32013-08-29 22:55:46765 }
treibcc82ab82015-03-02 09:41:49766
Jinho Bangb5216cec2018-01-17 19:43:11767 provider_list->push_back(std::make_unique<ExternalProviderImpl>(
lazyboyf33109d2016-08-31 00:37:08768 service, new ExternalComponentLoader(profile), profile,
769 Manifest::INVALID_LOCATION, Manifest::EXTERNAL_COMPONENT,
770 Extension::FROM_WEBSTORE | Extension::WAS_INSTALLED_BY_DEFAULT));
[email protected]8e4560b62011-01-14 10:09:14771}
[email protected]5df038b2012-07-16 19:03:27772
773} // namespace extensions