diff options
Diffstat (limited to 'chrome/browser/component_updater/component_updater_service.cc')
-rw-r--r-- | chrome/browser/component_updater/component_updater_service.cc | 211 |
1 files changed, 166 insertions, 45 deletions
diff --git a/chrome/browser/component_updater/component_updater_service.cc b/chrome/browser/component_updater/component_updater_service.cc index f3eee77..367ff6e 100644 --- a/chrome/browser/component_updater/component_updater_service.cc +++ b/chrome/browser/component_updater/component_updater_service.cc @@ -10,6 +10,7 @@ #include "base/at_exit.h" #include "base/bind.h" +#include "base/compiler_specific.h" #include "base/file_util.h" #include "base/files/file_path.h" #include "base/logging.h" @@ -21,11 +22,13 @@ #include "base/strings/stringprintf.h" #include "base/timer.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/component_updater/component_patcher.h" #include "chrome/browser/component_updater/component_unpacker.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/chrome_utility_messages.h" #include "chrome/common/chrome_version_info.h" #include "chrome/common/extensions/extension.h" +#include "chrome/common/omaha_query_params/omaha_query_params.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/utility_process_host.h" @@ -47,21 +50,24 @@ using extensions::Extension; // base::Bind() calls are not refcounted. namespace { + // Manifest sources, from most important to least important. const CrxComponent::UrlSource kManifestSources[] = { CrxComponent::BANDAID, CrxComponent::CWS_PUBLIC, - CrxComponent::CWS_SANDBOX + CrxComponent::CWS_SANDBOX, }; // Extends an omaha compatible update check url |query| string. Does // not mutate the string if it would be longer than |limit| chars. bool AddQueryString(const std::string& id, const std::string& version, + const std::string& fingerprint, size_t limit, std::string* query) { std::string additional = - base::StringPrintf("id=%s&v=%s&uc", id.c_str(), version.c_str()); + base::StringPrintf("id=%s&v=%s&fp=%s&uc", + id.c_str(), version.c_str(), fingerprint.c_str()); additional = "x=" + net::EscapeQueryParamValue(additional, true); if ((additional.size() + query->size() + 1) > limit) return false; @@ -163,7 +169,7 @@ void StartFetch(net::URLFetcher* fetcher, fetcher->Start(); } -// Returs true if the url request of |fetcher| was succesful. +// Returns true if the url request of |fetcher| was succesful. bool FetchSuccess(const net::URLFetcher& fetcher) { return (fetcher.GetStatus().status() == net::URLRequestStatus::SUCCESS) && (fetcher.GetResponseCode() == 200); @@ -174,23 +180,44 @@ bool FetchSuccess(const net::URLFetcher& fetcher) { // which is supplied by the the component updater client and |status| which // is modified as the item is processed by the update pipeline. The expected // transition graph is: -// error error error -// +--kNoUpdate<------<-------+------<------+------<------+ -// | | | | -// V yes | | | -// kNew --->kChecking-->[update?]----->kCanUpdate-->kDownloading-->kUpdating -// ^ | | -// | |no | -// |--kUpToDate<---+ | -// | success | -// +--kUpdated<-------------------------------------------+ +// +// kNew +// | +// V +// +----------------------> kChecking -<---------+-----<-------+ +// | | | | +// | error V no | | +// kNoUpdate <---------------- [update?] ->---- kUpToDate kUpdated +// ^ | ^ +// | yes | | +// | diff=false V | +// | +-----------> kCanUpdate | +// | | | | +// | | V no | +// | | [differential update?]->----+ | +// | | | | | +// | | yes | | | +// | | error V | | +// | +---------<- kDownloadingDiff | | +// | | | | | +// | | | | | +// | | error V | | +// | +---------<- kUpdatingDiff ->--------|-----------+ success +// | | | +// | error V | +// +----------------------------------------- kDownloading | +// | | | +// | error V | +// +------------------------------------------ kUpdating ->----+ success // struct CrxUpdateItem { enum Status { kNew, kChecking, kCanUpdate, + kDownloadingDiff, kDownloading, + kUpdatingDiff, kUpdating, kUpdated, kUpToDate, @@ -199,13 +226,33 @@ struct CrxUpdateItem { }; Status status; - GURL crx_url; std::string id; - base::Time last_check; CrxComponent component; + + base::Time last_check; + + // These members are initialized with their corresponding values from the + // update server response. + GURL crx_url; + GURL diff_crx_url; + int size; + int diff_size; + + // The from/to version and fingerprint values. + Version previous_version; Version next_version; + std::string previous_fp; + std::string next_fp; - CrxUpdateItem() : status(kNew) {} + // True if the differential update failed for any reason. + bool diff_update_failed; + + CrxUpdateItem() + : status(kNew), + size(0), + diff_size(0), + diff_update_failed(false) { + } // Function object used to find a specific component. class FindById { @@ -220,9 +267,21 @@ struct CrxUpdateItem { }; }; -} // namespace. +// Returns true if a differential update is available for the update item. +bool IsDiffUpdateAvailable(const CrxUpdateItem* update_item) { + return update_item->diff_crx_url.is_valid(); +} -typedef ComponentUpdateService::Configurator Config; +// Returns true if a differential update is available, it has not failed yet, +// and the configuration allows it. +bool CanTryDiffUpdate(const CrxUpdateItem* update_item, + const ComponentUpdateService::Configurator& config) { + return IsDiffUpdateAvailable(update_item) && + !update_item->diff_update_failed && + config.DeltasEnabled(); +} + +} // namespace. CrxComponent::CrxComponent() : installer(NULL), @@ -240,7 +299,7 @@ CrxComponent::~CrxComponent() { // rest of the browser, so even if we have many components registered and // eligible for update, we only do one thing at a time with pauses in between // the tasks. Also when we do network requests there is only one |url_fetcher_| -// in flight at at a time. +// in flight at a time. // There are no locks in this code, the main structure |work_items_| is mutated // only from the UI thread. The unpack and installation is done in the file // thread and the network requests are done in the IO thread and in the file @@ -304,6 +363,7 @@ class CrxUpdateService : public ComponentUpdateService { ComponentInstaller* installer; std::vector<uint8> pk_hash; std::string id; + std::string fingerprint; CRXContext() : installer(NULL) {} }; @@ -319,8 +379,7 @@ class CrxUpdateService : public ComponentUpdateService { const UpdateManifest::Results& results); // See ManifestParserBridge. - void OnParseUpdateManifestFailed( - const std::string& error_message); + void OnParseUpdateManifestFailed(const std::string& error_message); bool AddItemToUpdateCheck(CrxUpdateItem* item, std::string* query); @@ -333,19 +392,22 @@ class CrxUpdateService : public ComponentUpdateService { void Install(const CRXContext* context, const base::FilePath& crx_path); void DoneInstalling(const std::string& component_id, - ComponentUnpacker::Error error); + ComponentUnpacker::Error error, + int extended_error); size_t ChangeItemStatus(CrxUpdateItem::Status from, CrxUpdateItem::Status to); CrxUpdateItem* FindUpdateItemById(const std::string& id); - scoped_ptr<Config> config_; + scoped_ptr<ComponentUpdateService::Configurator> config_; + + scoped_ptr<ComponentPatcher> component_patcher_; scoped_ptr<net::URLFetcher> url_fetcher_; - typedef std::vector<CrxUpdateItem*> UpdateItems; // A collection of every work item. + typedef std::vector<CrxUpdateItem*> UpdateItems; UpdateItems work_items_; // A particular set of items from work_items_, which should be checked ASAP. @@ -353,7 +415,8 @@ class CrxUpdateService : public ComponentUpdateService { base::OneShotTimer<CrxUpdateService> timer_; - Version chrome_version_; + const Version chrome_version_; + const std::string prod_id_; bool running_; @@ -362,10 +425,12 @@ class CrxUpdateService : public ComponentUpdateService { ////////////////////////////////////////////////////////////////////////////// -CrxUpdateService::CrxUpdateService( - ComponentUpdateService::Configurator* config) +CrxUpdateService::CrxUpdateService(ComponentUpdateService::Configurator* config) : config_(config), + component_patcher_(config->CreateComponentPatcher()), chrome_version_(chrome::VersionInfo().Version()), + prod_id_(chrome::OmahaQueryParams::GetProdIdString( + chrome::OmahaQueryParams::CHROME)), running_(false) { } @@ -450,7 +515,7 @@ CrxUpdateItem* CrxUpdateService::FindUpdateItemById(const std::string& id) { } // Changes all the components in |work_items_| that have |from| status to -// |to| statatus and returns how many have been changed. +// |to| status and returns how many have been changed. size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from, CrxUpdateItem::Status to) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); @@ -491,6 +556,7 @@ ComponentUpdateService::Status CrxUpdateService::RegisterComponent( uit = new CrxUpdateItem; uit->id.swap(id); uit->component = component; + work_items_.push_back(uit); // If this is the first component registered we call Start to // schedule the first timer. @@ -501,17 +567,24 @@ ComponentUpdateService::Status CrxUpdateService::RegisterComponent( } // Sets a component to be checked for updates. -// The componet to add is |crxit| and the |query| string is modified with the +// The component to add is |crxit| and the |query| string is modified with the // required omaha compatible query. Returns false when the query strings // is longer than specified by UrlSizeLimit(). bool CrxUpdateService::AddItemToUpdateCheck(CrxUpdateItem* item, std::string* query) { if (!AddQueryString(item->id, item->component.version.GetString(), + item->component.fingerprint, config_->UrlSizeLimit(), query)) return false; + item->status = CrxUpdateItem::kChecking; item->last_check = base::Time::Now(); + item->previous_version = item->component.version; + item->next_version = Version(); + item->previous_fp = item->component.fingerprint; + item->next_fp.clear(); + item->diff_update_failed = false; return true; } @@ -535,16 +608,17 @@ ComponentUpdateService::Status CrxUpdateService::CheckForUpdateSoon( // Check if the request is too soon. base::TimeDelta delta = base::Time::Now() - uit->last_check; - if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay())) { + if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay())) return kError; - } switch (uit->status) { // If the item is already in the process of being updated, there is // no point in this call, so return kInProgress. case CrxUpdateItem::kChecking: case CrxUpdateItem::kCanUpdate: + case CrxUpdateItem::kDownloadingDiff: case CrxUpdateItem::kDownloading: + case CrxUpdateItem::kUpdatingDiff: case CrxUpdateItem::kUpdating: return kInProgress; // Otherwise the item was already checked a while back (or it is new), @@ -583,13 +657,21 @@ void CrxUpdateService::ProcessPendingItems() { if (item->status != CrxUpdateItem::kCanUpdate) continue; // Found component to update, start the process. - item->status = CrxUpdateItem::kDownloading; CRXContext* context = new CRXContext; context->pk_hash = item->component.pk_hash; context->id = item->id; context->installer = item->component.installer; + context->fingerprint = item->next_fp; + GURL package_url; + if (CanTryDiffUpdate(item, *config_)) { + package_url = item->diff_crx_url; + item->status = CrxUpdateItem::kDownloadingDiff; + } else { + package_url = item->crx_url; + item->status = CrxUpdateItem::kDownloading; + } url_fetcher_.reset(net::URLFetcher::Create( - 0, item->crx_url, net::URLFetcher::GET, + 0, package_url, net::URLFetcher::GET, MakeContextDelegate(this, context))); StartFetch(url_fetcher_.get(), config_->RequestContext(), true); return; @@ -700,11 +782,10 @@ void CrxUpdateService::ParseManifest(const std::string& xml) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (config_->InProcess()) { UpdateManifest manifest; - if (!manifest.Parse(xml)) { + if (!manifest.Parse(xml)) CrxUpdateService::OnParseUpdateManifestFailed(manifest.errors()); - } else { + else CrxUpdateService::OnParseUpdateManifestSucceeded(manifest.results()); - } } else { UtilityProcessHost* host = UtilityProcessHost::Create(new ManifestParserBridge(this), @@ -753,8 +834,12 @@ void CrxUpdateService::OnParseUpdateManifestSucceeded( // All test passed. Queue an upgrade for this component and fire the // notifications. crx->crx_url = it->crx_url; + crx->size = it->size; + crx->diff_crx_url = it->diff_crx_url; + crx->diff_size = it->diff_size; crx->status = CrxUpdateItem::kCanUpdate; crx->next_version = Version(it->version); + crx->next_fp = it->package_fingerprint; ++update_pending; content::NotificationService::current()->Notify( @@ -789,19 +874,39 @@ void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source, DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); int error_code = net::OK; + CrxUpdateItem* crx = FindUpdateItemById(context->id); + DCHECK(crx->status == CrxUpdateItem::kDownloadingDiff || + crx->status == CrxUpdateItem::kDownloading); + if (source->FileErrorOccurred(&error_code) || !FetchSuccess(*source)) { + if (crx->status == CrxUpdateItem::kDownloadingDiff) { + size_t count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff, + CrxUpdateItem::kCanUpdate); + DCHECK_EQ(count, 1ul); + ScheduleNextRun(true); + return; + } size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading, CrxUpdateItem::kNoUpdate); DCHECK_EQ(count, 1ul); config_->OnEvent(Configurator::kNetworkError, CrxIdtoUMAId(context->id)); url_fetcher_.reset(); + ScheduleNextRun(false); } else { base::FilePath temp_crx_path; CHECK(source->GetResponseAsFilePath(true, &temp_crx_path)); - size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading, - CrxUpdateItem::kUpdating); + + size_t count = 0; + if (crx->status == CrxUpdateItem::kDownloadingDiff) { + count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff, + CrxUpdateItem::kUpdatingDiff); + } else { + count = ChangeItemStatus(CrxUpdateItem::kDownloading, + CrxUpdateItem::kUpdating); + } DCHECK_EQ(count, 1ul); + url_fetcher_.reset(); content::NotificationService::current()->Notify( @@ -829,17 +934,19 @@ void CrxUpdateService::Install(const CRXContext* context, const base::FilePath& crx_path) { // This function owns the |crx_path| and the |context| object. DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - ComponentUnpacker - unpacker(context->pk_hash, crx_path, context->installer); - if (!file_util::Delete(crx_path, false)) { + ComponentUnpacker unpacker(context->pk_hash, + crx_path, + context->fingerprint, + component_patcher_.get(), + context->installer); + if (!file_util::Delete(crx_path, false)) NOTREACHED() << crx_path.value(); - } // Why unretained? See comment at top of file. BrowserThread::PostDelayedTask( BrowserThread::UI, FROM_HERE, base::Bind(&CrxUpdateService::DoneInstalling, base::Unretained(this), - context->id, unpacker.error()), + context->id, unpacker.error(), unpacker.extended_error()), base::TimeDelta::FromMilliseconds(config_->StepDelay())); delete context; } @@ -847,14 +954,28 @@ void CrxUpdateService::Install(const CRXContext* context, // Installation has been completed. Adjust the component status and // schedule the next check. void CrxUpdateService::DoneInstalling(const std::string& component_id, - ComponentUnpacker::Error error) { + ComponentUnpacker::Error error, + int extra_code) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); CrxUpdateItem* item = FindUpdateItemById(component_id); + if (item->status == CrxUpdateItem::kUpdatingDiff) { + if (error != ComponentUnpacker::kNone) { + item->diff_update_failed = true; + size_t count = ChangeItemStatus(CrxUpdateItem::kUpdatingDiff, + CrxUpdateItem::kCanUpdate); + DCHECK_EQ(count, 1ul); + ScheduleNextRun(true); + return; + } + } + item->status = (error == ComponentUnpacker::kNone) ? CrxUpdateItem::kUpdated : CrxUpdateItem::kNoUpdate; - if (item->status == CrxUpdateItem::kUpdated) + if (item->status == CrxUpdateItem::kUpdated) { item->component.version = item->next_version; + item->component.fingerprint = item->next_fp; + } Configurator::Events event; switch (error) { |