blob: f3982c0784ad210b3f66be2ad514c5e48afa762f [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]8f5f2ea2013-10-31 09:39:1023#include "base/threading/sequenced_worker_pool.h"
[email protected]41a17c52013-06-28 00:27:5324#include "base/timer/timer.h"
[email protected]e8f96ff2011-08-03 05:07:3325#include "chrome/browser/browser_process.h"
[email protected]e3e696d32013-06-21 20:41:3626#include "chrome/browser/component_updater/component_patcher.h"
[email protected]e8f96ff2011-08-03 05:07:3327#include "chrome/browser/component_updater/component_unpacker.h"
[email protected]7b0529242013-07-20 05:45:4628#include "chrome/browser/component_updater/component_updater_ping_manager.h"
29#include "chrome/browser/component_updater/crx_update_item.h"
[email protected]e8f96ff2011-08-03 05:07:3330#include "chrome/common/chrome_utility_messages.h"
31#include "chrome/common/chrome_version_info.h"
32#include "chrome/common/extensions/extension.h"
[email protected]b7b63872013-01-03 02:41:1933#include "content/public/browser/browser_thread.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 "net/base/escape.h"
37#include "net/base/load_flags.h"
[email protected]1dd4060e2013-03-13 13:15:1338#include "net/base/net_errors.h"
[email protected]3dc1bc42012-06-19 08:20:5339#include "net/url_request/url_fetcher.h"
[email protected]15fb2aa2012-05-22 22:52:5940#include "net/url_request/url_fetcher_delegate.h"
[email protected]9d8ea302012-09-25 15:04:2241#include "net/url_request/url_request_status.h"
[email protected]761fa4702013-07-02 15:25:1542#include "url/gurl.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]e8f96ff2011-08-03 05:07:3354// Extends an omaha compatible update check url |query| string. Does
55// not mutate the string if it would be longer than |limit| chars.
[email protected]4c37b452011-12-21 01:33:5256bool AddQueryString(const std::string& id,
57 const std::string& version,
[email protected]e3e696d32013-06-21 20:41:3658 const std::string& fingerprint,
[email protected]69b9f5de2013-06-24 20:59:4659 bool ondemand,
[email protected]4c37b452011-12-21 01:33:5260 size_t limit,
61 std::string* query) {
[email protected]e8f96ff2011-08-03 05:07:3362 std::string additional =
[email protected]69b9f5de2013-06-24 20:59:4663 base::StringPrintf("id=%s&v=%s&fp=%s&uc%s",
64 id.c_str(),
65 version.c_str(),
66 fingerprint.c_str(),
67 ondemand ? "&installsource=ondemand" : "");
[email protected]4a19be92011-09-22 14:25:0268 additional = "x=" + net::EscapeQueryParamValue(additional, true);
[email protected]e8f96ff2011-08-03 05:07:3369 if ((additional.size() + query->size() + 1) > limit)
70 return false;
[email protected]926d36332011-10-05 01:06:2571 if (!query->empty())
72 query->append(1, '&');
[email protected]e8f96ff2011-08-03 05:07:3373 query->append(additional);
74 return true;
75}
76
[email protected]926d36332011-10-05 01:06:2577// Create the final omaha compatible query. The |extra| is optional and can
78// be null. It should contain top level (non-escaped) parameters.
79std::string MakeFinalQuery(const std::string& host,
80 const std::string& query,
81 const char* extra) {
82 std::string request(host);
83 request.append(1, '?');
84 if (extra) {
85 request.append(extra);
86 request.append(1, '&');
87 }
88 request.append(query);
89 return request;
90}
91
[email protected]e8f96ff2011-08-03 05:07:3392// Produces an extension-like friendly |id|. This might be removed in the
93// future if we roll our on packing tools.
94static std::string HexStringToID(const std::string& hexstr) {
95 std::string id;
96 for (size_t i = 0; i < hexstr.size(); ++i) {
97 int val;
[email protected]eb72b272011-12-19 16:10:5598 if (base::HexStringToInt(base::StringPiece(hexstr.begin() + i,
99 hexstr.begin() + i + 1),
100 &val)) {
[email protected]e8f96ff2011-08-03 05:07:33101 id.append(1, val + 'a');
[email protected]eb72b272011-12-19 16:10:55102 } else {
[email protected]e8f96ff2011-08-03 05:07:33103 id.append(1, 'a');
[email protected]eb72b272011-12-19 16:10:55104 }
[email protected]e8f96ff2011-08-03 05:07:33105 }
106 DCHECK(Extension::IdIsValid(id));
107 return id;
108}
109
110// Helper to do version check for components.
111bool IsVersionNewer(const Version& current, const std::string& proposed) {
112 Version proposed_ver(proposed);
113 if (!proposed_ver.IsValid())
114 return false;
115 return (current.CompareTo(proposed_ver) < 0);
116}
117
118// Helper template class that allows our main class to have separate
[email protected]f1050432012-02-15 01:35:46119// OnURLFetchComplete() callbacks for different types of url requests
[email protected]e8f96ff2011-08-03 05:07:33120// they are differentiated by the |Ctx| type.
121template <typename Del, typename Ctx>
[email protected]15fb2aa2012-05-22 22:52:59122class DelegateWithContext : public net::URLFetcherDelegate {
[email protected]e8f96ff2011-08-03 05:07:33123 public:
124 DelegateWithContext(Del* delegate, Ctx* context)
125 : delegate_(delegate), context_(context) {}
126
[email protected]10c2d692012-05-11 05:32:23127 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
[email protected]e8f96ff2011-08-03 05:07:33128 delegate_->OnURLFetchComplete(source, context_);
129 delete this;
130 }
131
132 private:
133 ~DelegateWithContext() {}
134
135 Del* delegate_;
136 Ctx* context_;
137};
138// This function creates the right DelegateWithContext using template inference.
139template <typename Del, typename Ctx>
[email protected]15fb2aa2012-05-22 22:52:59140net::URLFetcherDelegate* MakeContextDelegate(Del* delegate, Ctx* context) {
[email protected]e8f96ff2011-08-03 05:07:33141 return new DelegateWithContext<Del, Ctx>(delegate, context);
142}
143
144// Helper to start a url request using |fetcher| with the common flags.
[email protected]d3ec669b2012-05-23 07:12:14145void StartFetch(net::URLFetcher* fetcher,
[email protected]e8f96ff2011-08-03 05:07:33146 net::URLRequestContextGetter* context_getter,
[email protected]8f5f2ea2013-10-31 09:39:10147 bool save_to_file,
148 scoped_refptr<base::SequencedTaskRunner> task_runner) {
[email protected]7cc6e5632011-10-25 17:56:12149 fetcher->SetRequestContext(context_getter);
150 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
151 net::LOAD_DO_NOT_SAVE_COOKIES |
152 net::LOAD_DISABLE_CACHE);
[email protected]e8f96ff2011-08-03 05:07:33153 // TODO(cpu): Define our retry and backoff policy.
[email protected]7cc6e5632011-10-25 17:56:12154 fetcher->SetAutomaticallyRetryOn5xx(false);
[email protected]e8f96ff2011-08-03 05:07:33155 if (save_to_file) {
[email protected]8f5f2ea2013-10-31 09:39:10156 fetcher->SaveResponseToTemporaryFile(task_runner);
[email protected]e8f96ff2011-08-03 05:07:33157 }
158 fetcher->Start();
159}
160
[email protected]e3e696d32013-06-21 20:41:36161// Returns true if the url request of |fetcher| was succesful.
[email protected]10c2d692012-05-11 05:32:23162bool FetchSuccess(const net::URLFetcher& fetcher) {
[email protected]7cc6e5632011-10-25 17:56:12163 return (fetcher.GetStatus().status() == net::URLRequestStatus::SUCCESS) &&
164 (fetcher.GetResponseCode() == 200);
[email protected]e8f96ff2011-08-03 05:07:33165}
166
[email protected]7b0529242013-07-20 05:45:46167// Returns the error code which occured during the fetch.The function returns 0
168// if the fetch was successful. If errors happen, the function could return a
169// network error, an http response code, or the status of the fetch, if the
170// fetch is pending or canceled.
171int GetFetchError(const net::URLFetcher& fetcher) {
172 if (FetchSuccess(fetcher))
173 return 0;
[email protected]e8f96ff2011-08-03 05:07:33174
[email protected]7b0529242013-07-20 05:45:46175 const net::URLRequestStatus::Status status(fetcher.GetStatus().status());
176 if (status == net::URLRequestStatus::FAILED)
177 return fetcher.GetStatus().error();
[email protected]3707eb22013-06-21 14:20:13178
[email protected]7b0529242013-07-20 05:45:46179 if (status == net::URLRequestStatus::IO_PENDING ||
180 status == net::URLRequestStatus::CANCELED)
181 return status;
[email protected]e3e696d32013-06-21 20:41:36182
[email protected]7b0529242013-07-20 05:45:46183 const int response_code(fetcher.GetResponseCode());
184 if (status == net::URLRequestStatus::SUCCESS && response_code != 200)
185 return response_code;
[email protected]e3e696d32013-06-21 20:41:36186
[email protected]7b0529242013-07-20 05:45:46187 return -1;
[email protected]e3e696d32013-06-21 20:41:36188 }
[email protected]e8f96ff2011-08-03 05:07:33189
[email protected]e3e696d32013-06-21 20:41:36190// Returns true if a differential update is available for the update item.
191bool IsDiffUpdateAvailable(const CrxUpdateItem* update_item) {
192 return update_item->diff_crx_url.is_valid();
193}
[email protected]e8f96ff2011-08-03 05:07:33194
[email protected]e3e696d32013-06-21 20:41:36195// Returns true if a differential update is available, it has not failed yet,
196// and the configuration allows it.
197bool CanTryDiffUpdate(const CrxUpdateItem* update_item,
198 const ComponentUpdateService::Configurator& config) {
199 return IsDiffUpdateAvailable(update_item) &&
200 !update_item->diff_update_failed &&
201 config.DeltasEnabled();
202}
203
[email protected]7b0529242013-07-20 05:45:46204} // namespace
205
206CrxUpdateItem::CrxUpdateItem()
207 : status(kNew),
[email protected]61aca4cd2013-10-26 10:50:59208 on_demand(false),
[email protected]7b0529242013-07-20 05:45:46209 diff_update_failed(false),
210 error_category(0),
211 error_code(0),
212 extra_code1(0),
213 diff_error_category(0),
214 diff_error_code(0),
215 diff_extra_code1(0) {
216}
217
218CrxUpdateItem::~CrxUpdateItem() {
219}
[email protected]86550a42013-06-21 15:20:49220
[email protected]dc06f0b2013-01-23 20:03:16221CrxComponent::CrxComponent()
[email protected]85e61d52013-08-01 22:23:42222 : installer(NULL),
223 observer(NULL) {
[email protected]dc06f0b2013-01-23 20:03:16224}
225
226CrxComponent::~CrxComponent() {
227}
[email protected]e8f96ff2011-08-03 05:07:33228
[email protected]2e919ddd2013-08-21 05:05:17229std::string GetCrxComponentID(const CrxComponent& component) {
230 return HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
231 component.pk_hash.size()/2)));
232}
233
234CrxComponentInfo::CrxComponentInfo() {
235}
236
237CrxComponentInfo::~CrxComponentInfo() {
238}
239
[email protected]e8f96ff2011-08-03 05:07:33240//////////////////////////////////////////////////////////////////////////////
241// The one and only implementation of the ComponentUpdateService interface. In
242// charge of running the show. The main method is ProcessPendingItems() which
[email protected]50b01392012-09-01 03:33:13243// is called periodically to do the upgrades/installs or the update checks.
[email protected]e8f96ff2011-08-03 05:07:33244// An important consideration here is to be as "low impact" as we can to the
245// rest of the browser, so even if we have many components registered and
[email protected]f1050432012-02-15 01:35:46246// eligible for update, we only do one thing at a time with pauses in between
[email protected]e8f96ff2011-08-03 05:07:33247// the tasks. Also when we do network requests there is only one |url_fetcher_|
[email protected]e3e696d32013-06-21 20:41:36248// in flight at a time.
[email protected]e8f96ff2011-08-03 05:07:33249// There are no locks in this code, the main structure |work_items_| is mutated
250// only from the UI thread. The unpack and installation is done in the file
251// thread and the network requests are done in the IO thread and in the file
252// thread.
253class CrxUpdateService : public ComponentUpdateService {
254 public:
255 explicit CrxUpdateService(ComponentUpdateService::Configurator* config);
256
257 virtual ~CrxUpdateService();
258
259 // Overrides for ComponentUpdateService.
260 virtual Status Start() OVERRIDE;
261 virtual Status Stop() OVERRIDE;
262 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE;
[email protected]61aca4cd2013-10-26 10:50:59263 virtual Status OnDemandUpdate(const std::string& component_id) OVERRIDE;
[email protected]2e919ddd2013-08-21 05:05:17264 virtual void GetComponents(
265 std::vector<CrxComponentInfo>* components) OVERRIDE;
[email protected]e8f96ff2011-08-03 05:07:33266
267 // The only purpose of this class is to forward the
[email protected]c4f883a2012-02-03 17:02:07268 // UtilityProcessHostClient callbacks so CrxUpdateService does
[email protected]e8f96ff2011-08-03 05:07:33269 // not have to derive from it because that is refcounted.
[email protected]c4f883a2012-02-03 17:02:07270 class ManifestParserBridge : public UtilityProcessHostClient {
[email protected]e8f96ff2011-08-03 05:07:33271 public:
272 explicit ManifestParserBridge(CrxUpdateService* service)
273 : service_(service) {}
274
275 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
276 bool handled = true;
277 IPC_BEGIN_MESSAGE_MAP(ManifestParserBridge, message)
[email protected]2ccf45c2011-08-19 23:35:50278 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseUpdateManifest_Succeeded,
[email protected]e8f96ff2011-08-03 05:07:33279 OnParseUpdateManifestSucceeded)
[email protected]2ccf45c2011-08-19 23:35:50280 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseUpdateManifest_Failed,
[email protected]e8f96ff2011-08-03 05:07:33281 OnParseUpdateManifestFailed)
282 IPC_MESSAGE_UNHANDLED(handled = false)
283 IPC_END_MESSAGE_MAP()
284 return handled;
285 }
286
287 private:
[email protected]a3988cc2012-04-27 05:07:18288 virtual ~ManifestParserBridge() {}
289
[email protected]f1050432012-02-15 01:35:46290 // Omaha update response XML was successfully parsed.
[email protected]e8f96ff2011-08-03 05:07:33291 void OnParseUpdateManifestSucceeded(const UpdateManifest::Results& r) {
292 service_->OnParseUpdateManifestSucceeded(r);
293 }
294 // Omaha update response XML could not be parsed.
295 void OnParseUpdateManifestFailed(const std::string& e) {
296 service_->OnParseUpdateManifestFailed(e);
297 }
298
299 CrxUpdateService* service_;
300 DISALLOW_COPY_AND_ASSIGN(ManifestParserBridge);
301 };
302
303 // Context for a update check url request. See DelegateWithContext above.
304 struct UpdateContext {
305 base::Time start;
306 UpdateContext() : start(base::Time::Now()) {}
307 };
308
309 // Context for a crx download url request. See DelegateWithContext above.
310 struct CRXContext {
311 ComponentInstaller* installer;
312 std::vector<uint8> pk_hash;
313 std::string id;
[email protected]e3e696d32013-06-21 20:41:36314 std::string fingerprint;
[email protected]e8f96ff2011-08-03 05:07:33315 CRXContext() : installer(NULL) {}
316 };
317
[email protected]10c2d692012-05-11 05:32:23318 void OnURLFetchComplete(const net::URLFetcher* source,
[email protected]7cc6e5632011-10-25 17:56:12319 UpdateContext* context);
[email protected]e8f96ff2011-08-03 05:07:33320
[email protected]10c2d692012-05-11 05:32:23321 void OnURLFetchComplete(const net::URLFetcher* source,
[email protected]7cc6e5632011-10-25 17:56:12322 CRXContext* context);
[email protected]e8f96ff2011-08-03 05:07:33323
324 private:
[email protected]7b0529242013-07-20 05:45:46325 enum ErrorCategory {
326 kErrorNone = 0,
327 kNetworkError,
328 kUnpackError,
329 kInstallError,
330 };
331
[email protected]32a6c8382013-08-20 00:29:20332 enum StepDelayInterval {
333 kStepDelayShort = 0,
334 kStepDelayMedium,
335 kStepDelayLong,
336 };
337
[email protected]e8f96ff2011-08-03 05:07:33338 // See ManifestParserBridge.
[email protected]7b0529242013-07-20 05:45:46339 void OnParseUpdateManifestSucceeded(const UpdateManifest::Results& results);
[email protected]e8f96ff2011-08-03 05:07:33340
341 // See ManifestParserBridge.
[email protected]e3e696d32013-06-21 20:41:36342 void OnParseUpdateManifestFailed(const std::string& error_message);
[email protected]e8f96ff2011-08-03 05:07:33343
344 bool AddItemToUpdateCheck(CrxUpdateItem* item, std::string* query);
345
346 void ProcessPendingItems();
347
[email protected]61aca4cd2013-10-26 10:50:59348 CrxUpdateItem* FindReadyComponent();
349
350 void UpdateComponent(CrxUpdateItem* workitem);
351
352 void AddUpdateCheckItems(std::string* query);
353
354 void DoUpdateCheck(const std::string& query);
355
[email protected]32a6c8382013-08-20 00:29:20356 void ScheduleNextRun(StepDelayInterval step_delay);
[email protected]e8f96ff2011-08-03 05:07:33357
358 void ParseManifest(const std::string& xml);
359
[email protected]650b2d52013-02-10 03:41:45360 void Install(const CRXContext* context, const base::FilePath& crx_path);
[email protected]e8f96ff2011-08-03 05:07:33361
[email protected]07f93af12011-08-17 20:57:22362 void DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:36363 ComponentUnpacker::Error error,
364 int extended_error);
[email protected]e8f96ff2011-08-03 05:07:33365
[email protected]61aca4cd2013-10-26 10:50:59366 void ChangeItemState(CrxUpdateItem* item, CrxUpdateItem::Status to);
367
[email protected]e8f96ff2011-08-03 05:07:33368 size_t ChangeItemStatus(CrxUpdateItem::Status from,
369 CrxUpdateItem::Status to);
370
371 CrxUpdateItem* FindUpdateItemById(const std::string& id);
372
[email protected]85e61d52013-08-01 22:23:42373 void NotifyComponentObservers(ComponentObserver::Events event,
374 int extra) const;
375
[email protected]61aca4cd2013-10-26 10:50:59376 bool HasOnDemandItems() const;
377
[email protected]e3e696d32013-06-21 20:41:36378 scoped_ptr<ComponentUpdateService::Configurator> config_;
379
380 scoped_ptr<ComponentPatcher> component_patcher_;
[email protected]e8f96ff2011-08-03 05:07:33381
[email protected]d3ec669b2012-05-23 07:12:14382 scoped_ptr<net::URLFetcher> url_fetcher_;
[email protected]e8f96ff2011-08-03 05:07:33383
[email protected]7b0529242013-07-20 05:45:46384 scoped_ptr<component_updater::PingManager> ping_manager_;
385
[email protected]86550a42013-06-21 15:20:49386 // A collection of every work item.
[email protected]e3e696d32013-06-21 20:41:36387 typedef std::vector<CrxUpdateItem*> UpdateItems;
[email protected]e8f96ff2011-08-03 05:07:33388 UpdateItems work_items_;
389
[email protected]e8f96ff2011-08-03 05:07:33390 base::OneShotTimer<CrxUpdateService> timer_;
391
[email protected]8f5f2ea2013-10-31 09:39:10392 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
393
[email protected]e3e696d32013-06-21 20:41:36394 const Version chrome_version_;
[email protected]e8f96ff2011-08-03 05:07:33395
396 bool running_;
397
398 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
399};
400
[email protected]e8f96ff2011-08-03 05:07:33401//////////////////////////////////////////////////////////////////////////////
402
[email protected]e3e696d32013-06-21 20:41:36403CrxUpdateService::CrxUpdateService(ComponentUpdateService::Configurator* config)
[email protected]e8f96ff2011-08-03 05:07:33404 : config_(config),
[email protected]e3e696d32013-06-21 20:41:36405 component_patcher_(config->CreateComponentPatcher()),
[email protected]7b0529242013-07-20 05:45:46406 ping_manager_(new component_updater::PingManager(
407 config->PingUrl(),
408 config->RequestContext())),
[email protected]8f5f2ea2013-10-31 09:39:10409 blocking_task_runner_(BrowserThread::GetBlockingPool()->
410 GetSequencedTaskRunnerWithShutdownBehavior(
411 BrowserThread::GetBlockingPool()->GetSequenceToken(),
412 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)),
[email protected]e8f96ff2011-08-03 05:07:33413 chrome_version_(chrome::VersionInfo().Version()),
414 running_(false) {
[email protected]1ea21ad2013-09-02 04:20:39415}
[email protected]e8f96ff2011-08-03 05:07:33416
417CrxUpdateService::~CrxUpdateService() {
418 // Because we are a singleton, at this point only the UI thread should be
419 // alive, this simplifies the management of the work that could be in
420 // flight in other threads.
421 Stop();
422 STLDeleteElements(&work_items_);
[email protected]1ea21ad2013-09-02 04:20:39423}
[email protected]e8f96ff2011-08-03 05:07:33424
425ComponentUpdateService::Status CrxUpdateService::Start() {
426 // Note that RegisterComponent will call Start() when the first
427 // component is registered, so it can be called twice. This way
428 // we avoid scheduling the timer if there is no work to do.
429 running_ = true;
430 if (work_items_.empty())
431 return kOk;
432
[email protected]85e61d52013-08-01 22:23:42433 NotifyComponentObservers(ComponentObserver::COMPONENT_UPDATER_STARTED, 0);
434
[email protected]d323a172011-09-02 18:23:02435 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->InitialDelay()),
[email protected]e8f96ff2011-08-03 05:07:33436 this, &CrxUpdateService::ProcessPendingItems);
437 return kOk;
438}
439
440// Stop the main check + update loop. In flight operations will be
441// completed.
442ComponentUpdateService::Status CrxUpdateService::Stop() {
443 running_ = false;
444 timer_.Stop();
445 return kOk;
446}
447
[email protected]61aca4cd2013-10-26 10:50:59448bool CrxUpdateService::HasOnDemandItems() const {
449 class Helper {
450 public:
451 static bool IsOnDemand(CrxUpdateItem* item) {
452 return item->on_demand;
453 }
454 };
455 return std::find_if(work_items_.begin(),
456 work_items_.end(),
457 Helper::IsOnDemand) != work_items_.end();
458}
459
[email protected]ccb4feef2013-02-14 06:16:47460// This function sets the timer which will call ProcessPendingItems() or
[email protected]61aca4cd2013-10-26 10:50:59461// ProcessRequestedItem() if there is an on_demand item. There
[email protected]32a6c8382013-08-20 00:29:20462// are three kinds of waits:
463// - a short delay, when there is immediate work to be done.
464// - a medium delay, when there are updates to be applied within the current
465// update cycle, or there are components that are still unchecked.
466// - a long delay when a full check/update cycle has completed for all
467// components.
468void CrxUpdateService::ScheduleNextRun(StepDelayInterval step_delay) {
[email protected]e8f96ff2011-08-03 05:07:33469 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cf442612011-08-09 20:20:12470 DCHECK(url_fetcher_.get() == NULL);
[email protected]e8f96ff2011-08-03 05:07:33471 CHECK(!timer_.IsRunning());
472 // It could be the case that Stop() had been called while a url request
473 // or unpacking was in flight, if so we arrive here but |running_| is
474 // false. In that case do not loop again.
475 if (!running_)
476 return;
477
[email protected]ccb4feef2013-02-14 06:16:47478 // Keep the delay short if in the middle of an update (step_delay),
479 // or there are new requested_work_items_ that have not been processed yet.
[email protected]32a6c8382013-08-20 00:29:20480 int64 delay_seconds = 0;
[email protected]61aca4cd2013-10-26 10:50:59481 if (!HasOnDemandItems()) {
[email protected]32a6c8382013-08-20 00:29:20482 switch (step_delay) {
483 case kStepDelayShort:
484 delay_seconds = config_->StepDelay();
485 break;
486 case kStepDelayMedium:
487 delay_seconds = config_->StepDelayMedium();
488 break;
489 case kStepDelayLong:
490 delay_seconds = config_->NextCheckDelay();
491 break;
492 }
493 } else {
494 delay_seconds = config_->StepDelay();
495 }
[email protected]cf442612011-08-09 20:20:12496
[email protected]32a6c8382013-08-20 00:29:20497 if (step_delay != kStepDelayShort) {
[email protected]85e61d52013-08-01 22:23:42498 NotifyComponentObservers(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0);
499
[email protected]e8f96ff2011-08-03 05:07:33500 // Zero is only used for unit tests.
[email protected]32a6c8382013-08-20 00:29:20501 if (0 == delay_seconds)
[email protected]e8f96ff2011-08-03 05:07:33502 return;
503 }
504
[email protected]32a6c8382013-08-20 00:29:20505 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay_seconds),
[email protected]e8f96ff2011-08-03 05:07:33506 this, &CrxUpdateService::ProcessPendingItems);
507}
508
509// Given a extension-like component id, find the associated component.
510CrxUpdateItem* CrxUpdateService::FindUpdateItemById(const std::string& id) {
511 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
512 CrxUpdateItem::FindById finder(id);
513 UpdateItems::iterator it = std::find_if(work_items_.begin(),
514 work_items_.end(),
515 finder);
516 if (it == work_items_.end())
517 return NULL;
518 return (*it);
519}
520
[email protected]61aca4cd2013-10-26 10:50:59521// Changes a component's status, clearing on_demand and firing notifications as
522// necessary. By convention, this is the only function that can change a
523// CrxUpdateItem's |status|.
524// TODO(waffles): Do we want to add DCHECKS for valid state transitions here?
525void CrxUpdateService::ChangeItemState(CrxUpdateItem* item,
526 CrxUpdateItem::Status to) {
527 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
528 if (to == CrxUpdateItem::kNoUpdate ||
529 to == CrxUpdateItem::kUpdated ||
530 to == CrxUpdateItem::kUpToDate) {
531 item->on_demand = false;
532 }
533
534 item->status = to;
535
536 ComponentObserver* observer = item->component.observer;
537 if (observer) {
538 switch (to) {
539 case CrxUpdateItem::kCanUpdate:
540 observer->OnEvent(ComponentObserver::COMPONENT_UPDATE_FOUND, 0);
541 break;
542 case CrxUpdateItem::kUpdatingDiff:
543 case CrxUpdateItem::kUpdating:
544 observer->OnEvent(ComponentObserver::COMPONENT_UPDATE_READY, 0);
545 break;
546 case CrxUpdateItem::kUpdated:
547 observer->OnEvent(ComponentObserver::COMPONENT_UPDATED, 0);
548 break;
549 case CrxUpdateItem::kUpToDate:
550 case CrxUpdateItem::kNoUpdate:
551 observer->OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0);
552 break;
553 case CrxUpdateItem::kNew:
554 case CrxUpdateItem::kChecking:
555 case CrxUpdateItem::kDownloading:
556 case CrxUpdateItem::kDownloadingDiff:
557 case CrxUpdateItem::kLastStatus:
558 // No notification for these states.
559 break;
560 }
561 }
562}
563
[email protected]e8f96ff2011-08-03 05:07:33564// Changes all the components in |work_items_| that have |from| status to
[email protected]e3e696d32013-06-21 20:41:36565// |to| status and returns how many have been changed.
[email protected]e8f96ff2011-08-03 05:07:33566size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from,
567 CrxUpdateItem::Status to) {
568 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
569 size_t count = 0;
570 for (UpdateItems::iterator it = work_items_.begin();
571 it != work_items_.end(); ++it) {
572 CrxUpdateItem* item = *it;
573 if (item->status != from)
574 continue;
[email protected]61aca4cd2013-10-26 10:50:59575 ChangeItemState(item, to);
[email protected]e8f96ff2011-08-03 05:07:33576 ++count;
577 }
578 return count;
579}
580
581// Adds a component to be checked for upgrades. If the component exists it
582// it will be replaced and the return code is kReplaced.
583//
584// TODO(cpu): Evaluate if we want to support un-registration.
585ComponentUpdateService::Status CrxUpdateService::RegisterComponent(
586 const CrxComponent& component) {
587 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
588 if (component.pk_hash.empty() ||
589 !component.version.IsValid() ||
590 !component.installer)
591 return kError;
592
593 std::string id =
594 HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
595 component.pk_hash.size()/2)));
596 CrxUpdateItem* uit;
597 uit = FindUpdateItemById(id);
598 if (uit) {
599 uit->component = component;
600 return kReplaced;
601 }
602
603 uit = new CrxUpdateItem;
604 uit->id.swap(id);
605 uit->component = component;
[email protected]e3e696d32013-06-21 20:41:36606
[email protected]e8f96ff2011-08-03 05:07:33607 work_items_.push_back(uit);
608 // If this is the first component registered we call Start to
609 // schedule the first timer.
610 if (running_ && (work_items_.size() == 1))
611 Start();
612
613 return kOk;
614}
615
616// Sets a component to be checked for updates.
[email protected]69b9f5de2013-06-24 20:59:46617// The component to add is |item| and the |query| string is modified with the
618// required omaha compatible query. Returns false when the query string is
619// longer than specified by UrlSizeLimit().
[email protected]e8f96ff2011-08-03 05:07:33620bool CrxUpdateService::AddItemToUpdateCheck(CrxUpdateItem* item,
621 std::string* query) {
622 if (!AddQueryString(item->id,
623 item->component.version.GetString(),
[email protected]e3e696d32013-06-21 20:41:36624 item->component.fingerprint,
[email protected]61aca4cd2013-10-26 10:50:59625 item->on_demand,
[email protected]69b9f5de2013-06-24 20:59:46626 config_->UrlSizeLimit(),
627 query))
[email protected]e8f96ff2011-08-03 05:07:33628 return false;
[email protected]e3e696d32013-06-21 20:41:36629
[email protected]61aca4cd2013-10-26 10:50:59630 ChangeItemState(item, CrxUpdateItem::kChecking);
[email protected]e8f96ff2011-08-03 05:07:33631 item->last_check = base::Time::Now();
[email protected]e3e696d32013-06-21 20:41:36632 item->previous_version = item->component.version;
633 item->next_version = Version();
634 item->previous_fp = item->component.fingerprint;
635 item->next_fp.clear();
636 item->diff_update_failed = false;
[email protected]7b0529242013-07-20 05:45:46637 item->error_category = 0;
638 item->error_code = 0;
639 item->extra_code1 = 0;
640 item->diff_error_category = 0;
641 item->diff_error_code = 0;
642 item->diff_extra_code1 = 0;
[email protected]e8f96ff2011-08-03 05:07:33643 return true;
644}
645
[email protected]ccb4feef2013-02-14 06:16:47646// Start the process of checking for an update, for a particular component
647// that was previously registered.
[email protected]2e919ddd2013-08-21 05:05:17648// |component_id| is a value returned from GetCrxComponentID().
[email protected]61aca4cd2013-10-26 10:50:59649ComponentUpdateService::Status CrxUpdateService::OnDemandUpdate(
[email protected]2e919ddd2013-08-21 05:05:17650 const std::string& component_id) {
[email protected]ccb4feef2013-02-14 06:16:47651 CrxUpdateItem* uit;
[email protected]2e919ddd2013-08-21 05:05:17652 uit = FindUpdateItemById(component_id);
[email protected]ccb4feef2013-02-14 06:16:47653 if (!uit)
654 return kError;
655
656 // Check if the request is too soon.
657 base::TimeDelta delta = base::Time::Now() - uit->last_check;
[email protected]e3e696d32013-06-21 20:41:36658 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
[email protected]ccb4feef2013-02-14 06:16:47659 return kError;
[email protected]ccb4feef2013-02-14 06:16:47660
661 switch (uit->status) {
662 // If the item is already in the process of being updated, there is
663 // no point in this call, so return kInProgress.
664 case CrxUpdateItem::kChecking:
665 case CrxUpdateItem::kCanUpdate:
[email protected]e3e696d32013-06-21 20:41:36666 case CrxUpdateItem::kDownloadingDiff:
[email protected]ccb4feef2013-02-14 06:16:47667 case CrxUpdateItem::kDownloading:
[email protected]e3e696d32013-06-21 20:41:36668 case CrxUpdateItem::kUpdatingDiff:
[email protected]ccb4feef2013-02-14 06:16:47669 case CrxUpdateItem::kUpdating:
670 return kInProgress;
671 // Otherwise the item was already checked a while back (or it is new),
672 // set its status to kNew to give it a slightly higher priority.
673 case CrxUpdateItem::kNew:
674 case CrxUpdateItem::kUpdated:
675 case CrxUpdateItem::kUpToDate:
676 case CrxUpdateItem::kNoUpdate:
[email protected]61aca4cd2013-10-26 10:50:59677 ChangeItemState(uit, CrxUpdateItem::kNew);
678 uit->on_demand = true;
[email protected]ccb4feef2013-02-14 06:16:47679 break;
680 case CrxUpdateItem::kLastStatus:
681 NOTREACHED() << uit->status;
682 }
683
684 // In case the current delay is long, set the timer to a shorter value
685 // to get the ball rolling.
686 if (timer_.IsRunning()) {
687 timer_.Stop();
688 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->StepDelay()),
689 this, &CrxUpdateService::ProcessPendingItems);
690 }
691
692 return kOk;
693}
694
[email protected]2e919ddd2013-08-21 05:05:17695void CrxUpdateService::GetComponents(
696 std::vector<CrxComponentInfo>* components) {
697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
698 for (UpdateItems::const_iterator it = work_items_.begin();
699 it != work_items_.end(); ++it) {
700 const CrxUpdateItem* item = *it;
701 CrxComponentInfo info;
702 info.id = GetCrxComponentID(item->component);
703 info.version = item->component.version.GetString();
704 info.name = item->component.name;
705 components->push_back(info);
706 }
707}
708
[email protected]61aca4cd2013-10-26 10:50:59709// This is the main loop of the component updater.
[email protected]e8f96ff2011-08-03 05:07:33710void CrxUpdateService::ProcessPendingItems() {
711 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]61aca4cd2013-10-26 10:50:59712 CrxUpdateItem* ready_upgrade = FindReadyComponent();
713 if (ready_upgrade) {
714 UpdateComponent(ready_upgrade);
[email protected]e8f96ff2011-08-03 05:07:33715 return;
716 }
[email protected]d63306d2013-06-29 13:56:02717 std::string query;
[email protected]61aca4cd2013-10-26 10:50:59718 AddUpdateCheckItems(&query);
719 if (!query.empty()) {
720 DoUpdateCheck(query);
721 return;
722 }
723 // No components to update. The next check will be after a long sleep.
724 ScheduleNextRun(kStepDelayLong);
725}
726
727CrxUpdateItem* CrxUpdateService::FindReadyComponent() {
728 class Helper {
729 public:
730 static bool IsReadyOnDemand(CrxUpdateItem* item) {
731 return item->on_demand && IsReady(item);
732 }
733 static bool IsReady(CrxUpdateItem* item) {
734 return item->status == CrxUpdateItem::kCanUpdate;
735 }
736 };
737
738 std::vector<CrxUpdateItem*>::iterator it = std::find_if(
739 work_items_.begin(), work_items_.end(), Helper::IsReadyOnDemand);
740 if (it != work_items_.end())
741 return *it;
742 it = std::find_if(work_items_.begin(), work_items_.end(), Helper::IsReady);
743 if (it != work_items_.end())
744 return *it;
745 return NULL;
746}
747
748void CrxUpdateService::UpdateComponent(CrxUpdateItem* workitem) {
749 CRXContext* context = new CRXContext;
750 context->pk_hash = workitem->component.pk_hash;
751 context->id = workitem->id;
752 context->installer = workitem->component.installer;
753 context->fingerprint = workitem->next_fp;
754 GURL package_url;
755 if (CanTryDiffUpdate(workitem, *config_)) {
756 package_url = workitem->diff_crx_url;
757 ChangeItemState(workitem, CrxUpdateItem::kDownloadingDiff);
758 } else {
759 package_url = workitem->crx_url;
760 ChangeItemState(workitem, CrxUpdateItem::kDownloading);
761 }
762 url_fetcher_.reset(net::URLFetcher::Create(
763 0, package_url, net::URLFetcher::GET,
764 MakeContextDelegate(this, context)));
[email protected]8f5f2ea2013-10-31 09:39:10765 StartFetch(url_fetcher_.get(),
766 config_->RequestContext(),
767 true,
768 blocking_task_runner_);
[email protected]61aca4cd2013-10-26 10:50:59769}
770
771// Given that our |work_items_| list is expected to contain relatively few
772// items, we simply loop several times.
773void CrxUpdateService::AddUpdateCheckItems(std::string* query){
[email protected]d63306d2013-06-29 13:56:02774 for (UpdateItems::const_iterator it = work_items_.begin();
775 it != work_items_.end(); ++it) {
776 CrxUpdateItem* item = *it;
777 if (item->status != CrxUpdateItem::kNew)
[email protected]dc06f0b2013-01-23 20:03:16778 continue;
[email protected]61aca4cd2013-10-26 10:50:59779 if (!AddItemToUpdateCheck(item, query))
[email protected]d63306d2013-06-29 13:56:02780 break;
[email protected]d63306d2013-06-29 13:56:02781 }
[email protected]dc06f0b2013-01-23 20:03:16782
[email protected]d63306d2013-06-29 13:56:02783 // Next we can go back to components we already checked, here
784 // we can also batch them in a single url request, as long as
785 // we have not checked them recently.
786 const base::TimeDelta min_delta_time =
787 base::TimeDelta::FromSeconds(config_->MinimumReCheckWait());
788
789 for (UpdateItems::const_iterator it = work_items_.begin();
790 it != work_items_.end(); ++it) {
791 CrxUpdateItem* item = *it;
792 if ((item->status != CrxUpdateItem::kNoUpdate) &&
793 (item->status != CrxUpdateItem::kUpToDate))
794 continue;
795 base::TimeDelta delta = base::Time::Now() - item->last_check;
796 if (delta < min_delta_time)
797 continue;
[email protected]61aca4cd2013-10-26 10:50:59798 if (!AddItemToUpdateCheck(item, query))
[email protected]d63306d2013-06-29 13:56:02799 break;
800 }
801
802 // Finally, we check components that we already updated as long as
803 // we have not checked them recently.
804 for (UpdateItems::const_iterator it = work_items_.begin();
805 it != work_items_.end(); ++it) {
806 CrxUpdateItem* item = *it;
807 if (item->status != CrxUpdateItem::kUpdated)
808 continue;
809 base::TimeDelta delta = base::Time::Now() - item->last_check;
810 if (delta < min_delta_time)
811 continue;
[email protected]61aca4cd2013-10-26 10:50:59812 if (!AddItemToUpdateCheck(item, query))
[email protected]d63306d2013-06-29 13:56:02813 break;
814 }
[email protected]61aca4cd2013-10-26 10:50:59815}
[email protected]d63306d2013-06-29 13:56:02816
[email protected]61aca4cd2013-10-26 10:50:59817void CrxUpdateService::DoUpdateCheck(const std::string& query) {
818 const std::string full_query =
819 MakeFinalQuery(config_->UpdateUrl().spec(),
820 query,
821 config_->ExtraRequestParams());
[email protected]dc06f0b2013-01-23 20:03:16822
[email protected]61aca4cd2013-10-26 10:50:59823 url_fetcher_.reset(net::URLFetcher::Create(
824 0, GURL(full_query), net::URLFetcher::GET,
825 MakeContextDelegate(this, new UpdateContext())));
[email protected]8f5f2ea2013-10-31 09:39:10826 StartFetch(url_fetcher_.get(),
827 config_->RequestContext(),
828 false,
829 blocking_task_runner_);
[email protected]e8f96ff2011-08-03 05:07:33830}
831
[email protected]ccb4feef2013-02-14 06:16:47832// Called when we got a response from the update server. It consists of an xml
[email protected]e8f96ff2011-08-03 05:07:33833// document following the omaha update scheme.
[email protected]10c2d692012-05-11 05:32:23834void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
[email protected]07f93af12011-08-17 20:57:22835 UpdateContext* context) {
[email protected]e8f96ff2011-08-03 05:07:33836 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
837 if (FetchSuccess(*source)) {
838 std::string xml;
839 source->GetResponseAsString(&xml);
[email protected]cf442612011-08-09 20:20:12840 url_fetcher_.reset();
[email protected]e8f96ff2011-08-03 05:07:33841 ParseManifest(xml);
842 } else {
[email protected]cf442612011-08-09 20:20:12843 url_fetcher_.reset();
[email protected]e8f96ff2011-08-03 05:07:33844 CrxUpdateService::OnParseUpdateManifestFailed("network error");
845 }
[email protected]07f93af12011-08-17 20:57:22846 delete context;
[email protected]e8f96ff2011-08-03 05:07:33847}
848
849// Parsing the manifest is either done right now for tests or in a sandboxed
850// process for the production environment. This mitigates the case where an
851// attacker was able to feed us a malicious xml string.
852void CrxUpdateService::ParseManifest(const std::string& xml) {
853 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
854 if (config_->InProcess()) {
855 UpdateManifest manifest;
[email protected]e3e696d32013-06-21 20:41:36856 if (!manifest.Parse(xml))
[email protected]e8f96ff2011-08-03 05:07:33857 CrxUpdateService::OnParseUpdateManifestFailed(manifest.errors());
[email protected]e3e696d32013-06-21 20:41:36858 else
[email protected]e8f96ff2011-08-03 05:07:33859 CrxUpdateService::OnParseUpdateManifestSucceeded(manifest.results());
[email protected]e8f96ff2011-08-03 05:07:33860 } else {
[email protected]cadac622013-06-11 16:46:36861 UtilityProcessHost* host =
862 UtilityProcessHost::Create(new ManifestParserBridge(this),
863 base::MessageLoopProxy::current().get());
[email protected]c4f883a2012-02-03 17:02:07864 host->EnableZygote();
[email protected]2ccf45c2011-08-19 23:35:50865 host->Send(new ChromeUtilityMsg_ParseUpdateManifest(xml));
[email protected]e8f96ff2011-08-03 05:07:33866 }
867}
868
869// A valid Omaha update check has arrived, from only the list of components that
870// we are currently upgrading we check for a match in which the server side
871// version is newer, if so we queue them for an upgrade. The next time we call
872// ProcessPendingItems() one of them will be drafted for the upgrade process.
873void CrxUpdateService::OnParseUpdateManifestSucceeded(
874 const UpdateManifest::Results& results) {
875 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a1f8c162012-09-27 22:32:21876 size_t update_pending = 0;
[email protected]e8f96ff2011-08-03 05:07:33877 std::vector<UpdateManifest::Result>::const_iterator it;
878 for (it = results.list.begin(); it != results.list.end(); ++it) {
879 CrxUpdateItem* crx = FindUpdateItemById(it->extension_id);
880 if (!crx)
881 continue;
882
883 if (crx->status != CrxUpdateItem::kChecking)
884 continue; // Not updating this component now.
885
886 if (it->version.empty()) {
[email protected]cf442612011-08-09 20:20:12887 // No version means no update available.
[email protected]61aca4cd2013-10-26 10:50:59888 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
[email protected]cf442612011-08-09 20:20:12889 continue;
[email protected]e8f96ff2011-08-03 05:07:33890 }
891 if (!IsVersionNewer(crx->component.version, it->version)) {
[email protected]cf442612011-08-09 20:20:12892 // Our component is up to date.
[email protected]61aca4cd2013-10-26 10:50:59893 ChangeItemState(crx, CrxUpdateItem::kUpToDate);
[email protected]cf442612011-08-09 20:20:12894 continue;
[email protected]e8f96ff2011-08-03 05:07:33895 }
896 if (!it->browser_min_version.empty()) {
[email protected]cf442612011-08-09 20:20:12897 if (IsVersionNewer(chrome_version_, it->browser_min_version)) {
898 // Does not apply for this chrome version.
[email protected]61aca4cd2013-10-26 10:50:59899 ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
[email protected]cf442612011-08-09 20:20:12900 continue;
901 }
[email protected]e8f96ff2011-08-03 05:07:33902 }
903 // All test passed. Queue an upgrade for this component and fire the
904 // notifications.
905 crx->crx_url = it->crx_url;
[email protected]e3e696d32013-06-21 20:41:36906 crx->diff_crx_url = it->diff_crx_url;
[email protected]61aca4cd2013-10-26 10:50:59907 ChangeItemState(crx, CrxUpdateItem::kCanUpdate);
[email protected]07f93af12011-08-17 20:57:22908 crx->next_version = Version(it->version);
[email protected]e3e696d32013-06-21 20:41:36909 crx->next_fp = it->package_fingerprint;
[email protected]e8f96ff2011-08-03 05:07:33910 ++update_pending;
[email protected]e8f96ff2011-08-03 05:07:33911 }
[email protected]cf442612011-08-09 20:20:12912
913 // All the components that are not mentioned in the manifest we
914 // consider them up to date.
915 ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kUpToDate);
916
[email protected]32a6c8382013-08-20 00:29:20917 // If there are updates pending we do a short wait, otherwise we take
918 // a longer delay until we check the components again.
919 ScheduleNextRun(update_pending > 0 ? kStepDelayShort : kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33920}
921
922void CrxUpdateService::OnParseUpdateManifestFailed(
923 const std::string& error_message) {
924 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
925 size_t count = ChangeItemStatus(CrxUpdateItem::kChecking,
926 CrxUpdateItem::kNoUpdate);
927 DCHECK_GT(count, 0ul);
[email protected]32a6c8382013-08-20 00:29:20928 ScheduleNextRun(kStepDelayLong);
[email protected]e8f96ff2011-08-03 05:07:33929}
930
931// Called when the CRX package has been downloaded to a temporary location.
932// Here we fire the notifications and schedule the component-specific installer
933// to be called in the file thread.
[email protected]10c2d692012-05-11 05:32:23934void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
[email protected]e8f96ff2011-08-03 05:07:33935 CRXContext* context) {
936 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]64f39fa12013-09-03 21:49:37937
938 scoped_ptr<CRXContext> crx_context(context);
[email protected]e8f96ff2011-08-03 05:07:33939
[email protected]64f39fa12013-09-03 21:49:37940 CrxUpdateItem* crx = FindUpdateItemById(crx_context->id);
[email protected]e3e696d32013-06-21 20:41:36941 DCHECK(crx->status == CrxUpdateItem::kDownloadingDiff ||
942 crx->status == CrxUpdateItem::kDownloading);
943
[email protected]376d26d2013-10-03 10:12:49944 if (!FetchSuccess(*source)) {
[email protected]e3e696d32013-06-21 20:41:36945 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
[email protected]7b0529242013-07-20 05:45:46946 crx->diff_error_category = kNetworkError;
947 crx->diff_error_code = GetFetchError(*source);
[email protected]e630ba62013-06-22 15:22:34948 crx->diff_update_failed = true;
[email protected]e3e696d32013-06-21 20:41:36949 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
950 CrxUpdateItem::kCanUpdate);
951 DCHECK_EQ(count, 1ul);
[email protected]7b0529242013-07-20 05:45:46952 url_fetcher_.reset();
953
[email protected]32a6c8382013-08-20 00:29:20954 ScheduleNextRun(kStepDelayShort);
[email protected]e3e696d32013-06-21 20:41:36955 return;
956 }
[email protected]7b0529242013-07-20 05:45:46957 crx->error_category = kNetworkError;
958 crx->error_code = GetFetchError(*source);
[email protected]e8f96ff2011-08-03 05:07:33959 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
960 CrxUpdateItem::kNoUpdate);
961 DCHECK_EQ(count, 1ul);
[email protected]cf442612011-08-09 20:20:12962 url_fetcher_.reset();
[email protected]e3e696d32013-06-21 20:41:36963
[email protected]7b0529242013-07-20 05:45:46964 // At this point, since both the differential and the full downloads failed,
965 // the update for this component has finished with an error.
966 ping_manager_->OnUpdateComplete(crx);
967
[email protected]32a6c8382013-08-20 00:29:20968 // Move on to the next update, if there is one available.
969 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:33970 } else {
[email protected]650b2d52013-02-10 03:41:45971 base::FilePath temp_crx_path;
[email protected]e8f96ff2011-08-03 05:07:33972 CHECK(source->GetResponseAsFilePath(true, &temp_crx_path));
[email protected]e3e696d32013-06-21 20:41:36973
974 size_t count = 0;
975 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
976 count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
977 CrxUpdateItem::kUpdatingDiff);
978 } else {
979 count = ChangeItemStatus(CrxUpdateItem::kDownloading,
980 CrxUpdateItem::kUpdating);
981 }
[email protected]e8f96ff2011-08-03 05:07:33982 DCHECK_EQ(count, 1ul);
[email protected]e3e696d32013-06-21 20:41:36983
[email protected]cf442612011-08-09 20:20:12984 url_fetcher_.reset();
985
[email protected]44da56e2011-11-21 19:59:14986 // Why unretained? See comment at top of file.
[email protected]8f5f2ea2013-10-31 09:39:10987 blocking_task_runner_->PostDelayedTask(
[email protected]73251e72012-03-04 02:10:33988 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:14989 base::Bind(&CrxUpdateService::Install,
990 base::Unretained(this),
[email protected]64f39fa12013-09-03 21:49:37991 crx_context.release(),
[email protected]44da56e2011-11-21 19:59:14992 temp_crx_path),
[email protected]73251e72012-03-04 02:10:33993 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]e8f96ff2011-08-03 05:07:33994 }
[email protected]e8f96ff2011-08-03 05:07:33995}
996
997// Install consists of digital signature verification, unpacking and then
998// calling the component specific installer. All that is handled by the
999// |unpacker|. If there is an error this function is in charge of deleting
1000// the files created.
1001void CrxUpdateService::Install(const CRXContext* context,
[email protected]650b2d52013-02-10 03:41:451002 const base::FilePath& crx_path) {
[email protected]8f5f2ea2013-10-31 09:39:101003 // This function owns the file at |crx_path| and the |context| object.
[email protected]e3e696d32013-06-21 20:41:361004 ComponentUnpacker unpacker(context->pk_hash,
1005 crx_path,
1006 context->fingerprint,
1007 component_patcher_.get(),
1008 context->installer);
[email protected]dd3aa792013-07-16 19:10:231009 if (!base::DeleteFile(crx_path, false))
[email protected]e8f96ff2011-08-03 05:07:331010 NOTREACHED() << crx_path.value();
[email protected]44da56e2011-11-21 19:59:141011 // Why unretained? See comment at top of file.
[email protected]73251e72012-03-04 02:10:331012 BrowserThread::PostDelayedTask(
1013 BrowserThread::UI,
1014 FROM_HERE,
[email protected]44da56e2011-11-21 19:59:141015 base::Bind(&CrxUpdateService::DoneInstalling, base::Unretained(this),
[email protected]e3e696d32013-06-21 20:41:361016 context->id, unpacker.error(), unpacker.extended_error()),
[email protected]73251e72012-03-04 02:10:331017 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
[email protected]07f93af12011-08-17 20:57:221018 delete context;
[email protected]e8f96ff2011-08-03 05:07:331019}
1020
1021// Installation has been completed. Adjust the component status and
[email protected]7b0529242013-07-20 05:45:461022// schedule the next check. Schedule a short delay before trying the full
1023// update when the differential update failed.
[email protected]07f93af12011-08-17 20:57:221024void CrxUpdateService::DoneInstalling(const std::string& component_id,
[email protected]e3e696d32013-06-21 20:41:361025 ComponentUnpacker::Error error,
1026 int extra_code) {
[email protected]e8f96ff2011-08-03 05:07:331027 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]07f93af12011-08-17 20:57:221028
[email protected]7b0529242013-07-20 05:45:461029 ErrorCategory error_category = kErrorNone;
1030 switch (error) {
1031 case ComponentUnpacker::kNone:
1032 break;
1033 case ComponentUnpacker::kInstallerError:
1034 error_category = kInstallError;
1035 break;
1036 default:
1037 error_category = kUnpackError;
1038 break;
1039 }
1040
1041 const bool is_success = error == ComponentUnpacker::kNone;
1042
[email protected]07f93af12011-08-17 20:57:221043 CrxUpdateItem* item = FindUpdateItemById(component_id);
[email protected]7b0529242013-07-20 05:45:461044 if (item->status == CrxUpdateItem::kUpdatingDiff && !is_success) {
1045 item->diff_error_category = error_category;
1046 item->diff_error_code = error;
1047 item->diff_extra_code1 = extra_code;
[email protected]1ea21ad2013-09-02 04:20:391048 item->diff_update_failed = true;
1049 size_t count = ChangeItemStatus(CrxUpdateItem::kUpdatingDiff,
1050 CrxUpdateItem::kCanUpdate);
1051 DCHECK_EQ(count, 1ul);
1052 ScheduleNextRun(kStepDelayShort);
1053 return;
[email protected]e3e696d32013-06-21 20:41:361054 }
[email protected]e3e696d32013-06-21 20:41:361055
[email protected]7b0529242013-07-20 05:45:461056 if (is_success) {
[email protected]61aca4cd2013-10-26 10:50:591057 ChangeItemState(item, CrxUpdateItem::kUpdated);
[email protected]07f93af12011-08-17 20:57:221058 item->component.version = item->next_version;
[email protected]e3e696d32013-06-21 20:41:361059 item->component.fingerprint = item->next_fp;
[email protected]7b0529242013-07-20 05:45:461060 } else {
[email protected]61aca4cd2013-10-26 10:50:591061 ChangeItemState(item, CrxUpdateItem::kNoUpdate);
[email protected]7b0529242013-07-20 05:45:461062 item->error_category = error_category;
1063 item->error_code = error;
1064 item->extra_code1 = extra_code;
[email protected]e3e696d32013-06-21 20:41:361065 }
[email protected]07f93af12011-08-17 20:57:221066
[email protected]7b0529242013-07-20 05:45:461067 ping_manager_->OnUpdateComplete(item);
[email protected]360b8bb2011-09-01 21:48:061068
[email protected]32a6c8382013-08-20 00:29:201069 // Move on to the next update, if there is one available.
1070 ScheduleNextRun(kStepDelayMedium);
[email protected]e8f96ff2011-08-03 05:07:331071}
1072
[email protected]85e61d52013-08-01 22:23:421073void CrxUpdateService::NotifyComponentObservers(
1074 ComponentObserver::Events event, int extra) const {
1075 for (UpdateItems::const_iterator it = work_items_.begin();
1076 it != work_items_.end(); ++it) {
1077 ComponentObserver* observer = (*it)->component.observer;
1078 if (observer)
1079 observer->OnEvent(event, 0);
1080 }
1081}
1082
[email protected]e8f96ff2011-08-03 05:07:331083// The component update factory. Using the component updater as a singleton
1084// is the job of the browser process.
1085ComponentUpdateService* ComponentUpdateServiceFactory(
1086 ComponentUpdateService::Configurator* config) {
1087 DCHECK(config);
1088 return new CrxUpdateService(config);
1089}