blob: f3eee77c204791f46acb13e813f98b5b3b1f8a6b [file] [log] [blame]
[email protected]f1050432012-02-15 01:35:461// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]e8f96ff2011-08-03 05:07:332// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/component_updater/component_updater_service.h"
6
7#include <algorithm>
[email protected]ccb4feef2013-02-14 06:16:478#include <set>
[email protected]e8f96ff2011-08-03 05:07:339#include <vector>
10
11#include "base/at_exit.h"
[email protected]44da56e2011-11-21 19:59:1412#include "base/bind.h"
[email protected]e8f96ff2011-08-03 05:07:3313#include "base/file_util.h"
[email protected]57999812013-02-24 05:40:5214#include "base/files/file_path.h"
[email protected]e8f96ff2011-08-03 05:07:3315#include "base/logging.h"
[email protected]7226b33c2011-08-18 08:44:2216#include "base/memory/scoped_ptr.h"
[email protected]e8f96ff2011-08-03 05:07:3317#include "base/stl_util.h"
[email protected]3ea1b182013-02-08 22:38:4118#include "base/strings/string_number_conversions.h"
[email protected]4570a252013-03-31 00:35:4319#include "base/strings/string_piece.h"
[email protected]e7463412013-06-10 22:53:4620#include "base/strings/string_util.h"
21#include "base/strings/stringprintf.h"
[email protected]e8f96ff2011-08-03 05:07:3322#include "base/timer.h"
23#include "chrome/browser/browser_process.h"
24#include "chrome/browser/component_updater/component_unpacker.h"
25#include "chrome/common/chrome_notification_types.h"
26#include "chrome/common/chrome_utility_messages.h"
27#include "chrome/common/chrome_version_info.h"
28#include "chrome/common/extensions/extension.h"
[email protected]b7b63872013-01-03 02:41:1929#include "content/public/browser/browser_thread.h"
[email protected]ad50def52011-10-19 23:17:0730#include "content/public/browser/notification_service.h"
[email protected]c4f883a2012-02-03 17:02:0731#include "content/public/browser/utility_process_host.h"
32#include "content/public/browser/utility_process_host_client.h"
[email protected]e8f96ff2011-08-03 05:07:3333#include "googleurl/src/gurl.h"
34#include "net/base/escape.h"
35#include "net/base/load_flags.h"
[email protected]1dd4060e2013-03-13 13:15:1336#include "net/base/net_errors.h"
[email protected]3dc1bc42012-06-19 08:20:5337#include "net/url_request/url_fetcher.h"
[email protected]15fb2aa2012-05-22 22:52:5938#include "net/url_request/url_fetcher_delegate.h"
[email protected]9d8ea302012-09-25 15:04:2239#include "net/url_request/url_request_status.h"
[email protected]e8f96ff2011-08-03 05:07:3340
[email protected]631bb742011-11-02 11:29:3941using content::BrowserThread;
[email protected]c4f883a2012-02-03 17:02:0742using content::UtilityProcessHost;
43using content::UtilityProcessHostClient;
[email protected]1c321ee52012-05-21 03:02:3444using extensions::Extension;
[email protected]631bb742011-11-02 11:29:3945
[email protected]44da56e2011-11-21 19:59:1446// The component updater is designed to live until process shutdown, so
47// base::Bind() calls are not refcounted.
48
[email protected]e8f96ff2011-08-03 05:07:3349namespace {
[email protected]dc06f0b2013-01-23 20:03:1650// Manifest sources, from most important to least important.
51const CrxComponent::UrlSource kManifestSources[] = {
52 CrxComponent::BANDAID,
53 CrxComponent::CWS_PUBLIC,
54 CrxComponent::CWS_SANDBOX
55};
56
[email protected]e8f96ff2011-08-03 05:07:3357// Extends an omaha compatible update check url |query| string. Does
58// not mutate the string if it would be longer than |limit| chars.
[email protected]4c37b452011-12-21 01:33:5259bool AddQueryString(const std::string& id,
60 const std::string& version,
61 size_t limit,
62 std::string* query) {
[email protected]e8f96ff2011-08-03 05:07:3363 std::string additional =
64 base::StringPrintf("id=%s&v=%s&uc", id.c_str(), version.c_str());
[email protected]4a19be92011-09-22 14:25:0265 additional = "x=" + net::EscapeQueryParamValue(additional, true);
[email protected]e8f96ff2011-08-03 05:07:3366 if ((additional.size() + query->size() + 1) > limit)
67 return false;
[email protected]926d36332011-10-05 01:06:2568 if (!query->empty())
69 query->append(1, '&');
[email protected]e8f96ff2011-08-03 05:07:3370 query->append(additional);
71 return true;
72}
73
[email protected]926d36332011-10-05 01:06:2574// Create the final omaha compatible query. The |extra| is optional and can
75// be null. It should contain top level (non-escaped) parameters.
76std::string MakeFinalQuery(const std::string& host,
77 const std::string& query,
78 const char* extra) {
79 std::string request(host);
80 request.append(1, '?');
81 if (extra) {
82 request.append(extra);
83 request.append(1, '&');
84 }
85 request.append(query);
86 return request;
87}
88
[email protected]e8f96ff2011-08-03 05:07:3389// Produces an extension-like friendly |id|. This might be removed in the
90// future if we roll our on packing tools.
91static std::string HexStringToID(const std::string& hexstr) {
92 std::string id;
93 for (size_t i = 0; i < hexstr.size(); ++i) {
94 int val;
[email protected]eb72b272011-12-19 16:10:5595 if (base::HexStringToInt(base::StringPiece(hexstr.begin() + i,
96 hexstr.begin() + i + 1),
97 &val)) {
[email protected]e8f96ff2011-08-03 05:07:3398 id.append(1, val + 'a');
[email protected]eb72b272011-12-19 16:10:5599 } else {
[email protected]e8f96ff2011-08-03 05:07:33100 id.append(1, 'a');
[email protected]eb72b272011-12-19 16:10:55101 }
[email protected]e8f96ff2011-08-03 05:07:33102 }
103 DCHECK(Extension::IdIsValid(id));
104 return id;
105}
106
[email protected]360b8bb2011-09-01 21:48:06107// Returns given a crx id it returns a small number, less than 100, that has a
108// decent chance of being unique among the registered components. It also has
109// the nice property that can be trivially computed by hand.
110static int CrxIdtoUMAId(const std::string& id) {
[email protected]a1f8c162012-09-27 22:32:21111 CHECK_GT(id.size(), 2U);
[email protected]360b8bb2011-09-01 21:48:06112 return id[0] + id[1] + id[2] - ('a' * 3);
113}
114
[email protected]e8f96ff2011-08-03 05:07:33115// Helper to do version check for components.
116bool IsVersionNewer(const Version& current, const std::string& proposed) {
117 Version proposed_ver(proposed);
118 if (!proposed_ver.IsValid())
119 return false;
120 return (current.CompareTo(proposed_ver) < 0);
121}
122
123// Helper template class that allows our main class to have separate
[email protected]f1050432012-02-15 01:35:46124// OnURLFetchComplete() callbacks for different types of url requests
[email protected]e8f96ff2011-08-03 05:07:33125// they are differentiated by the |Ctx| type.
126template <typename Del, typename Ctx>
[email protected]15fb2aa2012-05-22 22:52:59127class DelegateWithContext : public net::URLFetcherDelegate {
[email protected]e8f96ff2011-08-03 05:07:33128 public:
129 DelegateWithContext(Del* delegate, Ctx* context)
130 : delegate_(delegate), context_(context) {}
131
[email protected]10c2d692012-05-11 05:32:23132 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
[email protected]e8f96ff2011-08-03 05:07:33133 delegate_->OnURLFetchComplete(source, context_);
134 delete this;
135 }
136
137 private:
138 ~DelegateWithContext() {}
139
140 Del* delegate_;
141 Ctx* context_;
142};
143// This function creates the right DelegateWithContext using template inference.
144template <typename Del, typename Ctx>
[email protected]15fb2aa2012-05-22 22:52:59145net::URLFetcherDelegate* MakeContextDelegate(Del* delegate, Ctx* context) {
[email protected]e8f96ff2011-08-03 05:07:33146 return new DelegateWithContext<Del, Ctx>(delegate, context);
147}
148
149// Helper to start a url request using |fetcher| with the common flags.
[email protected]d3ec669b2012-05-23 07:12:14150void StartFetch(net::URLFetcher* fetcher,
[email protected]e8f96ff2011-08-03 05:07:33151 net::URLRequestContextGetter* context_getter,
152 bool save_to_file) {
[email protected]7cc6e5632011-10-25 17:56:12153 fetcher->SetRequestContext(context_getter);
154 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
155 net::LOAD_DO_NOT_SAVE_COOKIES |
156 net::LOAD_DISABLE_CACHE);
[email protected]e8f96ff2011-08-03 05:07:33157 // TODO(cpu): Define our retry and backoff policy.
[email protected]7cc6e5632011-10-25 17:56:12158 fetcher->SetAutomaticallyRetryOn5xx(false);
[email protected]e8f96ff2011-08-03 05:07:33159 if (save_to_file) {
160 fetcher->SaveResponseToTemporaryFile(
161 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
162 }
163 fetcher->Start();
164}
165
166// Returs true if the url request of |fetcher| was succesful.
[email protected]10c2d692012-05-11 05:32:23167bool FetchSuccess(const net::URLFetcher& fetcher) {
[email protected]7cc6e5632011-10-25 17:56:12168 return (fetcher.GetStatus().status() == net::URLRequestStatus::SUCCESS) &&
169 (fetcher.GetResponseCode() == 200);
[email protected]e8f96ff2011-08-03 05:07:33170}
171
172// This is the one and only per-item state structure. Designed to be hosted
173// in a std::vector or a std::list. The two main members are |component|
174// which is supplied by the the component updater client and |status| which
175// is modified as the item is processed by the update pipeline. The expected
176// transition graph is:
177// error error error
178// +--kNoUpdate<------<-------+------<------+------<------+
179// | | | |
180// V yes | | |
181// kNew --->kChecking-->[update?]----->kCanUpdate-->kDownloading-->kUpdating
182// ^ | |
183// | |no |
184// |--kUpToDate<---+ |
185// | success |
186// +--kUpdated<-------------------------------------------+
187//
188struct CrxUpdateItem {
189 enum Status {
190 kNew,
191 kChecking,
192 kCanUpdate,
193 kDownloading,
194 kUpdating,
195 kUpdated,
196 kUpToDate,
197 kNoUpdate,
198 kLastStatus
199 };
200
201 Status status;
202 GURL crx_url;
203 std::string id;
204 base::Time last_check;
205 CrxComponent component;
[email protected]07f93af12011-08-17 20:57:22206 Version next_version;
[email protected]e8f96ff2011-08-03 05:07:33207
208 CrxUpdateItem() : status(kNew) {}
209
210 // Function object used to find a specific component.
211 class FindById {
212 public:
213 explicit FindById(const std::string& id) : id_(id) {}
214
215 bool operator() (CrxUpdateItem* item) const {
216 return (item->id == id_);
217 }
218 private:
219 const std::string& id_;
220 };
221};
222
223} // namespace.
224
225typedef ComponentUpdateService::Configurator Config;
226
[email protected]dc06f0b2013-01-23 20:03:16227CrxComponent::CrxComponent()
228 : installer(NULL),
229 source(BANDAID) {
230}
231
232CrxComponent::~CrxComponent() {
233}
[email protected]e8f96ff2011-08-03 05:07:33234
235//////////////////////////////////////////////////////////////////////////////
236// The one and only implementation of the ComponentUpdateService interface. In
237// charge of running the show. The main method is ProcessPendingItems() which
[email protected]50b01392012-09-01 03:33:13238// is called periodically to do the upgrades/installs or the update checks.
[email protected]e8f96ff2011-08-03 05:07:33239// An important consideration here is to be as "low impact" as we can to the
240// rest of the browser, so even if we have many components registered and
[email protected]f1050432012-02-15 01:35:46241// eligible for update, we only do one thing at a time with pauses in between
[email protected]e8f96ff2011-08-03 05:07:33242// the tasks. Also when we do network requests there is only one |url_fetcher_|
243// in flight at at a time.
244// There are no locks in this code, the main structure |work_items_| is mutated
245// only from the UI thread. The unpack and installation is done in the file
246// thread and the network requests are done in the IO thread and in the file
247// thread.
248class CrxUpdateService : public ComponentUpdateService {
249 public:
250 explicit CrxUpdateService(ComponentUpdateService::Configurator* config);
251
252 virtual ~CrxUpdateService();
253
254 // Overrides for ComponentUpdateService.
255 virtual Status Start() OVERRIDE;
256 virtual Status Stop() OVERRIDE;
257 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE;
[email protected]ccb4feef2013-02-14 06:16:47258 virtual Status CheckForUpdateSoon(const CrxComponent& component) OVERRIDE;
[email protected]e8f96ff2011-08-03 05:07:33259
260 // The only purpose of this class is to forward the
[email protected]c4f883a2012-02-03 17:02:07261 // UtilityProcessHostClient callbacks so CrxUpdateService does
[email protected]e8f96ff2011-08-03 05:07:33262 // not have to derive from it because that is refcounted.
[email protected]c4f883a2012-02-03 17:02:07263 class ManifestParserBridge : public UtilityProcessHostClient {
[email protected]e8f96ff2011-08-03 05:07:33264 public:
265 explicit ManifestParserBridge(CrxUpdateService* service)
266 : service_(service) {}
267
268 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
269 bool handled = true;
270 IPC_BEGIN_MESSAGE_MAP(ManifestParserBridge, message)
[email protected]2ccf45c2011-08-19 23:35:50271 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseUpdateManifest_Succeeded,
[email protected]e8f96ff2011-08-03 05:07:33272 OnParseUpdateManifestSucceeded)
[email protected]2ccf45c2011-08-19 23:35:50273 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseUpdateManifest_Failed,
[email protected]e8f96ff2011-08-03 05:07:33274 OnParseUpdateManifestFailed)
275 IPC_MESSAGE_UNHANDLED(handled = false)
276 IPC_END_MESSAGE_MAP()
277 return handled;
278 }
279
280 private:
[email protected]a3988cc2012-04-27 05:07:18281 virtual ~ManifestParserBridge() {}
282
[email protected]f1050432012-02-15 01:35:46283 // Omaha update response XML was successfully parsed.
[email protected]e8f96ff2011-08-03 05:07:33284 void OnParseUpdateManifestSucceeded(const UpdateManifest::Results& r) {
285 service_->OnParseUpdateManifestSucceeded(r);
286 }
287 // Omaha update response XML could not be parsed.
288 void OnParseUpdateManifestFailed(const std::string& e) {
289 service_->OnParseUpdateManifestFailed(e);
290 }
291
292 CrxUpdateService* service_;
293 DISALLOW_COPY_AND_ASSIGN(ManifestParserBridge);
294 };
295
296 // Context for a update check url request. See DelegateWithContext above.
297 struct UpdateContext {
298 base::Time start;
299 UpdateContext() : start(base::Time::Now()) {}
300 };
301
302 // Context for a crx download url request. See DelegateWithContext above.
303 struct CRXContext {
304 ComponentInstaller* installer;
305 std::vector<uint8> pk_hash;
306 std::string id;
307 CRXContext() : installer(NULL) {}
308 };
309
[email protected]10c2d692012-05-11 05:32:23310 void OnURLFetchComplete(const net::URLFetcher* source,
[email protected]7cc6e5632011-10-25 17:56:12311 UpdateContext* context);
[email protected]e8f96ff2011-08-03 05:07:33312
[email protected]10c2d692012-05-11 05:32:23313 void OnURLFetchComplete(const net::URLFetcher* source,
[email protected]7cc6e5632011-10-25 17:56:12314 CRXContext* context);
[email protected]e8f96ff2011-08-03 05:07:33315
316 private:
317 // See ManifestParserBridge.
318 void OnParseUpdateManifestSucceeded(
319 const UpdateManifest::Results& results);
320
321 // See ManifestParserBridge.
322 void OnParseUpdateManifestFailed(
323 const std::string& error_message);
324
325 bool AddItemToUpdateCheck(CrxUpdateItem* item, std::string* query);
326
327 void ProcessPendingItems();
328
329 void ScheduleNextRun(bool step_delay);
330
331 void ParseManifest(const std::string& xml);
332
[email protected]650b2d52013-02-10 03:41:45333 void Install(const CRXContext* context, const base::FilePath& crx_path);
[email protected]e8f96ff2011-08-03 05:07:33334
[email protected]07f93af12011-08-17 20:57:22335 void DoneInstalling(const std::string& component_id,
336 ComponentUnpacker::Error error);
[email protected]e8f96ff2011-08-03 05:07:33337
338 size_t ChangeItemStatus(CrxUpdateItem::Status from,
339 CrxUpdateItem::Status to);
340
341 CrxUpdateItem* FindUpdateItemById(const std::string& id);
342
343 scoped_ptr<Config> config_;
344
[email protected]d3ec669b2012-05-23 07:12:14345 scoped_ptr<net::URLFetcher> url_fetcher_;
[email protected]e8f96ff2011-08-03 05:07:33346
347 typedef std::vector<CrxUpdateItem*> UpdateItems;
[email protected]ccb4feef2013-02-14 06:16:47348 // A collection of every work item.
[email protected]e8f96ff2011-08-03 05:07:33349 UpdateItems work_items_;
350
[email protected]ccb4feef2013-02-14 06:16:47351 // A particular set of items from work_items_, which should be checked ASAP.
352 std::set<CrxUpdateItem*> requested_work_items_;
353
[email protected]e8f96ff2011-08-03 05:07:33354 base::OneShotTimer<CrxUpdateService> timer_;
355
356 Version chrome_version_;
357
358 bool running_;
359
360 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
361};
362
[email protected]e8f96ff2011-08-03 05:07:33363//////////////////////////////////////////////////////////////////////////////
364
365CrxUpdateService::CrxUpdateService(
366 ComponentUpdateService::Configurator* config)
367 : config_(config),
368 chrome_version_(chrome::VersionInfo().Version()),
369 running_(false) {
370}
371
372CrxUpdateService::~CrxUpdateService() {
373 // Because we are a singleton, at this point only the UI thread should be
374 // alive, this simplifies the management of the work that could be in
375 // flight in other threads.
376 Stop();
377 STLDeleteElements(&work_items_);
378}
379
380ComponentUpdateService::Status CrxUpdateService::Start() {
381 // Note that RegisterComponent will call Start() when the first
382 // component is registered, so it can be called twice. This way
383 // we avoid scheduling the timer if there is no work to do.
384 running_ = true;
385 if (work_items_.empty())
386 return kOk;
387
[email protected]ad50def52011-10-19 23:17:07388 content::NotificationService::current()->Notify(
[email protected]e8f96ff2011-08-03 05:07:33389 chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED,
[email protected]6c2381d2011-10-19 02:52:53390 content::Source<ComponentUpdateService>(this),
[email protected]ad50def52011-10-19 23:17:07391 content::NotificationService::NoDetails());
[email protected]e8f96ff2011-08-03 05:07:33392
[email protected]d323a172011-09-02 18:23:02393 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->InitialDelay()),
[email protected]e8f96ff2011-08-03 05:07:33394 this, &CrxUpdateService::ProcessPendingItems);
395 return kOk;
396}
397
398// Stop the main check + update loop. In flight operations will be
399// completed.
400ComponentUpdateService::Status CrxUpdateService::Stop() {
401 running_ = false;
402 timer_.Stop();
403 return kOk;
404}
405
[email protected]ccb4feef2013-02-14 06:16:47406// This function sets the timer which will call ProcessPendingItems() or
407// ProcessRequestedItem() if there is an important requested item. There
408// are two kinds of waits: a short step_delay (when step_status is
409// kPrevInProgress) and a long one when a full check/update cycle
410// has completed either successfully or with an error.
[email protected]e8f96ff2011-08-03 05:07:33411void CrxUpdateService::ScheduleNextRun(bool step_delay) {
412 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cf442612011-08-09 20:20:12413 DCHECK(url_fetcher_.get() == NULL);
[email protected]e8f96ff2011-08-03 05:07:33414 CHECK(!timer_.IsRunning());
415 // It could be the case that Stop() had been called while a url request
416 // or unpacking was in flight, if so we arrive here but |running_| is
417 // false. In that case do not loop again.
418 if (!running_)
419 return;
420
[email protected]ccb4feef2013-02-14 06:16:47421 // Keep the delay short if in the middle of an update (step_delay),
422 // or there are new requested_work_items_ that have not been processed yet.
423 int64 delay = (step_delay || requested_work_items_.size() > 0)
424 ? config_->StepDelay() : config_->NextCheckDelay();
[email protected]cf442612011-08-09 20:20:12425
[email protected]e8f96ff2011-08-03 05:07:33426 if (!step_delay) {
[email protected]ad50def52011-10-19 23:17:07427 content::NotificationService::current()->Notify(
[email protected]e8f96ff2011-08-03 05:07:33428 chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING,
[email protected]6c2381d2011-10-19 02:52:53429 content::Source<ComponentUpdateService>(this),
[email protected]ad50def52011-10-19 23:17:07430 content::NotificationService::NoDetails());
[email protected]e8f96ff2011-08-03 05:07:33431 // Zero is only used for unit tests.
[email protected]cf442612011-08-09 20:20:12432 if (0 == delay)
[email protected]e8f96ff2011-08-03 05:07:33433 return;
434 }
435
[email protected]d323a172011-09-02 18:23:02436 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay),
[email protected]e8f96ff2011-08-03 05:07:33437 this, &CrxUpdateService::ProcessPendingItems);
438}
439
440// Given a extension-like component id, find the associated component.
441CrxUpdateItem* CrxUpdateService::FindUpdateItemById(const std::string& id) {
442 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
443 CrxUpdateItem::FindById finder(id);
444 UpdateItems::iterator it = std::find_if(work_items_.begin(),
445 work_items_.end(),
446 finder);
447 if (it == work_items_.end())
448 return NULL;
449 return (*it);
450}
451
452// Changes all the components in |work_items_| that have |from| status to
453// |to| statatus and returns how many have been changed.
454size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from,
455 CrxUpdateItem::Status to) {
456 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
457 size_t count = 0;
458 for (UpdateItems::iterator it = work_items_.begin();
459 it != work_items_.end(); ++it) {
460 CrxUpdateItem* item = *it;
461 if (item->status != from)
462 continue;
463 item->status = to;
464 ++count;
465 }
466 return count;
467}
468
469// Adds a component to be checked for upgrades. If the component exists it
470// it will be replaced and the return code is kReplaced.
471//
472// TODO(cpu): Evaluate if we want to support un-registration.
473ComponentUpdateService::Status CrxUpdateService::RegisterComponent(
474 const CrxComponent& component) {
475 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
476 if (component.pk_hash.empty() ||
477 !component.version.IsValid() ||
478 !component.installer)
479 return kError;
480
481 std::string id =
482 HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
483 component.pk_hash.size()/2)));
484 CrxUpdateItem* uit;
485 uit = FindUpdateItemById(id);
486 if (uit) {
487 uit->component = component;
488 return kReplaced;
489 }
490
491 uit = new CrxUpdateItem;
492 uit->id.swap(id);
493 uit->component = component;
494 work_items_.push_back(uit);
495 // If this is the first component registered we call Start to
496 // schedule the first timer.
497 if (running_ && (work_items_.size() == 1))
498 Start();
499
500 return kOk;
501}
502
503// Sets a component to be checked for updates.
504// The componet to add is |crxit| and the |query| string is modified with the
505// required omaha compatible query. Returns false when the query strings
506// is longer than specified by UrlSizeLimit().
507bool CrxUpdateService::AddItemToUpdateCheck(CrxUpdateItem* item,
508 std::string* query) {
509 if (!AddQueryString(item->id,
510 item->component.version.GetString(),
511 config_->UrlSizeLimit(), query))
512 return false;
513 item->status = CrxUpdateItem::kChecking;
514 item->last_check = base::Time::Now();
515 return true;
516}
517
[email protected]ccb4feef2013-02-14 06:16:47518// Start the process of checking for an update, for a particular component
519// that was previously registered.
520ComponentUpdateService::Status CrxUpdateService::CheckForUpdateSoon(
521 const CrxComponent& component) {
522 if (component.pk_hash.empty() ||
523 !component.version.IsValid() ||
524 !component.installer)
525 return kError;
526
527 std::string id =
528 HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
529 component.pk_hash.size()/2)));
530
531 CrxUpdateItem* uit;
532 uit = FindUpdateItemById(id);
533 if (!uit)
534 return kError;
535
536 // Check if the request is too soon.
537 base::TimeDelta delta = base::Time::Now() - uit->last_check;
538 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay())) {
539 return kError;
540 }
541
542 switch (uit->status) {
543 // If the item is already in the process of being updated, there is
544 // no point in this call, so return kInProgress.
545 case CrxUpdateItem::kChecking:
546 case CrxUpdateItem::kCanUpdate:
547 case CrxUpdateItem::kDownloading:
548 case CrxUpdateItem::kUpdating:
549 return kInProgress;
550 // Otherwise the item was already checked a while back (or it is new),
551 // set its status to kNew to give it a slightly higher priority.
552 case CrxUpdateItem::kNew:
553 case CrxUpdateItem::kUpdated:
554 case CrxUpdateItem::kUpToDate:
555 case CrxUpdateItem::kNoUpdate:
556 uit->status = CrxUpdateItem::kNew;
557 requested_work_items_.insert(uit);
558 break;
559 case CrxUpdateItem::kLastStatus:
560 NOTREACHED() << uit->status;
561 }
562
563 // In case the current delay is long, set the timer to a shorter value
564 // to get the ball rolling.
565 if (timer_.IsRunning()) {
566 timer_.Stop();
567 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->StepDelay()),
568 this, &CrxUpdateService::ProcessPendingItems);
569 }
570
571 return kOk;
572}
573
[email protected]e8f96ff2011-08-03 05:07:33574// Here is where the work gets scheduled. Given that our |work_items_| list
575// is expected to be ten or less items, we simply loop several times.
576void CrxUpdateService::ProcessPendingItems() {
577 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
578 // First check for ready upgrades and do one. The first
579 // step is to fetch the crx package.
580 for (UpdateItems::const_iterator it = work_items_.begin();
581 it != work_items_.end(); ++it) {
582 CrxUpdateItem* item = *it;
583 if (item->status != CrxUpdateItem::kCanUpdate)
584 continue;
585 // Found component to update, start the process.
586 item->status = CrxUpdateItem::kDownloading;
587 CRXContext* context = new CRXContext;
588 context->pk_hash = item->component.pk_hash;
589 context->id = item->id;
590 context->installer = item->component.installer;
[email protected]3dc1bc42012-06-19 08:20:53591 url_fetcher_.reset(net::URLFetcher::Create(
[email protected]d3ec669b2012-05-23 07:12:14592 0, item->crx_url, net::URLFetcher::GET,
[email protected]e8f96ff2011-08-03 05:07:33593 MakeContextDelegate(this, context)));
594 StartFetch(url_fetcher_.get(), config_->RequestContext(), true);
595 return;
596 }
597
[email protected]dc06f0b2013-01-23 20:03:16598 for (size_t ix = 0; ix != arraysize(kManifestSources); ++ix) {
599 const CrxComponent::UrlSource manifest_source = kManifestSources[ix];
[email protected]e8f96ff2011-08-03 05:07:33600
[email protected]dc06f0b2013-01-23 20:03:16601 std::string query;
602 // If no pending upgrades, we check if there are new components we have not
603 // checked against the server. We can batch some in a single url request.
604 for (UpdateItems::const_iterator it = work_items_.begin();
605 it != work_items_.end(); ++it) {
606 CrxUpdateItem* item = *it;
607 if (item->status != CrxUpdateItem::kNew)
608 continue;
609 if (item->component.source != manifest_source)
610 continue;
611 if (!AddItemToUpdateCheck(item, &query))
612 break;
[email protected]ccb4feef2013-02-14 06:16:47613 // Requested work items may speed up the update cycle up until
614 // the point that we start an update check. I.e., transition
615 // from kNew -> kChecking. Since the service doesn't guarantee that
616 // the requested items make it any further than kChecking,
617 // forget them now.
618 requested_work_items_.erase(item);
[email protected]dc06f0b2013-01-23 20:03:16619 }
[email protected]e8f96ff2011-08-03 05:07:33620
[email protected]dc06f0b2013-01-23 20:03:16621 // Next we can go back to components we already checked, here
622 // we can also batch them in a single url request, as long as
623 // we have not checked them recently.
624 const base::TimeDelta min_delta_time =
625 base::TimeDelta::FromSeconds(config_->MinimumReCheckWait());
[email protected]e8f96ff2011-08-03 05:07:33626
[email protected]dc06f0b2013-01-23 20:03:16627 for (UpdateItems::const_iterator it = work_items_.begin();
628 it != work_items_.end(); ++it) {
629 CrxUpdateItem* item = *it;
630 if ((item->status != CrxUpdateItem::kNoUpdate) &&
631 (item->status != CrxUpdateItem::kUpToDate))
632 continue;
633 if (item->component.source != manifest_source)
634 continue;
635 base::TimeDelta delta = base::Time::Now() - item->last_check;
636 if (delta < min_delta_time)
637 continue;
638 if (!AddItemToUpdateCheck(item, &query))
639 break;
640 }
641
642 // Finally, we check components that we already updated as long as
643 // we have not checked them recently.
644 for (UpdateItems::const_iterator it = work_items_.begin();
645 it != work_items_.end(); ++it) {
646 CrxUpdateItem* item = *it;
647 if (item->status != CrxUpdateItem::kUpdated)
648 continue;
649 if (item->component.source != manifest_source)
650 continue;
651 base::TimeDelta delta = base::Time::Now() - item->last_check;
652 if (delta < min_delta_time)
653 continue;
654 if (!AddItemToUpdateCheck(item, &query))
655 break;
656 }
657
658 // If no components to update we move down to the next source.
659 if (query.empty())
660 continue;
661
662 // We got components to check. Start the url request and exit.
663 const std::string full_query =
664 MakeFinalQuery(config_->UpdateUrl(manifest_source).spec(),
665 query,
666 config_->ExtraRequestParams());
667
668 url_fetcher_.reset(net::URLFetcher::Create(
669 0, GURL(full_query), net::URLFetcher::GET,
670 MakeContextDelegate(this, new UpdateContext())));
671 StartFetch(url_fetcher_.get(), config_->RequestContext(), false);
[email protected]e8f96ff2011-08-03 05:07:33672 return;
673 }
674
[email protected]dc06f0b2013-01-23 20:03:16675 // No components to update. Next check after the long sleep.
676 ScheduleNextRun(false);
[email protected]e8f96ff2011-08-03 05:07:33677}
678
[email protected]ccb4feef2013-02-14 06:16:47679// Called when we got a response from the update server. It consists of an xml
[email protected]e8f96ff2011-08-03 05:07:33680// document following the omaha update scheme.
[email protected]10c2d692012-05-11 05:32:23681void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
[email protected]07f93af12011-08-17 20:57:22682 UpdateContext* context) {
[email protected]e8f96ff2011-08-03 05:07:33683 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
684 if (FetchSuccess(*source)) {
685 std::string xml;
686 source->GetResponseAsString(&xml);
[email protected]cf442612011-08-09 20:20:12687 url_fetcher_.reset();
[email protected]e8f96ff2011-08-03 05:07:33688 ParseManifest(xml);
689 } else {
[email protected]cf442612011-08-09 20:20:12690 url_fetcher_.reset();
[email protected]e8f96ff2011-08-03 05:07:33691 CrxUpdateService::OnParseUpdateManifestFailed("network error");
692 }
[email protected]07f93af12011-08-17 20:57:22693 delete context;
[email protected]e8f96ff2011-08-03 05:07:33694}
695
696// Parsing the manifest is either done right now for tests or in a sandboxed
697// process for the production environment. This mitigates the case where an
698// attacker was able to feed us a malicious xml string.
699void CrxUpdateService::ParseManifest(const std::string& xml) {
700 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
701 if (config_->InProcess()) {
702 UpdateManifest manifest;
703 if (!manifest.Parse(xml)) {
704 CrxUpdateService::OnParseUpdateManifestFailed(manifest.errors());
705 } else {
706 CrxUpdateService::OnParseUpdateManifestSucceeded(manifest.results());
707 }
708 } else {
[email protected]cadac622013-06-11 16:46:36709 UtilityProcessHost* host =
710 UtilityProcessHost::Create(new ManifestParserBridge(this),
711 base::MessageLoopProxy::current().get());
[email protected]c4f883a2012-02-03 17:02:07712 host->EnableZygote();
[email protected]2ccf45c2011-08-19 23:35:50713 host->Send(new ChromeUtilityMsg_ParseUpdateManifest(xml));
[email protected]e8f96ff2011-08-03 05:07:33714 }
715}
716
717// A valid Omaha update check has arrived, from only the list of components that
718// we are currently upgrading we check for a match in which the server side
719// version is newer, if so we queue them for an upgrade. The next time we call
720// ProcessPendingItems() one of them will be drafted for the upgrade process.
721void CrxUpdateService::OnParseUpdateManifestSucceeded(
722 const UpdateManifest::Results& results) {
723 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a1f8c162012-09-27 22:32:21724 size_t update_pending = 0;
[email protected]e8f96ff2011-08-03 05:07:33725 std::vector<UpdateManifest::Result>::const_iterator it;
726 for (it = results.list.begin(); it != results.list.end(); ++it) {
727 CrxUpdateItem* crx = FindUpdateItemById(it->extension_id);
728 if (!crx)
729 continue;
730
731 if (crx->status != CrxUpdateItem::kChecking)
732 continue; // Not updating this component now.
733
[email protected]360b8bb2011-09-01 21:48:06734 config_->OnEvent(Configurator::kManifestCheck, CrxIdtoUMAId(crx->id));
735
[email protected]e8f96ff2011-08-03 05:07:33736 if (it->version.empty()) {
[email protected]cf442612011-08-09 20:20:12737 // No version means no update available.
[email protected]e8f96ff2011-08-03 05:07:33738 crx->status = CrxUpdateItem::kNoUpdate;
[email protected]cf442612011-08-09 20:20:12739 continue;
[email protected]e8f96ff2011-08-03 05:07:33740 }
741 if (!IsVersionNewer(crx->component.version, it->version)) {
[email protected]cf442612011-08-09 20:20:12742 // Our component is up to date.
[email protected]e8f96ff2011-08-03 05:07:33743 crx->status = CrxUpdateItem::kUpToDate;
[email protected]cf442612011-08-09 20:20:12744 continue;
[email protected]e8f96ff2011-08-03 05:07:33745 }
746 if (!it->browser_min_version.empty()) {
[email protected]cf442612011-08-09 20:20:12747 if (IsVersionNewer(chrome_version_, it->browser_min_version)) {
748 // Does not apply for this chrome version.
749 crx->status = CrxUpdateItem::kNoUpdate;
750 continue;
751 }
[email protected]e8f96ff2011-08-03 05:07:33752 }
753 // All test passed. Queue an upgrade for this component and fire the
754 // notifications.
755 crx->crx_url = it->crx_url;
756 crx->status = CrxUpdateItem::kCanUpdate;
[email protected]07f93af12011-08-17 20:57:22757 crx->next_version = Version(it->version);
[email protected]e8f96ff2011-08-03 05:07:33758 ++update_pending;
759
[email protected]ad50def52011-10-19 23:17:07760 content::NotificationService::current()->Notify(
[email protected]e8f96ff2011-08-03 05:07:33761 chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND,
[email protected]6c2381d2011-10-19 02:52:53762 content::Source<std::string>(&crx->id),
[email protected]ad50def52011-10-19 23:17:07763 content::NotificationService::NoDetails());
[email protected]e8f96ff2011-08-03 05:07:33764 }
[email protected]cf442612011-08-09 20:20:12765
766 // All the components that are not mentioned in the manifest we
767 // consider them up to date.
768 ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kUpToDate);
769
[email protected]e8f96ff2011-08-03 05:07:33770 // If there are updates pending we do a short wait.
[email protected]a1f8c162012-09-27 22:32:21771 ScheduleNextRun(update_pending > 0);
[email protected]e8f96ff2011-08-03 05:07:33772}
773
774void CrxUpdateService::OnParseUpdateManifestFailed(
775 const std::string& error_message) {
776 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
777 size_t count = ChangeItemStatus(CrxUpdateItem::kChecking,
778 CrxUpdateItem::kNoUpdate);
[email protected]360b8bb2011-09-01 21:48:06779 config_->OnEvent(Configurator::kManifestError, static_cast<int>(count));
[email protected]e8f96ff2011-08-03 05:07:33780 DCHECK_GT(count, 0ul);
781 ScheduleNextRun(false);
782}
783
784// Called when the CRX package has been downloaded to a temporary location.
785// Here we fire the notifications and schedule the component-specific installer
786// to be called in the file thread.
[email protected]10c2d692012-05-11 05:32:23787void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
[email protected]e8f96ff2011-08-03 05:07:33788 CRXContext* context) {
789 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]1dd4060e2013-03-13 13:15:13790 int error_code = net::OK;
[email protected]e8f96ff2011-08-03 05:07:33791
792 if (source->FileErrorOccurred(&error_code) || !FetchSuccess(*source)) {
793 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
794 CrxUpdateItem::kNoUpdate);
795 DCHECK_EQ(count, 1ul);
[email protected]360b8bb2011-09-01 21:48:06796 config_->OnEvent(Configurator::kNetworkError, CrxIdtoUMAId(context->id));
[email protected]cf442612011-08-09 20:20:12797 url_fetcher_.reset();
[email protected]e8f96ff2011-08-03 05:07:33798 ScheduleNextRun(false);
799 } else {
[email protected]650b2d52013-02-10 03:41:45800 base::FilePath temp_crx_path;
[email protected]e8f96ff2011-08-03 05:07:33801 CHECK(source->GetResponseAsFilePath(true, &temp_crx_path));
802 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
803 CrxUpdateItem::kUpdating);
804 DCHECK_EQ(count, 1ul);
[email protected]cf442612011-08-09 20:20:12805 url_fetcher_.reset();
806
[email protected]ad50def52011-10-19 23:17:07807 content::NotificationService::current()->Notify(
[email protected]e8f96ff2011-08-03 05:07:33808 chrome::NOTIFICATION_COMPONENT_UPDATE_READY,
[email protected]6c2381d2011-10-19 02:52:53809 content::Source<std::string>(&context->id),
[email protected]ad50def52011-10-19 23:17:07810 content::NotificationService::NoDetails());
[email protected]e8f96ff2011-08-03 05:07:33811
[email protected]44da56e2011-11-21 19:59:14812 // Why unretained? See comment at top of file.
[email protected]73251e72012-03-04 02:10:33813 BrowserThread::PostDelayedTask(
814 BrowserThread::FILE,
815 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14816 base::Bind(&CrxUpdateService::Install,
817 base::Unretained(this),
818 context,
819 temp_crx_path),
[email protected]73251e72012-03-04 02:10:33820 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]e8f96ff2011-08-03 05:07:33821 }
[email protected]e8f96ff2011-08-03 05:07:33822}
823
824// Install consists of digital signature verification, unpacking and then
825// calling the component specific installer. All that is handled by the
826// |unpacker|. If there is an error this function is in charge of deleting
827// the files created.
828void CrxUpdateService::Install(const CRXContext* context,
[email protected]650b2d52013-02-10 03:41:45829 const base::FilePath& crx_path) {
[email protected]e8f96ff2011-08-03 05:07:33830 // This function owns the |crx_path| and the |context| object.
831 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
832 ComponentUnpacker
833 unpacker(context->pk_hash, crx_path, context->installer);
[email protected]e8f96ff2011-08-03 05:07:33834 if (!file_util::Delete(crx_path, false)) {
835 NOTREACHED() << crx_path.value();
836 }
[email protected]44da56e2011-11-21 19:59:14837 // Why unretained? See comment at top of file.
[email protected]73251e72012-03-04 02:10:33838 BrowserThread::PostDelayedTask(
839 BrowserThread::UI,
840 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14841 base::Bind(&CrxUpdateService::DoneInstalling, base::Unretained(this),
842 context->id, unpacker.error()),
[email protected]73251e72012-03-04 02:10:33843 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]07f93af12011-08-17 20:57:22844 delete context;
[email protected]e8f96ff2011-08-03 05:07:33845}
846
847// Installation has been completed. Adjust the component status and
848// schedule the next check.
[email protected]07f93af12011-08-17 20:57:22849void CrxUpdateService::DoneInstalling(const std::string& component_id,
850 ComponentUnpacker::Error error) {
[email protected]e8f96ff2011-08-03 05:07:33851 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]07f93af12011-08-17 20:57:22852
853 CrxUpdateItem* item = FindUpdateItemById(component_id);
854 item->status = (error == ComponentUnpacker::kNone) ? CrxUpdateItem::kUpdated :
855 CrxUpdateItem::kNoUpdate;
856 if (item->status == CrxUpdateItem::kUpdated)
857 item->component.version = item->next_version;
858
[email protected]360b8bb2011-09-01 21:48:06859 Configurator::Events event;
860 switch (error) {
861 case ComponentUnpacker::kNone:
862 event = Configurator::kComponentUpdated;
863 break;
864 case ComponentUnpacker::kInstallerError:
865 event = Configurator::kInstallerError;
866 break;
867 default:
868 event = Configurator::kUnpackError;
869 break;
870 }
871
872 config_->OnEvent(event, CrxIdtoUMAId(component_id));
[email protected]e8f96ff2011-08-03 05:07:33873 ScheduleNextRun(false);
874}
875
876// The component update factory. Using the component updater as a singleton
877// is the job of the browser process.
878ComponentUpdateService* ComponentUpdateServiceFactory(
879 ComponentUpdateService::Configurator* config) {
880 DCHECK(config);
881 return new CrxUpdateService(config);
882}