blob: beee14aa0f4b942c49671c52933ed8bb64968160 [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]7b0529242013-07-20 05:45:4631#include "chrome/browser/component_updater/crx_update_item.h"
[email protected]2cddef42013-11-22 08:23:2232#include "chrome/browser/component_updater/update_manifest.h"
[email protected]e8f96ff2011-08-03 05:07:3333#include "chrome/common/chrome_version_info.h"
[email protected]b7b63872013-01-03 02:41:1934#include "content/public/browser/browser_thread.h"
[email protected]00a77fa2013-11-02 04:18:4635#include "content/public/browser/resource_controller.h"
36#include "content/public/browser/resource_throttle.h"
[email protected]e4452d32013-11-15 23:07:4137#include "extensions/common/extension.h"
[email protected]e8f96ff2011-08-03 05:07:3338#include "net/base/escape.h"
39#include "net/base/load_flags.h"
[email protected]1dd4060e2013-03-13 13:15:1340#include "net/base/net_errors.h"
[email protected]3dc1bc42012-06-19 08:20:5341#include "net/url_request/url_fetcher.h"
[email protected]15fb2aa2012-05-22 22:52:5942#include "net/url_request/url_fetcher_delegate.h"
[email protected]00a77fa2013-11-02 04:18:4643#include "net/url_request/url_request.h"
[email protected]9d8ea302012-09-25 15:04:2244#include "net/url_request/url_request_status.h"
[email protected]761fa4702013-07-02 15:25:1545#include "url/gurl.h"
[email protected]e8f96ff2011-08-03 05:07:3346
[email protected]631bb742011-11-02 11:29:3947using content::BrowserThread;
48
[email protected]44da56e2011-11-21 19:59:1449// The component updater is designed to live until process shutdown, so
50// base::Bind() calls are not refcounted.
51
[email protected]e8f96ff2011-08-03 05:07:3352namespace {
[email protected]e3e696d32013-06-21 20:41:3653
[email protected]e8f96ff2011-08-03 05:07:3354// Produces an extension-like friendly |id|. This might be removed in the
55// future if we roll our on packing tools.
56static std::string HexStringToID(const std::string& hexstr) {
57 std::string id;
58 for (size_t i = 0; i < hexstr.size(); ++i) {
[email protected]2cddef42013-11-22 08:23:2259 int val(0);
[email protected]eb72b272011-12-19 16:10:5560 if (base::HexStringToInt(base::StringPiece(hexstr.begin() + i,
61 hexstr.begin() + i + 1),
62 &val)) {
[email protected]e8f96ff2011-08-03 05:07:3363 id.append(1, val + 'a');
[email protected]eb72b272011-12-19 16:10:5564 } else {
[email protected]e8f96ff2011-08-03 05:07:3365 id.append(1, 'a');
[email protected]eb72b272011-12-19 16:10:5566 }
[email protected]e8f96ff2011-08-03 05:07:3367 }
[email protected]2cddef42013-11-22 08:23:2268 DCHECK(extensions::Extension::IdIsValid(id));
[email protected]e8f96ff2011-08-03 05:07:3369 return id;
70}
71
[email protected]2cddef42013-11-22 08:23:2272// Returns true if the |proposed| version is newer than |current| version.
[email protected]e8f96ff2011-08-03 05:07:3373bool IsVersionNewer(const Version& current, const std::string& proposed) {
74 Version proposed_ver(proposed);
[email protected]2cddef42013-11-22 08:23:2275 return proposed_ver.IsValid() && current.CompareTo(proposed_ver) < 0;
[email protected]e8f96ff2011-08-03 05:07:3376}
77
78// Helper template class that allows our main class to have separate
[email protected]f1050432012-02-15 01:35:4679// OnURLFetchComplete() callbacks for different types of url requests
[email protected]e8f96ff2011-08-03 05:07:3380// they are differentiated by the |Ctx| type.
81template <typename Del, typename Ctx>
[email protected]15fb2aa2012-05-22 22:52:5982class DelegateWithContext : public net::URLFetcherDelegate {
[email protected]e8f96ff2011-08-03 05:07:3383 public:
84 DelegateWithContext(Del* delegate, Ctx* context)
85 : delegate_(delegate), context_(context) {}
86
[email protected]10c2d692012-05-11 05:32:2387 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
[email protected]e8f96ff2011-08-03 05:07:3388 delegate_->OnURLFetchComplete(source, context_);
89 delete this;
90 }
91
92 private:
93 ~DelegateWithContext() {}
94
95 Del* delegate_;
96 Ctx* context_;
97};
98// This function creates the right DelegateWithContext using template inference.
99template <typename Del, typename Ctx>
[email protected]15fb2aa2012-05-22 22:52:59100net::URLFetcherDelegate* MakeContextDelegate(Del* delegate, Ctx* context) {
[email protected]e8f96ff2011-08-03 05:07:33101 return new DelegateWithContext<Del, Ctx>(delegate, context);
102}
103
104// Helper to start a url request using |fetcher| with the common flags.
[email protected]d3ec669b2012-05-23 07:12:14105void StartFetch(net::URLFetcher* fetcher,
[email protected]e8f96ff2011-08-03 05:07:33106 net::URLRequestContextGetter* context_getter,
[email protected]8f5f2ea2013-10-31 09:39:10107 bool save_to_file,
108 scoped_refptr<base::SequencedTaskRunner> task_runner) {
[email protected]7cc6e5632011-10-25 17:56:12109 fetcher->SetRequestContext(context_getter);
110 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
111 net::LOAD_DO_NOT_SAVE_COOKIES |
112 net::LOAD_DISABLE_CACHE);
[email protected]e8f96ff2011-08-03 05:07:33113 // TODO(cpu): Define our retry and backoff policy.
[email protected]7cc6e5632011-10-25 17:56:12114 fetcher->SetAutomaticallyRetryOn5xx(false);
[email protected]e8f96ff2011-08-03 05:07:33115 if (save_to_file) {
[email protected]8f5f2ea2013-10-31 09:39:10116 fetcher->SaveResponseToTemporaryFile(task_runner);
[email protected]e8f96ff2011-08-03 05:07:33117 }
118 fetcher->Start();
119}
120
[email protected]e3e696d32013-06-21 20:41:36121// Returns true if the url request of |fetcher| was succesful.
[email protected]10c2d692012-05-11 05:32:23122bool FetchSuccess(const net::URLFetcher& fetcher) {
[email protected]7cc6e5632011-10-25 17:56:12123 return (fetcher.GetStatus().status() == net::URLRequestStatus::SUCCESS) &&
124 (fetcher.GetResponseCode() == 200);
[email protected]e8f96ff2011-08-03 05:07:33125}
126
[email protected]7b0529242013-07-20 05:45:46127// Returns the error code which occured during the fetch.The function returns 0
128// if the fetch was successful. If errors happen, the function could return a
129// network error, an http response code, or the status of the fetch, if the
130// fetch is pending or canceled.
131int GetFetchError(const net::URLFetcher& fetcher) {
132 if (FetchSuccess(fetcher))
133 return 0;
[email protected]e8f96ff2011-08-03 05:07:33134
[email protected]7b0529242013-07-20 05:45:46135 const net::URLRequestStatus::Status status(fetcher.GetStatus().status());
136 if (status == net::URLRequestStatus::FAILED)
137 return fetcher.GetStatus().error();
[email protected]3707eb22013-06-21 14:20:13138
[email protected]7b0529242013-07-20 05:45:46139 if (status == net::URLRequestStatus::IO_PENDING ||
140 status == net::URLRequestStatus::CANCELED)
141 return status;
[email protected]e3e696d32013-06-21 20:41:36142
[email protected]7b0529242013-07-20 05:45:46143 const int response_code(fetcher.GetResponseCode());
144 if (status == net::URLRequestStatus::SUCCESS && response_code != 200)
145 return response_code;
[email protected]e3e696d32013-06-21 20:41:36146
[email protected]7b0529242013-07-20 05:45:46147 return -1;
[email protected]e3e696d32013-06-21 20:41:36148 }
[email protected]e8f96ff2011-08-03 05:07:33149
[email protected]e3e696d32013-06-21 20:41:36150// Returns true if a differential update is available for the update item.
151bool IsDiffUpdateAvailable(const CrxUpdateItem* update_item) {
152 return update_item->diff_crx_url.is_valid();
153}
[email protected]e8f96ff2011-08-03 05:07:33154
[email protected]e3e696d32013-06-21 20:41:36155// Returns true if a differential update is available, it has not failed yet,
156// and the configuration allows it.
157bool CanTryDiffUpdate(const CrxUpdateItem* update_item,
158 const ComponentUpdateService::Configurator& config) {
159 return IsDiffUpdateAvailable(update_item) &&
160 !update_item->diff_update_failed &&
161 config.DeltasEnabled();
162}
163
[email protected]7b0529242013-07-20 05:45:46164} // namespace
165
166CrxUpdateItem::CrxUpdateItem()
167 : status(kNew),
[email protected]61aca4cd2013-10-26 10:50:59168 on_demand(false),
[email protected]7b0529242013-07-20 05:45:46169 diff_update_failed(false),
170 error_category(0),
171 error_code(0),
172 extra_code1(0),
173 diff_error_category(0),
174 diff_error_code(0),
175 diff_extra_code1(0) {
176}
177
178CrxUpdateItem::~CrxUpdateItem() {
179}
[email protected]86550a42013-06-21 15:20:49180
[email protected]dc06f0b2013-01-23 20:03:16181CrxComponent::CrxComponent()
[email protected]85e61d52013-08-01 22:23:42182 : installer(NULL),
183 observer(NULL) {
[email protected]dc06f0b2013-01-23 20:03:16184}
185
186CrxComponent::~CrxComponent() {
187}
[email protected]e8f96ff2011-08-03 05:07:33188
[email protected]2e919ddd2013-08-21 05:05:17189std::string GetCrxComponentID(const CrxComponent& component) {
190 return HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
191 component.pk_hash.size()/2)));
192}
193
194CrxComponentInfo::CrxComponentInfo() {
195}
196
197CrxComponentInfo::~CrxComponentInfo() {
198}
199
[email protected]00a77fa2013-11-02 04:18:46200///////////////////////////////////////////////////////////////////////////////
201// In charge of blocking url requests until the |crx_id| component has been
202// updated. This class is touched solely from the IO thread. The UI thread
203// can post tasks to it via weak pointers. By default the request is blocked
204// unless the CrxUpdateService calls Unblock().
205// The lifetime is controlled by Chrome's resource loader so the component
206// updater cannot touch objects from this class except via weak pointers.
207class CUResourceThrottle
208 : public content::ResourceThrottle,
209 public base::SupportsWeakPtr<CUResourceThrottle> {
210 public:
211 explicit CUResourceThrottle(const net::URLRequest* request);
212 virtual ~CUResourceThrottle();
[email protected]2cddef42013-11-22 08:23:22213
[email protected]00a77fa2013-11-02 04:18:46214 // Overriden from ResourceThrottle.
215 virtual void WillStartRequest(bool* defer) OVERRIDE;
216 virtual void WillRedirectRequest(const GURL& new_url, bool* defer) OVERRIDE;
217
218 // Component updater calls this function via PostTask to unblock the request.
219 void Unblock();
220
221 typedef std::vector<base::WeakPtr<CUResourceThrottle> > WeakPtrVector;
222
223 private:
[email protected]2cddef42013-11-22 08:23:22224 enum State {
225 NEW,
226 BLOCKED,
227 UNBLOCKED
228 };
[email protected]00a77fa2013-11-02 04:18:46229
[email protected]2cddef42013-11-22 08:23:22230 State state_;
[email protected]00a77fa2013-11-02 04:18:46231};
232
233void UnblockResourceThrottle(base::WeakPtr<CUResourceThrottle> rt) {
234 BrowserThread::PostTask(
235 BrowserThread::IO,
236 FROM_HERE,
237 base::Bind(&CUResourceThrottle::Unblock, rt));
238}
239
240void UnblockandReapAllThrottles(CUResourceThrottle::WeakPtrVector* throttles) {
241 CUResourceThrottle::WeakPtrVector::iterator it;
242 for (it = throttles->begin(); it != throttles->end(); ++it)
243 UnblockResourceThrottle(*it);
244 throttles->clear();
245}
246
[email protected]e8f96ff2011-08-03 05:07:33247//////////////////////////////////////////////////////////////////////////////
248// The one and only implementation of the ComponentUpdateService interface. In
249// charge of running the show. The main method is ProcessPendingItems() which
[email protected]50b01392012-09-01 03:33:13250// is called periodically to do the upgrades/installs or the update checks.
[email protected]e8f96ff2011-08-03 05:07:33251// An important consideration here is to be as "low impact" as we can to the
252// rest of the browser, so even if we have many components registered and
[email protected]f1050432012-02-15 01:35:46253// eligible for update, we only do one thing at a time with pauses in between
[email protected]e8f96ff2011-08-03 05:07:33254// the tasks. Also when we do network requests there is only one |url_fetcher_|
[email protected]e3e696d32013-06-21 20:41:36255// in flight at a time.
[email protected]e8f96ff2011-08-03 05:07:33256// There are no locks in this code, the main structure |work_items_| is mutated
257// only from the UI thread. The unpack and installation is done in the file
258// thread and the network requests are done in the IO thread and in the file
259// thread.
260class CrxUpdateService : public ComponentUpdateService {
261 public:
262 explicit CrxUpdateService(ComponentUpdateService::Configurator* config);
[email protected]e8f96ff2011-08-03 05:07:33263 virtual ~CrxUpdateService();
264
265 // Overrides for ComponentUpdateService.
266 virtual Status Start() OVERRIDE;
267 virtual Status Stop() OVERRIDE;
268 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE;
[email protected]61aca4cd2013-10-26 10:50:59269 virtual Status OnDemandUpdate(const std::string& component_id) OVERRIDE;
[email protected]2e919ddd2013-08-21 05:05:17270 virtual void GetComponents(
271 std::vector<CrxComponentInfo>* components) OVERRIDE;
[email protected]00a77fa2013-11-02 04:18:46272 virtual content::ResourceThrottle* GetOnDemandResourceThrottle(
273 net::URLRequest* request, const std::string& crx_id) OVERRIDE;
[email protected]e8f96ff2011-08-03 05:07:33274
[email protected]e8f96ff2011-08-03 05:07:33275 // Context for a update check url request. See DelegateWithContext above.
276 struct UpdateContext {
277 base::Time start;
278 UpdateContext() : start(base::Time::Now()) {}
279 };
280
281 // Context for a crx download url request. See DelegateWithContext above.
282 struct CRXContext {
283 ComponentInstaller* installer;
284 std::vector<uint8> pk_hash;
285 std::string id;
[email protected]e3e696d32013-06-21 20:41:36286 std::string fingerprint;
[email protected]e8f96ff2011-08-03 05:07:33287 CRXContext() : installer(NULL) {}
288 };
289
[email protected]10c2d692012-05-11 05:32:23290 void OnURLFetchComplete(const net::URLFetcher* source,
[email protected]7cc6e5632011-10-25 17:56:12291 UpdateContext* context);
[email protected]e8f96ff2011-08-03 05:07:33292
[email protected]10c2d692012-05-11 05:32:23293 void OnURLFetchComplete(const net::URLFetcher* source,
[email protected]7cc6e5632011-10-25 17:56:12294 CRXContext* context);
[email protected]e8f96ff2011-08-03 05:07:33295
296 private:
[email protected]7b0529242013-07-20 05:45:46297 enum ErrorCategory {
298 kErrorNone = 0,
299 kNetworkError,
300 kUnpackError,
301 kInstallError,
302 };
303
[email protected]32a6c8382013-08-20 00:29:20304 enum StepDelayInterval {
305 kStepDelayShort = 0,
306 kStepDelayMedium,
307 kStepDelayLong,
308 };
309
[email protected]2cddef42013-11-22 08:23:22310 void OnParseUpdateManifestSucceeded(
311 const component_updater::UpdateManifest::Results& results);
[email protected]e3e696d32013-06-21 20:41:36312 void OnParseUpdateManifestFailed(const std::string& error_message);
[email protected]e8f96ff2011-08-03 05:07:33313
[email protected]00a77fa2013-11-02 04:18:46314 Status OnDemandUpdateInternal(CrxUpdateItem* item);
315
[email protected]e8f96ff2011-08-03 05:07:33316 void ProcessPendingItems();
317
[email protected]61aca4cd2013-10-26 10:50:59318 CrxUpdateItem* FindReadyComponent();
319
320 void UpdateComponent(CrxUpdateItem* workitem);
321
[email protected]2cddef42013-11-22 08:23:22322 void AddItemToUpdateCheck(CrxUpdateItem* item,
323 std::string* update_check_items);
[email protected]61aca4cd2013-10-26 10:50:59324
[email protected]2cddef42013-11-22 08:23:22325 void AddUpdateCheckItems(std::string* update_check_items);
326
327 void DoUpdateCheck(const std::string& update_check_items);
[email protected]61aca4cd2013-10-26 10:50:59328
[email protected]32a6c8382013-08-20 00:29:20329 void ScheduleNextRun(StepDelayInterval step_delay);
[email protected]e8f96ff2011-08-03 05:07:33330
331 void ParseManifest(const std::string& xml);
332
[email protected]650b2d52013-02-10 03:41:45333 void Install(const CRXContext* context, const base::FilePath& crx_path);
[email protected]e8f96ff2011-08-03 05:07:33334
[email protected]07f93af12011-08-17 20:57:22335 void DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:36336 ComponentUnpacker::Error error,
337 int extended_error);
[email protected]e8f96ff2011-08-03 05:07:33338
[email protected]61aca4cd2013-10-26 10:50:59339 void ChangeItemState(CrxUpdateItem* item, CrxUpdateItem::Status to);
340
[email protected]e8f96ff2011-08-03 05:07:33341 size_t ChangeItemStatus(CrxUpdateItem::Status from,
342 CrxUpdateItem::Status to);
343
344 CrxUpdateItem* FindUpdateItemById(const std::string& id);
345
[email protected]85e61d52013-08-01 22:23:42346 void NotifyComponentObservers(ComponentObserver::Events event,
347 int extra) const;
348
[email protected]61aca4cd2013-10-26 10:50:59349 bool HasOnDemandItems() const;
350
[email protected]00a77fa2013-11-02 04:18:46351 void OnNewResourceThrottle(base::WeakPtr<CUResourceThrottle> rt,
352 const std::string& crx_id);
353
[email protected]e3e696d32013-06-21 20:41:36354 scoped_ptr<ComponentUpdateService::Configurator> config_;
355
356 scoped_ptr<ComponentPatcher> component_patcher_;
[email protected]e8f96ff2011-08-03 05:07:33357
[email protected]d3ec669b2012-05-23 07:12:14358 scoped_ptr<net::URLFetcher> url_fetcher_;
[email protected]e8f96ff2011-08-03 05:07:33359
[email protected]7b0529242013-07-20 05:45:46360 scoped_ptr<component_updater::PingManager> ping_manager_;
361
[email protected]86550a42013-06-21 15:20:49362 // A collection of every work item.
[email protected]e3e696d32013-06-21 20:41:36363 typedef std::vector<CrxUpdateItem*> UpdateItems;
[email protected]e8f96ff2011-08-03 05:07:33364 UpdateItems work_items_;
365
366 base::OneShotTimer<CrxUpdateService> timer_;
367
[email protected]8f5f2ea2013-10-31 09:39:10368 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
369
[email protected]e3e696d32013-06-21 20:41:36370 const Version chrome_version_;
[email protected]e8f96ff2011-08-03 05:07:33371
372 bool running_;
373
374 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
375};
376
[email protected]e8f96ff2011-08-03 05:07:33377//////////////////////////////////////////////////////////////////////////////
378
[email protected]e3e696d32013-06-21 20:41:36379CrxUpdateService::CrxUpdateService(ComponentUpdateService::Configurator* config)
[email protected]e8f96ff2011-08-03 05:07:33380 : config_(config),
[email protected]e3e696d32013-06-21 20:41:36381 component_patcher_(config->CreateComponentPatcher()),
[email protected]7b0529242013-07-20 05:45:46382 ping_manager_(new component_updater::PingManager(
383 config->PingUrl(),
384 config->RequestContext())),
[email protected]8f5f2ea2013-10-31 09:39:10385 blocking_task_runner_(BrowserThread::GetBlockingPool()->
386 GetSequencedTaskRunnerWithShutdownBehavior(
387 BrowserThread::GetBlockingPool()->GetSequenceToken(),
388 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)),
[email protected]e8f96ff2011-08-03 05:07:33389 chrome_version_(chrome::VersionInfo().Version()),
390 running_(false) {
[email protected]1ea21ad2013-09-02 04:20:39391}
[email protected]e8f96ff2011-08-03 05:07:33392
393CrxUpdateService::~CrxUpdateService() {
394 // Because we are a singleton, at this point only the UI thread should be
395 // alive, this simplifies the management of the work that could be in
396 // flight in other threads.
397 Stop();
398 STLDeleteElements(&work_items_);
[email protected]1ea21ad2013-09-02 04:20:39399}
[email protected]e8f96ff2011-08-03 05:07:33400
401ComponentUpdateService::Status CrxUpdateService::Start() {
402 // Note that RegisterComponent will call Start() when the first
403 // component is registered, so it can be called twice. This way
404 // we avoid scheduling the timer if there is no work to do.
405 running_ = true;
406 if (work_items_.empty())
407 return kOk;
408
[email protected]85e61d52013-08-01 22:23:42409 NotifyComponentObservers(ComponentObserver::COMPONENT_UPDATER_STARTED, 0);
410
[email protected]d323a172011-09-02 18:23:02411 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->InitialDelay()),
[email protected]e8f96ff2011-08-03 05:07:33412 this, &CrxUpdateService::ProcessPendingItems);
413 return kOk;
414}
415
416// Stop the main check + update loop. In flight operations will be
417// completed.
418ComponentUpdateService::Status CrxUpdateService::Stop() {
419 running_ = false;
420 timer_.Stop();
421 return kOk;
422}
423
[email protected]61aca4cd2013-10-26 10:50:59424bool CrxUpdateService::HasOnDemandItems() const {
425 class Helper {
426 public:
427 static bool IsOnDemand(CrxUpdateItem* item) {
428 return item->on_demand;
429 }
430 };
431 return std::find_if(work_items_.begin(),
432 work_items_.end(),
433 Helper::IsOnDemand) != work_items_.end();
434}
435
[email protected]ccb4feef2013-02-14 06:16:47436// This function sets the timer which will call ProcessPendingItems() or
[email protected]61aca4cd2013-10-26 10:50:59437// ProcessRequestedItem() if there is an on_demand item. There
[email protected]32a6c8382013-08-20 00:29:20438// are three kinds of waits:
439// - a short delay, when there is immediate work to be done.
440// - a medium delay, when there are updates to be applied within the current
441// update cycle, or there are components that are still unchecked.
442// - a long delay when a full check/update cycle has completed for all
443// components.
444void CrxUpdateService::ScheduleNextRun(StepDelayInterval step_delay) {
[email protected]e8f96ff2011-08-03 05:07:33445 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cf442612011-08-09 20:20:12446 DCHECK(url_fetcher_.get() == NULL);
[email protected]e8f96ff2011-08-03 05:07:33447 CHECK(!timer_.IsRunning());
448 // It could be the case that Stop() had been called while a url request
449 // or unpacking was in flight, if so we arrive here but |running_| is
450 // false. In that case do not loop again.
451 if (!running_)
452 return;
453
[email protected]ccb4feef2013-02-14 06:16:47454 // Keep the delay short if in the middle of an update (step_delay),
455 // or there are new requested_work_items_ that have not been processed yet.
[email protected]32a6c8382013-08-20 00:29:20456 int64 delay_seconds = 0;
[email protected]61aca4cd2013-10-26 10:50:59457 if (!HasOnDemandItems()) {
[email protected]32a6c8382013-08-20 00:29:20458 switch (step_delay) {
459 case kStepDelayShort:
460 delay_seconds = config_->StepDelay();
461 break;
462 case kStepDelayMedium:
463 delay_seconds = config_->StepDelayMedium();
464 break;
465 case kStepDelayLong:
466 delay_seconds = config_->NextCheckDelay();
467 break;
468 }
469 } else {
470 delay_seconds = config_->StepDelay();
471 }
[email protected]cf442612011-08-09 20:20:12472
[email protected]32a6c8382013-08-20 00:29:20473 if (step_delay != kStepDelayShort) {
[email protected]85e61d52013-08-01 22:23:42474 NotifyComponentObservers(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0);
475
[email protected]e8f96ff2011-08-03 05:07:33476 // Zero is only used for unit tests.
[email protected]32a6c8382013-08-20 00:29:20477 if (0 == delay_seconds)
[email protected]e8f96ff2011-08-03 05:07:33478 return;
479 }
480
[email protected]32a6c8382013-08-20 00:29:20481 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay_seconds),
[email protected]e8f96ff2011-08-03 05:07:33482 this, &CrxUpdateService::ProcessPendingItems);
483}
484
485// Given a extension-like component id, find the associated component.
486CrxUpdateItem* CrxUpdateService::FindUpdateItemById(const std::string& id) {
487 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
488 CrxUpdateItem::FindById finder(id);
489 UpdateItems::iterator it = std::find_if(work_items_.begin(),
490 work_items_.end(),
491 finder);
492 if (it == work_items_.end())
493 return NULL;
494 return (*it);
495}
496
[email protected]61aca4cd2013-10-26 10:50:59497// Changes a component's status, clearing on_demand and firing notifications as
498// necessary. By convention, this is the only function that can change a
499// CrxUpdateItem's |status|.
500// TODO(waffles): Do we want to add DCHECKS for valid state transitions here?
501void CrxUpdateService::ChangeItemState(CrxUpdateItem* item,
502 CrxUpdateItem::Status to) {
503 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
504 if (to == CrxUpdateItem::kNoUpdate ||
505 to == CrxUpdateItem::kUpdated ||
506 to == CrxUpdateItem::kUpToDate) {
507 item->on_demand = false;
508 }
509
510 item->status = to;
511
512 ComponentObserver* observer = item->component.observer;
513 if (observer) {
514 switch (to) {
515 case CrxUpdateItem::kCanUpdate:
516 observer->OnEvent(ComponentObserver::COMPONENT_UPDATE_FOUND, 0);
517 break;
518 case CrxUpdateItem::kUpdatingDiff:
519 case CrxUpdateItem::kUpdating:
520 observer->OnEvent(ComponentObserver::COMPONENT_UPDATE_READY, 0);
521 break;
522 case CrxUpdateItem::kUpdated:
523 observer->OnEvent(ComponentObserver::COMPONENT_UPDATED, 0);
524 break;
525 case CrxUpdateItem::kUpToDate:
526 case CrxUpdateItem::kNoUpdate:
527 observer->OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0);
528 break;
529 case CrxUpdateItem::kNew:
530 case CrxUpdateItem::kChecking:
531 case CrxUpdateItem::kDownloading:
532 case CrxUpdateItem::kDownloadingDiff:
533 case CrxUpdateItem::kLastStatus:
534 // No notification for these states.
535 break;
536 }
537 }
[email protected]00a77fa2013-11-02 04:18:46538
539 // Free possible pending network requests.
540 if ((to == CrxUpdateItem::kUpdated) ||
541 (to == CrxUpdateItem::kUpToDate) ||
542 (to == CrxUpdateItem::kNoUpdate)) {
543 UnblockandReapAllThrottles(&item->throttles);
544 }
[email protected]61aca4cd2013-10-26 10:50:59545}
546
[email protected]e8f96ff2011-08-03 05:07:33547// Changes all the components in |work_items_| that have |from| status to
[email protected]e3e696d32013-06-21 20:41:36548// |to| status and returns how many have been changed.
[email protected]e8f96ff2011-08-03 05:07:33549size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from,
550 CrxUpdateItem::Status to) {
551 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
552 size_t count = 0;
553 for (UpdateItems::iterator it = work_items_.begin();
554 it != work_items_.end(); ++it) {
555 CrxUpdateItem* item = *it;
556 if (item->status != from)
557 continue;
[email protected]61aca4cd2013-10-26 10:50:59558 ChangeItemState(item, to);
[email protected]e8f96ff2011-08-03 05:07:33559 ++count;
560 }
561 return count;
562}
563
564// Adds a component to be checked for upgrades. If the component exists it
565// it will be replaced and the return code is kReplaced.
566//
567// TODO(cpu): Evaluate if we want to support un-registration.
568ComponentUpdateService::Status CrxUpdateService::RegisterComponent(
569 const CrxComponent& component) {
570 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
571 if (component.pk_hash.empty() ||
572 !component.version.IsValid() ||
573 !component.installer)
574 return kError;
575
576 std::string id =
577 HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
578 component.pk_hash.size()/2)));
579 CrxUpdateItem* uit;
580 uit = FindUpdateItemById(id);
581 if (uit) {
582 uit->component = component;
583 return kReplaced;
584 }
585
586 uit = new CrxUpdateItem;
587 uit->id.swap(id);
588 uit->component = component;
[email protected]e3e696d32013-06-21 20:41:36589
[email protected]e8f96ff2011-08-03 05:07:33590 work_items_.push_back(uit);
591 // If this is the first component registered we call Start to
592 // schedule the first timer.
593 if (running_ && (work_items_.size() == 1))
594 Start();
595
596 return kOk;
597}
598
[email protected]ccb4feef2013-02-14 06:16:47599// Start the process of checking for an update, for a particular component
600// that was previously registered.
[email protected]2e919ddd2013-08-21 05:05:17601// |component_id| is a value returned from GetCrxComponentID().
[email protected]61aca4cd2013-10-26 10:50:59602ComponentUpdateService::Status CrxUpdateService::OnDemandUpdate(
[email protected]2e919ddd2013-08-21 05:05:17603 const std::string& component_id) {
[email protected]00a77fa2013-11-02 04:18:46604 return OnDemandUpdateInternal(FindUpdateItemById(component_id));
605}
606
607ComponentUpdateService::Status CrxUpdateService::OnDemandUpdateInternal(
608 CrxUpdateItem* uit) {
[email protected]ccb4feef2013-02-14 06:16:47609 if (!uit)
610 return kError;
[email protected]2cddef42013-11-22 08:23:22611
[email protected]ccb4feef2013-02-14 06:16:47612 // Check if the request is too soon.
613 base::TimeDelta delta = base::Time::Now() - uit->last_check;
[email protected]e3e696d32013-06-21 20:41:36614 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
[email protected]ccb4feef2013-02-14 06:16:47615 return kError;
[email protected]ccb4feef2013-02-14 06:16:47616
617 switch (uit->status) {
618 // If the item is already in the process of being updated, there is
619 // no point in this call, so return kInProgress.
620 case CrxUpdateItem::kChecking:
621 case CrxUpdateItem::kCanUpdate:
[email protected]e3e696d32013-06-21 20:41:36622 case CrxUpdateItem::kDownloadingDiff:
[email protected]ccb4feef2013-02-14 06:16:47623 case CrxUpdateItem::kDownloading:
[email protected]e3e696d32013-06-21 20:41:36624 case CrxUpdateItem::kUpdatingDiff:
[email protected]ccb4feef2013-02-14 06:16:47625 case CrxUpdateItem::kUpdating:
626 return kInProgress;
627 // Otherwise the item was already checked a while back (or it is new),
628 // set its status to kNew to give it a slightly higher priority.
629 case CrxUpdateItem::kNew:
630 case CrxUpdateItem::kUpdated:
631 case CrxUpdateItem::kUpToDate:
632 case CrxUpdateItem::kNoUpdate:
[email protected]61aca4cd2013-10-26 10:50:59633 ChangeItemState(uit, CrxUpdateItem::kNew);
634 uit->on_demand = true;
[email protected]ccb4feef2013-02-14 06:16:47635 break;
636 case CrxUpdateItem::kLastStatus:
637 NOTREACHED() << uit->status;
638 }
639
640 // In case the current delay is long, set the timer to a shorter value
641 // to get the ball rolling.
642 if (timer_.IsRunning()) {
643 timer_.Stop();
644 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->StepDelay()),
645 this, &CrxUpdateService::ProcessPendingItems);
646 }
647
648 return kOk;
649}
650
[email protected]2e919ddd2013-08-21 05:05:17651void CrxUpdateService::GetComponents(
652 std::vector<CrxComponentInfo>* components) {
653 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
654 for (UpdateItems::const_iterator it = work_items_.begin();
655 it != work_items_.end(); ++it) {
656 const CrxUpdateItem* item = *it;
657 CrxComponentInfo info;
658 info.id = GetCrxComponentID(item->component);
659 info.version = item->component.version.GetString();
660 info.name = item->component.name;
661 components->push_back(info);
662 }
663}
664
[email protected]61aca4cd2013-10-26 10:50:59665// This is the main loop of the component updater.
[email protected]e8f96ff2011-08-03 05:07:33666void CrxUpdateService::ProcessPendingItems() {
667 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]61aca4cd2013-10-26 10:50:59668 CrxUpdateItem* ready_upgrade = FindReadyComponent();
669 if (ready_upgrade) {
670 UpdateComponent(ready_upgrade);
[email protected]e8f96ff2011-08-03 05:07:33671 return;
672 }
[email protected]2cddef42013-11-22 08:23:22673 std::string update_check_items;
674 AddUpdateCheckItems(&update_check_items);
675 if (!update_check_items.empty()) {
676 DoUpdateCheck(update_check_items);
[email protected]61aca4cd2013-10-26 10:50:59677 return;
678 }
679 // No components to update. The next check will be after a long sleep.
680 ScheduleNextRun(kStepDelayLong);
681}
682
683CrxUpdateItem* CrxUpdateService::FindReadyComponent() {
684 class Helper {
685 public:
686 static bool IsReadyOnDemand(CrxUpdateItem* item) {
687 return item->on_demand && IsReady(item);
688 }
689 static bool IsReady(CrxUpdateItem* item) {
690 return item->status == CrxUpdateItem::kCanUpdate;
691 }
692 };
693
694 std::vector<CrxUpdateItem*>::iterator it = std::find_if(
695 work_items_.begin(), work_items_.end(), Helper::IsReadyOnDemand);
696 if (it != work_items_.end())
697 return *it;
698 it = std::find_if(work_items_.begin(), work_items_.end(), Helper::IsReady);
699 if (it != work_items_.end())
700 return *it;
701 return NULL;
702}
703
704void CrxUpdateService::UpdateComponent(CrxUpdateItem* workitem) {
705 CRXContext* context = new CRXContext;
706 context->pk_hash = workitem->component.pk_hash;
707 context->id = workitem->id;
708 context->installer = workitem->component.installer;
709 context->fingerprint = workitem->next_fp;
710 GURL package_url;
711 if (CanTryDiffUpdate(workitem, *config_)) {
712 package_url = workitem->diff_crx_url;
713 ChangeItemState(workitem, CrxUpdateItem::kDownloadingDiff);
714 } else {
715 package_url = workitem->crx_url;
716 ChangeItemState(workitem, CrxUpdateItem::kDownloading);
717 }
718 url_fetcher_.reset(net::URLFetcher::Create(
719 0, package_url, net::URLFetcher::GET,
720 MakeContextDelegate(this, context)));
[email protected]8f5f2ea2013-10-31 09:39:10721 StartFetch(url_fetcher_.get(),
722 config_->RequestContext(),
723 true,
724 blocking_task_runner_);
[email protected]61aca4cd2013-10-26 10:50:59725}
726
[email protected]2cddef42013-11-22 08:23:22727// Sets the state of the component to be checked for updates. After the
728// function is called, the <app> element corresponding to the |item| parameter
729// is appended to the |update_check_items|.
730void CrxUpdateService::AddItemToUpdateCheck(CrxUpdateItem* item,
731 std::string* update_check_items) {
732 // The app element corresponding to an update items looks like this:
733 // <app appid="hnimpnehoodheedghdeeijklkeaacbdc"
734 // version="0.1.2.3" installsource="ondemand">
735 // <updatecheck />
736 // <packages>
737 // <package fp="abcd" />
738 // </packages>
739 // </app>
740 std::string app_attributes;
741 base::StringAppendF(&app_attributes,
742 "appid=\"%s\" version=\"%s\"",
743 item->id.c_str(),
744 item->component.version.GetString().c_str());
745 if (item->on_demand)
746 base::StringAppendF(&app_attributes, " installsource=\"ondemand\"");
747
748 std::string app;
749 if (item->component.fingerprint.empty())
750 base::StringAppendF(&app,
751 "<app %s>"
752 "<updatecheck />"
753 "</app>",
754 app_attributes.c_str());
755 else
756 base::StringAppendF(&app,
757 "<app %s>"
758 "<updatecheck />"
759 "<packages>"
760 "<package fp=\"%s\"/>"
761 "</packages>"
762 "</app>",
763 app_attributes.c_str(),
764 item->component.fingerprint.c_str());
765
766 update_check_items->append(app);
767
768 ChangeItemState(item, CrxUpdateItem::kChecking);
769 item->last_check = base::Time::Now();
770 item->crx_url = GURL();
771 item->diff_crx_url = GURL();
772 item->previous_version = item->component.version;
773 item->next_version = Version();
774 item->previous_fp = item->component.fingerprint;
775 item->next_fp.clear();
776 item->diff_update_failed = false;
777 item->error_category = 0;
778 item->error_code = 0;
779 item->extra_code1 = 0;
780 item->diff_error_category = 0;
781 item->diff_error_code = 0;
782 item->diff_extra_code1 = 0;
783}
784
785// Builds the sequence of <app> elements in the update check and returns it
786// in the |update_check_items| parameter.
787void CrxUpdateService::AddUpdateCheckItems(std::string* update_check_items) {
788 // Given that our |work_items_| list is expected to contain relatively few
789 // items, we simply loop several times.
[email protected]d63306d2013-06-29 13:56:02790 for (UpdateItems::const_iterator it = work_items_.begin();
791 it != work_items_.end(); ++it) {
792 CrxUpdateItem* item = *it;
793 if (item->status != CrxUpdateItem::kNew)
[email protected]dc06f0b2013-01-23 20:03:16794 continue;
[email protected]2cddef42013-11-22 08:23:22795 AddItemToUpdateCheck(item, update_check_items);
[email protected]d63306d2013-06-29 13:56:02796 }
[email protected]dc06f0b2013-01-23 20:03:16797
[email protected]d63306d2013-06-29 13:56:02798 // Next we can go back to components we already checked, here
799 // we can also batch them in a single url request, as long as
800 // we have not checked them recently.
801 const base::TimeDelta min_delta_time =
802 base::TimeDelta::FromSeconds(config_->MinimumReCheckWait());
803
804 for (UpdateItems::const_iterator it = work_items_.begin();
805 it != work_items_.end(); ++it) {
806 CrxUpdateItem* item = *it;
807 if ((item->status != CrxUpdateItem::kNoUpdate) &&
808 (item->status != CrxUpdateItem::kUpToDate))
809 continue;
810 base::TimeDelta delta = base::Time::Now() - item->last_check;
811 if (delta < min_delta_time)
812 continue;
[email protected]2cddef42013-11-22 08:23:22813 AddItemToUpdateCheck(item, update_check_items);
[email protected]d63306d2013-06-29 13:56:02814 }
815
816 // Finally, we check components that we already updated as long as
817 // we have not checked them recently.
818 for (UpdateItems::const_iterator it = work_items_.begin();
819 it != work_items_.end(); ++it) {
820 CrxUpdateItem* item = *it;
821 if (item->status != CrxUpdateItem::kUpdated)
822 continue;
823 base::TimeDelta delta = base::Time::Now() - item->last_check;
824 if (delta < min_delta_time)
825 continue;
[email protected]2cddef42013-11-22 08:23:22826 AddItemToUpdateCheck(item, update_check_items);
[email protected]d63306d2013-06-29 13:56:02827 }
[email protected]61aca4cd2013-10-26 10:50:59828}
[email protected]d63306d2013-06-29 13:56:02829
[email protected]2cddef42013-11-22 08:23:22830// Sends an update request. The |update_check_items| parameter
831// contains the sequence of <app> xml elements of the update check.
832void CrxUpdateService::DoUpdateCheck(const std::string& update_check_items) {
833 using component_updater::BuildProtocolRequest;
834 url_fetcher_.reset(component_updater::SendProtocolRequest(
835 config_->UpdateUrl(),
836 BuildProtocolRequest(update_check_items),
837 MakeContextDelegate(this, new UpdateContext()),
838 config_->RequestContext()));
[email protected]e8f96ff2011-08-03 05:07:33839}
840
[email protected]ccb4feef2013-02-14 06:16:47841// Called when we got a response from the update server. It consists of an xml
[email protected]e8f96ff2011-08-03 05:07:33842// document following the omaha update scheme.
[email protected]10c2d692012-05-11 05:32:23843void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
[email protected]07f93af12011-08-17 20:57:22844 UpdateContext* context) {
[email protected]e8f96ff2011-08-03 05:07:33845 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
846 if (FetchSuccess(*source)) {
847 std::string xml;
848 source->GetResponseAsString(&xml);
[email protected]cf442612011-08-09 20:20:12849 url_fetcher_.reset();
[email protected]e8f96ff2011-08-03 05:07:33850 ParseManifest(xml);
851 } else {
[email protected]cf442612011-08-09 20:20:12852 url_fetcher_.reset();
[email protected]e8f96ff2011-08-03 05:07:33853 CrxUpdateService::OnParseUpdateManifestFailed("network error");
854 }
[email protected]07f93af12011-08-17 20:57:22855 delete context;
[email protected]e8f96ff2011-08-03 05:07:33856}
857
[email protected]e8f96ff2011-08-03 05:07:33858void CrxUpdateService::ParseManifest(const std::string& xml) {
859 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2cddef42013-11-22 08:23:22860 component_updater::UpdateManifest manifest;
861 if (manifest.Parse(xml))
862 CrxUpdateService::OnParseUpdateManifestSucceeded(manifest.results());
[email protected]652f4272013-11-13 09:23:41863 else
[email protected]2cddef42013-11-22 08:23:22864 CrxUpdateService::OnParseUpdateManifestFailed(manifest.errors());
[email protected]e8f96ff2011-08-03 05:07:33865}
866
867// A valid Omaha update check has arrived, from only the list of components that
868// we are currently upgrading we check for a match in which the server side
869// version is newer, if so we queue them for an upgrade. The next time we call
870// ProcessPendingItems() one of them will be drafted for the upgrade process.
871void CrxUpdateService::OnParseUpdateManifestSucceeded(
[email protected]2cddef42013-11-22 08:23:22872 const component_updater::UpdateManifest::Results& results) {
873 size_t num_updates_pending = 0;
[email protected]e8f96ff2011-08-03 05:07:33874 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2cddef42013-11-22 08:23:22875 std::vector<component_updater::UpdateManifest::Result>::const_iterator it;
[email protected]e8f96ff2011-08-03 05:07:33876 for (it = results.list.begin(); it != results.list.end(); ++it) {
877 CrxUpdateItem* crx = FindUpdateItemById(it->extension_id);
878 if (!crx)
879 continue;
880
[email protected]2cddef42013-11-22 08:23:22881 if (crx->status != CrxUpdateItem::kChecking) {
882 NOTREACHED();
[email protected]e8f96ff2011-08-03 05:07:33883 continue; // Not updating this component now.
[email protected]2cddef42013-11-22 08:23:22884 }
[email protected]e8f96ff2011-08-03 05:07:33885
[email protected]2cddef42013-11-22 08:23:22886 if (it->manifest.version.empty()) {
[email protected]cf442612011-08-09 20:20:12887 // No version means no update available.
[email protected]61aca4cd2013-10-26 10:50:59888 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
[email protected]cf442612011-08-09 20:20:12889 continue;
[email protected]e8f96ff2011-08-03 05:07:33890 }
[email protected]2cddef42013-11-22 08:23:22891
892 if (!IsVersionNewer(crx->component.version, it->manifest.version)) {
893 // The component is up to date.
[email protected]61aca4cd2013-10-26 10:50:59894 ChangeItemState(crx, CrxUpdateItem::kUpToDate);
[email protected]cf442612011-08-09 20:20:12895 continue;
[email protected]e8f96ff2011-08-03 05:07:33896 }
[email protected]2cddef42013-11-22 08:23:22897
898 if (!it->manifest.browser_min_version.empty()) {
899 if (IsVersionNewer(chrome_version_, it->manifest.browser_min_version)) {
900 // The component is not compatible with this Chrome version.
[email protected]61aca4cd2013-10-26 10:50:59901 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
[email protected]cf442612011-08-09 20:20:12902 continue;
903 }
[email protected]e8f96ff2011-08-03 05:07:33904 }
[email protected]2cddef42013-11-22 08:23:22905
906 if (it->manifest.packages.size() != 1) {
907 // Assume one and only one package per component.
908 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
909 continue;
910 }
911
912 // Parse the members of the result and queue an upgrade for this component.
913 crx->next_version = Version(it->manifest.version);
914
915 typedef component_updater::
916 UpdateManifest::Result::Manifest::Package Package;
917 const Package& package(it->manifest.packages[0]);
918 crx->next_fp = package.fingerprint;
919
920 // Select the first url from the list of urls until support for
921 // fall back urls is implemented.
922 if (!it->crx_urls.empty())
923 crx->crx_url = it->crx_urls[0].Resolve(package.name);
924 if (!it->crx_diffurls.empty())
925 crx->diff_crx_url = it->crx_diffurls[0].Resolve(package.namediff);
926
[email protected]61aca4cd2013-10-26 10:50:59927 ChangeItemState(crx, CrxUpdateItem::kCanUpdate);
[email protected]2cddef42013-11-22 08:23:22928 ++num_updates_pending;
[email protected]e8f96ff2011-08-03 05:07:33929 }
[email protected]cf442612011-08-09 20:20:12930
[email protected]2cddef42013-11-22 08:23:22931 // All components that are not included in the update response are
932 // considered up to date.
[email protected]cf442612011-08-09 20:20:12933 ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kUpToDate);
934
[email protected]32a6c8382013-08-20 00:29:20935 // If there are updates pending we do a short wait, otherwise we take
936 // a longer delay until we check the components again.
[email protected]2cddef42013-11-22 08:23:22937 ScheduleNextRun(num_updates_pending > 0 ? kStepDelayShort : kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33938}
939
940void CrxUpdateService::OnParseUpdateManifestFailed(
941 const std::string& error_message) {
942 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
943 size_t count = ChangeItemStatus(CrxUpdateItem::kChecking,
944 CrxUpdateItem::kNoUpdate);
945 DCHECK_GT(count, 0ul);
[email protected]32a6c8382013-08-20 00:29:20946 ScheduleNextRun(kStepDelayLong);
[email protected]e8f96ff2011-08-03 05:07:33947}
948
949// Called when the CRX package has been downloaded to a temporary location.
950// Here we fire the notifications and schedule the component-specific installer
951// to be called in the file thread.
[email protected]10c2d692012-05-11 05:32:23952void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
[email protected]e8f96ff2011-08-03 05:07:33953 CRXContext* context) {
954 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]64f39fa12013-09-03 21:49:37955
956 scoped_ptr<CRXContext> crx_context(context);
[email protected]e8f96ff2011-08-03 05:07:33957
[email protected]64f39fa12013-09-03 21:49:37958 CrxUpdateItem* crx = FindUpdateItemById(crx_context->id);
[email protected]e3e696d32013-06-21 20:41:36959 DCHECK(crx->status == CrxUpdateItem::kDownloadingDiff ||
960 crx->status == CrxUpdateItem::kDownloading);
961
[email protected]376d26d2013-10-03 10:12:49962 if (!FetchSuccess(*source)) {
[email protected]e3e696d32013-06-21 20:41:36963 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
[email protected]7b0529242013-07-20 05:45:46964 crx->diff_error_category = kNetworkError;
965 crx->diff_error_code = GetFetchError(*source);
[email protected]e630ba62013-06-22 15:22:34966 crx->diff_update_failed = true;
[email protected]e3e696d32013-06-21 20:41:36967 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
968 CrxUpdateItem::kCanUpdate);
969 DCHECK_EQ(count, 1ul);
[email protected]7b0529242013-07-20 05:45:46970 url_fetcher_.reset();
971
[email protected]32a6c8382013-08-20 00:29:20972 ScheduleNextRun(kStepDelayShort);
[email protected]e3e696d32013-06-21 20:41:36973 return;
974 }
[email protected]7b0529242013-07-20 05:45:46975 crx->error_category = kNetworkError;
976 crx->error_code = GetFetchError(*source);
[email protected]e8f96ff2011-08-03 05:07:33977 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
978 CrxUpdateItem::kNoUpdate);
979 DCHECK_EQ(count, 1ul);
[email protected]cf442612011-08-09 20:20:12980 url_fetcher_.reset();
[email protected]e3e696d32013-06-21 20:41:36981
[email protected]7b0529242013-07-20 05:45:46982 // At this point, since both the differential and the full downloads failed,
983 // the update for this component has finished with an error.
984 ping_manager_->OnUpdateComplete(crx);
985
[email protected]32a6c8382013-08-20 00:29:20986 // Move on to the next update, if there is one available.
987 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33988 } else {
[email protected]650b2d52013-02-10 03:41:45989 base::FilePath temp_crx_path;
[email protected]e8f96ff2011-08-03 05:07:33990 CHECK(source->GetResponseAsFilePath(true, &temp_crx_path));
[email protected]e3e696d32013-06-21 20:41:36991
992 size_t count = 0;
993 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
994 count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
995 CrxUpdateItem::kUpdatingDiff);
996 } else {
997 count = ChangeItemStatus(CrxUpdateItem::kDownloading,
998 CrxUpdateItem::kUpdating);
999 }
[email protected]e8f96ff2011-08-03 05:07:331000 DCHECK_EQ(count, 1ul);
[email protected]e3e696d32013-06-21 20:41:361001
[email protected]cf442612011-08-09 20:20:121002 url_fetcher_.reset();
1003
[email protected]44da56e2011-11-21 19:59:141004 // Why unretained? See comment at top of file.
[email protected]8f5f2ea2013-10-31 09:39:101005 blocking_task_runner_->PostDelayedTask(
[email protected]73251e72012-03-04 02:10:331006 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:141007 base::Bind(&CrxUpdateService::Install,
1008 base::Unretained(this),
[email protected]64f39fa12013-09-03 21:49:371009 crx_context.release(),
[email protected]44da56e2011-11-21 19:59:141010 temp_crx_path),
[email protected]73251e72012-03-04 02:10:331011 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]e8f96ff2011-08-03 05:07:331012 }
[email protected]e8f96ff2011-08-03 05:07:331013}
1014
1015// Install consists of digital signature verification, unpacking and then
1016// calling the component specific installer. All that is handled by the
1017// |unpacker|. If there is an error this function is in charge of deleting
1018// the files created.
1019void CrxUpdateService::Install(const CRXContext* context,
[email protected]650b2d52013-02-10 03:41:451020 const base::FilePath& crx_path) {
[email protected]8f5f2ea2013-10-31 09:39:101021 // This function owns the file at |crx_path| and the |context| object.
[email protected]e3e696d32013-06-21 20:41:361022 ComponentUnpacker unpacker(context->pk_hash,
1023 crx_path,
1024 context->fingerprint,
1025 component_patcher_.get(),
1026 context->installer);
[email protected]dd3aa792013-07-16 19:10:231027 if (!base::DeleteFile(crx_path, false))
[email protected]e8f96ff2011-08-03 05:07:331028 NOTREACHED() << crx_path.value();
[email protected]44da56e2011-11-21 19:59:141029 // Why unretained? See comment at top of file.
[email protected]73251e72012-03-04 02:10:331030 BrowserThread::PostDelayedTask(
1031 BrowserThread::UI,
1032 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:141033 base::Bind(&CrxUpdateService::DoneInstalling, base::Unretained(this),
[email protected]e3e696d32013-06-21 20:41:361034 context->id, unpacker.error(), unpacker.extended_error()),
[email protected]73251e72012-03-04 02:10:331035 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]07f93af12011-08-17 20:57:221036 delete context;
[email protected]e8f96ff2011-08-03 05:07:331037}
1038
1039// Installation has been completed. Adjust the component status and
[email protected]7b0529242013-07-20 05:45:461040// schedule the next check. Schedule a short delay before trying the full
1041// update when the differential update failed.
[email protected]07f93af12011-08-17 20:57:221042void CrxUpdateService::DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:361043 ComponentUnpacker::Error error,
1044 int extra_code) {
[email protected]e8f96ff2011-08-03 05:07:331045 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]07f93af12011-08-17 20:57:221046
[email protected]7b0529242013-07-20 05:45:461047 ErrorCategory error_category = kErrorNone;
1048 switch (error) {
1049 case ComponentUnpacker::kNone:
1050 break;
1051 case ComponentUnpacker::kInstallerError:
1052 error_category = kInstallError;
1053 break;
1054 default:
1055 error_category = kUnpackError;
1056 break;
1057 }
1058
1059 const bool is_success = error == ComponentUnpacker::kNone;
1060
[email protected]07f93af12011-08-17 20:57:221061 CrxUpdateItem* item = FindUpdateItemById(component_id);
[email protected]7b0529242013-07-20 05:45:461062 if (item->status == CrxUpdateItem::kUpdatingDiff && !is_success) {
1063 item->diff_error_category = error_category;
1064 item->diff_error_code = error;
1065 item->diff_extra_code1 = extra_code;
[email protected]1ea21ad2013-09-02 04:20:391066 item->diff_update_failed = true;
1067 size_t count = ChangeItemStatus(CrxUpdateItem::kUpdatingDiff,
1068 CrxUpdateItem::kCanUpdate);
1069 DCHECK_EQ(count, 1ul);
1070 ScheduleNextRun(kStepDelayShort);
1071 return;
[email protected]e3e696d32013-06-21 20:41:361072 }
[email protected]e3e696d32013-06-21 20:41:361073
[email protected]7b0529242013-07-20 05:45:461074 if (is_success) {
[email protected]61aca4cd2013-10-26 10:50:591075 ChangeItemState(item, CrxUpdateItem::kUpdated);
[email protected]07f93af12011-08-17 20:57:221076 item->component.version = item->next_version;
[email protected]e3e696d32013-06-21 20:41:361077 item->component.fingerprint = item->next_fp;
[email protected]7b0529242013-07-20 05:45:461078 } else {
[email protected]61aca4cd2013-10-26 10:50:591079 ChangeItemState(item, CrxUpdateItem::kNoUpdate);
[email protected]7b0529242013-07-20 05:45:461080 item->error_category = error_category;
1081 item->error_code = error;
1082 item->extra_code1 = extra_code;
[email protected]e3e696d32013-06-21 20:41:361083 }
[email protected]07f93af12011-08-17 20:57:221084
[email protected]7b0529242013-07-20 05:45:461085 ping_manager_->OnUpdateComplete(item);
[email protected]360b8bb2011-09-01 21:48:061086
[email protected]32a6c8382013-08-20 00:29:201087 // Move on to the next update, if there is one available.
1088 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:331089}
1090
[email protected]85e61d52013-08-01 22:23:421091void CrxUpdateService::NotifyComponentObservers(
1092 ComponentObserver::Events event, int extra) const {
1093 for (UpdateItems::const_iterator it = work_items_.begin();
1094 it != work_items_.end(); ++it) {
1095 ComponentObserver* observer = (*it)->component.observer;
1096 if (observer)
1097 observer->OnEvent(event, 0);
1098 }
1099}
1100
[email protected]00a77fa2013-11-02 04:18:461101content::ResourceThrottle* CrxUpdateService::GetOnDemandResourceThrottle(
1102 net::URLRequest* request, const std::string& crx_id) {
1103 // We give the raw pointer to the caller, who will delete it at will
1104 // and we keep for ourselves a weak pointer to it so we can post tasks
1105 // from the UI thread without having to track lifetime directly.
1106 CUResourceThrottle* rt = new CUResourceThrottle(request);
1107 BrowserThread::PostTask(
1108 BrowserThread::UI,
1109 FROM_HERE,
1110 base::Bind(&CrxUpdateService::OnNewResourceThrottle,
1111 base::Unretained(this),
1112 rt->AsWeakPtr(),
1113 crx_id));
1114 return rt;
1115}
1116
1117void CrxUpdateService::OnNewResourceThrottle(
1118 base::WeakPtr<CUResourceThrottle> rt, const std::string& crx_id) {
1119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1120 // Check if we can on-demand update, else unblock the request anyway.
1121 CrxUpdateItem* item = FindUpdateItemById(crx_id);
1122 Status status = OnDemandUpdateInternal(item);
1123 if (status == kOk || status == kInProgress) {
1124 item->throttles.push_back(rt);
1125 return;
1126 }
1127 UnblockResourceThrottle(rt);
1128}
1129
1130///////////////////////////////////////////////////////////////////////////////
1131
1132CUResourceThrottle::CUResourceThrottle(const net::URLRequest* request)
1133 : state_(NEW) {
1134 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1135}
1136
1137CUResourceThrottle::~CUResourceThrottle() {
1138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1139}
1140
1141void CUResourceThrottle::WillStartRequest(bool* defer) {
1142 if (state_ != UNBLOCKED) {
1143 state_ = BLOCKED;
1144 *defer = true;
1145 } else {
1146 *defer = false;
1147 }
1148}
1149
1150void CUResourceThrottle::WillRedirectRequest(const GURL& new_url, bool* defer) {
1151 WillStartRequest(defer);
1152}
1153
1154void CUResourceThrottle::Unblock() {
1155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1156 if (state_ == BLOCKED)
1157 controller()->Resume();
1158 state_ = UNBLOCKED;
1159}
1160
[email protected]e8f96ff2011-08-03 05:07:331161// The component update factory. Using the component updater as a singleton
1162// is the job of the browser process.
1163ComponentUpdateService* ComponentUpdateServiceFactory(
1164 ComponentUpdateService::Configurator* config) {
1165 DCHECK(config);
1166 return new CrxUpdateService(config);
1167}
[email protected]2cddef42013-11-22 08:23:221168