Index: chrome/browser/component_updater/component_updater_service.cc |
diff --git a/chrome/browser/component_updater/component_updater_service.cc b/chrome/browser/component_updater/component_updater_service.cc |
index f3eee77c204791f46acb13e813f98b5b3b1f8a6b..367ff6e7d5ec326a0ca0d6807f36c76b4e5d3cd2 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) { |