Cleanup ExtensionSyncService and SyncBundle.

- Merge AppSyncData into ExtensionSyncData.
- Remove duplication between AppSyncBundle and ExtensionSyncBundle by moving everything into the common SyncBundle.
- In SyncBundle, use consistent "push"/"apply" notation for changes going to/coming from Sync, rather than "process" for everything.
- Reduce the back-and-forth of ExtensionSyncService and SyncBundle calling into each other.

TBRing a straightforward change in two_client_apps_sync_test.cc
[email protected]

BUG=None

Review URL: https://codereview.chromium.org/1214923004

Cr-Commit-Position: refs/heads/master@{#337793}
diff --git a/chrome/browser/extensions/extension_sync_service.cc b/chrome/browser/extensions/extension_sync_service.cc
index 90f679f..5848247 100644
--- a/chrome/browser/extensions/extension_sync_service.cc
+++ b/chrome/browser/extensions/extension_sync_service.cc
@@ -4,13 +4,9 @@
 
 #include "chrome/browser/extensions/extension_sync_service.h"
 
-#include <iterator>
-
 #include "base/basictypes.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_restrictions.h"
-#include "chrome/browser/extensions/app_sync_data.h"
 #include "chrome/browser/extensions/bookmark_app_helper.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_sync_data.h"
@@ -20,7 +16,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/glue/sync_start_util.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/extensions/sync_helper.h"
 #include "chrome/common/web_application_info.h"
 #include "components/sync_driver/sync_prefs.h"
@@ -30,21 +25,18 @@
 #include "extensions/browser/extension_util.h"
 #include "extensions/browser/uninstall_reason.h"
 #include "extensions/common/extension.h"
-#include "extensions/common/extension_icon_set.h"
-#include "extensions/common/feature_switch.h"
+#include "extensions/common/extension_set.h"
 #include "extensions/common/image_util.h"
-#include "extensions/common/manifest_constants.h"
-#include "extensions/common/manifest_handlers/icons_handler.h"
 #include "sync/api/sync_change.h"
 #include "sync/api/sync_error_factory.h"
-#include "ui/gfx/image/image_family.h"
 
-using extensions::AppSyncData;
 using extensions::Extension;
 using extensions::ExtensionPrefs;
 using extensions::ExtensionRegistry;
+using extensions::ExtensionSet;
 using extensions::ExtensionSyncData;
-using extensions::FeatureSwitch;
+using extensions::PendingEnables;
+using extensions::SyncBundle;
 
 namespace {
 
@@ -81,6 +73,28 @@
   return ExtensionSyncData::BOOLEAN_UNSET;
 }
 
+// Returns true if the sync type of |extension| matches |type|.
+bool IsCorrectSyncType(const Extension& extension, syncer::ModelType type) {
+  if (type == syncer::EXTENSIONS &&
+      extensions::sync_helper::IsSyncableExtension(&extension)) {
+    return true;
+  }
+
+  if (type == syncer::APPS &&
+      extensions::sync_helper::IsSyncableApp(&extension)) {
+    return true;
+  }
+
+  return false;
+}
+
+// Returns whether the given app or extension should be synced.
+bool ShouldSync(const Extension& extension, Profile* profile) {
+  if (extension.is_app())
+    return extensions::util::ShouldSyncApp(&extension, profile);
+  return extensions::util::ShouldSyncExtension(&extension, profile);
+}
+
 }  // namespace
 
 ExtensionSyncService::ExtensionSyncService(Profile* profile,
@@ -114,163 +128,119 @@
   return ExtensionSyncServiceFactory::GetForBrowserContext(context);
 }
 
-syncer::SyncChange ExtensionSyncService::PrepareToSyncUninstallExtension(
-    const extensions::Extension* extension, bool extensions_ready) {
+syncer::SyncData ExtensionSyncService::PrepareToSyncUninstallExtension(
+    const Extension& extension) {
   // Extract the data we need for sync now, but don't actually sync until we've
   // completed the uninstallation.
   // TODO(tim): If we get here and IsSyncing is false, this will cause
   // "back from the dead" style bugs, because sync will add-back the extension
   // that was uninstalled here when MergeDataAndStartSyncing is called.
   // See crbug.com/256795.
-  if (extensions::util::ShouldSyncApp(extension, profile_)) {
-    if (app_sync_bundle_.IsSyncing())
-      return app_sync_bundle_.CreateSyncChangeToDelete(extension);
-    else if (extensions_ready && !flare_.is_null())
-      flare_.Run(syncer::APPS);  // Tell sync to start ASAP.
-  } else if (extensions::sync_helper::IsSyncableExtension(extension)) {
-    if (extension_sync_bundle_.IsSyncing())
-      return extension_sync_bundle_.CreateSyncChangeToDelete(extension);
-    else if (extensions_ready && !flare_.is_null())
-      flare_.Run(syncer::EXTENSIONS);  // Tell sync to start ASAP.
+  syncer::ModelType type =
+      extension.is_app() ? syncer::APPS : syncer::EXTENSIONS;
+  const SyncBundle* bundle = GetSyncBundle(type);
+  if (ShouldSync(extension, profile_)) {
+    if (bundle->IsSyncing())
+      return CreateSyncData(extension).GetSyncData();
+    if (extension_service_->is_ready() && !flare_.is_null())
+      flare_.Run(type);  // Tell sync to start ASAP.
   }
 
-  return syncer::SyncChange();
+  return syncer::SyncData();
 }
 
 void ExtensionSyncService::ProcessSyncUninstallExtension(
     const std::string& extension_id,
-    const syncer::SyncChange& sync_change) {
-  if (app_sync_bundle_.HasExtensionId(extension_id) &&
-      sync_change.sync_data().GetDataType() == syncer::APPS) {
-    app_sync_bundle_.ProcessDeletion(extension_id, sync_change);
-  } else if (extension_sync_bundle_.HasExtensionId(extension_id) &&
-             sync_change.sync_data().GetDataType() == syncer::EXTENSIONS) {
-    extension_sync_bundle_.ProcessDeletion(extension_id, sync_change);
-  }
+    const syncer::SyncData& sync_data) {
+  SyncBundle* bundle = GetSyncBundle(sync_data.GetDataType());
+  if (bundle->HasExtensionId(extension_id))
+    bundle->PushSyncDeletion(extension_id, sync_data);
 }
 
-void ExtensionSyncService::SyncEnableExtension(
-    const extensions::Extension& extension) {
-
+void ExtensionSyncService::SyncEnableExtension(const Extension& extension) {
   // Syncing may not have started yet, so handle pending enables.
   if (extensions::util::ShouldSyncApp(&extension, profile_))
-    pending_app_enables_.OnExtensionEnabled(extension.id());
+    pending_app_enables_.Add(extension.id());
 
   if (extensions::util::ShouldSyncExtension(&extension, profile_))
-    pending_extension_enables_.OnExtensionEnabled(extension.id());
+    pending_extension_enables_.Add(extension.id());
 
   SyncExtensionChangeIfNeeded(extension);
 }
 
-void ExtensionSyncService::SyncDisableExtension(
-    const extensions::Extension& extension) {
-
+void ExtensionSyncService::SyncDisableExtension(const Extension& extension) {
   // Syncing may not have started yet, so handle pending enables.
   if (extensions::util::ShouldSyncApp(&extension, profile_))
-    pending_app_enables_.OnExtensionDisabled(extension.id());
+    pending_app_enables_.Remove(extension.id());
 
   if (extensions::util::ShouldSyncExtension(&extension, profile_))
-    pending_extension_enables_.OnExtensionDisabled(extension.id());
+    pending_extension_enables_.Remove(extension.id());
 
   SyncExtensionChangeIfNeeded(extension);
 }
 
+void ExtensionSyncService::SyncExtensionChangeIfNeeded(
+    const Extension& extension) {
+  if (!ShouldSync(extension, profile_))
+    return;
+
+  syncer::ModelType type =
+      extension.is_app() ? syncer::APPS : syncer::EXTENSIONS;
+  SyncBundle* bundle = GetSyncBundle(type);
+  if (bundle->IsSyncing())
+    bundle->PushSyncChangeIfNeeded(extension);
+  else if (extension_service_->is_ready() && !flare_.is_null())
+    flare_.Run(type);
+}
+
 syncer::SyncMergeResult ExtensionSyncService::MergeDataAndStartSyncing(
     syncer::ModelType type,
     const syncer::SyncDataList& initial_sync_data,
     scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
     scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
   CHECK(sync_processor.get());
-  CHECK(sync_error_factory.get());
+  LOG_IF(FATAL, type != syncer::EXTENSIONS && type != syncer::APPS)
+      << "Got " << type << " ModelType";
 
-  switch (type) {
-    case syncer::EXTENSIONS:
-      extension_sync_bundle_.SetupSync(sync_processor.release(),
-                                       sync_error_factory.release(),
-                                       initial_sync_data);
-      pending_extension_enables_.OnSyncStarted(extension_service_);
-      break;
+  SyncBundle* bundle = GetSyncBundle(type);
+  bool is_apps = (type == syncer::APPS);
+  PendingEnables* pending_enables =
+      is_apps ? &pending_app_enables_ : &pending_extension_enables_;
 
-    case syncer::APPS:
-      app_sync_bundle_.SetupSync(sync_processor.release(),
-                                 sync_error_factory.release(),
-                                 initial_sync_data);
-      pending_app_enables_.OnSyncStarted(extension_service_);
-      break;
-
-    default:
-      LOG(FATAL) << "Got " << type << " ModelType";
-  }
+  bundle->MergeDataAndStartSyncing(initial_sync_data, sync_processor.Pass());
+  pending_enables->OnSyncStarted(extension_service_);
 
   // Process local extensions.
   // TODO(yoz): Determine whether pending extensions should be considered too.
   //            See crbug.com/104399.
-  syncer::SyncDataList sync_data_list = GetAllSyncData(type);
-  syncer::SyncChangeList sync_change_list;
-  for (syncer::SyncDataList::const_iterator i = sync_data_list.begin();
-       i != sync_data_list.end();
-       ++i) {
-    switch (type) {
-        case syncer::EXTENSIONS:
-          sync_change_list.push_back(
-              extension_sync_bundle_.CreateSyncChange(*i));
-          break;
-        case syncer::APPS:
-          sync_change_list.push_back(app_sync_bundle_.CreateSyncChange(*i));
-          break;
-      default:
-        LOG(FATAL) << "Got " << type << " ModelType";
-    }
-  }
+  bundle->PushSyncDataList(GetAllSyncData(type));
 
-
-  if (type == syncer::EXTENSIONS) {
-    extension_sync_bundle_.ProcessSyncChangeList(sync_change_list);
-  } else if (type == syncer::APPS) {
-    app_sync_bundle_.ProcessSyncChangeList(sync_change_list);
-  }
+  if (is_apps)
+    extension_prefs_->app_sorting()->FixNTPOrdinalCollisions();
 
   return syncer::SyncMergeResult(type);
 }
 
 void ExtensionSyncService::StopSyncing(syncer::ModelType type) {
-  if (type == syncer::APPS) {
-    app_sync_bundle_.Reset();
-  } else if (type == syncer::EXTENSIONS) {
-    extension_sync_bundle_.Reset();
-  }
+  GetSyncBundle(type)->Reset();
 }
 
 syncer::SyncDataList ExtensionSyncService::GetAllSyncData(
     syncer::ModelType type) const {
-  if (type == syncer::EXTENSIONS)
-    return extension_sync_bundle_.GetAllSyncData();
-  if (type == syncer::APPS)
-    return app_sync_bundle_.GetAllSyncData();
-
-  // We should only get sync data for extensions and apps.
-  NOTREACHED();
-
-  return syncer::SyncDataList();
+  std::vector<ExtensionSyncData> data = GetSyncDataList(type);
+  syncer::SyncDataList result;
+  result.reserve(data.size());
+  for (const ExtensionSyncData& item : data)
+    result.push_back(item.GetSyncData());
+  return result;
 }
 
 syncer::SyncError ExtensionSyncService::ProcessSyncChanges(
     const tracked_objects::Location& from_here,
     const syncer::SyncChangeList& change_list) {
-  for (syncer::SyncChangeList::const_iterator i = change_list.begin();
-      i != change_list.end();
-      ++i) {
-    syncer::ModelType type = i->sync_data().GetDataType();
-    if (type == syncer::EXTENSIONS) {
-      scoped_ptr<ExtensionSyncData> extension_data(
-          ExtensionSyncData::CreateFromSyncChange(*i));
-      if (extension_data.get())
-        extension_sync_bundle_.ProcessSyncChange(*extension_data);
-    } else if (type == syncer::APPS) {
-      scoped_ptr<AppSyncData> app_data(AppSyncData::CreateFromSyncChange(*i));
-      if (app_data.get())
-        app_sync_bundle_.ProcessSyncChange(*app_data);
-    }
+  for (const syncer::SyncChange& sync_change : change_list) {
+    syncer::ModelType type = sync_change.sync_data().GetDataType();
+    GetSyncBundle(type)->ApplySyncChange(sync_change);
   }
 
   extension_prefs_->app_sorting()->FixNTPOrdinalCollisions();
@@ -278,76 +248,62 @@
   return syncer::SyncError();
 }
 
-ExtensionSyncData ExtensionSyncService::GetExtensionSyncData(
-    const Extension& extension) const {
+ExtensionSyncData ExtensionSyncService::CreateSyncData(
+    const extensions::Extension& extension) const {
+  bool enabled = extension_service_->IsExtensionEnabled(extension.id());
+  int disable_reasons = extension_prefs_->GetDisableReasons(extension.id());
+  bool incognito_enabled = extensions::util::IsIncognitoEnabled(extension.id(),
+                                                                profile_);
+  bool remote_install =
+      extension_prefs_->HasDisableReason(extension.id(),
+                                         Extension::DISABLE_REMOTE_INSTALL);
+  ExtensionSyncData::OptionalBoolean allowed_on_all_url =
+      GetAllowedOnAllUrlsOptionalBoolean(extension.id(), profile_);
+  if (extension.is_app()) {
+    return ExtensionSyncData(
+        extension, enabled, disable_reasons, incognito_enabled, remote_install,
+        allowed_on_all_url,
+        extension_prefs_->app_sorting()->GetAppLaunchOrdinal(extension.id()),
+        extension_prefs_->app_sorting()->GetPageOrdinal(extension.id()),
+        extensions::GetLaunchTypePrefValue(extension_prefs_, extension.id()));
+  }
   return ExtensionSyncData(
-      extension,
-      extension_service_->IsExtensionEnabled(extension.id()),
-      extension_prefs_->GetDisableReasons(extension.id()),
-      extensions::util::IsIncognitoEnabled(extension.id(), profile_),
-      extension_prefs_->HasDisableReason(extension.id(),
-                                         Extension::DISABLE_REMOTE_INSTALL),
-      GetAllowedOnAllUrlsOptionalBoolean(extension.id(), profile_));
+      extension, enabled, disable_reasons, incognito_enabled, remote_install,
+      allowed_on_all_url);
 }
 
-AppSyncData ExtensionSyncService::GetAppSyncData(
-    const Extension& extension) const {
-  return AppSyncData(
-      extension, extension_service_->IsExtensionEnabled(extension.id()),
-      extension_prefs_->GetDisableReasons(extension.id()),
-      extensions::util::IsIncognitoEnabled(extension.id(), profile_),
-      extension_prefs_->HasDisableReason(extension.id(),
-                                         Extension::DISABLE_REMOTE_INSTALL),
-      GetAllowedOnAllUrlsOptionalBoolean(extension.id(), profile_),
-      extension_prefs_->app_sorting()->GetAppLaunchOrdinal(extension.id()),
-      extension_prefs_->app_sorting()->GetPageOrdinal(extension.id()),
-      extensions::GetLaunchTypePrefValue(extension_prefs_, extension.id()));
-}
-
-std::vector<ExtensionSyncData>
-    ExtensionSyncService::GetExtensionSyncDataList() const {
-  ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
-  std::vector<ExtensionSyncData> extension_sync_list;
-  extension_sync_bundle_.GetExtensionSyncDataListHelper(
-      registry->enabled_extensions(), &extension_sync_list);
-  extension_sync_bundle_.GetExtensionSyncDataListHelper(
-      registry->disabled_extensions(), &extension_sync_list);
-  extension_sync_bundle_.GetExtensionSyncDataListHelper(
-      registry->terminated_extensions(), &extension_sync_list);
-
-  std::vector<ExtensionSyncData> pending_extensions =
-      extension_sync_bundle_.GetPendingData();
-  extension_sync_list.insert(extension_sync_list.begin(),
-                             pending_extensions.begin(),
-                             pending_extensions.end());
-
-  return extension_sync_list;
-}
-
-std::vector<AppSyncData> ExtensionSyncService::GetAppSyncDataList() const {
-  ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
-  std::vector<AppSyncData> app_sync_list;
-  app_sync_bundle_.GetAppSyncDataListHelper(
-      registry->enabled_extensions(), &app_sync_list);
-  app_sync_bundle_.GetAppSyncDataListHelper(
-      registry->disabled_extensions(), &app_sync_list);
-  app_sync_bundle_.GetAppSyncDataListHelper(
-      registry->terminated_extensions(), &app_sync_list);
-
-  std::vector<AppSyncData> pending_apps = app_sync_bundle_.GetPendingData();
-  app_sync_list.insert(app_sync_list.begin(),
-                       pending_apps.begin(),
-                       pending_apps.end());
-
-  return app_sync_list;
-}
-
-bool ExtensionSyncService::ProcessExtensionSyncData(
+bool ExtensionSyncService::ApplySyncData(
     const ExtensionSyncData& extension_sync_data) {
-  if (!ProcessExtensionSyncDataHelper(extension_sync_data,
-                                      syncer::EXTENSIONS)) {
-    extension_sync_bundle_.AddPendingExtension(extension_sync_data.id(),
-                                               extension_sync_data);
+  const std::string& id = extension_sync_data.id();
+
+  if (extension_sync_data.is_app()) {
+    if (extension_sync_data.app_launch_ordinal().IsValid() &&
+        extension_sync_data.page_ordinal().IsValid()) {
+      extension_prefs_->app_sorting()->SetAppLaunchOrdinal(
+          id,
+          extension_sync_data.app_launch_ordinal());
+      extension_prefs_->app_sorting()->SetPageOrdinal(
+          id,
+          extension_sync_data.page_ordinal());
+    }
+
+    // The corresponding validation of this value during AppSyncData population
+    // is in AppSyncData::PopulateAppSpecifics.
+    if (extension_sync_data.launch_type() >= extensions::LAUNCH_TYPE_FIRST &&
+        extension_sync_data.launch_type() < extensions::NUM_LAUNCH_TYPES) {
+      extensions::SetLaunchType(
+          profile_, id, extension_sync_data.launch_type());
+    }
+
+    if (!extension_sync_data.bookmark_app_url().empty())
+      ApplyBookmarkAppSyncData(extension_sync_data);
+  }
+
+  syncer::ModelType type = extension_sync_data.is_app() ? syncer::APPS
+                                                        : syncer::EXTENSIONS;
+
+  if (!ApplyExtensionSyncDataHelper(extension_sync_data, type)) {
+    GetSyncBundle(type)->AddPendingExtension(id, extension_sync_data);
     extension_service_->CheckForUpdatesSoon();
     return false;
   }
@@ -355,72 +311,39 @@
   return true;
 }
 
-bool ExtensionSyncService::ProcessAppSyncData(
-    const AppSyncData& app_sync_data) {
-  const std::string& id = app_sync_data.id();
+void ExtensionSyncService::ApplyBookmarkAppSyncData(
+    const extensions::ExtensionSyncData& extension_sync_data) {
+  DCHECK(extension_sync_data.is_app());
 
-  if (app_sync_data.app_launch_ordinal().IsValid() &&
-      app_sync_data.page_ordinal().IsValid()) {
-    extension_prefs_->app_sorting()->SetAppLaunchOrdinal(
-        id,
-        app_sync_data.app_launch_ordinal());
-    extension_prefs_->app_sorting()->SetPageOrdinal(
-        id,
-        app_sync_data.page_ordinal());
-  }
-
-  // The corresponding validation of this value during AppSyncData population
-  // is in AppSyncData::PopulateAppSpecifics.
-  if (app_sync_data.launch_type() >= extensions::LAUNCH_TYPE_FIRST &&
-      app_sync_data.launch_type() < extensions::NUM_LAUNCH_TYPES) {
-    extensions::SetLaunchType(profile_, id, app_sync_data.launch_type());
-  }
-
-  if (!app_sync_data.bookmark_app_url().empty())
-    ProcessBookmarkAppSyncData(app_sync_data);
-
-  if (!ProcessExtensionSyncDataHelper(app_sync_data.extension_sync_data(),
-                                      syncer::APPS)) {
-    app_sync_bundle_.AddPendingApp(id, app_sync_data);
-    extension_service_->CheckForUpdatesSoon();
-    return false;
-  }
-
-  return true;
-}
-
-void ExtensionSyncService::ProcessBookmarkAppSyncData(
-    const AppSyncData& app_sync_data) {
   // Process bookmark app sync if necessary.
-  GURL bookmark_app_url(app_sync_data.bookmark_app_url());
+  GURL bookmark_app_url(extension_sync_data.bookmark_app_url());
   if (!bookmark_app_url.is_valid() ||
-      app_sync_data.extension_sync_data().uninstalled()) {
+      extension_sync_data.uninstalled()) {
     return;
   }
 
-  const extensions::Extension* extension =
-      extension_service_->GetInstalledExtension(
-          app_sync_data.extension_sync_data().id());
+  const Extension* extension =
+      extension_service_->GetInstalledExtension(extension_sync_data.id());
 
   // Return if there are no bookmark app details that need updating.
-  if (extension && extension->non_localized_name() ==
-                       app_sync_data.extension_sync_data().name() &&
-      extension->description() == app_sync_data.bookmark_app_description()) {
+  if (extension &&
+      extension->non_localized_name() == extension_sync_data.name() &&
+      extension->description() ==
+          extension_sync_data.bookmark_app_description()) {
     return;
   }
 
   WebApplicationInfo web_app_info;
   web_app_info.app_url = bookmark_app_url;
-  web_app_info.title =
-      base::UTF8ToUTF16(app_sync_data.extension_sync_data().name());
+  web_app_info.title = base::UTF8ToUTF16(extension_sync_data.name());
   web_app_info.description =
-      base::UTF8ToUTF16(app_sync_data.bookmark_app_description());
-  if (!app_sync_data.bookmark_app_icon_color().empty()) {
+      base::UTF8ToUTF16(extension_sync_data.bookmark_app_description());
+  if (!extension_sync_data.bookmark_app_icon_color().empty()) {
     extensions::image_util::ParseCSSColorString(
-        app_sync_data.bookmark_app_icon_color(),
+        extension_sync_data.bookmark_app_icon_color(),
         &web_app_info.generated_icon_color);
   }
-  for (const auto& icon : app_sync_data.linked_icons()) {
+  for (const auto& icon : extension_sync_data.linked_icons()) {
     WebApplicationInfo::IconInfo icon_info;
     icon_info.url = icon.url;
     icon_info.width = icon.size;
@@ -432,7 +355,6 @@
   if (!extension) {
     CreateOrUpdateBookmarkApp(extension_service_, &web_app_info);
   } else {
-    app_sync_data.extension_sync_data().name();
     GetWebApplicationInfoFromApp(profile_,
                                  extension,
                                  base::Bind(&OnWebApplicationInfoLoaded,
@@ -442,8 +364,8 @@
 }
 
 void ExtensionSyncService::SyncOrderingChange(const std::string& extension_id) {
-  const extensions::Extension* ext = extension_service_->GetInstalledExtension(
-      extension_id);
+  const Extension* ext =
+      extension_service_->GetInstalledExtension(extension_id);
 
   if (ext)
     SyncExtensionChangeIfNeeded(*ext);
@@ -454,32 +376,62 @@
   flare_ = flare;
 }
 
-bool ExtensionSyncService::IsCorrectSyncType(const Extension& extension,
-                                         syncer::ModelType type) const {
-  if (type == syncer::EXTENSIONS &&
-      extensions::sync_helper::IsSyncableExtension(&extension)) {
-    return true;
-  }
-
-  if (type == syncer::APPS &&
-      extensions::sync_helper::IsSyncableApp(&extension)) {
-    return true;
-  }
-
-  return false;
-}
-
 bool ExtensionSyncService::IsPendingEnable(
     const std::string& extension_id) const {
   return pending_app_enables_.Contains(extension_id) ||
       pending_extension_enables_.Contains(extension_id);
 }
 
-bool ExtensionSyncService::ProcessExtensionSyncDataHelper(
+SyncBundle* ExtensionSyncService::GetSyncBundle(syncer::ModelType type) {
+  return const_cast<SyncBundle*>(
+      const_cast<const ExtensionSyncService&>(*this).GetSyncBundle(type));
+}
+
+const SyncBundle* ExtensionSyncService::GetSyncBundle(
+    syncer::ModelType type) const {
+  if (type == syncer::APPS)
+    return &app_sync_bundle_;
+  return &extension_sync_bundle_;
+}
+
+std::vector<ExtensionSyncData> ExtensionSyncService::GetSyncDataList(
+    syncer::ModelType type) const {
+  ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
+  std::vector<ExtensionSyncData> extension_sync_list;
+  FillSyncDataList(registry->enabled_extensions(), type, &extension_sync_list);
+  FillSyncDataList(registry->disabled_extensions(), type, &extension_sync_list);
+  FillSyncDataList(
+      registry->terminated_extensions(), type, &extension_sync_list);
+
+  std::vector<ExtensionSyncData> pending_extensions =
+      GetSyncBundle(type)->GetPendingData();
+  extension_sync_list.insert(extension_sync_list.begin(),
+                             pending_extensions.begin(),
+                             pending_extensions.end());
+
+  return extension_sync_list;
+}
+
+void ExtensionSyncService::FillSyncDataList(
+    const ExtensionSet& extensions,
+    syncer::ModelType type,
+    std::vector<ExtensionSyncData>* sync_data_list) const {
+  const SyncBundle* bundle = GetSyncBundle(type);
+  for (const scoped_refptr<const Extension>& extension : extensions) {
+    if (IsCorrectSyncType(*extension, type) &&
+        ShouldSync(*extension, profile_) &&
+        bundle->ShouldIncludeInLocalSyncDataList(*extension)) {
+      sync_data_list->push_back(CreateSyncData(*extension));
+    }
+  }
+}
+
+bool ExtensionSyncService::ApplyExtensionSyncDataHelper(
     const ExtensionSyncData& extension_sync_data,
     syncer::ModelType type) {
   const std::string& id = extension_sync_data.id();
-  const Extension* extension = extension_service_->GetInstalledExtension(id);
+  ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
+  const Extension* extension = registry->GetInstalledExtension(id);
 
   // TODO(bolms): we should really handle this better.  The particularly bad
   // case is where an app becomes an extension or vice versa, and we end up with
@@ -498,26 +450,28 @@
 
   // Extension from sync was uninstalled by the user as external extensions.
   // Honor user choice and skip installation/enabling.
-  if (extensions::ExtensionPrefs::Get(profile_)
-          ->IsExternalExtensionUninstalled(id)) {
+  if (ExtensionPrefs::Get(profile_)->IsExternalExtensionUninstalled(id)) {
     LOG(WARNING) << "Extension with id " << id
                  << " from sync was uninstalled as external extension";
     return true;
   }
 
+  int version_compare_result = extension ?
+      extension->version()->CompareTo(extension_sync_data.version()) : 0;
+
   // Set user settings.
   if (extension_sync_data.enabled()) {
+    DCHECK(!extension_sync_data.disable_reasons());
+
     // Only grant permissions if the sync data explicitly sets the disable
     // reasons to Extension::DISABLE_NONE (as opposed to the legacy (<M45) case
     // where they're not set at all), and if the version from sync matches our
     // local one. Otherwise we just enable it without granting permissions. If
     // any permissions are missing, CheckPermissionsIncrease will soon disable
     // it again.
-    DCHECK(!extension_sync_data.disable_reasons());
     bool grant_permissions =
         extension_sync_data.supports_disable_reasons() &&
-        extension &&
-        extension->version()->Equals(extension_sync_data.version());
+        extension && (version_compare_result == 0);
     if (grant_permissions)
       extension_service_->GrantPermissionsAndEnableExtension(extension);
     else
@@ -540,17 +494,14 @@
     // In the non-legacy case (>=M45), clear any existing disable reasons first.
     // Otherwise sync can't remove just some of them.
     if (extension_sync_data.supports_disable_reasons())
-      extensions::ExtensionPrefs::Get(profile_)->ClearDisableReasons(id);
+      ExtensionPrefs::Get(profile_)->ClearDisableReasons(id);
 
     extension_service_->DisableExtension(id, disable_reasons);
   }
 
-  // We need to cache some version information here because setting the
-  // incognito flag invalidates the |extension| pointer (it reloads the
-  // extension).
+  // We need to cache some information here because setting the incognito flag
+  // invalidates the |extension| pointer (it reloads the extension).
   bool extension_installed = (extension != NULL);
-  int version_compare_result = extension ?
-      extension->version()->CompareTo(extension_sync_data.version()) : 0;
 
   // If the target extension has already been installed ephemerally, it can
   // be promoted to a regular installed extension and downloading from the Web
@@ -601,18 +552,3 @@
 
   return true;
 }
-
-void ExtensionSyncService::SyncExtensionChangeIfNeeded(
-    const Extension& extension) {
-  if (extensions::util::ShouldSyncApp(&extension, profile_)) {
-    if (app_sync_bundle_.IsSyncing())
-      app_sync_bundle_.SyncChangeIfNeeded(extension);
-    else if (extension_service_->is_ready() && !flare_.is_null())
-      flare_.Run(syncer::APPS);
-  } else if (extensions::util::ShouldSyncExtension(&extension, profile_)) {
-    if (extension_sync_bundle_.IsSyncing())
-      extension_sync_bundle_.SyncChangeIfNeeded(extension);
-    else if (extension_service_->is_ready() && !flare_.is_null())
-      flare_.Run(syncer::EXTENSIONS);
-  }
-}