cygprofile: increase timeouts to allow showing web contents
[chromium-blink-merge.git] / chrome / browser / extensions / extension_sync_service.cc
blob93f89ee6e7121f5b7a9dec6c7b550daf9b770d09
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/extension_sync_service.h"
7 #include "base/basictypes.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/extensions/bookmark_app_helper.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/extensions/extension_sync_data.h"
12 #include "chrome/browser/extensions/extension_sync_service_factory.h"
13 #include "chrome/browser/extensions/extension_util.h"
14 #include "chrome/browser/extensions/launch_util.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/sync/glue/sync_start_util.h"
17 #include "chrome/common/extensions/extension_constants.h"
18 #include "chrome/common/extensions/sync_helper.h"
19 #include "chrome/common/web_application_info.h"
20 #include "extensions/browser/app_sorting.h"
21 #include "extensions/browser/extension_prefs.h"
22 #include "extensions/browser/extension_registry.h"
23 #include "extensions/browser/extension_system.h"
24 #include "extensions/browser/extension_util.h"
25 #include "extensions/browser/uninstall_reason.h"
26 #include "extensions/common/extension.h"
27 #include "extensions/common/extension_set.h"
28 #include "extensions/common/image_util.h"
29 #include "sync/api/sync_change.h"
30 #include "sync/api/sync_error_factory.h"
32 using extensions::AppSorting;
33 using extensions::Extension;
34 using extensions::ExtensionPrefs;
35 using extensions::ExtensionRegistry;
36 using extensions::ExtensionSet;
37 using extensions::ExtensionSyncData;
38 using extensions::ExtensionSystem;
39 using extensions::SyncBundle;
41 namespace {
43 void OnWebApplicationInfoLoaded(
44 WebApplicationInfo synced_info,
45 base::WeakPtr<ExtensionService> extension_service,
46 const WebApplicationInfo& loaded_info) {
47 DCHECK_EQ(synced_info.app_url, loaded_info.app_url);
49 if (!extension_service)
50 return;
52 // Use the old icons if they exist.
53 synced_info.icons = loaded_info.icons;
54 CreateOrUpdateBookmarkApp(extension_service.get(), &synced_info);
57 // Returns the pref value for "all urls enabled" for the given extension id.
58 ExtensionSyncData::OptionalBoolean GetAllowedOnAllUrlsOptionalBoolean(
59 const std::string& extension_id,
60 content::BrowserContext* context) {
61 bool allowed_on_all_urls =
62 extensions::util::AllowedScriptingOnAllUrls(extension_id, context);
63 // If the extension is not allowed on all urls (which is not the default),
64 // then we have to sync the preference.
65 if (!allowed_on_all_urls)
66 return ExtensionSyncData::BOOLEAN_FALSE;
68 // If the user has explicitly set a value, then we sync it.
69 if (extensions::util::HasSetAllowedScriptingOnAllUrls(extension_id, context))
70 return ExtensionSyncData::BOOLEAN_TRUE;
72 // Otherwise, unset.
73 return ExtensionSyncData::BOOLEAN_UNSET;
76 // Returns true if the sync type of |extension| matches |type|.
77 bool IsCorrectSyncType(const Extension& extension, syncer::ModelType type) {
78 return (type == syncer::EXTENSIONS && extension.is_extension()) ||
79 (type == syncer::APPS && extension.is_app());
82 syncer::SyncDataList ToSyncerSyncDataList(
83 const std::vector<ExtensionSyncData>& data) {
84 syncer::SyncDataList result;
85 result.reserve(data.size());
86 for (const ExtensionSyncData& item : data)
87 result.push_back(item.GetSyncData());
88 return result;
91 } // namespace
93 ExtensionSyncService::ExtensionSyncService(Profile* profile)
94 : profile_(profile),
95 registry_observer_(this),
96 prefs_observer_(this),
97 flare_(sync_start_util::GetFlareForSyncableService(profile->GetPath())) {
98 registry_observer_.Add(ExtensionRegistry::Get(profile_));
99 prefs_observer_.Add(ExtensionPrefs::Get(profile_));
102 ExtensionSyncService::~ExtensionSyncService() {
105 // static
106 ExtensionSyncService* ExtensionSyncService::Get(
107 content::BrowserContext* context) {
108 return ExtensionSyncServiceFactory::GetForBrowserContext(context);
111 void ExtensionSyncService::SyncExtensionChangeIfNeeded(
112 const Extension& extension) {
113 if (!extensions::util::ShouldSync(&extension, profile_))
114 return;
116 syncer::ModelType type =
117 extension.is_app() ? syncer::APPS : syncer::EXTENSIONS;
118 SyncBundle* bundle = GetSyncBundle(type);
119 if (bundle->IsSyncing()) {
120 bundle->PushSyncAddOrUpdate(extension.id(),
121 CreateSyncData(extension).GetSyncData());
122 DCHECK(!ExtensionPrefs::Get(profile_)->NeedsSync(extension.id()));
123 } else {
124 ExtensionPrefs::Get(profile_)->SetNeedsSync(extension.id(), true);
125 if (extension_service()->is_ready() && !flare_.is_null())
126 flare_.Run(type); // Tell sync to start ASAP.
130 syncer::SyncMergeResult ExtensionSyncService::MergeDataAndStartSyncing(
131 syncer::ModelType type,
132 const syncer::SyncDataList& initial_sync_data,
133 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
134 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
135 CHECK(sync_processor.get());
136 LOG_IF(FATAL, type != syncer::EXTENSIONS && type != syncer::APPS)
137 << "Got " << type << " ModelType";
139 SyncBundle* bundle = GetSyncBundle(type);
140 bundle->StartSyncing(sync_processor.Pass());
142 // Apply the initial sync data, filtering out any items where we have more
143 // recent local changes. Also tell the SyncBundle the extension IDs.
144 for (const syncer::SyncData& sync_data : initial_sync_data) {
145 scoped_ptr<ExtensionSyncData> extension_sync_data(
146 ExtensionSyncData::CreateFromSyncData(sync_data));
147 // If the extension has local state that needs to be synced, ignore this
148 // change (we assume the local state is more recent).
149 if (extension_sync_data &&
150 !ExtensionPrefs::Get(profile_)->NeedsSync(extension_sync_data->id())) {
151 ApplySyncData(*extension_sync_data);
155 // Now push those local changes to sync.
156 // TODO(treib,kalman): We should only have to send out changes for extensions
157 // which have NeedsSync set (i.e. |GetLocalSyncDataList(type, false)|). That
158 // makes some sync_integration_tests fail though - figure out why and fix it!
159 std::vector<ExtensionSyncData> data_list = GetLocalSyncDataList(type, true);
160 bundle->PushSyncDataList(ToSyncerSyncDataList(data_list));
161 for (const ExtensionSyncData& data : data_list)
162 ExtensionPrefs::Get(profile_)->SetNeedsSync(data.id(), false);
164 if (type == syncer::APPS)
165 ExtensionSystem::Get(profile_)->app_sorting()->FixNTPOrdinalCollisions();
167 return syncer::SyncMergeResult(type);
170 void ExtensionSyncService::StopSyncing(syncer::ModelType type) {
171 GetSyncBundle(type)->Reset();
174 syncer::SyncDataList ExtensionSyncService::GetAllSyncData(
175 syncer::ModelType type) const {
176 const SyncBundle* bundle = GetSyncBundle(type);
177 if (!bundle->IsSyncing())
178 return syncer::SyncDataList();
180 std::vector<ExtensionSyncData> sync_data_list =
181 GetLocalSyncDataList(type, true);
183 // Add pending data (where the local extension is not installed yet).
184 std::vector<ExtensionSyncData> pending_extensions =
185 bundle->GetPendingExtensionData();
186 sync_data_list.insert(sync_data_list.begin(),
187 pending_extensions.begin(),
188 pending_extensions.end());
190 return ToSyncerSyncDataList(sync_data_list);
193 syncer::SyncError ExtensionSyncService::ProcessSyncChanges(
194 const tracked_objects::Location& from_here,
195 const syncer::SyncChangeList& change_list) {
196 for (const syncer::SyncChange& sync_change : change_list) {
197 scoped_ptr<ExtensionSyncData> extension_sync_data(
198 ExtensionSyncData::CreateFromSyncChange(sync_change));
199 if (extension_sync_data)
200 ApplySyncData(*extension_sync_data);
203 ExtensionSystem::Get(profile_)->app_sorting()->FixNTPOrdinalCollisions();
205 return syncer::SyncError();
208 ExtensionSyncData ExtensionSyncService::CreateSyncData(
209 const Extension& extension) const {
210 const ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile_);
211 // Query the enabled state from ExtensionPrefs rather than
212 // ExtensionService::IsExtensionEnabled - the latter uses ExtensionRegistry
213 // which might not have been updated yet (ExtensionPrefs are updated first,
214 // and we're listening for changes to these).
215 bool enabled = !extension_prefs->IsExtensionDisabled(extension.id());
216 enabled = enabled &&
217 !extension_prefs->IsExternalExtensionUninstalled(extension.id());
218 // Blacklisted extensions are not marked as disabled in ExtensionPrefs.
219 enabled = enabled &&
220 extension_prefs->GetExtensionBlacklistState(extension.id()) ==
221 extensions::NOT_BLACKLISTED;
222 int disable_reasons = extension_prefs->GetDisableReasons(extension.id());
223 bool incognito_enabled = extensions::util::IsIncognitoEnabled(extension.id(),
224 profile_);
225 bool remote_install =
226 extension_prefs->HasDisableReason(extension.id(),
227 Extension::DISABLE_REMOTE_INSTALL);
228 ExtensionSyncData::OptionalBoolean allowed_on_all_url =
229 GetAllowedOnAllUrlsOptionalBoolean(extension.id(), profile_);
230 AppSorting* app_sorting = ExtensionSystem::Get(profile_)->app_sorting();
232 ExtensionSyncData result = extension.is_app()
233 ? ExtensionSyncData(
234 extension, enabled, disable_reasons, incognito_enabled,
235 remote_install, allowed_on_all_url,
236 app_sorting->GetAppLaunchOrdinal(extension.id()),
237 app_sorting->GetPageOrdinal(extension.id()),
238 extensions::GetLaunchTypePrefValue(extension_prefs,
239 extension.id()))
240 : ExtensionSyncData(
241 extension, enabled, disable_reasons, incognito_enabled,
242 remote_install, allowed_on_all_url);
244 // If there's a pending update, send the new version to sync instead of the
245 // installed one.
246 auto it = pending_update_versions_.find(extension.id());
247 if (it != pending_update_versions_.end()) {
248 const base::Version& version = it->second;
249 // If we have a pending version, it should be newer than the installed one.
250 DCHECK_EQ(-1, extension.version()->CompareTo(version));
251 result.set_version(version);
253 return result;
256 void ExtensionSyncService::ApplySyncData(
257 const ExtensionSyncData& extension_sync_data) {
258 syncer::ModelType type = extension_sync_data.is_app() ? syncer::APPS
259 : syncer::EXTENSIONS;
260 const std::string& id = extension_sync_data.id();
261 // Note: |extension| may be null if it hasn't been installed yet.
262 const Extension* extension =
263 ExtensionRegistry::Get(profile_)->GetInstalledExtension(id);
264 // TODO(bolms): we should really handle this better. The particularly bad
265 // case is where an app becomes an extension or vice versa, and we end up with
266 // a zombie extension that won't go away.
267 // TODO(treib): Is this still true?
268 if (extension && !IsCorrectSyncType(*extension, type))
269 return;
271 SyncBundle* bundle = GetSyncBundle(type);
272 // Forward to the bundle. This will just update the list of synced extensions.
273 bundle->ApplySyncData(extension_sync_data);
275 // Handle uninstalls first.
276 if (extension_sync_data.uninstalled()) {
277 if (!ExtensionService::UninstallExtensionHelper(
278 extension_service(), id, extensions::UNINSTALL_REASON_SYNC)) {
279 LOG(WARNING) << "Could not uninstall extension " << id << " for sync";
281 return;
284 // Extension from sync was uninstalled by the user as an external extension.
285 // Honor user choice and skip installation/enabling.
286 // TODO(treib): Should we still apply pref changes?
287 if (ExtensionPrefs::Get(profile_)->IsExternalExtensionUninstalled(id)) {
288 LOG(WARNING) << "Extension with id " << id
289 << " from sync was uninstalled as external extension";
290 return;
293 int version_compare_result = extension ?
294 extension->version()->CompareTo(extension_sync_data.version()) : 0;
296 // Enable/disable the extension.
297 if (extension_sync_data.enabled()) {
298 DCHECK(!extension_sync_data.disable_reasons());
300 // Only grant permissions if the sync data explicitly sets the disable
301 // reasons to Extension::DISABLE_NONE (as opposed to the legacy (<M45) case
302 // where they're not set at all), and if the version from sync matches our
303 // local one. Otherwise we just enable it without granting permissions. If
304 // any permissions are missing, CheckPermissionsIncrease will soon disable
305 // it again.
306 bool grant_permissions =
307 extension_sync_data.supports_disable_reasons() &&
308 extension && (version_compare_result == 0);
309 if (grant_permissions)
310 extension_service()->GrantPermissionsAndEnableExtension(extension);
311 else
312 extension_service()->EnableExtension(id);
313 } else {
314 int disable_reasons = extension_sync_data.disable_reasons();
315 if (extension_sync_data.remote_install()) {
316 if (!(disable_reasons & Extension::DISABLE_REMOTE_INSTALL)) {
317 // In the non-legacy case (>=M45) where disable reasons are synced at
318 // all, DISABLE_REMOTE_INSTALL should be among them already.
319 DCHECK(!extension_sync_data.supports_disable_reasons());
320 disable_reasons |= Extension::DISABLE_REMOTE_INSTALL;
322 } else if (!extension_sync_data.supports_disable_reasons()) {
323 // Legacy case (<M45), from before we synced disable reasons (see
324 // crbug.com/484214).
325 disable_reasons = Extension::DISABLE_UNKNOWN_FROM_SYNC;
328 // In the non-legacy case (>=M45), clear any existing disable reasons first.
329 // Otherwise sync can't remove just some of them.
330 if (extension_sync_data.supports_disable_reasons())
331 ExtensionPrefs::Get(profile_)->ClearDisableReasons(id);
333 extension_service()->DisableExtension(id, disable_reasons);
336 // If the target extension has already been installed ephemerally, it can
337 // be promoted to a regular installed extension and downloading from the Web
338 // Store is not necessary.
339 if (extension && extensions::util::IsEphemeralApp(id, profile_))
340 extension_service()->PromoteEphemeralApp(extension, true);
342 // Cache whether the extension was already installed because setting the
343 // incognito flag invalidates the |extension| pointer (it reloads the
344 // extension).
345 bool extension_installed = (extension != nullptr);
347 // Update the incognito flag.
348 extensions::util::SetIsIncognitoEnabled(
349 id, profile_, extension_sync_data.incognito_enabled());
350 extension = nullptr; // No longer safe to use.
352 // Update the all urls flag.
353 if (extension_sync_data.all_urls_enabled() !=
354 ExtensionSyncData::BOOLEAN_UNSET) {
355 bool allowed = extension_sync_data.all_urls_enabled() ==
356 ExtensionSyncData::BOOLEAN_TRUE;
357 extensions::util::SetAllowedScriptingOnAllUrls(id, profile_, allowed);
360 // Set app-specific data.
361 if (extension_sync_data.is_app()) {
362 if (extension_sync_data.app_launch_ordinal().IsValid() &&
363 extension_sync_data.page_ordinal().IsValid()) {
364 AppSorting* app_sorting = ExtensionSystem::Get(profile_)->app_sorting();
365 app_sorting->SetAppLaunchOrdinal(
367 extension_sync_data.app_launch_ordinal());
368 app_sorting->SetPageOrdinal(id, extension_sync_data.page_ordinal());
371 // The corresponding validation of this value during ExtensionSyncData
372 // population is in ExtensionSyncData::ToAppSpecifics.
373 if (extension_sync_data.launch_type() >= extensions::LAUNCH_TYPE_FIRST &&
374 extension_sync_data.launch_type() < extensions::NUM_LAUNCH_TYPES) {
375 extensions::SetLaunchType(
376 profile_, id, extension_sync_data.launch_type());
379 if (!extension_sync_data.bookmark_app_url().empty())
380 ApplyBookmarkAppSyncData(extension_sync_data);
383 // Finally, trigger installation/update as required.
384 bool check_for_updates = false;
385 if (extension_installed) {
386 // If the extension is installed but outdated, store the new version.
387 if (version_compare_result < 0) {
388 pending_update_versions_[id] = extension_sync_data.version();
389 check_for_updates = true;
391 } else {
392 if (!extension_service()->pending_extension_manager()->AddFromSync(
394 extension_sync_data.update_url(),
395 extensions::sync_helper::IsSyncable,
396 extension_sync_data.remote_install(),
397 extension_sync_data.installed_by_custodian())) {
398 LOG(WARNING) << "Could not add pending extension for " << id;
399 // This means that the extension is already pending installation, with a
400 // non-INTERNAL location. Add to pending_sync_data, even though it will
401 // never be removed (we'll never install a syncable version of the
402 // extension), so that GetAllSyncData() continues to send it.
404 // Track pending extensions so that we can return them in GetAllSyncData().
405 bundle->AddPendingExtensionData(id, extension_sync_data);
406 check_for_updates = true;
409 if (check_for_updates)
410 extension_service()->CheckForUpdatesSoon();
413 void ExtensionSyncService::ApplyBookmarkAppSyncData(
414 const ExtensionSyncData& extension_sync_data) {
415 DCHECK(extension_sync_data.is_app());
417 // Process bookmark app sync if necessary.
418 GURL bookmark_app_url(extension_sync_data.bookmark_app_url());
419 if (!bookmark_app_url.is_valid() ||
420 extension_sync_data.uninstalled()) {
421 return;
424 const Extension* extension =
425 extension_service()->GetInstalledExtension(extension_sync_data.id());
427 // Return if there are no bookmark app details that need updating.
428 if (extension &&
429 extension->non_localized_name() == extension_sync_data.name() &&
430 extension->description() ==
431 extension_sync_data.bookmark_app_description()) {
432 return;
435 WebApplicationInfo web_app_info;
436 web_app_info.app_url = bookmark_app_url;
437 web_app_info.title = base::UTF8ToUTF16(extension_sync_data.name());
438 web_app_info.description =
439 base::UTF8ToUTF16(extension_sync_data.bookmark_app_description());
440 if (!extension_sync_data.bookmark_app_icon_color().empty()) {
441 extensions::image_util::ParseCSSColorString(
442 extension_sync_data.bookmark_app_icon_color(),
443 &web_app_info.generated_icon_color);
445 for (const auto& icon : extension_sync_data.linked_icons()) {
446 WebApplicationInfo::IconInfo icon_info;
447 icon_info.url = icon.url;
448 icon_info.width = icon.size;
449 icon_info.height = icon.size;
450 web_app_info.icons.push_back(icon_info);
453 // If the bookmark app already exists, keep the old icons.
454 if (!extension) {
455 CreateOrUpdateBookmarkApp(extension_service(), &web_app_info);
456 } else {
457 GetWebApplicationInfoFromApp(profile_,
458 extension,
459 base::Bind(&OnWebApplicationInfoLoaded,
460 web_app_info,
461 extension_service()->AsWeakPtr()));
465 void ExtensionSyncService::SetSyncStartFlareForTesting(
466 const syncer::SyncableService::StartSyncFlare& flare) {
467 flare_ = flare;
470 ExtensionService* ExtensionSyncService::extension_service() const {
471 return ExtensionSystem::Get(profile_)->extension_service();
474 void ExtensionSyncService::OnExtensionInstalled(
475 content::BrowserContext* browser_context,
476 const Extension* extension,
477 bool is_update) {
478 DCHECK_EQ(profile_, browser_context);
479 // Clear pending version if the installed one has caught up.
480 auto it = pending_update_versions_.find(extension->id());
481 if (it != pending_update_versions_.end()) {
482 const base::Version& pending_version = it->second;
483 if (extension->version()->CompareTo(pending_version) >= 0)
484 pending_update_versions_.erase(it);
486 SyncExtensionChangeIfNeeded(*extension);
489 void ExtensionSyncService::OnExtensionUninstalled(
490 content::BrowserContext* browser_context,
491 const Extension* extension,
492 extensions::UninstallReason reason) {
493 DCHECK_EQ(profile_, browser_context);
494 // Don't bother syncing if the extension will be re-installed momentarily.
495 if (reason == extensions::UNINSTALL_REASON_REINSTALL ||
496 !extensions::util::ShouldSync(extension, profile_))
497 return;
499 // TODO(tim): If we get here and IsSyncing is false, this will cause
500 // "back from the dead" style bugs, because sync will add-back the extension
501 // that was uninstalled here when MergeDataAndStartSyncing is called.
502 // See crbug.com/256795.
503 // Possible fix: Set NeedsSync here, then in MergeDataAndStartSyncing, if
504 // NeedsSync is set but the extension isn't installed, send a sync deletion.
505 syncer::ModelType type =
506 extension->is_app() ? syncer::APPS : syncer::EXTENSIONS;
507 SyncBundle* bundle = GetSyncBundle(type);
508 if (bundle->IsSyncing()) {
509 bundle->PushSyncDeletion(extension->id(),
510 CreateSyncData(*extension).GetSyncData());
511 } else if (extension_service()->is_ready() && !flare_.is_null()) {
512 flare_.Run(type); // Tell sync to start ASAP.
515 pending_update_versions_.erase(extension->id());
518 void ExtensionSyncService::OnExtensionStateChanged(
519 const std::string& extension_id,
520 bool state) {
521 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
522 const Extension* extension = registry->GetInstalledExtension(extension_id);
523 // We can get pref change notifications for extensions that aren't installed
524 // (yet). In that case, we'll pick up the change later via ExtensionRegistry
525 // observation (in OnExtensionInstalled).
526 if (extension)
527 SyncExtensionChangeIfNeeded(*extension);
530 void ExtensionSyncService::OnExtensionDisableReasonsChanged(
531 const std::string& extension_id,
532 int disabled_reasons) {
533 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
534 const Extension* extension = registry->GetInstalledExtension(extension_id);
535 // We can get pref change notifications for extensions that aren't installed
536 // (yet). In that case, we'll pick up the change later via ExtensionRegistry
537 // observation (in OnExtensionInstalled).
538 if (extension)
539 SyncExtensionChangeIfNeeded(*extension);
542 SyncBundle* ExtensionSyncService::GetSyncBundle(syncer::ModelType type) {
543 return const_cast<SyncBundle*>(
544 const_cast<const ExtensionSyncService&>(*this).GetSyncBundle(type));
547 const SyncBundle* ExtensionSyncService::GetSyncBundle(
548 syncer::ModelType type) const {
549 return (type == syncer::APPS) ? &app_sync_bundle_ : &extension_sync_bundle_;
552 std::vector<ExtensionSyncData> ExtensionSyncService::GetLocalSyncDataList(
553 syncer::ModelType type,
554 bool include_everything) const {
555 // Collect the local state.
556 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
557 std::vector<ExtensionSyncData> data;
558 // TODO(treib, kalman): Should we be including blacklisted/blocked extensions
559 // here? I.e. just calling registry->GeneratedInstalledExtensionsSet()?
560 // It would be more consistent, but the danger is that the black/blocklist
561 // hasn't been updated on all clients by the time sync has kicked in -
562 // so it's safest not to. Take care to add any other extension lists here
563 // in the future if they are added.
564 FillSyncDataList(
565 registry->enabled_extensions(), type, include_everything, &data);
566 FillSyncDataList(
567 registry->disabled_extensions(), type, include_everything, &data);
568 FillSyncDataList(
569 registry->terminated_extensions(), type, include_everything, &data);
570 return data;
573 void ExtensionSyncService::FillSyncDataList(
574 const ExtensionSet& extensions,
575 syncer::ModelType type,
576 bool include_everything,
577 std::vector<ExtensionSyncData>* sync_data_list) const {
578 for (const scoped_refptr<const Extension>& extension : extensions) {
579 if (IsCorrectSyncType(*extension, type) &&
580 extensions::util::ShouldSync(extension.get(), profile_) &&
581 (include_everything ||
582 ExtensionPrefs::Get(profile_)->NeedsSync(extension->id()))) {
583 // We should never have pending data for an installed extension.
584 DCHECK(!GetSyncBundle(type)->HasPendingExtensionData(extension->id()));
585 sync_data_list->push_back(CreateSyncData(*extension));