// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_SYNC_SERVICE_H_ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_SYNC_SERVICE_H_ #include <string> #include <vector> #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/scoped_observer.h" #include "base/version.h" #include "chrome/browser/extensions/sync_bundle.h" #include "components/keyed_service/core/keyed_service.h" #include "extensions/browser/extension_prefs_observer.h" #include "extensions/browser/extension_registry_observer.h" #include "sync/api/syncable_service.h" class ExtensionService; class Profile; namespace extensions { class Extension; class ExtensionSet; class ExtensionSyncData; } // namespace extensions // SyncableService implementation responsible for the APPS and EXTENSIONS data // types, i.e. "proper" apps/extensions (not themes). class ExtensionSyncService : public syncer::SyncableService, public KeyedService, public extensions::ExtensionRegistryObserver, public extensions::ExtensionPrefsObserver { public: explicit ExtensionSyncService(Profile* profile); ~ExtensionSyncService() override; // Convenience function to get the ExtensionSyncService for a BrowserContext. static ExtensionSyncService* Get(content::BrowserContext* context); // Notifies Sync (if needed) of a newly-installed extension or a change to // an existing extension. Call this when you change an extension setting that // is synced as part of ExtensionSyncData (e.g. incognito_enabled or // all_urls_enabled). void SyncExtensionChangeIfNeeded(const extensions::Extension& extension); // Returns whether the extension with the given |id| will be re-enabled once // it is updated to the given |version|. This happens when we get a Sync // update telling us to re-enable a newer version than what is currently // installed. bool HasPendingReenable(const std::string& id, const base::Version& version) const; // syncer::SyncableService implementation. syncer::SyncMergeResult MergeDataAndStartSyncing( syncer::ModelType type, const syncer::SyncDataList& initial_sync_data, scoped_ptr<syncer::SyncChangeProcessor> sync_processor, scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) override; void StopSyncing(syncer::ModelType type) override; syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override; syncer::SyncError ProcessSyncChanges( const tracked_objects::Location& from_here, const syncer::SyncChangeList& change_list) override; void SetSyncStartFlareForTesting( const syncer::SyncableService::StartSyncFlare& flare); // Special hack: There was a bug where themes incorrectly ended up in the // syncer::EXTENSIONS type. This is for cleaning up the data. crbug.com/558299 // DO NOT USE FOR ANYTHING ELSE! // TODO(treib,devlin): Remove this after M52 or so. void DeleteThemeDoNotUse(const extensions::Extension& theme); private: FRIEND_TEST_ALL_PREFIXES(TwoClientAppsSyncTest, UnexpectedLaunchType); FRIEND_TEST_ALL_PREFIXES(ExtensionDisabledGlobalErrorTest, HigherPermissionsFromSync); ExtensionService* extension_service() const; // extensions::ExtensionRegistryObserver: void OnExtensionInstalled(content::BrowserContext* browser_context, const extensions::Extension* extension, bool is_update) override; void OnExtensionUninstalled(content::BrowserContext* browser_context, const extensions::Extension* extension, extensions::UninstallReason reason) override; // extensions::ExtensionPrefsObserver: void OnExtensionStateChanged(const std::string& extension_id, bool state) override; void OnExtensionDisableReasonsChanged(const std::string& extension_id, int disabled_reasons) override; // Gets the SyncBundle for the given |type|. extensions::SyncBundle* GetSyncBundle(syncer::ModelType type); const extensions::SyncBundle* GetSyncBundle(syncer::ModelType type) const; // Creates the ExtensionSyncData for the given app/extension. extensions::ExtensionSyncData CreateSyncData( const extensions::Extension& extension) const; // Applies the given change coming in from the server to the local state. void ApplySyncData(const extensions::ExtensionSyncData& extension_sync_data); // Applies the bookmark app specific parts of |extension_sync_data|. void ApplyBookmarkAppSyncData( const extensions::ExtensionSyncData& extension_sync_data); // Collects the ExtensionSyncData for all installed apps or extensions. std::vector<extensions::ExtensionSyncData> GetLocalSyncDataList( syncer::ModelType type) const; // Helper for GetLocalSyncDataList. void FillSyncDataList( const extensions::ExtensionSet& extensions, syncer::ModelType type, std::vector<extensions::ExtensionSyncData>* sync_data_list) const; // Returns whether the given extension should be synced by this class. // Filters out unsyncable extensions as well as themes (which are handled by // ThemeSyncableService instead). bool ShouldSync(const extensions::Extension& extension) const; // The normal profile associated with this ExtensionSyncService. Profile* profile_; ScopedObserver<extensions::ExtensionRegistry, extensions::ExtensionRegistryObserver> registry_observer_; ScopedObserver<extensions::ExtensionPrefs, extensions::ExtensionPrefsObserver> prefs_observer_; // When this is set to true, any incoming updates (from the observers as well // as from explicit SyncExtensionChangeIfNeeded calls) are ignored. This is // set during ApplySyncData, so that ExtensionSyncService doesn't end up // notifying itself while applying sync changes. bool ignore_updates_; extensions::SyncBundle app_sync_bundle_; extensions::SyncBundle extension_sync_bundle_; // Map from extension id to pending update data. Used for two things: // - To send the new version back to the sync server while we're waiting for // an extension to update. // - For re-enables, to defer granting permissions until the version matches. struct PendingUpdate; std::map<std::string, PendingUpdate> pending_updates_; // Run()ning tells sync to try and start soon, because syncable changes // have started happening. It will cause sync to call us back // asynchronously via MergeDataAndStartSyncing as soon as possible. syncer::SyncableService::StartSyncFlare flare_; DISALLOW_COPY_AND_ASSIGN(ExtensionSyncService); }; #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_SYNC_SERVICE_H_