• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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.
4 
5 #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_UPDATER_H_
6 #define CHROME_BROWSER_EXTENSIONS_EXTENSION_UPDATER_H_
7 #pragma once
8 
9 #include <deque>
10 #include <map>
11 #include <set>
12 #include <string>
13 #include <vector>
14 
15 #include "base/gtest_prod_util.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/memory/scoped_temp_dir.h"
19 #include "base/memory/weak_ptr.h"
20 #include "base/task.h"
21 #include "base/time.h"
22 #include "base/timer.h"
23 #include "chrome/browser/extensions/extension_service.h"
24 #include "chrome/common/extensions/update_manifest.h"
25 #include "chrome/common/net/url_fetcher.h"
26 #include "googleurl/src/gurl.h"
27 
28 class Extension;
29 class ExtensionPrefs;
30 class ExtensionUpdaterTest;
31 class ExtensionUpdaterFileHandler;
32 class PrefService;
33 class Profile;
34 class SafeManifestParser;
35 
36 // To save on server resources we can request updates for multiple extensions
37 // in one manifest check. This class helps us keep track of the id's for a
38 // given fetch, building up the actual URL, and what if anything to include
39 // in the ping parameter.
40 class ManifestFetchData {
41  public:
42   static const int kNeverPinged = -1;
43 
44   // Each ping type is sent at most once per day.
45   enum PingType {
46     // Used for counting total installs of an extension/app/theme.
47     ROLLCALL,
48 
49     // Used for counting number of active users of an app, where "active" means
50     // the app was launched at least once since the last active ping.
51     ACTIVE
52   };
53 
54   struct PingData {
55     // The number of days it's been since our last rollcall or active ping,
56     // respectively. These are calculated based on the start of day from the
57     // server's perspective.
58     int rollcall_days;
59     int active_days;
60 
PingDataPingData61     PingData() : rollcall_days(0), active_days(0) {}
PingDataPingData62     PingData(int rollcall, int active)
63         : rollcall_days(rollcall), active_days(active) {}
64   };
65 
66   explicit ManifestFetchData(const GURL& update_url);
67   ~ManifestFetchData();
68 
69   // Returns true if this extension information was successfully added. If the
70   // return value is false it means the full_url would have become too long, and
71   // this ManifestFetchData object remains unchanged.
72   bool AddExtension(std::string id, std::string version,
73                     const PingData& ping_data,
74                     const std::string& update_url_data);
75 
base_url()76   const GURL& base_url() const { return base_url_; }
full_url()77   const GURL& full_url() const { return full_url_; }
extension_count()78   int extension_count() { return extension_ids_.size(); }
extension_ids()79   const std::set<std::string>& extension_ids() const { return extension_ids_; }
80 
81   // Returns true if the given id is included in this manifest fetch.
82   bool Includes(const std::string& extension_id) const;
83 
84   // Returns true if a ping parameter for |type| was added to full_url for this
85   // extension id.
86   bool DidPing(std::string extension_id, PingType type) const;
87 
88  private:
89   // The set of extension id's for this ManifestFetchData.
90   std::set<std::string> extension_ids_;
91 
92   // The set of ping data we actually sent.
93   std::map<std::string, PingData> pings_;
94 
95   // The base update url without any arguments added.
96   GURL base_url_;
97 
98   // The base update url plus arguments indicating the id, version, etc.
99   // information about each extension.
100   GURL full_url_;
101 
102   DISALLOW_COPY_AND_ASSIGN(ManifestFetchData);
103 };
104 
105 // A class for building a set of ManifestFetchData objects from
106 // extensions and pending extensions.
107 class ManifestFetchesBuilder {
108  public:
109   ManifestFetchesBuilder(ExtensionServiceInterface* service,
110                          ExtensionPrefs* prefs);
111   ~ManifestFetchesBuilder();
112 
113   void AddExtension(const Extension& extension);
114 
115   void AddPendingExtension(const std::string& id,
116                            const PendingExtensionInfo& info);
117 
118   // Adds all recorded stats taken so far to histogram counts.
119   void ReportStats() const;
120 
121   // Caller takes ownership of the returned ManifestFetchData
122   // objects.  Clears all recorded stats.
123   std::vector<ManifestFetchData*> GetFetches();
124 
125  private:
126   struct URLStats {
URLStatsURLStats127     URLStats()
128         : no_url_count(0),
129           google_url_count(0),
130           other_url_count(0),
131           extension_count(0),
132           theme_count(0),
133           app_count(0),
134           pending_count(0) {}
135 
136     int no_url_count, google_url_count, other_url_count;
137     int extension_count, theme_count, app_count, pending_count;
138   };
139 
140   void AddExtensionData(Extension::Location location,
141                         const std::string& id,
142                         const Version& version,
143                         Extension::Type extension_type,
144                         GURL update_url,
145                         const std::string& update_url_data);
146   ExtensionServiceInterface* const service_;
147   ExtensionPrefs* const prefs_;
148 
149   // List of data on fetches we're going to do. We limit the number of
150   // extensions grouped together in one batch to avoid running into the limits
151   // on the length of http GET requests, so there might be multiple
152   // ManifestFetchData* objects with the same base_url.
153   std::multimap<GURL, ManifestFetchData*> fetches_;
154 
155   URLStats url_stats_;
156 
157   DISALLOW_COPY_AND_ASSIGN(ManifestFetchesBuilder);
158 };
159 
160 // A class for doing auto-updates of installed Extensions. Used like this:
161 //
162 // ExtensionUpdater* updater = new ExtensionUpdater(my_extensions_service,
163 //                                                  pref_service,
164 //                                                  update_frequency_secs);
165 // updater->Start();
166 // ....
167 // updater->Stop();
168 class ExtensionUpdater : public URLFetcher::Delegate {
169  public:
170   // Holds a pointer to the passed |service|, using it for querying installed
171   // extensions and installing updated ones. The |frequency_seconds| parameter
172   // controls how often update checks are scheduled.
173   ExtensionUpdater(ExtensionServiceInterface* service,
174                    ExtensionPrefs* extension_prefs,
175                    PrefService* prefs,
176                    Profile* profile,
177                    int frequency_seconds);
178 
179   virtual ~ExtensionUpdater();
180 
181   // Starts the updater running.  Should be called at most once.
182   void Start();
183 
184   // Stops the updater running, cancelling any outstanding update manifest and
185   // crx downloads. Does not cancel any in-progress installs.
186   void Stop();
187 
188   // Posts a task to do an update check.  Does nothing if there is
189   // already a pending task that has not yet run.
190   void CheckSoon();
191 
192   // Starts an update check right now, instead of waiting for the next
193   // regularly scheduled check or a pending check from CheckSoon().
194   void CheckNow();
195 
196   // Set blacklist checks on or off.
set_blacklist_checks_enabled(bool enabled)197   void set_blacklist_checks_enabled(bool enabled) {
198     blacklist_checks_enabled_ = enabled;
199   }
200 
201   // Returns true iff CheckSoon() has been called but the update check
202   // hasn't been performed yet.  This is used mostly by tests; calling
203   // code should just call CheckSoon().
204   bool WillCheckSoon() const;
205 
206  private:
207   friend class ExtensionUpdaterTest;
208   friend class ExtensionUpdaterFileHandler;
209   friend class SafeManifestParser;
210 
211   // We need to keep track of some information associated with a url
212   // when doing a fetch.
213   struct ExtensionFetch {
214     ExtensionFetch();
215     ExtensionFetch(const std::string& i, const GURL& u,
216                    const std::string& h, const std::string& v);
217     ~ExtensionFetch();
218 
219     std::string id;
220     GURL url;
221     std::string package_hash;
222     std::string version;
223   };
224 
225   // These are needed for unit testing, to help identify the correct mock
226   // URLFetcher objects.
227   static const int kManifestFetcherId = 1;
228   static const int kExtensionFetcherId = 2;
229 
230   static const char* kBlacklistAppID;
231 
232   // Does common work from constructors.
233   void Init();
234 
235   // Computes when to schedule the first update check.
236   base::TimeDelta DetermineFirstCheckDelay();
237 
238   // URLFetcher::Delegate interface.
239   virtual void OnURLFetchComplete(const URLFetcher* source,
240                                   const GURL& url,
241                                   const net::URLRequestStatus& status,
242                                   int response_code,
243                                   const ResponseCookies& cookies,
244                                   const std::string& data);
245 
246   // These do the actual work when a URL fetch completes.
247   virtual void OnManifestFetchComplete(const GURL& url,
248                                        const net::URLRequestStatus& status,
249                                        int response_code,
250                                        const std::string& data);
251   virtual void OnCRXFetchComplete(const GURL& url,
252                                   const net::URLRequestStatus& status,
253                                   int response_code,
254                                   const std::string& data);
255 
256   // Called when a crx file has been written into a temp file, and is ready
257   // to be installed.
258   void OnCRXFileWritten(const std::string& id,
259                         const FilePath& path,
260                         const GURL& download_url);
261 
262   // Called when we encountered an error writing a crx file to a temp file.
263   void OnCRXFileWriteError(const std::string& id);
264 
265   // Verifies downloaded blacklist. Based on the blacklist, calls extension
266   // service to unload blacklisted extensions and update pref.
267   void ProcessBlacklist(const std::string& data);
268 
269   // Sets the timer to call TimerFired after roughly |target_delay| from now.
270   // To help spread load evenly on servers, this method adds some random
271   // jitter. It also saves the scheduled time so it can be reloaded on
272   // browser restart.
273   void ScheduleNextCheck(const base::TimeDelta& target_delay);
274 
275   // BaseTimer::ReceiverMethod callback.
276   void TimerFired();
277 
278   // Posted by CheckSoon().
279   void DoCheckSoon();
280 
281   // Begins an update check. Takes ownership of |fetch_data|.
282   void StartUpdateCheck(ManifestFetchData* fetch_data);
283 
284   // Begins (or queues up) download of an updated extension.
285   void FetchUpdatedExtension(const std::string& id, const GURL& url,
286     const std::string& hash, const std::string& version);
287 
288   // Once a manifest is parsed, this starts fetches of any relevant crx files.
289   // If |results| is null, it means something went wrong when parsing it.
290   void HandleManifestResults(const ManifestFetchData& fetch_data,
291                              const UpdateManifest::Results* results);
292 
293   // Determines the version of an existing extension.
294   // Returns true on success and false on failures.
295   bool GetExistingVersion(const std::string& id, std::string* version);
296 
297   // Given a list of potential updates, returns the indices of the ones that are
298   // applicable (are actually a new version, etc.) in |result|.
299   std::vector<int> DetermineUpdates(const ManifestFetchData& fetch_data,
300       const UpdateManifest::Results& possible_updates);
301 
302   // Send a notification that update checks are starting.
303   void NotifyStarted();
304 
305   // Send a notification that an update was found for extension_id that we'll
306   // attempt to download and install.
307   void NotifyUpdateFound(const std::string& extension_id);
308 
309   // Send a notification if we're finished updating.
310   void NotifyIfFinished();
311 
312   // Adds a set of ids to in_progress_ids_.
313   void AddToInProgress(const std::set<std::string>& ids);
314 
315   // Removes a set of ids from in_progress_ids_.
316   void RemoveFromInProgress(const std::set<std::string>& ids);
317 
318   // Whether Start() has been called but not Stop().
319   bool alive_;
320 
321   base::WeakPtrFactory<ExtensionUpdater> weak_ptr_factory_;
322 
323   // Outstanding url fetch requests for manifests and updates.
324   scoped_ptr<URLFetcher> manifest_fetcher_;
325   scoped_ptr<URLFetcher> extension_fetcher_;
326 
327   // Pending manifests and extensions to be fetched when the appropriate fetcher
328   // is available.
329   std::deque<ManifestFetchData*> manifests_pending_;
330   std::deque<ExtensionFetch> extensions_pending_;
331 
332   // The manifest currently being fetched (if any).
333   scoped_ptr<ManifestFetchData> current_manifest_fetch_;
334 
335   // The extension currently being fetched (if any).
336   ExtensionFetch current_extension_fetch_;
337 
338   // Pointer back to the service that owns this ExtensionUpdater.
339   ExtensionServiceInterface* service_;
340 
341   base::OneShotTimer<ExtensionUpdater> timer_;
342   int frequency_seconds_;
343 
344   ScopedRunnableMethodFactory<ExtensionUpdater> method_factory_;
345 
346   bool will_check_soon_;
347 
348   ExtensionPrefs* extension_prefs_;
349   PrefService* prefs_;
350   Profile* profile_;
351 
352   scoped_refptr<ExtensionUpdaterFileHandler> file_handler_;
353   bool blacklist_checks_enabled_;
354 
355   // The ids of extensions that have in-progress update checks.
356   std::set<std::string> in_progress_ids_;
357 
358   FRIEND_TEST(ExtensionUpdaterTest, TestStartUpdateCheckMemory);
359   FRIEND_TEST(ExtensionUpdaterTest, TestAfterStopBehavior);
360 
361   DISALLOW_COPY_AND_ASSIGN(ExtensionUpdater);
362 };
363 
364 #endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_UPDATER_H_
365