blob: 5325d600d17ba85fc1ff16cbe3b65d453bc5fbeb [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]3a0092d2013-12-18 03:04:3549using component_updater::CrxDownloader;
50using component_updater::CrxUpdateItem;
51
[email protected]44da56e2011-11-21 19:59:1452// The component updater is designed to live until process shutdown, so
53// base::Bind() calls are not refcounted.
54
[email protected]e8f96ff2011-08-03 05:07:3355namespace {
[email protected]e3e696d32013-06-21 20:41:3656
[email protected]e8f96ff2011-08-03 05:07:3357// Produces an extension-like friendly |id|. This might be removed in the
58// future if we roll our on packing tools.
59static std::string HexStringToID(const std::string& hexstr) {
60 std::string id;
61 for (size_t i = 0; i < hexstr.size(); ++i) {
[email protected]2cddef42013-11-22 08:23:2262 int val(0);
[email protected]eb72b272011-12-19 16:10:5563 if (base::HexStringToInt(base::StringPiece(hexstr.begin() + i,
64 hexstr.begin() + i + 1),
65 &val)) {
[email protected]e8f96ff2011-08-03 05:07:3366 id.append(1, val + 'a');
[email protected]eb72b272011-12-19 16:10:5567 } else {
[email protected]e8f96ff2011-08-03 05:07:3368 id.append(1, 'a');
[email protected]eb72b272011-12-19 16:10:5569 }
[email protected]e8f96ff2011-08-03 05:07:3370 }
[email protected]2cddef42013-11-22 08:23:2271 DCHECK(extensions::Extension::IdIsValid(id));
[email protected]e8f96ff2011-08-03 05:07:3372 return id;
73}
74
[email protected]2cddef42013-11-22 08:23:2275// Returns true if the |proposed| version is newer than |current| version.
[email protected]e8f96ff2011-08-03 05:07:3376bool IsVersionNewer(const Version& current, const std::string& proposed) {
77 Version proposed_ver(proposed);
[email protected]2cddef42013-11-22 08:23:2278 return proposed_ver.IsValid() && current.CompareTo(proposed_ver) < 0;
[email protected]e8f96ff2011-08-03 05:07:3379}
80
81// Helper template class that allows our main class to have separate
[email protected]f1050432012-02-15 01:35:4682// OnURLFetchComplete() callbacks for different types of url requests
[email protected]e8f96ff2011-08-03 05:07:3383// they are differentiated by the |Ctx| type.
84template <typename Del, typename Ctx>
[email protected]15fb2aa2012-05-22 22:52:5985class DelegateWithContext : public net::URLFetcherDelegate {
[email protected]e8f96ff2011-08-03 05:07:3386 public:
87 DelegateWithContext(Del* delegate, Ctx* context)
88 : delegate_(delegate), context_(context) {}
89
[email protected]10c2d692012-05-11 05:32:2390 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
[email protected]e8f96ff2011-08-03 05:07:3391 delegate_->OnURLFetchComplete(source, context_);
92 delete this;
93 }
94
95 private:
96 ~DelegateWithContext() {}
97
98 Del* delegate_;
99 Ctx* context_;
100};
101// This function creates the right DelegateWithContext using template inference.
102template <typename Del, typename Ctx>
[email protected]15fb2aa2012-05-22 22:52:59103net::URLFetcherDelegate* MakeContextDelegate(Del* delegate, Ctx* context) {
[email protected]e8f96ff2011-08-03 05:07:33104 return new DelegateWithContext<Del, Ctx>(delegate, context);
105}
106
[email protected]e3e696d32013-06-21 20:41:36107// Returns true if a differential update is available, it has not failed yet,
108// and the configuration allows it.
109bool CanTryDiffUpdate(const CrxUpdateItem* update_item,
110 const ComponentUpdateService::Configurator& config) {
[email protected]da37c1d2013-12-19 01:04:38111 return component_updater::HasDiffUpdate(update_item) &&
[email protected]e3e696d32013-06-21 20:41:36112 !update_item->diff_update_failed &&
113 config.DeltasEnabled();
114}
115
[email protected]3a0092d2013-12-18 03:04:35116void AppendDownloadMetrics(
117 const std::vector<CrxDownloader::DownloadMetrics>& source,
118 std::vector<CrxDownloader::DownloadMetrics>* destination) {
119 destination->insert(destination->end(), source.begin(), source.end());
120}
121
[email protected]7b0529242013-07-20 05:45:46122} // namespace
123
124CrxUpdateItem::CrxUpdateItem()
125 : status(kNew),
[email protected]61aca4cd2013-10-26 10:50:59126 on_demand(false),
[email protected]7b0529242013-07-20 05:45:46127 diff_update_failed(false),
128 error_category(0),
129 error_code(0),
130 extra_code1(0),
131 diff_error_category(0),
132 diff_error_code(0),
133 diff_extra_code1(0) {
134}
135
136CrxUpdateItem::~CrxUpdateItem() {
137}
[email protected]86550a42013-06-21 15:20:49138
[email protected]dc06f0b2013-01-23 20:03:16139CrxComponent::CrxComponent()
[email protected]85e61d52013-08-01 22:23:42140 : installer(NULL),
141 observer(NULL) {
[email protected]dc06f0b2013-01-23 20:03:16142}
143
144CrxComponent::~CrxComponent() {
145}
[email protected]e8f96ff2011-08-03 05:07:33146
[email protected]2e919ddd2013-08-21 05:05:17147std::string GetCrxComponentID(const CrxComponent& component) {
148 return HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
149 component.pk_hash.size()/2)));
150}
151
152CrxComponentInfo::CrxComponentInfo() {
153}
154
155CrxComponentInfo::~CrxComponentInfo() {
156}
157
[email protected]00a77fa2013-11-02 04:18:46158///////////////////////////////////////////////////////////////////////////////
159// In charge of blocking url requests until the |crx_id| component has been
160// updated. This class is touched solely from the IO thread. The UI thread
161// can post tasks to it via weak pointers. By default the request is blocked
162// unless the CrxUpdateService calls Unblock().
163// The lifetime is controlled by Chrome's resource loader so the component
164// updater cannot touch objects from this class except via weak pointers.
165class CUResourceThrottle
166 : public content::ResourceThrottle,
167 public base::SupportsWeakPtr<CUResourceThrottle> {
168 public:
169 explicit CUResourceThrottle(const net::URLRequest* request);
170 virtual ~CUResourceThrottle();
[email protected]2cddef42013-11-22 08:23:22171
[email protected]00a77fa2013-11-02 04:18:46172 // Overriden from ResourceThrottle.
173 virtual void WillStartRequest(bool* defer) OVERRIDE;
174 virtual void WillRedirectRequest(const GURL& new_url, bool* defer) OVERRIDE;
[email protected]f8fe5cf2013-12-04 20:11:53175 virtual const char* GetNameForLogging() const OVERRIDE;
[email protected]00a77fa2013-11-02 04:18:46176
177 // Component updater calls this function via PostTask to unblock the request.
178 void Unblock();
179
180 typedef std::vector<base::WeakPtr<CUResourceThrottle> > WeakPtrVector;
181
182 private:
[email protected]2cddef42013-11-22 08:23:22183 enum State {
184 NEW,
185 BLOCKED,
186 UNBLOCKED
187 };
[email protected]00a77fa2013-11-02 04:18:46188
[email protected]2cddef42013-11-22 08:23:22189 State state_;
[email protected]00a77fa2013-11-02 04:18:46190};
191
192void UnblockResourceThrottle(base::WeakPtr<CUResourceThrottle> rt) {
193 BrowserThread::PostTask(
194 BrowserThread::IO,
195 FROM_HERE,
196 base::Bind(&CUResourceThrottle::Unblock, rt));
197}
198
199void UnblockandReapAllThrottles(CUResourceThrottle::WeakPtrVector* throttles) {
200 CUResourceThrottle::WeakPtrVector::iterator it;
201 for (it = throttles->begin(); it != throttles->end(); ++it)
202 UnblockResourceThrottle(*it);
203 throttles->clear();
204}
205
[email protected]e8f96ff2011-08-03 05:07:33206//////////////////////////////////////////////////////////////////////////////
207// The one and only implementation of the ComponentUpdateService interface. In
208// charge of running the show. The main method is ProcessPendingItems() which
[email protected]50b01392012-09-01 03:33:13209// is called periodically to do the upgrades/installs or the update checks.
[email protected]e8f96ff2011-08-03 05:07:33210// An important consideration here is to be as "low impact" as we can to the
211// rest of the browser, so even if we have many components registered and
[email protected]f1050432012-02-15 01:35:46212// eligible for update, we only do one thing at a time with pauses in between
[email protected]e8f96ff2011-08-03 05:07:33213// the tasks. Also when we do network requests there is only one |url_fetcher_|
[email protected]e3e696d32013-06-21 20:41:36214// in flight at a time.
[email protected]e8f96ff2011-08-03 05:07:33215// There are no locks in this code, the main structure |work_items_| is mutated
216// only from the UI thread. The unpack and installation is done in the file
217// thread and the network requests are done in the IO thread and in the file
218// thread.
219class CrxUpdateService : public ComponentUpdateService {
220 public:
221 explicit CrxUpdateService(ComponentUpdateService::Configurator* config);
[email protected]e8f96ff2011-08-03 05:07:33222 virtual ~CrxUpdateService();
223
224 // Overrides for ComponentUpdateService.
225 virtual Status Start() OVERRIDE;
226 virtual Status Stop() OVERRIDE;
227 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE;
[email protected]61aca4cd2013-10-26 10:50:59228 virtual Status OnDemandUpdate(const std::string& component_id) OVERRIDE;
[email protected]2e919ddd2013-08-21 05:05:17229 virtual void GetComponents(
230 std::vector<CrxComponentInfo>* components) OVERRIDE;
[email protected]00a77fa2013-11-02 04:18:46231 virtual content::ResourceThrottle* GetOnDemandResourceThrottle(
232 net::URLRequest* request, const std::string& crx_id) OVERRIDE;
[email protected]e8f96ff2011-08-03 05:07:33233
[email protected]e8f96ff2011-08-03 05:07:33234 // Context for a update check url request. See DelegateWithContext above.
235 struct UpdateContext {
236 base::Time start;
237 UpdateContext() : start(base::Time::Now()) {}
238 };
239
240 // Context for a crx download url request. See DelegateWithContext above.
241 struct CRXContext {
242 ComponentInstaller* installer;
243 std::vector<uint8> pk_hash;
244 std::string id;
[email protected]e3e696d32013-06-21 20:41:36245 std::string fingerprint;
[email protected]e8f96ff2011-08-03 05:07:33246 CRXContext() : installer(NULL) {}
247 };
248
[email protected]10c2d692012-05-11 05:32:23249 void OnURLFetchComplete(const net::URLFetcher* source,
[email protected]7cc6e5632011-10-25 17:56:12250 UpdateContext* context);
[email protected]e8f96ff2011-08-03 05:07:33251
[email protected]e8f96ff2011-08-03 05:07:33252 private:
[email protected]7b0529242013-07-20 05:45:46253 enum ErrorCategory {
254 kErrorNone = 0,
255 kNetworkError,
256 kUnpackError,
257 kInstallError,
258 };
259
[email protected]32a6c8382013-08-20 00:29:20260 enum StepDelayInterval {
261 kStepDelayShort = 0,
262 kStepDelayMedium,
263 kStepDelayLong,
264 };
265
[email protected]6268d3a2013-11-27 01:28:09266 void OnParseUpdateResponseSucceeded(
267 const component_updater::UpdateResponse::Results& results);
268 void OnParseUpdateResponseFailed(const std::string& error_message);
[email protected]e8f96ff2011-08-03 05:07:33269
[email protected]3cb2a4f2013-12-07 21:54:34270 void DownloadComplete(
271 scoped_ptr<CRXContext> crx_context,
[email protected]3a0092d2013-12-18 03:04:35272 const CrxDownloader::Result& download_result);
[email protected]afa378f22013-12-02 03:37:54273
[email protected]00a77fa2013-11-02 04:18:46274 Status OnDemandUpdateInternal(CrxUpdateItem* item);
275
[email protected]e8f96ff2011-08-03 05:07:33276 void ProcessPendingItems();
277
[email protected]61aca4cd2013-10-26 10:50:59278 CrxUpdateItem* FindReadyComponent();
279
280 void UpdateComponent(CrxUpdateItem* workitem);
281
[email protected]2cddef42013-11-22 08:23:22282 void AddItemToUpdateCheck(CrxUpdateItem* item,
283 std::string* update_check_items);
[email protected]61aca4cd2013-10-26 10:50:59284
[email protected]2cddef42013-11-22 08:23:22285 void AddUpdateCheckItems(std::string* update_check_items);
286
287 void DoUpdateCheck(const std::string& update_check_items);
[email protected]61aca4cd2013-10-26 10:50:59288
[email protected]32a6c8382013-08-20 00:29:20289 void ScheduleNextRun(StepDelayInterval step_delay);
[email protected]e8f96ff2011-08-03 05:07:33290
[email protected]6268d3a2013-11-27 01:28:09291 void ParseResponse(const std::string& xml);
[email protected]e8f96ff2011-08-03 05:07:33292
[email protected]afa378f22013-12-02 03:37:54293 void Install(scoped_ptr<CRXContext> context, const base::FilePath& crx_path);
[email protected]e8f96ff2011-08-03 05:07:33294
[email protected]07f93af12011-08-17 20:57:22295 void DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:36296 ComponentUnpacker::Error error,
297 int extended_error);
[email protected]e8f96ff2011-08-03 05:07:33298
[email protected]61aca4cd2013-10-26 10:50:59299 void ChangeItemState(CrxUpdateItem* item, CrxUpdateItem::Status to);
300
[email protected]e8f96ff2011-08-03 05:07:33301 size_t ChangeItemStatus(CrxUpdateItem::Status from,
302 CrxUpdateItem::Status to);
303
304 CrxUpdateItem* FindUpdateItemById(const std::string& id);
305
[email protected]85e61d52013-08-01 22:23:42306 void NotifyComponentObservers(ComponentObserver::Events event,
307 int extra) const;
308
[email protected]61aca4cd2013-10-26 10:50:59309 bool HasOnDemandItems() const;
310
[email protected]00a77fa2013-11-02 04:18:46311 void OnNewResourceThrottle(base::WeakPtr<CUResourceThrottle> rt,
312 const std::string& crx_id);
313
[email protected]e3e696d32013-06-21 20:41:36314 scoped_ptr<ComponentUpdateService::Configurator> config_;
315
316 scoped_ptr<ComponentPatcher> component_patcher_;
[email protected]e8f96ff2011-08-03 05:07:33317
[email protected]d3ec669b2012-05-23 07:12:14318 scoped_ptr<net::URLFetcher> url_fetcher_;
[email protected]e8f96ff2011-08-03 05:07:33319
[email protected]7b0529242013-07-20 05:45:46320 scoped_ptr<component_updater::PingManager> ping_manager_;
321
[email protected]3a0092d2013-12-18 03:04:35322 scoped_ptr<CrxDownloader> crx_downloader_;
[email protected]afa378f22013-12-02 03:37:54323
[email protected]86550a42013-06-21 15:20:49324 // A collection of every work item.
[email protected]e3e696d32013-06-21 20:41:36325 typedef std::vector<CrxUpdateItem*> UpdateItems;
[email protected]e8f96ff2011-08-03 05:07:33326 UpdateItems work_items_;
327
328 base::OneShotTimer<CrxUpdateService> timer_;
329
[email protected]8f5f2ea2013-10-31 09:39:10330 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
331
[email protected]e3e696d32013-06-21 20:41:36332 const Version chrome_version_;
[email protected]e8f96ff2011-08-03 05:07:33333
334 bool running_;
335
336 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
337};
338
[email protected]e8f96ff2011-08-03 05:07:33339//////////////////////////////////////////////////////////////////////////////
340
[email protected]e3e696d32013-06-21 20:41:36341CrxUpdateService::CrxUpdateService(ComponentUpdateService::Configurator* config)
[email protected]e8f96ff2011-08-03 05:07:33342 : config_(config),
[email protected]e3e696d32013-06-21 20:41:36343 component_patcher_(config->CreateComponentPatcher()),
[email protected]7b0529242013-07-20 05:45:46344 ping_manager_(new component_updater::PingManager(
345 config->PingUrl(),
346 config->RequestContext())),
[email protected]8f5f2ea2013-10-31 09:39:10347 blocking_task_runner_(BrowserThread::GetBlockingPool()->
348 GetSequencedTaskRunnerWithShutdownBehavior(
349 BrowserThread::GetBlockingPool()->GetSequenceToken(),
350 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)),
[email protected]e8f96ff2011-08-03 05:07:33351 chrome_version_(chrome::VersionInfo().Version()),
352 running_(false) {
[email protected]1ea21ad2013-09-02 04:20:39353}
[email protected]e8f96ff2011-08-03 05:07:33354
355CrxUpdateService::~CrxUpdateService() {
356 // Because we are a singleton, at this point only the UI thread should be
357 // alive, this simplifies the management of the work that could be in
358 // flight in other threads.
359 Stop();
360 STLDeleteElements(&work_items_);
[email protected]1ea21ad2013-09-02 04:20:39361}
[email protected]e8f96ff2011-08-03 05:07:33362
363ComponentUpdateService::Status CrxUpdateService::Start() {
364 // Note that RegisterComponent will call Start() when the first
365 // component is registered, so it can be called twice. This way
366 // we avoid scheduling the timer if there is no work to do.
367 running_ = true;
368 if (work_items_.empty())
369 return kOk;
370
[email protected]85e61d52013-08-01 22:23:42371 NotifyComponentObservers(ComponentObserver::COMPONENT_UPDATER_STARTED, 0);
372
[email protected]d323a172011-09-02 18:23:02373 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->InitialDelay()),
[email protected]e8f96ff2011-08-03 05:07:33374 this, &CrxUpdateService::ProcessPendingItems);
375 return kOk;
376}
377
378// Stop the main check + update loop. In flight operations will be
379// completed.
380ComponentUpdateService::Status CrxUpdateService::Stop() {
381 running_ = false;
382 timer_.Stop();
383 return kOk;
384}
385
[email protected]61aca4cd2013-10-26 10:50:59386bool CrxUpdateService::HasOnDemandItems() const {
387 class Helper {
388 public:
389 static bool IsOnDemand(CrxUpdateItem* item) {
390 return item->on_demand;
391 }
392 };
393 return std::find_if(work_items_.begin(),
394 work_items_.end(),
395 Helper::IsOnDemand) != work_items_.end();
396}
397
[email protected]ccb4feef2013-02-14 06:16:47398// This function sets the timer which will call ProcessPendingItems() or
[email protected]61aca4cd2013-10-26 10:50:59399// ProcessRequestedItem() if there is an on_demand item. There
[email protected]32a6c8382013-08-20 00:29:20400// are three kinds of waits:
401// - a short delay, when there is immediate work to be done.
402// - a medium delay, when there are updates to be applied within the current
403// update cycle, or there are components that are still unchecked.
404// - a long delay when a full check/update cycle has completed for all
405// components.
406void CrxUpdateService::ScheduleNextRun(StepDelayInterval step_delay) {
[email protected]e8f96ff2011-08-03 05:07:33407 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cf442612011-08-09 20:20:12408 DCHECK(url_fetcher_.get() == NULL);
[email protected]e8f96ff2011-08-03 05:07:33409 CHECK(!timer_.IsRunning());
410 // It could be the case that Stop() had been called while a url request
411 // or unpacking was in flight, if so we arrive here but |running_| is
412 // false. In that case do not loop again.
413 if (!running_)
414 return;
415
[email protected]ccb4feef2013-02-14 06:16:47416 // Keep the delay short if in the middle of an update (step_delay),
417 // or there are new requested_work_items_ that have not been processed yet.
[email protected]32a6c8382013-08-20 00:29:20418 int64 delay_seconds = 0;
[email protected]61aca4cd2013-10-26 10:50:59419 if (!HasOnDemandItems()) {
[email protected]32a6c8382013-08-20 00:29:20420 switch (step_delay) {
421 case kStepDelayShort:
422 delay_seconds = config_->StepDelay();
423 break;
424 case kStepDelayMedium:
425 delay_seconds = config_->StepDelayMedium();
426 break;
427 case kStepDelayLong:
428 delay_seconds = config_->NextCheckDelay();
429 break;
430 }
431 } else {
432 delay_seconds = config_->StepDelay();
433 }
[email protected]cf442612011-08-09 20:20:12434
[email protected]32a6c8382013-08-20 00:29:20435 if (step_delay != kStepDelayShort) {
[email protected]85e61d52013-08-01 22:23:42436 NotifyComponentObservers(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0);
437
[email protected]e8f96ff2011-08-03 05:07:33438 // Zero is only used for unit tests.
[email protected]32a6c8382013-08-20 00:29:20439 if (0 == delay_seconds)
[email protected]e8f96ff2011-08-03 05:07:33440 return;
441 }
442
[email protected]32a6c8382013-08-20 00:29:20443 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay_seconds),
[email protected]e8f96ff2011-08-03 05:07:33444 this, &CrxUpdateService::ProcessPendingItems);
445}
446
447// Given a extension-like component id, find the associated component.
448CrxUpdateItem* CrxUpdateService::FindUpdateItemById(const std::string& id) {
449 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
450 CrxUpdateItem::FindById finder(id);
451 UpdateItems::iterator it = std::find_if(work_items_.begin(),
452 work_items_.end(),
453 finder);
454 if (it == work_items_.end())
455 return NULL;
456 return (*it);
457}
458
[email protected]61aca4cd2013-10-26 10:50:59459// Changes a component's status, clearing on_demand and firing notifications as
460// necessary. By convention, this is the only function that can change a
461// CrxUpdateItem's |status|.
462// TODO(waffles): Do we want to add DCHECKS for valid state transitions here?
463void CrxUpdateService::ChangeItemState(CrxUpdateItem* item,
464 CrxUpdateItem::Status to) {
465 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
466 if (to == CrxUpdateItem::kNoUpdate ||
467 to == CrxUpdateItem::kUpdated ||
468 to == CrxUpdateItem::kUpToDate) {
469 item->on_demand = false;
470 }
471
472 item->status = to;
473
474 ComponentObserver* observer = item->component.observer;
475 if (observer) {
476 switch (to) {
477 case CrxUpdateItem::kCanUpdate:
478 observer->OnEvent(ComponentObserver::COMPONENT_UPDATE_FOUND, 0);
479 break;
480 case CrxUpdateItem::kUpdatingDiff:
481 case CrxUpdateItem::kUpdating:
482 observer->OnEvent(ComponentObserver::COMPONENT_UPDATE_READY, 0);
483 break;
484 case CrxUpdateItem::kUpdated:
485 observer->OnEvent(ComponentObserver::COMPONENT_UPDATED, 0);
486 break;
487 case CrxUpdateItem::kUpToDate:
488 case CrxUpdateItem::kNoUpdate:
489 observer->OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0);
490 break;
491 case CrxUpdateItem::kNew:
492 case CrxUpdateItem::kChecking:
493 case CrxUpdateItem::kDownloading:
494 case CrxUpdateItem::kDownloadingDiff:
495 case CrxUpdateItem::kLastStatus:
496 // No notification for these states.
497 break;
498 }
499 }
[email protected]00a77fa2013-11-02 04:18:46500
501 // Free possible pending network requests.
502 if ((to == CrxUpdateItem::kUpdated) ||
503 (to == CrxUpdateItem::kUpToDate) ||
504 (to == CrxUpdateItem::kNoUpdate)) {
505 UnblockandReapAllThrottles(&item->throttles);
506 }
[email protected]61aca4cd2013-10-26 10:50:59507}
508
[email protected]e8f96ff2011-08-03 05:07:33509// Changes all the components in |work_items_| that have |from| status to
[email protected]e3e696d32013-06-21 20:41:36510// |to| status and returns how many have been changed.
[email protected]e8f96ff2011-08-03 05:07:33511size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from,
512 CrxUpdateItem::Status to) {
513 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
514 size_t count = 0;
515 for (UpdateItems::iterator it = work_items_.begin();
516 it != work_items_.end(); ++it) {
517 CrxUpdateItem* item = *it;
518 if (item->status != from)
519 continue;
[email protected]61aca4cd2013-10-26 10:50:59520 ChangeItemState(item, to);
[email protected]e8f96ff2011-08-03 05:07:33521 ++count;
522 }
523 return count;
524}
525
526// Adds a component to be checked for upgrades. If the component exists it
527// it will be replaced and the return code is kReplaced.
528//
529// TODO(cpu): Evaluate if we want to support un-registration.
530ComponentUpdateService::Status CrxUpdateService::RegisterComponent(
531 const CrxComponent& component) {
532 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
533 if (component.pk_hash.empty() ||
534 !component.version.IsValid() ||
535 !component.installer)
536 return kError;
537
538 std::string id =
539 HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
540 component.pk_hash.size()/2)));
541 CrxUpdateItem* uit;
542 uit = FindUpdateItemById(id);
543 if (uit) {
544 uit->component = component;
545 return kReplaced;
546 }
547
548 uit = new CrxUpdateItem;
549 uit->id.swap(id);
550 uit->component = component;
[email protected]e3e696d32013-06-21 20:41:36551
[email protected]e8f96ff2011-08-03 05:07:33552 work_items_.push_back(uit);
553 // If this is the first component registered we call Start to
554 // schedule the first timer.
555 if (running_ && (work_items_.size() == 1))
556 Start();
557
558 return kOk;
559}
560
[email protected]ccb4feef2013-02-14 06:16:47561// Start the process of checking for an update, for a particular component
562// that was previously registered.
[email protected]2e919ddd2013-08-21 05:05:17563// |component_id| is a value returned from GetCrxComponentID().
[email protected]61aca4cd2013-10-26 10:50:59564ComponentUpdateService::Status CrxUpdateService::OnDemandUpdate(
[email protected]2e919ddd2013-08-21 05:05:17565 const std::string& component_id) {
[email protected]00a77fa2013-11-02 04:18:46566 return OnDemandUpdateInternal(FindUpdateItemById(component_id));
567}
568
569ComponentUpdateService::Status CrxUpdateService::OnDemandUpdateInternal(
570 CrxUpdateItem* uit) {
[email protected]ccb4feef2013-02-14 06:16:47571 if (!uit)
572 return kError;
[email protected]2cddef42013-11-22 08:23:22573
[email protected]ccb4feef2013-02-14 06:16:47574 // Check if the request is too soon.
575 base::TimeDelta delta = base::Time::Now() - uit->last_check;
[email protected]e3e696d32013-06-21 20:41:36576 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
[email protected]ccb4feef2013-02-14 06:16:47577 return kError;
[email protected]ccb4feef2013-02-14 06:16:47578
579 switch (uit->status) {
580 // If the item is already in the process of being updated, there is
581 // no point in this call, so return kInProgress.
582 case CrxUpdateItem::kChecking:
583 case CrxUpdateItem::kCanUpdate:
[email protected]e3e696d32013-06-21 20:41:36584 case CrxUpdateItem::kDownloadingDiff:
[email protected]ccb4feef2013-02-14 06:16:47585 case CrxUpdateItem::kDownloading:
[email protected]e3e696d32013-06-21 20:41:36586 case CrxUpdateItem::kUpdatingDiff:
[email protected]ccb4feef2013-02-14 06:16:47587 case CrxUpdateItem::kUpdating:
588 return kInProgress;
589 // Otherwise the item was already checked a while back (or it is new),
590 // set its status to kNew to give it a slightly higher priority.
591 case CrxUpdateItem::kNew:
592 case CrxUpdateItem::kUpdated:
593 case CrxUpdateItem::kUpToDate:
594 case CrxUpdateItem::kNoUpdate:
[email protected]61aca4cd2013-10-26 10:50:59595 ChangeItemState(uit, CrxUpdateItem::kNew);
596 uit->on_demand = true;
[email protected]ccb4feef2013-02-14 06:16:47597 break;
598 case CrxUpdateItem::kLastStatus:
599 NOTREACHED() << uit->status;
600 }
601
602 // In case the current delay is long, set the timer to a shorter value
603 // to get the ball rolling.
604 if (timer_.IsRunning()) {
605 timer_.Stop();
606 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->StepDelay()),
607 this, &CrxUpdateService::ProcessPendingItems);
608 }
609
610 return kOk;
611}
612
[email protected]2e919ddd2013-08-21 05:05:17613void CrxUpdateService::GetComponents(
614 std::vector<CrxComponentInfo>* components) {
615 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
616 for (UpdateItems::const_iterator it = work_items_.begin();
617 it != work_items_.end(); ++it) {
618 const CrxUpdateItem* item = *it;
619 CrxComponentInfo info;
620 info.id = GetCrxComponentID(item->component);
621 info.version = item->component.version.GetString();
622 info.name = item->component.name;
623 components->push_back(info);
624 }
625}
626
[email protected]61aca4cd2013-10-26 10:50:59627// This is the main loop of the component updater.
[email protected]e8f96ff2011-08-03 05:07:33628void CrxUpdateService::ProcessPendingItems() {
629 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]61aca4cd2013-10-26 10:50:59630 CrxUpdateItem* ready_upgrade = FindReadyComponent();
631 if (ready_upgrade) {
632 UpdateComponent(ready_upgrade);
[email protected]e8f96ff2011-08-03 05:07:33633 return;
634 }
[email protected]2cddef42013-11-22 08:23:22635 std::string update_check_items;
636 AddUpdateCheckItems(&update_check_items);
637 if (!update_check_items.empty()) {
638 DoUpdateCheck(update_check_items);
[email protected]61aca4cd2013-10-26 10:50:59639 return;
640 }
641 // No components to update. The next check will be after a long sleep.
642 ScheduleNextRun(kStepDelayLong);
643}
644
645CrxUpdateItem* CrxUpdateService::FindReadyComponent() {
646 class Helper {
647 public:
648 static bool IsReadyOnDemand(CrxUpdateItem* item) {
649 return item->on_demand && IsReady(item);
650 }
651 static bool IsReady(CrxUpdateItem* item) {
652 return item->status == CrxUpdateItem::kCanUpdate;
653 }
654 };
655
656 std::vector<CrxUpdateItem*>::iterator it = std::find_if(
657 work_items_.begin(), work_items_.end(), Helper::IsReadyOnDemand);
658 if (it != work_items_.end())
659 return *it;
660 it = std::find_if(work_items_.begin(), work_items_.end(), Helper::IsReady);
661 if (it != work_items_.end())
662 return *it;
663 return NULL;
664}
665
666void CrxUpdateService::UpdateComponent(CrxUpdateItem* workitem) {
[email protected]afa378f22013-12-02 03:37:54667 scoped_ptr<CRXContext> crx_context(new CRXContext);
668 crx_context->pk_hash = workitem->component.pk_hash;
669 crx_context->id = workitem->id;
670 crx_context->installer = workitem->component.installer;
671 crx_context->fingerprint = workitem->next_fp;
[email protected]da37c1d2013-12-19 01:04:38672 const std::vector<GURL>* urls = NULL;
[email protected]61aca4cd2013-10-26 10:50:59673 if (CanTryDiffUpdate(workitem, *config_)) {
[email protected]da37c1d2013-12-19 01:04:38674 urls = &workitem->crx_diffurls;
[email protected]61aca4cd2013-10-26 10:50:59675 ChangeItemState(workitem, CrxUpdateItem::kDownloadingDiff);
676 } else {
[email protected]da37c1d2013-12-19 01:04:38677 urls = &workitem->crx_urls;
[email protected]61aca4cd2013-10-26 10:50:59678 ChangeItemState(workitem, CrxUpdateItem::kDownloading);
679 }
[email protected]3cb2a4f2013-12-07 21:54:34680
681 // On demand component updates are always downloaded in foreground.
682 const bool is_background_download = !workitem->on_demand &&
683 config_->UseBackgroundDownloader();
684
[email protected]3a0092d2013-12-18 03:04:35685 crx_downloader_.reset(CrxDownloader::Create(
[email protected]3cb2a4f2013-12-07 21:54:34686 is_background_download,
[email protected]afa378f22013-12-02 03:37:54687 config_->RequestContext(),
688 blocking_task_runner_,
689 base::Bind(&CrxUpdateService::DownloadComplete,
690 base::Unretained(this),
691 base::Passed(&crx_context))));
[email protected]da37c1d2013-12-19 01:04:38692 crx_downloader_->StartDownload(*urls);
[email protected]61aca4cd2013-10-26 10:50:59693}
694
[email protected]2cddef42013-11-22 08:23:22695// Sets the state of the component to be checked for updates. After the
696// function is called, the <app> element corresponding to the |item| parameter
697// is appended to the |update_check_items|.
698void CrxUpdateService::AddItemToUpdateCheck(CrxUpdateItem* item,
699 std::string* update_check_items) {
700 // The app element corresponding to an update items looks like this:
701 // <app appid="hnimpnehoodheedghdeeijklkeaacbdc"
702 // version="0.1.2.3" installsource="ondemand">
703 // <updatecheck />
704 // <packages>
705 // <package fp="abcd" />
706 // </packages>
707 // </app>
708 std::string app_attributes;
709 base::StringAppendF(&app_attributes,
710 "appid=\"%s\" version=\"%s\"",
711 item->id.c_str(),
712 item->component.version.GetString().c_str());
713 if (item->on_demand)
714 base::StringAppendF(&app_attributes, " installsource=\"ondemand\"");
715
716 std::string app;
717 if (item->component.fingerprint.empty())
718 base::StringAppendF(&app,
719 "<app %s>"
720 "<updatecheck />"
721 "</app>",
722 app_attributes.c_str());
723 else
724 base::StringAppendF(&app,
725 "<app %s>"
726 "<updatecheck />"
727 "<packages>"
728 "<package fp=\"%s\"/>"
729 "</packages>"
730 "</app>",
731 app_attributes.c_str(),
732 item->component.fingerprint.c_str());
733
734 update_check_items->append(app);
735
736 ChangeItemState(item, CrxUpdateItem::kChecking);
737 item->last_check = base::Time::Now();
[email protected]da37c1d2013-12-19 01:04:38738 item->crx_urls.clear();
739 item->crx_diffurls.clear();
[email protected]2cddef42013-11-22 08:23:22740 item->previous_version = item->component.version;
741 item->next_version = Version();
742 item->previous_fp = item->component.fingerprint;
743 item->next_fp.clear();
744 item->diff_update_failed = false;
745 item->error_category = 0;
746 item->error_code = 0;
747 item->extra_code1 = 0;
748 item->diff_error_category = 0;
749 item->diff_error_code = 0;
750 item->diff_extra_code1 = 0;
[email protected]3a0092d2013-12-18 03:04:35751 item->download_metrics.clear();
[email protected]2cddef42013-11-22 08:23:22752}
753
754// Builds the sequence of <app> elements in the update check and returns it
755// in the |update_check_items| parameter.
756void CrxUpdateService::AddUpdateCheckItems(std::string* update_check_items) {
[email protected]77bcf7c2013-12-12 18:36:08757 // All items are added to a single update check.
[email protected]d63306d2013-06-29 13:56:02758 for (UpdateItems::const_iterator it = work_items_.begin();
759 it != work_items_.end(); ++it) {
760 CrxUpdateItem* item = *it;
[email protected]77bcf7c2013-12-12 18:36:08761 DCHECK(item->status == CrxUpdateItem::kNew ||
762 item->status == CrxUpdateItem::kNoUpdate ||
763 item->status == CrxUpdateItem::kUpToDate ||
764 item->status == CrxUpdateItem::kUpdated);
[email protected]2cddef42013-11-22 08:23:22765 AddItemToUpdateCheck(item, update_check_items);
[email protected]d63306d2013-06-29 13:56:02766 }
[email protected]61aca4cd2013-10-26 10:50:59767}
[email protected]d63306d2013-06-29 13:56:02768
[email protected]2cddef42013-11-22 08:23:22769// Sends an update request. The |update_check_items| parameter
770// contains the sequence of <app> xml elements of the update check.
771void CrxUpdateService::DoUpdateCheck(const std::string& update_check_items) {
772 using component_updater::BuildProtocolRequest;
773 url_fetcher_.reset(component_updater::SendProtocolRequest(
774 config_->UpdateUrl(),
[email protected]f5343ef72013-12-17 03:34:26775 BuildProtocolRequest(update_check_items, config_->ExtraRequestParams()),
[email protected]2cddef42013-11-22 08:23:22776 MakeContextDelegate(this, new UpdateContext()),
777 config_->RequestContext()));
[email protected]e8f96ff2011-08-03 05:07:33778}
779
[email protected]ccb4feef2013-02-14 06:16:47780// Called when we got a response from the update server. It consists of an xml
[email protected]e8f96ff2011-08-03 05:07:33781// document following the omaha update scheme.
[email protected]10c2d692012-05-11 05:32:23782void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
[email protected]07f93af12011-08-17 20:57:22783 UpdateContext* context) {
[email protected]e8f96ff2011-08-03 05:07:33784 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]afa378f22013-12-02 03:37:54785 if (component_updater::FetchSuccess(*source)) {
[email protected]e8f96ff2011-08-03 05:07:33786 std::string xml;
787 source->GetResponseAsString(&xml);
[email protected]cf442612011-08-09 20:20:12788 url_fetcher_.reset();
[email protected]6268d3a2013-11-27 01:28:09789 ParseResponse(xml);
[email protected]e8f96ff2011-08-03 05:07:33790 } else {
[email protected]cf442612011-08-09 20:20:12791 url_fetcher_.reset();
[email protected]6268d3a2013-11-27 01:28:09792 CrxUpdateService::OnParseUpdateResponseFailed("network error");
[email protected]e8f96ff2011-08-03 05:07:33793 }
[email protected]07f93af12011-08-17 20:57:22794 delete context;
[email protected]e8f96ff2011-08-03 05:07:33795}
796
[email protected]6268d3a2013-11-27 01:28:09797void CrxUpdateService::ParseResponse(const std::string& xml) {
[email protected]e8f96ff2011-08-03 05:07:33798 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]6268d3a2013-11-27 01:28:09799 component_updater::UpdateResponse update_response;
800 if (update_response.Parse(xml))
801 CrxUpdateService::OnParseUpdateResponseSucceeded(update_response.results());
[email protected]652f4272013-11-13 09:23:41802 else
[email protected]6268d3a2013-11-27 01:28:09803 CrxUpdateService::OnParseUpdateResponseFailed(update_response.errors());
[email protected]e8f96ff2011-08-03 05:07:33804}
805
806// A valid Omaha update check has arrived, from only the list of components that
807// we are currently upgrading we check for a match in which the server side
808// version is newer, if so we queue them for an upgrade. The next time we call
809// ProcessPendingItems() one of them will be drafted for the upgrade process.
[email protected]6268d3a2013-11-27 01:28:09810void CrxUpdateService::OnParseUpdateResponseSucceeded(
811 const component_updater::UpdateResponse::Results& results) {
[email protected]2cddef42013-11-22 08:23:22812 size_t num_updates_pending = 0;
[email protected]e8f96ff2011-08-03 05:07:33813 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]6268d3a2013-11-27 01:28:09814 std::vector<component_updater::UpdateResponse::Result>::const_iterator it;
[email protected]e8f96ff2011-08-03 05:07:33815 for (it = results.list.begin(); it != results.list.end(); ++it) {
816 CrxUpdateItem* crx = FindUpdateItemById(it->extension_id);
817 if (!crx)
818 continue;
819
[email protected]2cddef42013-11-22 08:23:22820 if (crx->status != CrxUpdateItem::kChecking) {
821 NOTREACHED();
[email protected]e8f96ff2011-08-03 05:07:33822 continue; // Not updating this component now.
[email protected]2cddef42013-11-22 08:23:22823 }
[email protected]e8f96ff2011-08-03 05:07:33824
[email protected]2cddef42013-11-22 08:23:22825 if (it->manifest.version.empty()) {
[email protected]cf442612011-08-09 20:20:12826 // No version means no update available.
[email protected]61aca4cd2013-10-26 10:50:59827 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
[email protected]cf442612011-08-09 20:20:12828 continue;
[email protected]e8f96ff2011-08-03 05:07:33829 }
[email protected]2cddef42013-11-22 08:23:22830
831 if (!IsVersionNewer(crx->component.version, it->manifest.version)) {
832 // The component is up to date.
[email protected]61aca4cd2013-10-26 10:50:59833 ChangeItemState(crx, CrxUpdateItem::kUpToDate);
[email protected]cf442612011-08-09 20:20:12834 continue;
[email protected]e8f96ff2011-08-03 05:07:33835 }
[email protected]2cddef42013-11-22 08:23:22836
837 if (!it->manifest.browser_min_version.empty()) {
838 if (IsVersionNewer(chrome_version_, it->manifest.browser_min_version)) {
839 // The component is not compatible with this Chrome version.
[email protected]61aca4cd2013-10-26 10:50:59840 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
[email protected]cf442612011-08-09 20:20:12841 continue;
842 }
[email protected]e8f96ff2011-08-03 05:07:33843 }
[email protected]2cddef42013-11-22 08:23:22844
845 if (it->manifest.packages.size() != 1) {
846 // Assume one and only one package per component.
847 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
848 continue;
849 }
850
851 // Parse the members of the result and queue an upgrade for this component.
852 crx->next_version = Version(it->manifest.version);
853
854 typedef component_updater::
[email protected]6268d3a2013-11-27 01:28:09855 UpdateResponse::Result::Manifest::Package Package;
[email protected]2cddef42013-11-22 08:23:22856 const Package& package(it->manifest.packages[0]);
857 crx->next_fp = package.fingerprint;
858
[email protected]da37c1d2013-12-19 01:04:38859 // Resolve the urls by combining the base urls with the package names.
860 for (size_t i = 0; i != it->crx_urls.size(); ++i) {
861 const GURL url(it->crx_urls[i].Resolve(package.name));
862 if (url.is_valid())
863 crx->crx_urls.push_back(url);
864 }
865 for (size_t i = 0; i != it->crx_diffurls.size(); ++i) {
866 const GURL url(it->crx_diffurls[i].Resolve(package.namediff));
867 if (url.is_valid())
868 crx->crx_diffurls.push_back(url);
869 }
[email protected]2cddef42013-11-22 08:23:22870
[email protected]61aca4cd2013-10-26 10:50:59871 ChangeItemState(crx, CrxUpdateItem::kCanUpdate);
[email protected]2cddef42013-11-22 08:23:22872 ++num_updates_pending;
[email protected]e8f96ff2011-08-03 05:07:33873 }
[email protected]cf442612011-08-09 20:20:12874
[email protected]2cddef42013-11-22 08:23:22875 // All components that are not included in the update response are
876 // considered up to date.
[email protected]cf442612011-08-09 20:20:12877 ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kUpToDate);
878
[email protected]32a6c8382013-08-20 00:29:20879 // If there are updates pending we do a short wait, otherwise we take
880 // a longer delay until we check the components again.
[email protected]2cddef42013-11-22 08:23:22881 ScheduleNextRun(num_updates_pending > 0 ? kStepDelayShort : kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33882}
883
[email protected]6268d3a2013-11-27 01:28:09884void CrxUpdateService::OnParseUpdateResponseFailed(
[email protected]e8f96ff2011-08-03 05:07:33885 const std::string& error_message) {
886 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
887 size_t count = ChangeItemStatus(CrxUpdateItem::kChecking,
888 CrxUpdateItem::kNoUpdate);
889 DCHECK_GT(count, 0ul);
[email protected]32a6c8382013-08-20 00:29:20890 ScheduleNextRun(kStepDelayLong);
[email protected]e8f96ff2011-08-03 05:07:33891}
892
893// Called when the CRX package has been downloaded to a temporary location.
894// Here we fire the notifications and schedule the component-specific installer
895// to be called in the file thread.
[email protected]3cb2a4f2013-12-07 21:54:34896void CrxUpdateService::DownloadComplete(
897 scoped_ptr<CRXContext> crx_context,
[email protected]3a0092d2013-12-18 03:04:35898 const CrxDownloader::Result& download_result) {
[email protected]e8f96ff2011-08-03 05:07:33899 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]64f39fa12013-09-03 21:49:37900
[email protected]64f39fa12013-09-03 21:49:37901 CrxUpdateItem* crx = FindUpdateItemById(crx_context->id);
[email protected]e3e696d32013-06-21 20:41:36902 DCHECK(crx->status == CrxUpdateItem::kDownloadingDiff ||
903 crx->status == CrxUpdateItem::kDownloading);
904
[email protected]3a0092d2013-12-18 03:04:35905 AppendDownloadMetrics(crx_downloader_->download_metrics(),
906 &crx->download_metrics);
907
[email protected]3cb2a4f2013-12-07 21:54:34908 if (download_result.error) {
[email protected]e3e696d32013-06-21 20:41:36909 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
[email protected]7b0529242013-07-20 05:45:46910 crx->diff_error_category = kNetworkError;
[email protected]3cb2a4f2013-12-07 21:54:34911 crx->diff_error_code = download_result.error;
[email protected]e630ba62013-06-22 15:22:34912 crx->diff_update_failed = true;
[email protected]e3e696d32013-06-21 20:41:36913 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
914 CrxUpdateItem::kCanUpdate);
915 DCHECK_EQ(count, 1ul);
[email protected]afa378f22013-12-02 03:37:54916 crx_downloader_.reset();
[email protected]7b0529242013-07-20 05:45:46917
[email protected]32a6c8382013-08-20 00:29:20918 ScheduleNextRun(kStepDelayShort);
[email protected]e3e696d32013-06-21 20:41:36919 return;
920 }
[email protected]7b0529242013-07-20 05:45:46921 crx->error_category = kNetworkError;
[email protected]3cb2a4f2013-12-07 21:54:34922 crx->error_code = download_result.error;
[email protected]e8f96ff2011-08-03 05:07:33923 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
924 CrxUpdateItem::kNoUpdate);
925 DCHECK_EQ(count, 1ul);
[email protected]afa378f22013-12-02 03:37:54926 crx_downloader_.reset();
[email protected]e3e696d32013-06-21 20:41:36927
[email protected]7b0529242013-07-20 05:45:46928 // At this point, since both the differential and the full downloads failed,
929 // the update for this component has finished with an error.
930 ping_manager_->OnUpdateComplete(crx);
931
[email protected]32a6c8382013-08-20 00:29:20932 // Move on to the next update, if there is one available.
933 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33934 } else {
[email protected]e3e696d32013-06-21 20:41:36935 size_t count = 0;
936 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
937 count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
938 CrxUpdateItem::kUpdatingDiff);
939 } else {
940 count = ChangeItemStatus(CrxUpdateItem::kDownloading,
941 CrxUpdateItem::kUpdating);
942 }
[email protected]e8f96ff2011-08-03 05:07:33943 DCHECK_EQ(count, 1ul);
[email protected]afa378f22013-12-02 03:37:54944 crx_downloader_.reset();
[email protected]cf442612011-08-09 20:20:12945
[email protected]44da56e2011-11-21 19:59:14946 // Why unretained? See comment at top of file.
[email protected]8f5f2ea2013-10-31 09:39:10947 blocking_task_runner_->PostDelayedTask(
[email protected]73251e72012-03-04 02:10:33948 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14949 base::Bind(&CrxUpdateService::Install,
950 base::Unretained(this),
[email protected]afa378f22013-12-02 03:37:54951 base::Passed(&crx_context),
[email protected]3cb2a4f2013-12-07 21:54:34952 download_result.response),
[email protected]73251e72012-03-04 02:10:33953 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]e8f96ff2011-08-03 05:07:33954 }
[email protected]e8f96ff2011-08-03 05:07:33955}
956
957// Install consists of digital signature verification, unpacking and then
958// calling the component specific installer. All that is handled by the
959// |unpacker|. If there is an error this function is in charge of deleting
960// the files created.
[email protected]afa378f22013-12-02 03:37:54961void CrxUpdateService::Install(scoped_ptr<CRXContext> context,
[email protected]650b2d52013-02-10 03:41:45962 const base::FilePath& crx_path) {
[email protected]8f5f2ea2013-10-31 09:39:10963 // This function owns the file at |crx_path| and the |context| object.
[email protected]e3e696d32013-06-21 20:41:36964 ComponentUnpacker unpacker(context->pk_hash,
965 crx_path,
966 context->fingerprint,
967 component_patcher_.get(),
968 context->installer);
[email protected]2e2c5292013-12-17 03:48:40969 if (!component_updater::DeleteFileAndEmptyParentDirectory(crx_path))
[email protected]e8f96ff2011-08-03 05:07:33970 NOTREACHED() << crx_path.value();
[email protected]2e2c5292013-12-17 03:48:40971
[email protected]44da56e2011-11-21 19:59:14972 // Why unretained? See comment at top of file.
[email protected]73251e72012-03-04 02:10:33973 BrowserThread::PostDelayedTask(
974 BrowserThread::UI,
975 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14976 base::Bind(&CrxUpdateService::DoneInstalling, base::Unretained(this),
[email protected]e3e696d32013-06-21 20:41:36977 context->id, unpacker.error(), unpacker.extended_error()),
[email protected]73251e72012-03-04 02:10:33978 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]e8f96ff2011-08-03 05:07:33979}
980
981// Installation has been completed. Adjust the component status and
[email protected]7b0529242013-07-20 05:45:46982// schedule the next check. Schedule a short delay before trying the full
983// update when the differential update failed.
[email protected]07f93af12011-08-17 20:57:22984void CrxUpdateService::DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:36985 ComponentUnpacker::Error error,
986 int extra_code) {
[email protected]e8f96ff2011-08-03 05:07:33987 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]07f93af12011-08-17 20:57:22988
[email protected]7b0529242013-07-20 05:45:46989 ErrorCategory error_category = kErrorNone;
990 switch (error) {
991 case ComponentUnpacker::kNone:
992 break;
993 case ComponentUnpacker::kInstallerError:
994 error_category = kInstallError;
995 break;
996 default:
997 error_category = kUnpackError;
998 break;
999 }
1000
1001 const bool is_success = error == ComponentUnpacker::kNone;
1002
[email protected]07f93af12011-08-17 20:57:221003 CrxUpdateItem* item = FindUpdateItemById(component_id);
[email protected]7b0529242013-07-20 05:45:461004 if (item->status == CrxUpdateItem::kUpdatingDiff && !is_success) {
1005 item->diff_error_category = error_category;
1006 item->diff_error_code = error;
1007 item->diff_extra_code1 = extra_code;
[email protected]1ea21ad2013-09-02 04:20:391008 item->diff_update_failed = true;
1009 size_t count = ChangeItemStatus(CrxUpdateItem::kUpdatingDiff,
1010 CrxUpdateItem::kCanUpdate);
1011 DCHECK_EQ(count, 1ul);
1012 ScheduleNextRun(kStepDelayShort);
1013 return;
[email protected]e3e696d32013-06-21 20:41:361014 }
[email protected]e3e696d32013-06-21 20:41:361015
[email protected]7b0529242013-07-20 05:45:461016 if (is_success) {
[email protected]61aca4cd2013-10-26 10:50:591017 ChangeItemState(item, CrxUpdateItem::kUpdated);
[email protected]07f93af12011-08-17 20:57:221018 item->component.version = item->next_version;
[email protected]e3e696d32013-06-21 20:41:361019 item->component.fingerprint = item->next_fp;
[email protected]7b0529242013-07-20 05:45:461020 } else {
[email protected]61aca4cd2013-10-26 10:50:591021 ChangeItemState(item, CrxUpdateItem::kNoUpdate);
[email protected]7b0529242013-07-20 05:45:461022 item->error_category = error_category;
1023 item->error_code = error;
1024 item->extra_code1 = extra_code;
[email protected]e3e696d32013-06-21 20:41:361025 }
[email protected]07f93af12011-08-17 20:57:221026
[email protected]7b0529242013-07-20 05:45:461027 ping_manager_->OnUpdateComplete(item);
[email protected]360b8bb2011-09-01 21:48:061028
[email protected]32a6c8382013-08-20 00:29:201029 // Move on to the next update, if there is one available.
1030 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:331031}
1032
[email protected]85e61d52013-08-01 22:23:421033void CrxUpdateService::NotifyComponentObservers(
1034 ComponentObserver::Events event, int extra) const {
1035 for (UpdateItems::const_iterator it = work_items_.begin();
1036 it != work_items_.end(); ++it) {
1037 ComponentObserver* observer = (*it)->component.observer;
1038 if (observer)
1039 observer->OnEvent(event, 0);
1040 }
1041}
1042
[email protected]00a77fa2013-11-02 04:18:461043content::ResourceThrottle* CrxUpdateService::GetOnDemandResourceThrottle(
1044 net::URLRequest* request, const std::string& crx_id) {
1045 // We give the raw pointer to the caller, who will delete it at will
1046 // and we keep for ourselves a weak pointer to it so we can post tasks
1047 // from the UI thread without having to track lifetime directly.
1048 CUResourceThrottle* rt = new CUResourceThrottle(request);
1049 BrowserThread::PostTask(
1050 BrowserThread::UI,
1051 FROM_HERE,
1052 base::Bind(&CrxUpdateService::OnNewResourceThrottle,
1053 base::Unretained(this),
1054 rt->AsWeakPtr(),
1055 crx_id));
1056 return rt;
1057}
1058
1059void CrxUpdateService::OnNewResourceThrottle(
1060 base::WeakPtr<CUResourceThrottle> rt, const std::string& crx_id) {
1061 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1062 // Check if we can on-demand update, else unblock the request anyway.
1063 CrxUpdateItem* item = FindUpdateItemById(crx_id);
1064 Status status = OnDemandUpdateInternal(item);
1065 if (status == kOk || status == kInProgress) {
1066 item->throttles.push_back(rt);
1067 return;
1068 }
1069 UnblockResourceThrottle(rt);
1070}
1071
1072///////////////////////////////////////////////////////////////////////////////
1073
1074CUResourceThrottle::CUResourceThrottle(const net::URLRequest* request)
1075 : state_(NEW) {
1076 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1077}
1078
1079CUResourceThrottle::~CUResourceThrottle() {
1080 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1081}
1082
1083void CUResourceThrottle::WillStartRequest(bool* defer) {
1084 if (state_ != UNBLOCKED) {
1085 state_ = BLOCKED;
1086 *defer = true;
1087 } else {
1088 *defer = false;
1089 }
1090}
1091
1092void CUResourceThrottle::WillRedirectRequest(const GURL& new_url, bool* defer) {
1093 WillStartRequest(defer);
1094}
1095
[email protected]f8fe5cf2013-12-04 20:11:531096const char* CUResourceThrottle::GetNameForLogging() const {
1097 return "ComponentUpdateResourceThrottle";
1098}
1099
[email protected]00a77fa2013-11-02 04:18:461100void CUResourceThrottle::Unblock() {
1101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1102 if (state_ == BLOCKED)
1103 controller()->Resume();
1104 state_ = UNBLOCKED;
1105}
1106
[email protected]e8f96ff2011-08-03 05:07:331107// The component update factory. Using the component updater as a singleton
1108// is the job of the browser process.
1109ComponentUpdateService* ComponentUpdateServiceFactory(
1110 ComponentUpdateService::Configurator* config) {
1111 DCHECK(config);
1112 return new CrxUpdateService(config);
1113}
[email protected]2cddef42013-11-22 08:23:221114