blob: ea0aa8d69d2054abe2a66fe1478137b60ec5224c [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]e8f96ff2011-08-03 05:07:3318#include "base/stl_util.h"
[email protected]3ea1b182013-02-08 22:38:4119#include "base/strings/string_number_conversions.h"
[email protected]4570a252013-03-31 00:35:4320#include "base/strings/string_piece.h"
[email protected]e7463412013-06-10 22:53:4621#include "base/strings/string_util.h"
22#include "base/strings/stringprintf.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"
[email protected]e3e696d32013-06-21 20:41:3625#include "chrome/browser/component_updater/component_patcher.h"
[email protected]e8f96ff2011-08-03 05:07:3326#include "chrome/browser/component_updater/component_unpacker.h"
[email protected]7b0529242013-07-20 05:45:4627#include "chrome/browser/component_updater/component_updater_ping_manager.h"
28#include "chrome/browser/component_updater/crx_update_item.h"
[email protected]e8f96ff2011-08-03 05:07:3329#include "chrome/common/chrome_utility_messages.h"
30#include "chrome/common/chrome_version_info.h"
31#include "chrome/common/extensions/extension.h"
[email protected]b7b63872013-01-03 02:41:1932#include "content/public/browser/browser_thread.h"
[email protected]c4f883a2012-02-03 17:02:0733#include "content/public/browser/utility_process_host.h"
34#include "content/public/browser/utility_process_host_client.h"
[email protected]e8f96ff2011-08-03 05:07:3335#include "net/base/escape.h"
36#include "net/base/load_flags.h"
[email protected]1dd4060e2013-03-13 13:15:1337#include "net/base/net_errors.h"
[email protected]3dc1bc42012-06-19 08:20:5338#include "net/url_request/url_fetcher.h"
[email protected]15fb2aa2012-05-22 22:52:5939#include "net/url_request/url_fetcher_delegate.h"
[email protected]9d8ea302012-09-25 15:04:2240#include "net/url_request/url_request_status.h"
[email protected]761fa4702013-07-02 15:25:1541#include "url/gurl.h"
[email protected]e8f96ff2011-08-03 05:07:3342
[email protected]631bb742011-11-02 11:29:3943using content::BrowserThread;
[email protected]c4f883a2012-02-03 17:02:0744using content::UtilityProcessHost;
45using content::UtilityProcessHostClient;
[email protected]1c321ee52012-05-21 03:02:3446using extensions::Extension;
[email protected]631bb742011-11-02 11:29:3947
[email protected]44da56e2011-11-21 19:59:1448// The component updater is designed to live until process shutdown, so
49// base::Bind() calls are not refcounted.
50
[email protected]e8f96ff2011-08-03 05:07:3351namespace {
[email protected]e3e696d32013-06-21 20:41:3652
[email protected]e8f96ff2011-08-03 05:07:3353// Extends an omaha compatible update check url |query| string. Does
54// not mutate the string if it would be longer than |limit| chars.
[email protected]4c37b452011-12-21 01:33:5255bool AddQueryString(const std::string& id,
56 const std::string& version,
[email protected]e3e696d32013-06-21 20:41:3657 const std::string& fingerprint,
[email protected]69b9f5de2013-06-24 20:59:4658 bool ondemand,
[email protected]4c37b452011-12-21 01:33:5259 size_t limit,
60 std::string* query) {
[email protected]e8f96ff2011-08-03 05:07:3361 std::string additional =
[email protected]69b9f5de2013-06-24 20:59:4662 base::StringPrintf("id=%s&v=%s&fp=%s&uc%s",
63 id.c_str(),
64 version.c_str(),
65 fingerprint.c_str(),
66 ondemand ? "&installsource=ondemand" : "");
[email protected]4a19be92011-09-22 14:25:0267 additional = "x=" + net::EscapeQueryParamValue(additional, true);
[email protected]e8f96ff2011-08-03 05:07:3368 if ((additional.size() + query->size() + 1) > limit)
69 return false;
[email protected]926d36332011-10-05 01:06:2570 if (!query->empty())
71 query->append(1, '&');
[email protected]e8f96ff2011-08-03 05:07:3372 query->append(additional);
73 return true;
74}
75
[email protected]926d36332011-10-05 01:06:2576// Create the final omaha compatible query. The |extra| is optional and can
77// be null. It should contain top level (non-escaped) parameters.
78std::string MakeFinalQuery(const std::string& host,
79 const std::string& query,
80 const char* extra) {
81 std::string request(host);
82 request.append(1, '?');
83 if (extra) {
84 request.append(extra);
85 request.append(1, '&');
86 }
87 request.append(query);
88 return request;
89}
90
[email protected]e8f96ff2011-08-03 05:07:3391// Produces an extension-like friendly |id|. This might be removed in the
92// future if we roll our on packing tools.
93static std::string HexStringToID(const std::string& hexstr) {
94 std::string id;
95 for (size_t i = 0; i < hexstr.size(); ++i) {
96 int val;
[email protected]eb72b272011-12-19 16:10:5597 if (base::HexStringToInt(base::StringPiece(hexstr.begin() + i,
98 hexstr.begin() + i + 1),
99 &val)) {
[email protected]e8f96ff2011-08-03 05:07:33100 id.append(1, val + 'a');
[email protected]eb72b272011-12-19 16:10:55101 } else {
[email protected]e8f96ff2011-08-03 05:07:33102 id.append(1, 'a');
[email protected]eb72b272011-12-19 16:10:55103 }
[email protected]e8f96ff2011-08-03 05:07:33104 }
105 DCHECK(Extension::IdIsValid(id));
106 return id;
107}
108
[email protected]e8f96ff2011-08-03 05:07:33109// Helper to do version check for components.
110bool IsVersionNewer(const Version& current, const std::string& proposed) {
111 Version proposed_ver(proposed);
112 if (!proposed_ver.IsValid())
113 return false;
114 return (current.CompareTo(proposed_ver) < 0);
115}
116
117// Helper template class that allows our main class to have separate
[email protected]f1050432012-02-15 01:35:46118// OnURLFetchComplete() callbacks for different types of url requests
[email protected]e8f96ff2011-08-03 05:07:33119// they are differentiated by the |Ctx| type.
120template <typename Del, typename Ctx>
[email protected]15fb2aa2012-05-22 22:52:59121class DelegateWithContext : public net::URLFetcherDelegate {
[email protected]e8f96ff2011-08-03 05:07:33122 public:
123 DelegateWithContext(Del* delegate, Ctx* context)
124 : delegate_(delegate), context_(context) {}
125
[email protected]10c2d692012-05-11 05:32:23126 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
[email protected]e8f96ff2011-08-03 05:07:33127 delegate_->OnURLFetchComplete(source, context_);
128 delete this;
129 }
130
131 private:
132 ~DelegateWithContext() {}
133
134 Del* delegate_;
135 Ctx* context_;
136};
137// This function creates the right DelegateWithContext using template inference.
138template <typename Del, typename Ctx>
[email protected]15fb2aa2012-05-22 22:52:59139net::URLFetcherDelegate* MakeContextDelegate(Del* delegate, Ctx* context) {
[email protected]e8f96ff2011-08-03 05:07:33140 return new DelegateWithContext<Del, Ctx>(delegate, context);
141}
142
143// Helper to start a url request using |fetcher| with the common flags.
[email protected]d3ec669b2012-05-23 07:12:14144void StartFetch(net::URLFetcher* fetcher,
[email protected]e8f96ff2011-08-03 05:07:33145 net::URLRequestContextGetter* context_getter,
146 bool save_to_file) {
[email protected]7cc6e5632011-10-25 17:56:12147 fetcher->SetRequestContext(context_getter);
148 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
149 net::LOAD_DO_NOT_SAVE_COOKIES |
150 net::LOAD_DISABLE_CACHE);
[email protected]e8f96ff2011-08-03 05:07:33151 // TODO(cpu): Define our retry and backoff policy.
[email protected]7cc6e5632011-10-25 17:56:12152 fetcher->SetAutomaticallyRetryOn5xx(false);
[email protected]e8f96ff2011-08-03 05:07:33153 if (save_to_file) {
154 fetcher->SaveResponseToTemporaryFile(
155 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
156 }
157 fetcher->Start();
158}
159
[email protected]e3e696d32013-06-21 20:41:36160// Returns true if the url request of |fetcher| was succesful.
[email protected]10c2d692012-05-11 05:32:23161bool FetchSuccess(const net::URLFetcher& fetcher) {
[email protected]7cc6e5632011-10-25 17:56:12162 return (fetcher.GetStatus().status() == net::URLRequestStatus::SUCCESS) &&
163 (fetcher.GetResponseCode() == 200);
[email protected]e8f96ff2011-08-03 05:07:33164}
165
[email protected]7b0529242013-07-20 05:45:46166// Returns the error code which occured during the fetch.The function returns 0
167// if the fetch was successful. If errors happen, the function could return a
168// network error, an http response code, or the status of the fetch, if the
169// fetch is pending or canceled.
170int GetFetchError(const net::URLFetcher& fetcher) {
171 if (FetchSuccess(fetcher))
172 return 0;
[email protected]e8f96ff2011-08-03 05:07:33173
[email protected]7b0529242013-07-20 05:45:46174 const net::URLRequestStatus::Status status(fetcher.GetStatus().status());
175 if (status == net::URLRequestStatus::FAILED)
176 return fetcher.GetStatus().error();
[email protected]3707eb22013-06-21 14:20:13177
[email protected]7b0529242013-07-20 05:45:46178 if (status == net::URLRequestStatus::IO_PENDING ||
179 status == net::URLRequestStatus::CANCELED)
180 return status;
[email protected]e3e696d32013-06-21 20:41:36181
[email protected]7b0529242013-07-20 05:45:46182 const int response_code(fetcher.GetResponseCode());
183 if (status == net::URLRequestStatus::SUCCESS && response_code != 200)
184 return response_code;
[email protected]e3e696d32013-06-21 20:41:36185
[email protected]7b0529242013-07-20 05:45:46186 return -1;
[email protected]e3e696d32013-06-21 20:41:36187 }
[email protected]e8f96ff2011-08-03 05:07:33188
[email protected]e3e696d32013-06-21 20:41:36189// Returns true if a differential update is available for the update item.
190bool IsDiffUpdateAvailable(const CrxUpdateItem* update_item) {
191 return update_item->diff_crx_url.is_valid();
192}
[email protected]e8f96ff2011-08-03 05:07:33193
[email protected]e3e696d32013-06-21 20:41:36194// Returns true if a differential update is available, it has not failed yet,
195// and the configuration allows it.
196bool CanTryDiffUpdate(const CrxUpdateItem* update_item,
197 const ComponentUpdateService::Configurator& config) {
198 return IsDiffUpdateAvailable(update_item) &&
199 !update_item->diff_update_failed &&
200 config.DeltasEnabled();
201}
202
[email protected]7b0529242013-07-20 05:45:46203} // namespace
204
205CrxUpdateItem::CrxUpdateItem()
206 : status(kNew),
207 diff_update_failed(false),
208 error_category(0),
209 error_code(0),
210 extra_code1(0),
211 diff_error_category(0),
212 diff_error_code(0),
213 diff_extra_code1(0) {
214}
215
216CrxUpdateItem::~CrxUpdateItem() {
217}
[email protected]86550a42013-06-21 15:20:49218
[email protected]dc06f0b2013-01-23 20:03:16219CrxComponent::CrxComponent()
[email protected]85e61d52013-08-01 22:23:42220 : installer(NULL),
221 observer(NULL) {
[email protected]dc06f0b2013-01-23 20:03:16222}
223
224CrxComponent::~CrxComponent() {
225}
[email protected]e8f96ff2011-08-03 05:07:33226
227//////////////////////////////////////////////////////////////////////////////
228// The one and only implementation of the ComponentUpdateService interface. In
229// charge of running the show. The main method is ProcessPendingItems() which
[email protected]50b01392012-09-01 03:33:13230// is called periodically to do the upgrades/installs or the update checks.
[email protected]e8f96ff2011-08-03 05:07:33231// An important consideration here is to be as "low impact" as we can to the
232// rest of the browser, so even if we have many components registered and
[email protected]f1050432012-02-15 01:35:46233// eligible for update, we only do one thing at a time with pauses in between
[email protected]e8f96ff2011-08-03 05:07:33234// the tasks. Also when we do network requests there is only one |url_fetcher_|
[email protected]e3e696d32013-06-21 20:41:36235// in flight at a time.
[email protected]e8f96ff2011-08-03 05:07:33236// There are no locks in this code, the main structure |work_items_| is mutated
237// only from the UI thread. The unpack and installation is done in the file
238// thread and the network requests are done in the IO thread and in the file
239// thread.
240class CrxUpdateService : public ComponentUpdateService {
241 public:
242 explicit CrxUpdateService(ComponentUpdateService::Configurator* config);
243
244 virtual ~CrxUpdateService();
245
246 // Overrides for ComponentUpdateService.
247 virtual Status Start() OVERRIDE;
248 virtual Status Stop() OVERRIDE;
249 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE;
[email protected]ccb4feef2013-02-14 06:16:47250 virtual Status CheckForUpdateSoon(const CrxComponent& component) OVERRIDE;
[email protected]e8f96ff2011-08-03 05:07:33251
252 // The only purpose of this class is to forward the
[email protected]c4f883a2012-02-03 17:02:07253 // UtilityProcessHostClient callbacks so CrxUpdateService does
[email protected]e8f96ff2011-08-03 05:07:33254 // not have to derive from it because that is refcounted.
[email protected]c4f883a2012-02-03 17:02:07255 class ManifestParserBridge : public UtilityProcessHostClient {
[email protected]e8f96ff2011-08-03 05:07:33256 public:
257 explicit ManifestParserBridge(CrxUpdateService* service)
258 : service_(service) {}
259
260 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
261 bool handled = true;
262 IPC_BEGIN_MESSAGE_MAP(ManifestParserBridge, message)
[email protected]2ccf45c2011-08-19 23:35:50263 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseUpdateManifest_Succeeded,
[email protected]e8f96ff2011-08-03 05:07:33264 OnParseUpdateManifestSucceeded)
[email protected]2ccf45c2011-08-19 23:35:50265 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseUpdateManifest_Failed,
[email protected]e8f96ff2011-08-03 05:07:33266 OnParseUpdateManifestFailed)
267 IPC_MESSAGE_UNHANDLED(handled = false)
268 IPC_END_MESSAGE_MAP()
269 return handled;
270 }
271
272 private:
[email protected]a3988cc2012-04-27 05:07:18273 virtual ~ManifestParserBridge() {}
274
[email protected]f1050432012-02-15 01:35:46275 // Omaha update response XML was successfully parsed.
[email protected]e8f96ff2011-08-03 05:07:33276 void OnParseUpdateManifestSucceeded(const UpdateManifest::Results& r) {
277 service_->OnParseUpdateManifestSucceeded(r);
278 }
279 // Omaha update response XML could not be parsed.
280 void OnParseUpdateManifestFailed(const std::string& e) {
281 service_->OnParseUpdateManifestFailed(e);
282 }
283
284 CrxUpdateService* service_;
285 DISALLOW_COPY_AND_ASSIGN(ManifestParserBridge);
286 };
287
288 // Context for a update check url request. See DelegateWithContext above.
289 struct UpdateContext {
290 base::Time start;
291 UpdateContext() : start(base::Time::Now()) {}
292 };
293
294 // Context for a crx download url request. See DelegateWithContext above.
295 struct CRXContext {
296 ComponentInstaller* installer;
297 std::vector<uint8> pk_hash;
298 std::string id;
[email protected]e3e696d32013-06-21 20:41:36299 std::string fingerprint;
[email protected]e8f96ff2011-08-03 05:07:33300 CRXContext() : installer(NULL) {}
301 };
302
[email protected]10c2d692012-05-11 05:32:23303 void OnURLFetchComplete(const net::URLFetcher* source,
[email protected]7cc6e5632011-10-25 17:56:12304 UpdateContext* context);
[email protected]e8f96ff2011-08-03 05:07:33305
[email protected]10c2d692012-05-11 05:32:23306 void OnURLFetchComplete(const net::URLFetcher* source,
[email protected]7cc6e5632011-10-25 17:56:12307 CRXContext* context);
[email protected]e8f96ff2011-08-03 05:07:33308
309 private:
[email protected]7b0529242013-07-20 05:45:46310 enum ErrorCategory {
311 kErrorNone = 0,
312 kNetworkError,
313 kUnpackError,
314 kInstallError,
315 };
316
[email protected]32a6c8382013-08-20 00:29:20317 enum StepDelayInterval {
318 kStepDelayShort = 0,
319 kStepDelayMedium,
320 kStepDelayLong,
321 };
322
[email protected]e8f96ff2011-08-03 05:07:33323 // See ManifestParserBridge.
[email protected]7b0529242013-07-20 05:45:46324 void OnParseUpdateManifestSucceeded(const UpdateManifest::Results& results);
[email protected]e8f96ff2011-08-03 05:07:33325
326 // See ManifestParserBridge.
[email protected]e3e696d32013-06-21 20:41:36327 void OnParseUpdateManifestFailed(const std::string& error_message);
[email protected]e8f96ff2011-08-03 05:07:33328
329 bool AddItemToUpdateCheck(CrxUpdateItem* item, std::string* query);
330
331 void ProcessPendingItems();
332
[email protected]32a6c8382013-08-20 00:29:20333 void ScheduleNextRun(StepDelayInterval step_delay);
[email protected]e8f96ff2011-08-03 05:07:33334
335 void ParseManifest(const std::string& xml);
336
[email protected]650b2d52013-02-10 03:41:45337 void Install(const CRXContext* context, const base::FilePath& crx_path);
[email protected]e8f96ff2011-08-03 05:07:33338
[email protected]07f93af12011-08-17 20:57:22339 void DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:36340 ComponentUnpacker::Error error,
341 int extended_error);
[email protected]e8f96ff2011-08-03 05:07:33342
343 size_t ChangeItemStatus(CrxUpdateItem::Status from,
344 CrxUpdateItem::Status to);
345
346 CrxUpdateItem* FindUpdateItemById(const std::string& id);
347
[email protected]85e61d52013-08-01 22:23:42348 void NotifyComponentObservers(ComponentObserver::Events event,
349 int extra) const;
350
[email protected]e3e696d32013-06-21 20:41:36351 scoped_ptr<ComponentUpdateService::Configurator> config_;
352
353 scoped_ptr<ComponentPatcher> component_patcher_;
[email protected]e8f96ff2011-08-03 05:07:33354
[email protected]d3ec669b2012-05-23 07:12:14355 scoped_ptr<net::URLFetcher> url_fetcher_;
[email protected]e8f96ff2011-08-03 05:07:33356
[email protected]7b0529242013-07-20 05:45:46357 scoped_ptr<component_updater::PingManager> ping_manager_;
358
[email protected]86550a42013-06-21 15:20:49359 // A collection of every work item.
[email protected]e3e696d32013-06-21 20:41:36360 typedef std::vector<CrxUpdateItem*> UpdateItems;
[email protected]e8f96ff2011-08-03 05:07:33361 UpdateItems work_items_;
362
[email protected]ccb4feef2013-02-14 06:16:47363 // A particular set of items from work_items_, which should be checked ASAP.
364 std::set<CrxUpdateItem*> requested_work_items_;
365
[email protected]e8f96ff2011-08-03 05:07:33366 base::OneShotTimer<CrxUpdateService> timer_;
367
[email protected]e3e696d32013-06-21 20:41:36368 const Version chrome_version_;
[email protected]e8f96ff2011-08-03 05:07:33369
370 bool running_;
371
372 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
373};
374
[email protected]e8f96ff2011-08-03 05:07:33375//////////////////////////////////////////////////////////////////////////////
376
[email protected]e3e696d32013-06-21 20:41:36377CrxUpdateService::CrxUpdateService(ComponentUpdateService::Configurator* config)
[email protected]e8f96ff2011-08-03 05:07:33378 : config_(config),
[email protected]e3e696d32013-06-21 20:41:36379 component_patcher_(config->CreateComponentPatcher()),
[email protected]7b0529242013-07-20 05:45:46380 ping_manager_(new component_updater::PingManager(
381 config->PingUrl(),
382 config->RequestContext())),
[email protected]e8f96ff2011-08-03 05:07:33383 chrome_version_(chrome::VersionInfo().Version()),
[email protected]e8f96ff2011-08-03 05:07:33384 running_(false) {
[email protected]7b0529242013-07-20 05:45:46385 }
[email protected]e8f96ff2011-08-03 05:07:33386
387CrxUpdateService::~CrxUpdateService() {
388 // Because we are a singleton, at this point only the UI thread should be
389 // alive, this simplifies the management of the work that could be in
390 // flight in other threads.
391 Stop();
392 STLDeleteElements(&work_items_);
[email protected]7b0529242013-07-20 05:45:46393 }
[email protected]e8f96ff2011-08-03 05:07:33394
395ComponentUpdateService::Status CrxUpdateService::Start() {
396 // Note that RegisterComponent will call Start() when the first
397 // component is registered, so it can be called twice. This way
398 // we avoid scheduling the timer if there is no work to do.
399 running_ = true;
400 if (work_items_.empty())
401 return kOk;
402
[email protected]85e61d52013-08-01 22:23:42403 NotifyComponentObservers(ComponentObserver::COMPONENT_UPDATER_STARTED, 0);
404
[email protected]d323a172011-09-02 18:23:02405 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->InitialDelay()),
[email protected]e8f96ff2011-08-03 05:07:33406 this, &CrxUpdateService::ProcessPendingItems);
407 return kOk;
408}
409
410// Stop the main check + update loop. In flight operations will be
411// completed.
412ComponentUpdateService::Status CrxUpdateService::Stop() {
413 running_ = false;
414 timer_.Stop();
415 return kOk;
416}
417
[email protected]ccb4feef2013-02-14 06:16:47418// This function sets the timer which will call ProcessPendingItems() or
419// ProcessRequestedItem() if there is an important requested item. There
[email protected]32a6c8382013-08-20 00:29:20420// are three kinds of waits:
421// - a short delay, when there is immediate work to be done.
422// - a medium delay, when there are updates to be applied within the current
423// update cycle, or there are components that are still unchecked.
424// - a long delay when a full check/update cycle has completed for all
425// components.
426void CrxUpdateService::ScheduleNextRun(StepDelayInterval step_delay) {
[email protected]e8f96ff2011-08-03 05:07:33427 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cf442612011-08-09 20:20:12428 DCHECK(url_fetcher_.get() == NULL);
[email protected]e8f96ff2011-08-03 05:07:33429 CHECK(!timer_.IsRunning());
430 // It could be the case that Stop() had been called while a url request
431 // or unpacking was in flight, if so we arrive here but |running_| is
432 // false. In that case do not loop again.
433 if (!running_)
434 return;
435
[email protected]ccb4feef2013-02-14 06:16:47436 // Keep the delay short if in the middle of an update (step_delay),
437 // or there are new requested_work_items_ that have not been processed yet.
[email protected]32a6c8382013-08-20 00:29:20438 int64 delay_seconds = 0;
439 if (requested_work_items_.empty()) {
440 switch (step_delay) {
441 case kStepDelayShort:
442 delay_seconds = config_->StepDelay();
443 break;
444 case kStepDelayMedium:
445 delay_seconds = config_->StepDelayMedium();
446 break;
447 case kStepDelayLong:
448 delay_seconds = config_->NextCheckDelay();
449 break;
450 }
451 } else {
452 delay_seconds = config_->StepDelay();
453 }
[email protected]cf442612011-08-09 20:20:12454
[email protected]32a6c8382013-08-20 00:29:20455 if (step_delay != kStepDelayShort) {
[email protected]85e61d52013-08-01 22:23:42456 NotifyComponentObservers(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0);
457
[email protected]e8f96ff2011-08-03 05:07:33458 // Zero is only used for unit tests.
[email protected]32a6c8382013-08-20 00:29:20459 if (0 == delay_seconds)
[email protected]e8f96ff2011-08-03 05:07:33460 return;
461 }
462
[email protected]32a6c8382013-08-20 00:29:20463 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay_seconds),
[email protected]e8f96ff2011-08-03 05:07:33464 this, &CrxUpdateService::ProcessPendingItems);
465}
466
467// Given a extension-like component id, find the associated component.
468CrxUpdateItem* CrxUpdateService::FindUpdateItemById(const std::string& id) {
469 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
470 CrxUpdateItem::FindById finder(id);
471 UpdateItems::iterator it = std::find_if(work_items_.begin(),
472 work_items_.end(),
473 finder);
474 if (it == work_items_.end())
475 return NULL;
476 return (*it);
477}
478
479// Changes all the components in |work_items_| that have |from| status to
[email protected]e3e696d32013-06-21 20:41:36480// |to| status and returns how many have been changed.
[email protected]e8f96ff2011-08-03 05:07:33481size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from,
482 CrxUpdateItem::Status to) {
483 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
484 size_t count = 0;
485 for (UpdateItems::iterator it = work_items_.begin();
486 it != work_items_.end(); ++it) {
487 CrxUpdateItem* item = *it;
488 if (item->status != from)
489 continue;
490 item->status = to;
491 ++count;
492 }
493 return count;
494}
495
496// Adds a component to be checked for upgrades. If the component exists it
497// it will be replaced and the return code is kReplaced.
498//
499// TODO(cpu): Evaluate if we want to support un-registration.
500ComponentUpdateService::Status CrxUpdateService::RegisterComponent(
501 const CrxComponent& component) {
502 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
503 if (component.pk_hash.empty() ||
504 !component.version.IsValid() ||
505 !component.installer)
506 return kError;
507
508 std::string id =
509 HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
510 component.pk_hash.size()/2)));
511 CrxUpdateItem* uit;
512 uit = FindUpdateItemById(id);
513 if (uit) {
514 uit->component = component;
515 return kReplaced;
516 }
517
518 uit = new CrxUpdateItem;
519 uit->id.swap(id);
520 uit->component = component;
[email protected]e3e696d32013-06-21 20:41:36521
[email protected]e8f96ff2011-08-03 05:07:33522 work_items_.push_back(uit);
523 // If this is the first component registered we call Start to
524 // schedule the first timer.
525 if (running_ && (work_items_.size() == 1))
526 Start();
527
528 return kOk;
529}
530
531// Sets a component to be checked for updates.
[email protected]69b9f5de2013-06-24 20:59:46532// The component to add is |item| and the |query| string is modified with the
533// required omaha compatible query. Returns false when the query string is
534// longer than specified by UrlSizeLimit().
535// If the item is currently on the requested_work_items_ list, the update check
536// is considered to be "on-demand": the server may honor on-demand checks by
537// serving updates at 100% rather than a gated fraction.
[email protected]e8f96ff2011-08-03 05:07:33538bool CrxUpdateService::AddItemToUpdateCheck(CrxUpdateItem* item,
539 std::string* query) {
540 if (!AddQueryString(item->id,
541 item->component.version.GetString(),
[email protected]e3e696d32013-06-21 20:41:36542 item->component.fingerprint,
[email protected]69b9f5de2013-06-24 20:59:46543 requested_work_items_.count(item) > 0, // is_ondemand
544 config_->UrlSizeLimit(),
545 query))
[email protected]e8f96ff2011-08-03 05:07:33546 return false;
[email protected]e3e696d32013-06-21 20:41:36547
[email protected]e8f96ff2011-08-03 05:07:33548 item->status = CrxUpdateItem::kChecking;
549 item->last_check = base::Time::Now();
[email protected]e3e696d32013-06-21 20:41:36550 item->previous_version = item->component.version;
551 item->next_version = Version();
552 item->previous_fp = item->component.fingerprint;
553 item->next_fp.clear();
554 item->diff_update_failed = false;
[email protected]7b0529242013-07-20 05:45:46555 item->error_category = 0;
556 item->error_code = 0;
557 item->extra_code1 = 0;
558 item->diff_error_category = 0;
559 item->diff_error_code = 0;
560 item->diff_extra_code1 = 0;
[email protected]e8f96ff2011-08-03 05:07:33561 return true;
562}
563
[email protected]ccb4feef2013-02-14 06:16:47564// Start the process of checking for an update, for a particular component
565// that was previously registered.
566ComponentUpdateService::Status CrxUpdateService::CheckForUpdateSoon(
567 const CrxComponent& component) {
568 if (component.pk_hash.empty() ||
569 !component.version.IsValid() ||
570 !component.installer)
571 return kError;
572
573 std::string id =
574 HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
575 component.pk_hash.size()/2)));
576
577 CrxUpdateItem* uit;
578 uit = FindUpdateItemById(id);
579 if (!uit)
580 return kError;
581
582 // Check if the request is too soon.
583 base::TimeDelta delta = base::Time::Now() - uit->last_check;
[email protected]e3e696d32013-06-21 20:41:36584 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
[email protected]ccb4feef2013-02-14 06:16:47585 return kError;
[email protected]ccb4feef2013-02-14 06:16:47586
587 switch (uit->status) {
588 // If the item is already in the process of being updated, there is
589 // no point in this call, so return kInProgress.
590 case CrxUpdateItem::kChecking:
591 case CrxUpdateItem::kCanUpdate:
[email protected]e3e696d32013-06-21 20:41:36592 case CrxUpdateItem::kDownloadingDiff:
[email protected]ccb4feef2013-02-14 06:16:47593 case CrxUpdateItem::kDownloading:
[email protected]e3e696d32013-06-21 20:41:36594 case CrxUpdateItem::kUpdatingDiff:
[email protected]ccb4feef2013-02-14 06:16:47595 case CrxUpdateItem::kUpdating:
596 return kInProgress;
597 // Otherwise the item was already checked a while back (or it is new),
598 // set its status to kNew to give it a slightly higher priority.
599 case CrxUpdateItem::kNew:
600 case CrxUpdateItem::kUpdated:
601 case CrxUpdateItem::kUpToDate:
602 case CrxUpdateItem::kNoUpdate:
603 uit->status = CrxUpdateItem::kNew;
604 requested_work_items_.insert(uit);
605 break;
606 case CrxUpdateItem::kLastStatus:
607 NOTREACHED() << uit->status;
608 }
609
610 // In case the current delay is long, set the timer to a shorter value
611 // to get the ball rolling.
612 if (timer_.IsRunning()) {
613 timer_.Stop();
614 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->StepDelay()),
615 this, &CrxUpdateService::ProcessPendingItems);
616 }
617
618 return kOk;
619}
620
[email protected]e8f96ff2011-08-03 05:07:33621// Here is where the work gets scheduled. Given that our |work_items_| list
622// is expected to be ten or less items, we simply loop several times.
623void CrxUpdateService::ProcessPendingItems() {
624 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
625 // First check for ready upgrades and do one. The first
626 // step is to fetch the crx package.
627 for (UpdateItems::const_iterator it = work_items_.begin();
628 it != work_items_.end(); ++it) {
629 CrxUpdateItem* item = *it;
630 if (item->status != CrxUpdateItem::kCanUpdate)
631 continue;
632 // Found component to update, start the process.
[email protected]e8f96ff2011-08-03 05:07:33633 CRXContext* context = new CRXContext;
634 context->pk_hash = item->component.pk_hash;
635 context->id = item->id;
636 context->installer = item->component.installer;
[email protected]e3e696d32013-06-21 20:41:36637 context->fingerprint = item->next_fp;
638 GURL package_url;
639 if (CanTryDiffUpdate(item, *config_)) {
640 package_url = item->diff_crx_url;
641 item->status = CrxUpdateItem::kDownloadingDiff;
642 } else {
643 package_url = item->crx_url;
644 item->status = CrxUpdateItem::kDownloading;
645 }
[email protected]3dc1bc42012-06-19 08:20:53646 url_fetcher_.reset(net::URLFetcher::Create(
[email protected]e3e696d32013-06-21 20:41:36647 0, package_url, net::URLFetcher::GET,
[email protected]e8f96ff2011-08-03 05:07:33648 MakeContextDelegate(this, context)));
649 StartFetch(url_fetcher_.get(), config_->RequestContext(), true);
650 return;
651 }
652
[email protected]d63306d2013-06-29 13:56:02653 std::string query;
654 // If no pending upgrades, we check if there are new components we have not
655 // checked against the server. We can batch some in a single url request.
656 for (UpdateItems::const_iterator it = work_items_.begin();
657 it != work_items_.end(); ++it) {
658 CrxUpdateItem* item = *it;
659 if (item->status != CrxUpdateItem::kNew)
[email protected]dc06f0b2013-01-23 20:03:16660 continue;
[email protected]d63306d2013-06-29 13:56:02661 if (!AddItemToUpdateCheck(item, &query))
662 break;
663 // Requested work items may speed up the update cycle up until
664 // the point that we start an update check. I.e., transition
665 // from kNew -> kChecking. Since the service doesn't guarantee that
666 // the requested items make it any further than kChecking,
667 // forget them now.
668 requested_work_items_.erase(item);
669 }
[email protected]dc06f0b2013-01-23 20:03:16670
[email protected]d63306d2013-06-29 13:56:02671 // Next we can go back to components we already checked, here
672 // we can also batch them in a single url request, as long as
673 // we have not checked them recently.
674 const base::TimeDelta min_delta_time =
675 base::TimeDelta::FromSeconds(config_->MinimumReCheckWait());
676
677 for (UpdateItems::const_iterator it = work_items_.begin();
678 it != work_items_.end(); ++it) {
679 CrxUpdateItem* item = *it;
680 if ((item->status != CrxUpdateItem::kNoUpdate) &&
681 (item->status != CrxUpdateItem::kUpToDate))
682 continue;
683 base::TimeDelta delta = base::Time::Now() - item->last_check;
684 if (delta < min_delta_time)
685 continue;
686 if (!AddItemToUpdateCheck(item, &query))
687 break;
688 }
689
690 // Finally, we check components that we already updated as long as
691 // we have not checked them recently.
692 for (UpdateItems::const_iterator it = work_items_.begin();
693 it != work_items_.end(); ++it) {
694 CrxUpdateItem* item = *it;
695 if (item->status != CrxUpdateItem::kUpdated)
696 continue;
697 base::TimeDelta delta = base::Time::Now() - item->last_check;
698 if (delta < min_delta_time)
699 continue;
700 if (!AddItemToUpdateCheck(item, &query))
701 break;
702 }
703
704 if (!query.empty()) {
[email protected]dc06f0b2013-01-23 20:03:16705 // We got components to check. Start the url request and exit.
706 const std::string full_query =
[email protected]d63306d2013-06-29 13:56:02707 MakeFinalQuery(config_->UpdateUrl().spec(),
[email protected]dc06f0b2013-01-23 20:03:16708 query,
709 config_->ExtraRequestParams());
710
711 url_fetcher_.reset(net::URLFetcher::Create(
712 0, GURL(full_query), net::URLFetcher::GET,
713 MakeContextDelegate(this, new UpdateContext())));
714 StartFetch(url_fetcher_.get(), config_->RequestContext(), false);
[email protected]e8f96ff2011-08-03 05:07:33715 return;
716 }
717
[email protected]dc06f0b2013-01-23 20:03:16718 // No components to update. Next check after the long sleep.
[email protected]32a6c8382013-08-20 00:29:20719 ScheduleNextRun(kStepDelayLong);
[email protected]e8f96ff2011-08-03 05:07:33720}
721
[email protected]ccb4feef2013-02-14 06:16:47722// Called when we got a response from the update server. It consists of an xml
[email protected]e8f96ff2011-08-03 05:07:33723// document following the omaha update scheme.
[email protected]10c2d692012-05-11 05:32:23724void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
[email protected]07f93af12011-08-17 20:57:22725 UpdateContext* context) {
[email protected]e8f96ff2011-08-03 05:07:33726 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
727 if (FetchSuccess(*source)) {
728 std::string xml;
729 source->GetResponseAsString(&xml);
[email protected]cf442612011-08-09 20:20:12730 url_fetcher_.reset();
[email protected]e8f96ff2011-08-03 05:07:33731 ParseManifest(xml);
732 } else {
[email protected]cf442612011-08-09 20:20:12733 url_fetcher_.reset();
[email protected]e8f96ff2011-08-03 05:07:33734 CrxUpdateService::OnParseUpdateManifestFailed("network error");
735 }
[email protected]07f93af12011-08-17 20:57:22736 delete context;
[email protected]e8f96ff2011-08-03 05:07:33737}
738
739// Parsing the manifest is either done right now for tests or in a sandboxed
740// process for the production environment. This mitigates the case where an
741// attacker was able to feed us a malicious xml string.
742void CrxUpdateService::ParseManifest(const std::string& xml) {
743 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
744 if (config_->InProcess()) {
745 UpdateManifest manifest;
[email protected]e3e696d32013-06-21 20:41:36746 if (!manifest.Parse(xml))
[email protected]e8f96ff2011-08-03 05:07:33747 CrxUpdateService::OnParseUpdateManifestFailed(manifest.errors());
[email protected]e3e696d32013-06-21 20:41:36748 else
[email protected]e8f96ff2011-08-03 05:07:33749 CrxUpdateService::OnParseUpdateManifestSucceeded(manifest.results());
[email protected]e8f96ff2011-08-03 05:07:33750 } else {
[email protected]cadac622013-06-11 16:46:36751 UtilityProcessHost* host =
752 UtilityProcessHost::Create(new ManifestParserBridge(this),
753 base::MessageLoopProxy::current().get());
[email protected]c4f883a2012-02-03 17:02:07754 host->EnableZygote();
[email protected]2ccf45c2011-08-19 23:35:50755 host->Send(new ChromeUtilityMsg_ParseUpdateManifest(xml));
[email protected]e8f96ff2011-08-03 05:07:33756 }
757}
758
759// A valid Omaha update check has arrived, from only the list of components that
760// we are currently upgrading we check for a match in which the server side
761// version is newer, if so we queue them for an upgrade. The next time we call
762// ProcessPendingItems() one of them will be drafted for the upgrade process.
763void CrxUpdateService::OnParseUpdateManifestSucceeded(
764 const UpdateManifest::Results& results) {
765 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a1f8c162012-09-27 22:32:21766 size_t update_pending = 0;
[email protected]e8f96ff2011-08-03 05:07:33767 std::vector<UpdateManifest::Result>::const_iterator it;
768 for (it = results.list.begin(); it != results.list.end(); ++it) {
769 CrxUpdateItem* crx = FindUpdateItemById(it->extension_id);
770 if (!crx)
771 continue;
772
773 if (crx->status != CrxUpdateItem::kChecking)
774 continue; // Not updating this component now.
775
[email protected]e8f96ff2011-08-03 05:07:33776 if (it->version.empty()) {
[email protected]cf442612011-08-09 20:20:12777 // No version means no update available.
[email protected]e8f96ff2011-08-03 05:07:33778 crx->status = CrxUpdateItem::kNoUpdate;
[email protected]cf442612011-08-09 20:20:12779 continue;
[email protected]e8f96ff2011-08-03 05:07:33780 }
781 if (!IsVersionNewer(crx->component.version, it->version)) {
[email protected]cf442612011-08-09 20:20:12782 // Our component is up to date.
[email protected]e8f96ff2011-08-03 05:07:33783 crx->status = CrxUpdateItem::kUpToDate;
[email protected]cf442612011-08-09 20:20:12784 continue;
[email protected]e8f96ff2011-08-03 05:07:33785 }
786 if (!it->browser_min_version.empty()) {
[email protected]cf442612011-08-09 20:20:12787 if (IsVersionNewer(chrome_version_, it->browser_min_version)) {
788 // Does not apply for this chrome version.
789 crx->status = CrxUpdateItem::kNoUpdate;
790 continue;
791 }
[email protected]e8f96ff2011-08-03 05:07:33792 }
793 // All test passed. Queue an upgrade for this component and fire the
794 // notifications.
795 crx->crx_url = it->crx_url;
[email protected]e3e696d32013-06-21 20:41:36796 crx->diff_crx_url = it->diff_crx_url;
[email protected]e8f96ff2011-08-03 05:07:33797 crx->status = CrxUpdateItem::kCanUpdate;
[email protected]07f93af12011-08-17 20:57:22798 crx->next_version = Version(it->version);
[email protected]e3e696d32013-06-21 20:41:36799 crx->next_fp = it->package_fingerprint;
[email protected]e8f96ff2011-08-03 05:07:33800 ++update_pending;
801
[email protected]85e61d52013-08-01 22:23:42802 if (crx->component.observer) {
803 crx->component.observer->OnEvent(
804 ComponentObserver::COMPONENT_UPDATE_FOUND, 0);
805 }
[email protected]e8f96ff2011-08-03 05:07:33806 }
[email protected]cf442612011-08-09 20:20:12807
808 // All the components that are not mentioned in the manifest we
809 // consider them up to date.
810 ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kUpToDate);
811
[email protected]32a6c8382013-08-20 00:29:20812 // If there are updates pending we do a short wait, otherwise we take
813 // a longer delay until we check the components again.
814 ScheduleNextRun(update_pending > 0 ? kStepDelayShort : kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33815}
816
817void CrxUpdateService::OnParseUpdateManifestFailed(
818 const std::string& error_message) {
819 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
820 size_t count = ChangeItemStatus(CrxUpdateItem::kChecking,
821 CrxUpdateItem::kNoUpdate);
[email protected]e8f96ff2011-08-03 05:07:33822 DCHECK_GT(count, 0ul);
[email protected]32a6c8382013-08-20 00:29:20823 ScheduleNextRun(kStepDelayLong);
[email protected]e8f96ff2011-08-03 05:07:33824}
825
826// Called when the CRX package has been downloaded to a temporary location.
827// Here we fire the notifications and schedule the component-specific installer
828// to be called in the file thread.
[email protected]10c2d692012-05-11 05:32:23829void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
[email protected]e8f96ff2011-08-03 05:07:33830 CRXContext* context) {
831 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]1dd4060e2013-03-13 13:15:13832 int error_code = net::OK;
[email protected]e8f96ff2011-08-03 05:07:33833
[email protected]e3e696d32013-06-21 20:41:36834 CrxUpdateItem* crx = FindUpdateItemById(context->id);
835 DCHECK(crx->status == CrxUpdateItem::kDownloadingDiff ||
836 crx->status == CrxUpdateItem::kDownloading);
837
[email protected]e8f96ff2011-08-03 05:07:33838 if (source->FileErrorOccurred(&error_code) || !FetchSuccess(*source)) {
[email protected]e3e696d32013-06-21 20:41:36839 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
[email protected]7b0529242013-07-20 05:45:46840 crx->diff_error_category = kNetworkError;
841 crx->diff_error_code = GetFetchError(*source);
[email protected]e630ba62013-06-22 15:22:34842 crx->diff_update_failed = true;
[email protected]e3e696d32013-06-21 20:41:36843 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
844 CrxUpdateItem::kCanUpdate);
845 DCHECK_EQ(count, 1ul);
[email protected]7b0529242013-07-20 05:45:46846 url_fetcher_.reset();
847
[email protected]32a6c8382013-08-20 00:29:20848 ScheduleNextRun(kStepDelayShort);
[email protected]e3e696d32013-06-21 20:41:36849 return;
850 }
[email protected]7b0529242013-07-20 05:45:46851 crx->error_category = kNetworkError;
852 crx->error_code = GetFetchError(*source);
[email protected]e8f96ff2011-08-03 05:07:33853 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
854 CrxUpdateItem::kNoUpdate);
855 DCHECK_EQ(count, 1ul);
[email protected]cf442612011-08-09 20:20:12856 url_fetcher_.reset();
[email protected]e3e696d32013-06-21 20:41:36857
[email protected]7b0529242013-07-20 05:45:46858 // At this point, since both the differential and the full downloads failed,
859 // the update for this component has finished with an error.
860 ping_manager_->OnUpdateComplete(crx);
861
[email protected]32a6c8382013-08-20 00:29:20862 // Move on to the next update, if there is one available.
863 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33864 } else {
[email protected]650b2d52013-02-10 03:41:45865 base::FilePath temp_crx_path;
[email protected]e8f96ff2011-08-03 05:07:33866 CHECK(source->GetResponseAsFilePath(true, &temp_crx_path));
[email protected]e3e696d32013-06-21 20:41:36867
868 size_t count = 0;
869 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
870 count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
871 CrxUpdateItem::kUpdatingDiff);
872 } else {
873 count = ChangeItemStatus(CrxUpdateItem::kDownloading,
874 CrxUpdateItem::kUpdating);
875 }
[email protected]e8f96ff2011-08-03 05:07:33876 DCHECK_EQ(count, 1ul);
[email protected]e3e696d32013-06-21 20:41:36877
[email protected]cf442612011-08-09 20:20:12878 url_fetcher_.reset();
879
[email protected]85e61d52013-08-01 22:23:42880 if (crx->component.observer) {
881 crx->component.observer->OnEvent(
882 ComponentObserver::COMPONENT_UPDATE_READY, 0);
883 }
884
[email protected]44da56e2011-11-21 19:59:14885 // Why unretained? See comment at top of file.
[email protected]73251e72012-03-04 02:10:33886 BrowserThread::PostDelayedTask(
887 BrowserThread::FILE,
888 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14889 base::Bind(&CrxUpdateService::Install,
890 base::Unretained(this),
891 context,
892 temp_crx_path),
[email protected]73251e72012-03-04 02:10:33893 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]e8f96ff2011-08-03 05:07:33894 }
[email protected]e8f96ff2011-08-03 05:07:33895}
896
897// Install consists of digital signature verification, unpacking and then
898// calling the component specific installer. All that is handled by the
899// |unpacker|. If there is an error this function is in charge of deleting
900// the files created.
901void CrxUpdateService::Install(const CRXContext* context,
[email protected]650b2d52013-02-10 03:41:45902 const base::FilePath& crx_path) {
[email protected]e8f96ff2011-08-03 05:07:33903 // This function owns the |crx_path| and the |context| object.
904 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]e3e696d32013-06-21 20:41:36905 ComponentUnpacker unpacker(context->pk_hash,
906 crx_path,
907 context->fingerprint,
908 component_patcher_.get(),
909 context->installer);
[email protected]dd3aa792013-07-16 19:10:23910 if (!base::DeleteFile(crx_path, false))
[email protected]e8f96ff2011-08-03 05:07:33911 NOTREACHED() << crx_path.value();
[email protected]44da56e2011-11-21 19:59:14912 // Why unretained? See comment at top of file.
[email protected]73251e72012-03-04 02:10:33913 BrowserThread::PostDelayedTask(
914 BrowserThread::UI,
915 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14916 base::Bind(&CrxUpdateService::DoneInstalling, base::Unretained(this),
[email protected]e3e696d32013-06-21 20:41:36917 context->id, unpacker.error(), unpacker.extended_error()),
[email protected]73251e72012-03-04 02:10:33918 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]07f93af12011-08-17 20:57:22919 delete context;
[email protected]e8f96ff2011-08-03 05:07:33920}
921
922// Installation has been completed. Adjust the component status and
[email protected]7b0529242013-07-20 05:45:46923// schedule the next check. Schedule a short delay before trying the full
924// update when the differential update failed.
[email protected]07f93af12011-08-17 20:57:22925void CrxUpdateService::DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:36926 ComponentUnpacker::Error error,
927 int extra_code) {
[email protected]e8f96ff2011-08-03 05:07:33928 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]07f93af12011-08-17 20:57:22929
[email protected]7b0529242013-07-20 05:45:46930 ErrorCategory error_category = kErrorNone;
931 switch (error) {
932 case ComponentUnpacker::kNone:
933 break;
934 case ComponentUnpacker::kInstallerError:
935 error_category = kInstallError;
936 break;
937 default:
938 error_category = kUnpackError;
939 break;
940 }
941
942 const bool is_success = error == ComponentUnpacker::kNone;
943
[email protected]07f93af12011-08-17 20:57:22944 CrxUpdateItem* item = FindUpdateItemById(component_id);
[email protected]7b0529242013-07-20 05:45:46945 if (item->status == CrxUpdateItem::kUpdatingDiff && !is_success) {
946 item->diff_error_category = error_category;
947 item->diff_error_code = error;
948 item->diff_extra_code1 = extra_code;
[email protected]e3e696d32013-06-21 20:41:36949 item->diff_update_failed = true;
950 size_t count = ChangeItemStatus(CrxUpdateItem::kUpdatingDiff,
951 CrxUpdateItem::kCanUpdate);
952 DCHECK_EQ(count, 1ul);
[email protected]32a6c8382013-08-20 00:29:20953 ScheduleNextRun(kStepDelayShort);
[email protected]e3e696d32013-06-21 20:41:36954 return;
955 }
[email protected]e3e696d32013-06-21 20:41:36956
[email protected]7b0529242013-07-20 05:45:46957 if (is_success) {
958 item->status = CrxUpdateItem::kUpdated;
[email protected]07f93af12011-08-17 20:57:22959 item->component.version = item->next_version;
[email protected]e3e696d32013-06-21 20:41:36960 item->component.fingerprint = item->next_fp;
[email protected]7b0529242013-07-20 05:45:46961 } else {
962 item->status = CrxUpdateItem::kNoUpdate;
963 item->error_category = error_category;
964 item->error_code = error;
965 item->extra_code1 = extra_code;
[email protected]e3e696d32013-06-21 20:41:36966 }
[email protected]07f93af12011-08-17 20:57:22967
[email protected]7b0529242013-07-20 05:45:46968 ping_manager_->OnUpdateComplete(item);
[email protected]360b8bb2011-09-01 21:48:06969
[email protected]32a6c8382013-08-20 00:29:20970 // Move on to the next update, if there is one available.
971 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33972}
973
[email protected]85e61d52013-08-01 22:23:42974void CrxUpdateService::NotifyComponentObservers(
975 ComponentObserver::Events event, int extra) const {
976 for (UpdateItems::const_iterator it = work_items_.begin();
977 it != work_items_.end(); ++it) {
978 ComponentObserver* observer = (*it)->component.observer;
979 if (observer)
980 observer->OnEvent(event, 0);
981 }
982}
983
[email protected]e8f96ff2011-08-03 05:07:33984// The component update factory. Using the component updater as a singleton
985// is the job of the browser process.
986ComponentUpdateService* ComponentUpdateServiceFactory(
987 ComponentUpdateService::Configurator* config) {
988 DCHECK(config);
989 return new CrxUpdateService(config);
990}