blob: 3dbf5a7e0d5b3664f5fa7ea30b32db9e1c113f9b [file] [log] [blame]
[email protected]e8f96ff2011-08-03 05:07:331// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// 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>
8#include <vector>
9
10#include "base/at_exit.h"
11#include "base/file_path.h"
12#include "base/file_util.h"
13#include "base/logging.h"
14#include "base/scoped_ptr.h"
15#include "base/stl_util.h"
16#include "base/string_number_conversions.h"
17#include "base/string_util.h"
18#include "base/stringprintf.h"
19#include "base/timer.h"
20#include "chrome/browser/browser_process.h"
21#include "chrome/browser/component_updater/component_unpacker.h"
22#include "chrome/common/chrome_notification_types.h"
23#include "chrome/common/chrome_utility_messages.h"
24#include "chrome/common/chrome_version_info.h"
25#include "chrome/common/extensions/extension.h"
26#include "content/browser/utility_process_host.h"
27#include "content/common/notification_service.h"
28#include "content/common/url_fetcher.h"
29#include "googleurl/src/gurl.h"
30#include "net/base/escape.h"
31#include "net/base/load_flags.h"
32
33namespace {
34// Extends an omaha compatible update check url |query| string. Does
35// not mutate the string if it would be longer than |limit| chars.
36bool AddQueryString(std::string id, std::string version,
37 size_t limit, std::string* query) {
38 std::string additional =
39 base::StringPrintf("id=%s&v=%s&uc", id.c_str(), version.c_str());
40 additional = "x=" + EscapeQueryParamValue(additional, true);
41 if ((additional.size() + query->size() + 1) > limit)
42 return false;
43 query->append(1, query->empty()? '?' : '&');
44 query->append(additional);
45 return true;
46}
47
48// Produces an extension-like friendly |id|. This might be removed in the
49// future if we roll our on packing tools.
50static std::string HexStringToID(const std::string& hexstr) {
51 std::string id;
52 for (size_t i = 0; i < hexstr.size(); ++i) {
53 int val;
54 if (base::HexStringToInt(hexstr.begin() + i, hexstr.begin() + i + 1, &val))
55 id.append(1, val + 'a');
56 else
57 id.append(1, 'a');
58 }
59 DCHECK(Extension::IdIsValid(id));
60 return id;
61}
62
63// Helper to do version check for components.
64bool IsVersionNewer(const Version& current, const std::string& proposed) {
65 Version proposed_ver(proposed);
66 if (!proposed_ver.IsValid())
67 return false;
68 return (current.CompareTo(proposed_ver) < 0);
69}
70
71// Helper template class that allows our main class to have separate
72// OnURLFetchComplete() callbacks for diffent types of url requests
73// they are differentiated by the |Ctx| type.
74template <typename Del, typename Ctx>
75class DelegateWithContext : public URLFetcher::Delegate {
76 public:
77 DelegateWithContext(Del* delegate, Ctx* context)
78 : delegate_(delegate), context_(context) {}
79
80 virtual void OnURLFetchComplete(const URLFetcher* source) OVERRIDE {
81 delegate_->OnURLFetchComplete(source, context_);
82 delete this;
83 }
84
85 private:
86 ~DelegateWithContext() {}
87
88 Del* delegate_;
89 Ctx* context_;
90};
91// This function creates the right DelegateWithContext using template inference.
92template <typename Del, typename Ctx>
93URLFetcher::Delegate* MakeContextDelegate(Del* delegate, Ctx* context) {
94 return new DelegateWithContext<Del, Ctx>(delegate, context);
95}
96
97// Helper to start a url request using |fetcher| with the common flags.
98void StartFetch(URLFetcher* fetcher,
99 net::URLRequestContextGetter* context_getter,
100 bool save_to_file) {
101 fetcher->set_request_context(context_getter);
102 fetcher->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES |
103 net::LOAD_DO_NOT_SAVE_COOKIES |
104 net::LOAD_DISABLE_CACHE);
105 // TODO(cpu): Define our retry and backoff policy.
106 fetcher->set_automatically_retry_on_5xx(false);
107 if (save_to_file) {
108 fetcher->SaveResponseToTemporaryFile(
109 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
110 }
111 fetcher->Start();
112}
113
114// Returs true if the url request of |fetcher| was succesful.
115bool FetchSuccess(const URLFetcher& fetcher) {
116 return (fetcher.status().status() == net::URLRequestStatus::SUCCESS) &&
117 (fetcher.response_code() == 200);
118}
119
120// This is the one and only per-item state structure. Designed to be hosted
121// in a std::vector or a std::list. The two main members are |component|
122// which is supplied by the the component updater client and |status| which
123// is modified as the item is processed by the update pipeline. The expected
124// transition graph is:
125// error error error
126// +--kNoUpdate<------<-------+------<------+------<------+
127// | | | |
128// V yes | | |
129// kNew --->kChecking-->[update?]----->kCanUpdate-->kDownloading-->kUpdating
130// ^ | |
131// | |no |
132// |--kUpToDate<---+ |
133// | success |
134// +--kUpdated<-------------------------------------------+
135//
136struct CrxUpdateItem {
137 enum Status {
138 kNew,
139 kChecking,
140 kCanUpdate,
141 kDownloading,
142 kUpdating,
143 kUpdated,
144 kUpToDate,
145 kNoUpdate,
146 kLastStatus
147 };
148
149 Status status;
150 GURL crx_url;
151 std::string id;
152 base::Time last_check;
153 CrxComponent component;
154
155 CrxUpdateItem() : status(kNew) {}
156
157 // Function object used to find a specific component.
158 class FindById {
159 public:
160 explicit FindById(const std::string& id) : id_(id) {}
161
162 bool operator() (CrxUpdateItem* item) const {
163 return (item->id == id_);
164 }
165 private:
166 const std::string& id_;
167 };
168};
169
170} // namespace.
171
172typedef ComponentUpdateService::Configurator Config;
173
174CrxComponent::CrxComponent() {}
175CrxComponent::~CrxComponent() {}
176
177//////////////////////////////////////////////////////////////////////////////
178// The one and only implementation of the ComponentUpdateService interface. In
179// charge of running the show. The main method is ProcessPendingItems() which
180// is called periodically to do the updgrades/installs or the update checks.
181// An important consideration here is to be as "low impact" as we can to the
182// rest of the browser, so even if we have many components registered and
183// elegible for update, we only do one thing at a time with pauses in between
184// the tasks. Also when we do network requests there is only one |url_fetcher_|
185// in flight at at a time.
186// There are no locks in this code, the main structure |work_items_| is mutated
187// only from the UI thread. The unpack and installation is done in the file
188// thread and the network requests are done in the IO thread and in the file
189// thread.
190class CrxUpdateService : public ComponentUpdateService {
191 public:
192 explicit CrxUpdateService(ComponentUpdateService::Configurator* config);
193
194 virtual ~CrxUpdateService();
195
196 // Overrides for ComponentUpdateService.
197 virtual Status Start() OVERRIDE;
198 virtual Status Stop() OVERRIDE;
199 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE;
200
201 // The only purpose of this class is to forward the
202 // UtilityProcessHost::Client callbacks so CrxUpdateService does
203 // not have to derive from it because that is refcounted.
204 class ManifestParserBridge : public UtilityProcessHost::Client {
205 public:
206 explicit ManifestParserBridge(CrxUpdateService* service)
207 : service_(service) {}
208
209 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
210 bool handled = true;
211 IPC_BEGIN_MESSAGE_MAP(ManifestParserBridge, message)
212 IPC_MESSAGE_HANDLER(UtilityHostMsg_ParseUpdateManifest_Succeeded,
213 OnParseUpdateManifestSucceeded)
214 IPC_MESSAGE_HANDLER(UtilityHostMsg_ParseUpdateManifest_Failed,
215 OnParseUpdateManifestFailed)
216 IPC_MESSAGE_UNHANDLED(handled = false)
217 IPC_END_MESSAGE_MAP()
218 return handled;
219 }
220
221 private:
222 // Omaha update response XML was succesfuly parsed.
223 void OnParseUpdateManifestSucceeded(const UpdateManifest::Results& r) {
224 service_->OnParseUpdateManifestSucceeded(r);
225 }
226 // Omaha update response XML could not be parsed.
227 void OnParseUpdateManifestFailed(const std::string& e) {
228 service_->OnParseUpdateManifestFailed(e);
229 }
230
231 CrxUpdateService* service_;
232 DISALLOW_COPY_AND_ASSIGN(ManifestParserBridge);
233 };
234
235 // Context for a update check url request. See DelegateWithContext above.
236 struct UpdateContext {
237 base::Time start;
238 UpdateContext() : start(base::Time::Now()) {}
239 };
240
241 // Context for a crx download url request. See DelegateWithContext above.
242 struct CRXContext {
243 ComponentInstaller* installer;
244 std::vector<uint8> pk_hash;
245 std::string id;
246 CRXContext() : installer(NULL) {}
247 };
248
249 void OnURLFetchComplete(const URLFetcher* source, UpdateContext* context);
250
251 void OnURLFetchComplete(const URLFetcher* source, CRXContext* context);
252
253 private:
254 // See ManifestParserBridge.
255 void OnParseUpdateManifestSucceeded(
256 const UpdateManifest::Results& results);
257
258 // See ManifestParserBridge.
259 void OnParseUpdateManifestFailed(
260 const std::string& error_message);
261
262 bool AddItemToUpdateCheck(CrxUpdateItem* item, std::string* query);
263
264 void ProcessPendingItems();
265
266 void ScheduleNextRun(bool step_delay);
267
268 void ParseManifest(const std::string& xml);
269
270 void Install(const CRXContext* context, const FilePath& crx_path);
271
272 void DoneInstalling(ComponentUnpacker::Error error);
273
274 size_t ChangeItemStatus(CrxUpdateItem::Status from,
275 CrxUpdateItem::Status to);
276
277 CrxUpdateItem* FindUpdateItemById(const std::string& id);
278
279 scoped_ptr<Config> config_;
280
281 scoped_ptr<URLFetcher> url_fetcher_;
282
283 typedef std::vector<CrxUpdateItem*> UpdateItems;
284 UpdateItems work_items_;
285
286 base::OneShotTimer<CrxUpdateService> timer_;
287
288 Version chrome_version_;
289
290 bool running_;
291
292 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
293};
294
295// The component updater is designed to live until process shutdown, besides
296// we can't be refcounted because we are a singleton.
297DISABLE_RUNNABLE_METHOD_REFCOUNT(CrxUpdateService);
298
299//////////////////////////////////////////////////////////////////////////////
300
301CrxUpdateService::CrxUpdateService(
302 ComponentUpdateService::Configurator* config)
303 : config_(config),
304 chrome_version_(chrome::VersionInfo().Version()),
305 running_(false) {
306}
307
308CrxUpdateService::~CrxUpdateService() {
309 // Because we are a singleton, at this point only the UI thread should be
310 // alive, this simplifies the management of the work that could be in
311 // flight in other threads.
312 Stop();
313 STLDeleteElements(&work_items_);
314}
315
316ComponentUpdateService::Status CrxUpdateService::Start() {
317 // Note that RegisterComponent will call Start() when the first
318 // component is registered, so it can be called twice. This way
319 // we avoid scheduling the timer if there is no work to do.
320 running_ = true;
321 if (work_items_.empty())
322 return kOk;
323
324 NotificationService::current()->Notify(
325 chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED,
326 Source<ComponentUpdateService>(this),
327 NotificationService::NoDetails());
328
329 timer_.Start(base::TimeDelta::FromSeconds(config_->InitialDelay()),
330 this, &CrxUpdateService::ProcessPendingItems);
331 return kOk;
332}
333
334// Stop the main check + update loop. In flight operations will be
335// completed.
336ComponentUpdateService::Status CrxUpdateService::Stop() {
337 running_ = false;
338 timer_.Stop();
339 return kOk;
340}
341
342// This function sets the timer which will call ProcessPendingItems() there
343// are two kind of waits, the short one (with step_delay = true) and the
344// long one.
345void CrxUpdateService::ScheduleNextRun(bool step_delay) {
346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
347 CHECK(!timer_.IsRunning());
348 // It could be the case that Stop() had been called while a url request
349 // or unpacking was in flight, if so we arrive here but |running_| is
350 // false. In that case do not loop again.
351 if (!running_)
352 return;
353
354 if (!step_delay) {
355 NotificationService::current()->Notify(
356 chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING,
357 Source<ComponentUpdateService>(this),
358 NotificationService::NoDetails());
359 // Zero is only used for unit tests.
360 if (0 == config_->NextCheckDelay())
361 return;
362 }
363
364 int64 delay = step_delay ? config_->StepDelay() : config_->NextCheckDelay();
365 timer_.Start(base::TimeDelta::FromSeconds(delay),
366 this, &CrxUpdateService::ProcessPendingItems);
367}
368
369// Given a extension-like component id, find the associated component.
370CrxUpdateItem* CrxUpdateService::FindUpdateItemById(const std::string& id) {
371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
372 CrxUpdateItem::FindById finder(id);
373 UpdateItems::iterator it = std::find_if(work_items_.begin(),
374 work_items_.end(),
375 finder);
376 if (it == work_items_.end())
377 return NULL;
378 return (*it);
379}
380
381// Changes all the components in |work_items_| that have |from| status to
382// |to| statatus and returns how many have been changed.
383size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from,
384 CrxUpdateItem::Status to) {
385 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
386 size_t count = 0;
387 for (UpdateItems::iterator it = work_items_.begin();
388 it != work_items_.end(); ++it) {
389 CrxUpdateItem* item = *it;
390 if (item->status != from)
391 continue;
392 item->status = to;
393 ++count;
394 }
395 return count;
396}
397
398// Adds a component to be checked for upgrades. If the component exists it
399// it will be replaced and the return code is kReplaced.
400//
401// TODO(cpu): Evaluate if we want to support un-registration.
402ComponentUpdateService::Status CrxUpdateService::RegisterComponent(
403 const CrxComponent& component) {
404 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
405 if (component.pk_hash.empty() ||
406 !component.version.IsValid() ||
407 !component.installer)
408 return kError;
409
410 std::string id =
411 HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
412 component.pk_hash.size()/2)));
413 CrxUpdateItem* uit;
414 uit = FindUpdateItemById(id);
415 if (uit) {
416 uit->component = component;
417 return kReplaced;
418 }
419
420 uit = new CrxUpdateItem;
421 uit->id.swap(id);
422 uit->component = component;
423 work_items_.push_back(uit);
424 // If this is the first component registered we call Start to
425 // schedule the first timer.
426 if (running_ && (work_items_.size() == 1))
427 Start();
428
429 return kOk;
430}
431
432// Sets a component to be checked for updates.
433// The componet to add is |crxit| and the |query| string is modified with the
434// required omaha compatible query. Returns false when the query strings
435// is longer than specified by UrlSizeLimit().
436bool CrxUpdateService::AddItemToUpdateCheck(CrxUpdateItem* item,
437 std::string* query) {
438 if (!AddQueryString(item->id,
439 item->component.version.GetString(),
440 config_->UrlSizeLimit(), query))
441 return false;
442 item->status = CrxUpdateItem::kChecking;
443 item->last_check = base::Time::Now();
444 return true;
445}
446
447// Here is where the work gets scheduled. Given that our |work_items_| list
448// is expected to be ten or less items, we simply loop several times.
449void CrxUpdateService::ProcessPendingItems() {
450 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
451 // First check for ready upgrades and do one. The first
452 // step is to fetch the crx package.
453 for (UpdateItems::const_iterator it = work_items_.begin();
454 it != work_items_.end(); ++it) {
455 CrxUpdateItem* item = *it;
456 if (item->status != CrxUpdateItem::kCanUpdate)
457 continue;
458 // Found component to update, start the process.
459 item->status = CrxUpdateItem::kDownloading;
460 CRXContext* context = new CRXContext;
461 context->pk_hash = item->component.pk_hash;
462 context->id = item->id;
463 context->installer = item->component.installer;
464 url_fetcher_.reset(URLFetcher::Create(0, item->crx_url, URLFetcher::GET,
465 MakeContextDelegate(this, context)));
466 StartFetch(url_fetcher_.get(), config_->RequestContext(), true);
467 return;
468 }
469
470 std::string query;
471 // If no pending upgrades, we check the if there are new
472 // components we have not checked against the server. We
473 // can batch a bunch in a single url request.
474 for (UpdateItems::const_iterator it = work_items_.begin();
475 it != work_items_.end(); ++it) {
476 CrxUpdateItem* item = *it;
477 if (item->status != CrxUpdateItem::kNew)
478 continue;
479 if (!AddItemToUpdateCheck(item, &query))
480 break;
481 }
482
483 // Next we can go back to components we already checked, here
484 // we can also batch them in a single url request, as long as
485 // we have not checked them recently.
486 base::TimeDelta min_delta_time =
487 base::TimeDelta::FromSeconds(config_->MinimumReCheckWait());
488
489 for (UpdateItems::const_iterator it = work_items_.begin();
490 it != work_items_.end(); ++it) {
491 CrxUpdateItem* item = *it;
492 if ((item->status != CrxUpdateItem::kNoUpdate) ||
493 (item->status != CrxUpdateItem::kUpToDate))
494 continue;
495 base::TimeDelta delta = base::Time::Now() - item->last_check;
496 if (delta < min_delta_time)
497 continue;
498 if (!AddItemToUpdateCheck(item, &query))
499 break;
500 }
501 // Finally, we check components that we already updated.
502 for (UpdateItems::const_iterator it = work_items_.begin();
503 it != work_items_.end(); ++it) {
504 CrxUpdateItem* item = *it;
505 if (item->status != CrxUpdateItem::kUpdated)
506 continue;
507 base::TimeDelta delta = base::Time::Now() - item->last_check;
508 if (delta < min_delta_time)
509 continue;
510 if (!AddItemToUpdateCheck(item, &query))
511 break;
512 }
513
514 if (query.empty()) {
515 // Next check after the long sleep.
516 ScheduleNextRun(false);
517 return;
518 }
519
520 // We got components to check. Start the url request.
521 GURL url(config_->UpdateUrl().spec() + query);
522 url_fetcher_.reset(URLFetcher::Create(0, url, URLFetcher::GET,
523 MakeContextDelegate(this, new UpdateContext())));
524 StartFetch(url_fetcher_.get(), config_->RequestContext(), false);
525}
526
527// Caled when we got a response from the update server. It consists of an xml
528// document following the omaha update scheme.
529void CrxUpdateService::OnURLFetchComplete(const URLFetcher* source,
530 UpdateContext*) {
531 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
532 if (FetchSuccess(*source)) {
533 std::string xml;
534 source->GetResponseAsString(&xml);
535 ParseManifest(xml);
536 } else {
537 CrxUpdateService::OnParseUpdateManifestFailed("network error");
538 }
539 url_fetcher_.reset();
540}
541
542// Parsing the manifest is either done right now for tests or in a sandboxed
543// process for the production environment. This mitigates the case where an
544// attacker was able to feed us a malicious xml string.
545void CrxUpdateService::ParseManifest(const std::string& xml) {
546 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
547 if (config_->InProcess()) {
548 UpdateManifest manifest;
549 if (!manifest.Parse(xml)) {
550 CrxUpdateService::OnParseUpdateManifestFailed(manifest.errors());
551 } else {
552 CrxUpdateService::OnParseUpdateManifestSucceeded(manifest.results());
553 }
554 } else {
555 UtilityProcessHost* host =
556 new UtilityProcessHost(new ManifestParserBridge(this),
557 BrowserThread::UI);
558 host->Send(new UtilityMsg_ParseUpdateManifest(xml));
559 }
560}
561
562// A valid Omaha update check has arrived, from only the list of components that
563// we are currently upgrading we check for a match in which the server side
564// version is newer, if so we queue them for an upgrade. The next time we call
565// ProcessPendingItems() one of them will be drafted for the upgrade process.
566void CrxUpdateService::OnParseUpdateManifestSucceeded(
567 const UpdateManifest::Results& results) {
568 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
569 int update_pending = 0;
570 std::vector<UpdateManifest::Result>::const_iterator it;
571 for (it = results.list.begin(); it != results.list.end(); ++it) {
572 CrxUpdateItem* crx = FindUpdateItemById(it->extension_id);
573 if (!crx)
574 continue;
575
576 if (crx->status != CrxUpdateItem::kChecking)
577 continue; // Not updating this component now.
578
579 if (it->version.empty()) {
580 crx->status = CrxUpdateItem::kNoUpdate;
581 continue; // No version means no update available.
582 }
583 if (!IsVersionNewer(crx->component.version, it->version)) {
584 crx->status = CrxUpdateItem::kUpToDate;
585 continue; // Our component is up to date.
586 }
587 if (!it->browser_min_version.empty()) {
588 if (IsVersionNewer(chrome_version_, it->browser_min_version))
589 continue; // Does not apply for this version.
590 }
591 // All test passed. Queue an upgrade for this component and fire the
592 // notifications.
593 crx->crx_url = it->crx_url;
594 crx->status = CrxUpdateItem::kCanUpdate;
595 ++update_pending;
596
597 NotificationService::current()->Notify(
598 chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND,
599 Source<std::string>(&crx->id),
600 NotificationService::NoDetails());
601 }
602 // If there are updates pending we do a short wait.
603 ScheduleNextRun(update_pending ? true : false);
604}
605
606void CrxUpdateService::OnParseUpdateManifestFailed(
607 const std::string& error_message) {
608 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
609 size_t count = ChangeItemStatus(CrxUpdateItem::kChecking,
610 CrxUpdateItem::kNoUpdate);
611 DCHECK_GT(count, 0ul);
612 ScheduleNextRun(false);
613}
614
615// Called when the CRX package has been downloaded to a temporary location.
616// Here we fire the notifications and schedule the component-specific installer
617// to be called in the file thread.
618void CrxUpdateService::OnURLFetchComplete(const URLFetcher* source,
619 CRXContext* context) {
620 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
621 base::PlatformFileError error_code;
622
623 if (source->FileErrorOccurred(&error_code) || !FetchSuccess(*source)) {
624 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
625 CrxUpdateItem::kNoUpdate);
626 DCHECK_EQ(count, 1ul);
627 ScheduleNextRun(false);
628 } else {
629 FilePath temp_crx_path;
630 CHECK(source->GetResponseAsFilePath(true, &temp_crx_path));
631 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
632 CrxUpdateItem::kUpdating);
633 DCHECK_EQ(count, 1ul);
634 NotificationService::current()->Notify(
635 chrome::NOTIFICATION_COMPONENT_UPDATE_READY,
636 Source<std::string>(&context->id),
637 NotificationService::NoDetails());
638
639 BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE,
640 NewRunnableMethod(this, &CrxUpdateService::Install,
641 context,
642 temp_crx_path),
643 config_->StepDelay());
644 }
645
646 url_fetcher_.reset();
647}
648
649// Install consists of digital signature verification, unpacking and then
650// calling the component specific installer. All that is handled by the
651// |unpacker|. If there is an error this function is in charge of deleting
652// the files created.
653void CrxUpdateService::Install(const CRXContext* context,
654 const FilePath& crx_path) {
655 // This function owns the |crx_path| and the |context| object.
656 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
657 ComponentUnpacker
658 unpacker(context->pk_hash, crx_path, context->installer);
659 delete context;
660 if (!file_util::Delete(crx_path, false)) {
661 NOTREACHED() << crx_path.value();
662 }
663
664 BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
665 NewRunnableMethod(this, &CrxUpdateService::DoneInstalling,
666 unpacker.error()),
667 config_->StepDelay());
668}
669
670// Installation has been completed. Adjust the component status and
671// schedule the next check.
672void CrxUpdateService::DoneInstalling(ComponentUnpacker::Error error) {
673 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
674 CrxUpdateItem::Status status =
675 (error == ComponentUnpacker::kNone) ? CrxUpdateItem::kUpdated :
676 CrxUpdateItem::kNoUpdate;
677 size_t count = ChangeItemStatus(CrxUpdateItem::kUpdating, status);
678 DCHECK_EQ(count, 1ul);
679 ScheduleNextRun(false);
680}
681
682// The component update factory. Using the component updater as a singleton
683// is the job of the browser process.
684ComponentUpdateService* ComponentUpdateServiceFactory(
685 ComponentUpdateService::Configurator* config) {
686 DCHECK(config);
687 return new CrxUpdateService(config);
688}
689