blob: 532a375e315c2314bbd2d5d320ddb9312df9b6d5 [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
109// 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
[email protected]2e919ddd2013-08-21 05:05:17227std::string GetCrxComponentID(const CrxComponent& component) {
228 return HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
229 component.pk_hash.size()/2)));
230}
231
232CrxComponentInfo::CrxComponentInfo() {
233}
234
235CrxComponentInfo::~CrxComponentInfo() {
236}
237
[email protected]e8f96ff2011-08-03 05:07:33238//////////////////////////////////////////////////////////////////////////////
239// The one and only implementation of the ComponentUpdateService interface. In
240// charge of running the show. The main method is ProcessPendingItems() which
[email protected]50b01392012-09-01 03:33:13241// is called periodically to do the upgrades/installs or the update checks.
[email protected]e8f96ff2011-08-03 05:07:33242// An important consideration here is to be as "low impact" as we can to the
243// rest of the browser, so even if we have many components registered and
[email protected]f1050432012-02-15 01:35:46244// eligible for update, we only do one thing at a time with pauses in between
[email protected]e8f96ff2011-08-03 05:07:33245// the tasks. Also when we do network requests there is only one |url_fetcher_|
[email protected]e3e696d32013-06-21 20:41:36246// in flight at a time.
[email protected]e8f96ff2011-08-03 05:07:33247// There are no locks in this code, the main structure |work_items_| is mutated
248// only from the UI thread. The unpack and installation is done in the file
249// thread and the network requests are done in the IO thread and in the file
250// thread.
251class CrxUpdateService : public ComponentUpdateService {
252 public:
253 explicit CrxUpdateService(ComponentUpdateService::Configurator* config);
254
255 virtual ~CrxUpdateService();
256
257 // Overrides for ComponentUpdateService.
258 virtual Status Start() OVERRIDE;
259 virtual Status Stop() OVERRIDE;
260 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE;
[email protected]2e919ddd2013-08-21 05:05:17261 virtual Status CheckForUpdateSoon(const std::string& component_id) OVERRIDE;
262 virtual void GetComponents(
263 std::vector<CrxComponentInfo>* components) OVERRIDE;
[email protected]e8f96ff2011-08-03 05:07:33264
265 // The only purpose of this class is to forward the
[email protected]c4f883a2012-02-03 17:02:07266 // UtilityProcessHostClient callbacks so CrxUpdateService does
[email protected]e8f96ff2011-08-03 05:07:33267 // not have to derive from it because that is refcounted.
[email protected]c4f883a2012-02-03 17:02:07268 class ManifestParserBridge : public UtilityProcessHostClient {
[email protected]e8f96ff2011-08-03 05:07:33269 public:
270 explicit ManifestParserBridge(CrxUpdateService* service)
271 : service_(service) {}
272
273 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
274 bool handled = true;
275 IPC_BEGIN_MESSAGE_MAP(ManifestParserBridge, message)
[email protected]2ccf45c2011-08-19 23:35:50276 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseUpdateManifest_Succeeded,
[email protected]e8f96ff2011-08-03 05:07:33277 OnParseUpdateManifestSucceeded)
[email protected]2ccf45c2011-08-19 23:35:50278 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseUpdateManifest_Failed,
[email protected]e8f96ff2011-08-03 05:07:33279 OnParseUpdateManifestFailed)
280 IPC_MESSAGE_UNHANDLED(handled = false)
281 IPC_END_MESSAGE_MAP()
282 return handled;
283 }
284
285 private:
[email protected]a3988cc2012-04-27 05:07:18286 virtual ~ManifestParserBridge() {}
287
[email protected]f1050432012-02-15 01:35:46288 // Omaha update response XML was successfully parsed.
[email protected]e8f96ff2011-08-03 05:07:33289 void OnParseUpdateManifestSucceeded(const UpdateManifest::Results& r) {
290 service_->OnParseUpdateManifestSucceeded(r);
291 }
292 // Omaha update response XML could not be parsed.
293 void OnParseUpdateManifestFailed(const std::string& e) {
294 service_->OnParseUpdateManifestFailed(e);
295 }
296
297 CrxUpdateService* service_;
298 DISALLOW_COPY_AND_ASSIGN(ManifestParserBridge);
299 };
300
301 // Context for a update check url request. See DelegateWithContext above.
302 struct UpdateContext {
303 base::Time start;
304 UpdateContext() : start(base::Time::Now()) {}
305 };
306
307 // Context for a crx download url request. See DelegateWithContext above.
308 struct CRXContext {
309 ComponentInstaller* installer;
310 std::vector<uint8> pk_hash;
311 std::string id;
[email protected]e3e696d32013-06-21 20:41:36312 std::string fingerprint;
[email protected]e8f96ff2011-08-03 05:07:33313 CRXContext() : installer(NULL) {}
314 };
315
[email protected]10c2d692012-05-11 05:32:23316 void OnURLFetchComplete(const net::URLFetcher* source,
[email protected]7cc6e5632011-10-25 17:56:12317 UpdateContext* context);
[email protected]e8f96ff2011-08-03 05:07:33318
[email protected]10c2d692012-05-11 05:32:23319 void OnURLFetchComplete(const net::URLFetcher* source,
[email protected]7cc6e5632011-10-25 17:56:12320 CRXContext* context);
[email protected]e8f96ff2011-08-03 05:07:33321
322 private:
[email protected]7b0529242013-07-20 05:45:46323 enum ErrorCategory {
324 kErrorNone = 0,
325 kNetworkError,
326 kUnpackError,
327 kInstallError,
328 };
329
[email protected]32a6c8382013-08-20 00:29:20330 enum StepDelayInterval {
331 kStepDelayShort = 0,
332 kStepDelayMedium,
333 kStepDelayLong,
334 };
335
[email protected]e8f96ff2011-08-03 05:07:33336 // See ManifestParserBridge.
[email protected]7b0529242013-07-20 05:45:46337 void OnParseUpdateManifestSucceeded(const UpdateManifest::Results& results);
[email protected]e8f96ff2011-08-03 05:07:33338
339 // See ManifestParserBridge.
[email protected]e3e696d32013-06-21 20:41:36340 void OnParseUpdateManifestFailed(const std::string& error_message);
[email protected]e8f96ff2011-08-03 05:07:33341
342 bool AddItemToUpdateCheck(CrxUpdateItem* item, std::string* query);
343
344 void ProcessPendingItems();
345
[email protected]32a6c8382013-08-20 00:29:20346 void ScheduleNextRun(StepDelayInterval step_delay);
[email protected]e8f96ff2011-08-03 05:07:33347
348 void ParseManifest(const std::string& xml);
349
[email protected]650b2d52013-02-10 03:41:45350 void Install(const CRXContext* context, const base::FilePath& crx_path);
[email protected]e8f96ff2011-08-03 05:07:33351
[email protected]07f93af12011-08-17 20:57:22352 void DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:36353 ComponentUnpacker::Error error,
354 int extended_error);
[email protected]e8f96ff2011-08-03 05:07:33355
356 size_t ChangeItemStatus(CrxUpdateItem::Status from,
357 CrxUpdateItem::Status to);
358
359 CrxUpdateItem* FindUpdateItemById(const std::string& id);
360
[email protected]85e61d52013-08-01 22:23:42361 void NotifyComponentObservers(ComponentObserver::Events event,
362 int extra) const;
363
[email protected]e3e696d32013-06-21 20:41:36364 scoped_ptr<ComponentUpdateService::Configurator> config_;
365
366 scoped_ptr<ComponentPatcher> component_patcher_;
[email protected]e8f96ff2011-08-03 05:07:33367
[email protected]d3ec669b2012-05-23 07:12:14368 scoped_ptr<net::URLFetcher> url_fetcher_;
[email protected]e8f96ff2011-08-03 05:07:33369
[email protected]7b0529242013-07-20 05:45:46370 scoped_ptr<component_updater::PingManager> ping_manager_;
371
[email protected]86550a42013-06-21 15:20:49372 // A collection of every work item.
[email protected]e3e696d32013-06-21 20:41:36373 typedef std::vector<CrxUpdateItem*> UpdateItems;
[email protected]e8f96ff2011-08-03 05:07:33374 UpdateItems work_items_;
375
[email protected]ccb4feef2013-02-14 06:16:47376 // A particular set of items from work_items_, which should be checked ASAP.
377 std::set<CrxUpdateItem*> requested_work_items_;
378
[email protected]e8f96ff2011-08-03 05:07:33379 base::OneShotTimer<CrxUpdateService> timer_;
380
[email protected]e3e696d32013-06-21 20:41:36381 const Version chrome_version_;
[email protected]e8f96ff2011-08-03 05:07:33382
383 bool running_;
384
385 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
386};
387
[email protected]e8f96ff2011-08-03 05:07:33388//////////////////////////////////////////////////////////////////////////////
389
[email protected]e3e696d32013-06-21 20:41:36390CrxUpdateService::CrxUpdateService(ComponentUpdateService::Configurator* config)
[email protected]e8f96ff2011-08-03 05:07:33391 : config_(config),
[email protected]e3e696d32013-06-21 20:41:36392 component_patcher_(config->CreateComponentPatcher()),
[email protected]7b0529242013-07-20 05:45:46393 ping_manager_(new component_updater::PingManager(
394 config->PingUrl(),
395 config->RequestContext())),
[email protected]e8f96ff2011-08-03 05:07:33396 chrome_version_(chrome::VersionInfo().Version()),
397 running_(false) {
[email protected]1ea21ad2013-09-02 04:20:39398}
[email protected]e8f96ff2011-08-03 05:07:33399
400CrxUpdateService::~CrxUpdateService() {
401 // Because we are a singleton, at this point only the UI thread should be
402 // alive, this simplifies the management of the work that could be in
403 // flight in other threads.
404 Stop();
405 STLDeleteElements(&work_items_);
[email protected]1ea21ad2013-09-02 04:20:39406}
[email protected]e8f96ff2011-08-03 05:07:33407
408ComponentUpdateService::Status CrxUpdateService::Start() {
409 // Note that RegisterComponent will call Start() when the first
410 // component is registered, so it can be called twice. This way
411 // we avoid scheduling the timer if there is no work to do.
412 running_ = true;
413 if (work_items_.empty())
414 return kOk;
415
[email protected]85e61d52013-08-01 22:23:42416 NotifyComponentObservers(ComponentObserver::COMPONENT_UPDATER_STARTED, 0);
417
[email protected]d323a172011-09-02 18:23:02418 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->InitialDelay()),
[email protected]e8f96ff2011-08-03 05:07:33419 this, &CrxUpdateService::ProcessPendingItems);
420 return kOk;
421}
422
423// Stop the main check + update loop. In flight operations will be
424// completed.
425ComponentUpdateService::Status CrxUpdateService::Stop() {
426 running_ = false;
427 timer_.Stop();
428 return kOk;
429}
430
[email protected]ccb4feef2013-02-14 06:16:47431// This function sets the timer which will call ProcessPendingItems() or
432// ProcessRequestedItem() if there is an important requested item. There
[email protected]32a6c8382013-08-20 00:29:20433// are three kinds of waits:
434// - a short delay, when there is immediate work to be done.
435// - a medium delay, when there are updates to be applied within the current
436// update cycle, or there are components that are still unchecked.
437// - a long delay when a full check/update cycle has completed for all
438// components.
439void CrxUpdateService::ScheduleNextRun(StepDelayInterval step_delay) {
[email protected]e8f96ff2011-08-03 05:07:33440 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cf442612011-08-09 20:20:12441 DCHECK(url_fetcher_.get() == NULL);
[email protected]e8f96ff2011-08-03 05:07:33442 CHECK(!timer_.IsRunning());
443 // It could be the case that Stop() had been called while a url request
444 // or unpacking was in flight, if so we arrive here but |running_| is
445 // false. In that case do not loop again.
446 if (!running_)
447 return;
448
[email protected]ccb4feef2013-02-14 06:16:47449 // Keep the delay short if in the middle of an update (step_delay),
450 // or there are new requested_work_items_ that have not been processed yet.
[email protected]32a6c8382013-08-20 00:29:20451 int64 delay_seconds = 0;
452 if (requested_work_items_.empty()) {
453 switch (step_delay) {
454 case kStepDelayShort:
455 delay_seconds = config_->StepDelay();
456 break;
457 case kStepDelayMedium:
458 delay_seconds = config_->StepDelayMedium();
459 break;
460 case kStepDelayLong:
461 delay_seconds = config_->NextCheckDelay();
462 break;
463 }
464 } else {
465 delay_seconds = config_->StepDelay();
466 }
[email protected]cf442612011-08-09 20:20:12467
[email protected]32a6c8382013-08-20 00:29:20468 if (step_delay != kStepDelayShort) {
[email protected]85e61d52013-08-01 22:23:42469 NotifyComponentObservers(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0);
470
[email protected]e8f96ff2011-08-03 05:07:33471 // Zero is only used for unit tests.
[email protected]32a6c8382013-08-20 00:29:20472 if (0 == delay_seconds)
[email protected]e8f96ff2011-08-03 05:07:33473 return;
474 }
475
[email protected]32a6c8382013-08-20 00:29:20476 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay_seconds),
[email protected]e8f96ff2011-08-03 05:07:33477 this, &CrxUpdateService::ProcessPendingItems);
478}
479
480// Given a extension-like component id, find the associated component.
481CrxUpdateItem* CrxUpdateService::FindUpdateItemById(const std::string& id) {
482 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
483 CrxUpdateItem::FindById finder(id);
484 UpdateItems::iterator it = std::find_if(work_items_.begin(),
485 work_items_.end(),
486 finder);
487 if (it == work_items_.end())
488 return NULL;
489 return (*it);
490}
491
492// Changes all the components in |work_items_| that have |from| status to
[email protected]e3e696d32013-06-21 20:41:36493// |to| status and returns how many have been changed.
[email protected]e8f96ff2011-08-03 05:07:33494size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from,
495 CrxUpdateItem::Status to) {
496 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
497 size_t count = 0;
498 for (UpdateItems::iterator it = work_items_.begin();
499 it != work_items_.end(); ++it) {
500 CrxUpdateItem* item = *it;
501 if (item->status != from)
502 continue;
503 item->status = to;
504 ++count;
505 }
506 return count;
507}
508
509// Adds a component to be checked for upgrades. If the component exists it
510// it will be replaced and the return code is kReplaced.
511//
512// TODO(cpu): Evaluate if we want to support un-registration.
513ComponentUpdateService::Status CrxUpdateService::RegisterComponent(
514 const CrxComponent& component) {
515 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
516 if (component.pk_hash.empty() ||
517 !component.version.IsValid() ||
518 !component.installer)
519 return kError;
520
521 std::string id =
522 HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
523 component.pk_hash.size()/2)));
524 CrxUpdateItem* uit;
525 uit = FindUpdateItemById(id);
526 if (uit) {
527 uit->component = component;
528 return kReplaced;
529 }
530
531 uit = new CrxUpdateItem;
532 uit->id.swap(id);
533 uit->component = component;
[email protected]e3e696d32013-06-21 20:41:36534
[email protected]e8f96ff2011-08-03 05:07:33535 work_items_.push_back(uit);
536 // If this is the first component registered we call Start to
537 // schedule the first timer.
538 if (running_ && (work_items_.size() == 1))
539 Start();
540
541 return kOk;
542}
543
544// Sets a component to be checked for updates.
[email protected]69b9f5de2013-06-24 20:59:46545// The component to add is |item| and the |query| string is modified with the
546// required omaha compatible query. Returns false when the query string is
547// longer than specified by UrlSizeLimit().
548// If the item is currently on the requested_work_items_ list, the update check
549// is considered to be "on-demand": the server may honor on-demand checks by
550// serving updates at 100% rather than a gated fraction.
[email protected]e8f96ff2011-08-03 05:07:33551bool CrxUpdateService::AddItemToUpdateCheck(CrxUpdateItem* item,
552 std::string* query) {
553 if (!AddQueryString(item->id,
554 item->component.version.GetString(),
[email protected]e3e696d32013-06-21 20:41:36555 item->component.fingerprint,
[email protected]69b9f5de2013-06-24 20:59:46556 requested_work_items_.count(item) > 0, // is_ondemand
557 config_->UrlSizeLimit(),
558 query))
[email protected]e8f96ff2011-08-03 05:07:33559 return false;
[email protected]e3e696d32013-06-21 20:41:36560
[email protected]e8f96ff2011-08-03 05:07:33561 item->status = CrxUpdateItem::kChecking;
562 item->last_check = base::Time::Now();
[email protected]e3e696d32013-06-21 20:41:36563 item->previous_version = item->component.version;
564 item->next_version = Version();
565 item->previous_fp = item->component.fingerprint;
566 item->next_fp.clear();
567 item->diff_update_failed = false;
[email protected]7b0529242013-07-20 05:45:46568 item->error_category = 0;
569 item->error_code = 0;
570 item->extra_code1 = 0;
571 item->diff_error_category = 0;
572 item->diff_error_code = 0;
573 item->diff_extra_code1 = 0;
[email protected]e8f96ff2011-08-03 05:07:33574 return true;
575}
576
[email protected]ccb4feef2013-02-14 06:16:47577// Start the process of checking for an update, for a particular component
578// that was previously registered.
[email protected]2e919ddd2013-08-21 05:05:17579// |component_id| is a value returned from GetCrxComponentID().
[email protected]ccb4feef2013-02-14 06:16:47580ComponentUpdateService::Status CrxUpdateService::CheckForUpdateSoon(
[email protected]2e919ddd2013-08-21 05:05:17581 const std::string& component_id) {
[email protected]ccb4feef2013-02-14 06:16:47582 CrxUpdateItem* uit;
[email protected]2e919ddd2013-08-21 05:05:17583 uit = FindUpdateItemById(component_id);
[email protected]ccb4feef2013-02-14 06:16:47584 if (!uit)
585 return kError;
586
587 // Check if the request is too soon.
588 base::TimeDelta delta = base::Time::Now() - uit->last_check;
[email protected]e3e696d32013-06-21 20:41:36589 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
[email protected]ccb4feef2013-02-14 06:16:47590 return kError;
[email protected]ccb4feef2013-02-14 06:16:47591
592 switch (uit->status) {
593 // If the item is already in the process of being updated, there is
594 // no point in this call, so return kInProgress.
595 case CrxUpdateItem::kChecking:
596 case CrxUpdateItem::kCanUpdate:
[email protected]e3e696d32013-06-21 20:41:36597 case CrxUpdateItem::kDownloadingDiff:
[email protected]ccb4feef2013-02-14 06:16:47598 case CrxUpdateItem::kDownloading:
[email protected]e3e696d32013-06-21 20:41:36599 case CrxUpdateItem::kUpdatingDiff:
[email protected]ccb4feef2013-02-14 06:16:47600 case CrxUpdateItem::kUpdating:
601 return kInProgress;
602 // Otherwise the item was already checked a while back (or it is new),
603 // set its status to kNew to give it a slightly higher priority.
604 case CrxUpdateItem::kNew:
605 case CrxUpdateItem::kUpdated:
606 case CrxUpdateItem::kUpToDate:
607 case CrxUpdateItem::kNoUpdate:
608 uit->status = CrxUpdateItem::kNew;
609 requested_work_items_.insert(uit);
610 break;
611 case CrxUpdateItem::kLastStatus:
612 NOTREACHED() << uit->status;
613 }
614
615 // In case the current delay is long, set the timer to a shorter value
616 // to get the ball rolling.
617 if (timer_.IsRunning()) {
618 timer_.Stop();
619 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->StepDelay()),
620 this, &CrxUpdateService::ProcessPendingItems);
621 }
622
623 return kOk;
624}
625
[email protected]2e919ddd2013-08-21 05:05:17626void CrxUpdateService::GetComponents(
627 std::vector<CrxComponentInfo>* components) {
628 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
629 for (UpdateItems::const_iterator it = work_items_.begin();
630 it != work_items_.end(); ++it) {
631 const CrxUpdateItem* item = *it;
632 CrxComponentInfo info;
633 info.id = GetCrxComponentID(item->component);
634 info.version = item->component.version.GetString();
635 info.name = item->component.name;
636 components->push_back(info);
637 }
638}
639
[email protected]e8f96ff2011-08-03 05:07:33640// Here is where the work gets scheduled. Given that our |work_items_| list
641// is expected to be ten or less items, we simply loop several times.
642void CrxUpdateService::ProcessPendingItems() {
643 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
644 // First check for ready upgrades and do one. The first
645 // step is to fetch the crx package.
646 for (UpdateItems::const_iterator it = work_items_.begin();
647 it != work_items_.end(); ++it) {
648 CrxUpdateItem* item = *it;
649 if (item->status != CrxUpdateItem::kCanUpdate)
650 continue;
651 // Found component to update, start the process.
[email protected]e8f96ff2011-08-03 05:07:33652 CRXContext* context = new CRXContext;
653 context->pk_hash = item->component.pk_hash;
654 context->id = item->id;
655 context->installer = item->component.installer;
[email protected]e3e696d32013-06-21 20:41:36656 context->fingerprint = item->next_fp;
657 GURL package_url;
658 if (CanTryDiffUpdate(item, *config_)) {
659 package_url = item->diff_crx_url;
660 item->status = CrxUpdateItem::kDownloadingDiff;
661 } else {
662 package_url = item->crx_url;
663 item->status = CrxUpdateItem::kDownloading;
664 }
[email protected]3dc1bc42012-06-19 08:20:53665 url_fetcher_.reset(net::URLFetcher::Create(
[email protected]e3e696d32013-06-21 20:41:36666 0, package_url, net::URLFetcher::GET,
[email protected]e8f96ff2011-08-03 05:07:33667 MakeContextDelegate(this, context)));
668 StartFetch(url_fetcher_.get(), config_->RequestContext(), true);
669 return;
670 }
671
[email protected]d63306d2013-06-29 13:56:02672 std::string query;
673 // If no pending upgrades, we check if there are new components we have not
674 // checked against the server. We can batch some in a single url request.
675 for (UpdateItems::const_iterator it = work_items_.begin();
676 it != work_items_.end(); ++it) {
677 CrxUpdateItem* item = *it;
678 if (item->status != CrxUpdateItem::kNew)
[email protected]dc06f0b2013-01-23 20:03:16679 continue;
[email protected]d63306d2013-06-29 13:56:02680 if (!AddItemToUpdateCheck(item, &query))
681 break;
682 // Requested work items may speed up the update cycle up until
683 // the point that we start an update check. I.e., transition
684 // from kNew -> kChecking. Since the service doesn't guarantee that
685 // the requested items make it any further than kChecking,
686 // forget them now.
687 requested_work_items_.erase(item);
688 }
[email protected]dc06f0b2013-01-23 20:03:16689
[email protected]d63306d2013-06-29 13:56:02690 // Next we can go back to components we already checked, here
691 // we can also batch them in a single url request, as long as
692 // we have not checked them recently.
693 const base::TimeDelta min_delta_time =
694 base::TimeDelta::FromSeconds(config_->MinimumReCheckWait());
695
696 for (UpdateItems::const_iterator it = work_items_.begin();
697 it != work_items_.end(); ++it) {
698 CrxUpdateItem* item = *it;
699 if ((item->status != CrxUpdateItem::kNoUpdate) &&
700 (item->status != CrxUpdateItem::kUpToDate))
701 continue;
702 base::TimeDelta delta = base::Time::Now() - item->last_check;
703 if (delta < min_delta_time)
704 continue;
705 if (!AddItemToUpdateCheck(item, &query))
706 break;
707 }
708
709 // Finally, we check components that we already updated as long as
710 // we have not checked them recently.
711 for (UpdateItems::const_iterator it = work_items_.begin();
712 it != work_items_.end(); ++it) {
713 CrxUpdateItem* item = *it;
714 if (item->status != CrxUpdateItem::kUpdated)
715 continue;
716 base::TimeDelta delta = base::Time::Now() - item->last_check;
717 if (delta < min_delta_time)
718 continue;
719 if (!AddItemToUpdateCheck(item, &query))
720 break;
721 }
722
723 if (!query.empty()) {
[email protected]dc06f0b2013-01-23 20:03:16724 // We got components to check. Start the url request and exit.
725 const std::string full_query =
[email protected]d63306d2013-06-29 13:56:02726 MakeFinalQuery(config_->UpdateUrl().spec(),
[email protected]dc06f0b2013-01-23 20:03:16727 query,
728 config_->ExtraRequestParams());
729
730 url_fetcher_.reset(net::URLFetcher::Create(
731 0, GURL(full_query), net::URLFetcher::GET,
732 MakeContextDelegate(this, new UpdateContext())));
733 StartFetch(url_fetcher_.get(), config_->RequestContext(), false);
[email protected]e8f96ff2011-08-03 05:07:33734 return;
735 }
736
[email protected]dc06f0b2013-01-23 20:03:16737 // No components to update. Next check after the long sleep.
[email protected]32a6c8382013-08-20 00:29:20738 ScheduleNextRun(kStepDelayLong);
[email protected]e8f96ff2011-08-03 05:07:33739}
740
[email protected]ccb4feef2013-02-14 06:16:47741// Called when we got a response from the update server. It consists of an xml
[email protected]e8f96ff2011-08-03 05:07:33742// document following the omaha update scheme.
[email protected]10c2d692012-05-11 05:32:23743void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
[email protected]07f93af12011-08-17 20:57:22744 UpdateContext* context) {
[email protected]e8f96ff2011-08-03 05:07:33745 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
746 if (FetchSuccess(*source)) {
747 std::string xml;
748 source->GetResponseAsString(&xml);
[email protected]cf442612011-08-09 20:20:12749 url_fetcher_.reset();
[email protected]e8f96ff2011-08-03 05:07:33750 ParseManifest(xml);
751 } else {
[email protected]cf442612011-08-09 20:20:12752 url_fetcher_.reset();
[email protected]e8f96ff2011-08-03 05:07:33753 CrxUpdateService::OnParseUpdateManifestFailed("network error");
754 }
[email protected]07f93af12011-08-17 20:57:22755 delete context;
[email protected]e8f96ff2011-08-03 05:07:33756}
757
758// Parsing the manifest is either done right now for tests or in a sandboxed
759// process for the production environment. This mitigates the case where an
760// attacker was able to feed us a malicious xml string.
761void CrxUpdateService::ParseManifest(const std::string& xml) {
762 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
763 if (config_->InProcess()) {
764 UpdateManifest manifest;
[email protected]e3e696d32013-06-21 20:41:36765 if (!manifest.Parse(xml))
[email protected]e8f96ff2011-08-03 05:07:33766 CrxUpdateService::OnParseUpdateManifestFailed(manifest.errors());
[email protected]e3e696d32013-06-21 20:41:36767 else
[email protected]e8f96ff2011-08-03 05:07:33768 CrxUpdateService::OnParseUpdateManifestSucceeded(manifest.results());
[email protected]e8f96ff2011-08-03 05:07:33769 } else {
[email protected]cadac622013-06-11 16:46:36770 UtilityProcessHost* host =
771 UtilityProcessHost::Create(new ManifestParserBridge(this),
772 base::MessageLoopProxy::current().get());
[email protected]c4f883a2012-02-03 17:02:07773 host->EnableZygote();
[email protected]2ccf45c2011-08-19 23:35:50774 host->Send(new ChromeUtilityMsg_ParseUpdateManifest(xml));
[email protected]e8f96ff2011-08-03 05:07:33775 }
776}
777
778// A valid Omaha update check has arrived, from only the list of components that
779// we are currently upgrading we check for a match in which the server side
780// version is newer, if so we queue them for an upgrade. The next time we call
781// ProcessPendingItems() one of them will be drafted for the upgrade process.
782void CrxUpdateService::OnParseUpdateManifestSucceeded(
783 const UpdateManifest::Results& results) {
784 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a1f8c162012-09-27 22:32:21785 size_t update_pending = 0;
[email protected]e8f96ff2011-08-03 05:07:33786 std::vector<UpdateManifest::Result>::const_iterator it;
787 for (it = results.list.begin(); it != results.list.end(); ++it) {
788 CrxUpdateItem* crx = FindUpdateItemById(it->extension_id);
789 if (!crx)
790 continue;
791
792 if (crx->status != CrxUpdateItem::kChecking)
793 continue; // Not updating this component now.
794
795 if (it->version.empty()) {
[email protected]cf442612011-08-09 20:20:12796 // No version means no update available.
[email protected]e8f96ff2011-08-03 05:07:33797 crx->status = CrxUpdateItem::kNoUpdate;
[email protected]cf442612011-08-09 20:20:12798 continue;
[email protected]e8f96ff2011-08-03 05:07:33799 }
800 if (!IsVersionNewer(crx->component.version, it->version)) {
[email protected]cf442612011-08-09 20:20:12801 // Our component is up to date.
[email protected]e8f96ff2011-08-03 05:07:33802 crx->status = CrxUpdateItem::kUpToDate;
[email protected]cf442612011-08-09 20:20:12803 continue;
[email protected]e8f96ff2011-08-03 05:07:33804 }
805 if (!it->browser_min_version.empty()) {
[email protected]cf442612011-08-09 20:20:12806 if (IsVersionNewer(chrome_version_, it->browser_min_version)) {
807 // Does not apply for this chrome version.
808 crx->status = CrxUpdateItem::kNoUpdate;
809 continue;
810 }
[email protected]e8f96ff2011-08-03 05:07:33811 }
812 // All test passed. Queue an upgrade for this component and fire the
813 // notifications.
814 crx->crx_url = it->crx_url;
[email protected]e3e696d32013-06-21 20:41:36815 crx->diff_crx_url = it->diff_crx_url;
[email protected]e8f96ff2011-08-03 05:07:33816 crx->status = CrxUpdateItem::kCanUpdate;
[email protected]07f93af12011-08-17 20:57:22817 crx->next_version = Version(it->version);
[email protected]e3e696d32013-06-21 20:41:36818 crx->next_fp = it->package_fingerprint;
[email protected]e8f96ff2011-08-03 05:07:33819 ++update_pending;
820
[email protected]85e61d52013-08-01 22:23:42821 if (crx->component.observer) {
822 crx->component.observer->OnEvent(
823 ComponentObserver::COMPONENT_UPDATE_FOUND, 0);
824 }
[email protected]e8f96ff2011-08-03 05:07:33825 }
[email protected]cf442612011-08-09 20:20:12826
827 // All the components that are not mentioned in the manifest we
828 // consider them up to date.
829 ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kUpToDate);
830
[email protected]32a6c8382013-08-20 00:29:20831 // If there are updates pending we do a short wait, otherwise we take
832 // a longer delay until we check the components again.
833 ScheduleNextRun(update_pending > 0 ? kStepDelayShort : kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33834}
835
836void CrxUpdateService::OnParseUpdateManifestFailed(
837 const std::string& error_message) {
838 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
839 size_t count = ChangeItemStatus(CrxUpdateItem::kChecking,
840 CrxUpdateItem::kNoUpdate);
841 DCHECK_GT(count, 0ul);
[email protected]32a6c8382013-08-20 00:29:20842 ScheduleNextRun(kStepDelayLong);
[email protected]e8f96ff2011-08-03 05:07:33843}
844
845// Called when the CRX package has been downloaded to a temporary location.
846// Here we fire the notifications and schedule the component-specific installer
847// to be called in the file thread.
[email protected]10c2d692012-05-11 05:32:23848void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
[email protected]e8f96ff2011-08-03 05:07:33849 CRXContext* context) {
850 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]64f39fa12013-09-03 21:49:37851
852 scoped_ptr<CRXContext> crx_context(context);
[email protected]1dd4060e2013-03-13 13:15:13853 int error_code = net::OK;
[email protected]e8f96ff2011-08-03 05:07:33854
[email protected]64f39fa12013-09-03 21:49:37855 CrxUpdateItem* crx = FindUpdateItemById(crx_context->id);
[email protected]e3e696d32013-06-21 20:41:36856 DCHECK(crx->status == CrxUpdateItem::kDownloadingDiff ||
857 crx->status == CrxUpdateItem::kDownloading);
858
[email protected]e8f96ff2011-08-03 05:07:33859 if (source->FileErrorOccurred(&error_code) || !FetchSuccess(*source)) {
[email protected]e3e696d32013-06-21 20:41:36860 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
[email protected]7b0529242013-07-20 05:45:46861 crx->diff_error_category = kNetworkError;
862 crx->diff_error_code = GetFetchError(*source);
[email protected]e630ba62013-06-22 15:22:34863 crx->diff_update_failed = true;
[email protected]e3e696d32013-06-21 20:41:36864 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
865 CrxUpdateItem::kCanUpdate);
866 DCHECK_EQ(count, 1ul);
[email protected]7b0529242013-07-20 05:45:46867 url_fetcher_.reset();
868
[email protected]32a6c8382013-08-20 00:29:20869 ScheduleNextRun(kStepDelayShort);
[email protected]e3e696d32013-06-21 20:41:36870 return;
871 }
[email protected]7b0529242013-07-20 05:45:46872 crx->error_category = kNetworkError;
873 crx->error_code = GetFetchError(*source);
[email protected]e8f96ff2011-08-03 05:07:33874 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
875 CrxUpdateItem::kNoUpdate);
876 DCHECK_EQ(count, 1ul);
[email protected]cf442612011-08-09 20:20:12877 url_fetcher_.reset();
[email protected]e3e696d32013-06-21 20:41:36878
[email protected]7b0529242013-07-20 05:45:46879 // At this point, since both the differential and the full downloads failed,
880 // the update for this component has finished with an error.
881 ping_manager_->OnUpdateComplete(crx);
882
[email protected]32a6c8382013-08-20 00:29:20883 // Move on to the next update, if there is one available.
884 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33885 } else {
[email protected]650b2d52013-02-10 03:41:45886 base::FilePath temp_crx_path;
[email protected]e8f96ff2011-08-03 05:07:33887 CHECK(source->GetResponseAsFilePath(true, &temp_crx_path));
[email protected]e3e696d32013-06-21 20:41:36888
889 size_t count = 0;
890 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
891 count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
892 CrxUpdateItem::kUpdatingDiff);
893 } else {
894 count = ChangeItemStatus(CrxUpdateItem::kDownloading,
895 CrxUpdateItem::kUpdating);
896 }
[email protected]e8f96ff2011-08-03 05:07:33897 DCHECK_EQ(count, 1ul);
[email protected]e3e696d32013-06-21 20:41:36898
[email protected]cf442612011-08-09 20:20:12899 url_fetcher_.reset();
900
[email protected]85e61d52013-08-01 22:23:42901 if (crx->component.observer) {
902 crx->component.observer->OnEvent(
903 ComponentObserver::COMPONENT_UPDATE_READY, 0);
904 }
905
[email protected]44da56e2011-11-21 19:59:14906 // Why unretained? See comment at top of file.
[email protected]73251e72012-03-04 02:10:33907 BrowserThread::PostDelayedTask(
908 BrowserThread::FILE,
909 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14910 base::Bind(&CrxUpdateService::Install,
911 base::Unretained(this),
[email protected]64f39fa12013-09-03 21:49:37912 crx_context.release(),
[email protected]44da56e2011-11-21 19:59:14913 temp_crx_path),
[email protected]73251e72012-03-04 02:10:33914 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]e8f96ff2011-08-03 05:07:33915 }
[email protected]e8f96ff2011-08-03 05:07:33916}
917
918// Install consists of digital signature verification, unpacking and then
919// calling the component specific installer. All that is handled by the
920// |unpacker|. If there is an error this function is in charge of deleting
921// the files created.
922void CrxUpdateService::Install(const CRXContext* context,
[email protected]650b2d52013-02-10 03:41:45923 const base::FilePath& crx_path) {
[email protected]e8f96ff2011-08-03 05:07:33924 // This function owns the |crx_path| and the |context| object.
925 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]e3e696d32013-06-21 20:41:36926 ComponentUnpacker unpacker(context->pk_hash,
927 crx_path,
928 context->fingerprint,
929 component_patcher_.get(),
930 context->installer);
[email protected]dd3aa792013-07-16 19:10:23931 if (!base::DeleteFile(crx_path, false))
[email protected]e8f96ff2011-08-03 05:07:33932 NOTREACHED() << crx_path.value();
[email protected]44da56e2011-11-21 19:59:14933 // Why unretained? See comment at top of file.
[email protected]73251e72012-03-04 02:10:33934 BrowserThread::PostDelayedTask(
935 BrowserThread::UI,
936 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14937 base::Bind(&CrxUpdateService::DoneInstalling, base::Unretained(this),
[email protected]e3e696d32013-06-21 20:41:36938 context->id, unpacker.error(), unpacker.extended_error()),
[email protected]73251e72012-03-04 02:10:33939 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]07f93af12011-08-17 20:57:22940 delete context;
[email protected]e8f96ff2011-08-03 05:07:33941}
942
943// Installation has been completed. Adjust the component status and
[email protected]7b0529242013-07-20 05:45:46944// schedule the next check. Schedule a short delay before trying the full
945// update when the differential update failed.
[email protected]07f93af12011-08-17 20:57:22946void CrxUpdateService::DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:36947 ComponentUnpacker::Error error,
948 int extra_code) {
[email protected]e8f96ff2011-08-03 05:07:33949 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]07f93af12011-08-17 20:57:22950
[email protected]7b0529242013-07-20 05:45:46951 ErrorCategory error_category = kErrorNone;
952 switch (error) {
953 case ComponentUnpacker::kNone:
954 break;
955 case ComponentUnpacker::kInstallerError:
956 error_category = kInstallError;
957 break;
958 default:
959 error_category = kUnpackError;
960 break;
961 }
962
963 const bool is_success = error == ComponentUnpacker::kNone;
964
[email protected]07f93af12011-08-17 20:57:22965 CrxUpdateItem* item = FindUpdateItemById(component_id);
[email protected]7b0529242013-07-20 05:45:46966 if (item->status == CrxUpdateItem::kUpdatingDiff && !is_success) {
967 item->diff_error_category = error_category;
968 item->diff_error_code = error;
969 item->diff_extra_code1 = extra_code;
[email protected]1ea21ad2013-09-02 04:20:39970 item->diff_update_failed = true;
971 size_t count = ChangeItemStatus(CrxUpdateItem::kUpdatingDiff,
972 CrxUpdateItem::kCanUpdate);
973 DCHECK_EQ(count, 1ul);
974 ScheduleNextRun(kStepDelayShort);
975 return;
[email protected]e3e696d32013-06-21 20:41:36976 }
[email protected]e3e696d32013-06-21 20:41:36977
[email protected]7b0529242013-07-20 05:45:46978 if (is_success) {
979 item->status = CrxUpdateItem::kUpdated;
[email protected]07f93af12011-08-17 20:57:22980 item->component.version = item->next_version;
[email protected]e3e696d32013-06-21 20:41:36981 item->component.fingerprint = item->next_fp;
[email protected]7b0529242013-07-20 05:45:46982 } else {
983 item->status = CrxUpdateItem::kNoUpdate;
984 item->error_category = error_category;
985 item->error_code = error;
986 item->extra_code1 = extra_code;
[email protected]e3e696d32013-06-21 20:41:36987 }
[email protected]07f93af12011-08-17 20:57:22988
[email protected]7b0529242013-07-20 05:45:46989 ping_manager_->OnUpdateComplete(item);
[email protected]360b8bb2011-09-01 21:48:06990
[email protected]32a6c8382013-08-20 00:29:20991 // Move on to the next update, if there is one available.
992 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33993}
994
[email protected]85e61d52013-08-01 22:23:42995void CrxUpdateService::NotifyComponentObservers(
996 ComponentObserver::Events event, int extra) const {
997 for (UpdateItems::const_iterator it = work_items_.begin();
998 it != work_items_.end(); ++it) {
999 ComponentObserver* observer = (*it)->component.observer;
1000 if (observer)
1001 observer->OnEvent(event, 0);
1002 }
1003}
1004
[email protected]e8f96ff2011-08-03 05:07:331005// The component update factory. Using the component updater as a singleton
1006// is the job of the browser process.
1007ComponentUpdateService* ComponentUpdateServiceFactory(
1008 ComponentUpdateService::Configurator* config) {
1009 DCHECK(config);
1010 return new CrxUpdateService(config);
1011}