blob: b790dad01534f7a7fb56ba52785bb00a9c1b7852 [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]e3e696d32013-06-21 20:41:3613#include "base/compiler_specific.h"
[email protected]e8f96ff2011-08-03 05:07:3314#include "base/file_util.h"
[email protected]57999812013-02-24 05:40:5215#include "base/files/file_path.h"
[email protected]e8f96ff2011-08-03 05:07:3316#include "base/logging.h"
[email protected]7226b33c2011-08-18 08:44:2217#include "base/memory/scoped_ptr.h"
[email protected]00a77fa2013-11-02 04:18:4618#include "base/memory/weak_ptr.h"
[email protected]e8f96ff2011-08-03 05:07:3319#include "base/stl_util.h"
[email protected]3ea1b182013-02-08 22:38:4120#include "base/strings/string_number_conversions.h"
[email protected]4570a252013-03-31 00:35:4321#include "base/strings/string_piece.h"
[email protected]e7463412013-06-10 22:53:4622#include "base/strings/string_util.h"
23#include "base/strings/stringprintf.h"
[email protected]8f5f2ea2013-10-31 09:39:1024#include "base/threading/sequenced_worker_pool.h"
[email protected]41a17c52013-06-28 00:27:5325#include "base/timer/timer.h"
[email protected]e8f96ff2011-08-03 05:07:3326#include "chrome/browser/browser_process.h"
[email protected]e3e696d32013-06-21 20:41:3627#include "chrome/browser/component_updater/component_patcher.h"
[email protected]e8f96ff2011-08-03 05:07:3328#include "chrome/browser/component_updater/component_unpacker.h"
[email protected]7b0529242013-07-20 05:45:4629#include "chrome/browser/component_updater/component_updater_ping_manager.h"
[email protected]2cddef42013-11-22 08:23:2230#include "chrome/browser/component_updater/component_updater_utils.h"
[email protected]afa378f22013-12-02 03:37:5431#include "chrome/browser/component_updater/crx_downloader.h"
[email protected]7b0529242013-07-20 05:45:4632#include "chrome/browser/component_updater/crx_update_item.h"
[email protected]6268d3a2013-11-27 01:28:0933#include "chrome/browser/component_updater/update_response.h"
[email protected]e8f96ff2011-08-03 05:07:3334#include "chrome/common/chrome_version_info.h"
[email protected]b7b63872013-01-03 02:41:1935#include "content/public/browser/browser_thread.h"
[email protected]00a77fa2013-11-02 04:18:4636#include "content/public/browser/resource_controller.h"
37#include "content/public/browser/resource_throttle.h"
[email protected]e4452d32013-11-15 23:07:4138#include "extensions/common/extension.h"
[email protected]e8f96ff2011-08-03 05:07:3339#include "net/base/escape.h"
40#include "net/base/load_flags.h"
[email protected]1dd4060e2013-03-13 13:15:1341#include "net/base/net_errors.h"
[email protected]3dc1bc42012-06-19 08:20:5342#include "net/url_request/url_fetcher.h"
[email protected]15fb2aa2012-05-22 22:52:5943#include "net/url_request/url_fetcher_delegate.h"
[email protected]00a77fa2013-11-02 04:18:4644#include "net/url_request/url_request.h"
[email protected]761fa4702013-07-02 15:25:1545#include "url/gurl.h"
[email protected]e8f96ff2011-08-03 05:07:3346
[email protected]631bb742011-11-02 11:29:3947using content::BrowserThread;
48
[email protected]44da56e2011-11-21 19:59:1449// The component updater is designed to live until process shutdown, so
50// base::Bind() calls are not refcounted.
51
[email protected]e8f96ff2011-08-03 05:07:3352namespace {
[email protected]e3e696d32013-06-21 20:41:3653
[email protected]e8f96ff2011-08-03 05:07:3354// Produces an extension-like friendly |id|. This might be removed in the
55// future if we roll our on packing tools.
56static std::string HexStringToID(const std::string& hexstr) {
57 std::string id;
58 for (size_t i = 0; i < hexstr.size(); ++i) {
[email protected]2cddef42013-11-22 08:23:2259 int val(0);
[email protected]eb72b272011-12-19 16:10:5560 if (base::HexStringToInt(base::StringPiece(hexstr.begin() + i,
61 hexstr.begin() + i + 1),
62 &val)) {
[email protected]e8f96ff2011-08-03 05:07:3363 id.append(1, val + 'a');
[email protected]eb72b272011-12-19 16:10:5564 } else {
[email protected]e8f96ff2011-08-03 05:07:3365 id.append(1, 'a');
[email protected]eb72b272011-12-19 16:10:5566 }
[email protected]e8f96ff2011-08-03 05:07:3367 }
[email protected]2cddef42013-11-22 08:23:2268 DCHECK(extensions::Extension::IdIsValid(id));
[email protected]e8f96ff2011-08-03 05:07:3369 return id;
70}
71
[email protected]2cddef42013-11-22 08:23:2272// Returns true if the |proposed| version is newer than |current| version.
[email protected]e8f96ff2011-08-03 05:07:3373bool IsVersionNewer(const Version& current, const std::string& proposed) {
74 Version proposed_ver(proposed);
[email protected]2cddef42013-11-22 08:23:2275 return proposed_ver.IsValid() && current.CompareTo(proposed_ver) < 0;
[email protected]e8f96ff2011-08-03 05:07:3376}
77
78// Helper template class that allows our main class to have separate
[email protected]f1050432012-02-15 01:35:4679// OnURLFetchComplete() callbacks for different types of url requests
[email protected]e8f96ff2011-08-03 05:07:3380// they are differentiated by the |Ctx| type.
81template <typename Del, typename Ctx>
[email protected]15fb2aa2012-05-22 22:52:5982class DelegateWithContext : public net::URLFetcherDelegate {
[email protected]e8f96ff2011-08-03 05:07:3383 public:
84 DelegateWithContext(Del* delegate, Ctx* context)
85 : delegate_(delegate), context_(context) {}
86
[email protected]10c2d692012-05-11 05:32:2387 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
[email protected]e8f96ff2011-08-03 05:07:3388 delegate_->OnURLFetchComplete(source, context_);
89 delete this;
90 }
91
92 private:
93 ~DelegateWithContext() {}
94
95 Del* delegate_;
96 Ctx* context_;
97};
98// This function creates the right DelegateWithContext using template inference.
99template <typename Del, typename Ctx>
[email protected]15fb2aa2012-05-22 22:52:59100net::URLFetcherDelegate* MakeContextDelegate(Del* delegate, Ctx* context) {
[email protected]e8f96ff2011-08-03 05:07:33101 return new DelegateWithContext<Del, Ctx>(delegate, context);
102}
103
[email protected]e3e696d32013-06-21 20:41:36104// Returns true if a differential update is available for the update item.
105bool IsDiffUpdateAvailable(const CrxUpdateItem* update_item) {
106 return update_item->diff_crx_url.is_valid();
107}
[email protected]e8f96ff2011-08-03 05:07:33108
[email protected]e3e696d32013-06-21 20:41:36109// Returns true if a differential update is available, it has not failed yet,
110// and the configuration allows it.
111bool CanTryDiffUpdate(const CrxUpdateItem* update_item,
112 const ComponentUpdateService::Configurator& config) {
113 return IsDiffUpdateAvailable(update_item) &&
114 !update_item->diff_update_failed &&
115 config.DeltasEnabled();
116}
117
[email protected]7b0529242013-07-20 05:45:46118} // namespace
119
120CrxUpdateItem::CrxUpdateItem()
121 : status(kNew),
[email protected]61aca4cd2013-10-26 10:50:59122 on_demand(false),
[email protected]7b0529242013-07-20 05:45:46123 diff_update_failed(false),
124 error_category(0),
125 error_code(0),
126 extra_code1(0),
127 diff_error_category(0),
128 diff_error_code(0),
129 diff_extra_code1(0) {
130}
131
132CrxUpdateItem::~CrxUpdateItem() {
133}
[email protected]86550a42013-06-21 15:20:49134
[email protected]dc06f0b2013-01-23 20:03:16135CrxComponent::CrxComponent()
[email protected]85e61d52013-08-01 22:23:42136 : installer(NULL),
137 observer(NULL) {
[email protected]dc06f0b2013-01-23 20:03:16138}
139
140CrxComponent::~CrxComponent() {
141}
[email protected]e8f96ff2011-08-03 05:07:33142
[email protected]2e919ddd2013-08-21 05:05:17143std::string GetCrxComponentID(const CrxComponent& component) {
144 return HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
145 component.pk_hash.size()/2)));
146}
147
148CrxComponentInfo::CrxComponentInfo() {
149}
150
151CrxComponentInfo::~CrxComponentInfo() {
152}
153
[email protected]00a77fa2013-11-02 04:18:46154///////////////////////////////////////////////////////////////////////////////
155// In charge of blocking url requests until the |crx_id| component has been
156// updated. This class is touched solely from the IO thread. The UI thread
157// can post tasks to it via weak pointers. By default the request is blocked
158// unless the CrxUpdateService calls Unblock().
159// The lifetime is controlled by Chrome's resource loader so the component
160// updater cannot touch objects from this class except via weak pointers.
161class CUResourceThrottle
162 : public content::ResourceThrottle,
163 public base::SupportsWeakPtr<CUResourceThrottle> {
164 public:
165 explicit CUResourceThrottle(const net::URLRequest* request);
166 virtual ~CUResourceThrottle();
[email protected]2cddef42013-11-22 08:23:22167
[email protected]00a77fa2013-11-02 04:18:46168 // Overriden from ResourceThrottle.
169 virtual void WillStartRequest(bool* defer) OVERRIDE;
170 virtual void WillRedirectRequest(const GURL& new_url, bool* defer) OVERRIDE;
171
172 // Component updater calls this function via PostTask to unblock the request.
173 void Unblock();
174
175 typedef std::vector<base::WeakPtr<CUResourceThrottle> > WeakPtrVector;
176
177 private:
[email protected]2cddef42013-11-22 08:23:22178 enum State {
179 NEW,
180 BLOCKED,
181 UNBLOCKED
182 };
[email protected]00a77fa2013-11-02 04:18:46183
[email protected]2cddef42013-11-22 08:23:22184 State state_;
[email protected]00a77fa2013-11-02 04:18:46185};
186
187void UnblockResourceThrottle(base::WeakPtr<CUResourceThrottle> rt) {
188 BrowserThread::PostTask(
189 BrowserThread::IO,
190 FROM_HERE,
191 base::Bind(&CUResourceThrottle::Unblock, rt));
192}
193
194void UnblockandReapAllThrottles(CUResourceThrottle::WeakPtrVector* throttles) {
195 CUResourceThrottle::WeakPtrVector::iterator it;
196 for (it = throttles->begin(); it != throttles->end(); ++it)
197 UnblockResourceThrottle(*it);
198 throttles->clear();
199}
200
[email protected]e8f96ff2011-08-03 05:07:33201//////////////////////////////////////////////////////////////////////////////
202// The one and only implementation of the ComponentUpdateService interface. In
203// charge of running the show. The main method is ProcessPendingItems() which
[email protected]50b01392012-09-01 03:33:13204// is called periodically to do the upgrades/installs or the update checks.
[email protected]e8f96ff2011-08-03 05:07:33205// An important consideration here is to be as "low impact" as we can to the
206// rest of the browser, so even if we have many components registered and
[email protected]f1050432012-02-15 01:35:46207// eligible for update, we only do one thing at a time with pauses in between
[email protected]e8f96ff2011-08-03 05:07:33208// the tasks. Also when we do network requests there is only one |url_fetcher_|
[email protected]e3e696d32013-06-21 20:41:36209// in flight at a time.
[email protected]e8f96ff2011-08-03 05:07:33210// There are no locks in this code, the main structure |work_items_| is mutated
211// only from the UI thread. The unpack and installation is done in the file
212// thread and the network requests are done in the IO thread and in the file
213// thread.
214class CrxUpdateService : public ComponentUpdateService {
215 public:
216 explicit CrxUpdateService(ComponentUpdateService::Configurator* config);
[email protected]e8f96ff2011-08-03 05:07:33217 virtual ~CrxUpdateService();
218
219 // Overrides for ComponentUpdateService.
220 virtual Status Start() OVERRIDE;
221 virtual Status Stop() OVERRIDE;
222 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE;
[email protected]61aca4cd2013-10-26 10:50:59223 virtual Status OnDemandUpdate(const std::string& component_id) OVERRIDE;
[email protected]2e919ddd2013-08-21 05:05:17224 virtual void GetComponents(
225 std::vector<CrxComponentInfo>* components) OVERRIDE;
[email protected]00a77fa2013-11-02 04:18:46226 virtual content::ResourceThrottle* GetOnDemandResourceThrottle(
227 net::URLRequest* request, const std::string& crx_id) OVERRIDE;
[email protected]e8f96ff2011-08-03 05:07:33228
[email protected]e8f96ff2011-08-03 05:07:33229 // Context for a update check url request. See DelegateWithContext above.
230 struct UpdateContext {
231 base::Time start;
232 UpdateContext() : start(base::Time::Now()) {}
233 };
234
235 // Context for a crx download url request. See DelegateWithContext above.
236 struct CRXContext {
237 ComponentInstaller* installer;
238 std::vector<uint8> pk_hash;
239 std::string id;
[email protected]e3e696d32013-06-21 20:41:36240 std::string fingerprint;
[email protected]e8f96ff2011-08-03 05:07:33241 CRXContext() : installer(NULL) {}
242 };
243
[email protected]10c2d692012-05-11 05:32:23244 void OnURLFetchComplete(const net::URLFetcher* source,
[email protected]7cc6e5632011-10-25 17:56:12245 UpdateContext* context);
[email protected]e8f96ff2011-08-03 05:07:33246
[email protected]e8f96ff2011-08-03 05:07:33247 private:
[email protected]7b0529242013-07-20 05:45:46248 enum ErrorCategory {
249 kErrorNone = 0,
250 kNetworkError,
251 kUnpackError,
252 kInstallError,
253 };
254
[email protected]32a6c8382013-08-20 00:29:20255 enum StepDelayInterval {
256 kStepDelayShort = 0,
257 kStepDelayMedium,
258 kStepDelayLong,
259 };
260
[email protected]6268d3a2013-11-27 01:28:09261 void OnParseUpdateResponseSucceeded(
262 const component_updater::UpdateResponse::Results& results);
263 void OnParseUpdateResponseFailed(const std::string& error_message);
[email protected]e8f96ff2011-08-03 05:07:33264
[email protected]afa378f22013-12-02 03:37:54265 void DownloadComplete(scoped_ptr<CRXContext> crx_context,
266 int error,
267 const base::FilePath& response);
268
[email protected]00a77fa2013-11-02 04:18:46269 Status OnDemandUpdateInternal(CrxUpdateItem* item);
270
[email protected]e8f96ff2011-08-03 05:07:33271 void ProcessPendingItems();
272
[email protected]61aca4cd2013-10-26 10:50:59273 CrxUpdateItem* FindReadyComponent();
274
275 void UpdateComponent(CrxUpdateItem* workitem);
276
[email protected]2cddef42013-11-22 08:23:22277 void AddItemToUpdateCheck(CrxUpdateItem* item,
278 std::string* update_check_items);
[email protected]61aca4cd2013-10-26 10:50:59279
[email protected]2cddef42013-11-22 08:23:22280 void AddUpdateCheckItems(std::string* update_check_items);
281
282 void DoUpdateCheck(const std::string& update_check_items);
[email protected]61aca4cd2013-10-26 10:50:59283
[email protected]32a6c8382013-08-20 00:29:20284 void ScheduleNextRun(StepDelayInterval step_delay);
[email protected]e8f96ff2011-08-03 05:07:33285
[email protected]6268d3a2013-11-27 01:28:09286 void ParseResponse(const std::string& xml);
[email protected]e8f96ff2011-08-03 05:07:33287
[email protected]afa378f22013-12-02 03:37:54288 void Install(scoped_ptr<CRXContext> context, const base::FilePath& crx_path);
[email protected]e8f96ff2011-08-03 05:07:33289
[email protected]07f93af12011-08-17 20:57:22290 void DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:36291 ComponentUnpacker::Error error,
292 int extended_error);
[email protected]e8f96ff2011-08-03 05:07:33293
[email protected]61aca4cd2013-10-26 10:50:59294 void ChangeItemState(CrxUpdateItem* item, CrxUpdateItem::Status to);
295
[email protected]e8f96ff2011-08-03 05:07:33296 size_t ChangeItemStatus(CrxUpdateItem::Status from,
297 CrxUpdateItem::Status to);
298
299 CrxUpdateItem* FindUpdateItemById(const std::string& id);
300
[email protected]85e61d52013-08-01 22:23:42301 void NotifyComponentObservers(ComponentObserver::Events event,
302 int extra) const;
303
[email protected]61aca4cd2013-10-26 10:50:59304 bool HasOnDemandItems() const;
305
[email protected]00a77fa2013-11-02 04:18:46306 void OnNewResourceThrottle(base::WeakPtr<CUResourceThrottle> rt,
307 const std::string& crx_id);
308
[email protected]e3e696d32013-06-21 20:41:36309 scoped_ptr<ComponentUpdateService::Configurator> config_;
310
311 scoped_ptr<ComponentPatcher> component_patcher_;
[email protected]e8f96ff2011-08-03 05:07:33312
[email protected]d3ec669b2012-05-23 07:12:14313 scoped_ptr<net::URLFetcher> url_fetcher_;
[email protected]e8f96ff2011-08-03 05:07:33314
[email protected]7b0529242013-07-20 05:45:46315 scoped_ptr<component_updater::PingManager> ping_manager_;
316
[email protected]afa378f22013-12-02 03:37:54317 scoped_ptr<component_updater::CrxDownloader> crx_downloader_;
318
[email protected]86550a42013-06-21 15:20:49319 // A collection of every work item.
[email protected]e3e696d32013-06-21 20:41:36320 typedef std::vector<CrxUpdateItem*> UpdateItems;
[email protected]e8f96ff2011-08-03 05:07:33321 UpdateItems work_items_;
322
323 base::OneShotTimer<CrxUpdateService> timer_;
324
[email protected]8f5f2ea2013-10-31 09:39:10325 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
326
[email protected]e3e696d32013-06-21 20:41:36327 const Version chrome_version_;
[email protected]e8f96ff2011-08-03 05:07:33328
329 bool running_;
330
331 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
332};
333
[email protected]e8f96ff2011-08-03 05:07:33334//////////////////////////////////////////////////////////////////////////////
335
[email protected]e3e696d32013-06-21 20:41:36336CrxUpdateService::CrxUpdateService(ComponentUpdateService::Configurator* config)
[email protected]e8f96ff2011-08-03 05:07:33337 : config_(config),
[email protected]e3e696d32013-06-21 20:41:36338 component_patcher_(config->CreateComponentPatcher()),
[email protected]7b0529242013-07-20 05:45:46339 ping_manager_(new component_updater::PingManager(
340 config->PingUrl(),
341 config->RequestContext())),
[email protected]8f5f2ea2013-10-31 09:39:10342 blocking_task_runner_(BrowserThread::GetBlockingPool()->
343 GetSequencedTaskRunnerWithShutdownBehavior(
344 BrowserThread::GetBlockingPool()->GetSequenceToken(),
345 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)),
[email protected]e8f96ff2011-08-03 05:07:33346 chrome_version_(chrome::VersionInfo().Version()),
347 running_(false) {
[email protected]1ea21ad2013-09-02 04:20:39348}
[email protected]e8f96ff2011-08-03 05:07:33349
350CrxUpdateService::~CrxUpdateService() {
351 // Because we are a singleton, at this point only the UI thread should be
352 // alive, this simplifies the management of the work that could be in
353 // flight in other threads.
354 Stop();
355 STLDeleteElements(&work_items_);
[email protected]1ea21ad2013-09-02 04:20:39356}
[email protected]e8f96ff2011-08-03 05:07:33357
358ComponentUpdateService::Status CrxUpdateService::Start() {
359 // Note that RegisterComponent will call Start() when the first
360 // component is registered, so it can be called twice. This way
361 // we avoid scheduling the timer if there is no work to do.
362 running_ = true;
363 if (work_items_.empty())
364 return kOk;
365
[email protected]85e61d52013-08-01 22:23:42366 NotifyComponentObservers(ComponentObserver::COMPONENT_UPDATER_STARTED, 0);
367
[email protected]d323a172011-09-02 18:23:02368 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->InitialDelay()),
[email protected]e8f96ff2011-08-03 05:07:33369 this, &CrxUpdateService::ProcessPendingItems);
370 return kOk;
371}
372
373// Stop the main check + update loop. In flight operations will be
374// completed.
375ComponentUpdateService::Status CrxUpdateService::Stop() {
376 running_ = false;
377 timer_.Stop();
378 return kOk;
379}
380
[email protected]61aca4cd2013-10-26 10:50:59381bool CrxUpdateService::HasOnDemandItems() const {
382 class Helper {
383 public:
384 static bool IsOnDemand(CrxUpdateItem* item) {
385 return item->on_demand;
386 }
387 };
388 return std::find_if(work_items_.begin(),
389 work_items_.end(),
390 Helper::IsOnDemand) != work_items_.end();
391}
392
[email protected]ccb4feef2013-02-14 06:16:47393// This function sets the timer which will call ProcessPendingItems() or
[email protected]61aca4cd2013-10-26 10:50:59394// ProcessRequestedItem() if there is an on_demand item. There
[email protected]32a6c8382013-08-20 00:29:20395// are three kinds of waits:
396// - a short delay, when there is immediate work to be done.
397// - a medium delay, when there are updates to be applied within the current
398// update cycle, or there are components that are still unchecked.
399// - a long delay when a full check/update cycle has completed for all
400// components.
401void CrxUpdateService::ScheduleNextRun(StepDelayInterval step_delay) {
[email protected]e8f96ff2011-08-03 05:07:33402 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cf442612011-08-09 20:20:12403 DCHECK(url_fetcher_.get() == NULL);
[email protected]e8f96ff2011-08-03 05:07:33404 CHECK(!timer_.IsRunning());
405 // It could be the case that Stop() had been called while a url request
406 // or unpacking was in flight, if so we arrive here but |running_| is
407 // false. In that case do not loop again.
408 if (!running_)
409 return;
410
[email protected]ccb4feef2013-02-14 06:16:47411 // Keep the delay short if in the middle of an update (step_delay),
412 // or there are new requested_work_items_ that have not been processed yet.
[email protected]32a6c8382013-08-20 00:29:20413 int64 delay_seconds = 0;
[email protected]61aca4cd2013-10-26 10:50:59414 if (!HasOnDemandItems()) {
[email protected]32a6c8382013-08-20 00:29:20415 switch (step_delay) {
416 case kStepDelayShort:
417 delay_seconds = config_->StepDelay();
418 break;
419 case kStepDelayMedium:
420 delay_seconds = config_->StepDelayMedium();
421 break;
422 case kStepDelayLong:
423 delay_seconds = config_->NextCheckDelay();
424 break;
425 }
426 } else {
427 delay_seconds = config_->StepDelay();
428 }
[email protected]cf442612011-08-09 20:20:12429
[email protected]32a6c8382013-08-20 00:29:20430 if (step_delay != kStepDelayShort) {
[email protected]85e61d52013-08-01 22:23:42431 NotifyComponentObservers(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0);
432
[email protected]e8f96ff2011-08-03 05:07:33433 // Zero is only used for unit tests.
[email protected]32a6c8382013-08-20 00:29:20434 if (0 == delay_seconds)
[email protected]e8f96ff2011-08-03 05:07:33435 return;
436 }
437
[email protected]32a6c8382013-08-20 00:29:20438 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay_seconds),
[email protected]e8f96ff2011-08-03 05:07:33439 this, &CrxUpdateService::ProcessPendingItems);
440}
441
442// Given a extension-like component id, find the associated component.
443CrxUpdateItem* CrxUpdateService::FindUpdateItemById(const std::string& id) {
444 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
445 CrxUpdateItem::FindById finder(id);
446 UpdateItems::iterator it = std::find_if(work_items_.begin(),
447 work_items_.end(),
448 finder);
449 if (it == work_items_.end())
450 return NULL;
451 return (*it);
452}
453
[email protected]61aca4cd2013-10-26 10:50:59454// Changes a component's status, clearing on_demand and firing notifications as
455// necessary. By convention, this is the only function that can change a
456// CrxUpdateItem's |status|.
457// TODO(waffles): Do we want to add DCHECKS for valid state transitions here?
458void CrxUpdateService::ChangeItemState(CrxUpdateItem* item,
459 CrxUpdateItem::Status to) {
460 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
461 if (to == CrxUpdateItem::kNoUpdate ||
462 to == CrxUpdateItem::kUpdated ||
463 to == CrxUpdateItem::kUpToDate) {
464 item->on_demand = false;
465 }
466
467 item->status = to;
468
469 ComponentObserver* observer = item->component.observer;
470 if (observer) {
471 switch (to) {
472 case CrxUpdateItem::kCanUpdate:
473 observer->OnEvent(ComponentObserver::COMPONENT_UPDATE_FOUND, 0);
474 break;
475 case CrxUpdateItem::kUpdatingDiff:
476 case CrxUpdateItem::kUpdating:
477 observer->OnEvent(ComponentObserver::COMPONENT_UPDATE_READY, 0);
478 break;
479 case CrxUpdateItem::kUpdated:
480 observer->OnEvent(ComponentObserver::COMPONENT_UPDATED, 0);
481 break;
482 case CrxUpdateItem::kUpToDate:
483 case CrxUpdateItem::kNoUpdate:
484 observer->OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0);
485 break;
486 case CrxUpdateItem::kNew:
487 case CrxUpdateItem::kChecking:
488 case CrxUpdateItem::kDownloading:
489 case CrxUpdateItem::kDownloadingDiff:
490 case CrxUpdateItem::kLastStatus:
491 // No notification for these states.
492 break;
493 }
494 }
[email protected]00a77fa2013-11-02 04:18:46495
496 // Free possible pending network requests.
497 if ((to == CrxUpdateItem::kUpdated) ||
498 (to == CrxUpdateItem::kUpToDate) ||
499 (to == CrxUpdateItem::kNoUpdate)) {
500 UnblockandReapAllThrottles(&item->throttles);
501 }
[email protected]61aca4cd2013-10-26 10:50:59502}
503
[email protected]e8f96ff2011-08-03 05:07:33504// Changes all the components in |work_items_| that have |from| status to
[email protected]e3e696d32013-06-21 20:41:36505// |to| status and returns how many have been changed.
[email protected]e8f96ff2011-08-03 05:07:33506size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from,
507 CrxUpdateItem::Status to) {
508 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
509 size_t count = 0;
510 for (UpdateItems::iterator it = work_items_.begin();
511 it != work_items_.end(); ++it) {
512 CrxUpdateItem* item = *it;
513 if (item->status != from)
514 continue;
[email protected]61aca4cd2013-10-26 10:50:59515 ChangeItemState(item, to);
[email protected]e8f96ff2011-08-03 05:07:33516 ++count;
517 }
518 return count;
519}
520
521// Adds a component to be checked for upgrades. If the component exists it
522// it will be replaced and the return code is kReplaced.
523//
524// TODO(cpu): Evaluate if we want to support un-registration.
525ComponentUpdateService::Status CrxUpdateService::RegisterComponent(
526 const CrxComponent& component) {
527 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
528 if (component.pk_hash.empty() ||
529 !component.version.IsValid() ||
530 !component.installer)
531 return kError;
532
533 std::string id =
534 HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
535 component.pk_hash.size()/2)));
536 CrxUpdateItem* uit;
537 uit = FindUpdateItemById(id);
538 if (uit) {
539 uit->component = component;
540 return kReplaced;
541 }
542
543 uit = new CrxUpdateItem;
544 uit->id.swap(id);
545 uit->component = component;
[email protected]e3e696d32013-06-21 20:41:36546
[email protected]e8f96ff2011-08-03 05:07:33547 work_items_.push_back(uit);
548 // If this is the first component registered we call Start to
549 // schedule the first timer.
550 if (running_ && (work_items_.size() == 1))
551 Start();
552
553 return kOk;
554}
555
[email protected]ccb4feef2013-02-14 06:16:47556// Start the process of checking for an update, for a particular component
557// that was previously registered.
[email protected]2e919ddd2013-08-21 05:05:17558// |component_id| is a value returned from GetCrxComponentID().
[email protected]61aca4cd2013-10-26 10:50:59559ComponentUpdateService::Status CrxUpdateService::OnDemandUpdate(
[email protected]2e919ddd2013-08-21 05:05:17560 const std::string& component_id) {
[email protected]00a77fa2013-11-02 04:18:46561 return OnDemandUpdateInternal(FindUpdateItemById(component_id));
562}
563
564ComponentUpdateService::Status CrxUpdateService::OnDemandUpdateInternal(
565 CrxUpdateItem* uit) {
[email protected]ccb4feef2013-02-14 06:16:47566 if (!uit)
567 return kError;
[email protected]2cddef42013-11-22 08:23:22568
[email protected]ccb4feef2013-02-14 06:16:47569 // Check if the request is too soon.
570 base::TimeDelta delta = base::Time::Now() - uit->last_check;
[email protected]e3e696d32013-06-21 20:41:36571 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
[email protected]ccb4feef2013-02-14 06:16:47572 return kError;
[email protected]ccb4feef2013-02-14 06:16:47573
574 switch (uit->status) {
575 // If the item is already in the process of being updated, there is
576 // no point in this call, so return kInProgress.
577 case CrxUpdateItem::kChecking:
578 case CrxUpdateItem::kCanUpdate:
[email protected]e3e696d32013-06-21 20:41:36579 case CrxUpdateItem::kDownloadingDiff:
[email protected]ccb4feef2013-02-14 06:16:47580 case CrxUpdateItem::kDownloading:
[email protected]e3e696d32013-06-21 20:41:36581 case CrxUpdateItem::kUpdatingDiff:
[email protected]ccb4feef2013-02-14 06:16:47582 case CrxUpdateItem::kUpdating:
583 return kInProgress;
584 // Otherwise the item was already checked a while back (or it is new),
585 // set its status to kNew to give it a slightly higher priority.
586 case CrxUpdateItem::kNew:
587 case CrxUpdateItem::kUpdated:
588 case CrxUpdateItem::kUpToDate:
589 case CrxUpdateItem::kNoUpdate:
[email protected]61aca4cd2013-10-26 10:50:59590 ChangeItemState(uit, CrxUpdateItem::kNew);
591 uit->on_demand = true;
[email protected]ccb4feef2013-02-14 06:16:47592 break;
593 case CrxUpdateItem::kLastStatus:
594 NOTREACHED() << uit->status;
595 }
596
597 // In case the current delay is long, set the timer to a shorter value
598 // to get the ball rolling.
599 if (timer_.IsRunning()) {
600 timer_.Stop();
601 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->StepDelay()),
602 this, &CrxUpdateService::ProcessPendingItems);
603 }
604
605 return kOk;
606}
607
[email protected]2e919ddd2013-08-21 05:05:17608void CrxUpdateService::GetComponents(
609 std::vector<CrxComponentInfo>* components) {
610 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
611 for (UpdateItems::const_iterator it = work_items_.begin();
612 it != work_items_.end(); ++it) {
613 const CrxUpdateItem* item = *it;
614 CrxComponentInfo info;
615 info.id = GetCrxComponentID(item->component);
616 info.version = item->component.version.GetString();
617 info.name = item->component.name;
618 components->push_back(info);
619 }
620}
621
[email protected]61aca4cd2013-10-26 10:50:59622// This is the main loop of the component updater.
[email protected]e8f96ff2011-08-03 05:07:33623void CrxUpdateService::ProcessPendingItems() {
624 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]61aca4cd2013-10-26 10:50:59625 CrxUpdateItem* ready_upgrade = FindReadyComponent();
626 if (ready_upgrade) {
627 UpdateComponent(ready_upgrade);
[email protected]e8f96ff2011-08-03 05:07:33628 return;
629 }
[email protected]2cddef42013-11-22 08:23:22630 std::string update_check_items;
631 AddUpdateCheckItems(&update_check_items);
632 if (!update_check_items.empty()) {
633 DoUpdateCheck(update_check_items);
[email protected]61aca4cd2013-10-26 10:50:59634 return;
635 }
636 // No components to update. The next check will be after a long sleep.
637 ScheduleNextRun(kStepDelayLong);
638}
639
640CrxUpdateItem* CrxUpdateService::FindReadyComponent() {
641 class Helper {
642 public:
643 static bool IsReadyOnDemand(CrxUpdateItem* item) {
644 return item->on_demand && IsReady(item);
645 }
646 static bool IsReady(CrxUpdateItem* item) {
647 return item->status == CrxUpdateItem::kCanUpdate;
648 }
649 };
650
651 std::vector<CrxUpdateItem*>::iterator it = std::find_if(
652 work_items_.begin(), work_items_.end(), Helper::IsReadyOnDemand);
653 if (it != work_items_.end())
654 return *it;
655 it = std::find_if(work_items_.begin(), work_items_.end(), Helper::IsReady);
656 if (it != work_items_.end())
657 return *it;
658 return NULL;
659}
660
661void CrxUpdateService::UpdateComponent(CrxUpdateItem* workitem) {
[email protected]afa378f22013-12-02 03:37:54662 scoped_ptr<CRXContext> crx_context(new CRXContext);
663 crx_context->pk_hash = workitem->component.pk_hash;
664 crx_context->id = workitem->id;
665 crx_context->installer = workitem->component.installer;
666 crx_context->fingerprint = workitem->next_fp;
[email protected]61aca4cd2013-10-26 10:50:59667 GURL package_url;
668 if (CanTryDiffUpdate(workitem, *config_)) {
669 package_url = workitem->diff_crx_url;
670 ChangeItemState(workitem, CrxUpdateItem::kDownloadingDiff);
671 } else {
672 package_url = workitem->crx_url;
673 ChangeItemState(workitem, CrxUpdateItem::kDownloading);
674 }
[email protected]afa378f22013-12-02 03:37:54675 crx_downloader_.reset(component_updater::CrxDownloader::Create(
676 config_->RequestContext(),
677 blocking_task_runner_,
678 base::Bind(&CrxUpdateService::DownloadComplete,
679 base::Unretained(this),
680 base::Passed(&crx_context))));
681 crx_downloader_->StartDownloadFromUrl(package_url);
[email protected]61aca4cd2013-10-26 10:50:59682}
683
[email protected]2cddef42013-11-22 08:23:22684// Sets the state of the component to be checked for updates. After the
685// function is called, the <app> element corresponding to the |item| parameter
686// is appended to the |update_check_items|.
687void CrxUpdateService::AddItemToUpdateCheck(CrxUpdateItem* item,
688 std::string* update_check_items) {
689 // The app element corresponding to an update items looks like this:
690 // <app appid="hnimpnehoodheedghdeeijklkeaacbdc"
691 // version="0.1.2.3" installsource="ondemand">
692 // <updatecheck />
693 // <packages>
694 // <package fp="abcd" />
695 // </packages>
696 // </app>
697 std::string app_attributes;
698 base::StringAppendF(&app_attributes,
699 "appid=\"%s\" version=\"%s\"",
700 item->id.c_str(),
701 item->component.version.GetString().c_str());
702 if (item->on_demand)
703 base::StringAppendF(&app_attributes, " installsource=\"ondemand\"");
704
705 std::string app;
706 if (item->component.fingerprint.empty())
707 base::StringAppendF(&app,
708 "<app %s>"
709 "<updatecheck />"
710 "</app>",
711 app_attributes.c_str());
712 else
713 base::StringAppendF(&app,
714 "<app %s>"
715 "<updatecheck />"
716 "<packages>"
717 "<package fp=\"%s\"/>"
718 "</packages>"
719 "</app>",
720 app_attributes.c_str(),
721 item->component.fingerprint.c_str());
722
723 update_check_items->append(app);
724
725 ChangeItemState(item, CrxUpdateItem::kChecking);
726 item->last_check = base::Time::Now();
727 item->crx_url = GURL();
728 item->diff_crx_url = GURL();
729 item->previous_version = item->component.version;
730 item->next_version = Version();
731 item->previous_fp = item->component.fingerprint;
732 item->next_fp.clear();
733 item->diff_update_failed = false;
734 item->error_category = 0;
735 item->error_code = 0;
736 item->extra_code1 = 0;
737 item->diff_error_category = 0;
738 item->diff_error_code = 0;
739 item->diff_extra_code1 = 0;
740}
741
742// Builds the sequence of <app> elements in the update check and returns it
743// in the |update_check_items| parameter.
744void CrxUpdateService::AddUpdateCheckItems(std::string* update_check_items) {
745 // Given that our |work_items_| list is expected to contain relatively few
746 // items, we simply loop several times.
[email protected]d63306d2013-06-29 13:56:02747 for (UpdateItems::const_iterator it = work_items_.begin();
748 it != work_items_.end(); ++it) {
749 CrxUpdateItem* item = *it;
750 if (item->status != CrxUpdateItem::kNew)
[email protected]dc06f0b2013-01-23 20:03:16751 continue;
[email protected]2cddef42013-11-22 08:23:22752 AddItemToUpdateCheck(item, update_check_items);
[email protected]d63306d2013-06-29 13:56:02753 }
[email protected]dc06f0b2013-01-23 20:03:16754
[email protected]d63306d2013-06-29 13:56:02755 // Next we can go back to components we already checked, here
756 // we can also batch them in a single url request, as long as
757 // we have not checked them recently.
758 const base::TimeDelta min_delta_time =
759 base::TimeDelta::FromSeconds(config_->MinimumReCheckWait());
760
761 for (UpdateItems::const_iterator it = work_items_.begin();
762 it != work_items_.end(); ++it) {
763 CrxUpdateItem* item = *it;
764 if ((item->status != CrxUpdateItem::kNoUpdate) &&
765 (item->status != CrxUpdateItem::kUpToDate))
766 continue;
767 base::TimeDelta delta = base::Time::Now() - item->last_check;
768 if (delta < min_delta_time)
769 continue;
[email protected]2cddef42013-11-22 08:23:22770 AddItemToUpdateCheck(item, update_check_items);
[email protected]d63306d2013-06-29 13:56:02771 }
772
773 // Finally, we check components that we already updated as long as
774 // we have not checked them recently.
775 for (UpdateItems::const_iterator it = work_items_.begin();
776 it != work_items_.end(); ++it) {
777 CrxUpdateItem* item = *it;
778 if (item->status != CrxUpdateItem::kUpdated)
779 continue;
780 base::TimeDelta delta = base::Time::Now() - item->last_check;
781 if (delta < min_delta_time)
782 continue;
[email protected]2cddef42013-11-22 08:23:22783 AddItemToUpdateCheck(item, update_check_items);
[email protected]d63306d2013-06-29 13:56:02784 }
[email protected]61aca4cd2013-10-26 10:50:59785}
[email protected]d63306d2013-06-29 13:56:02786
[email protected]2cddef42013-11-22 08:23:22787// Sends an update request. The |update_check_items| parameter
788// contains the sequence of <app> xml elements of the update check.
789void CrxUpdateService::DoUpdateCheck(const std::string& update_check_items) {
790 using component_updater::BuildProtocolRequest;
791 url_fetcher_.reset(component_updater::SendProtocolRequest(
792 config_->UpdateUrl(),
793 BuildProtocolRequest(update_check_items),
794 MakeContextDelegate(this, new UpdateContext()),
795 config_->RequestContext()));
[email protected]e8f96ff2011-08-03 05:07:33796}
797
[email protected]ccb4feef2013-02-14 06:16:47798// Called when we got a response from the update server. It consists of an xml
[email protected]e8f96ff2011-08-03 05:07:33799// document following the omaha update scheme.
[email protected]10c2d692012-05-11 05:32:23800void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
[email protected]07f93af12011-08-17 20:57:22801 UpdateContext* context) {
[email protected]e8f96ff2011-08-03 05:07:33802 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]afa378f22013-12-02 03:37:54803 if (component_updater::FetchSuccess(*source)) {
[email protected]e8f96ff2011-08-03 05:07:33804 std::string xml;
805 source->GetResponseAsString(&xml);
[email protected]cf442612011-08-09 20:20:12806 url_fetcher_.reset();
[email protected]6268d3a2013-11-27 01:28:09807 ParseResponse(xml);
[email protected]e8f96ff2011-08-03 05:07:33808 } else {
[email protected]cf442612011-08-09 20:20:12809 url_fetcher_.reset();
[email protected]6268d3a2013-11-27 01:28:09810 CrxUpdateService::OnParseUpdateResponseFailed("network error");
[email protected]e8f96ff2011-08-03 05:07:33811 }
[email protected]07f93af12011-08-17 20:57:22812 delete context;
[email protected]e8f96ff2011-08-03 05:07:33813}
814
[email protected]6268d3a2013-11-27 01:28:09815void CrxUpdateService::ParseResponse(const std::string& xml) {
[email protected]e8f96ff2011-08-03 05:07:33816 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]6268d3a2013-11-27 01:28:09817 component_updater::UpdateResponse update_response;
818 if (update_response.Parse(xml))
819 CrxUpdateService::OnParseUpdateResponseSucceeded(update_response.results());
[email protected]652f4272013-11-13 09:23:41820 else
[email protected]6268d3a2013-11-27 01:28:09821 CrxUpdateService::OnParseUpdateResponseFailed(update_response.errors());
[email protected]e8f96ff2011-08-03 05:07:33822}
823
824// A valid Omaha update check has arrived, from only the list of components that
825// we are currently upgrading we check for a match in which the server side
826// version is newer, if so we queue them for an upgrade. The next time we call
827// ProcessPendingItems() one of them will be drafted for the upgrade process.
[email protected]6268d3a2013-11-27 01:28:09828void CrxUpdateService::OnParseUpdateResponseSucceeded(
829 const component_updater::UpdateResponse::Results& results) {
[email protected]2cddef42013-11-22 08:23:22830 size_t num_updates_pending = 0;
[email protected]e8f96ff2011-08-03 05:07:33831 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]6268d3a2013-11-27 01:28:09832 std::vector<component_updater::UpdateResponse::Result>::const_iterator it;
[email protected]e8f96ff2011-08-03 05:07:33833 for (it = results.list.begin(); it != results.list.end(); ++it) {
834 CrxUpdateItem* crx = FindUpdateItemById(it->extension_id);
835 if (!crx)
836 continue;
837
[email protected]2cddef42013-11-22 08:23:22838 if (crx->status != CrxUpdateItem::kChecking) {
839 NOTREACHED();
[email protected]e8f96ff2011-08-03 05:07:33840 continue; // Not updating this component now.
[email protected]2cddef42013-11-22 08:23:22841 }
[email protected]e8f96ff2011-08-03 05:07:33842
[email protected]2cddef42013-11-22 08:23:22843 if (it->manifest.version.empty()) {
[email protected]cf442612011-08-09 20:20:12844 // No version means no update available.
[email protected]61aca4cd2013-10-26 10:50:59845 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
[email protected]cf442612011-08-09 20:20:12846 continue;
[email protected]e8f96ff2011-08-03 05:07:33847 }
[email protected]2cddef42013-11-22 08:23:22848
849 if (!IsVersionNewer(crx->component.version, it->manifest.version)) {
850 // The component is up to date.
[email protected]61aca4cd2013-10-26 10:50:59851 ChangeItemState(crx, CrxUpdateItem::kUpToDate);
[email protected]cf442612011-08-09 20:20:12852 continue;
[email protected]e8f96ff2011-08-03 05:07:33853 }
[email protected]2cddef42013-11-22 08:23:22854
855 if (!it->manifest.browser_min_version.empty()) {
856 if (IsVersionNewer(chrome_version_, it->manifest.browser_min_version)) {
857 // The component is not compatible with this Chrome version.
[email protected]61aca4cd2013-10-26 10:50:59858 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
[email protected]cf442612011-08-09 20:20:12859 continue;
860 }
[email protected]e8f96ff2011-08-03 05:07:33861 }
[email protected]2cddef42013-11-22 08:23:22862
863 if (it->manifest.packages.size() != 1) {
864 // Assume one and only one package per component.
865 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
866 continue;
867 }
868
869 // Parse the members of the result and queue an upgrade for this component.
870 crx->next_version = Version(it->manifest.version);
871
872 typedef component_updater::
[email protected]6268d3a2013-11-27 01:28:09873 UpdateResponse::Result::Manifest::Package Package;
[email protected]2cddef42013-11-22 08:23:22874 const Package& package(it->manifest.packages[0]);
875 crx->next_fp = package.fingerprint;
876
877 // Select the first url from the list of urls until support for
878 // fall back urls is implemented.
879 if (!it->crx_urls.empty())
880 crx->crx_url = it->crx_urls[0].Resolve(package.name);
881 if (!it->crx_diffurls.empty())
882 crx->diff_crx_url = it->crx_diffurls[0].Resolve(package.namediff);
883
[email protected]61aca4cd2013-10-26 10:50:59884 ChangeItemState(crx, CrxUpdateItem::kCanUpdate);
[email protected]2cddef42013-11-22 08:23:22885 ++num_updates_pending;
[email protected]e8f96ff2011-08-03 05:07:33886 }
[email protected]cf442612011-08-09 20:20:12887
[email protected]2cddef42013-11-22 08:23:22888 // All components that are not included in the update response are
889 // considered up to date.
[email protected]cf442612011-08-09 20:20:12890 ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kUpToDate);
891
[email protected]32a6c8382013-08-20 00:29:20892 // If there are updates pending we do a short wait, otherwise we take
893 // a longer delay until we check the components again.
[email protected]2cddef42013-11-22 08:23:22894 ScheduleNextRun(num_updates_pending > 0 ? kStepDelayShort : kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33895}
896
[email protected]6268d3a2013-11-27 01:28:09897void CrxUpdateService::OnParseUpdateResponseFailed(
[email protected]e8f96ff2011-08-03 05:07:33898 const std::string& error_message) {
899 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
900 size_t count = ChangeItemStatus(CrxUpdateItem::kChecking,
901 CrxUpdateItem::kNoUpdate);
902 DCHECK_GT(count, 0ul);
[email protected]32a6c8382013-08-20 00:29:20903 ScheduleNextRun(kStepDelayLong);
[email protected]e8f96ff2011-08-03 05:07:33904}
905
906// Called when the CRX package has been downloaded to a temporary location.
907// Here we fire the notifications and schedule the component-specific installer
908// to be called in the file thread.
[email protected]afa378f22013-12-02 03:37:54909void CrxUpdateService::DownloadComplete(scoped_ptr<CRXContext> crx_context,
910 int error,
911 const base::FilePath& temp_crx_path) {
[email protected]e8f96ff2011-08-03 05:07:33912 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]64f39fa12013-09-03 21:49:37913
[email protected]64f39fa12013-09-03 21:49:37914 CrxUpdateItem* crx = FindUpdateItemById(crx_context->id);
[email protected]e3e696d32013-06-21 20:41:36915 DCHECK(crx->status == CrxUpdateItem::kDownloadingDiff ||
916 crx->status == CrxUpdateItem::kDownloading);
917
[email protected]afa378f22013-12-02 03:37:54918 if (error) {
[email protected]e3e696d32013-06-21 20:41:36919 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
[email protected]7b0529242013-07-20 05:45:46920 crx->diff_error_category = kNetworkError;
[email protected]afa378f22013-12-02 03:37:54921 crx->diff_error_code = error;
[email protected]e630ba62013-06-22 15:22:34922 crx->diff_update_failed = true;
[email protected]e3e696d32013-06-21 20:41:36923 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
924 CrxUpdateItem::kCanUpdate);
925 DCHECK_EQ(count, 1ul);
[email protected]afa378f22013-12-02 03:37:54926 crx_downloader_.reset();
[email protected]7b0529242013-07-20 05:45:46927
[email protected]32a6c8382013-08-20 00:29:20928 ScheduleNextRun(kStepDelayShort);
[email protected]e3e696d32013-06-21 20:41:36929 return;
930 }
[email protected]7b0529242013-07-20 05:45:46931 crx->error_category = kNetworkError;
[email protected]afa378f22013-12-02 03:37:54932 crx->error_code = error;
[email protected]e8f96ff2011-08-03 05:07:33933 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
934 CrxUpdateItem::kNoUpdate);
935 DCHECK_EQ(count, 1ul);
[email protected]afa378f22013-12-02 03:37:54936 crx_downloader_.reset();
[email protected]e3e696d32013-06-21 20:41:36937
[email protected]7b0529242013-07-20 05:45:46938 // At this point, since both the differential and the full downloads failed,
939 // the update for this component has finished with an error.
940 ping_manager_->OnUpdateComplete(crx);
941
[email protected]32a6c8382013-08-20 00:29:20942 // Move on to the next update, if there is one available.
943 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33944 } else {
[email protected]e3e696d32013-06-21 20:41:36945 size_t count = 0;
946 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
947 count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
948 CrxUpdateItem::kUpdatingDiff);
949 } else {
950 count = ChangeItemStatus(CrxUpdateItem::kDownloading,
951 CrxUpdateItem::kUpdating);
952 }
[email protected]e8f96ff2011-08-03 05:07:33953 DCHECK_EQ(count, 1ul);
[email protected]e3e696d32013-06-21 20:41:36954
[email protected]afa378f22013-12-02 03:37:54955 crx_downloader_.reset();
[email protected]cf442612011-08-09 20:20:12956
[email protected]44da56e2011-11-21 19:59:14957 // Why unretained? See comment at top of file.
[email protected]8f5f2ea2013-10-31 09:39:10958 blocking_task_runner_->PostDelayedTask(
[email protected]73251e72012-03-04 02:10:33959 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14960 base::Bind(&CrxUpdateService::Install,
961 base::Unretained(this),
[email protected]afa378f22013-12-02 03:37:54962 base::Passed(&crx_context),
[email protected]44da56e2011-11-21 19:59:14963 temp_crx_path),
[email protected]73251e72012-03-04 02:10:33964 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]e8f96ff2011-08-03 05:07:33965 }
[email protected]e8f96ff2011-08-03 05:07:33966}
967
968// Install consists of digital signature verification, unpacking and then
969// calling the component specific installer. All that is handled by the
970// |unpacker|. If there is an error this function is in charge of deleting
971// the files created.
[email protected]afa378f22013-12-02 03:37:54972void CrxUpdateService::Install(scoped_ptr<CRXContext> context,
[email protected]650b2d52013-02-10 03:41:45973 const base::FilePath& crx_path) {
[email protected]8f5f2ea2013-10-31 09:39:10974 // This function owns the file at |crx_path| and the |context| object.
[email protected]e3e696d32013-06-21 20:41:36975 ComponentUnpacker unpacker(context->pk_hash,
976 crx_path,
977 context->fingerprint,
978 component_patcher_.get(),
979 context->installer);
[email protected]dd3aa792013-07-16 19:10:23980 if (!base::DeleteFile(crx_path, false))
[email protected]e8f96ff2011-08-03 05:07:33981 NOTREACHED() << crx_path.value();
[email protected]44da56e2011-11-21 19:59:14982 // Why unretained? See comment at top of file.
[email protected]73251e72012-03-04 02:10:33983 BrowserThread::PostDelayedTask(
984 BrowserThread::UI,
985 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14986 base::Bind(&CrxUpdateService::DoneInstalling, base::Unretained(this),
[email protected]e3e696d32013-06-21 20:41:36987 context->id, unpacker.error(), unpacker.extended_error()),
[email protected]73251e72012-03-04 02:10:33988 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]e8f96ff2011-08-03 05:07:33989}
990
991// Installation has been completed. Adjust the component status and
[email protected]7b0529242013-07-20 05:45:46992// schedule the next check. Schedule a short delay before trying the full
993// update when the differential update failed.
[email protected]07f93af12011-08-17 20:57:22994void CrxUpdateService::DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:36995 ComponentUnpacker::Error error,
996 int extra_code) {
[email protected]e8f96ff2011-08-03 05:07:33997 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]07f93af12011-08-17 20:57:22998
[email protected]7b0529242013-07-20 05:45:46999 ErrorCategory error_category = kErrorNone;
1000 switch (error) {
1001 case ComponentUnpacker::kNone:
1002 break;
1003 case ComponentUnpacker::kInstallerError:
1004 error_category = kInstallError;
1005 break;
1006 default:
1007 error_category = kUnpackError;
1008 break;
1009 }
1010
1011 const bool is_success = error == ComponentUnpacker::kNone;
1012
[email protected]07f93af12011-08-17 20:57:221013 CrxUpdateItem* item = FindUpdateItemById(component_id);
[email protected]7b0529242013-07-20 05:45:461014 if (item->status == CrxUpdateItem::kUpdatingDiff && !is_success) {
1015 item->diff_error_category = error_category;
1016 item->diff_error_code = error;
1017 item->diff_extra_code1 = extra_code;
[email protected]1ea21ad2013-09-02 04:20:391018 item->diff_update_failed = true;
1019 size_t count = ChangeItemStatus(CrxUpdateItem::kUpdatingDiff,
1020 CrxUpdateItem::kCanUpdate);
1021 DCHECK_EQ(count, 1ul);
1022 ScheduleNextRun(kStepDelayShort);
1023 return;
[email protected]e3e696d32013-06-21 20:41:361024 }
[email protected]e3e696d32013-06-21 20:41:361025
[email protected]7b0529242013-07-20 05:45:461026 if (is_success) {
[email protected]61aca4cd2013-10-26 10:50:591027 ChangeItemState(item, CrxUpdateItem::kUpdated);
[email protected]07f93af12011-08-17 20:57:221028 item->component.version = item->next_version;
[email protected]e3e696d32013-06-21 20:41:361029 item->component.fingerprint = item->next_fp;
[email protected]7b0529242013-07-20 05:45:461030 } else {
[email protected]61aca4cd2013-10-26 10:50:591031 ChangeItemState(item, CrxUpdateItem::kNoUpdate);
[email protected]7b0529242013-07-20 05:45:461032 item->error_category = error_category;
1033 item->error_code = error;
1034 item->extra_code1 = extra_code;
[email protected]e3e696d32013-06-21 20:41:361035 }
[email protected]07f93af12011-08-17 20:57:221036
[email protected]7b0529242013-07-20 05:45:461037 ping_manager_->OnUpdateComplete(item);
[email protected]360b8bb2011-09-01 21:48:061038
[email protected]32a6c8382013-08-20 00:29:201039 // Move on to the next update, if there is one available.
1040 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:331041}
1042
[email protected]85e61d52013-08-01 22:23:421043void CrxUpdateService::NotifyComponentObservers(
1044 ComponentObserver::Events event, int extra) const {
1045 for (UpdateItems::const_iterator it = work_items_.begin();
1046 it != work_items_.end(); ++it) {
1047 ComponentObserver* observer = (*it)->component.observer;
1048 if (observer)
1049 observer->OnEvent(event, 0);
1050 }
1051}
1052
[email protected]00a77fa2013-11-02 04:18:461053content::ResourceThrottle* CrxUpdateService::GetOnDemandResourceThrottle(
1054 net::URLRequest* request, const std::string& crx_id) {
1055 // We give the raw pointer to the caller, who will delete it at will
1056 // and we keep for ourselves a weak pointer to it so we can post tasks
1057 // from the UI thread without having to track lifetime directly.
1058 CUResourceThrottle* rt = new CUResourceThrottle(request);
1059 BrowserThread::PostTask(
1060 BrowserThread::UI,
1061 FROM_HERE,
1062 base::Bind(&CrxUpdateService::OnNewResourceThrottle,
1063 base::Unretained(this),
1064 rt->AsWeakPtr(),
1065 crx_id));
1066 return rt;
1067}
1068
1069void CrxUpdateService::OnNewResourceThrottle(
1070 base::WeakPtr<CUResourceThrottle> rt, const std::string& crx_id) {
1071 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1072 // Check if we can on-demand update, else unblock the request anyway.
1073 CrxUpdateItem* item = FindUpdateItemById(crx_id);
1074 Status status = OnDemandUpdateInternal(item);
1075 if (status == kOk || status == kInProgress) {
1076 item->throttles.push_back(rt);
1077 return;
1078 }
1079 UnblockResourceThrottle(rt);
1080}
1081
1082///////////////////////////////////////////////////////////////////////////////
1083
1084CUResourceThrottle::CUResourceThrottle(const net::URLRequest* request)
1085 : state_(NEW) {
1086 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1087}
1088
1089CUResourceThrottle::~CUResourceThrottle() {
1090 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1091}
1092
1093void CUResourceThrottle::WillStartRequest(bool* defer) {
1094 if (state_ != UNBLOCKED) {
1095 state_ = BLOCKED;
1096 *defer = true;
1097 } else {
1098 *defer = false;
1099 }
1100}
1101
1102void CUResourceThrottle::WillRedirectRequest(const GURL& new_url, bool* defer) {
1103 WillStartRequest(defer);
1104}
1105
1106void CUResourceThrottle::Unblock() {
1107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1108 if (state_ == BLOCKED)
1109 controller()->Resume();
1110 state_ = UNBLOCKED;
1111}
1112
[email protected]e8f96ff2011-08-03 05:07:331113// The component update factory. Using the component updater as a singleton
1114// is the job of the browser process.
1115ComponentUpdateService* ComponentUpdateServiceFactory(
1116 ComponentUpdateService::Configurator* config) {
1117 DCHECK(config);
1118 return new CrxUpdateService(config);
1119}
[email protected]2cddef42013-11-22 08:23:221120