blob: 927f32a8f6fe43a4a1cf6e2a03c194c53fb25fab [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;
[email protected]f8fe5cf2013-12-04 20:11:53171 virtual const char* GetNameForLogging() const OVERRIDE;
[email protected]00a77fa2013-11-02 04:18:46172
173 // Component updater calls this function via PostTask to unblock the request.
174 void Unblock();
175
176 typedef std::vector<base::WeakPtr<CUResourceThrottle> > WeakPtrVector;
177
178 private:
[email protected]2cddef42013-11-22 08:23:22179 enum State {
180 NEW,
181 BLOCKED,
182 UNBLOCKED
183 };
[email protected]00a77fa2013-11-02 04:18:46184
[email protected]2cddef42013-11-22 08:23:22185 State state_;
[email protected]00a77fa2013-11-02 04:18:46186};
187
188void UnblockResourceThrottle(base::WeakPtr<CUResourceThrottle> rt) {
189 BrowserThread::PostTask(
190 BrowserThread::IO,
191 FROM_HERE,
192 base::Bind(&CUResourceThrottle::Unblock, rt));
193}
194
195void UnblockandReapAllThrottles(CUResourceThrottle::WeakPtrVector* throttles) {
196 CUResourceThrottle::WeakPtrVector::iterator it;
197 for (it = throttles->begin(); it != throttles->end(); ++it)
198 UnblockResourceThrottle(*it);
199 throttles->clear();
200}
201
[email protected]e8f96ff2011-08-03 05:07:33202//////////////////////////////////////////////////////////////////////////////
203// The one and only implementation of the ComponentUpdateService interface. In
204// charge of running the show. The main method is ProcessPendingItems() which
[email protected]50b01392012-09-01 03:33:13205// is called periodically to do the upgrades/installs or the update checks.
[email protected]e8f96ff2011-08-03 05:07:33206// An important consideration here is to be as "low impact" as we can to the
207// rest of the browser, so even if we have many components registered and
[email protected]f1050432012-02-15 01:35:46208// eligible for update, we only do one thing at a time with pauses in between
[email protected]e8f96ff2011-08-03 05:07:33209// the tasks. Also when we do network requests there is only one |url_fetcher_|
[email protected]e3e696d32013-06-21 20:41:36210// in flight at a time.
[email protected]e8f96ff2011-08-03 05:07:33211// There are no locks in this code, the main structure |work_items_| is mutated
212// only from the UI thread. The unpack and installation is done in the file
213// thread and the network requests are done in the IO thread and in the file
214// thread.
215class CrxUpdateService : public ComponentUpdateService {
216 public:
217 explicit CrxUpdateService(ComponentUpdateService::Configurator* config);
[email protected]e8f96ff2011-08-03 05:07:33218 virtual ~CrxUpdateService();
219
220 // Overrides for ComponentUpdateService.
221 virtual Status Start() OVERRIDE;
222 virtual Status Stop() OVERRIDE;
223 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE;
[email protected]61aca4cd2013-10-26 10:50:59224 virtual Status OnDemandUpdate(const std::string& component_id) OVERRIDE;
[email protected]2e919ddd2013-08-21 05:05:17225 virtual void GetComponents(
226 std::vector<CrxComponentInfo>* components) OVERRIDE;
[email protected]00a77fa2013-11-02 04:18:46227 virtual content::ResourceThrottle* GetOnDemandResourceThrottle(
228 net::URLRequest* request, const std::string& crx_id) OVERRIDE;
[email protected]e8f96ff2011-08-03 05:07:33229
[email protected]e8f96ff2011-08-03 05:07:33230 // Context for a update check url request. See DelegateWithContext above.
231 struct UpdateContext {
232 base::Time start;
233 UpdateContext() : start(base::Time::Now()) {}
234 };
235
236 // Context for a crx download url request. See DelegateWithContext above.
237 struct CRXContext {
238 ComponentInstaller* installer;
239 std::vector<uint8> pk_hash;
240 std::string id;
[email protected]e3e696d32013-06-21 20:41:36241 std::string fingerprint;
[email protected]e8f96ff2011-08-03 05:07:33242 CRXContext() : installer(NULL) {}
243 };
244
[email protected]10c2d692012-05-11 05:32:23245 void OnURLFetchComplete(const net::URLFetcher* source,
[email protected]7cc6e5632011-10-25 17:56:12246 UpdateContext* context);
[email protected]e8f96ff2011-08-03 05:07:33247
[email protected]e8f96ff2011-08-03 05:07:33248 private:
[email protected]7b0529242013-07-20 05:45:46249 enum ErrorCategory {
250 kErrorNone = 0,
251 kNetworkError,
252 kUnpackError,
253 kInstallError,
254 };
255
[email protected]32a6c8382013-08-20 00:29:20256 enum StepDelayInterval {
257 kStepDelayShort = 0,
258 kStepDelayMedium,
259 kStepDelayLong,
260 };
261
[email protected]6268d3a2013-11-27 01:28:09262 void OnParseUpdateResponseSucceeded(
263 const component_updater::UpdateResponse::Results& results);
264 void OnParseUpdateResponseFailed(const std::string& error_message);
[email protected]e8f96ff2011-08-03 05:07:33265
[email protected]3cb2a4f2013-12-07 21:54:34266 void DownloadComplete(
267 scoped_ptr<CRXContext> crx_context,
268 const component_updater::CrxDownloader::Result& download_result);
[email protected]afa378f22013-12-02 03:37:54269
[email protected]00a77fa2013-11-02 04:18:46270 Status OnDemandUpdateInternal(CrxUpdateItem* item);
271
[email protected]e8f96ff2011-08-03 05:07:33272 void ProcessPendingItems();
273
[email protected]61aca4cd2013-10-26 10:50:59274 CrxUpdateItem* FindReadyComponent();
275
276 void UpdateComponent(CrxUpdateItem* workitem);
277
[email protected]2cddef42013-11-22 08:23:22278 void AddItemToUpdateCheck(CrxUpdateItem* item,
279 std::string* update_check_items);
[email protected]61aca4cd2013-10-26 10:50:59280
[email protected]2cddef42013-11-22 08:23:22281 void AddUpdateCheckItems(std::string* update_check_items);
282
283 void DoUpdateCheck(const std::string& update_check_items);
[email protected]61aca4cd2013-10-26 10:50:59284
[email protected]32a6c8382013-08-20 00:29:20285 void ScheduleNextRun(StepDelayInterval step_delay);
[email protected]e8f96ff2011-08-03 05:07:33286
[email protected]6268d3a2013-11-27 01:28:09287 void ParseResponse(const std::string& xml);
[email protected]e8f96ff2011-08-03 05:07:33288
[email protected]afa378f22013-12-02 03:37:54289 void Install(scoped_ptr<CRXContext> context, const base::FilePath& crx_path);
[email protected]e8f96ff2011-08-03 05:07:33290
[email protected]07f93af12011-08-17 20:57:22291 void DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:36292 ComponentUnpacker::Error error,
293 int extended_error);
[email protected]e8f96ff2011-08-03 05:07:33294
[email protected]61aca4cd2013-10-26 10:50:59295 void ChangeItemState(CrxUpdateItem* item, CrxUpdateItem::Status to);
296
[email protected]e8f96ff2011-08-03 05:07:33297 size_t ChangeItemStatus(CrxUpdateItem::Status from,
298 CrxUpdateItem::Status to);
299
300 CrxUpdateItem* FindUpdateItemById(const std::string& id);
301
[email protected]85e61d52013-08-01 22:23:42302 void NotifyComponentObservers(ComponentObserver::Events event,
303 int extra) const;
304
[email protected]61aca4cd2013-10-26 10:50:59305 bool HasOnDemandItems() const;
306
[email protected]00a77fa2013-11-02 04:18:46307 void OnNewResourceThrottle(base::WeakPtr<CUResourceThrottle> rt,
308 const std::string& crx_id);
309
[email protected]e3e696d32013-06-21 20:41:36310 scoped_ptr<ComponentUpdateService::Configurator> config_;
311
312 scoped_ptr<ComponentPatcher> component_patcher_;
[email protected]e8f96ff2011-08-03 05:07:33313
[email protected]d3ec669b2012-05-23 07:12:14314 scoped_ptr<net::URLFetcher> url_fetcher_;
[email protected]e8f96ff2011-08-03 05:07:33315
[email protected]7b0529242013-07-20 05:45:46316 scoped_ptr<component_updater::PingManager> ping_manager_;
317
[email protected]afa378f22013-12-02 03:37:54318 scoped_ptr<component_updater::CrxDownloader> crx_downloader_;
319
[email protected]86550a42013-06-21 15:20:49320 // A collection of every work item.
[email protected]e3e696d32013-06-21 20:41:36321 typedef std::vector<CrxUpdateItem*> UpdateItems;
[email protected]e8f96ff2011-08-03 05:07:33322 UpdateItems work_items_;
323
324 base::OneShotTimer<CrxUpdateService> timer_;
325
[email protected]8f5f2ea2013-10-31 09:39:10326 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
327
[email protected]e3e696d32013-06-21 20:41:36328 const Version chrome_version_;
[email protected]e8f96ff2011-08-03 05:07:33329
330 bool running_;
331
332 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
333};
334
[email protected]e8f96ff2011-08-03 05:07:33335//////////////////////////////////////////////////////////////////////////////
336
[email protected]e3e696d32013-06-21 20:41:36337CrxUpdateService::CrxUpdateService(ComponentUpdateService::Configurator* config)
[email protected]e8f96ff2011-08-03 05:07:33338 : config_(config),
[email protected]e3e696d32013-06-21 20:41:36339 component_patcher_(config->CreateComponentPatcher()),
[email protected]7b0529242013-07-20 05:45:46340 ping_manager_(new component_updater::PingManager(
341 config->PingUrl(),
342 config->RequestContext())),
[email protected]8f5f2ea2013-10-31 09:39:10343 blocking_task_runner_(BrowserThread::GetBlockingPool()->
344 GetSequencedTaskRunnerWithShutdownBehavior(
345 BrowserThread::GetBlockingPool()->GetSequenceToken(),
346 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)),
[email protected]e8f96ff2011-08-03 05:07:33347 chrome_version_(chrome::VersionInfo().Version()),
348 running_(false) {
[email protected]1ea21ad2013-09-02 04:20:39349}
[email protected]e8f96ff2011-08-03 05:07:33350
351CrxUpdateService::~CrxUpdateService() {
352 // Because we are a singleton, at this point only the UI thread should be
353 // alive, this simplifies the management of the work that could be in
354 // flight in other threads.
355 Stop();
356 STLDeleteElements(&work_items_);
[email protected]1ea21ad2013-09-02 04:20:39357}
[email protected]e8f96ff2011-08-03 05:07:33358
359ComponentUpdateService::Status CrxUpdateService::Start() {
360 // Note that RegisterComponent will call Start() when the first
361 // component is registered, so it can be called twice. This way
362 // we avoid scheduling the timer if there is no work to do.
363 running_ = true;
364 if (work_items_.empty())
365 return kOk;
366
[email protected]85e61d52013-08-01 22:23:42367 NotifyComponentObservers(ComponentObserver::COMPONENT_UPDATER_STARTED, 0);
368
[email protected]d323a172011-09-02 18:23:02369 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->InitialDelay()),
[email protected]e8f96ff2011-08-03 05:07:33370 this, &CrxUpdateService::ProcessPendingItems);
371 return kOk;
372}
373
374// Stop the main check + update loop. In flight operations will be
375// completed.
376ComponentUpdateService::Status CrxUpdateService::Stop() {
377 running_ = false;
378 timer_.Stop();
379 return kOk;
380}
381
[email protected]61aca4cd2013-10-26 10:50:59382bool CrxUpdateService::HasOnDemandItems() const {
383 class Helper {
384 public:
385 static bool IsOnDemand(CrxUpdateItem* item) {
386 return item->on_demand;
387 }
388 };
389 return std::find_if(work_items_.begin(),
390 work_items_.end(),
391 Helper::IsOnDemand) != work_items_.end();
392}
393
[email protected]ccb4feef2013-02-14 06:16:47394// This function sets the timer which will call ProcessPendingItems() or
[email protected]61aca4cd2013-10-26 10:50:59395// ProcessRequestedItem() if there is an on_demand item. There
[email protected]32a6c8382013-08-20 00:29:20396// are three kinds of waits:
397// - a short delay, when there is immediate work to be done.
398// - a medium delay, when there are updates to be applied within the current
399// update cycle, or there are components that are still unchecked.
400// - a long delay when a full check/update cycle has completed for all
401// components.
402void CrxUpdateService::ScheduleNextRun(StepDelayInterval step_delay) {
[email protected]e8f96ff2011-08-03 05:07:33403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cf442612011-08-09 20:20:12404 DCHECK(url_fetcher_.get() == NULL);
[email protected]e8f96ff2011-08-03 05:07:33405 CHECK(!timer_.IsRunning());
406 // It could be the case that Stop() had been called while a url request
407 // or unpacking was in flight, if so we arrive here but |running_| is
408 // false. In that case do not loop again.
409 if (!running_)
410 return;
411
[email protected]ccb4feef2013-02-14 06:16:47412 // Keep the delay short if in the middle of an update (step_delay),
413 // or there are new requested_work_items_ that have not been processed yet.
[email protected]32a6c8382013-08-20 00:29:20414 int64 delay_seconds = 0;
[email protected]61aca4cd2013-10-26 10:50:59415 if (!HasOnDemandItems()) {
[email protected]32a6c8382013-08-20 00:29:20416 switch (step_delay) {
417 case kStepDelayShort:
418 delay_seconds = config_->StepDelay();
419 break;
420 case kStepDelayMedium:
421 delay_seconds = config_->StepDelayMedium();
422 break;
423 case kStepDelayLong:
424 delay_seconds = config_->NextCheckDelay();
425 break;
426 }
427 } else {
428 delay_seconds = config_->StepDelay();
429 }
[email protected]cf442612011-08-09 20:20:12430
[email protected]32a6c8382013-08-20 00:29:20431 if (step_delay != kStepDelayShort) {
[email protected]85e61d52013-08-01 22:23:42432 NotifyComponentObservers(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0);
433
[email protected]e8f96ff2011-08-03 05:07:33434 // Zero is only used for unit tests.
[email protected]32a6c8382013-08-20 00:29:20435 if (0 == delay_seconds)
[email protected]e8f96ff2011-08-03 05:07:33436 return;
437 }
438
[email protected]32a6c8382013-08-20 00:29:20439 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay_seconds),
[email protected]e8f96ff2011-08-03 05:07:33440 this, &CrxUpdateService::ProcessPendingItems);
441}
442
443// Given a extension-like component id, find the associated component.
444CrxUpdateItem* CrxUpdateService::FindUpdateItemById(const std::string& id) {
445 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
446 CrxUpdateItem::FindById finder(id);
447 UpdateItems::iterator it = std::find_if(work_items_.begin(),
448 work_items_.end(),
449 finder);
450 if (it == work_items_.end())
451 return NULL;
452 return (*it);
453}
454
[email protected]61aca4cd2013-10-26 10:50:59455// Changes a component's status, clearing on_demand and firing notifications as
456// necessary. By convention, this is the only function that can change a
457// CrxUpdateItem's |status|.
458// TODO(waffles): Do we want to add DCHECKS for valid state transitions here?
459void CrxUpdateService::ChangeItemState(CrxUpdateItem* item,
460 CrxUpdateItem::Status to) {
461 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
462 if (to == CrxUpdateItem::kNoUpdate ||
463 to == CrxUpdateItem::kUpdated ||
464 to == CrxUpdateItem::kUpToDate) {
465 item->on_demand = false;
466 }
467
468 item->status = to;
469
470 ComponentObserver* observer = item->component.observer;
471 if (observer) {
472 switch (to) {
473 case CrxUpdateItem::kCanUpdate:
474 observer->OnEvent(ComponentObserver::COMPONENT_UPDATE_FOUND, 0);
475 break;
476 case CrxUpdateItem::kUpdatingDiff:
477 case CrxUpdateItem::kUpdating:
478 observer->OnEvent(ComponentObserver::COMPONENT_UPDATE_READY, 0);
479 break;
480 case CrxUpdateItem::kUpdated:
481 observer->OnEvent(ComponentObserver::COMPONENT_UPDATED, 0);
482 break;
483 case CrxUpdateItem::kUpToDate:
484 case CrxUpdateItem::kNoUpdate:
485 observer->OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0);
486 break;
487 case CrxUpdateItem::kNew:
488 case CrxUpdateItem::kChecking:
489 case CrxUpdateItem::kDownloading:
490 case CrxUpdateItem::kDownloadingDiff:
491 case CrxUpdateItem::kLastStatus:
492 // No notification for these states.
493 break;
494 }
495 }
[email protected]00a77fa2013-11-02 04:18:46496
497 // Free possible pending network requests.
498 if ((to == CrxUpdateItem::kUpdated) ||
499 (to == CrxUpdateItem::kUpToDate) ||
500 (to == CrxUpdateItem::kNoUpdate)) {
501 UnblockandReapAllThrottles(&item->throttles);
502 }
[email protected]61aca4cd2013-10-26 10:50:59503}
504
[email protected]e8f96ff2011-08-03 05:07:33505// Changes all the components in |work_items_| that have |from| status to
[email protected]e3e696d32013-06-21 20:41:36506// |to| status and returns how many have been changed.
[email protected]e8f96ff2011-08-03 05:07:33507size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from,
508 CrxUpdateItem::Status to) {
509 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
510 size_t count = 0;
511 for (UpdateItems::iterator it = work_items_.begin();
512 it != work_items_.end(); ++it) {
513 CrxUpdateItem* item = *it;
514 if (item->status != from)
515 continue;
[email protected]61aca4cd2013-10-26 10:50:59516 ChangeItemState(item, to);
[email protected]e8f96ff2011-08-03 05:07:33517 ++count;
518 }
519 return count;
520}
521
522// Adds a component to be checked for upgrades. If the component exists it
523// it will be replaced and the return code is kReplaced.
524//
525// TODO(cpu): Evaluate if we want to support un-registration.
526ComponentUpdateService::Status CrxUpdateService::RegisterComponent(
527 const CrxComponent& component) {
528 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
529 if (component.pk_hash.empty() ||
530 !component.version.IsValid() ||
531 !component.installer)
532 return kError;
533
534 std::string id =
535 HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
536 component.pk_hash.size()/2)));
537 CrxUpdateItem* uit;
538 uit = FindUpdateItemById(id);
539 if (uit) {
540 uit->component = component;
541 return kReplaced;
542 }
543
544 uit = new CrxUpdateItem;
545 uit->id.swap(id);
546 uit->component = component;
[email protected]e3e696d32013-06-21 20:41:36547
[email protected]e8f96ff2011-08-03 05:07:33548 work_items_.push_back(uit);
549 // If this is the first component registered we call Start to
550 // schedule the first timer.
551 if (running_ && (work_items_.size() == 1))
552 Start();
553
554 return kOk;
555}
556
[email protected]ccb4feef2013-02-14 06:16:47557// Start the process of checking for an update, for a particular component
558// that was previously registered.
[email protected]2e919ddd2013-08-21 05:05:17559// |component_id| is a value returned from GetCrxComponentID().
[email protected]61aca4cd2013-10-26 10:50:59560ComponentUpdateService::Status CrxUpdateService::OnDemandUpdate(
[email protected]2e919ddd2013-08-21 05:05:17561 const std::string& component_id) {
[email protected]00a77fa2013-11-02 04:18:46562 return OnDemandUpdateInternal(FindUpdateItemById(component_id));
563}
564
565ComponentUpdateService::Status CrxUpdateService::OnDemandUpdateInternal(
566 CrxUpdateItem* uit) {
[email protected]ccb4feef2013-02-14 06:16:47567 if (!uit)
568 return kError;
[email protected]2cddef42013-11-22 08:23:22569
[email protected]ccb4feef2013-02-14 06:16:47570 // Check if the request is too soon.
571 base::TimeDelta delta = base::Time::Now() - uit->last_check;
[email protected]e3e696d32013-06-21 20:41:36572 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
[email protected]ccb4feef2013-02-14 06:16:47573 return kError;
[email protected]ccb4feef2013-02-14 06:16:47574
575 switch (uit->status) {
576 // If the item is already in the process of being updated, there is
577 // no point in this call, so return kInProgress.
578 case CrxUpdateItem::kChecking:
579 case CrxUpdateItem::kCanUpdate:
[email protected]e3e696d32013-06-21 20:41:36580 case CrxUpdateItem::kDownloadingDiff:
[email protected]ccb4feef2013-02-14 06:16:47581 case CrxUpdateItem::kDownloading:
[email protected]e3e696d32013-06-21 20:41:36582 case CrxUpdateItem::kUpdatingDiff:
[email protected]ccb4feef2013-02-14 06:16:47583 case CrxUpdateItem::kUpdating:
584 return kInProgress;
585 // Otherwise the item was already checked a while back (or it is new),
586 // set its status to kNew to give it a slightly higher priority.
587 case CrxUpdateItem::kNew:
588 case CrxUpdateItem::kUpdated:
589 case CrxUpdateItem::kUpToDate:
590 case CrxUpdateItem::kNoUpdate:
[email protected]61aca4cd2013-10-26 10:50:59591 ChangeItemState(uit, CrxUpdateItem::kNew);
592 uit->on_demand = true;
[email protected]ccb4feef2013-02-14 06:16:47593 break;
594 case CrxUpdateItem::kLastStatus:
595 NOTREACHED() << uit->status;
596 }
597
598 // In case the current delay is long, set the timer to a shorter value
599 // to get the ball rolling.
600 if (timer_.IsRunning()) {
601 timer_.Stop();
602 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->StepDelay()),
603 this, &CrxUpdateService::ProcessPendingItems);
604 }
605
606 return kOk;
607}
608
[email protected]2e919ddd2013-08-21 05:05:17609void CrxUpdateService::GetComponents(
610 std::vector<CrxComponentInfo>* components) {
611 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
612 for (UpdateItems::const_iterator it = work_items_.begin();
613 it != work_items_.end(); ++it) {
614 const CrxUpdateItem* item = *it;
615 CrxComponentInfo info;
616 info.id = GetCrxComponentID(item->component);
617 info.version = item->component.version.GetString();
618 info.name = item->component.name;
619 components->push_back(info);
620 }
621}
622
[email protected]61aca4cd2013-10-26 10:50:59623// This is the main loop of the component updater.
[email protected]e8f96ff2011-08-03 05:07:33624void CrxUpdateService::ProcessPendingItems() {
625 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]61aca4cd2013-10-26 10:50:59626 CrxUpdateItem* ready_upgrade = FindReadyComponent();
627 if (ready_upgrade) {
628 UpdateComponent(ready_upgrade);
[email protected]e8f96ff2011-08-03 05:07:33629 return;
630 }
[email protected]2cddef42013-11-22 08:23:22631 std::string update_check_items;
632 AddUpdateCheckItems(&update_check_items);
633 if (!update_check_items.empty()) {
634 DoUpdateCheck(update_check_items);
[email protected]61aca4cd2013-10-26 10:50:59635 return;
636 }
637 // No components to update. The next check will be after a long sleep.
638 ScheduleNextRun(kStepDelayLong);
639}
640
641CrxUpdateItem* CrxUpdateService::FindReadyComponent() {
642 class Helper {
643 public:
644 static bool IsReadyOnDemand(CrxUpdateItem* item) {
645 return item->on_demand && IsReady(item);
646 }
647 static bool IsReady(CrxUpdateItem* item) {
648 return item->status == CrxUpdateItem::kCanUpdate;
649 }
650 };
651
652 std::vector<CrxUpdateItem*>::iterator it = std::find_if(
653 work_items_.begin(), work_items_.end(), Helper::IsReadyOnDemand);
654 if (it != work_items_.end())
655 return *it;
656 it = std::find_if(work_items_.begin(), work_items_.end(), Helper::IsReady);
657 if (it != work_items_.end())
658 return *it;
659 return NULL;
660}
661
662void CrxUpdateService::UpdateComponent(CrxUpdateItem* workitem) {
[email protected]afa378f22013-12-02 03:37:54663 scoped_ptr<CRXContext> crx_context(new CRXContext);
664 crx_context->pk_hash = workitem->component.pk_hash;
665 crx_context->id = workitem->id;
666 crx_context->installer = workitem->component.installer;
667 crx_context->fingerprint = workitem->next_fp;
[email protected]61aca4cd2013-10-26 10:50:59668 GURL package_url;
669 if (CanTryDiffUpdate(workitem, *config_)) {
670 package_url = workitem->diff_crx_url;
671 ChangeItemState(workitem, CrxUpdateItem::kDownloadingDiff);
672 } else {
673 package_url = workitem->crx_url;
674 ChangeItemState(workitem, CrxUpdateItem::kDownloading);
675 }
[email protected]3cb2a4f2013-12-07 21:54:34676
677 // On demand component updates are always downloaded in foreground.
678 const bool is_background_download = !workitem->on_demand &&
679 config_->UseBackgroundDownloader();
680
[email protected]afa378f22013-12-02 03:37:54681 crx_downloader_.reset(component_updater::CrxDownloader::Create(
[email protected]3cb2a4f2013-12-07 21:54:34682 is_background_download,
[email protected]afa378f22013-12-02 03:37:54683 config_->RequestContext(),
684 blocking_task_runner_,
685 base::Bind(&CrxUpdateService::DownloadComplete,
686 base::Unretained(this),
687 base::Passed(&crx_context))));
688 crx_downloader_->StartDownloadFromUrl(package_url);
[email protected]61aca4cd2013-10-26 10:50:59689}
690
[email protected]2cddef42013-11-22 08:23:22691// Sets the state of the component to be checked for updates. After the
692// function is called, the <app> element corresponding to the |item| parameter
693// is appended to the |update_check_items|.
694void CrxUpdateService::AddItemToUpdateCheck(CrxUpdateItem* item,
695 std::string* update_check_items) {
696 // The app element corresponding to an update items looks like this:
697 // <app appid="hnimpnehoodheedghdeeijklkeaacbdc"
698 // version="0.1.2.3" installsource="ondemand">
699 // <updatecheck />
700 // <packages>
701 // <package fp="abcd" />
702 // </packages>
703 // </app>
704 std::string app_attributes;
705 base::StringAppendF(&app_attributes,
706 "appid=\"%s\" version=\"%s\"",
707 item->id.c_str(),
708 item->component.version.GetString().c_str());
709 if (item->on_demand)
710 base::StringAppendF(&app_attributes, " installsource=\"ondemand\"");
711
712 std::string app;
713 if (item->component.fingerprint.empty())
714 base::StringAppendF(&app,
715 "<app %s>"
716 "<updatecheck />"
717 "</app>",
718 app_attributes.c_str());
719 else
720 base::StringAppendF(&app,
721 "<app %s>"
722 "<updatecheck />"
723 "<packages>"
724 "<package fp=\"%s\"/>"
725 "</packages>"
726 "</app>",
727 app_attributes.c_str(),
728 item->component.fingerprint.c_str());
729
730 update_check_items->append(app);
731
732 ChangeItemState(item, CrxUpdateItem::kChecking);
733 item->last_check = base::Time::Now();
734 item->crx_url = GURL();
735 item->diff_crx_url = GURL();
736 item->previous_version = item->component.version;
737 item->next_version = Version();
738 item->previous_fp = item->component.fingerprint;
739 item->next_fp.clear();
740 item->diff_update_failed = false;
741 item->error_category = 0;
742 item->error_code = 0;
743 item->extra_code1 = 0;
744 item->diff_error_category = 0;
745 item->diff_error_code = 0;
746 item->diff_extra_code1 = 0;
747}
748
749// Builds the sequence of <app> elements in the update check and returns it
750// in the |update_check_items| parameter.
751void CrxUpdateService::AddUpdateCheckItems(std::string* update_check_items) {
752 // Given that our |work_items_| list is expected to contain relatively few
753 // items, we simply loop several times.
[email protected]d63306d2013-06-29 13:56:02754 for (UpdateItems::const_iterator it = work_items_.begin();
755 it != work_items_.end(); ++it) {
756 CrxUpdateItem* item = *it;
757 if (item->status != CrxUpdateItem::kNew)
[email protected]dc06f0b2013-01-23 20:03:16758 continue;
[email protected]2cddef42013-11-22 08:23:22759 AddItemToUpdateCheck(item, update_check_items);
[email protected]d63306d2013-06-29 13:56:02760 }
[email protected]dc06f0b2013-01-23 20:03:16761
[email protected]d63306d2013-06-29 13:56:02762 // Next we can go back to components we already checked, here
763 // we can also batch them in a single url request, as long as
764 // we have not checked them recently.
765 const base::TimeDelta min_delta_time =
766 base::TimeDelta::FromSeconds(config_->MinimumReCheckWait());
767
768 for (UpdateItems::const_iterator it = work_items_.begin();
769 it != work_items_.end(); ++it) {
770 CrxUpdateItem* item = *it;
771 if ((item->status != CrxUpdateItem::kNoUpdate) &&
772 (item->status != CrxUpdateItem::kUpToDate))
773 continue;
774 base::TimeDelta delta = base::Time::Now() - item->last_check;
775 if (delta < min_delta_time)
776 continue;
[email protected]2cddef42013-11-22 08:23:22777 AddItemToUpdateCheck(item, update_check_items);
[email protected]d63306d2013-06-29 13:56:02778 }
779
780 // Finally, we check components that we already updated as long as
781 // we have not checked them recently.
782 for (UpdateItems::const_iterator it = work_items_.begin();
783 it != work_items_.end(); ++it) {
784 CrxUpdateItem* item = *it;
785 if (item->status != CrxUpdateItem::kUpdated)
786 continue;
787 base::TimeDelta delta = base::Time::Now() - item->last_check;
788 if (delta < min_delta_time)
789 continue;
[email protected]2cddef42013-11-22 08:23:22790 AddItemToUpdateCheck(item, update_check_items);
[email protected]d63306d2013-06-29 13:56:02791 }
[email protected]61aca4cd2013-10-26 10:50:59792}
[email protected]d63306d2013-06-29 13:56:02793
[email protected]2cddef42013-11-22 08:23:22794// Sends an update request. The |update_check_items| parameter
795// contains the sequence of <app> xml elements of the update check.
796void CrxUpdateService::DoUpdateCheck(const std::string& update_check_items) {
797 using component_updater::BuildProtocolRequest;
798 url_fetcher_.reset(component_updater::SendProtocolRequest(
799 config_->UpdateUrl(),
800 BuildProtocolRequest(update_check_items),
801 MakeContextDelegate(this, new UpdateContext()),
802 config_->RequestContext()));
[email protected]e8f96ff2011-08-03 05:07:33803}
804
[email protected]ccb4feef2013-02-14 06:16:47805// Called when we got a response from the update server. It consists of an xml
[email protected]e8f96ff2011-08-03 05:07:33806// document following the omaha update scheme.
[email protected]10c2d692012-05-11 05:32:23807void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
[email protected]07f93af12011-08-17 20:57:22808 UpdateContext* context) {
[email protected]e8f96ff2011-08-03 05:07:33809 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]afa378f22013-12-02 03:37:54810 if (component_updater::FetchSuccess(*source)) {
[email protected]e8f96ff2011-08-03 05:07:33811 std::string xml;
812 source->GetResponseAsString(&xml);
[email protected]cf442612011-08-09 20:20:12813 url_fetcher_.reset();
[email protected]6268d3a2013-11-27 01:28:09814 ParseResponse(xml);
[email protected]e8f96ff2011-08-03 05:07:33815 } else {
[email protected]cf442612011-08-09 20:20:12816 url_fetcher_.reset();
[email protected]6268d3a2013-11-27 01:28:09817 CrxUpdateService::OnParseUpdateResponseFailed("network error");
[email protected]e8f96ff2011-08-03 05:07:33818 }
[email protected]07f93af12011-08-17 20:57:22819 delete context;
[email protected]e8f96ff2011-08-03 05:07:33820}
821
[email protected]6268d3a2013-11-27 01:28:09822void CrxUpdateService::ParseResponse(const std::string& xml) {
[email protected]e8f96ff2011-08-03 05:07:33823 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]6268d3a2013-11-27 01:28:09824 component_updater::UpdateResponse update_response;
825 if (update_response.Parse(xml))
826 CrxUpdateService::OnParseUpdateResponseSucceeded(update_response.results());
[email protected]652f4272013-11-13 09:23:41827 else
[email protected]6268d3a2013-11-27 01:28:09828 CrxUpdateService::OnParseUpdateResponseFailed(update_response.errors());
[email protected]e8f96ff2011-08-03 05:07:33829}
830
831// A valid Omaha update check has arrived, from only the list of components that
832// we are currently upgrading we check for a match in which the server side
833// version is newer, if so we queue them for an upgrade. The next time we call
834// ProcessPendingItems() one of them will be drafted for the upgrade process.
[email protected]6268d3a2013-11-27 01:28:09835void CrxUpdateService::OnParseUpdateResponseSucceeded(
836 const component_updater::UpdateResponse::Results& results) {
[email protected]2cddef42013-11-22 08:23:22837 size_t num_updates_pending = 0;
[email protected]e8f96ff2011-08-03 05:07:33838 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]6268d3a2013-11-27 01:28:09839 std::vector<component_updater::UpdateResponse::Result>::const_iterator it;
[email protected]e8f96ff2011-08-03 05:07:33840 for (it = results.list.begin(); it != results.list.end(); ++it) {
841 CrxUpdateItem* crx = FindUpdateItemById(it->extension_id);
842 if (!crx)
843 continue;
844
[email protected]2cddef42013-11-22 08:23:22845 if (crx->status != CrxUpdateItem::kChecking) {
846 NOTREACHED();
[email protected]e8f96ff2011-08-03 05:07:33847 continue; // Not updating this component now.
[email protected]2cddef42013-11-22 08:23:22848 }
[email protected]e8f96ff2011-08-03 05:07:33849
[email protected]2cddef42013-11-22 08:23:22850 if (it->manifest.version.empty()) {
[email protected]cf442612011-08-09 20:20:12851 // No version means no update available.
[email protected]61aca4cd2013-10-26 10:50:59852 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
[email protected]cf442612011-08-09 20:20:12853 continue;
[email protected]e8f96ff2011-08-03 05:07:33854 }
[email protected]2cddef42013-11-22 08:23:22855
856 if (!IsVersionNewer(crx->component.version, it->manifest.version)) {
857 // The component is up to date.
[email protected]61aca4cd2013-10-26 10:50:59858 ChangeItemState(crx, CrxUpdateItem::kUpToDate);
[email protected]cf442612011-08-09 20:20:12859 continue;
[email protected]e8f96ff2011-08-03 05:07:33860 }
[email protected]2cddef42013-11-22 08:23:22861
862 if (!it->manifest.browser_min_version.empty()) {
863 if (IsVersionNewer(chrome_version_, it->manifest.browser_min_version)) {
864 // The component is not compatible with this Chrome version.
[email protected]61aca4cd2013-10-26 10:50:59865 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
[email protected]cf442612011-08-09 20:20:12866 continue;
867 }
[email protected]e8f96ff2011-08-03 05:07:33868 }
[email protected]2cddef42013-11-22 08:23:22869
870 if (it->manifest.packages.size() != 1) {
871 // Assume one and only one package per component.
872 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
873 continue;
874 }
875
876 // Parse the members of the result and queue an upgrade for this component.
877 crx->next_version = Version(it->manifest.version);
878
879 typedef component_updater::
[email protected]6268d3a2013-11-27 01:28:09880 UpdateResponse::Result::Manifest::Package Package;
[email protected]2cddef42013-11-22 08:23:22881 const Package& package(it->manifest.packages[0]);
882 crx->next_fp = package.fingerprint;
883
884 // Select the first url from the list of urls until support for
885 // fall back urls is implemented.
886 if (!it->crx_urls.empty())
887 crx->crx_url = it->crx_urls[0].Resolve(package.name);
888 if (!it->crx_diffurls.empty())
889 crx->diff_crx_url = it->crx_diffurls[0].Resolve(package.namediff);
890
[email protected]61aca4cd2013-10-26 10:50:59891 ChangeItemState(crx, CrxUpdateItem::kCanUpdate);
[email protected]2cddef42013-11-22 08:23:22892 ++num_updates_pending;
[email protected]e8f96ff2011-08-03 05:07:33893 }
[email protected]cf442612011-08-09 20:20:12894
[email protected]2cddef42013-11-22 08:23:22895 // All components that are not included in the update response are
896 // considered up to date.
[email protected]cf442612011-08-09 20:20:12897 ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kUpToDate);
898
[email protected]32a6c8382013-08-20 00:29:20899 // If there are updates pending we do a short wait, otherwise we take
900 // a longer delay until we check the components again.
[email protected]2cddef42013-11-22 08:23:22901 ScheduleNextRun(num_updates_pending > 0 ? kStepDelayShort : kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33902}
903
[email protected]6268d3a2013-11-27 01:28:09904void CrxUpdateService::OnParseUpdateResponseFailed(
[email protected]e8f96ff2011-08-03 05:07:33905 const std::string& error_message) {
906 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
907 size_t count = ChangeItemStatus(CrxUpdateItem::kChecking,
908 CrxUpdateItem::kNoUpdate);
909 DCHECK_GT(count, 0ul);
[email protected]32a6c8382013-08-20 00:29:20910 ScheduleNextRun(kStepDelayLong);
[email protected]e8f96ff2011-08-03 05:07:33911}
912
913// Called when the CRX package has been downloaded to a temporary location.
914// Here we fire the notifications and schedule the component-specific installer
915// to be called in the file thread.
[email protected]3cb2a4f2013-12-07 21:54:34916void CrxUpdateService::DownloadComplete(
917 scoped_ptr<CRXContext> crx_context,
918 const component_updater::CrxDownloader::Result& download_result) {
[email protected]e8f96ff2011-08-03 05:07:33919 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]64f39fa12013-09-03 21:49:37920
[email protected]64f39fa12013-09-03 21:49:37921 CrxUpdateItem* crx = FindUpdateItemById(crx_context->id);
[email protected]e3e696d32013-06-21 20:41:36922 DCHECK(crx->status == CrxUpdateItem::kDownloadingDiff ||
923 crx->status == CrxUpdateItem::kDownloading);
924
[email protected]3cb2a4f2013-12-07 21:54:34925 if (download_result.error) {
[email protected]e3e696d32013-06-21 20:41:36926 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
[email protected]7b0529242013-07-20 05:45:46927 crx->diff_error_category = kNetworkError;
[email protected]3cb2a4f2013-12-07 21:54:34928 crx->diff_error_code = download_result.error;
[email protected]e630ba62013-06-22 15:22:34929 crx->diff_update_failed = true;
[email protected]e3e696d32013-06-21 20:41:36930 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
931 CrxUpdateItem::kCanUpdate);
932 DCHECK_EQ(count, 1ul);
[email protected]afa378f22013-12-02 03:37:54933 crx_downloader_.reset();
[email protected]7b0529242013-07-20 05:45:46934
[email protected]32a6c8382013-08-20 00:29:20935 ScheduleNextRun(kStepDelayShort);
[email protected]e3e696d32013-06-21 20:41:36936 return;
937 }
[email protected]7b0529242013-07-20 05:45:46938 crx->error_category = kNetworkError;
[email protected]3cb2a4f2013-12-07 21:54:34939 crx->error_code = download_result.error;
[email protected]e8f96ff2011-08-03 05:07:33940 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
941 CrxUpdateItem::kNoUpdate);
942 DCHECK_EQ(count, 1ul);
[email protected]afa378f22013-12-02 03:37:54943 crx_downloader_.reset();
[email protected]e3e696d32013-06-21 20:41:36944
[email protected]7b0529242013-07-20 05:45:46945 // At this point, since both the differential and the full downloads failed,
946 // the update for this component has finished with an error.
947 ping_manager_->OnUpdateComplete(crx);
948
[email protected]32a6c8382013-08-20 00:29:20949 // Move on to the next update, if there is one available.
950 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33951 } else {
[email protected]e3e696d32013-06-21 20:41:36952 size_t count = 0;
953 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
954 count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
955 CrxUpdateItem::kUpdatingDiff);
956 } else {
957 count = ChangeItemStatus(CrxUpdateItem::kDownloading,
958 CrxUpdateItem::kUpdating);
959 }
[email protected]e8f96ff2011-08-03 05:07:33960 DCHECK_EQ(count, 1ul);
[email protected]e3e696d32013-06-21 20:41:36961
[email protected]afa378f22013-12-02 03:37:54962 crx_downloader_.reset();
[email protected]cf442612011-08-09 20:20:12963
[email protected]44da56e2011-11-21 19:59:14964 // Why unretained? See comment at top of file.
[email protected]8f5f2ea2013-10-31 09:39:10965 blocking_task_runner_->PostDelayedTask(
[email protected]73251e72012-03-04 02:10:33966 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14967 base::Bind(&CrxUpdateService::Install,
968 base::Unretained(this),
[email protected]afa378f22013-12-02 03:37:54969 base::Passed(&crx_context),
[email protected]3cb2a4f2013-12-07 21:54:34970 download_result.response),
[email protected]73251e72012-03-04 02:10:33971 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]e8f96ff2011-08-03 05:07:33972 }
[email protected]e8f96ff2011-08-03 05:07:33973}
974
975// Install consists of digital signature verification, unpacking and then
976// calling the component specific installer. All that is handled by the
977// |unpacker|. If there is an error this function is in charge of deleting
978// the files created.
[email protected]afa378f22013-12-02 03:37:54979void CrxUpdateService::Install(scoped_ptr<CRXContext> context,
[email protected]650b2d52013-02-10 03:41:45980 const base::FilePath& crx_path) {
[email protected]8f5f2ea2013-10-31 09:39:10981 // This function owns the file at |crx_path| and the |context| object.
[email protected]e3e696d32013-06-21 20:41:36982 ComponentUnpacker unpacker(context->pk_hash,
983 crx_path,
984 context->fingerprint,
985 component_patcher_.get(),
986 context->installer);
[email protected]dd3aa792013-07-16 19:10:23987 if (!base::DeleteFile(crx_path, false))
[email protected]e8f96ff2011-08-03 05:07:33988 NOTREACHED() << crx_path.value();
[email protected]44da56e2011-11-21 19:59:14989 // Why unretained? See comment at top of file.
[email protected]73251e72012-03-04 02:10:33990 BrowserThread::PostDelayedTask(
991 BrowserThread::UI,
992 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14993 base::Bind(&CrxUpdateService::DoneInstalling, base::Unretained(this),
[email protected]e3e696d32013-06-21 20:41:36994 context->id, unpacker.error(), unpacker.extended_error()),
[email protected]73251e72012-03-04 02:10:33995 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]e8f96ff2011-08-03 05:07:33996}
997
998// Installation has been completed. Adjust the component status and
[email protected]7b0529242013-07-20 05:45:46999// schedule the next check. Schedule a short delay before trying the full
1000// update when the differential update failed.
[email protected]07f93af12011-08-17 20:57:221001void CrxUpdateService::DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:361002 ComponentUnpacker::Error error,
1003 int extra_code) {
[email protected]e8f96ff2011-08-03 05:07:331004 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]07f93af12011-08-17 20:57:221005
[email protected]7b0529242013-07-20 05:45:461006 ErrorCategory error_category = kErrorNone;
1007 switch (error) {
1008 case ComponentUnpacker::kNone:
1009 break;
1010 case ComponentUnpacker::kInstallerError:
1011 error_category = kInstallError;
1012 break;
1013 default:
1014 error_category = kUnpackError;
1015 break;
1016 }
1017
1018 const bool is_success = error == ComponentUnpacker::kNone;
1019
[email protected]07f93af12011-08-17 20:57:221020 CrxUpdateItem* item = FindUpdateItemById(component_id);
[email protected]7b0529242013-07-20 05:45:461021 if (item->status == CrxUpdateItem::kUpdatingDiff && !is_success) {
1022 item->diff_error_category = error_category;
1023 item->diff_error_code = error;
1024 item->diff_extra_code1 = extra_code;
[email protected]1ea21ad2013-09-02 04:20:391025 item->diff_update_failed = true;
1026 size_t count = ChangeItemStatus(CrxUpdateItem::kUpdatingDiff,
1027 CrxUpdateItem::kCanUpdate);
1028 DCHECK_EQ(count, 1ul);
1029 ScheduleNextRun(kStepDelayShort);
1030 return;
[email protected]e3e696d32013-06-21 20:41:361031 }
[email protected]e3e696d32013-06-21 20:41:361032
[email protected]7b0529242013-07-20 05:45:461033 if (is_success) {
[email protected]61aca4cd2013-10-26 10:50:591034 ChangeItemState(item, CrxUpdateItem::kUpdated);
[email protected]07f93af12011-08-17 20:57:221035 item->component.version = item->next_version;
[email protected]e3e696d32013-06-21 20:41:361036 item->component.fingerprint = item->next_fp;
[email protected]7b0529242013-07-20 05:45:461037 } else {
[email protected]61aca4cd2013-10-26 10:50:591038 ChangeItemState(item, CrxUpdateItem::kNoUpdate);
[email protected]7b0529242013-07-20 05:45:461039 item->error_category = error_category;
1040 item->error_code = error;
1041 item->extra_code1 = extra_code;
[email protected]e3e696d32013-06-21 20:41:361042 }
[email protected]07f93af12011-08-17 20:57:221043
[email protected]7b0529242013-07-20 05:45:461044 ping_manager_->OnUpdateComplete(item);
[email protected]360b8bb2011-09-01 21:48:061045
[email protected]32a6c8382013-08-20 00:29:201046 // Move on to the next update, if there is one available.
1047 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:331048}
1049
[email protected]85e61d52013-08-01 22:23:421050void CrxUpdateService::NotifyComponentObservers(
1051 ComponentObserver::Events event, int extra) const {
1052 for (UpdateItems::const_iterator it = work_items_.begin();
1053 it != work_items_.end(); ++it) {
1054 ComponentObserver* observer = (*it)->component.observer;
1055 if (observer)
1056 observer->OnEvent(event, 0);
1057 }
1058}
1059
[email protected]00a77fa2013-11-02 04:18:461060content::ResourceThrottle* CrxUpdateService::GetOnDemandResourceThrottle(
1061 net::URLRequest* request, const std::string& crx_id) {
1062 // We give the raw pointer to the caller, who will delete it at will
1063 // and we keep for ourselves a weak pointer to it so we can post tasks
1064 // from the UI thread without having to track lifetime directly.
1065 CUResourceThrottle* rt = new CUResourceThrottle(request);
1066 BrowserThread::PostTask(
1067 BrowserThread::UI,
1068 FROM_HERE,
1069 base::Bind(&CrxUpdateService::OnNewResourceThrottle,
1070 base::Unretained(this),
1071 rt->AsWeakPtr(),
1072 crx_id));
1073 return rt;
1074}
1075
1076void CrxUpdateService::OnNewResourceThrottle(
1077 base::WeakPtr<CUResourceThrottle> rt, const std::string& crx_id) {
1078 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1079 // Check if we can on-demand update, else unblock the request anyway.
1080 CrxUpdateItem* item = FindUpdateItemById(crx_id);
1081 Status status = OnDemandUpdateInternal(item);
1082 if (status == kOk || status == kInProgress) {
1083 item->throttles.push_back(rt);
1084 return;
1085 }
1086 UnblockResourceThrottle(rt);
1087}
1088
1089///////////////////////////////////////////////////////////////////////////////
1090
1091CUResourceThrottle::CUResourceThrottle(const net::URLRequest* request)
1092 : state_(NEW) {
1093 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1094}
1095
1096CUResourceThrottle::~CUResourceThrottle() {
1097 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1098}
1099
1100void CUResourceThrottle::WillStartRequest(bool* defer) {
1101 if (state_ != UNBLOCKED) {
1102 state_ = BLOCKED;
1103 *defer = true;
1104 } else {
1105 *defer = false;
1106 }
1107}
1108
1109void CUResourceThrottle::WillRedirectRequest(const GURL& new_url, bool* defer) {
1110 WillStartRequest(defer);
1111}
1112
[email protected]f8fe5cf2013-12-04 20:11:531113const char* CUResourceThrottle::GetNameForLogging() const {
1114 return "ComponentUpdateResourceThrottle";
1115}
1116
[email protected]00a77fa2013-11-02 04:18:461117void CUResourceThrottle::Unblock() {
1118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1119 if (state_ == BLOCKED)
1120 controller()->Resume();
1121 state_ = UNBLOCKED;
1122}
1123
[email protected]e8f96ff2011-08-03 05:07:331124// The component update factory. Using the component updater as a singleton
1125// is the job of the browser process.
1126ComponentUpdateService* ComponentUpdateServiceFactory(
1127 ComponentUpdateService::Configurator* config) {
1128 DCHECK(config);
1129 return new CrxUpdateService(config);
1130}
[email protected]2cddef42013-11-22 08:23:221131