diff options
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/extensions/extension_prefs.cc | 31 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_prefs.h | 10 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_updater.cc | 339 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_updater.h | 100 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_updater_unittest.cc | 127 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service.cc | 12 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service.h | 11 | ||||
-rw-r--r-- | chrome/browser/utility_process_host.h | 2 | ||||
-rw-r--r-- | chrome/common/extensions/update_manifest.cc | 24 | ||||
-rw-r--r-- | chrome/common/extensions/update_manifest.h | 18 | ||||
-rw-r--r-- | chrome/common/extensions/update_manifest_unittest.cc | 38 | ||||
-rw-r--r-- | chrome/common/utility_messages.h | 20 | ||||
-rw-r--r-- | chrome/common/utility_messages_internal.h | 2 |
13 files changed, 506 insertions, 228 deletions
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc index af58426..6d92ad2 100644 --- a/chrome/browser/extensions/extension_prefs.cc +++ b/chrome/browser/extensions/extension_prefs.cc @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/extensions/extension_prefs.h" - #include "base/string_util.h" +#include "chrome/browser/extensions/extension_prefs.h" #include "chrome/common/extensions/extension.h" +using base::Time; + namespace { // Preferences keys @@ -44,6 +45,10 @@ const wchar_t kExtensionShelf[] = L"extensions.shelf"; // object stored in the Preferences file. The extensions are stored by ID. const wchar_t kExtensionToolbar[] = L"extensions.toolbar"; +// The key for a serialized Time value indicating the start of the day (from the +// server's perspective) an extension last included a "ping" parameter during +// its update check. +const wchar_t kLastPingDay[] = L"lastpingday"; } //////////////////////////////////////////////////////////////////////////////// @@ -231,6 +236,28 @@ void ExtensionPrefs::UpdateBlacklist( return; } +Time ExtensionPrefs::LastPingDay(const std::string& extension_id) { + DictionaryValue* dictionary = GetExtensionPref(extension_id); + if (dictionary && dictionary->HasKey(kLastPingDay)) { + std::string string_value; + int64 value; + dictionary->GetString(kLastPingDay, &string_value); + if (StringToInt64(string_value, &value)) { + return Time::FromInternalValue(value); + } + } + return Time(); +} + +void ExtensionPrefs::SetLastPingDay(const std::string& extension_id, + const Time& time) { + std::string value = Int64ToString(time.ToInternalValue()); + UpdateExtensionPref(extension_id, kLastPingDay, + Value::CreateStringValue(value)); + prefs_->ScheduleSavePersistentPrefs(); +} + + void ExtensionPrefs::GetKilledExtensionIds(std::set<std::string>* killed_ids) { const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref); if (!dict || dict->empty()) diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h index e976b53..d8d3694 100644 --- a/chrome/browser/extensions/extension_prefs.h +++ b/chrome/browser/extensions/extension_prefs.h @@ -11,6 +11,7 @@ #include "base/linked_ptr.h" #include "base/task.h" +#include "base/time.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/pref_service.h" #include "googleurl/src/gurl.h" @@ -85,6 +86,15 @@ class ExtensionPrefs { // Did the extension ask to escalate its permission during an upgrade? bool DidExtensionEscalatePermissions(const std::string& id); + // Returns the last value set via SetLastPingDay. If there isn't such a + // pref, the returned Time will return true for is_null(). + base::Time LastPingDay(const std::string& extension_id); + + // The time stored is based on the server's perspective of day start time, not + // the client's. + void SetLastPingDay(const std::string& extension_id, const base::Time& time); + + // Saves ExtensionInfo for each installed extension with the path to the // version directory and the location. Blacklisted extensions won't be saved // and neither will external extensions the user has explicitly uninstalled. diff --git a/chrome/browser/extensions/extension_updater.cc b/chrome/browser/extensions/extension_updater.cc index da55735..7567039 100644 --- a/chrome/browser/extensions/extension_updater.cc +++ b/chrome/browser/extensions/extension_updater.cc @@ -11,8 +11,8 @@ #include "base/file_util.h" #include "base/file_version_info.h" #include "base/rand_util.h" -#include "base/scoped_vector.h" #include "base/sha2.h" +#include "base/stl_util-inl.h" #include "base/string_util.h" #include "base/time.h" #include "base/thread.h" @@ -54,8 +54,6 @@ const char* ExtensionUpdater::kBlacklistUpdateUrl = // Update AppID for extension blacklist. const char* ExtensionUpdater::kBlacklistAppID = "com.google.crx.blacklist"; -const char* ExtensionUpdater::kUidKey = "uid"; - // Wait at least 5 minutes after browser startup before we do any checks. If you // change this value, make sure to update comments where it is used. const int kStartupWaitSeconds = 60 * 5; @@ -64,6 +62,82 @@ const int kStartupWaitSeconds = 60 * 5; static const int kMinUpdateFrequencySeconds = 30; static const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days +// Maximum length of an extension manifest update check url, since it is a GET +// request. We want to stay under 2K because of proxies, etc. +static const int kExtensionsManifestMaxURLSize = 2000; + + +// The format for request parameters in update checks is: +// +// ?x=EXT1_INFO&x=EXT2_INFO +// +// where EXT1_INFO and EXT2_INFO are url-encoded strings of the form: +// +// id=EXTENSION_ID&v=VERSION&uc +// +// Additionally, we may include the parameter ping=PING_DATA where PING_DATA +// looks like r=DAYS for extensions in the Chrome extensions gallery. This value +// will be present at most once every 24 hours, and indicate the number of days +// since the last time it was present in an update check. +// +// So for two extensions like: +// Extension 1- id:aaaa version:1.1 +// Extension 2- id:bbbb version:2.0 +// +// the full update url would be: +// http://somehost/path?x=id%3Daaaa%26v%3D1.1%26uc&x=id%3Dbbbb%26v%3D2.0%26uc +// +// (Note that '=' is %3D and '&' is %26 when urlencoded.) +bool ManifestFetchData::AddExtension(std::string id, std::string version, + int days) { + if (extension_ids_.find(id) != extension_ids_.end()) { + NOTREACHED() << "Duplicate extension id " << id; + return false; + } + + // Compute the string we'd append onto the full_url_, and see if it fits. + std::vector<std::string> parts; + parts.push_back("id=" + id); + parts.push_back("v=" + version); + parts.push_back("uc"); + + if (ShouldPing(days)) { + parts.push_back("ping=" + EscapeQueryParamValue("r=" + IntToString(days), + true)); + } + + std::string extra = full_url_.has_query() ? "&" : "?"; + extra += "x=" + EscapeQueryParamValue(JoinString(parts, '&'), true); + + // Check against our max url size, exempting the first extension added. + int new_size = full_url_.possibly_invalid_spec().size() + extra.size(); + if (extension_ids_.size() > 0 && new_size > kExtensionsManifestMaxURLSize) { + UMA_HISTOGRAM_PERCENTAGE("Extensions.UpdateCheckHitUrlSizeLimit", 1); + return false; + } + UMA_HISTOGRAM_PERCENTAGE("Extensions.UpdateCheckHitUrlSizeLimit", 0); + + // We have room so go ahead and add the extension. + extension_ids_.insert(id); + ping_days_[id] = days; + full_url_ = GURL(full_url_.possibly_invalid_spec() + extra); + return true; +} + +bool ManifestFetchData::DidPing(std::string extension_id) const { + std::map<std::string, int>::const_iterator i = ping_days_.find(extension_id); + if (i != ping_days_.end()) { + return ShouldPing(i->second); + } + return false; +} + +bool ManifestFetchData::ShouldPing(int days) const { + return base_url_.DomainIs("google.com") && + (days == kNeverPinged || days > 0); +} + + // A utility class to do file handling on the file I/O thread. class ExtensionUpdaterFileHandler : public base::RefCountedThreadSafe<ExtensionUpdaterFileHandler> { @@ -110,55 +184,12 @@ class ExtensionUpdaterFileHandler ~ExtensionUpdaterFileHandler() {} }; -class DefaultUidProvider : public ExtensionUpdater::UidProvider { - public: - DefaultUidProvider() {} - virtual ~DefaultUidProvider() {} - - virtual std::string GetUidString() { - std::string result; -#if defined(OS_WIN) - // First try looking in HKCU, then try HKLM. - HKEY rootKeys[] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }; - for (int i = 0; i < sizeof(rootKeys); i++) { - RegKey key(rootKeys[i], L"Software\\Google\\Update"); - std::wstring value; - if (key.ReadValue(L"ui", &value)) { - if (IsStringASCII(value) && - value.length() <= UidProvider::maxUidLength) { - result = WideToASCII(value); - break; - } else { - NOTREACHED(); - } - } - } -#elif defined(OS_MACOSX) - CFStringRef guid = (CFStringRef) - CFPreferencesCopyAppValue(CFSTR("GUID"), - CFSTR("com.google.Keystone.Agent")); - if (guid) { - std::string value = base::SysCFStringRefToUTF8(guid); - if (IsStringASCII(value) && - value.length() <= UidProvider::maxUidLength) { - result = value; - } else { - NOTREACHED(); - } - CFRelease(guid); - } -#endif - return result; - } -}; - - ExtensionUpdater::ExtensionUpdater(ExtensionUpdateService* service, PrefService* prefs, int frequency_seconds) : service_(service), frequency_seconds_(frequency_seconds), prefs_(prefs), file_handler_(new ExtensionUpdaterFileHandler()), - blacklist_checks_enabled_(true), uid_provider_(new DefaultUidProvider()) { + blacklist_checks_enabled_(true) { Init(); } @@ -172,7 +203,9 @@ void ExtensionUpdater::Init() { frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds); } -ExtensionUpdater::~ExtensionUpdater() {} +ExtensionUpdater::~ExtensionUpdater() { + STLDeleteElements(&manifests_pending_); +} static void EnsureInt64PrefRegistered(PrefService* prefs, const wchar_t name[]) { @@ -261,8 +294,11 @@ void ExtensionUpdater::OnURLFetchComplete( // Utility class to handle doing xml parsing in a sandboxed utility process. class SafeManifestParser : public UtilityProcessHost::Client { public: - SafeManifestParser(const std::string& xml, ExtensionUpdater* updater) + // Takes ownership of |fetch_data|. + SafeManifestParser(const std::string& xml, ManifestFetchData* fetch_data, + ExtensionUpdater* updater) : xml_(xml), updater_(updater) { + fetch_data_.reset(fetch_data); } // Posts a task over to the IO loop to start the parsing of xml_ in a @@ -308,9 +344,9 @@ class SafeManifestParser : public UtilityProcessHost::Client { // Callback from the utility process when parsing succeeded. virtual void OnParseUpdateManifestSucceeded( - const UpdateManifest::ResultList& list) { + const UpdateManifest::Results& results) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - updater_->HandleManifestResults(list); + updater_->HandleManifestResults(*fetch_data_, results); } // Callback from the utility process when parsing failed. @@ -323,6 +359,7 @@ class SafeManifestParser : public UtilityProcessHost::Client { ~SafeManifestParser() {} const std::string& xml_; + scoped_ptr<ManifestFetchData> fetch_data_; scoped_refptr<ExtensionUpdater> updater_; }; @@ -336,7 +373,7 @@ void ExtensionUpdater::OnManifestFetchComplete(const GURL& url, // available, we want to fire off requests to fetch those updates. if (status.status() == URLRequestStatus::SUCCESS && response_code == 200) { scoped_refptr<SafeManifestParser> safe_parser = - new SafeManifestParser(data, this); + new SafeManifestParser(data, current_manifest_fetch_.release(), this); safe_parser->Start(); } else { // TODO(asargent) Do exponential backoff here. (http://crbug.com/12546). @@ -344,23 +381,44 @@ void ExtensionUpdater::OnManifestFetchComplete(const GURL& url, "' response code:" << response_code; } manifest_fetcher_.reset(); + current_manifest_fetch_.reset(); // If we have any pending manifest requests, fire off the next one. if (!manifests_pending_.empty()) { - GURL url = manifests_pending_.front(); + ManifestFetchData* manifest_fetch = manifests_pending_.front(); manifests_pending_.pop_front(); - StartUpdateCheck(url); + StartUpdateCheck(manifest_fetch); } } void ExtensionUpdater::HandleManifestResults( - const UpdateManifest::ResultList& results) { - std::vector<int> updates = DetermineUpdates(results); + const ManifestFetchData& fetch_data, + const UpdateManifest::Results& results) { + + // Examine the parsed manifest and kick off fetches of any new crx files. + std::vector<int> updates = DetermineUpdates(fetch_data, results); for (size_t i = 0; i < updates.size(); i++) { - const UpdateManifest::Result* update = &(results.at(updates[i])); + const UpdateManifest::Result* update = &(results.list.at(updates[i])); FetchUpdatedExtension(update->extension_id, update->crx_url, update->package_hash, update->version); } + + // If the manifest response included a <daystart> element, we want to save + // that value for any extensions which had sent ping_days in the request. + if (fetch_data.base_url().DomainIs("google.com") && + results.daystart_elapsed_seconds >= 0) { + Time daystart = + Time::Now() - TimeDelta::FromSeconds(results.daystart_elapsed_seconds); + + const std::set<std::string>& extension_ids = fetch_data.extension_ids(); + std::set<std::string>::const_iterator i; + for (i = extension_ids.begin(); i != extension_ids.end(); i++) { + bool did_ping = fetch_data.DidPing(*i); + if (did_ping && service_->GetExtensionById(*i, true)) { + service_->SetLastPingDay(*i, daystart); + } + } + } } void ExtensionUpdater::ProcessBlacklist(const std::string& data) { @@ -440,49 +498,6 @@ void ExtensionUpdater::OnExtensionInstallFinished(const FilePath& path, file_handler_.get(), &ExtensionUpdaterFileHandler::DeleteFile, path)); } - -// Helper function for building up request parameters in update check urls. It -// appends information about one extension to a request parameter string. The -// format for request parameters in update checks is: -// -// ?x=EXT1_INFO&x=EXT2_INFO -// -// where EXT1_INFO and EXT2_INFO are url-encoded strings of the form: -// -// id=EXTENSION_ID&v=VERSION&uc -// -// So for two extensions like: -// Extension 1- id:aaaa version:1.1 -// Extension 2- id:bbbb version:2.0 -// -// the full update url would be: -// http://somehost/path?x=id%3Daaaa%26v%3D1.1%26uc&x=id%3Dbbbb%26v%3D2.0%26uc -// -// (Note that '=' is %3D and '&' is %26 when urlencoded.) -// -// Again, this function would just append one extension's worth of data, e.g. -// "x=id%3Daaaa%26v%3D1.1%26uc" -void AppendExtensionInfo(std::string* str, const Extension& extension) { - const Version* version = extension.version(); - DCHECK(version); - std::vector<std::string> parts; - - // Push extension id, version, and uc (indicates an update check to Omaha). - parts.push_back("id=" + extension.id()); - parts.push_back("v=" + version->GetString()); - parts.push_back("uc"); - - str->append("x=" + EscapeQueryParamValue(JoinString(parts, '&'), true)); -} - -// Creates a blacklist update url. -GURL ExtensionUpdater::GetBlacklistUpdateUrl(const std::wstring& version) { - std::string blklist_info = StringPrintf("id=%s&v=%s&uc", kBlacklistAppID, - WideToASCII(version).c_str()); - return GURL(StringPrintf("%s?x=%s", kBlacklistUpdateUrl, - EscapeQueryParamValue(blklist_info, true).c_str())); -} - void ExtensionUpdater::ScheduleNextCheck(const TimeDelta& target_delay) { DCHECK(!timer_.IsRunning()); DCHECK(target_delay >= TimeDelta::FromSeconds(1)); @@ -527,13 +542,11 @@ void ExtensionUpdater::TimerFired() { } void ExtensionUpdater::CheckNow() { - // Generate a set of update urls for loaded extensions. - std::set<GURL> urls; - - if (blacklist_checks_enabled_ && service_->HasInstalledExtensions()) { - urls.insert(GetBlacklistUpdateUrl( - prefs_->GetString(kExtensionBlacklistUpdateVersion))); - } + // List of data on fetches we're going to do. We limit the number of + // extensions grouped together in one batch to avoid running into the limits + // on the length of http GET requests, so there might be multiple + // ManifestFetchData* objects with the same base_url. + std::multimap<GURL, ManifestFetchData*> fetches; int no_url_count = 0; int google_url_count = 0; @@ -545,9 +558,9 @@ void ExtensionUpdater::CheckNow() { iter != extensions->end(); ++iter) { Extension* extension = (*iter); const GURL& update_url = extension->update_url(); - const std::string google_suffix = ".google.com"; - size_t suffix_index = update_url.host().length() - google_suffix.length(); - if (update_url.host().find(google_suffix) == suffix_index) { + + // Collect histogram data and skip extensions with no update url. + if (update_url.DomainIs("google.com")) { google_url_count++; } else if (update_url.is_empty() || extension->id().empty()) { // TODO(asargent) when a default URL is added, make sure to update @@ -563,36 +576,49 @@ void ExtensionUpdater::CheckNow() { theme_count++; DCHECK(update_url.is_valid()); - DCHECK(!update_url.has_ref()); - // Append extension information to the url. - std::string full_url_string = update_url.spec(); - full_url_string.append(update_url.has_query() ? "&" : "?"); - AppendExtensionInfo(&full_url_string, *extension); - - // Send the Omaha uid when doing update checks to Omaha. - if (update_url.DomainIs("google.com")) { - std::string uid = uid_provider_->GetUidString(); - if (uid.length() > 0 && uid.length() <= UidProvider::maxUidLength) { - full_url_string.append("&" + std::string(ExtensionUpdater::kUidKey) + - "=" + EscapeQueryParamValue(uid, true)); + ManifestFetchData* fetch = NULL; + std::multimap<GURL, ManifestFetchData*>::iterator existing_iter = + fetches.find(update_url); + + // Find or create a ManifestFetchData to add this extension to. + std::string id = extension->id(); + std::string version = extension->VersionString(); + int ping_days = CalculatePingDays(extension->id()); + while (existing_iter != fetches.end()) { + if (existing_iter->second->AddExtension(id, version, ping_days)) { + fetch = existing_iter->second; + break; } + existing_iter++; } - - GURL full_url(full_url_string); - if (!full_url.is_valid()) { - LOG(ERROR) << "invalid url: " << full_url.possibly_invalid_spec(); - NOTREACHED(); - } else { - urls.insert(full_url); + if (!fetch) { + fetch = new ManifestFetchData(update_url); + fetches.insert(std::pair<GURL, ManifestFetchData*>(update_url, fetch)); + bool added = fetch->AddExtension(id, version, ping_days); + DCHECK(added); } } - // Now do an update check for each url we found. - for (std::set<GURL>::iterator iter = urls.begin(); iter != urls.end(); - ++iter) { + + // Start a fetch of the blacklist if needed. + if (blacklist_checks_enabled_ && service_->HasInstalledExtensions()) { + ManifestFetchData* blacklist_fetch = + new ManifestFetchData(GURL(kBlacklistUpdateUrl)); + std::wstring version = prefs_->GetString(kExtensionBlacklistUpdateVersion); + blacklist_fetch->AddExtension(kBlacklistAppID, WideToASCII(version), 0); + StartUpdateCheck(blacklist_fetch); + } + + // Now start fetching regular extension updates + std::multimap<GURL, ManifestFetchData*>::iterator i = fetches.begin(); + while (i != fetches.end()) { + ManifestFetchData *fetch = i->second; + // StartUpdateCheck makes sure the url isn't already downloading or - // scheduled, so we don't need to check before calling it. - StartUpdateCheck(*iter); + // scheduled, so we don't need to check before calling it. Ownership of + // fetch is transferred here. + StartUpdateCheck(fetch); + fetches.erase(i++); } UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtensions", @@ -607,6 +633,14 @@ void ExtensionUpdater::CheckNow() { no_url_count); } +int ExtensionUpdater::CalculatePingDays(const std::string& extension_id) { + int days = ManifestFetchData::kNeverPinged; + Time last_ping_day = service_->LastPingDay(extension_id); + if (!last_ping_day.is_null()) { + days = (Time::Now() - last_ping_day).InDays(); + } + return days; +} bool ExtensionUpdater::GetExistingVersion(const std::string& id, std::string* version) { @@ -624,21 +658,23 @@ bool ExtensionUpdater::GetExistingVersion(const std::string& id, } std::vector<int> ExtensionUpdater::DetermineUpdates( - const std::vector<UpdateManifest::Result>& possible_updates) { - + const ManifestFetchData& fetch_data, + const UpdateManifest::Results& possible_updates) { std::vector<int> result; // This will only get set if one of possible_updates specifies // browser_min_version. scoped_ptr<Version> browser_version; - for (size_t i = 0; i < possible_updates.size(); i++) { - const UpdateManifest::Result* update = &possible_updates[i]; + for (size_t i = 0; i < possible_updates.list.size(); i++) { + const UpdateManifest::Result* update = &possible_updates.list[i]; + + if (!fetch_data.Includes(update->extension_id)) + continue; std::string version; - if (!GetExistingVersion(update->extension_id, &version)) { + if (!GetExistingVersion(update->extension_id, &version)) continue; - } // If the update version is the same or older than what's already installed, // we don't want it. @@ -681,19 +717,28 @@ std::vector<int> ExtensionUpdater::DetermineUpdates( return result; } -void ExtensionUpdater::StartUpdateCheck(const GURL& url) { - if (std::find(manifests_pending_.begin(), manifests_pending_.end(), url) != - manifests_pending_.end()) { - return; // already scheduled +void ExtensionUpdater::StartUpdateCheck(ManifestFetchData* fetch_data) { + std::deque<ManifestFetchData*>::const_iterator i; + for (i = manifests_pending_.begin(); i != manifests_pending_.end(); i++) { + if (fetch_data->full_url() == (*i)->full_url()) { + // This url is already scheduled to be fetched. + delete fetch_data; + return; + } } if (manifest_fetcher_.get() != NULL) { - if (manifest_fetcher_->url() != url) { - manifests_pending_.push_back(url); + if (manifest_fetcher_->url() != fetch_data->full_url()) { + manifests_pending_.push_back(fetch_data); } } else { + UMA_HISTOGRAM_COUNTS("Extensions.UpdateCheckUrlLength", + fetch_data->full_url().possibly_invalid_spec().length()); + + current_manifest_fetch_.reset(fetch_data); manifest_fetcher_.reset( - URLFetcher::Create(kManifestFetcherId, url, URLFetcher::GET, this)); + URLFetcher::Create(kManifestFetcherId, fetch_data->full_url(), + URLFetcher::GET, this)); manifest_fetcher_->set_request_context(Profile::GetDefaultRequestContext()); manifest_fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); diff --git a/chrome/browser/extensions/extension_updater.h b/chrome/browser/extensions/extension_updater.h index 8b2aed1..ae6d87c 100644 --- a/chrome/browser/extensions/extension_updater.h +++ b/chrome/browser/extensions/extension_updater.h @@ -6,6 +6,8 @@ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_UPDATER_H_ #include <deque> +#include <map> +#include <set> #include <string> #include <vector> @@ -25,6 +27,57 @@ class ExtensionUpdaterTest; class ExtensionUpdaterFileHandler; class PrefService; +// To save on server resources we can request updates for multiple extensions +// in one manifest check. This class helps us keep track of the id's for a +// given fetch, building up the actual URL, and what if anything to include +// in the ping parameter. +class ManifestFetchData { + public: + static const int kNeverPinged = -1; + + explicit ManifestFetchData(GURL update_url) : base_url_(update_url), + full_url_(update_url) {} + + // Returns true if this extension information was successfully added. If the + // return value is false it means the full_url would have become too long, and + // this ManifestFetchData object remains unchanged. + bool AddExtension(std::string id, std::string version, int ping_days); + + const GURL& base_url() const { return base_url_; } + const GURL& full_url() const { return full_url_; } + int extension_count() { return extension_ids_.size(); } + const std::set<std::string>& extension_ids() const { return extension_ids_; } + + // Returns true if the given id is included in this manifest fetch. + bool Includes(std::string extension_id) const { + return extension_ids_.find(extension_id) != extension_ids_.end(); + } + + // Returns true if a ping parameter was added to full_url for this extension + // id. + bool DidPing(std::string extension_id) const; + + private: + // Returns true if we should include a ping parameter for a given number of + // days. + bool ShouldPing(int days) const; + + std::set<std::string> extension_ids_; + + // Keeps track of the day value to use for the extensions where we want to + // send a 'days since last ping' parameter in the check. + std::map<std::string, int> ping_days_; + + // The base update url without any arguments added. + GURL base_url_; + + // The base update url plus arguments indicating the id, version, etc. + // information about each extension. + GURL full_url_; + + DISALLOW_COPY_AND_ASSIGN(ManifestFetchData); +}; + // A class for doing auto-updates of installed Extensions. Used like this: // // ExtensionUpdater* updater = new ExtensionUpdater(my_extensions_service, @@ -60,19 +113,6 @@ class ExtensionUpdater blacklist_checks_enabled_ = enabled; } - // Interface for getting a uid to send for checks to the gallery. - class UidProvider { - public: - static const unsigned int maxUidLength = 256; - virtual ~UidProvider() {} - - // This should return a uid string no longer than maxUidLength, or the empty - // string if there is no known uid (in which case nothing will be sent). It - // will be url-escaped by the consumer so implementers of this interface - // don't need to worry about it. - virtual std::string GetUidString() = 0; - }; - private: friend class base::RefCountedThreadSafe<ExtensionUpdater>; friend class ExtensionUpdaterTest; @@ -102,9 +142,6 @@ class ExtensionUpdater static const char* kBlacklistUpdateUrl; static const char* kBlacklistAppID; - // Key used to denote Omaha uid in gallery update check urls. - static const char* kUidKey; - // Does common work from constructors. void Init(); @@ -149,15 +186,20 @@ class ExtensionUpdater // BaseTimer::ReceiverMethod callback. void TimerFired(); - // Begins an update check - called with url to fetch an update manifest. - void StartUpdateCheck(const GURL& url); + // Begins an update check. Takes ownership of |fetch_data|. + void StartUpdateCheck(ManifestFetchData* fetch_data); // Begins (or queues up) download of an updated extension. void FetchUpdatedExtension(const std::string& id, const GURL& url, const std::string& hash, const std::string& version); // Once a manifest is parsed, this starts fetches of any relevant crx files. - void HandleManifestResults(const UpdateManifest::ResultList& results); + void HandleManifestResults(const ManifestFetchData& fetch_data, + const UpdateManifest::Results& results); + + // Calculates the value to use for the ping days parameter in manifest + // fetches for a given extension. + int CalculatePingDays(const std::string& extension_id); // Determines the version of an existing extension. // Returns true on success and false on failures. @@ -165,17 +207,8 @@ class ExtensionUpdater // Given a list of potential updates, returns the indices of the ones that are // applicable (are actually a new version, etc.) in |result|. - std::vector<int> DetermineUpdates( - const std::vector<UpdateManifest::Result>& possible_updates); - - // Creates a blacklist update url. - static GURL GetBlacklistUpdateUrl(const std::wstring& version); - - // Registers a custom UidProvider, deleting the default one. Takes ownership - // of |provider|. Useful mainly for testing. - void set_uid_provider(UidProvider* provider) { - uid_provider_.reset(provider); - } + std::vector<int> DetermineUpdates(const ManifestFetchData& fetch_data, + const UpdateManifest::Results& possible_updates); // Outstanding url fetch requests for manifests and updates. scoped_ptr<URLFetcher> manifest_fetcher_; @@ -183,9 +216,12 @@ class ExtensionUpdater // Pending manifests and extensions to be fetched when the appropriate fetcher // is available. - std::deque<GURL> manifests_pending_; + std::deque<ManifestFetchData*> manifests_pending_; std::deque<ExtensionFetch> extensions_pending_; + // The manifest currently being fetched (if any). + scoped_ptr<ManifestFetchData> current_manifest_fetch_; + // The extension currently being fetched (if any). ExtensionFetch current_extension_fetch_; @@ -200,8 +236,6 @@ class ExtensionUpdater scoped_refptr<ExtensionUpdaterFileHandler> file_handler_; bool blacklist_checks_enabled_; - scoped_ptr<UidProvider> uid_provider_; - DISALLOW_COPY_AND_ASSIGN(ExtensionUpdater); }; diff --git a/chrome/browser/extensions/extension_updater_unittest.cc b/chrome/browser/extensions/extension_updater_unittest.cc index 3f8a2c9..9439638 100644 --- a/chrome/browser/extensions/extension_updater_unittest.cc +++ b/chrome/browser/extensions/extension_updater_unittest.cc @@ -33,6 +33,9 @@ #define MAYBE_TestBlacklistUpdateCheckRequests TestBlacklistUpdateCheckRequests #endif +using base::Time; +using base::TimeDelta; + static int expected_load_flags = net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES; @@ -66,7 +69,23 @@ class MockService : public ExtensionUpdateService { EXPECT_TRUE(false); return false; } + + virtual void SetLastPingDay(const std::string& extension_id, + const Time& time) { + last_ping_days_[extension_id] = time; + } + + virtual Time LastPingDay(const std::string& extension_id) { + std::map<std::string, Time>::iterator i = + last_ping_days_.find(extension_id); + if (i != last_ping_days_.end()) + return i->second; + + return Time(); + } + private: + std::map<std::string, Time> last_ping_days_; DISALLOW_COPY_AND_ASSIGN(MockService); }; @@ -200,19 +219,6 @@ class ServiceForBlacklistTests : public MockService { FilePath install_path_; }; - -// For testing gallery updates. -class MockUidProvider : public ExtensionUpdater::UidProvider { - public: - explicit MockUidProvider(std::string uid) : uid_(uid) {} - virtual ~MockUidProvider() {} - virtual std::string GetUidString() { - return uid_; - } - private: - std::string uid_; -}; - static const int kUpdateFrequencySecs = 15; // Takes a string with KEY=VALUE parameters separated by '&' in |params| and @@ -240,8 +246,6 @@ static void ExtractParameters(const std::string& params, // inside this class (which is a friend to ExtensionUpdater). class ExtensionUpdaterTest : public testing::Test { public: - - static void SimulateTimerFired(ExtensionUpdater* updater) { EXPECT_TRUE(updater->timer_.IsRunning()); updater->timer_.Stop(); @@ -253,12 +257,12 @@ class ExtensionUpdaterTest : public testing::Test { const std::string& id, const std::string& version, const std::string& url, - std::vector<UpdateManifest::Result>* results) { + UpdateManifest::Results* results) { UpdateManifest::Result result; result.extension_id = id; result.version = version; result.crx_url = GURL(url); - results->push_back(result); + results->list.push_back(result); } static void TestExtensionUpdateCheckRequests() { @@ -379,8 +383,10 @@ class ExtensionUpdaterTest : public testing::Test { new ExtensionUpdater(&service, prefs.get(), kUpdateFrequencySecs); // Check passing an empty list of parse results to DetermineUpdates - std::vector<UpdateManifest::Result> updates; - std::vector<int> updateable = updater->DetermineUpdates(updates); + ManifestFetchData fetch_data(GURL("http://localhost/foo")); + UpdateManifest::Results updates; + std::vector<int> updateable = updater->DetermineUpdates(fetch_data, + updates); EXPECT_TRUE(updateable.empty()); // Create two updates - expect that DetermineUpdates will return the first @@ -388,11 +394,15 @@ class ExtensionUpdaterTest : public testing::Test { // installed and available at v2.0). scoped_ptr<Version> one(Version::GetVersionFromString("1.0")); EXPECT_TRUE(tmp[0]->version()->Equals(*one)); + fetch_data.AddExtension(tmp[0]->id(), tmp[0]->VersionString(), + ManifestFetchData::kNeverPinged); AddParseResult(tmp[0]->id(), "1.1", "http://localhost/e1_1.1.crx", &updates); + fetch_data.AddExtension(tmp[1]->id(), tmp[1]->VersionString(), + ManifestFetchData::kNeverPinged); AddParseResult(tmp[1]->id(), tmp[1]->VersionString(), "http://localhost/e2_2.0.crx", &updates); - updateable = updater->DetermineUpdates(updates); + updateable = updater->DetermineUpdates(fetch_data, updates); EXPECT_EQ(1u, updateable.size()); EXPECT_EQ(0, updateable[0]); STLDeleteElements(&tmp); @@ -419,8 +429,12 @@ class ExtensionUpdaterTest : public testing::Test { // Request 2 update checks - the first should begin immediately and the // second one should be queued up. - updater->StartUpdateCheck(url1); - updater->StartUpdateCheck(url2); + ManifestFetchData* fetch1 = new ManifestFetchData(url1); + ManifestFetchData* fetch2 = new ManifestFetchData(url2); + fetch1->AddExtension("1111", "1.0", 0); + fetch2->AddExtension("12345", "2.0", ManifestFetchData::kNeverPinged); + updater->StartUpdateCheck(fetch1); + updater->StartUpdateCheck(fetch2); std::string invalid_xml = "invalid xml"; fetcher = factory.GetFetcherByID(ExtensionUpdater::kManifestFetcherId); @@ -622,7 +636,7 @@ class ExtensionUpdaterTest : public testing::Test { file_util::Delete(service.install_path(), false); } - static void TestGalleryRequests() { + static void TestGalleryRequests(int ping_days) { TestURLFetcherFactory factory; URLFetcher::set_factory(&factory); @@ -637,16 +651,21 @@ class ExtensionUpdaterTest : public testing::Test { EXPECT_EQ(2u, tmp.size()); service.set_extensions(tmp); + Time now = Time::Now(); + if (ping_days == 0) { + service.SetLastPingDay(tmp[0]->id(), now - TimeDelta::FromSeconds(15)); + } else if (ping_days > 0) { + Time last_ping_day = + now - TimeDelta::FromDays(ping_days) - TimeDelta::FromSeconds(15); + service.SetLastPingDay(tmp[0]->id(), last_ping_day); + } + MessageLoop message_loop; ScopedTempPrefService prefs; scoped_refptr<ExtensionUpdater> updater = new ExtensionUpdater(&service, prefs.get(), kUpdateFrequencySecs); updater->set_blacklist_checks_enabled(false); - // Create a mock uid provider and have the updater take ownership of it. - MockUidProvider* uid_provider = new MockUidProvider("foobar"); - updater->set_uid_provider(uid_provider); - // Make the updater do manifest fetching, and note the urls it tries to // fetch. std::vector<GURL> fetched_urls; @@ -675,11 +694,48 @@ class ExtensionUpdaterTest : public testing::Test { NOTREACHED(); } - // Now make sure the google query had the uid but the regular one did not. - std::string search_string = std::string(ExtensionUpdater::kUidKey) + "=" + - uid_provider->GetUidString(); - EXPECT_TRUE(url1_query.find(search_string) != std::string::npos); + // Now make sure the non-google query had no ping parameter, but the google + // one did (depending on ping_days). + std::string search_string = "ping%3Dr"; EXPECT_TRUE(url2_query.find(search_string) == std::string::npos); + if (ping_days == 0) { + EXPECT_TRUE(url1_query.find(search_string) == std::string::npos); + } else { + search_string += "%253D" + IntToString(ping_days); + size_t pos = url1_query.find(search_string); + EXPECT_TRUE(pos != std::string::npos); + } + + STLDeleteElements(&tmp); + } + + // This makes sure that the extension updater properly stores the results + // of a <daystart> tag from a manifest fetch in one of two cases: 1) This is + // the first time we fetched the extension, or 2) We sent a ping value of + // >= 1 day for the extension. + static void TestHandleManifestResults() { + ServiceForManifestTests service; + ScopedTempPrefService prefs; + scoped_refptr<ExtensionUpdater> updater = + new ExtensionUpdater(&service, prefs.get(), kUpdateFrequencySecs); + + GURL update_url("http://www.google.com/manifest"); + ExtensionList tmp; + CreateTestExtensions(1, &tmp, &update_url.spec()); + service.set_extensions(tmp); + + ManifestFetchData fetch_data(update_url); + Extension* extension = tmp[0]; + fetch_data.AddExtension(extension->id(), extension->VersionString(), + ManifestFetchData::kNeverPinged); + UpdateManifest::Results results; + results.daystart_elapsed_seconds = 750; + + updater->HandleManifestResults(fetch_data, results); + Time last_ping_day = service.LastPingDay(extension->id()); + EXPECT_FALSE(last_ping_day.is_null()); + int64 seconds_diff = (Time::Now() - last_ping_day).InSeconds(); + EXPECT_LT(seconds_diff - results.daystart_elapsed_seconds, 5); STLDeleteElements(&tmp); } @@ -720,7 +776,14 @@ TEST(ExtensionUpdaterTest, TestMultipleExtensionDownloading) { } TEST(ExtensionUpdaterTest, TestGalleryRequests) { - ExtensionUpdaterTest::TestGalleryRequests(); + ExtensionUpdaterTest::TestGalleryRequests(ManifestFetchData::kNeverPinged); + ExtensionUpdaterTest::TestGalleryRequests(0); + ExtensionUpdaterTest::TestGalleryRequests(1); + ExtensionUpdaterTest::TestGalleryRequests(5); +} + +TEST(ExtensionUpdaterTest, TestHandleManifestResults) { + ExtensionUpdaterTest::TestHandleManifestResults(); } // TODO(asargent) - (http://crbug.com/12780) add tests for: diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc index de75aba..a62799f 100644 --- a/chrome/browser/extensions/extensions_service.cc +++ b/chrome/browser/extensions/extensions_service.cc @@ -42,6 +42,8 @@ #include "chrome/browser/extensions/external_registry_extension_provider_win.h" #endif +using base::Time; + namespace errors = extension_manifest_errors; namespace { @@ -433,7 +435,6 @@ void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info, info.extension_id, info.extension_location)); } - } void ExtensionsService::NotifyExtensionLoaded(Extension* extension) { @@ -515,6 +516,15 @@ void ExtensionsService::UpdateExtensionBlacklist( } } +void ExtensionsService::SetLastPingDay(const std::string& extension_id, + const base::Time& time) { + extension_prefs_->SetLastPingDay(extension_id, time); +} + +base::Time ExtensionsService::LastPingDay(const std::string& extension_id) { + return extension_prefs_->LastPingDay(extension_id); +} + void ExtensionsService::CheckForExternalUpdates() { // This installs or updates externally provided extensions. // TODO(aa): Why pass this list into the provider, why not just filter it diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h index 4b18c90..f71f044 100644 --- a/chrome/browser/extensions/extensions_service.h +++ b/chrome/browser/extensions/extensions_service.h @@ -51,6 +51,12 @@ class ExtensionUpdateService { virtual void UpdateExtensionBlacklist( const std::vector<std::string>& blacklist) = 0; virtual bool HasInstalledExtensions() = 0; + + // These set/get a server-provided time representing the start of the last day + // that we sent the 'ping' parameter during an update check. + virtual void SetLastPingDay(const std::string& extension_id, + const base::Time& time) = 0; + virtual base::Time LastPingDay(const std::string& extension_id) = 0; }; // Manages installed and running Chromium extensions. @@ -96,6 +102,11 @@ class ExtensionsService return !(extensions_.empty() && disabled_extensions_.empty()); } + virtual void SetLastPingDay(const std::string& extension_id, + const base::Time& time); + virtual base::Time LastPingDay(const std::string& extension_id); + + const FilePath& install_directory() const { return install_directory_; } // Initialize and start all installed extensions. diff --git a/chrome/browser/utility_process_host.h b/chrome/browser/utility_process_host.h index 69fb270..3b5d58f 100644 --- a/chrome/browser/utility_process_host.h +++ b/chrome/browser/utility_process_host.h @@ -57,7 +57,7 @@ class UtilityProcessHost : public ChildProcessHost { // Called when an update manifest xml file was successfully parsed. virtual void OnParseUpdateManifestSucceeded( - const UpdateManifest::ResultList& list) {} + const UpdateManifest::Results& results) {} // Called when an update manifest xml file failed parsing. |error_message| // contains details suitable for logging. diff --git a/chrome/common/extensions/update_manifest.cc b/chrome/common/extensions/update_manifest.cc index e3f1b4d..e461d7b 100644 --- a/chrome/common/extensions/update_manifest.cc +++ b/chrome/common/extensions/update_manifest.cc @@ -17,7 +17,9 @@ static const char* kExpectedGupdateProtocol = "2.0"; static const char* kExpectedGupdateXmlns = "http://www.google.com/update2/response"; -UpdateManifest::UpdateManifest() {} +UpdateManifest::UpdateManifest() { + results_.daystart_elapsed_seconds = kNoDaystart; +} UpdateManifest::~UpdateManifest() {} @@ -135,6 +137,10 @@ static bool ParseSingleAppTag(xmlNode* app_node, xmlNs* xml_namespace, } xmlNode *updatecheck = updates[0]; + if (GetAttribute(updatecheck, "status") == "noupdate") { + return true; + } + // Find the url to the crx file. result->crx_url = GURL(GetAttribute(updatecheck, "codebase")); if (!result->crx_url.is_valid()) { @@ -180,7 +186,8 @@ static bool ParseSingleAppTag(xmlNode* app_node, xmlNs* xml_namespace, bool UpdateManifest::Parse(const std::string& manifest_xml) { - results_.resize(0); + results_.list.resize(0); + results_.daystart_elapsed_seconds = kNoDaystart; if (manifest_xml.length() < 1) { return false; @@ -222,6 +229,17 @@ bool UpdateManifest::Parse(const std::string& manifest_xml) { return false; } + // Parse the first <daystart> if it's present. + std::vector<xmlNode*> daystarts = GetChildren(root, gupdate_ns, "daystart"); + if (daystarts.size() > 0) { + xmlNode* first = daystarts[0]; + std::string elapsed_seconds = GetAttribute(first, "elapsed_seconds"); + int parsed_elapsed = kNoDaystart; + if (StringToInt(elapsed_seconds, &parsed_elapsed)) { + results_.daystart_elapsed_seconds = parsed_elapsed; + } + } + // Parse each of the <app> tags. std::vector<xmlNode*> apps = GetChildren(root, gupdate_ns, "app"); for (unsigned int i = 0; i < apps.size(); i++) { @@ -231,7 +249,7 @@ bool UpdateManifest::Parse(const std::string& manifest_xml) { ParseError("%s", error.c_str()); return false; } - results_.push_back(current); + results_.list.push_back(current); } return true; diff --git a/chrome/common/extensions/update_manifest.h b/chrome/common/extensions/update_manifest.h index c1e5b2b..be0f643 100644 --- a/chrome/common/extensions/update_manifest.h +++ b/chrome/common/extensions/update_manifest.h @@ -23,6 +23,7 @@ class UpdateManifest { // // <?xml version='1.0' encoding='UTF-8'?> // <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'> + // <daystart elapsed_seconds='300' /> // <app appid='12345'> // <updatecheck codebase='http://example.com/extension_1.2.3.4.crx' // version='1.2.3.4' prodversionmin='2.0.143.0' @@ -30,6 +31,9 @@ class UpdateManifest { // </app> // </gupdate> // + // The <daystart> tag contains a "elapsed_seconds" attribute which refers to + // the server's notion of how many seconds it has been since midnight. + // // The "appid" attribute of the <app> tag refers to the unique id of the // extension. The "codebase" attribute of the <updatecheck> tag is the url to // fetch the updated crx file, and the "prodversionmin" attribute refers to @@ -44,7 +48,12 @@ class UpdateManifest { GURL crx_url; }; - typedef std::vector<Result> ResultList; + static const int kNoDaystart = -1; + struct Results { + std::vector<Result> list; + // This will be >= 0, or kNoDaystart if the <daystart> tag was not present. + int daystart_elapsed_seconds; + }; UpdateManifest(); ~UpdateManifest(); @@ -55,16 +64,17 @@ class UpdateManifest { // by calling errors(). bool Parse(const std::string& manifest_xml); - const ResultList& results() { return results_; } + const Results& results() { return results_; } const std::string& errors() { return errors_; } private: - ResultList results_; - + Results results_; std::string errors_; // Helper function that adds parse error details to our errors_ string. void ParseError(const char* details, ...); + + DISALLOW_COPY_AND_ASSIGN(UpdateManifest); }; #endif // CHROME_COMMON_EXTENSIONS_UPDATE_MANIFEST_H_ diff --git a/chrome/common/extensions/update_manifest_unittest.cc b/chrome/common/extensions/update_manifest_unittest.cc index 7adc17f..fb7ee0e9 100644 --- a/chrome/common/extensions/update_manifest_unittest.cc +++ b/chrome/common/extensions/update_manifest_unittest.cc @@ -85,6 +85,25 @@ static const char* kSimilarTagnames = " </app>" "</gupdate>"; +// Includes a <daystart> tag. +static const char* kWithDaystart = +"<?xml version='1.0' encoding='UTF-8'?>" +"<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>" +" <daystart elapsed_seconds='456' />" +" <app appid='12345'>" +" <updatecheck codebase='http://example.com/extension_1.2.3.4.crx'" +" version='1.2.3.4' prodversionmin='2.0.143.0' />" +" </app>" +"</gupdate>"; + +// Indicates no updates available - this should not be a parse error. +static const char* kNoUpdate = +"<?xml version='1.0' encoding='UTF-8'?>" +"<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>" +" <app appid='12345'>" +" <updatecheck status='noupdate' />" +" </app>" +"</gupdate>"; TEST(ExtensionUpdateManifestTest, TestUpdateManifest) { UpdateManifest parser; @@ -98,8 +117,8 @@ TEST(ExtensionUpdateManifestTest, TestUpdateManifest) { // Parse some valid XML, and check that all params came out as expected EXPECT_TRUE(parser.Parse(kValidXml)); - EXPECT_FALSE(parser.results().empty()); - const UpdateManifest::Result* firstResult = &parser.results().at(0); + EXPECT_FALSE(parser.results().list.empty()); + const UpdateManifest::Result* firstResult = &parser.results().list.at(0); EXPECT_EQ(GURL("http://example.com/extension_1.2.3.4.crx"), firstResult->crx_url); @@ -113,7 +132,18 @@ TEST(ExtensionUpdateManifestTest, TestUpdateManifest) { // Parse xml with hash value EXPECT_TRUE(parser.Parse(valid_xml_with_hash)); - EXPECT_FALSE(parser.results().empty()); - firstResult = &parser.results().at(0); + EXPECT_FALSE(parser.results().list.empty()); + firstResult = &parser.results().list.at(0); EXPECT_EQ("1234", firstResult->package_hash); + + EXPECT_TRUE(parser.Parse(kWithDaystart)); + EXPECT_FALSE(parser.results().list.empty()); + EXPECT_EQ(parser.results().daystart_elapsed_seconds, 456); + + // Parse a no-update response. + EXPECT_TRUE(parser.Parse(kNoUpdate)); + EXPECT_FALSE(parser.results().list.empty()); + firstResult = &parser.results().list.at(0); + EXPECT_EQ(firstResult->extension_id, "12345"); + EXPECT_EQ(firstResult->version, ""); } diff --git a/chrome/common/utility_messages.h b/chrome/common/utility_messages.h index eccdc14..867131f 100644 --- a/chrome/common/utility_messages.h +++ b/chrome/common/utility_messages.h @@ -50,6 +50,26 @@ struct ParamTraits<UpdateManifest::Result> { } }; +template<> +struct ParamTraits<UpdateManifest::Results> { + typedef UpdateManifest::Results param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.list); + WriteParam(m, p.daystart_elapsed_seconds); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->list) && + ReadParam(m, iter, &p->daystart_elapsed_seconds); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.list, l); + l->append(L", "); + LogParam(p.daystart_elapsed_seconds, l); + l->append(L")"); + } +}; + } // namespace IPC #define MESSAGES_INTERNAL_FILE "chrome/common/utility_messages_internal.h" diff --git a/chrome/common/utility_messages_internal.h b/chrome/common/utility_messages_internal.h index 4947079..4933742 100644 --- a/chrome/common/utility_messages_internal.h +++ b/chrome/common/utility_messages_internal.h @@ -64,7 +64,7 @@ IPC_BEGIN_MESSAGES(UtilityHost) // Reply when the utility process has succeeded in parsing an update manifest // xml document. IPC_MESSAGE_CONTROL1(UtilityHostMsg_ParseUpdateManifest_Succeeded, - std::vector<UpdateManifest::Result> /* updates */) + UpdateManifest::Results /* updates */) // Reply when an error occured parsing the update manifest. |error_message| // is a description of what went wrong suitable for logging. |