blob: a87c3da100c02a2dd8ba329d3c64c4bb924035fa [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]e8f96ff2011-08-03 05:07:3323#include "base/timer.h"
24#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"
27#include "chrome/common/chrome_notification_types.h"
28#include "chrome/common/chrome_utility_messages.h"
29#include "chrome/common/chrome_version_info.h"
30#include "chrome/common/extensions/extension.h"
[email protected]e3e696d32013-06-21 20:41:3631#include "chrome/common/omaha_query_params/omaha_query_params.h"
[email protected]b7b63872013-01-03 02:41:1932#include "content/public/browser/browser_thread.h"
[email protected]ad50def52011-10-19 23:17:0733#include "content/public/browser/notification_service.h"
[email protected]c4f883a2012-02-03 17:02:0734#include "content/public/browser/utility_process_host.h"
35#include "content/public/browser/utility_process_host_client.h"
[email protected]e8f96ff2011-08-03 05:07:3336#include "googleurl/src/gurl.h"
37#include "net/base/escape.h"
38#include "net/base/load_flags.h"
[email protected]1dd4060e2013-03-13 13:15:1339#include "net/base/net_errors.h"
[email protected]3dc1bc42012-06-19 08:20:5340#include "net/url_request/url_fetcher.h"
[email protected]15fb2aa2012-05-22 22:52:5941#include "net/url_request/url_fetcher_delegate.h"
[email protected]9d8ea302012-09-25 15:04:2242#include "net/url_request/url_request_status.h"
[email protected]e8f96ff2011-08-03 05:07:3343
[email protected]631bb742011-11-02 11:29:3944using content::BrowserThread;
[email protected]c4f883a2012-02-03 17:02:0745using content::UtilityProcessHost;
46using content::UtilityProcessHostClient;
[email protected]1c321ee52012-05-21 03:02:3447using extensions::Extension;
[email protected]631bb742011-11-02 11:29:3948
[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]dc06f0b2013-01-23 20:03:1654// Manifest sources, from most important to least important.
55const CrxComponent::UrlSource kManifestSources[] = {
56 CrxComponent::BANDAID,
57 CrxComponent::CWS_PUBLIC,
[email protected]e3e696d32013-06-21 20:41:3658 CrxComponent::CWS_SANDBOX,
[email protected]dc06f0b2013-01-23 20:03:1659};
60
[email protected]e8f96ff2011-08-03 05:07:3361// Extends an omaha compatible update check url |query| string. Does
62// not mutate the string if it would be longer than |limit| chars.
[email protected]4c37b452011-12-21 01:33:5263bool AddQueryString(const std::string& id,
64 const std::string& version,
[email protected]e3e696d32013-06-21 20:41:3665 const std::string& fingerprint,
[email protected]4c37b452011-12-21 01:33:5266 size_t limit,
67 std::string* query) {
[email protected]e8f96ff2011-08-03 05:07:3368 std::string additional =
[email protected]e3e696d32013-06-21 20:41:3669 base::StringPrintf("id=%s&v=%s&fp=%s&uc",
70 id.c_str(), version.c_str(), fingerprint.c_str());
[email protected]4a19be92011-09-22 14:25:0271 additional = "x=" + net::EscapeQueryParamValue(additional, true);
[email protected]e8f96ff2011-08-03 05:07:3372 if ((additional.size() + query->size() + 1) > limit)
73 return false;
[email protected]926d36332011-10-05 01:06:2574 if (!query->empty())
75 query->append(1, '&');
[email protected]e8f96ff2011-08-03 05:07:3376 query->append(additional);
77 return true;
78}
79
[email protected]926d36332011-10-05 01:06:2580// Create the final omaha compatible query. The |extra| is optional and can
81// be null. It should contain top level (non-escaped) parameters.
82std::string MakeFinalQuery(const std::string& host,
83 const std::string& query,
84 const char* extra) {
85 std::string request(host);
86 request.append(1, '?');
87 if (extra) {
88 request.append(extra);
89 request.append(1, '&');
90 }
91 request.append(query);
92 return request;
93}
94
[email protected]e8f96ff2011-08-03 05:07:3395// Produces an extension-like friendly |id|. This might be removed in the
96// future if we roll our on packing tools.
97static std::string HexStringToID(const std::string& hexstr) {
98 std::string id;
99 for (size_t i = 0; i < hexstr.size(); ++i) {
100 int val;
[email protected]eb72b272011-12-19 16:10:55101 if (base::HexStringToInt(base::StringPiece(hexstr.begin() + i,
102 hexstr.begin() + i + 1),
103 &val)) {
[email protected]e8f96ff2011-08-03 05:07:33104 id.append(1, val + 'a');
[email protected]eb72b272011-12-19 16:10:55105 } else {
[email protected]e8f96ff2011-08-03 05:07:33106 id.append(1, 'a');
[email protected]eb72b272011-12-19 16:10:55107 }
[email protected]e8f96ff2011-08-03 05:07:33108 }
109 DCHECK(Extension::IdIsValid(id));
110 return id;
111}
112
[email protected]360b8bb2011-09-01 21:48:06113// Returns given a crx id it returns a small number, less than 100, that has a
114// decent chance of being unique among the registered components. It also has
115// the nice property that can be trivially computed by hand.
116static int CrxIdtoUMAId(const std::string& id) {
[email protected]a1f8c162012-09-27 22:32:21117 CHECK_GT(id.size(), 2U);
[email protected]360b8bb2011-09-01 21:48:06118 return id[0] + id[1] + id[2] - ('a' * 3);
119}
120
[email protected]e8f96ff2011-08-03 05:07:33121// Helper to do version check for components.
122bool IsVersionNewer(const Version& current, const std::string& proposed) {
123 Version proposed_ver(proposed);
124 if (!proposed_ver.IsValid())
125 return false;
126 return (current.CompareTo(proposed_ver) < 0);
127}
128
129// Helper template class that allows our main class to have separate
[email protected]f1050432012-02-15 01:35:46130// OnURLFetchComplete() callbacks for different types of url requests
[email protected]e8f96ff2011-08-03 05:07:33131// they are differentiated by the |Ctx| type.
132template <typename Del, typename Ctx>
[email protected]15fb2aa2012-05-22 22:52:59133class DelegateWithContext : public net::URLFetcherDelegate {
[email protected]e8f96ff2011-08-03 05:07:33134 public:
135 DelegateWithContext(Del* delegate, Ctx* context)
136 : delegate_(delegate), context_(context) {}
137
[email protected]10c2d692012-05-11 05:32:23138 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
[email protected]e8f96ff2011-08-03 05:07:33139 delegate_->OnURLFetchComplete(source, context_);
140 delete this;
141 }
142
143 private:
144 ~DelegateWithContext() {}
145
146 Del* delegate_;
147 Ctx* context_;
148};
149// This function creates the right DelegateWithContext using template inference.
150template <typename Del, typename Ctx>
[email protected]15fb2aa2012-05-22 22:52:59151net::URLFetcherDelegate* MakeContextDelegate(Del* delegate, Ctx* context) {
[email protected]e8f96ff2011-08-03 05:07:33152 return new DelegateWithContext<Del, Ctx>(delegate, context);
153}
154
155// Helper to start a url request using |fetcher| with the common flags.
[email protected]d3ec669b2012-05-23 07:12:14156void StartFetch(net::URLFetcher* fetcher,
[email protected]e8f96ff2011-08-03 05:07:33157 net::URLRequestContextGetter* context_getter,
158 bool save_to_file) {
[email protected]7cc6e5632011-10-25 17:56:12159 fetcher->SetRequestContext(context_getter);
160 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
161 net::LOAD_DO_NOT_SAVE_COOKIES |
162 net::LOAD_DISABLE_CACHE);
[email protected]e8f96ff2011-08-03 05:07:33163 // TODO(cpu): Define our retry and backoff policy.
[email protected]7cc6e5632011-10-25 17:56:12164 fetcher->SetAutomaticallyRetryOn5xx(false);
[email protected]e8f96ff2011-08-03 05:07:33165 if (save_to_file) {
166 fetcher->SaveResponseToTemporaryFile(
167 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
168 }
169 fetcher->Start();
170}
171
[email protected]e3e696d32013-06-21 20:41:36172// Returns true if the url request of |fetcher| was succesful.
[email protected]10c2d692012-05-11 05:32:23173bool FetchSuccess(const net::URLFetcher& fetcher) {
[email protected]7cc6e5632011-10-25 17:56:12174 return (fetcher.GetStatus().status() == net::URLRequestStatus::SUCCESS) &&
175 (fetcher.GetResponseCode() == 200);
[email protected]e8f96ff2011-08-03 05:07:33176}
177
178// This is the one and only per-item state structure. Designed to be hosted
179// in a std::vector or a std::list. The two main members are |component|
180// which is supplied by the the component updater client and |status| which
181// is modified as the item is processed by the update pipeline. The expected
182// transition graph is:
[email protected]e3e696d32013-06-21 20:41:36183//
184// kNew
185// |
186// V
187// +----------------------> kChecking -<---------+-----<-------+
188// | | | |
189// | error V no | |
190// kNoUpdate <---------------- [update?] ->---- kUpToDate kUpdated
191// ^ | ^
192// | yes | |
193// | diff=false V |
194// | +-----------> kCanUpdate |
195// | | | |
196// | | V no |
197// | | [differential update?]->----+ |
198// | | | | |
199// | | yes | | |
200// | | error V | |
201// | +---------<- kDownloadingDiff | |
202// | | | | |
203// | | | | |
204// | | error V | |
205// | +---------<- kUpdatingDiff ->--------|-----------+ success
206// | | |
207// | error V |
208// +----------------------------------------- kDownloading |
209// | | |
210// | error V |
211// +------------------------------------------ kUpdating ->----+ success
[email protected]e8f96ff2011-08-03 05:07:33212//
213struct CrxUpdateItem {
214 enum Status {
215 kNew,
216 kChecking,
217 kCanUpdate,
[email protected]e3e696d32013-06-21 20:41:36218 kDownloadingDiff,
[email protected]e8f96ff2011-08-03 05:07:33219 kDownloading,
[email protected]e3e696d32013-06-21 20:41:36220 kUpdatingDiff,
[email protected]e8f96ff2011-08-03 05:07:33221 kUpdating,
222 kUpdated,
223 kUpToDate,
224 kNoUpdate,
225 kLastStatus
226 };
227
228 Status status;
[email protected]86550a42013-06-21 15:20:49229 std::string id;
[email protected]86550a42013-06-21 15:20:49230 CrxComponent component;
[email protected]3707eb22013-06-21 14:20:13231
[email protected]e3e696d32013-06-21 20:41:36232 base::Time last_check;
233
234 // These members are initialized with their corresponding values from the
235 // update server response.
236 GURL crx_url;
237 GURL diff_crx_url;
238 int size;
239 int diff_size;
240
241 // The from/to version and fingerprint values.
242 Version previous_version;
243 Version next_version;
244 std::string previous_fp;
245 std::string next_fp;
246
247 // True if the differential update failed for any reason.
248 bool diff_update_failed;
249
250 CrxUpdateItem()
251 : status(kNew),
252 size(0),
253 diff_size(0),
254 diff_update_failed(false) {
255 }
[email protected]e8f96ff2011-08-03 05:07:33256
257 // Function object used to find a specific component.
258 class FindById {
259 public:
260 explicit FindById(const std::string& id) : id_(id) {}
261
262 bool operator() (CrxUpdateItem* item) const {
263 return (item->id == id_);
264 }
265 private:
266 const std::string& id_;
267 };
268};
269
[email protected]e3e696d32013-06-21 20:41:36270// Returns true if a differential update is available for the update item.
271bool IsDiffUpdateAvailable(const CrxUpdateItem* update_item) {
272 return update_item->diff_crx_url.is_valid();
273}
[email protected]e8f96ff2011-08-03 05:07:33274
[email protected]e3e696d32013-06-21 20:41:36275// Returns true if a differential update is available, it has not failed yet,
276// and the configuration allows it.
277bool CanTryDiffUpdate(const CrxUpdateItem* update_item,
278 const ComponentUpdateService::Configurator& config) {
279 return IsDiffUpdateAvailable(update_item) &&
280 !update_item->diff_update_failed &&
281 config.DeltasEnabled();
282}
283
284} // namespace.
[email protected]86550a42013-06-21 15:20:49285
[email protected]dc06f0b2013-01-23 20:03:16286CrxComponent::CrxComponent()
287 : installer(NULL),
288 source(BANDAID) {
289}
290
291CrxComponent::~CrxComponent() {
292}
[email protected]e8f96ff2011-08-03 05:07:33293
294//////////////////////////////////////////////////////////////////////////////
295// The one and only implementation of the ComponentUpdateService interface. In
296// charge of running the show. The main method is ProcessPendingItems() which
[email protected]50b01392012-09-01 03:33:13297// is called periodically to do the upgrades/installs or the update checks.
[email protected]e8f96ff2011-08-03 05:07:33298// An important consideration here is to be as "low impact" as we can to the
299// rest of the browser, so even if we have many components registered and
[email protected]f1050432012-02-15 01:35:46300// eligible for update, we only do one thing at a time with pauses in between
[email protected]e8f96ff2011-08-03 05:07:33301// the tasks. Also when we do network requests there is only one |url_fetcher_|
[email protected]e3e696d32013-06-21 20:41:36302// in flight at a time.
[email protected]e8f96ff2011-08-03 05:07:33303// There are no locks in this code, the main structure |work_items_| is mutated
304// only from the UI thread. The unpack and installation is done in the file
305// thread and the network requests are done in the IO thread and in the file
306// thread.
307class CrxUpdateService : public ComponentUpdateService {
308 public:
309 explicit CrxUpdateService(ComponentUpdateService::Configurator* config);
310
311 virtual ~CrxUpdateService();
312
313 // Overrides for ComponentUpdateService.
314 virtual Status Start() OVERRIDE;
315 virtual Status Stop() OVERRIDE;
316 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE;
[email protected]ccb4feef2013-02-14 06:16:47317 virtual Status CheckForUpdateSoon(const CrxComponent& component) OVERRIDE;
[email protected]e8f96ff2011-08-03 05:07:33318
319 // The only purpose of this class is to forward the
[email protected]c4f883a2012-02-03 17:02:07320 // UtilityProcessHostClient callbacks so CrxUpdateService does
[email protected]e8f96ff2011-08-03 05:07:33321 // not have to derive from it because that is refcounted.
[email protected]c4f883a2012-02-03 17:02:07322 class ManifestParserBridge : public UtilityProcessHostClient {
[email protected]e8f96ff2011-08-03 05:07:33323 public:
324 explicit ManifestParserBridge(CrxUpdateService* service)
325 : service_(service) {}
326
327 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
328 bool handled = true;
329 IPC_BEGIN_MESSAGE_MAP(ManifestParserBridge, message)
[email protected]2ccf45c2011-08-19 23:35:50330 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseUpdateManifest_Succeeded,
[email protected]e8f96ff2011-08-03 05:07:33331 OnParseUpdateManifestSucceeded)
[email protected]2ccf45c2011-08-19 23:35:50332 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseUpdateManifest_Failed,
[email protected]e8f96ff2011-08-03 05:07:33333 OnParseUpdateManifestFailed)
334 IPC_MESSAGE_UNHANDLED(handled = false)
335 IPC_END_MESSAGE_MAP()
336 return handled;
337 }
338
339 private:
[email protected]a3988cc2012-04-27 05:07:18340 virtual ~ManifestParserBridge() {}
341
[email protected]f1050432012-02-15 01:35:46342 // Omaha update response XML was successfully parsed.
[email protected]e8f96ff2011-08-03 05:07:33343 void OnParseUpdateManifestSucceeded(const UpdateManifest::Results& r) {
344 service_->OnParseUpdateManifestSucceeded(r);
345 }
346 // Omaha update response XML could not be parsed.
347 void OnParseUpdateManifestFailed(const std::string& e) {
348 service_->OnParseUpdateManifestFailed(e);
349 }
350
351 CrxUpdateService* service_;
352 DISALLOW_COPY_AND_ASSIGN(ManifestParserBridge);
353 };
354
355 // Context for a update check url request. See DelegateWithContext above.
356 struct UpdateContext {
357 base::Time start;
358 UpdateContext() : start(base::Time::Now()) {}
359 };
360
361 // Context for a crx download url request. See DelegateWithContext above.
362 struct CRXContext {
363 ComponentInstaller* installer;
364 std::vector<uint8> pk_hash;
365 std::string id;
[email protected]e3e696d32013-06-21 20:41:36366 std::string fingerprint;
[email protected]e8f96ff2011-08-03 05:07:33367 CRXContext() : installer(NULL) {}
368 };
369
[email protected]10c2d692012-05-11 05:32:23370 void OnURLFetchComplete(const net::URLFetcher* source,
[email protected]7cc6e5632011-10-25 17:56:12371 UpdateContext* context);
[email protected]e8f96ff2011-08-03 05:07:33372
[email protected]10c2d692012-05-11 05:32:23373 void OnURLFetchComplete(const net::URLFetcher* source,
[email protected]7cc6e5632011-10-25 17:56:12374 CRXContext* context);
[email protected]e8f96ff2011-08-03 05:07:33375
376 private:
377 // See ManifestParserBridge.
378 void OnParseUpdateManifestSucceeded(
379 const UpdateManifest::Results& results);
380
381 // See ManifestParserBridge.
[email protected]e3e696d32013-06-21 20:41:36382 void OnParseUpdateManifestFailed(const std::string& error_message);
[email protected]e8f96ff2011-08-03 05:07:33383
384 bool AddItemToUpdateCheck(CrxUpdateItem* item, std::string* query);
385
386 void ProcessPendingItems();
387
388 void ScheduleNextRun(bool step_delay);
389
390 void ParseManifest(const std::string& xml);
391
[email protected]650b2d52013-02-10 03:41:45392 void Install(const CRXContext* context, const base::FilePath& crx_path);
[email protected]e8f96ff2011-08-03 05:07:33393
[email protected]07f93af12011-08-17 20:57:22394 void DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:36395 ComponentUnpacker::Error error,
396 int extended_error);
[email protected]e8f96ff2011-08-03 05:07:33397
398 size_t ChangeItemStatus(CrxUpdateItem::Status from,
399 CrxUpdateItem::Status to);
400
401 CrxUpdateItem* FindUpdateItemById(const std::string& id);
402
[email protected]e3e696d32013-06-21 20:41:36403 scoped_ptr<ComponentUpdateService::Configurator> config_;
404
405 scoped_ptr<ComponentPatcher> component_patcher_;
[email protected]e8f96ff2011-08-03 05:07:33406
[email protected]d3ec669b2012-05-23 07:12:14407 scoped_ptr<net::URLFetcher> url_fetcher_;
[email protected]e8f96ff2011-08-03 05:07:33408
[email protected]86550a42013-06-21 15:20:49409 // A collection of every work item.
[email protected]e3e696d32013-06-21 20:41:36410 typedef std::vector<CrxUpdateItem*> UpdateItems;
[email protected]e8f96ff2011-08-03 05:07:33411 UpdateItems work_items_;
412
[email protected]ccb4feef2013-02-14 06:16:47413 // A particular set of items from work_items_, which should be checked ASAP.
414 std::set<CrxUpdateItem*> requested_work_items_;
415
[email protected]e8f96ff2011-08-03 05:07:33416 base::OneShotTimer<CrxUpdateService> timer_;
417
[email protected]e3e696d32013-06-21 20:41:36418 const Version chrome_version_;
419 const std::string prod_id_;
[email protected]e8f96ff2011-08-03 05:07:33420
421 bool running_;
422
423 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
424};
425
[email protected]e8f96ff2011-08-03 05:07:33426//////////////////////////////////////////////////////////////////////////////
427
[email protected]e3e696d32013-06-21 20:41:36428CrxUpdateService::CrxUpdateService(ComponentUpdateService::Configurator* config)
[email protected]e8f96ff2011-08-03 05:07:33429 : config_(config),
[email protected]e3e696d32013-06-21 20:41:36430 component_patcher_(config->CreateComponentPatcher()),
[email protected]e8f96ff2011-08-03 05:07:33431 chrome_version_(chrome::VersionInfo().Version()),
[email protected]e3e696d32013-06-21 20:41:36432 prod_id_(chrome::OmahaQueryParams::GetProdIdString(
433 chrome::OmahaQueryParams::CHROME)),
[email protected]e8f96ff2011-08-03 05:07:33434 running_(false) {
435}
436
437CrxUpdateService::~CrxUpdateService() {
438 // Because we are a singleton, at this point only the UI thread should be
439 // alive, this simplifies the management of the work that could be in
440 // flight in other threads.
441 Stop();
442 STLDeleteElements(&work_items_);
443}
444
445ComponentUpdateService::Status CrxUpdateService::Start() {
446 // Note that RegisterComponent will call Start() when the first
447 // component is registered, so it can be called twice. This way
448 // we avoid scheduling the timer if there is no work to do.
449 running_ = true;
450 if (work_items_.empty())
451 return kOk;
452
[email protected]ad50def52011-10-19 23:17:07453 content::NotificationService::current()->Notify(
[email protected]e8f96ff2011-08-03 05:07:33454 chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED,
[email protected]6c2381d2011-10-19 02:52:53455 content::Source<ComponentUpdateService>(this),
[email protected]ad50def52011-10-19 23:17:07456 content::NotificationService::NoDetails());
[email protected]e8f96ff2011-08-03 05:07:33457
[email protected]d323a172011-09-02 18:23:02458 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->InitialDelay()),
[email protected]e8f96ff2011-08-03 05:07:33459 this, &CrxUpdateService::ProcessPendingItems);
460 return kOk;
461}
462
463// Stop the main check + update loop. In flight operations will be
464// completed.
465ComponentUpdateService::Status CrxUpdateService::Stop() {
466 running_ = false;
467 timer_.Stop();
468 return kOk;
469}
470
[email protected]ccb4feef2013-02-14 06:16:47471// This function sets the timer which will call ProcessPendingItems() or
472// ProcessRequestedItem() if there is an important requested item. There
473// are two kinds of waits: a short step_delay (when step_status is
474// kPrevInProgress) and a long one when a full check/update cycle
475// has completed either successfully or with an error.
[email protected]e8f96ff2011-08-03 05:07:33476void CrxUpdateService::ScheduleNextRun(bool step_delay) {
477 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cf442612011-08-09 20:20:12478 DCHECK(url_fetcher_.get() == NULL);
[email protected]e8f96ff2011-08-03 05:07:33479 CHECK(!timer_.IsRunning());
480 // It could be the case that Stop() had been called while a url request
481 // or unpacking was in flight, if so we arrive here but |running_| is
482 // false. In that case do not loop again.
483 if (!running_)
484 return;
485
[email protected]ccb4feef2013-02-14 06:16:47486 // Keep the delay short if in the middle of an update (step_delay),
487 // or there are new requested_work_items_ that have not been processed yet.
488 int64 delay = (step_delay || requested_work_items_.size() > 0)
489 ? config_->StepDelay() : config_->NextCheckDelay();
[email protected]cf442612011-08-09 20:20:12490
[email protected]e8f96ff2011-08-03 05:07:33491 if (!step_delay) {
[email protected]ad50def52011-10-19 23:17:07492 content::NotificationService::current()->Notify(
[email protected]e8f96ff2011-08-03 05:07:33493 chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING,
[email protected]6c2381d2011-10-19 02:52:53494 content::Source<ComponentUpdateService>(this),
[email protected]ad50def52011-10-19 23:17:07495 content::NotificationService::NoDetails());
[email protected]e8f96ff2011-08-03 05:07:33496 // Zero is only used for unit tests.
[email protected]cf442612011-08-09 20:20:12497 if (0 == delay)
[email protected]e8f96ff2011-08-03 05:07:33498 return;
499 }
500
[email protected]d323a172011-09-02 18:23:02501 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay),
[email protected]e8f96ff2011-08-03 05:07:33502 this, &CrxUpdateService::ProcessPendingItems);
503}
504
505// Given a extension-like component id, find the associated component.
506CrxUpdateItem* CrxUpdateService::FindUpdateItemById(const std::string& id) {
507 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
508 CrxUpdateItem::FindById finder(id);
509 UpdateItems::iterator it = std::find_if(work_items_.begin(),
510 work_items_.end(),
511 finder);
512 if (it == work_items_.end())
513 return NULL;
514 return (*it);
515}
516
517// Changes all the components in |work_items_| that have |from| status to
[email protected]e3e696d32013-06-21 20:41:36518// |to| status and returns how many have been changed.
[email protected]e8f96ff2011-08-03 05:07:33519size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from,
520 CrxUpdateItem::Status to) {
521 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
522 size_t count = 0;
523 for (UpdateItems::iterator it = work_items_.begin();
524 it != work_items_.end(); ++it) {
525 CrxUpdateItem* item = *it;
526 if (item->status != from)
527 continue;
528 item->status = to;
529 ++count;
530 }
531 return count;
532}
533
534// Adds a component to be checked for upgrades. If the component exists it
535// it will be replaced and the return code is kReplaced.
536//
537// TODO(cpu): Evaluate if we want to support un-registration.
538ComponentUpdateService::Status CrxUpdateService::RegisterComponent(
539 const CrxComponent& component) {
540 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
541 if (component.pk_hash.empty() ||
542 !component.version.IsValid() ||
543 !component.installer)
544 return kError;
545
546 std::string id =
547 HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
548 component.pk_hash.size()/2)));
549 CrxUpdateItem* uit;
550 uit = FindUpdateItemById(id);
551 if (uit) {
552 uit->component = component;
553 return kReplaced;
554 }
555
556 uit = new CrxUpdateItem;
557 uit->id.swap(id);
558 uit->component = component;
[email protected]e3e696d32013-06-21 20:41:36559
[email protected]e8f96ff2011-08-03 05:07:33560 work_items_.push_back(uit);
561 // If this is the first component registered we call Start to
562 // schedule the first timer.
563 if (running_ && (work_items_.size() == 1))
564 Start();
565
566 return kOk;
567}
568
569// Sets a component to be checked for updates.
[email protected]e3e696d32013-06-21 20:41:36570// The component to add is |crxit| and the |query| string is modified with the
[email protected]e8f96ff2011-08-03 05:07:33571// required omaha compatible query. Returns false when the query strings
572// is longer than specified by UrlSizeLimit().
573bool CrxUpdateService::AddItemToUpdateCheck(CrxUpdateItem* item,
574 std::string* query) {
575 if (!AddQueryString(item->id,
576 item->component.version.GetString(),
[email protected]e3e696d32013-06-21 20:41:36577 item->component.fingerprint,
[email protected]e8f96ff2011-08-03 05:07:33578 config_->UrlSizeLimit(), query))
579 return false;
[email protected]e3e696d32013-06-21 20:41:36580
[email protected]e8f96ff2011-08-03 05:07:33581 item->status = CrxUpdateItem::kChecking;
582 item->last_check = base::Time::Now();
[email protected]e3e696d32013-06-21 20:41:36583 item->previous_version = item->component.version;
584 item->next_version = Version();
585 item->previous_fp = item->component.fingerprint;
586 item->next_fp.clear();
587 item->diff_update_failed = false;
[email protected]e8f96ff2011-08-03 05:07:33588 return true;
589}
590
[email protected]ccb4feef2013-02-14 06:16:47591// Start the process of checking for an update, for a particular component
592// that was previously registered.
593ComponentUpdateService::Status CrxUpdateService::CheckForUpdateSoon(
594 const CrxComponent& component) {
595 if (component.pk_hash.empty() ||
596 !component.version.IsValid() ||
597 !component.installer)
598 return kError;
599
600 std::string id =
601 HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
602 component.pk_hash.size()/2)));
603
604 CrxUpdateItem* uit;
605 uit = FindUpdateItemById(id);
606 if (!uit)
607 return kError;
608
609 // Check if the request is too soon.
610 base::TimeDelta delta = base::Time::Now() - uit->last_check;
[email protected]e3e696d32013-06-21 20:41:36611 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
[email protected]ccb4feef2013-02-14 06:16:47612 return kError;
[email protected]ccb4feef2013-02-14 06:16:47613
614 switch (uit->status) {
615 // If the item is already in the process of being updated, there is
616 // no point in this call, so return kInProgress.
617 case CrxUpdateItem::kChecking:
618 case CrxUpdateItem::kCanUpdate:
[email protected]e3e696d32013-06-21 20:41:36619 case CrxUpdateItem::kDownloadingDiff:
[email protected]ccb4feef2013-02-14 06:16:47620 case CrxUpdateItem::kDownloading:
[email protected]e3e696d32013-06-21 20:41:36621 case CrxUpdateItem::kUpdatingDiff:
[email protected]ccb4feef2013-02-14 06:16:47622 case CrxUpdateItem::kUpdating:
623 return kInProgress;
624 // Otherwise the item was already checked a while back (or it is new),
625 // set its status to kNew to give it a slightly higher priority.
626 case CrxUpdateItem::kNew:
627 case CrxUpdateItem::kUpdated:
628 case CrxUpdateItem::kUpToDate:
629 case CrxUpdateItem::kNoUpdate:
630 uit->status = CrxUpdateItem::kNew;
631 requested_work_items_.insert(uit);
632 break;
633 case CrxUpdateItem::kLastStatus:
634 NOTREACHED() << uit->status;
635 }
636
637 // In case the current delay is long, set the timer to a shorter value
638 // to get the ball rolling.
639 if (timer_.IsRunning()) {
640 timer_.Stop();
641 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->StepDelay()),
642 this, &CrxUpdateService::ProcessPendingItems);
643 }
644
645 return kOk;
646}
647
[email protected]e8f96ff2011-08-03 05:07:33648// Here is where the work gets scheduled. Given that our |work_items_| list
649// is expected to be ten or less items, we simply loop several times.
650void CrxUpdateService::ProcessPendingItems() {
651 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
652 // First check for ready upgrades and do one. The first
653 // step is to fetch the crx package.
654 for (UpdateItems::const_iterator it = work_items_.begin();
655 it != work_items_.end(); ++it) {
656 CrxUpdateItem* item = *it;
657 if (item->status != CrxUpdateItem::kCanUpdate)
658 continue;
659 // Found component to update, start the process.
[email protected]e8f96ff2011-08-03 05:07:33660 CRXContext* context = new CRXContext;
661 context->pk_hash = item->component.pk_hash;
662 context->id = item->id;
663 context->installer = item->component.installer;
[email protected]e3e696d32013-06-21 20:41:36664 context->fingerprint = item->next_fp;
665 GURL package_url;
666 if (CanTryDiffUpdate(item, *config_)) {
667 package_url = item->diff_crx_url;
668 item->status = CrxUpdateItem::kDownloadingDiff;
669 } else {
670 package_url = item->crx_url;
671 item->status = CrxUpdateItem::kDownloading;
672 }
[email protected]3dc1bc42012-06-19 08:20:53673 url_fetcher_.reset(net::URLFetcher::Create(
[email protected]e3e696d32013-06-21 20:41:36674 0, package_url, net::URLFetcher::GET,
[email protected]e8f96ff2011-08-03 05:07:33675 MakeContextDelegate(this, context)));
676 StartFetch(url_fetcher_.get(), config_->RequestContext(), true);
677 return;
678 }
679
[email protected]dc06f0b2013-01-23 20:03:16680 for (size_t ix = 0; ix != arraysize(kManifestSources); ++ix) {
681 const CrxComponent::UrlSource manifest_source = kManifestSources[ix];
[email protected]e8f96ff2011-08-03 05:07:33682
[email protected]dc06f0b2013-01-23 20:03:16683 std::string query;
684 // If no pending upgrades, we check if there are new components we have not
685 // checked against the server. We can batch some in a single url request.
686 for (UpdateItems::const_iterator it = work_items_.begin();
687 it != work_items_.end(); ++it) {
688 CrxUpdateItem* item = *it;
689 if (item->status != CrxUpdateItem::kNew)
690 continue;
691 if (item->component.source != manifest_source)
692 continue;
693 if (!AddItemToUpdateCheck(item, &query))
694 break;
[email protected]ccb4feef2013-02-14 06:16:47695 // Requested work items may speed up the update cycle up until
696 // the point that we start an update check. I.e., transition
697 // from kNew -> kChecking. Since the service doesn't guarantee that
698 // the requested items make it any further than kChecking,
699 // forget them now.
700 requested_work_items_.erase(item);
[email protected]dc06f0b2013-01-23 20:03:16701 }
[email protected]e8f96ff2011-08-03 05:07:33702
[email protected]dc06f0b2013-01-23 20:03:16703 // Next we can go back to components we already checked, here
704 // we can also batch them in a single url request, as long as
705 // we have not checked them recently.
706 const base::TimeDelta min_delta_time =
707 base::TimeDelta::FromSeconds(config_->MinimumReCheckWait());
[email protected]e8f96ff2011-08-03 05:07:33708
[email protected]dc06f0b2013-01-23 20:03:16709 for (UpdateItems::const_iterator it = work_items_.begin();
710 it != work_items_.end(); ++it) {
711 CrxUpdateItem* item = *it;
712 if ((item->status != CrxUpdateItem::kNoUpdate) &&
713 (item->status != CrxUpdateItem::kUpToDate))
714 continue;
715 if (item->component.source != manifest_source)
716 continue;
717 base::TimeDelta delta = base::Time::Now() - item->last_check;
718 if (delta < min_delta_time)
719 continue;
720 if (!AddItemToUpdateCheck(item, &query))
721 break;
722 }
723
724 // Finally, we check components that we already updated as long as
725 // we have not checked them recently.
726 for (UpdateItems::const_iterator it = work_items_.begin();
727 it != work_items_.end(); ++it) {
728 CrxUpdateItem* item = *it;
729 if (item->status != CrxUpdateItem::kUpdated)
730 continue;
731 if (item->component.source != manifest_source)
732 continue;
733 base::TimeDelta delta = base::Time::Now() - item->last_check;
734 if (delta < min_delta_time)
735 continue;
736 if (!AddItemToUpdateCheck(item, &query))
737 break;
738 }
739
740 // If no components to update we move down to the next source.
741 if (query.empty())
742 continue;
743
744 // We got components to check. Start the url request and exit.
745 const std::string full_query =
746 MakeFinalQuery(config_->UpdateUrl(manifest_source).spec(),
747 query,
748 config_->ExtraRequestParams());
749
750 url_fetcher_.reset(net::URLFetcher::Create(
751 0, GURL(full_query), net::URLFetcher::GET,
752 MakeContextDelegate(this, new UpdateContext())));
753 StartFetch(url_fetcher_.get(), config_->RequestContext(), false);
[email protected]e8f96ff2011-08-03 05:07:33754 return;
755 }
756
[email protected]dc06f0b2013-01-23 20:03:16757 // No components to update. Next check after the long sleep.
758 ScheduleNextRun(false);
[email protected]e8f96ff2011-08-03 05:07:33759}
760
[email protected]ccb4feef2013-02-14 06:16:47761// Called when we got a response from the update server. It consists of an xml
[email protected]e8f96ff2011-08-03 05:07:33762// document following the omaha update scheme.
[email protected]10c2d692012-05-11 05:32:23763void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
[email protected]07f93af12011-08-17 20:57:22764 UpdateContext* context) {
[email protected]e8f96ff2011-08-03 05:07:33765 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
766 if (FetchSuccess(*source)) {
767 std::string xml;
768 source->GetResponseAsString(&xml);
[email protected]cf442612011-08-09 20:20:12769 url_fetcher_.reset();
[email protected]e8f96ff2011-08-03 05:07:33770 ParseManifest(xml);
771 } else {
[email protected]cf442612011-08-09 20:20:12772 url_fetcher_.reset();
[email protected]e8f96ff2011-08-03 05:07:33773 CrxUpdateService::OnParseUpdateManifestFailed("network error");
774 }
[email protected]07f93af12011-08-17 20:57:22775 delete context;
[email protected]e8f96ff2011-08-03 05:07:33776}
777
778// Parsing the manifest is either done right now for tests or in a sandboxed
779// process for the production environment. This mitigates the case where an
780// attacker was able to feed us a malicious xml string.
781void CrxUpdateService::ParseManifest(const std::string& xml) {
782 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
783 if (config_->InProcess()) {
784 UpdateManifest manifest;
[email protected]e3e696d32013-06-21 20:41:36785 if (!manifest.Parse(xml))
[email protected]e8f96ff2011-08-03 05:07:33786 CrxUpdateService::OnParseUpdateManifestFailed(manifest.errors());
[email protected]e3e696d32013-06-21 20:41:36787 else
[email protected]e8f96ff2011-08-03 05:07:33788 CrxUpdateService::OnParseUpdateManifestSucceeded(manifest.results());
[email protected]e8f96ff2011-08-03 05:07:33789 } else {
[email protected]cadac622013-06-11 16:46:36790 UtilityProcessHost* host =
791 UtilityProcessHost::Create(new ManifestParserBridge(this),
792 base::MessageLoopProxy::current().get());
[email protected]c4f883a2012-02-03 17:02:07793 host->EnableZygote();
[email protected]2ccf45c2011-08-19 23:35:50794 host->Send(new ChromeUtilityMsg_ParseUpdateManifest(xml));
[email protected]e8f96ff2011-08-03 05:07:33795 }
796}
797
798// A valid Omaha update check has arrived, from only the list of components that
799// we are currently upgrading we check for a match in which the server side
800// version is newer, if so we queue them for an upgrade. The next time we call
801// ProcessPendingItems() one of them will be drafted for the upgrade process.
802void CrxUpdateService::OnParseUpdateManifestSucceeded(
803 const UpdateManifest::Results& results) {
804 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a1f8c162012-09-27 22:32:21805 size_t update_pending = 0;
[email protected]e8f96ff2011-08-03 05:07:33806 std::vector<UpdateManifest::Result>::const_iterator it;
807 for (it = results.list.begin(); it != results.list.end(); ++it) {
808 CrxUpdateItem* crx = FindUpdateItemById(it->extension_id);
809 if (!crx)
810 continue;
811
812 if (crx->status != CrxUpdateItem::kChecking)
813 continue; // Not updating this component now.
814
[email protected]360b8bb2011-09-01 21:48:06815 config_->OnEvent(Configurator::kManifestCheck, CrxIdtoUMAId(crx->id));
816
[email protected]e8f96ff2011-08-03 05:07:33817 if (it->version.empty()) {
[email protected]cf442612011-08-09 20:20:12818 // No version means no update available.
[email protected]e8f96ff2011-08-03 05:07:33819 crx->status = CrxUpdateItem::kNoUpdate;
[email protected]cf442612011-08-09 20:20:12820 continue;
[email protected]e8f96ff2011-08-03 05:07:33821 }
822 if (!IsVersionNewer(crx->component.version, it->version)) {
[email protected]cf442612011-08-09 20:20:12823 // Our component is up to date.
[email protected]e8f96ff2011-08-03 05:07:33824 crx->status = CrxUpdateItem::kUpToDate;
[email protected]cf442612011-08-09 20:20:12825 continue;
[email protected]e8f96ff2011-08-03 05:07:33826 }
827 if (!it->browser_min_version.empty()) {
[email protected]cf442612011-08-09 20:20:12828 if (IsVersionNewer(chrome_version_, it->browser_min_version)) {
829 // Does not apply for this chrome version.
830 crx->status = CrxUpdateItem::kNoUpdate;
831 continue;
832 }
[email protected]e8f96ff2011-08-03 05:07:33833 }
834 // All test passed. Queue an upgrade for this component and fire the
835 // notifications.
836 crx->crx_url = it->crx_url;
[email protected]e3e696d32013-06-21 20:41:36837 crx->size = it->size;
838 crx->diff_crx_url = it->diff_crx_url;
839 crx->diff_size = it->diff_size;
[email protected]e8f96ff2011-08-03 05:07:33840 crx->status = CrxUpdateItem::kCanUpdate;
[email protected]07f93af12011-08-17 20:57:22841 crx->next_version = Version(it->version);
[email protected]e3e696d32013-06-21 20:41:36842 crx->next_fp = it->package_fingerprint;
[email protected]e8f96ff2011-08-03 05:07:33843 ++update_pending;
844
[email protected]ad50def52011-10-19 23:17:07845 content::NotificationService::current()->Notify(
[email protected]e8f96ff2011-08-03 05:07:33846 chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND,
[email protected]6c2381d2011-10-19 02:52:53847 content::Source<std::string>(&crx->id),
[email protected]ad50def52011-10-19 23:17:07848 content::NotificationService::NoDetails());
[email protected]e8f96ff2011-08-03 05:07:33849 }
[email protected]cf442612011-08-09 20:20:12850
851 // All the components that are not mentioned in the manifest we
852 // consider them up to date.
853 ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kUpToDate);
854
[email protected]e8f96ff2011-08-03 05:07:33855 // If there are updates pending we do a short wait.
[email protected]a1f8c162012-09-27 22:32:21856 ScheduleNextRun(update_pending > 0);
[email protected]e8f96ff2011-08-03 05:07:33857}
858
859void CrxUpdateService::OnParseUpdateManifestFailed(
860 const std::string& error_message) {
861 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
862 size_t count = ChangeItemStatus(CrxUpdateItem::kChecking,
863 CrxUpdateItem::kNoUpdate);
[email protected]360b8bb2011-09-01 21:48:06864 config_->OnEvent(Configurator::kManifestError, static_cast<int>(count));
[email protected]e8f96ff2011-08-03 05:07:33865 DCHECK_GT(count, 0ul);
866 ScheduleNextRun(false);
867}
868
869// Called when the CRX package has been downloaded to a temporary location.
870// Here we fire the notifications and schedule the component-specific installer
871// to be called in the file thread.
[email protected]10c2d692012-05-11 05:32:23872void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
[email protected]e8f96ff2011-08-03 05:07:33873 CRXContext* context) {
874 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]1dd4060e2013-03-13 13:15:13875 int error_code = net::OK;
[email protected]e8f96ff2011-08-03 05:07:33876
[email protected]e3e696d32013-06-21 20:41:36877 CrxUpdateItem* crx = FindUpdateItemById(context->id);
878 DCHECK(crx->status == CrxUpdateItem::kDownloadingDiff ||
879 crx->status == CrxUpdateItem::kDownloading);
880
[email protected]e8f96ff2011-08-03 05:07:33881 if (source->FileErrorOccurred(&error_code) || !FetchSuccess(*source)) {
[email protected]e3e696d32013-06-21 20:41:36882 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
[email protected]e630ba62013-06-22 15:22:34883 crx->diff_update_failed = true;
[email protected]e3e696d32013-06-21 20:41:36884 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
885 CrxUpdateItem::kCanUpdate);
886 DCHECK_EQ(count, 1ul);
887 ScheduleNextRun(true);
888 return;
889 }
[email protected]e8f96ff2011-08-03 05:07:33890 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
891 CrxUpdateItem::kNoUpdate);
892 DCHECK_EQ(count, 1ul);
[email protected]360b8bb2011-09-01 21:48:06893 config_->OnEvent(Configurator::kNetworkError, CrxIdtoUMAId(context->id));
[email protected]cf442612011-08-09 20:20:12894 url_fetcher_.reset();
[email protected]e3e696d32013-06-21 20:41:36895
[email protected]e8f96ff2011-08-03 05:07:33896 ScheduleNextRun(false);
897 } else {
[email protected]650b2d52013-02-10 03:41:45898 base::FilePath temp_crx_path;
[email protected]e8f96ff2011-08-03 05:07:33899 CHECK(source->GetResponseAsFilePath(true, &temp_crx_path));
[email protected]e3e696d32013-06-21 20:41:36900
901 size_t count = 0;
902 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
903 count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
904 CrxUpdateItem::kUpdatingDiff);
905 } else {
906 count = ChangeItemStatus(CrxUpdateItem::kDownloading,
907 CrxUpdateItem::kUpdating);
908 }
[email protected]e8f96ff2011-08-03 05:07:33909 DCHECK_EQ(count, 1ul);
[email protected]e3e696d32013-06-21 20:41:36910
[email protected]cf442612011-08-09 20:20:12911 url_fetcher_.reset();
912
[email protected]ad50def52011-10-19 23:17:07913 content::NotificationService::current()->Notify(
[email protected]e8f96ff2011-08-03 05:07:33914 chrome::NOTIFICATION_COMPONENT_UPDATE_READY,
[email protected]6c2381d2011-10-19 02:52:53915 content::Source<std::string>(&context->id),
[email protected]ad50def52011-10-19 23:17:07916 content::NotificationService::NoDetails());
[email protected]e8f96ff2011-08-03 05:07:33917
[email protected]44da56e2011-11-21 19:59:14918 // Why unretained? See comment at top of file.
[email protected]73251e72012-03-04 02:10:33919 BrowserThread::PostDelayedTask(
920 BrowserThread::FILE,
921 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14922 base::Bind(&CrxUpdateService::Install,
923 base::Unretained(this),
924 context,
925 temp_crx_path),
[email protected]73251e72012-03-04 02:10:33926 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]e8f96ff2011-08-03 05:07:33927 }
[email protected]e8f96ff2011-08-03 05:07:33928}
929
930// Install consists of digital signature verification, unpacking and then
931// calling the component specific installer. All that is handled by the
932// |unpacker|. If there is an error this function is in charge of deleting
933// the files created.
934void CrxUpdateService::Install(const CRXContext* context,
[email protected]650b2d52013-02-10 03:41:45935 const base::FilePath& crx_path) {
[email protected]e8f96ff2011-08-03 05:07:33936 // This function owns the |crx_path| and the |context| object.
937 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]e3e696d32013-06-21 20:41:36938 ComponentUnpacker unpacker(context->pk_hash,
939 crx_path,
940 context->fingerprint,
941 component_patcher_.get(),
942 context->installer);
943 if (!file_util::Delete(crx_path, false))
[email protected]e8f96ff2011-08-03 05:07:33944 NOTREACHED() << crx_path.value();
[email protected]44da56e2011-11-21 19:59:14945 // Why unretained? See comment at top of file.
[email protected]73251e72012-03-04 02:10:33946 BrowserThread::PostDelayedTask(
947 BrowserThread::UI,
948 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14949 base::Bind(&CrxUpdateService::DoneInstalling, base::Unretained(this),
[email protected]e3e696d32013-06-21 20:41:36950 context->id, unpacker.error(), unpacker.extended_error()),
[email protected]73251e72012-03-04 02:10:33951 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]07f93af12011-08-17 20:57:22952 delete context;
[email protected]e8f96ff2011-08-03 05:07:33953}
954
955// Installation has been completed. Adjust the component status and
956// schedule the next check.
[email protected]07f93af12011-08-17 20:57:22957void CrxUpdateService::DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:36958 ComponentUnpacker::Error error,
959 int extra_code) {
[email protected]e8f96ff2011-08-03 05:07:33960 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]07f93af12011-08-17 20:57:22961
962 CrxUpdateItem* item = FindUpdateItemById(component_id);
[email protected]e3e696d32013-06-21 20:41:36963 if (item->status == CrxUpdateItem::kUpdatingDiff) {
964 if (error != ComponentUnpacker::kNone) {
965 item->diff_update_failed = true;
966 size_t count = ChangeItemStatus(CrxUpdateItem::kUpdatingDiff,
967 CrxUpdateItem::kCanUpdate);
968 DCHECK_EQ(count, 1ul);
969 ScheduleNextRun(true);
970 return;
971 }
972 }
973
[email protected]07f93af12011-08-17 20:57:22974 item->status = (error == ComponentUnpacker::kNone) ? CrxUpdateItem::kUpdated :
975 CrxUpdateItem::kNoUpdate;
[email protected]e3e696d32013-06-21 20:41:36976 if (item->status == CrxUpdateItem::kUpdated) {
[email protected]07f93af12011-08-17 20:57:22977 item->component.version = item->next_version;
[email protected]e3e696d32013-06-21 20:41:36978 item->component.fingerprint = item->next_fp;
979 }
[email protected]07f93af12011-08-17 20:57:22980
[email protected]360b8bb2011-09-01 21:48:06981 Configurator::Events event;
982 switch (error) {
983 case ComponentUnpacker::kNone:
984 event = Configurator::kComponentUpdated;
985 break;
986 case ComponentUnpacker::kInstallerError:
987 event = Configurator::kInstallerError;
988 break;
989 default:
990 event = Configurator::kUnpackError;
991 break;
992 }
993
994 config_->OnEvent(event, CrxIdtoUMAId(component_id));
[email protected]e8f96ff2011-08-03 05:07:33995 ScheduleNextRun(false);
996}
997
998// The component update factory. Using the component updater as a singleton
999// is the job of the browser process.
1000ComponentUpdateService* ComponentUpdateServiceFactory(
1001 ComponentUpdateService::Configurator* config) {
1002 DCHECK(config);
1003 return new CrxUpdateService(config);
1004}