| Index: chrome/browser/component_updater/component_updater_service.cc
|
| ===================================================================
|
| --- chrome/browser/component_updater/component_updater_service.cc (revision 201835)
|
| +++ chrome/browser/component_updater/component_updater_service.cc (working copy)
|
| @@ -12,6 +12,7 @@
|
| #include "base/bind.h"
|
| #include "base/file_util.h"
|
| #include "base/files/file_path.h"
|
| +#include "base/guid.h"
|
| #include "base/logging.h"
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/stl_util.h"
|
| @@ -19,13 +20,16 @@
|
| #include "base/stringprintf.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/string_piece.h"
|
| +#include "base/sys_info.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 +51,26 @@
|
| // base::Bind() calls are not refcounted.
|
|
|
| namespace {
|
| +
|
| +typedef ComponentUpdateService::Configurator Config;
|
| +
|
| // 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,34 +172,81 @@
|
| 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);
|
| }
|
|
|
| +// Returns the error code which occured during the fetch. This function
|
| +// is intended to be called for logging purposes only, since it folds different
|
| +// types of errors to fit them in the returned type. The function returns 0 if
|
| +// the fetch was successful. If errors happen, the function could return a
|
| +// network error, an http response code, or the status of the fetch, if the
|
| +// fetch is pending or canceled.
|
| +int GetFetchError(const net::URLFetcher& fetcher) {
|
| + if (FetchSuccess(fetcher))
|
| + return 0;
|
| +
|
| + const net::URLRequestStatus::Status status(fetcher.GetStatus().status());
|
| + if (status == net::URLRequestStatus::FAILED)
|
| + return fetcher.GetStatus().error();
|
| +
|
| + if (status == net::URLRequestStatus::IO_PENDING ||
|
| + status == net::URLRequestStatus::CANCELED)
|
| + return status;
|
| +
|
| + const int response_code(fetcher.GetResponseCode());
|
| + if (status == net::URLRequestStatus::SUCCESS && response_code != 200)
|
| + return response_code;
|
| +
|
| + return -1;
|
| +}
|
| +
|
| +
|
| // This is the one and only per-item state structure. Designed to be hosted
|
| // in a std::vector or a std::list. The two main members are |component|
|
| // 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 -<---------+-----<-------+
|
| +// | | | |
|
| +// | 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,14 +255,56 @@
|
| };
|
|
|
| Status status;
|
| - GURL crx_url;
|
| std::string id;
|
| + CrxComponent component;
|
| +
|
| base::Time last_check;
|
| - CrxComponent component;
|
| +
|
| + // True if the update response includes an update for this component.
|
| + bool is_update_available;
|
| +
|
| + // True is a completion ping has been queued for this component. If an update
|
| + // is available for this component, one completion ping must be sent
|
| + // after the component has reached either the kNoUpdate or kUpdated states.
|
| + bool ping_queued;
|
| +
|
| + // These members are initialized with their corresponding values from the
|
| + // update server response.
|
| + GURL crx_url;
|
| + GURL diff_crx_url;
|
| + std::string package_hash;
|
| + std::string diff_package_hash;
|
| + 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;
|
|
|
| + // The error information for full and differential updates.
|
| + int error_code;
|
| + int extra_code1;
|
| + int diff_error_code;
|
| + int diff_extra_code1;
|
| +
|
| + CrxUpdateItem()
|
| + : status(kNew),
|
| + is_update_available(false),
|
| + ping_queued(false),
|
| + size(0),
|
| + diff_size(0),
|
| + diff_update_failed(false),
|
| + error_code(0),
|
| + extra_code1(0),
|
| + diff_error_code(0),
|
| + diff_extra_code1(0) {
|
| + }
|
| +
|
| // Function object used to find a specific component.
|
| class FindById {
|
| public:
|
| @@ -220,10 +318,21 @@
|
| };
|
| };
|
|
|
| +// 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();
|
| +}
|
| +
|
| +// 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 Config& config) {
|
| + return IsDiffUpdateAvailable(update_item) &&
|
| + !update_item->diff_update_failed &&
|
| + config.DeltasEnabled();
|
| +}
|
| +
|
| } // namespace.
|
|
|
| -typedef ComponentUpdateService::Configurator Config;
|
| -
|
| CrxComponent::CrxComponent()
|
| : installer(NULL),
|
| source(BANDAID) {
|
| @@ -240,7 +349,7 @@
|
| // 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
|
| @@ -299,11 +408,16 @@
|
| UpdateContext() : start(base::Time::Now()) {}
|
| };
|
|
|
| + // Context for a completion ping.
|
| + struct PingContext {
|
| + };
|
| +
|
| // Context for a crx download url request. See DelegateWithContext above.
|
| struct CRXContext {
|
| ComponentInstaller* installer;
|
| std::vector<uint8> pk_hash;
|
| std::string id;
|
| + std::string fingerprint;
|
| CRXContext() : installer(NULL) {}
|
| };
|
|
|
| @@ -313,14 +427,16 @@
|
| void OnURLFetchComplete(const net::URLFetcher* source,
|
| CRXContext* context);
|
|
|
| + void OnURLFetchComplete(const net::URLFetcher* source,
|
| + PingContext* context);
|
| +
|
| private:
|
| // See ManifestParserBridge.
|
| void OnParseUpdateManifestSucceeded(
|
| 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 +449,33 @@
|
| 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);
|
|
|
| + void SendPing(const std::string& ping);
|
| +
|
| + // These functions build a ping request. Building the ping changes the state
|
| + // of the update item to indicate that a completion ping has been collected
|
| + // and queued for this item.
|
| + std::string BuildPing() const;
|
| + std::string BuildPingApps() const;
|
| + static std::string BuildPingEvent(CrxUpdateItem* item);
|
| +
|
| scoped_ptr<Config> config_;
|
|
|
| + scoped_ptr<ComponentPatcher> component_patcher_;
|
| +
|
| scoped_ptr<net::URLFetcher> url_fetcher_;
|
|
|
| + scoped_ptr<net::URLFetcher> ping_sender_;
|
| +
|
| + // A collection of every work item.
|
| typedef std::vector<CrxUpdateItem*> UpdateItems;
|
| - // A collection of every work item.
|
| UpdateItems work_items_;
|
|
|
| // A particular set of items from work_items_, which should be checked ASAP.
|
| @@ -353,7 +483,10 @@
|
|
|
| base::OneShotTimer<CrxUpdateService> timer_;
|
|
|
| - Version chrome_version_;
|
| + const Version chrome_version_;
|
| + const std::string prod_id_;
|
| + const std::string os_type_;
|
| + const std::string os_version_;
|
|
|
| bool running_;
|
|
|
| @@ -362,10 +495,14 @@
|
|
|
| //////////////////////////////////////////////////////////////////////////////
|
|
|
| -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)),
|
| + os_type_(chrome::VersionInfo().OSType()),
|
| + os_version_(base::SysInfo().OperatingSystemVersion()),
|
| running_(false) {
|
| }
|
|
|
| @@ -418,6 +555,13 @@
|
| if (!running_)
|
| return;
|
|
|
| + if (!step_delay && config_->PingsEnabled()) {
|
| + const std::string ping(BuildPing());
|
| + if (!ping.empty()) {
|
| + SendPing(ping);
|
| + }
|
| + }
|
| +
|
| // Keep the delay short if in the middle of an update (step_delay),
|
| // or there are new requested_work_items_ that have not been processed yet.
|
| int64 delay = (step_delay || requested_work_items_.size() > 0)
|
| @@ -491,6 +635,7 @@
|
| 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.
|
| @@ -508,10 +653,23 @@
|
| 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->is_update_available = false;
|
| + item->ping_queued = false;
|
| + item->previous_version = item->component.version;
|
| + item->next_version = Version();
|
| + item->previous_fp = item->component.fingerprint;
|
| + item->next_fp = "";
|
| + item->diff_update_failed = false;
|
| + item->error_code = 0;
|
| + item->extra_code1 = 0;
|
| + item->diff_error_code = 0;
|
| + item->diff_extra_code1 = 0;
|
| return true;
|
| }
|
|
|
| @@ -544,7 +702,9 @@
|
| // 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 +743,21 @@
|
| 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;
|
| @@ -752,9 +920,16 @@
|
| }
|
| // All test passed. Queue an upgrade for this component and fire the
|
| // notifications.
|
| + crx->is_update_available = true;
|
| crx->crx_url = it->crx_url;
|
| + crx->package_hash = it->package_hash;
|
| + crx->size = it->size;
|
| + crx->diff_crx_url = it->diff_crx_url;
|
| + crx->diff_package_hash = it->diff_package_hash;
|
| + 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 +964,31 @@
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| int error_code = net::OK;
|
|
|
| + CrxUpdateItem* crx = FindUpdateItemById(context->id);
|
| +
|
| if (source->FileErrorOccurred(&error_code) || !FetchSuccess(*source)) {
|
| - size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
|
| - CrxUpdateItem::kNoUpdate);
|
| - DCHECK_EQ(count, 1ul);
|
| + if (crx->status == CrxUpdateItem::kDownloadingDiff) {
|
| + crx->diff_error_code = GetFetchError(*source);
|
| + crx->diff_update_failed = true;
|
| + crx->status = CrxUpdateItem::kCanUpdate;
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI,
|
| + FROM_HERE,
|
| + base::Bind(&CrxUpdateService::ProcessPendingItems,
|
| + base::Unretained(this)));
|
| + return;
|
| + }
|
| + crx->error_code = GetFetchError(*source);
|
| + crx->status = CrxUpdateItem::kNoUpdate;
|
| 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);
|
| - DCHECK_EQ(count, 1ul);
|
| + crx->status = (crx->status == CrxUpdateItem::kDownloadingDiff) ?
|
| + CrxUpdateItem::kUpdatingDiff : CrxUpdateItem::kUpdating;
|
| +
|
| url_fetcher_.reset();
|
|
|
| content::NotificationService::current()->Notify(
|
| @@ -829,8 +1016,11 @@
|
| 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);
|
| + 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();
|
| }
|
| @@ -839,7 +1029,7 @@
|
| 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 +1037,37 @@
|
| // 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_error_code = error;
|
| + item->diff_extra_code1 = extra_code;
|
| + item->diff_update_failed = true;
|
| + item->status = CrxUpdateItem::kCanUpdate;
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI,
|
| + FROM_HERE,
|
| + base::Bind(&CrxUpdateService::ProcessPendingItems,
|
| + base::Unretained(this)));
|
| + return;
|
| + }
|
| + }
|
| +
|
| + if (error != ComponentUnpacker::kNone) {
|
| + item->error_code = error;
|
| + item->extra_code1 = extra_code;
|
| + }
|
| +
|
| 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) {
|
| @@ -873,6 +1086,114 @@
|
| ScheduleNextRun(false);
|
| }
|
|
|
| +void CrxUpdateService::SendPing(const std::string& ping) {
|
| + VLOG(3) << "Sending ping. " << ping;
|
| + const std::string ping_url(config_->PingUrl().spec());
|
| + ping_sender_.reset(net::URLFetcher::Create(
|
| + 0, GURL(ping_url), net::URLFetcher::POST,
|
| + MakeContextDelegate(this, new PingContext())));
|
| + ping_sender_->SetUploadData(std::string("application/xml"), ping);
|
| + StartFetch(ping_sender_.get(), config_->RequestContext(), false);
|
| +}
|
| +
|
| +void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
|
| + PingContext* context) {
|
| + VLOG(3) << "Sending component update ping returned "
|
| + << FetchSuccess(*source);
|
| + ping_sender_.reset();
|
| +}
|
| +
|
| +// Builds a ping message for the update items that have completed. Returns
|
| +// an empty string if there are no completed items.
|
| +std::string CrxUpdateService::BuildPing() const {
|
| + const std::string apps(BuildPingApps());
|
| + if (apps.empty())
|
| + return std::string();
|
| +
|
| + const char response_format[] =
|
| + "<o:gupdate xmlns:o=\"http://www.google.com/update2/request\" "
|
| + "protocol=\"2.0\" version=\"%s-%s\" requestid=\"{%s}\"> "
|
| + "<o:os platform=\"%s\" version=\"%s\"/> "
|
| + "%s"
|
| + "</o:gupdate>";
|
| + const std::string response_envelope(
|
| + base::StringPrintf(response_format,
|
| + prod_id_.c_str(),
|
| + chrome_version_.GetString().c_str(),
|
| + base::GenerateGUID().c_str(),
|
| + os_type_.c_str(),
|
| + os_version_.c_str(),
|
| + apps.c_str()));
|
| + return response_envelope;
|
| +}
|
| +
|
| +// Returns a string containing the sequence of app elements inside the
|
| +// ping message.
|
| +std::string CrxUpdateService::BuildPingApps() const {
|
| + const char app_format[] = "<o:app appid=\"%s\" version=\"%s\">%s</o:app>";
|
| +
|
| + std::string ping_apps;
|
| + for (UpdateItems::const_iterator it = work_items_.begin();
|
| + it != work_items_.end(); ++it) {
|
| + CrxUpdateItem* item = *it;
|
| + // Only ping once if an update was available and the item is completed.
|
| + if (item->is_update_available && !item->ping_queued &&
|
| + (item->status == CrxUpdateItem::kNoUpdate ||
|
| + item->status == CrxUpdateItem::kUpdated)) {
|
| + const std::string version = item->component.version.GetString().c_str();
|
| + ping_apps += base::StringPrintf(app_format,
|
| + item->id.c_str(),
|
| + version.c_str(),
|
| + BuildPingEvent(item).c_str());
|
| + }
|
| + }
|
| + return ping_apps;
|
| +}
|
| +
|
| +// Returns a string representing one ping event for an update item.
|
| +std::string CrxUpdateService::BuildPingEvent(CrxUpdateItem* item) {
|
| + DCHECK(item->status == CrxUpdateItem::kNoUpdate ||
|
| + item->status == CrxUpdateItem::kUpdated);
|
| + DCHECK(item->is_update_available);
|
| +
|
| + using base::StringAppendF;
|
| +
|
| + std::string ping_event("<o:event eventtype=\"3\"");
|
| + const int event_result = item->status == CrxUpdateItem::kUpdated;
|
| + StringAppendF(&ping_event, " eventresult=\"%d\"", event_result);
|
| + StringAppendF(&ping_event, " previousversion=\"%s\"",
|
| + item->previous_version.GetString().c_str());
|
| + StringAppendF(&ping_event, " nextversion=\"%s\"",
|
| + item->next_version.GetString().c_str());
|
| + if (item->error_code) {
|
| + StringAppendF(&ping_event, " errorcode=\"%d\"", item->error_code);
|
| + }
|
| + if (item->extra_code1) {
|
| + StringAppendF(&ping_event, " extracode1=\"%d\"", item->extra_code1);
|
| + }
|
| + if (IsDiffUpdateAvailable(item)) {
|
| + StringAppendF(&ping_event, " diffresult=\"%d\"", !item->diff_update_failed);
|
| + }
|
| + if (item->diff_error_code) {
|
| + StringAppendF(&ping_event, " differrorcode=\"%d\"", item->diff_error_code);
|
| + }
|
| + if (item->diff_extra_code1) {
|
| + StringAppendF(&ping_event,
|
| + " diffextracode1=\"%d\"",
|
| + item->diff_extra_code1);
|
| + }
|
| + if (!item->previous_fp.empty()) {
|
| + StringAppendF(&ping_event, " previousfp=\"%s\"", item->previous_fp.c_str());
|
| + }
|
| + if (!item->next_fp.empty()) {
|
| + StringAppendF(&ping_event, " nextfp=\"%s\"", item->next_fp.c_str());
|
| + }
|
| + StringAppendF(&ping_event, "/>");
|
| + item->ping_queued = true;
|
| + return ping_event;
|
| +}
|
| +
|
| +
|
| // The component update factory. Using the component updater as a singleton
|
| // is the job of the browser process.
|
| ComponentUpdateService* ComponentUpdateServiceFactory(
|
|
|