| // Copyright (c) 2011 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_UPDATER_H_ |
| #define CHROME_BROWSER_EXTENSIONS_EXTENSION_UPDATER_H_ |
| #pragma once |
| |
| #include <deque> |
| #include <map> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include "base/gtest_prod_util.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/memory/scoped_temp_dir.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/task.h" |
| #include "base/time.h" |
| #include "base/timer.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/common/extensions/update_manifest.h" |
| #include "chrome/common/net/url_fetcher.h" |
| #include "googleurl/src/gurl.h" |
| |
| class Extension; |
| class ExtensionPrefs; |
| class ExtensionUpdaterTest; |
| class ExtensionUpdaterFileHandler; |
| class PrefService; |
| class Profile; |
| class SafeManifestParser; |
| |
| // To save on server resources we can request updates for multiple extensions |
| // in one manifest check. This class helps us keep track of the id's for a |
| // given fetch, building up the actual URL, and what if anything to include |
| // in the ping parameter. |
| class ManifestFetchData { |
| public: |
| static const int kNeverPinged = -1; |
| |
| // Each ping type is sent at most once per day. |
| enum PingType { |
| // Used for counting total installs of an extension/app/theme. |
| ROLLCALL, |
| |
| // Used for counting number of active users of an app, where "active" means |
| // the app was launched at least once since the last active ping. |
| ACTIVE |
| }; |
| |
| struct PingData { |
| // The number of days it's been since our last rollcall or active ping, |
| // respectively. These are calculated based on the start of day from the |
| // server's perspective. |
| int rollcall_days; |
| int active_days; |
| |
| PingData() : rollcall_days(0), active_days(0) {} |
| PingData(int rollcall, int active) |
| : rollcall_days(rollcall), active_days(active) {} |
| }; |
| |
| explicit ManifestFetchData(const GURL& update_url); |
| ~ManifestFetchData(); |
| |
| // Returns true if this extension information was successfully added. If the |
| // return value is false it means the full_url would have become too long, and |
| // this ManifestFetchData object remains unchanged. |
| bool AddExtension(std::string id, std::string version, |
| const PingData& ping_data, |
| const std::string& update_url_data); |
| |
| const GURL& base_url() const { return base_url_; } |
| const GURL& full_url() const { return full_url_; } |
| int extension_count() { return extension_ids_.size(); } |
| const std::set<std::string>& extension_ids() const { return extension_ids_; } |
| |
| // Returns true if the given id is included in this manifest fetch. |
| bool Includes(const std::string& extension_id) const; |
| |
| // Returns true if a ping parameter for |type| was added to full_url for this |
| // extension id. |
| bool DidPing(std::string extension_id, PingType type) const; |
| |
| private: |
| // The set of extension id's for this ManifestFetchData. |
| std::set<std::string> extension_ids_; |
| |
| // The set of ping data we actually sent. |
| std::map<std::string, PingData> pings_; |
| |
| // The base update url without any arguments added. |
| GURL base_url_; |
| |
| // The base update url plus arguments indicating the id, version, etc. |
| // information about each extension. |
| GURL full_url_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ManifestFetchData); |
| }; |
| |
| // A class for building a set of ManifestFetchData objects from |
| // extensions and pending extensions. |
| class ManifestFetchesBuilder { |
| public: |
| ManifestFetchesBuilder(ExtensionServiceInterface* service, |
| ExtensionPrefs* prefs); |
| ~ManifestFetchesBuilder(); |
| |
| void AddExtension(const Extension& extension); |
| |
| void AddPendingExtension(const std::string& id, |
| const PendingExtensionInfo& info); |
| |
| // Adds all recorded stats taken so far to histogram counts. |
| void ReportStats() const; |
| |
| // Caller takes ownership of the returned ManifestFetchData |
| // objects. Clears all recorded stats. |
| std::vector<ManifestFetchData*> GetFetches(); |
| |
| private: |
| struct URLStats { |
| URLStats() |
| : no_url_count(0), |
| google_url_count(0), |
| other_url_count(0), |
| extension_count(0), |
| theme_count(0), |
| app_count(0), |
| pending_count(0) {} |
| |
| int no_url_count, google_url_count, other_url_count; |
| int extension_count, theme_count, app_count, pending_count; |
| }; |
| |
| void AddExtensionData(Extension::Location location, |
| const std::string& id, |
| const Version& version, |
| Extension::Type extension_type, |
| GURL update_url, |
| const std::string& update_url_data); |
| ExtensionServiceInterface* const service_; |
| ExtensionPrefs* const prefs_; |
| |
| // List of data on fetches we're going to do. We limit the number of |
| // extensions grouped together in one batch to avoid running into the limits |
| // on the length of http GET requests, so there might be multiple |
| // ManifestFetchData* objects with the same base_url. |
| std::multimap<GURL, ManifestFetchData*> fetches_; |
| |
| URLStats url_stats_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ManifestFetchesBuilder); |
| }; |
| |
| // A class for doing auto-updates of installed Extensions. Used like this: |
| // |
| // ExtensionUpdater* updater = new ExtensionUpdater(my_extensions_service, |
| // pref_service, |
| // update_frequency_secs); |
| // updater->Start(); |
| // .... |
| // updater->Stop(); |
| class ExtensionUpdater : public URLFetcher::Delegate { |
| public: |
| // Holds a pointer to the passed |service|, using it for querying installed |
| // extensions and installing updated ones. The |frequency_seconds| parameter |
| // controls how often update checks are scheduled. |
| ExtensionUpdater(ExtensionServiceInterface* service, |
| ExtensionPrefs* extension_prefs, |
| PrefService* prefs, |
| Profile* profile, |
| int frequency_seconds); |
| |
| virtual ~ExtensionUpdater(); |
| |
| // Starts the updater running. Should be called at most once. |
| void Start(); |
| |
| // Stops the updater running, cancelling any outstanding update manifest and |
| // crx downloads. Does not cancel any in-progress installs. |
| void Stop(); |
| |
| // Posts a task to do an update check. Does nothing if there is |
| // already a pending task that has not yet run. |
| void CheckSoon(); |
| |
| // Starts an update check right now, instead of waiting for the next |
| // regularly scheduled check or a pending check from CheckSoon(). |
| void CheckNow(); |
| |
| // Set blacklist checks on or off. |
| void set_blacklist_checks_enabled(bool enabled) { |
| blacklist_checks_enabled_ = enabled; |
| } |
| |
| // Returns true iff CheckSoon() has been called but the update check |
| // hasn't been performed yet. This is used mostly by tests; calling |
| // code should just call CheckSoon(). |
| bool WillCheckSoon() const; |
| |
| private: |
| friend class ExtensionUpdaterTest; |
| friend class ExtensionUpdaterFileHandler; |
| friend class SafeManifestParser; |
| |
| // We need to keep track of some information associated with a url |
| // when doing a fetch. |
| struct ExtensionFetch { |
| ExtensionFetch(); |
| ExtensionFetch(const std::string& i, const GURL& u, |
| const std::string& h, const std::string& v); |
| ~ExtensionFetch(); |
| |
| std::string id; |
| GURL url; |
| std::string package_hash; |
| std::string version; |
| }; |
| |
| // These are needed for unit testing, to help identify the correct mock |
| // URLFetcher objects. |
| static const int kManifestFetcherId = 1; |
| static const int kExtensionFetcherId = 2; |
| |
| static const char* kBlacklistAppID; |
| |
| // Does common work from constructors. |
| void Init(); |
| |
| // Computes when to schedule the first update check. |
| base::TimeDelta DetermineFirstCheckDelay(); |
| |
| // URLFetcher::Delegate interface. |
| virtual void OnURLFetchComplete(const URLFetcher* source, |
| const GURL& url, |
| const net::URLRequestStatus& status, |
| int response_code, |
| const ResponseCookies& cookies, |
| const std::string& data); |
| |
| // These do the actual work when a URL fetch completes. |
| virtual void OnManifestFetchComplete(const GURL& url, |
| const net::URLRequestStatus& status, |
| int response_code, |
| const std::string& data); |
| virtual void OnCRXFetchComplete(const GURL& url, |
| const net::URLRequestStatus& status, |
| int response_code, |
| const std::string& data); |
| |
| // Called when a crx file has been written into a temp file, and is ready |
| // to be installed. |
| void OnCRXFileWritten(const std::string& id, |
| const FilePath& path, |
| const GURL& download_url); |
| |
| // Called when we encountered an error writing a crx file to a temp file. |
| void OnCRXFileWriteError(const std::string& id); |
| |
| // Verifies downloaded blacklist. Based on the blacklist, calls extension |
| // service to unload blacklisted extensions and update pref. |
| void ProcessBlacklist(const std::string& data); |
| |
| // Sets the timer to call TimerFired after roughly |target_delay| from now. |
| // To help spread load evenly on servers, this method adds some random |
| // jitter. It also saves the scheduled time so it can be reloaded on |
| // browser restart. |
| void ScheduleNextCheck(const base::TimeDelta& target_delay); |
| |
| // BaseTimer::ReceiverMethod callback. |
| void TimerFired(); |
| |
| // Posted by CheckSoon(). |
| void DoCheckSoon(); |
| |
| // Begins an update check. Takes ownership of |fetch_data|. |
| void StartUpdateCheck(ManifestFetchData* fetch_data); |
| |
| // Begins (or queues up) download of an updated extension. |
| void FetchUpdatedExtension(const std::string& id, const GURL& url, |
| const std::string& hash, const std::string& version); |
| |
| // Once a manifest is parsed, this starts fetches of any relevant crx files. |
| // If |results| is null, it means something went wrong when parsing it. |
| void HandleManifestResults(const ManifestFetchData& fetch_data, |
| const UpdateManifest::Results* results); |
| |
| // Determines the version of an existing extension. |
| // Returns true on success and false on failures. |
| bool GetExistingVersion(const std::string& id, std::string* version); |
| |
| // Given a list of potential updates, returns the indices of the ones that are |
| // applicable (are actually a new version, etc.) in |result|. |
| std::vector<int> DetermineUpdates(const ManifestFetchData& fetch_data, |
| const UpdateManifest::Results& possible_updates); |
| |
| // Send a notification that update checks are starting. |
| void NotifyStarted(); |
| |
| // Send a notification that an update was found for extension_id that we'll |
| // attempt to download and install. |
| void NotifyUpdateFound(const std::string& extension_id); |
| |
| // Send a notification if we're finished updating. |
| void NotifyIfFinished(); |
| |
| // Adds a set of ids to in_progress_ids_. |
| void AddToInProgress(const std::set<std::string>& ids); |
| |
| // Removes a set of ids from in_progress_ids_. |
| void RemoveFromInProgress(const std::set<std::string>& ids); |
| |
| // Whether Start() has been called but not Stop(). |
| bool alive_; |
| |
| base::WeakPtrFactory<ExtensionUpdater> weak_ptr_factory_; |
| |
| // Outstanding url fetch requests for manifests and updates. |
| scoped_ptr<URLFetcher> manifest_fetcher_; |
| scoped_ptr<URLFetcher> extension_fetcher_; |
| |
| // Pending manifests and extensions to be fetched when the appropriate fetcher |
| // is available. |
| std::deque<ManifestFetchData*> manifests_pending_; |
| std::deque<ExtensionFetch> extensions_pending_; |
| |
| // The manifest currently being fetched (if any). |
| scoped_ptr<ManifestFetchData> current_manifest_fetch_; |
| |
| // The extension currently being fetched (if any). |
| ExtensionFetch current_extension_fetch_; |
| |
| // Pointer back to the service that owns this ExtensionUpdater. |
| ExtensionServiceInterface* service_; |
| |
| base::OneShotTimer<ExtensionUpdater> timer_; |
| int frequency_seconds_; |
| |
| ScopedRunnableMethodFactory<ExtensionUpdater> method_factory_; |
| |
| bool will_check_soon_; |
| |
| ExtensionPrefs* extension_prefs_; |
| PrefService* prefs_; |
| Profile* profile_; |
| |
| scoped_refptr<ExtensionUpdaterFileHandler> file_handler_; |
| bool blacklist_checks_enabled_; |
| |
| // The ids of extensions that have in-progress update checks. |
| std::set<std::string> in_progress_ids_; |
| |
| FRIEND_TEST(ExtensionUpdaterTest, TestStartUpdateCheckMemory); |
| FRIEND_TEST(ExtensionUpdaterTest, TestAfterStopBehavior); |
| |
| DISALLOW_COPY_AND_ASSIGN(ExtensionUpdater); |
| }; |
| |
| #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_UPDATER_H_ |