blob: 2a8d14fc728b3205127feafc817ac850b2da40dd [file] [log] [blame]
[email protected]93e8e2c2014-01-04 12:29:231// Copyright 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]d3268fe2014-04-25 02:14:2319#include "base/observer_list.h"
[email protected]f5d27e32014-01-31 06:48:5320#include "base/sequenced_task_runner.h"
[email protected]e8f96ff2011-08-03 05:07:3321#include "base/stl_util.h"
[email protected]8f5f2ea2013-10-31 09:39:1022#include "base/threading/sequenced_worker_pool.h"
[email protected]41a17c52013-06-28 00:27:5323#include "base/timer/timer.h"
[email protected]e8f96ff2011-08-03 05:07:3324#include "chrome/browser/browser_process.h"
25#include "chrome/browser/component_updater/component_unpacker.h"
[email protected]7b0529242013-07-20 05:45:4626#include "chrome/browser/component_updater/component_updater_ping_manager.h"
[email protected]2cddef42013-11-22 08:23:2227#include "chrome/browser/component_updater/component_updater_utils.h"
[email protected]afa378f22013-12-02 03:37:5428#include "chrome/browser/component_updater/crx_downloader.h"
[email protected]7b0529242013-07-20 05:45:4629#include "chrome/browser/component_updater/crx_update_item.h"
[email protected]93e8e2c2014-01-04 12:29:2330#include "chrome/browser/component_updater/update_checker.h"
[email protected]6268d3a2013-11-27 01:28:0931#include "chrome/browser/component_updater/update_response.h"
[email protected]e8f96ff2011-08-03 05:07:3332#include "chrome/common/chrome_version_info.h"
[email protected]b7b63872013-01-03 02:41:1933#include "content/public/browser/browser_thread.h"
[email protected]00a77fa2013-11-02 04:18:4634#include "content/public/browser/resource_controller.h"
35#include "content/public/browser/resource_throttle.h"
[email protected]761fa4702013-07-02 15:25:1536#include "url/gurl.h"
[email protected]e8f96ff2011-08-03 05:07:3337
[email protected]631bb742011-11-02 11:29:3938using content::BrowserThread;
39
[email protected]055981f2014-01-17 20:22:3240namespace component_updater {
[email protected]3a0092d2013-12-18 03:04:3541
[email protected]44da56e2011-11-21 19:59:1442// The component updater is designed to live until process shutdown, so
43// base::Bind() calls are not refcounted.
44
[email protected]e8f96ff2011-08-03 05:07:3345namespace {
[email protected]e3e696d32013-06-21 20:41:3646
[email protected]2cddef42013-11-22 08:23:2247// Returns true if the |proposed| version is newer than |current| version.
[email protected]c5e4a2222014-01-03 16:06:1348bool IsVersionNewer(const Version& current, const std::string& proposed) {
49 Version proposed_ver(proposed);
[email protected]2cddef42013-11-22 08:23:2250 return proposed_ver.IsValid() && current.CompareTo(proposed_ver) < 0;
[email protected]e8f96ff2011-08-03 05:07:3351}
52
[email protected]e3e696d32013-06-21 20:41:3653// Returns true if a differential update is available, it has not failed yet,
54// and the configuration allows it.
55bool CanTryDiffUpdate(const CrxUpdateItem* update_item,
56 const ComponentUpdateService::Configurator& config) {
[email protected]055981f2014-01-17 20:22:3257 return HasDiffUpdate(update_item) &&
[email protected]e3e696d32013-06-21 20:41:3658 !update_item->diff_update_failed &&
59 config.DeltasEnabled();
60}
61
[email protected]3a0092d2013-12-18 03:04:3562void AppendDownloadMetrics(
63 const std::vector<CrxDownloader::DownloadMetrics>& source,
64 std::vector<CrxDownloader::DownloadMetrics>* destination) {
65 destination->insert(destination->end(), source.begin(), source.end());
66}
67
[email protected]7b0529242013-07-20 05:45:4668} // namespace
69
70CrxUpdateItem::CrxUpdateItem()
71 : status(kNew),
[email protected]61aca4cd2013-10-26 10:50:5972 on_demand(false),
[email protected]7b0529242013-07-20 05:45:4673 diff_update_failed(false),
74 error_category(0),
75 error_code(0),
76 extra_code1(0),
77 diff_error_category(0),
78 diff_error_code(0),
79 diff_extra_code1(0) {
80}
81
82CrxUpdateItem::~CrxUpdateItem() {
83}
[email protected]86550a42013-06-21 15:20:4984
[email protected]dc06f0b2013-01-23 20:03:1685CrxComponent::CrxComponent()
[email protected]85e61d52013-08-01 22:23:4286 : installer(NULL),
[email protected]cfd13e52014-02-05 09:35:0787 allow_background_download(true) {
[email protected]dc06f0b2013-01-23 20:03:1688}
89
90CrxComponent::~CrxComponent() {
91}
[email protected]e8f96ff2011-08-03 05:07:3392
[email protected]2e919ddd2013-08-21 05:05:1793CrxComponentInfo::CrxComponentInfo() {
94}
95
96CrxComponentInfo::~CrxComponentInfo() {
97}
98
[email protected]00a77fa2013-11-02 04:18:4699///////////////////////////////////////////////////////////////////////////////
100// In charge of blocking url requests until the |crx_id| component has been
101// updated. This class is touched solely from the IO thread. The UI thread
102// can post tasks to it via weak pointers. By default the request is blocked
103// unless the CrxUpdateService calls Unblock().
104// The lifetime is controlled by Chrome's resource loader so the component
105// updater cannot touch objects from this class except via weak pointers.
106class CUResourceThrottle
107 : public content::ResourceThrottle,
108 public base::SupportsWeakPtr<CUResourceThrottle> {
109 public:
110 explicit CUResourceThrottle(const net::URLRequest* request);
111 virtual ~CUResourceThrottle();
[email protected]2cddef42013-11-22 08:23:22112
[email protected]00a77fa2013-11-02 04:18:46113 // Overriden from ResourceThrottle.
114 virtual void WillStartRequest(bool* defer) OVERRIDE;
115 virtual void WillRedirectRequest(const GURL& new_url, bool* defer) OVERRIDE;
[email protected]f8fe5cf2013-12-04 20:11:53116 virtual const char* GetNameForLogging() const OVERRIDE;
[email protected]00a77fa2013-11-02 04:18:46117
118 // Component updater calls this function via PostTask to unblock the request.
119 void Unblock();
120
121 typedef std::vector<base::WeakPtr<CUResourceThrottle> > WeakPtrVector;
122
123 private:
[email protected]2cddef42013-11-22 08:23:22124 enum State {
125 NEW,
126 BLOCKED,
127 UNBLOCKED
128 };
[email protected]00a77fa2013-11-02 04:18:46129
[email protected]2cddef42013-11-22 08:23:22130 State state_;
[email protected]00a77fa2013-11-02 04:18:46131};
132
133void UnblockResourceThrottle(base::WeakPtr<CUResourceThrottle> rt) {
134 BrowserThread::PostTask(
135 BrowserThread::IO,
136 FROM_HERE,
137 base::Bind(&CUResourceThrottle::Unblock, rt));
138}
139
140void UnblockandReapAllThrottles(CUResourceThrottle::WeakPtrVector* throttles) {
141 CUResourceThrottle::WeakPtrVector::iterator it;
142 for (it = throttles->begin(); it != throttles->end(); ++it)
143 UnblockResourceThrottle(*it);
144 throttles->clear();
145}
146
[email protected]e8f96ff2011-08-03 05:07:33147//////////////////////////////////////////////////////////////////////////////
148// The one and only implementation of the ComponentUpdateService interface. In
149// charge of running the show. The main method is ProcessPendingItems() which
[email protected]50b01392012-09-01 03:33:13150// is called periodically to do the upgrades/installs or the update checks.
[email protected]e8f96ff2011-08-03 05:07:33151// An important consideration here is to be as "low impact" as we can to the
152// rest of the browser, so even if we have many components registered and
[email protected]f1050432012-02-15 01:35:46153// eligible for update, we only do one thing at a time with pauses in between
[email protected]e8f96ff2011-08-03 05:07:33154// the tasks. Also when we do network requests there is only one |url_fetcher_|
[email protected]e3e696d32013-06-21 20:41:36155// in flight at a time.
[email protected]e8f96ff2011-08-03 05:07:33156// There are no locks in this code, the main structure |work_items_| is mutated
[email protected]74be2642014-02-07 09:40:37157// only from the UI thread. The unpack and installation is done in a blocking
158// pool thread. The network requests are done in the IO thread or in the file
[email protected]e8f96ff2011-08-03 05:07:33159// thread.
160class CrxUpdateService : public ComponentUpdateService {
161 public:
162 explicit CrxUpdateService(ComponentUpdateService::Configurator* config);
[email protected]e8f96ff2011-08-03 05:07:33163 virtual ~CrxUpdateService();
164
165 // Overrides for ComponentUpdateService.
[email protected]d3268fe2014-04-25 02:14:23166 virtual void AddObserver(Observer* observer) OVERRIDE;
167 virtual void RemoveObserver(Observer* observer) OVERRIDE;
[email protected]e8f96ff2011-08-03 05:07:33168 virtual Status Start() OVERRIDE;
169 virtual Status Stop() OVERRIDE;
170 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE;
[email protected]61aca4cd2013-10-26 10:50:59171 virtual Status OnDemandUpdate(const std::string& component_id) OVERRIDE;
[email protected]2e919ddd2013-08-21 05:05:17172 virtual void GetComponents(
173 std::vector<CrxComponentInfo>* components) OVERRIDE;
[email protected]00a77fa2013-11-02 04:18:46174 virtual content::ResourceThrottle* GetOnDemandResourceThrottle(
175 net::URLRequest* request, const std::string& crx_id) OVERRIDE;
[email protected]e8f96ff2011-08-03 05:07:33176
[email protected]93e8e2c2014-01-04 12:29:23177 // Context for a crx download url request.
178 struct CRXContext {
179 ComponentInstaller* installer;
180 std::vector<uint8> pk_hash;
181 std::string id;
182 std::string fingerprint;
183 CRXContext() : installer(NULL) {}
184 };
[email protected]e8f96ff2011-08-03 05:07:33185
[email protected]e8f96ff2011-08-03 05:07:33186 private:
[email protected]7b0529242013-07-20 05:45:46187 enum ErrorCategory {
188 kErrorNone = 0,
189 kNetworkError,
190 kUnpackError,
191 kInstallError,
192 };
193
[email protected]32a6c8382013-08-20 00:29:20194 enum StepDelayInterval {
195 kStepDelayShort = 0,
196 kStepDelayMedium,
197 kStepDelayLong,
198 };
199
[email protected]055981f2014-01-17 20:22:32200 void UpdateCheckComplete(int error,
201 const std::string& error_message,
202 const UpdateResponse::Results& results);
203 void OnUpdateCheckSucceeded(const UpdateResponse::Results& results);
[email protected]93e8e2c2014-01-04 12:29:23204 void OnUpdateCheckFailed(int error, const std::string& error_message);
[email protected]e8f96ff2011-08-03 05:07:33205
[email protected]3cb2a4f2013-12-07 21:54:34206 void DownloadComplete(
207 scoped_ptr<CRXContext> crx_context,
[email protected]3a0092d2013-12-18 03:04:35208 const CrxDownloader::Result& download_result);
[email protected]afa378f22013-12-02 03:37:54209
[email protected]00a77fa2013-11-02 04:18:46210 Status OnDemandUpdateInternal(CrxUpdateItem* item);
211
[email protected]e8f96ff2011-08-03 05:07:33212 void ProcessPendingItems();
213
[email protected]93e8e2c2014-01-04 12:29:23214 // Find a component that is ready to update.
215 CrxUpdateItem* FindReadyComponent() const;
216
217 // Prepares the components for an update check and initiates the request.
218 // Returns true if an update check request has been made. Returns false if
219 // no update check was needed or an error occured.
220 bool CheckForUpdates();
[email protected]61aca4cd2013-10-26 10:50:59221
222 void UpdateComponent(CrxUpdateItem* workitem);
223
[email protected]32a6c8382013-08-20 00:29:20224 void ScheduleNextRun(StepDelayInterval step_delay);
[email protected]e8f96ff2011-08-03 05:07:33225
[email protected]6268d3a2013-11-27 01:28:09226 void ParseResponse(const std::string& xml);
[email protected]e8f96ff2011-08-03 05:07:33227
[email protected]afa378f22013-12-02 03:37:54228 void Install(scoped_ptr<CRXContext> context, const base::FilePath& crx_path);
[email protected]e8f96ff2011-08-03 05:07:33229
[email protected]f5d27e32014-01-31 06:48:53230 void EndUnpacking(const std::string& component_id,
231 const base::FilePath& crx_path,
232 ComponentUnpacker::Error error,
233 int extended_error);
234
[email protected]07f93af12011-08-17 20:57:22235 void DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:36236 ComponentUnpacker::Error error,
237 int extended_error);
[email protected]e8f96ff2011-08-03 05:07:33238
[email protected]61aca4cd2013-10-26 10:50:59239 void ChangeItemState(CrxUpdateItem* item, CrxUpdateItem::Status to);
240
[email protected]e8f96ff2011-08-03 05:07:33241 size_t ChangeItemStatus(CrxUpdateItem::Status from,
242 CrxUpdateItem::Status to);
243
244 CrxUpdateItem* FindUpdateItemById(const std::string& id);
245
[email protected]d3268fe2014-04-25 02:14:23246 void NotifyObservers(Observer::Events event, const std::string& id);
[email protected]85e61d52013-08-01 22:23:42247
[email protected]61aca4cd2013-10-26 10:50:59248 bool HasOnDemandItems() const;
249
[email protected]00a77fa2013-11-02 04:18:46250 void OnNewResourceThrottle(base::WeakPtr<CUResourceThrottle> rt,
251 const std::string& crx_id);
252
[email protected]e3e696d32013-06-21 20:41:36253 scoped_ptr<ComponentUpdateService::Configurator> config_;
254
[email protected]055981f2014-01-17 20:22:32255 scoped_ptr<UpdateChecker> update_checker_;
[email protected]e8f96ff2011-08-03 05:07:33256
[email protected]055981f2014-01-17 20:22:32257 scoped_ptr<PingManager> ping_manager_;
[email protected]7b0529242013-07-20 05:45:46258
[email protected]94a481b2014-03-28 19:41:55259 scoped_refptr<ComponentUnpacker> unpacker_;
[email protected]f5d27e32014-01-31 06:48:53260
[email protected]055981f2014-01-17 20:22:32261 scoped_ptr<CrxDownloader> crx_downloader_;
[email protected]afa378f22013-12-02 03:37:54262
[email protected]86550a42013-06-21 15:20:49263 // A collection of every work item.
[email protected]e3e696d32013-06-21 20:41:36264 typedef std::vector<CrxUpdateItem*> UpdateItems;
[email protected]e8f96ff2011-08-03 05:07:33265 UpdateItems work_items_;
266
267 base::OneShotTimer<CrxUpdateService> timer_;
268
[email protected]8f5f2ea2013-10-31 09:39:10269 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
270
[email protected]c5e4a2222014-01-03 16:06:13271 const Version chrome_version_;
[email protected]e8f96ff2011-08-03 05:07:33272
273 bool running_;
274
[email protected]d3268fe2014-04-25 02:14:23275 ObserverList<Observer> observer_list_;
276
[email protected]e8f96ff2011-08-03 05:07:33277 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
278};
279
[email protected]e8f96ff2011-08-03 05:07:33280//////////////////////////////////////////////////////////////////////////////
281
[email protected]e3e696d32013-06-21 20:41:36282CrxUpdateService::CrxUpdateService(ComponentUpdateService::Configurator* config)
[email protected]e8f96ff2011-08-03 05:07:33283 : config_(config),
[email protected]055981f2014-01-17 20:22:32284 ping_manager_(new PingManager(config->PingUrl(),
285 config->RequestContext())),
[email protected]8f5f2ea2013-10-31 09:39:10286 blocking_task_runner_(BrowserThread::GetBlockingPool()->
287 GetSequencedTaskRunnerWithShutdownBehavior(
288 BrowserThread::GetBlockingPool()->GetSequenceToken(),
289 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)),
[email protected]e8f96ff2011-08-03 05:07:33290 chrome_version_(chrome::VersionInfo().Version()),
291 running_(false) {
[email protected]1ea21ad2013-09-02 04:20:39292}
[email protected]e8f96ff2011-08-03 05:07:33293
294CrxUpdateService::~CrxUpdateService() {
295 // Because we are a singleton, at this point only the UI thread should be
296 // alive, this simplifies the management of the work that could be in
297 // flight in other threads.
298 Stop();
299 STLDeleteElements(&work_items_);
[email protected]1ea21ad2013-09-02 04:20:39300}
[email protected]e8f96ff2011-08-03 05:07:33301
[email protected]d3268fe2014-04-25 02:14:23302void CrxUpdateService::AddObserver(Observer* observer) {
303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
304 observer_list_.AddObserver(observer);
305}
306
307void CrxUpdateService::RemoveObserver(Observer* observer) {
308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
309 observer_list_.RemoveObserver(observer);
310}
311
[email protected]e8f96ff2011-08-03 05:07:33312ComponentUpdateService::Status CrxUpdateService::Start() {
313 // Note that RegisterComponent will call Start() when the first
314 // component is registered, so it can be called twice. This way
315 // we avoid scheduling the timer if there is no work to do.
316 running_ = true;
317 if (work_items_.empty())
318 return kOk;
319
[email protected]d3268fe2014-04-25 02:14:23320 NotifyObservers(Observer::COMPONENT_UPDATER_STARTED, "");
[email protected]85e61d52013-08-01 22:23:42321
[email protected]d323a172011-09-02 18:23:02322 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->InitialDelay()),
[email protected]e8f96ff2011-08-03 05:07:33323 this, &CrxUpdateService::ProcessPendingItems);
324 return kOk;
325}
326
327// Stop the main check + update loop. In flight operations will be
328// completed.
329ComponentUpdateService::Status CrxUpdateService::Stop() {
330 running_ = false;
331 timer_.Stop();
332 return kOk;
333}
334
[email protected]61aca4cd2013-10-26 10:50:59335bool CrxUpdateService::HasOnDemandItems() const {
336 class Helper {
337 public:
338 static bool IsOnDemand(CrxUpdateItem* item) {
339 return item->on_demand;
340 }
341 };
342 return std::find_if(work_items_.begin(),
343 work_items_.end(),
344 Helper::IsOnDemand) != work_items_.end();
345}
346
[email protected]ccb4feef2013-02-14 06:16:47347// This function sets the timer which will call ProcessPendingItems() or
[email protected]61aca4cd2013-10-26 10:50:59348// ProcessRequestedItem() if there is an on_demand item. There
[email protected]32a6c8382013-08-20 00:29:20349// are three kinds of waits:
350// - a short delay, when there is immediate work to be done.
351// - a medium delay, when there are updates to be applied within the current
352// update cycle, or there are components that are still unchecked.
353// - a long delay when a full check/update cycle has completed for all
354// components.
355void CrxUpdateService::ScheduleNextRun(StepDelayInterval step_delay) {
[email protected]e8f96ff2011-08-03 05:07:33356 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]93e8e2c2014-01-04 12:29:23357 DCHECK(!update_checker_);
[email protected]e8f96ff2011-08-03 05:07:33358 CHECK(!timer_.IsRunning());
359 // It could be the case that Stop() had been called while a url request
360 // or unpacking was in flight, if so we arrive here but |running_| is
361 // false. In that case do not loop again.
362 if (!running_)
363 return;
364
[email protected]ccb4feef2013-02-14 06:16:47365 // Keep the delay short if in the middle of an update (step_delay),
366 // or there are new requested_work_items_ that have not been processed yet.
[email protected]32a6c8382013-08-20 00:29:20367 int64 delay_seconds = 0;
[email protected]61aca4cd2013-10-26 10:50:59368 if (!HasOnDemandItems()) {
[email protected]32a6c8382013-08-20 00:29:20369 switch (step_delay) {
370 case kStepDelayShort:
371 delay_seconds = config_->StepDelay();
372 break;
373 case kStepDelayMedium:
374 delay_seconds = config_->StepDelayMedium();
375 break;
376 case kStepDelayLong:
377 delay_seconds = config_->NextCheckDelay();
378 break;
379 }
380 } else {
381 delay_seconds = config_->StepDelay();
382 }
[email protected]cf442612011-08-09 20:20:12383
[email protected]32a6c8382013-08-20 00:29:20384 if (step_delay != kStepDelayShort) {
[email protected]d3268fe2014-04-25 02:14:23385 NotifyObservers(Observer::COMPONENT_UPDATER_SLEEPING, "");
[email protected]85e61d52013-08-01 22:23:42386
[email protected]e8f96ff2011-08-03 05:07:33387 // Zero is only used for unit tests.
[email protected]32a6c8382013-08-20 00:29:20388 if (0 == delay_seconds)
[email protected]e8f96ff2011-08-03 05:07:33389 return;
390 }
391
[email protected]32a6c8382013-08-20 00:29:20392 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay_seconds),
[email protected]e8f96ff2011-08-03 05:07:33393 this, &CrxUpdateService::ProcessPendingItems);
394}
395
396// Given a extension-like component id, find the associated component.
397CrxUpdateItem* CrxUpdateService::FindUpdateItemById(const std::string& id) {
398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
399 CrxUpdateItem::FindById finder(id);
400 UpdateItems::iterator it = std::find_if(work_items_.begin(),
401 work_items_.end(),
402 finder);
[email protected]93e8e2c2014-01-04 12:29:23403 return it != work_items_.end() ? *it : NULL;
[email protected]e8f96ff2011-08-03 05:07:33404}
405
[email protected]61aca4cd2013-10-26 10:50:59406// Changes a component's status, clearing on_demand and firing notifications as
407// necessary. By convention, this is the only function that can change a
408// CrxUpdateItem's |status|.
409// TODO(waffles): Do we want to add DCHECKS for valid state transitions here?
410void CrxUpdateService::ChangeItemState(CrxUpdateItem* item,
411 CrxUpdateItem::Status to) {
412 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
413 if (to == CrxUpdateItem::kNoUpdate ||
414 to == CrxUpdateItem::kUpdated ||
415 to == CrxUpdateItem::kUpToDate) {
416 item->on_demand = false;
417 }
418
419 item->status = to;
420
[email protected]d3268fe2014-04-25 02:14:23421 switch (to) {
422 case CrxUpdateItem::kCanUpdate:
423 NotifyObservers(Observer::COMPONENT_UPDATE_FOUND, item->id);
424 break;
425 case CrxUpdateItem::kUpdatingDiff:
426 case CrxUpdateItem::kUpdating:
427 NotifyObservers(Observer::COMPONENT_UPDATE_READY, item->id);
428 break;
429 case CrxUpdateItem::kUpdated:
430 NotifyObservers(Observer::COMPONENT_UPDATED, item->id);
431 break;
432 case CrxUpdateItem::kUpToDate:
433 case CrxUpdateItem::kNoUpdate:
434 NotifyObservers(Observer::COMPONENT_NOT_UPDATED, item->id);
435 break;
436 case CrxUpdateItem::kNew:
437 case CrxUpdateItem::kChecking:
438 case CrxUpdateItem::kDownloading:
439 case CrxUpdateItem::kDownloadingDiff:
440 case CrxUpdateItem::kLastStatus:
441 // No notification for these states.
442 break;
[email protected]61aca4cd2013-10-26 10:50:59443 }
[email protected]00a77fa2013-11-02 04:18:46444
445 // Free possible pending network requests.
446 if ((to == CrxUpdateItem::kUpdated) ||
447 (to == CrxUpdateItem::kUpToDate) ||
448 (to == CrxUpdateItem::kNoUpdate)) {
449 UnblockandReapAllThrottles(&item->throttles);
450 }
[email protected]61aca4cd2013-10-26 10:50:59451}
452
[email protected]e8f96ff2011-08-03 05:07:33453// Changes all the components in |work_items_| that have |from| status to
[email protected]e3e696d32013-06-21 20:41:36454// |to| status and returns how many have been changed.
[email protected]e8f96ff2011-08-03 05:07:33455size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from,
456 CrxUpdateItem::Status to) {
457 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
458 size_t count = 0;
459 for (UpdateItems::iterator it = work_items_.begin();
460 it != work_items_.end(); ++it) {
461 CrxUpdateItem* item = *it;
[email protected]93e8e2c2014-01-04 12:29:23462 if (item->status == from) {
463 ChangeItemState(item, to);
464 ++count;
465 }
[email protected]e8f96ff2011-08-03 05:07:33466 }
467 return count;
468}
469
470// Adds a component to be checked for upgrades. If the component exists it
471// it will be replaced and the return code is kReplaced.
[email protected]e8f96ff2011-08-03 05:07:33472ComponentUpdateService::Status CrxUpdateService::RegisterComponent(
473 const CrxComponent& component) {
474 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
475 if (component.pk_hash.empty() ||
476 !component.version.IsValid() ||
477 !component.installer)
478 return kError;
479
[email protected]055981f2014-01-17 20:22:32480 std::string id(GetCrxComponentID(component));
[email protected]93e8e2c2014-01-04 12:29:23481 CrxUpdateItem* uit = FindUpdateItemById(id);
[email protected]e8f96ff2011-08-03 05:07:33482 if (uit) {
483 uit->component = component;
484 return kReplaced;
485 }
486
487 uit = new CrxUpdateItem;
488 uit->id.swap(id);
489 uit->component = component;
[email protected]e3e696d32013-06-21 20:41:36490
[email protected]e8f96ff2011-08-03 05:07:33491 work_items_.push_back(uit);
492 // If this is the first component registered we call Start to
493 // schedule the first timer.
494 if (running_ && (work_items_.size() == 1))
495 Start();
496
497 return kOk;
498}
499
[email protected]ccb4feef2013-02-14 06:16:47500// Start the process of checking for an update, for a particular component
501// that was previously registered.
[email protected]2e919ddd2013-08-21 05:05:17502// |component_id| is a value returned from GetCrxComponentID().
[email protected]61aca4cd2013-10-26 10:50:59503ComponentUpdateService::Status CrxUpdateService::OnDemandUpdate(
[email protected]2e919ddd2013-08-21 05:05:17504 const std::string& component_id) {
[email protected]00a77fa2013-11-02 04:18:46505 return OnDemandUpdateInternal(FindUpdateItemById(component_id));
506}
507
508ComponentUpdateService::Status CrxUpdateService::OnDemandUpdateInternal(
509 CrxUpdateItem* uit) {
[email protected]ccb4feef2013-02-14 06:16:47510 if (!uit)
511 return kError;
[email protected]2cddef42013-11-22 08:23:22512
[email protected]ccb4feef2013-02-14 06:16:47513 // Check if the request is too soon.
514 base::TimeDelta delta = base::Time::Now() - uit->last_check;
[email protected]e3e696d32013-06-21 20:41:36515 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
[email protected]ccb4feef2013-02-14 06:16:47516 return kError;
[email protected]ccb4feef2013-02-14 06:16:47517
518 switch (uit->status) {
519 // If the item is already in the process of being updated, there is
520 // no point in this call, so return kInProgress.
521 case CrxUpdateItem::kChecking:
522 case CrxUpdateItem::kCanUpdate:
[email protected]e3e696d32013-06-21 20:41:36523 case CrxUpdateItem::kDownloadingDiff:
[email protected]ccb4feef2013-02-14 06:16:47524 case CrxUpdateItem::kDownloading:
[email protected]e3e696d32013-06-21 20:41:36525 case CrxUpdateItem::kUpdatingDiff:
[email protected]ccb4feef2013-02-14 06:16:47526 case CrxUpdateItem::kUpdating:
527 return kInProgress;
528 // Otherwise the item was already checked a while back (or it is new),
529 // set its status to kNew to give it a slightly higher priority.
530 case CrxUpdateItem::kNew:
531 case CrxUpdateItem::kUpdated:
532 case CrxUpdateItem::kUpToDate:
533 case CrxUpdateItem::kNoUpdate:
[email protected]61aca4cd2013-10-26 10:50:59534 ChangeItemState(uit, CrxUpdateItem::kNew);
535 uit->on_demand = true;
[email protected]ccb4feef2013-02-14 06:16:47536 break;
537 case CrxUpdateItem::kLastStatus:
538 NOTREACHED() << uit->status;
539 }
540
541 // In case the current delay is long, set the timer to a shorter value
542 // to get the ball rolling.
543 if (timer_.IsRunning()) {
544 timer_.Stop();
545 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->StepDelay()),
546 this, &CrxUpdateService::ProcessPendingItems);
547 }
548
549 return kOk;
550}
551
[email protected]2e919ddd2013-08-21 05:05:17552void CrxUpdateService::GetComponents(
553 std::vector<CrxComponentInfo>* components) {
554 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
555 for (UpdateItems::const_iterator it = work_items_.begin();
556 it != work_items_.end(); ++it) {
557 const CrxUpdateItem* item = *it;
558 CrxComponentInfo info;
[email protected]055981f2014-01-17 20:22:32559 info.id = GetCrxComponentID(item->component);
[email protected]2e919ddd2013-08-21 05:05:17560 info.version = item->component.version.GetString();
561 info.name = item->component.name;
562 components->push_back(info);
563 }
564}
565
[email protected]93e8e2c2014-01-04 12:29:23566// This is the main loop of the component updater. It updates one component
567// at a time if updates are available. Otherwise, it does an update check or
568// takes a long sleep until the loop runs again.
[email protected]e8f96ff2011-08-03 05:07:33569void CrxUpdateService::ProcessPendingItems() {
570 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]93e8e2c2014-01-04 12:29:23571
[email protected]61aca4cd2013-10-26 10:50:59572 CrxUpdateItem* ready_upgrade = FindReadyComponent();
573 if (ready_upgrade) {
574 UpdateComponent(ready_upgrade);
[email protected]e8f96ff2011-08-03 05:07:33575 return;
576 }
[email protected]93e8e2c2014-01-04 12:29:23577
578 if (!CheckForUpdates())
579 ScheduleNextRun(kStepDelayLong);
[email protected]61aca4cd2013-10-26 10:50:59580}
581
[email protected]93e8e2c2014-01-04 12:29:23582CrxUpdateItem* CrxUpdateService::FindReadyComponent() const {
[email protected]c4b4cfa2014-03-10 18:55:00583 class Helper {
584 public:
585 static bool IsReadyOnDemand(CrxUpdateItem* item) {
586 return item->on_demand && IsReady(item);
[email protected]61aca4cd2013-10-26 10:50:59587 }
[email protected]c4b4cfa2014-03-10 18:55:00588 static bool IsReady(CrxUpdateItem* item) {
589 return item->status == CrxUpdateItem::kCanUpdate;
590 }
591 };
[email protected]61aca4cd2013-10-26 10:50:59592
[email protected]c4b4cfa2014-03-10 18:55:00593 std::vector<CrxUpdateItem*>::const_iterator it = std::find_if(
594 work_items_.begin(), work_items_.end(), Helper::IsReadyOnDemand);
595 if (it != work_items_.end())
596 return *it;
597 it = std::find_if(work_items_.begin(), work_items_.end(), Helper::IsReady);
598 if (it != work_items_.end())
599 return *it;
[email protected]61aca4cd2013-10-26 10:50:59600 return NULL;
601}
602
[email protected]93e8e2c2014-01-04 12:29:23603// Prepares the components for an update check and initiates the request.
[email protected]21a9c9a2014-02-19 19:37:11604// On demand components are always included in the update check request.
605// Otherwise, only include components that have not been checked recently.
[email protected]93e8e2c2014-01-04 12:29:23606bool CrxUpdateService::CheckForUpdates() {
[email protected]21a9c9a2014-02-19 19:37:11607 const base::TimeDelta minimum_recheck_wait_time =
608 base::TimeDelta::FromSeconds(config_->MinimumReCheckWait());
609 const base::Time now(base::Time::Now());
610
[email protected]93e8e2c2014-01-04 12:29:23611 std::vector<CrxUpdateItem*> items_to_check;
612 for (size_t i = 0; i != work_items_.size(); ++i) {
613 CrxUpdateItem* item = work_items_[i];
614 DCHECK(item->status == CrxUpdateItem::kNew ||
615 item->status == CrxUpdateItem::kNoUpdate ||
616 item->status == CrxUpdateItem::kUpToDate ||
617 item->status == CrxUpdateItem::kUpdated);
618
[email protected]21a9c9a2014-02-19 19:37:11619 const base::TimeDelta time_since_last_checked(now - item->last_check);
620
621 if (!item->on_demand &&
622 time_since_last_checked < minimum_recheck_wait_time) {
623 continue;
624 }
625
[email protected]93e8e2c2014-01-04 12:29:23626 ChangeItemState(item, CrxUpdateItem::kChecking);
627
[email protected]21a9c9a2014-02-19 19:37:11628 item->last_check = now;
[email protected]93e8e2c2014-01-04 12:29:23629 item->crx_urls.clear();
630 item->crx_diffurls.clear();
631 item->previous_version = item->component.version;
632 item->next_version = Version();
633 item->previous_fp = item->component.fingerprint;
634 item->next_fp.clear();
635 item->diff_update_failed = false;
636 item->error_category = 0;
637 item->error_code = 0;
638 item->extra_code1 = 0;
639 item->diff_error_category = 0;
640 item->diff_error_code = 0;
641 item->diff_extra_code1 = 0;
642 item->download_metrics.clear();
643
644 items_to_check.push_back(item);
645 }
646
647 if (items_to_check.empty())
648 return false;
649
[email protected]055981f2014-01-17 20:22:32650 update_checker_ = UpdateChecker::Create(
[email protected]93e8e2c2014-01-04 12:29:23651 config_->UpdateUrl(),
652 config_->RequestContext(),
653 base::Bind(&CrxUpdateService::UpdateCheckComplete,
654 base::Unretained(this))).Pass();
655 return update_checker_->CheckForUpdates(items_to_check,
656 config_->ExtraRequestParams());
657}
658
[email protected]61aca4cd2013-10-26 10:50:59659void CrxUpdateService::UpdateComponent(CrxUpdateItem* workitem) {
[email protected]afa378f22013-12-02 03:37:54660 scoped_ptr<CRXContext> crx_context(new CRXContext);
661 crx_context->pk_hash = workitem->component.pk_hash;
662 crx_context->id = workitem->id;
663 crx_context->installer = workitem->component.installer;
664 crx_context->fingerprint = workitem->next_fp;
[email protected]da37c1d2013-12-19 01:04:38665 const std::vector<GURL>* urls = NULL;
[email protected]cfd13e52014-02-05 09:35:07666 bool allow_background_download = false;
[email protected]61aca4cd2013-10-26 10:50:59667 if (CanTryDiffUpdate(workitem, *config_)) {
[email protected]da37c1d2013-12-19 01:04:38668 urls = &workitem->crx_diffurls;
[email protected]61aca4cd2013-10-26 10:50:59669 ChangeItemState(workitem, CrxUpdateItem::kDownloadingDiff);
670 } else {
[email protected]cfd13e52014-02-05 09:35:07671 // Background downloads are enabled only for selected components and
672 // only for full downloads (see issue 340448).
673 allow_background_download = workitem->component.allow_background_download;
[email protected]da37c1d2013-12-19 01:04:38674 urls = &workitem->crx_urls;
[email protected]61aca4cd2013-10-26 10:50:59675 ChangeItemState(workitem, CrxUpdateItem::kDownloading);
676 }
[email protected]3cb2a4f2013-12-07 21:54:34677
678 // On demand component updates are always downloaded in foreground.
[email protected]cfd13e52014-02-05 09:35:07679 const bool is_background_download =
680 !workitem->on_demand && allow_background_download &&
681 config_->UseBackgroundDownloader();
[email protected]3cb2a4f2013-12-07 21:54:34682
[email protected]1b6587dc52014-04-26 00:38:55683 crx_downloader_.reset(CrxDownloader::Create(is_background_download,
684 config_->RequestContext(),
685 blocking_task_runner_));
686 crx_downloader_->StartDownload(*urls,
687 base::Bind(&CrxUpdateService::DownloadComplete,
688 base::Unretained(this),
689 base::Passed(&crx_context)));
[email protected]61aca4cd2013-10-26 10:50:59690}
691
[email protected]93e8e2c2014-01-04 12:29:23692void CrxUpdateService::UpdateCheckComplete(
693 int error,
694 const std::string& error_message,
[email protected]055981f2014-01-17 20:22:32695 const UpdateResponse::Results& results) {
[email protected]e8f96ff2011-08-03 05:07:33696 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]93e8e2c2014-01-04 12:29:23697 update_checker_.reset();
698 if (!error)
699 OnUpdateCheckSucceeded(results);
[email protected]652f4272013-11-13 09:23:41700 else
[email protected]93e8e2c2014-01-04 12:29:23701 OnUpdateCheckFailed(error, error_message);
[email protected]e8f96ff2011-08-03 05:07:33702}
703
[email protected]93e8e2c2014-01-04 12:29:23704// Handles a valid Omaha update check response by matching the results with
705// the registered components which were checked for updates.
706// If updates are found, prepare the components for the actual version upgrade.
707// One of these components will be drafted for the upgrade next time
708// ProcessPendingItems is called.
709void CrxUpdateService::OnUpdateCheckSucceeded(
[email protected]055981f2014-01-17 20:22:32710 const UpdateResponse::Results& results) {
[email protected]2cddef42013-11-22 08:23:22711 size_t num_updates_pending = 0;
[email protected]e8f96ff2011-08-03 05:07:33712 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]055981f2014-01-17 20:22:32713 std::vector<UpdateResponse::Result>::const_iterator it;
[email protected]e8f96ff2011-08-03 05:07:33714 for (it = results.list.begin(); it != results.list.end(); ++it) {
715 CrxUpdateItem* crx = FindUpdateItemById(it->extension_id);
716 if (!crx)
717 continue;
718
[email protected]2cddef42013-11-22 08:23:22719 if (crx->status != CrxUpdateItem::kChecking) {
720 NOTREACHED();
[email protected]e8f96ff2011-08-03 05:07:33721 continue; // Not updating this component now.
[email protected]2cddef42013-11-22 08:23:22722 }
[email protected]e8f96ff2011-08-03 05:07:33723
[email protected]2cddef42013-11-22 08:23:22724 if (it->manifest.version.empty()) {
[email protected]cf442612011-08-09 20:20:12725 // No version means no update available.
[email protected]61aca4cd2013-10-26 10:50:59726 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
[email protected]cf442612011-08-09 20:20:12727 continue;
[email protected]e8f96ff2011-08-03 05:07:33728 }
[email protected]2cddef42013-11-22 08:23:22729
730 if (!IsVersionNewer(crx->component.version, it->manifest.version)) {
731 // The component is up to date.
[email protected]61aca4cd2013-10-26 10:50:59732 ChangeItemState(crx, CrxUpdateItem::kUpToDate);
[email protected]cf442612011-08-09 20:20:12733 continue;
[email protected]e8f96ff2011-08-03 05:07:33734 }
[email protected]2cddef42013-11-22 08:23:22735
736 if (!it->manifest.browser_min_version.empty()) {
737 if (IsVersionNewer(chrome_version_, it->manifest.browser_min_version)) {
738 // The component is not compatible with this Chrome version.
[email protected]61aca4cd2013-10-26 10:50:59739 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
[email protected]cf442612011-08-09 20:20:12740 continue;
741 }
[email protected]e8f96ff2011-08-03 05:07:33742 }
[email protected]2cddef42013-11-22 08:23:22743
744 if (it->manifest.packages.size() != 1) {
745 // Assume one and only one package per component.
746 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
747 continue;
748 }
749
750 // Parse the members of the result and queue an upgrade for this component.
[email protected]c5e4a2222014-01-03 16:06:13751 crx->next_version = Version(it->manifest.version);
[email protected]2cddef42013-11-22 08:23:22752
[email protected]055981f2014-01-17 20:22:32753 typedef UpdateResponse::Result::Manifest::Package Package;
[email protected]2cddef42013-11-22 08:23:22754 const Package& package(it->manifest.packages[0]);
755 crx->next_fp = package.fingerprint;
756
[email protected]da37c1d2013-12-19 01:04:38757 // Resolve the urls by combining the base urls with the package names.
758 for (size_t i = 0; i != it->crx_urls.size(); ++i) {
759 const GURL url(it->crx_urls[i].Resolve(package.name));
760 if (url.is_valid())
761 crx->crx_urls.push_back(url);
762 }
763 for (size_t i = 0; i != it->crx_diffurls.size(); ++i) {
764 const GURL url(it->crx_diffurls[i].Resolve(package.namediff));
765 if (url.is_valid())
766 crx->crx_diffurls.push_back(url);
767 }
[email protected]2cddef42013-11-22 08:23:22768
[email protected]61aca4cd2013-10-26 10:50:59769 ChangeItemState(crx, CrxUpdateItem::kCanUpdate);
[email protected]2cddef42013-11-22 08:23:22770 ++num_updates_pending;
[email protected]e8f96ff2011-08-03 05:07:33771 }
[email protected]cf442612011-08-09 20:20:12772
[email protected]2cddef42013-11-22 08:23:22773 // All components that are not included in the update response are
774 // considered up to date.
[email protected]cf442612011-08-09 20:20:12775 ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kUpToDate);
776
[email protected]32a6c8382013-08-20 00:29:20777 // If there are updates pending we do a short wait, otherwise we take
778 // a longer delay until we check the components again.
[email protected]21a9c9a2014-02-19 19:37:11779 ScheduleNextRun(num_updates_pending > 0 ? kStepDelayShort : kStepDelayLong);
[email protected]e8f96ff2011-08-03 05:07:33780}
781
[email protected]93e8e2c2014-01-04 12:29:23782// TODO: record UMA stats.
783void CrxUpdateService::OnUpdateCheckFailed(int error,
784 const std::string& error_message) {
[email protected]e8f96ff2011-08-03 05:07:33785 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]93e8e2c2014-01-04 12:29:23786 DCHECK(error);
[email protected]e8f96ff2011-08-03 05:07:33787 size_t count = ChangeItemStatus(CrxUpdateItem::kChecking,
788 CrxUpdateItem::kNoUpdate);
789 DCHECK_GT(count, 0ul);
[email protected]32a6c8382013-08-20 00:29:20790 ScheduleNextRun(kStepDelayLong);
[email protected]e8f96ff2011-08-03 05:07:33791}
792
793// Called when the CRX package has been downloaded to a temporary location.
794// Here we fire the notifications and schedule the component-specific installer
795// to be called in the file thread.
[email protected]3cb2a4f2013-12-07 21:54:34796void CrxUpdateService::DownloadComplete(
797 scoped_ptr<CRXContext> crx_context,
[email protected]3a0092d2013-12-18 03:04:35798 const CrxDownloader::Result& download_result) {
[email protected]e8f96ff2011-08-03 05:07:33799 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]64f39fa12013-09-03 21:49:37800
[email protected]64f39fa12013-09-03 21:49:37801 CrxUpdateItem* crx = FindUpdateItemById(crx_context->id);
[email protected]e3e696d32013-06-21 20:41:36802 DCHECK(crx->status == CrxUpdateItem::kDownloadingDiff ||
803 crx->status == CrxUpdateItem::kDownloading);
804
[email protected]3a0092d2013-12-18 03:04:35805 AppendDownloadMetrics(crx_downloader_->download_metrics(),
806 &crx->download_metrics);
807
[email protected]3cb2a4f2013-12-07 21:54:34808 if (download_result.error) {
[email protected]e3e696d32013-06-21 20:41:36809 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
[email protected]7b0529242013-07-20 05:45:46810 crx->diff_error_category = kNetworkError;
[email protected]3cb2a4f2013-12-07 21:54:34811 crx->diff_error_code = download_result.error;
[email protected]e630ba62013-06-22 15:22:34812 crx->diff_update_failed = true;
[email protected]e3e696d32013-06-21 20:41:36813 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
814 CrxUpdateItem::kCanUpdate);
815 DCHECK_EQ(count, 1ul);
[email protected]afa378f22013-12-02 03:37:54816 crx_downloader_.reset();
[email protected]7b0529242013-07-20 05:45:46817
[email protected]32a6c8382013-08-20 00:29:20818 ScheduleNextRun(kStepDelayShort);
[email protected]e3e696d32013-06-21 20:41:36819 return;
820 }
[email protected]7b0529242013-07-20 05:45:46821 crx->error_category = kNetworkError;
[email protected]3cb2a4f2013-12-07 21:54:34822 crx->error_code = download_result.error;
[email protected]e8f96ff2011-08-03 05:07:33823 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
824 CrxUpdateItem::kNoUpdate);
825 DCHECK_EQ(count, 1ul);
[email protected]afa378f22013-12-02 03:37:54826 crx_downloader_.reset();
[email protected]e3e696d32013-06-21 20:41:36827
[email protected]7b0529242013-07-20 05:45:46828 // At this point, since both the differential and the full downloads failed,
829 // the update for this component has finished with an error.
830 ping_manager_->OnUpdateComplete(crx);
831
[email protected]32a6c8382013-08-20 00:29:20832 // Move on to the next update, if there is one available.
833 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33834 } else {
[email protected]e3e696d32013-06-21 20:41:36835 size_t count = 0;
836 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
837 count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
838 CrxUpdateItem::kUpdatingDiff);
839 } else {
840 count = ChangeItemStatus(CrxUpdateItem::kDownloading,
841 CrxUpdateItem::kUpdating);
842 }
[email protected]e8f96ff2011-08-03 05:07:33843 DCHECK_EQ(count, 1ul);
[email protected]afa378f22013-12-02 03:37:54844 crx_downloader_.reset();
[email protected]cf442612011-08-09 20:20:12845
[email protected]44da56e2011-11-21 19:59:14846 // Why unretained? See comment at top of file.
[email protected]8f5f2ea2013-10-31 09:39:10847 blocking_task_runner_->PostDelayedTask(
[email protected]73251e72012-03-04 02:10:33848 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14849 base::Bind(&CrxUpdateService::Install,
850 base::Unretained(this),
[email protected]afa378f22013-12-02 03:37:54851 base::Passed(&crx_context),
[email protected]3cb2a4f2013-12-07 21:54:34852 download_result.response),
[email protected]73251e72012-03-04 02:10:33853 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]e8f96ff2011-08-03 05:07:33854 }
[email protected]e8f96ff2011-08-03 05:07:33855}
856
857// Install consists of digital signature verification, unpacking and then
858// calling the component specific installer. All that is handled by the
[email protected]f5d27e32014-01-31 06:48:53859// |unpacker_|. If there is an error this function is in charge of deleting
[email protected]e8f96ff2011-08-03 05:07:33860// the files created.
[email protected]afa378f22013-12-02 03:37:54861void CrxUpdateService::Install(scoped_ptr<CRXContext> context,
[email protected]650b2d52013-02-10 03:41:45862 const base::FilePath& crx_path) {
[email protected]8f5f2ea2013-10-31 09:39:10863 // This function owns the file at |crx_path| and the |context| object.
[email protected]94a481b2014-03-28 19:41:55864 unpacker_ = new ComponentUnpacker(context->pk_hash,
865 crx_path,
866 context->fingerprint,
867 context->installer,
868 config_->InProcess(),
869 blocking_task_runner_);
[email protected]f5d27e32014-01-31 06:48:53870 unpacker_->Unpack(base::Bind(&CrxUpdateService::EndUnpacking,
871 base::Unretained(this),
872 context->id,
873 crx_path));
874}
875
876void CrxUpdateService::EndUnpacking(const std::string& component_id,
877 const base::FilePath& crx_path,
878 ComponentUnpacker::Error error,
879 int extended_error) {
[email protected]055981f2014-01-17 20:22:32880 if (!DeleteFileAndEmptyParentDirectory(crx_path))
[email protected]e8f96ff2011-08-03 05:07:33881 NOTREACHED() << crx_path.value();
[email protected]73251e72012-03-04 02:10:33882 BrowserThread::PostDelayedTask(
883 BrowserThread::UI,
884 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14885 base::Bind(&CrxUpdateService::DoneInstalling, base::Unretained(this),
[email protected]f5d27e32014-01-31 06:48:53886 component_id, error, extended_error),
[email protected]73251e72012-03-04 02:10:33887 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]94a481b2014-03-28 19:41:55888 // Reset the unpacker last, otherwise we free our own arguments.
889 unpacker_ = NULL;
[email protected]e8f96ff2011-08-03 05:07:33890}
891
892// Installation has been completed. Adjust the component status and
[email protected]7b0529242013-07-20 05:45:46893// schedule the next check. Schedule a short delay before trying the full
894// update when the differential update failed.
[email protected]07f93af12011-08-17 20:57:22895void CrxUpdateService::DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:36896 ComponentUnpacker::Error error,
897 int extra_code) {
[email protected]e8f96ff2011-08-03 05:07:33898 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]07f93af12011-08-17 20:57:22899
[email protected]7b0529242013-07-20 05:45:46900 ErrorCategory error_category = kErrorNone;
901 switch (error) {
902 case ComponentUnpacker::kNone:
903 break;
904 case ComponentUnpacker::kInstallerError:
905 error_category = kInstallError;
906 break;
907 default:
908 error_category = kUnpackError;
909 break;
910 }
911
912 const bool is_success = error == ComponentUnpacker::kNone;
913
[email protected]07f93af12011-08-17 20:57:22914 CrxUpdateItem* item = FindUpdateItemById(component_id);
[email protected]7b0529242013-07-20 05:45:46915 if (item->status == CrxUpdateItem::kUpdatingDiff && !is_success) {
916 item->diff_error_category = error_category;
917 item->diff_error_code = error;
918 item->diff_extra_code1 = extra_code;
[email protected]1ea21ad2013-09-02 04:20:39919 item->diff_update_failed = true;
920 size_t count = ChangeItemStatus(CrxUpdateItem::kUpdatingDiff,
921 CrxUpdateItem::kCanUpdate);
922 DCHECK_EQ(count, 1ul);
923 ScheduleNextRun(kStepDelayShort);
924 return;
[email protected]e3e696d32013-06-21 20:41:36925 }
[email protected]e3e696d32013-06-21 20:41:36926
[email protected]7b0529242013-07-20 05:45:46927 if (is_success) {
[email protected]61aca4cd2013-10-26 10:50:59928 ChangeItemState(item, CrxUpdateItem::kUpdated);
[email protected]07f93af12011-08-17 20:57:22929 item->component.version = item->next_version;
[email protected]e3e696d32013-06-21 20:41:36930 item->component.fingerprint = item->next_fp;
[email protected]7b0529242013-07-20 05:45:46931 } else {
[email protected]61aca4cd2013-10-26 10:50:59932 ChangeItemState(item, CrxUpdateItem::kNoUpdate);
[email protected]7b0529242013-07-20 05:45:46933 item->error_category = error_category;
934 item->error_code = error;
935 item->extra_code1 = extra_code;
[email protected]e3e696d32013-06-21 20:41:36936 }
[email protected]07f93af12011-08-17 20:57:22937
[email protected]7b0529242013-07-20 05:45:46938 ping_manager_->OnUpdateComplete(item);
[email protected]360b8bb2011-09-01 21:48:06939
[email protected]32a6c8382013-08-20 00:29:20940 // Move on to the next update, if there is one available.
941 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33942}
943
[email protected]d3268fe2014-04-25 02:14:23944void CrxUpdateService::NotifyObservers(Observer::Events event,
945 const std::string& id) {
946 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
947 FOR_EACH_OBSERVER(Observer, observer_list_, OnEvent(event, id));
[email protected]85e61d52013-08-01 22:23:42948}
949
[email protected]00a77fa2013-11-02 04:18:46950content::ResourceThrottle* CrxUpdateService::GetOnDemandResourceThrottle(
951 net::URLRequest* request, const std::string& crx_id) {
952 // We give the raw pointer to the caller, who will delete it at will
953 // and we keep for ourselves a weak pointer to it so we can post tasks
954 // from the UI thread without having to track lifetime directly.
955 CUResourceThrottle* rt = new CUResourceThrottle(request);
956 BrowserThread::PostTask(
957 BrowserThread::UI,
958 FROM_HERE,
959 base::Bind(&CrxUpdateService::OnNewResourceThrottle,
960 base::Unretained(this),
961 rt->AsWeakPtr(),
962 crx_id));
963 return rt;
964}
965
966void CrxUpdateService::OnNewResourceThrottle(
967 base::WeakPtr<CUResourceThrottle> rt, const std::string& crx_id) {
968 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
969 // Check if we can on-demand update, else unblock the request anyway.
970 CrxUpdateItem* item = FindUpdateItemById(crx_id);
971 Status status = OnDemandUpdateInternal(item);
972 if (status == kOk || status == kInProgress) {
973 item->throttles.push_back(rt);
974 return;
975 }
976 UnblockResourceThrottle(rt);
977}
978
979///////////////////////////////////////////////////////////////////////////////
980
981CUResourceThrottle::CUResourceThrottle(const net::URLRequest* request)
982 : state_(NEW) {
983 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
984}
985
986CUResourceThrottle::~CUResourceThrottle() {
987 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
988}
989
990void CUResourceThrottle::WillStartRequest(bool* defer) {
991 if (state_ != UNBLOCKED) {
992 state_ = BLOCKED;
993 *defer = true;
994 } else {
995 *defer = false;
996 }
997}
998
999void CUResourceThrottle::WillRedirectRequest(const GURL& new_url, bool* defer) {
1000 WillStartRequest(defer);
1001}
1002
[email protected]f8fe5cf2013-12-04 20:11:531003const char* CUResourceThrottle::GetNameForLogging() const {
1004 return "ComponentUpdateResourceThrottle";
1005}
1006
[email protected]00a77fa2013-11-02 04:18:461007void CUResourceThrottle::Unblock() {
1008 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1009 if (state_ == BLOCKED)
1010 controller()->Resume();
1011 state_ = UNBLOCKED;
1012}
1013
[email protected]e8f96ff2011-08-03 05:07:331014// The component update factory. Using the component updater as a singleton
1015// is the job of the browser process.
1016ComponentUpdateService* ComponentUpdateServiceFactory(
1017 ComponentUpdateService::Configurator* config) {
1018 DCHECK(config);
1019 return new CrxUpdateService(config);
1020}
[email protected]2cddef42013-11-22 08:23:221021
[email protected]055981f2014-01-17 20:22:321022} // namespace component_updater
1023