123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431 |
- //
- // Copyright (C) 2012 The Android Open Source Project
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- #include "update_engine/payload_state.h"
- #include <algorithm>
- #include <string>
- #include <base/logging.h>
- #include <base/strings/string_util.h>
- #include <base/strings/stringprintf.h>
- #include <metrics/metrics_library.h>
- #include <policy/device_policy.h>
- #include "update_engine/common/clock.h"
- #include "update_engine/common/constants.h"
- #include "update_engine/common/error_code_utils.h"
- #include "update_engine/common/hardware_interface.h"
- #include "update_engine/common/prefs.h"
- #include "update_engine/common/utils.h"
- #include "update_engine/connection_manager_interface.h"
- #include "update_engine/metrics_reporter_interface.h"
- #include "update_engine/metrics_utils.h"
- #include "update_engine/omaha_request_params.h"
- #include "update_engine/payload_consumer/install_plan.h"
- #include "update_engine/system_state.h"
- using base::Time;
- using base::TimeDelta;
- using std::min;
- using std::string;
- namespace chromeos_update_engine {
- using metrics_utils::GetPersistedValue;
- const TimeDelta PayloadState::kDurationSlack = TimeDelta::FromSeconds(600);
- // We want to upperbound backoffs to 16 days
- static const int kMaxBackoffDays = 16;
- // We want to randomize retry attempts after the backoff by +/- 6 hours.
- static const uint32_t kMaxBackoffFuzzMinutes = 12 * 60;
- // Limit persisting current update duration uptime to once per second
- static const uint64_t kUptimeResolution = 1;
- PayloadState::PayloadState()
- : prefs_(nullptr),
- using_p2p_for_downloading_(false),
- p2p_num_attempts_(0),
- payload_attempt_number_(0),
- full_payload_attempt_number_(0),
- url_index_(0),
- url_failure_count_(0),
- url_switch_count_(0),
- rollback_happened_(false),
- attempt_num_bytes_downloaded_(0),
- attempt_connection_type_(metrics::ConnectionType::kUnknown),
- attempt_type_(AttemptType::kUpdate) {
- for (int i = 0; i <= kNumDownloadSources; i++)
- total_bytes_downloaded_[i] = current_bytes_downloaded_[i] = 0;
- }
- bool PayloadState::Initialize(SystemState* system_state) {
- system_state_ = system_state;
- prefs_ = system_state_->prefs();
- powerwash_safe_prefs_ = system_state_->powerwash_safe_prefs();
- LoadResponseSignature();
- LoadPayloadAttemptNumber();
- LoadFullPayloadAttemptNumber();
- LoadUrlIndex();
- LoadUrlFailureCount();
- LoadUrlSwitchCount();
- LoadBackoffExpiryTime();
- LoadUpdateTimestampStart();
- // The LoadUpdateDurationUptime() method relies on LoadUpdateTimestampStart()
- // being called before it. Don't reorder.
- LoadUpdateDurationUptime();
- for (int i = 0; i < kNumDownloadSources; i++) {
- DownloadSource source = static_cast<DownloadSource>(i);
- LoadCurrentBytesDownloaded(source);
- LoadTotalBytesDownloaded(source);
- }
- LoadNumReboots();
- LoadNumResponsesSeen();
- LoadRollbackHappened();
- LoadRollbackVersion();
- LoadP2PFirstAttemptTimestamp();
- LoadP2PNumAttempts();
- return true;
- }
- void PayloadState::SetResponse(const OmahaResponse& omaha_response) {
- // Always store the latest response.
- response_ = omaha_response;
- // Compute the candidate URLs first as they are used to calculate the
- // response signature so that a change in enterprise policy for
- // HTTP downloads being enabled or not could be honored as soon as the
- // next update check happens.
- ComputeCandidateUrls();
- // Check if the "signature" of this response (i.e. the fields we care about)
- // has changed.
- string new_response_signature = CalculateResponseSignature();
- bool has_response_changed = (response_signature_ != new_response_signature);
- // If the response has changed, we should persist the new signature and
- // clear away all the existing state.
- if (has_response_changed) {
- LOG(INFO) << "Resetting all persisted state as this is a new response";
- SetNumResponsesSeen(num_responses_seen_ + 1);
- SetResponseSignature(new_response_signature);
- ResetPersistedState();
- return;
- }
- // Always start from payload index 0, even for resume, to download partition
- // info from previous payloads.
- payload_index_ = 0;
- // This is the earliest point at which we can validate whether the URL index
- // we loaded from the persisted state is a valid value. If the response
- // hasn't changed but the URL index is invalid, it's indicative of some
- // tampering of the persisted state.
- if (payload_index_ >= candidate_urls_.size() ||
- url_index_ >= candidate_urls_[payload_index_].size()) {
- LOG(INFO) << "Resetting all payload state as the url index seems to have "
- "been tampered with";
- ResetPersistedState();
- return;
- }
- // Update the current download source which depends on the latest value of
- // the response.
- UpdateCurrentDownloadSource();
- }
- void PayloadState::SetUsingP2PForDownloading(bool value) {
- using_p2p_for_downloading_ = value;
- // Update the current download source which depends on whether we are
- // using p2p or not.
- UpdateCurrentDownloadSource();
- }
- void PayloadState::DownloadComplete() {
- LOG(INFO) << "Payload downloaded successfully";
- IncrementPayloadAttemptNumber();
- IncrementFullPayloadAttemptNumber();
- }
- void PayloadState::DownloadProgress(size_t count) {
- if (count == 0)
- return;
- CalculateUpdateDurationUptime();
- UpdateBytesDownloaded(count);
- // We've received non-zero bytes from a recent download operation. Since our
- // URL failure count is meant to penalize a URL only for consecutive
- // failures, downloading bytes successfully means we should reset the failure
- // count (as we know at least that the URL is working). In future, we can
- // design this to be more sophisticated to check for more intelligent failure
- // patterns, but right now, even 1 byte downloaded will mark the URL to be
- // good unless it hits 10 (or configured number of) consecutive failures
- // again.
- if (GetUrlFailureCount() == 0)
- return;
- LOG(INFO) << "Resetting failure count of Url" << GetUrlIndex()
- << " to 0 as we received " << count << " bytes successfully";
- SetUrlFailureCount(0);
- }
- void PayloadState::AttemptStarted(AttemptType attempt_type) {
- // Flush previous state from abnormal attempt failure, if any.
- ReportAndClearPersistedAttemptMetrics();
- attempt_type_ = attempt_type;
- ClockInterface* clock = system_state_->clock();
- attempt_start_time_boot_ = clock->GetBootTime();
- attempt_start_time_monotonic_ = clock->GetMonotonicTime();
- attempt_num_bytes_downloaded_ = 0;
- metrics::ConnectionType type;
- ConnectionType network_connection_type;
- ConnectionTethering tethering;
- ConnectionManagerInterface* connection_manager =
- system_state_->connection_manager();
- if (!connection_manager->GetConnectionProperties(&network_connection_type,
- &tethering)) {
- LOG(ERROR) << "Failed to determine connection type.";
- type = metrics::ConnectionType::kUnknown;
- } else {
- type = metrics_utils::GetConnectionType(network_connection_type, tethering);
- }
- attempt_connection_type_ = type;
- if (attempt_type == AttemptType::kUpdate)
- PersistAttemptMetrics();
- }
- void PayloadState::UpdateResumed() {
- LOG(INFO) << "Resuming an update that was previously started.";
- UpdateNumReboots();
- AttemptStarted(AttemptType::kUpdate);
- }
- void PayloadState::UpdateRestarted() {
- LOG(INFO) << "Starting a new update";
- ResetDownloadSourcesOnNewUpdate();
- SetNumReboots(0);
- AttemptStarted(AttemptType::kUpdate);
- }
- void PayloadState::UpdateSucceeded() {
- // Send the relevant metrics that are tracked in this class to UMA.
- CalculateUpdateDurationUptime();
- SetUpdateTimestampEnd(system_state_->clock()->GetWallclockTime());
- switch (attempt_type_) {
- case AttemptType::kUpdate:
- CollectAndReportAttemptMetrics(ErrorCode::kSuccess);
- CollectAndReportSuccessfulUpdateMetrics();
- ClearPersistedAttemptMetrics();
- break;
- case AttemptType::kRollback:
- system_state_->metrics_reporter()->ReportRollbackMetrics(
- metrics::RollbackResult::kSuccess);
- break;
- }
- // Reset the number of responses seen since it counts from the last
- // successful update, e.g. now.
- SetNumResponsesSeen(0);
- SetPayloadIndex(0);
- metrics_utils::SetSystemUpdatedMarker(system_state_->clock(), prefs_);
- }
- void PayloadState::UpdateFailed(ErrorCode error) {
- ErrorCode base_error = utils::GetBaseErrorCode(error);
- LOG(INFO) << "Updating payload state for error code: " << base_error << " ("
- << utils::ErrorCodeToString(base_error) << ")";
- if (candidate_urls_.size() == 0) {
- // This means we got this error even before we got a valid Omaha response
- // or don't have any valid candidates in the Omaha response.
- // So we should not advance the url_index_ in such cases.
- LOG(INFO) << "Ignoring failures until we get a valid Omaha response.";
- return;
- }
- switch (attempt_type_) {
- case AttemptType::kUpdate:
- CollectAndReportAttemptMetrics(base_error);
- ClearPersistedAttemptMetrics();
- break;
- case AttemptType::kRollback:
- system_state_->metrics_reporter()->ReportRollbackMetrics(
- metrics::RollbackResult::kFailed);
- break;
- }
- switch (base_error) {
- // Errors which are good indicators of a problem with a particular URL or
- // the protocol used in the URL or entities in the communication channel
- // (e.g. proxies). We should try the next available URL in the next update
- // check to quickly recover from these errors.
- case ErrorCode::kPayloadHashMismatchError:
- case ErrorCode::kPayloadSizeMismatchError:
- case ErrorCode::kDownloadPayloadVerificationError:
- case ErrorCode::kDownloadPayloadPubKeyVerificationError:
- case ErrorCode::kSignedDeltaPayloadExpectedError:
- case ErrorCode::kDownloadInvalidMetadataMagicString:
- case ErrorCode::kDownloadSignatureMissingInManifest:
- case ErrorCode::kDownloadManifestParseError:
- case ErrorCode::kDownloadMetadataSignatureError:
- case ErrorCode::kDownloadMetadataSignatureVerificationError:
- case ErrorCode::kDownloadMetadataSignatureMismatch:
- case ErrorCode::kDownloadOperationHashVerificationError:
- case ErrorCode::kDownloadOperationExecutionError:
- case ErrorCode::kDownloadOperationHashMismatch:
- case ErrorCode::kDownloadInvalidMetadataSize:
- case ErrorCode::kDownloadInvalidMetadataSignature:
- case ErrorCode::kDownloadOperationHashMissingError:
- case ErrorCode::kDownloadMetadataSignatureMissingError:
- case ErrorCode::kPayloadMismatchedType:
- case ErrorCode::kUnsupportedMajorPayloadVersion:
- case ErrorCode::kUnsupportedMinorPayloadVersion:
- case ErrorCode::kPayloadTimestampError:
- case ErrorCode::kVerityCalculationError:
- IncrementUrlIndex();
- break;
- // Errors which seem to be just transient network/communication related
- // failures and do not indicate any inherent problem with the URL itself.
- // So, we should keep the current URL but just increment the
- // failure count to give it more chances. This way, while we maximize our
- // chances of downloading from the URLs that appear earlier in the
- // response (because download from a local server URL that appears earlier
- // in a response is preferable than downloading from the next URL which
- // could be a internet URL and thus could be more expensive).
- case ErrorCode::kError:
- case ErrorCode::kDownloadTransferError:
- case ErrorCode::kDownloadWriteError:
- case ErrorCode::kDownloadStateInitializationError:
- case ErrorCode::kOmahaErrorInHTTPResponse: // Aggregate for HTTP errors.
- IncrementFailureCount();
- break;
- // Errors which are not specific to a URL and hence shouldn't result in
- // the URL being penalized. This can happen in two cases:
- // 1. We haven't started downloading anything: These errors don't cost us
- // anything in terms of actual payload bytes, so we should just do the
- // regular retries at the next update check.
- // 2. We have successfully downloaded the payload: In this case, the
- // payload attempt number would have been incremented and would take care
- // of the backoff at the next update check.
- // In either case, there's no need to update URL index or failure count.
- case ErrorCode::kOmahaRequestError:
- case ErrorCode::kOmahaResponseHandlerError:
- case ErrorCode::kPostinstallRunnerError:
- case ErrorCode::kFilesystemCopierError:
- case ErrorCode::kInstallDeviceOpenError:
- case ErrorCode::kKernelDeviceOpenError:
- case ErrorCode::kDownloadNewPartitionInfoError:
- case ErrorCode::kNewRootfsVerificationError:
- case ErrorCode::kNewKernelVerificationError:
- case ErrorCode::kPostinstallBootedFromFirmwareB:
- case ErrorCode::kPostinstallFirmwareRONotUpdatable:
- case ErrorCode::kOmahaRequestEmptyResponseError:
- case ErrorCode::kOmahaRequestXMLParseError:
- case ErrorCode::kOmahaResponseInvalid:
- case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
- case ErrorCode::kOmahaUpdateDeferredPerPolicy:
- case ErrorCode::kNonCriticalUpdateInOOBE:
- case ErrorCode::kOmahaUpdateDeferredForBackoff:
- case ErrorCode::kPostinstallPowerwashError:
- case ErrorCode::kUpdateCanceledByChannelChange:
- case ErrorCode::kOmahaRequestXMLHasEntityDecl:
- case ErrorCode::kFilesystemVerifierError:
- case ErrorCode::kUserCanceled:
- case ErrorCode::kOmahaUpdateIgnoredOverCellular:
- case ErrorCode::kUpdatedButNotActive:
- case ErrorCode::kNoUpdate:
- case ErrorCode::kRollbackNotPossible:
- case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
- LOG(INFO) << "Not incrementing URL index or failure count for this error";
- break;
- case ErrorCode::kSuccess: // success code
- case ErrorCode::kUmaReportedMax: // not an error code
- case ErrorCode::kOmahaRequestHTTPResponseBase: // aggregated already
- case ErrorCode::kDevModeFlag: // not an error code
- case ErrorCode::kResumedFlag: // not an error code
- case ErrorCode::kTestImageFlag: // not an error code
- case ErrorCode::kTestOmahaUrlFlag: // not an error code
- case ErrorCode::kSpecialFlags: // not an error code
- // These shouldn't happen. Enumerating these explicitly here so that we
- // can let the compiler warn about new error codes that are added to
- // action_processor.h but not added here.
- LOG(WARNING) << "Unexpected error code for UpdateFailed";
- break;
- // Note: Not adding a default here so as to let the compiler warn us of
- // any new enums that were added in the .h but not listed in this switch.
- }
- }
- bool PayloadState::ShouldBackoffDownload() {
- if (response_.disable_payload_backoff) {
- LOG(INFO) << "Payload backoff logic is disabled. "
- "Can proceed with the download";
- return false;
- }
- if (GetUsingP2PForDownloading() && !GetP2PUrl().empty()) {
- LOG(INFO) << "Payload backoff logic is disabled because download "
- << "will happen from local peer (via p2p).";
- return false;
- }
- if (system_state_->request_params()->interactive()) {
- LOG(INFO) << "Payload backoff disabled for interactive update checks.";
- return false;
- }
- for (const auto& package : response_.packages) {
- if (package.is_delta) {
- // If delta payloads fail, we want to fallback quickly to full payloads as
- // they are more likely to succeed. Exponential backoffs would greatly
- // slow down the fallback to full payloads. So we don't backoff for delta
- // payloads.
- LOG(INFO) << "No backoffs for delta payloads. "
- << "Can proceed with the download";
- return false;
- }
- }
- if (!system_state_->hardware()->IsOfficialBuild() &&
- !prefs_->Exists(kPrefsNoIgnoreBackoff)) {
- // Backoffs are needed only for official builds. We do not want any delays
- // or update failures due to backoffs during testing or development. Unless
- // the |kPrefsNoIgnoreBackoff| is manually set.
- LOG(INFO) << "No backoffs for test/dev images. "
- << "Can proceed with the download";
- return false;
- }
- if (backoff_expiry_time_.is_null()) {
- LOG(INFO) << "No backoff expiry time has been set. "
- << "Can proceed with the download";
- return false;
- }
- if (backoff_expiry_time_ < Time::Now()) {
- LOG(INFO) << "The backoff expiry time ("
- << utils::ToString(backoff_expiry_time_)
- << ") has elapsed. Can proceed with the download";
- return false;
- }
- LOG(INFO) << "Cannot proceed with downloads as we need to backoff until "
- << utils::ToString(backoff_expiry_time_);
- return true;
- }
- void PayloadState::Rollback() {
- SetRollbackVersion(system_state_->request_params()->app_version());
- AttemptStarted(AttemptType::kRollback);
- }
- void PayloadState::IncrementPayloadAttemptNumber() {
- // Update the payload attempt number for both payload types: full and delta.
- SetPayloadAttemptNumber(GetPayloadAttemptNumber() + 1);
- }
- void PayloadState::IncrementFullPayloadAttemptNumber() {
- // Update the payload attempt number for full payloads and the backoff time.
- if (response_.packages[payload_index_].is_delta) {
- LOG(INFO) << "Not incrementing payload attempt number for delta payloads";
- return;
- }
- LOG(INFO) << "Incrementing the full payload attempt number";
- SetFullPayloadAttemptNumber(GetFullPayloadAttemptNumber() + 1);
- UpdateBackoffExpiryTime();
- }
- void PayloadState::IncrementUrlIndex() {
- size_t next_url_index = url_index_ + 1;
- size_t max_url_size = 0;
- for (const auto& urls : candidate_urls_)
- max_url_size = std::max(max_url_size, urls.size());
- if (next_url_index < max_url_size) {
- LOG(INFO) << "Incrementing the URL index for next attempt";
- SetUrlIndex(next_url_index);
- } else {
- LOG(INFO) << "Resetting the current URL index (" << url_index_ << ") to "
- << "0 as we only have " << max_url_size << " candidate URL(s)";
- SetUrlIndex(0);
- IncrementPayloadAttemptNumber();
- IncrementFullPayloadAttemptNumber();
- }
- // If we have multiple URLs, record that we just switched to another one
- if (max_url_size > 1)
- SetUrlSwitchCount(url_switch_count_ + 1);
- // Whenever we update the URL index, we should also clear the URL failure
- // count so we can start over fresh for the new URL.
- SetUrlFailureCount(0);
- }
- void PayloadState::IncrementFailureCount() {
- uint32_t next_url_failure_count = GetUrlFailureCount() + 1;
- if (next_url_failure_count < response_.max_failure_count_per_url) {
- LOG(INFO) << "Incrementing the URL failure count";
- SetUrlFailureCount(next_url_failure_count);
- } else {
- LOG(INFO) << "Reached max number of failures for Url" << GetUrlIndex()
- << ". Trying next available URL";
- IncrementUrlIndex();
- }
- }
- void PayloadState::UpdateBackoffExpiryTime() {
- if (response_.disable_payload_backoff) {
- LOG(INFO) << "Resetting backoff expiry time as payload backoff is disabled";
- SetBackoffExpiryTime(Time());
- return;
- }
- if (GetFullPayloadAttemptNumber() == 0) {
- SetBackoffExpiryTime(Time());
- return;
- }
- // Since we're doing left-shift below, make sure we don't shift more
- // than this. E.g. if int is 4-bytes, don't left-shift more than 30 bits,
- // since we don't expect value of kMaxBackoffDays to be more than 100 anyway.
- int num_days = 1; // the value to be shifted.
- const int kMaxShifts = (sizeof(num_days) * 8) - 2;
- // Normal backoff days is 2 raised to (payload_attempt_number - 1).
- // E.g. if payload_attempt_number is over 30, limit power to 30.
- int power = min(GetFullPayloadAttemptNumber() - 1, kMaxShifts);
- // The number of days is the minimum of 2 raised to (payload_attempt_number
- // - 1) or kMaxBackoffDays.
- num_days = min(num_days << power, kMaxBackoffDays);
- // We don't want all retries to happen exactly at the same time when
- // retrying after backoff. So add some random minutes to fuzz.
- int fuzz_minutes = utils::FuzzInt(0, kMaxBackoffFuzzMinutes);
- TimeDelta next_backoff_interval =
- TimeDelta::FromDays(num_days) + TimeDelta::FromMinutes(fuzz_minutes);
- LOG(INFO) << "Incrementing the backoff expiry time by "
- << utils::FormatTimeDelta(next_backoff_interval);
- SetBackoffExpiryTime(Time::Now() + next_backoff_interval);
- }
- void PayloadState::UpdateCurrentDownloadSource() {
- current_download_source_ = kNumDownloadSources;
- if (using_p2p_for_downloading_) {
- current_download_source_ = kDownloadSourceHttpPeer;
- } else if (payload_index_ < candidate_urls_.size() &&
- candidate_urls_[payload_index_].size() != 0) {
- const string& current_url = candidate_urls_[payload_index_][GetUrlIndex()];
- if (base::StartsWith(
- current_url, "https://", base::CompareCase::INSENSITIVE_ASCII)) {
- current_download_source_ = kDownloadSourceHttpsServer;
- } else if (base::StartsWith(current_url,
- "http://",
- base::CompareCase::INSENSITIVE_ASCII)) {
- current_download_source_ = kDownloadSourceHttpServer;
- }
- }
- LOG(INFO) << "Current download source: "
- << utils::ToString(current_download_source_);
- }
- void PayloadState::UpdateBytesDownloaded(size_t count) {
- SetCurrentBytesDownloaded(
- current_download_source_,
- GetCurrentBytesDownloaded(current_download_source_) + count,
- false);
- SetTotalBytesDownloaded(
- current_download_source_,
- GetTotalBytesDownloaded(current_download_source_) + count,
- false);
- attempt_num_bytes_downloaded_ += count;
- }
- PayloadType PayloadState::CalculatePayloadType() {
- for (const auto& package : response_.packages) {
- if (package.is_delta) {
- return kPayloadTypeDelta;
- }
- }
- OmahaRequestParams* params = system_state_->request_params();
- if (params->delta_okay()) {
- return kPayloadTypeFull;
- }
- // Full payload, delta was not allowed by request.
- return kPayloadTypeForcedFull;
- }
- // TODO(zeuthen): Currently we don't report the UpdateEngine.Attempt.*
- // metrics if the attempt ends abnormally, e.g. if the update_engine
- // process crashes or the device is rebooted. See
- // http://crbug.com/357676
- void PayloadState::CollectAndReportAttemptMetrics(ErrorCode code) {
- int attempt_number = GetPayloadAttemptNumber();
- PayloadType payload_type = CalculatePayloadType();
- int64_t payload_size = GetPayloadSize();
- int64_t payload_bytes_downloaded = attempt_num_bytes_downloaded_;
- ClockInterface* clock = system_state_->clock();
- TimeDelta duration = clock->GetBootTime() - attempt_start_time_boot_;
- TimeDelta duration_uptime =
- clock->GetMonotonicTime() - attempt_start_time_monotonic_;
- int64_t payload_download_speed_bps = 0;
- int64_t usec = duration_uptime.InMicroseconds();
- if (usec > 0) {
- double sec = static_cast<double>(usec) / Time::kMicrosecondsPerSecond;
- double bps = static_cast<double>(payload_bytes_downloaded) / sec;
- payload_download_speed_bps = static_cast<int64_t>(bps);
- }
- DownloadSource download_source = current_download_source_;
- metrics::DownloadErrorCode payload_download_error_code =
- metrics::DownloadErrorCode::kUnset;
- ErrorCode internal_error_code = ErrorCode::kSuccess;
- metrics::AttemptResult attempt_result = metrics_utils::GetAttemptResult(code);
- // Add additional detail to AttemptResult
- switch (attempt_result) {
- case metrics::AttemptResult::kPayloadDownloadError:
- payload_download_error_code = metrics_utils::GetDownloadErrorCode(code);
- break;
- case metrics::AttemptResult::kInternalError:
- internal_error_code = code;
- break;
- // Explicit fall-through for cases where we do not have additional
- // detail. We avoid the default keyword to force people adding new
- // AttemptResult values to visit this code and examine whether
- // additional detail is needed.
- case metrics::AttemptResult::kUpdateSucceeded:
- case metrics::AttemptResult::kMetadataMalformed:
- case metrics::AttemptResult::kOperationMalformed:
- case metrics::AttemptResult::kOperationExecutionError:
- case metrics::AttemptResult::kMetadataVerificationFailed:
- case metrics::AttemptResult::kPayloadVerificationFailed:
- case metrics::AttemptResult::kVerificationFailed:
- case metrics::AttemptResult::kPostInstallFailed:
- case metrics::AttemptResult::kAbnormalTermination:
- case metrics::AttemptResult::kUpdateCanceled:
- case metrics::AttemptResult::kUpdateSucceededNotActive:
- case metrics::AttemptResult::kNumConstants:
- case metrics::AttemptResult::kUnset:
- break;
- }
- system_state_->metrics_reporter()->ReportUpdateAttemptMetrics(
- system_state_,
- attempt_number,
- payload_type,
- duration,
- duration_uptime,
- payload_size,
- attempt_result,
- internal_error_code);
- system_state_->metrics_reporter()->ReportUpdateAttemptDownloadMetrics(
- payload_bytes_downloaded,
- payload_download_speed_bps,
- download_source,
- payload_download_error_code,
- attempt_connection_type_);
- }
- void PayloadState::PersistAttemptMetrics() {
- // TODO(zeuthen): For now we only persist whether an attempt was in
- // progress and not values/metrics related to the attempt. This
- // means that when this happens, of all the UpdateEngine.Attempt.*
- // metrics, only UpdateEngine.Attempt.Result is reported (with the
- // value |kAbnormalTermination|). In the future we might want to
- // persist more data so we can report other metrics in the
- // UpdateEngine.Attempt.* namespace when this happens.
- prefs_->SetBoolean(kPrefsAttemptInProgress, true);
- }
- void PayloadState::ClearPersistedAttemptMetrics() {
- prefs_->Delete(kPrefsAttemptInProgress);
- }
- void PayloadState::ReportAndClearPersistedAttemptMetrics() {
- bool attempt_in_progress = false;
- if (!prefs_->GetBoolean(kPrefsAttemptInProgress, &attempt_in_progress))
- return;
- if (!attempt_in_progress)
- return;
- system_state_->metrics_reporter()
- ->ReportAbnormallyTerminatedUpdateAttemptMetrics();
- ClearPersistedAttemptMetrics();
- }
- void PayloadState::CollectAndReportSuccessfulUpdateMetrics() {
- string metric;
- // Report metrics collected from all known download sources to UMA.
- int64_t total_bytes_by_source[kNumDownloadSources];
- int64_t successful_bytes = 0;
- int64_t total_bytes = 0;
- int64_t successful_mbs = 0;
- int64_t total_mbs = 0;
- for (int i = 0; i < kNumDownloadSources; i++) {
- DownloadSource source = static_cast<DownloadSource>(i);
- int64_t bytes;
- // Only consider this download source (and send byte counts) as
- // having been used if we downloaded a non-trivial amount of bytes
- // (e.g. at least 1 MiB) that contributed to the final success of
- // the update. Otherwise we're going to end up with a lot of
- // zero-byte events in the histogram.
- bytes = GetCurrentBytesDownloaded(source);
- successful_bytes += bytes;
- successful_mbs += bytes / kNumBytesInOneMiB;
- SetCurrentBytesDownloaded(source, 0, true);
- bytes = GetTotalBytesDownloaded(source);
- total_bytes_by_source[i] = bytes;
- total_bytes += bytes;
- total_mbs += bytes / kNumBytesInOneMiB;
- SetTotalBytesDownloaded(source, 0, true);
- }
- int download_overhead_percentage = 0;
- if (successful_bytes > 0) {
- download_overhead_percentage =
- (total_bytes - successful_bytes) * 100ULL / successful_bytes;
- }
- int url_switch_count = static_cast<int>(url_switch_count_);
- int reboot_count = GetNumReboots();
- SetNumReboots(0);
- TimeDelta duration = GetUpdateDuration();
- TimeDelta duration_uptime = GetUpdateDurationUptime();
- prefs_->Delete(kPrefsUpdateTimestampStart);
- prefs_->Delete(kPrefsUpdateDurationUptime);
- PayloadType payload_type = CalculatePayloadType();
- int64_t payload_size = GetPayloadSize();
- int attempt_count = GetPayloadAttemptNumber();
- int updates_abandoned_count = num_responses_seen_ - 1;
- system_state_->metrics_reporter()->ReportSuccessfulUpdateMetrics(
- attempt_count,
- updates_abandoned_count,
- payload_type,
- payload_size,
- total_bytes_by_source,
- download_overhead_percentage,
- duration,
- duration_uptime,
- reboot_count,
- url_switch_count);
- }
- void PayloadState::UpdateNumReboots() {
- // We only update the reboot count when the system has been detected to have
- // been rebooted.
- if (!system_state_->system_rebooted()) {
- return;
- }
- SetNumReboots(GetNumReboots() + 1);
- }
- void PayloadState::SetNumReboots(uint32_t num_reboots) {
- num_reboots_ = num_reboots;
- metrics_utils::SetNumReboots(num_reboots, prefs_);
- }
- void PayloadState::ResetPersistedState() {
- SetPayloadAttemptNumber(0);
- SetFullPayloadAttemptNumber(0);
- SetPayloadIndex(0);
- SetUrlIndex(0);
- SetUrlFailureCount(0);
- SetUrlSwitchCount(0);
- UpdateBackoffExpiryTime(); // This will reset the backoff expiry time.
- SetUpdateTimestampStart(system_state_->clock()->GetWallclockTime());
- SetUpdateTimestampEnd(Time()); // Set to null time
- SetUpdateDurationUptime(TimeDelta::FromSeconds(0));
- ResetDownloadSourcesOnNewUpdate();
- ResetRollbackVersion();
- SetP2PNumAttempts(0);
- SetP2PFirstAttemptTimestamp(Time()); // Set to null time
- SetScatteringWaitPeriod(TimeDelta());
- SetStagingWaitPeriod(TimeDelta());
- }
- void PayloadState::ResetRollbackVersion() {
- CHECK(powerwash_safe_prefs_);
- rollback_version_ = "";
- powerwash_safe_prefs_->Delete(kPrefsRollbackVersion);
- }
- void PayloadState::ResetDownloadSourcesOnNewUpdate() {
- for (int i = 0; i < kNumDownloadSources; i++) {
- DownloadSource source = static_cast<DownloadSource>(i);
- SetCurrentBytesDownloaded(source, 0, true);
- // Note: Not resetting the TotalBytesDownloaded as we want that metric
- // to count the bytes downloaded across various update attempts until
- // we have successfully applied the update.
- }
- }
- string PayloadState::CalculateResponseSignature() {
- string response_sign;
- for (size_t i = 0; i < response_.packages.size(); i++) {
- const auto& package = response_.packages[i];
- response_sign += base::StringPrintf(
- "Payload %zu:\n"
- " Size = %ju\n"
- " Sha256 Hash = %s\n"
- " Metadata Size = %ju\n"
- " Metadata Signature = %s\n"
- " Is Delta = %d\n"
- " NumURLs = %zu\n",
- i,
- static_cast<uintmax_t>(package.size),
- package.hash.c_str(),
- static_cast<uintmax_t>(package.metadata_size),
- package.metadata_signature.c_str(),
- package.is_delta,
- candidate_urls_[i].size());
- for (size_t j = 0; j < candidate_urls_[i].size(); j++)
- response_sign += base::StringPrintf(
- " Candidate Url%zu = %s\n", j, candidate_urls_[i][j].c_str());
- }
- response_sign += base::StringPrintf(
- "Max Failure Count Per Url = %d\n"
- "Disable Payload Backoff = %d\n",
- response_.max_failure_count_per_url,
- response_.disable_payload_backoff);
- return response_sign;
- }
- void PayloadState::LoadResponseSignature() {
- CHECK(prefs_);
- string stored_value;
- if (prefs_->Exists(kPrefsCurrentResponseSignature) &&
- prefs_->GetString(kPrefsCurrentResponseSignature, &stored_value)) {
- SetResponseSignature(stored_value);
- }
- }
- void PayloadState::SetResponseSignature(const string& response_signature) {
- CHECK(prefs_);
- response_signature_ = response_signature;
- LOG(INFO) << "Current Response Signature = \n" << response_signature_;
- prefs_->SetString(kPrefsCurrentResponseSignature, response_signature_);
- }
- void PayloadState::LoadPayloadAttemptNumber() {
- SetPayloadAttemptNumber(
- GetPersistedValue(kPrefsPayloadAttemptNumber, prefs_));
- }
- void PayloadState::LoadFullPayloadAttemptNumber() {
- SetFullPayloadAttemptNumber(
- GetPersistedValue(kPrefsFullPayloadAttemptNumber, prefs_));
- }
- void PayloadState::SetPayloadAttemptNumber(int payload_attempt_number) {
- payload_attempt_number_ = payload_attempt_number;
- metrics_utils::SetPayloadAttemptNumber(payload_attempt_number, prefs_);
- }
- void PayloadState::SetFullPayloadAttemptNumber(
- int full_payload_attempt_number) {
- CHECK(prefs_);
- full_payload_attempt_number_ = full_payload_attempt_number;
- LOG(INFO) << "Full Payload Attempt Number = " << full_payload_attempt_number_;
- prefs_->SetInt64(kPrefsFullPayloadAttemptNumber,
- full_payload_attempt_number_);
- }
- void PayloadState::SetPayloadIndex(size_t payload_index) {
- CHECK(prefs_);
- payload_index_ = payload_index;
- LOG(INFO) << "Payload Index = " << payload_index_;
- prefs_->SetInt64(kPrefsUpdateStatePayloadIndex, payload_index_);
- }
- bool PayloadState::NextPayload() {
- if (payload_index_ + 1 >= candidate_urls_.size())
- return false;
- SetPayloadIndex(payload_index_ + 1);
- return true;
- }
- void PayloadState::LoadUrlIndex() {
- SetUrlIndex(GetPersistedValue(kPrefsCurrentUrlIndex, prefs_));
- }
- void PayloadState::SetUrlIndex(uint32_t url_index) {
- CHECK(prefs_);
- url_index_ = url_index;
- LOG(INFO) << "Current URL Index = " << url_index_;
- prefs_->SetInt64(kPrefsCurrentUrlIndex, url_index_);
- // Also update the download source, which is purely dependent on the
- // current URL index alone.
- UpdateCurrentDownloadSource();
- }
- void PayloadState::LoadScatteringWaitPeriod() {
- SetScatteringWaitPeriod(TimeDelta::FromSeconds(
- GetPersistedValue(kPrefsWallClockScatteringWaitPeriod, prefs_)));
- }
- void PayloadState::SetScatteringWaitPeriod(TimeDelta wait_period) {
- CHECK(prefs_);
- scattering_wait_period_ = wait_period;
- LOG(INFO) << "Scattering Wait Period (seconds) = "
- << scattering_wait_period_.InSeconds();
- if (scattering_wait_period_.InSeconds() > 0) {
- prefs_->SetInt64(kPrefsWallClockScatteringWaitPeriod,
- scattering_wait_period_.InSeconds());
- } else {
- prefs_->Delete(kPrefsWallClockScatteringWaitPeriod);
- }
- }
- void PayloadState::LoadStagingWaitPeriod() {
- SetStagingWaitPeriod(TimeDelta::FromSeconds(
- GetPersistedValue(kPrefsWallClockStagingWaitPeriod, prefs_)));
- }
- void PayloadState::SetStagingWaitPeriod(TimeDelta wait_period) {
- CHECK(prefs_);
- staging_wait_period_ = wait_period;
- LOG(INFO) << "Staging Wait Period (days) =" << staging_wait_period_.InDays();
- if (staging_wait_period_.InSeconds() > 0) {
- prefs_->SetInt64(kPrefsWallClockStagingWaitPeriod,
- staging_wait_period_.InSeconds());
- } else {
- prefs_->Delete(kPrefsWallClockStagingWaitPeriod);
- }
- }
- void PayloadState::LoadUrlSwitchCount() {
- SetUrlSwitchCount(GetPersistedValue(kPrefsUrlSwitchCount, prefs_));
- }
- void PayloadState::SetUrlSwitchCount(uint32_t url_switch_count) {
- CHECK(prefs_);
- url_switch_count_ = url_switch_count;
- LOG(INFO) << "URL Switch Count = " << url_switch_count_;
- prefs_->SetInt64(kPrefsUrlSwitchCount, url_switch_count_);
- }
- void PayloadState::LoadUrlFailureCount() {
- SetUrlFailureCount(GetPersistedValue(kPrefsCurrentUrlFailureCount, prefs_));
- }
- void PayloadState::SetUrlFailureCount(uint32_t url_failure_count) {
- CHECK(prefs_);
- url_failure_count_ = url_failure_count;
- LOG(INFO) << "Current URL (Url" << GetUrlIndex()
- << ")'s Failure Count = " << url_failure_count_;
- prefs_->SetInt64(kPrefsCurrentUrlFailureCount, url_failure_count_);
- }
- void PayloadState::LoadBackoffExpiryTime() {
- CHECK(prefs_);
- int64_t stored_value;
- if (!prefs_->Exists(kPrefsBackoffExpiryTime))
- return;
- if (!prefs_->GetInt64(kPrefsBackoffExpiryTime, &stored_value))
- return;
- Time stored_time = Time::FromInternalValue(stored_value);
- if (stored_time > Time::Now() + TimeDelta::FromDays(kMaxBackoffDays)) {
- LOG(ERROR) << "Invalid backoff expiry time ("
- << utils::ToString(stored_time)
- << ") in persisted state. Resetting.";
- stored_time = Time();
- }
- SetBackoffExpiryTime(stored_time);
- }
- void PayloadState::SetBackoffExpiryTime(const Time& new_time) {
- CHECK(prefs_);
- backoff_expiry_time_ = new_time;
- LOG(INFO) << "Backoff Expiry Time = "
- << utils::ToString(backoff_expiry_time_);
- prefs_->SetInt64(kPrefsBackoffExpiryTime,
- backoff_expiry_time_.ToInternalValue());
- }
- TimeDelta PayloadState::GetUpdateDuration() {
- Time end_time = update_timestamp_end_.is_null()
- ? system_state_->clock()->GetWallclockTime()
- : update_timestamp_end_;
- return end_time - update_timestamp_start_;
- }
- void PayloadState::LoadUpdateTimestampStart() {
- int64_t stored_value;
- Time stored_time;
- CHECK(prefs_);
- Time now = system_state_->clock()->GetWallclockTime();
- if (!prefs_->Exists(kPrefsUpdateTimestampStart)) {
- // The preference missing is not unexpected - in that case, just
- // use the current time as start time
- stored_time = now;
- } else if (!prefs_->GetInt64(kPrefsUpdateTimestampStart, &stored_value)) {
- LOG(ERROR) << "Invalid UpdateTimestampStart value. Resetting.";
- stored_time = now;
- } else {
- stored_time = Time::FromInternalValue(stored_value);
- }
- // Sanity check: If the time read from disk is in the future
- // (modulo some slack to account for possible NTP drift
- // adjustments), something is fishy and we should report and
- // reset.
- TimeDelta duration_according_to_stored_time = now - stored_time;
- if (duration_according_to_stored_time < -kDurationSlack) {
- LOG(ERROR) << "The UpdateTimestampStart value ("
- << utils::ToString(stored_time) << ") in persisted state is "
- << utils::FormatTimeDelta(duration_according_to_stored_time)
- << " in the future. Resetting.";
- stored_time = now;
- }
- SetUpdateTimestampStart(stored_time);
- }
- void PayloadState::SetUpdateTimestampStart(const Time& value) {
- update_timestamp_start_ = value;
- metrics_utils::SetUpdateTimestampStart(value, prefs_);
- }
- void PayloadState::SetUpdateTimestampEnd(const Time& value) {
- update_timestamp_end_ = value;
- LOG(INFO) << "Update Timestamp End = "
- << utils::ToString(update_timestamp_end_);
- }
- TimeDelta PayloadState::GetUpdateDurationUptime() {
- return update_duration_uptime_;
- }
- void PayloadState::LoadUpdateDurationUptime() {
- int64_t stored_value;
- TimeDelta stored_delta;
- CHECK(prefs_);
- if (!prefs_->Exists(kPrefsUpdateDurationUptime)) {
- // The preference missing is not unexpected - in that case, just
- // we'll use zero as the delta
- } else if (!prefs_->GetInt64(kPrefsUpdateDurationUptime, &stored_value)) {
- LOG(ERROR) << "Invalid UpdateDurationUptime value. Resetting.";
- stored_delta = TimeDelta::FromSeconds(0);
- } else {
- stored_delta = TimeDelta::FromInternalValue(stored_value);
- }
- // Sanity-check: Uptime can never be greater than the wall-clock
- // difference (modulo some slack). If it is, report and reset
- // to the wall-clock difference.
- TimeDelta diff = GetUpdateDuration() - stored_delta;
- if (diff < -kDurationSlack) {
- LOG(ERROR) << "The UpdateDurationUptime value ("
- << utils::FormatTimeDelta(stored_delta)
- << ") in persisted state is " << utils::FormatTimeDelta(diff)
- << " larger than the wall-clock delta. Resetting.";
- stored_delta = update_duration_current_;
- }
- SetUpdateDurationUptime(stored_delta);
- }
- void PayloadState::LoadNumReboots() {
- SetNumReboots(GetPersistedValue(kPrefsNumReboots, prefs_));
- }
- void PayloadState::LoadRollbackHappened() {
- CHECK(powerwash_safe_prefs_);
- bool rollback_happened = false;
- powerwash_safe_prefs_->GetBoolean(kPrefsRollbackHappened, &rollback_happened);
- SetRollbackHappened(rollback_happened);
- }
- void PayloadState::SetRollbackHappened(bool rollback_happened) {
- CHECK(powerwash_safe_prefs_);
- LOG(INFO) << "Setting rollback-happened to " << rollback_happened << ".";
- rollback_happened_ = rollback_happened;
- if (rollback_happened) {
- powerwash_safe_prefs_->SetBoolean(kPrefsRollbackHappened,
- rollback_happened);
- } else {
- powerwash_safe_prefs_->Delete(kPrefsRollbackHappened);
- }
- }
- void PayloadState::LoadRollbackVersion() {
- CHECK(powerwash_safe_prefs_);
- string rollback_version;
- if (powerwash_safe_prefs_->GetString(kPrefsRollbackVersion,
- &rollback_version)) {
- SetRollbackVersion(rollback_version);
- }
- }
- void PayloadState::SetRollbackVersion(const string& rollback_version) {
- CHECK(powerwash_safe_prefs_);
- LOG(INFO) << "Blacklisting version " << rollback_version;
- rollback_version_ = rollback_version;
- powerwash_safe_prefs_->SetString(kPrefsRollbackVersion, rollback_version);
- }
- void PayloadState::SetUpdateDurationUptimeExtended(const TimeDelta& value,
- const Time& timestamp,
- bool use_logging) {
- CHECK(prefs_);
- update_duration_uptime_ = value;
- update_duration_uptime_timestamp_ = timestamp;
- prefs_->SetInt64(kPrefsUpdateDurationUptime,
- update_duration_uptime_.ToInternalValue());
- if (use_logging) {
- LOG(INFO) << "Update Duration Uptime = "
- << utils::FormatTimeDelta(update_duration_uptime_);
- }
- }
- void PayloadState::SetUpdateDurationUptime(const TimeDelta& value) {
- Time now = system_state_->clock()->GetMonotonicTime();
- SetUpdateDurationUptimeExtended(value, now, true);
- }
- void PayloadState::CalculateUpdateDurationUptime() {
- Time now = system_state_->clock()->GetMonotonicTime();
- TimeDelta uptime_since_last_update = now - update_duration_uptime_timestamp_;
- if (uptime_since_last_update > TimeDelta::FromSeconds(kUptimeResolution)) {
- TimeDelta new_uptime = update_duration_uptime_ + uptime_since_last_update;
- // We're frequently called so avoid logging this write
- SetUpdateDurationUptimeExtended(new_uptime, now, false);
- }
- }
- string PayloadState::GetPrefsKey(const string& prefix, DownloadSource source) {
- return prefix + "-from-" + utils::ToString(source);
- }
- void PayloadState::LoadCurrentBytesDownloaded(DownloadSource source) {
- string key = GetPrefsKey(kPrefsCurrentBytesDownloaded, source);
- SetCurrentBytesDownloaded(source, GetPersistedValue(key, prefs_), true);
- }
- void PayloadState::SetCurrentBytesDownloaded(DownloadSource source,
- uint64_t current_bytes_downloaded,
- bool log) {
- CHECK(prefs_);
- if (source >= kNumDownloadSources)
- return;
- // Update the in-memory value.
- current_bytes_downloaded_[source] = current_bytes_downloaded;
- string prefs_key = GetPrefsKey(kPrefsCurrentBytesDownloaded, source);
- prefs_->SetInt64(prefs_key, current_bytes_downloaded);
- LOG_IF(INFO, log) << "Current bytes downloaded for "
- << utils::ToString(source) << " = "
- << GetCurrentBytesDownloaded(source);
- }
- void PayloadState::LoadTotalBytesDownloaded(DownloadSource source) {
- string key = GetPrefsKey(kPrefsTotalBytesDownloaded, source);
- SetTotalBytesDownloaded(source, GetPersistedValue(key, prefs_), true);
- }
- void PayloadState::SetTotalBytesDownloaded(DownloadSource source,
- uint64_t total_bytes_downloaded,
- bool log) {
- CHECK(prefs_);
- if (source >= kNumDownloadSources)
- return;
- // Update the in-memory value.
- total_bytes_downloaded_[source] = total_bytes_downloaded;
- // Persist.
- string prefs_key = GetPrefsKey(kPrefsTotalBytesDownloaded, source);
- prefs_->SetInt64(prefs_key, total_bytes_downloaded);
- LOG_IF(INFO, log) << "Total bytes downloaded for " << utils::ToString(source)
- << " = " << GetTotalBytesDownloaded(source);
- }
- void PayloadState::LoadNumResponsesSeen() {
- SetNumResponsesSeen(GetPersistedValue(kPrefsNumResponsesSeen, prefs_));
- }
- void PayloadState::SetNumResponsesSeen(int num_responses_seen) {
- CHECK(prefs_);
- num_responses_seen_ = num_responses_seen;
- LOG(INFO) << "Num Responses Seen = " << num_responses_seen_;
- prefs_->SetInt64(kPrefsNumResponsesSeen, num_responses_seen_);
- }
- void PayloadState::ComputeCandidateUrls() {
- bool http_url_ok = true;
- if (system_state_->hardware()->IsOfficialBuild()) {
- const policy::DevicePolicy* policy = system_state_->device_policy();
- if (policy && policy->GetHttpDownloadsEnabled(&http_url_ok) && !http_url_ok)
- LOG(INFO) << "Downloads via HTTP Url are not enabled by device policy";
- } else {
- LOG(INFO) << "Allowing HTTP downloads for unofficial builds";
- http_url_ok = true;
- }
- candidate_urls_.clear();
- for (const auto& package : response_.packages) {
- candidate_urls_.emplace_back();
- for (const string& candidate_url : package.payload_urls) {
- if (base::StartsWith(
- candidate_url, "http://", base::CompareCase::INSENSITIVE_ASCII) &&
- !http_url_ok) {
- continue;
- }
- candidate_urls_.back().push_back(candidate_url);
- LOG(INFO) << "Candidate Url" << (candidate_urls_.back().size() - 1)
- << ": " << candidate_url;
- }
- LOG(INFO) << "Found " << candidate_urls_.back().size() << " candidate URLs "
- << "out of " << package.payload_urls.size()
- << " URLs supplied in package " << candidate_urls_.size() - 1;
- }
- }
- void PayloadState::UpdateEngineStarted() {
- // Flush previous state from abnormal attempt failure, if any.
- ReportAndClearPersistedAttemptMetrics();
- // Avoid the UpdateEngineStarted actions if this is not the first time we
- // run the update engine since reboot.
- if (!system_state_->system_rebooted())
- return;
- // Report time_to_reboot if we booted into a new update.
- metrics_utils::LoadAndReportTimeToReboot(
- system_state_->metrics_reporter(), prefs_, system_state_->clock());
- prefs_->Delete(kPrefsSystemUpdatedMarker);
- // Check if it is needed to send metrics about a failed reboot into a new
- // version.
- ReportFailedBootIfNeeded();
- }
- void PayloadState::ReportFailedBootIfNeeded() {
- // If the kPrefsTargetVersionInstalledFrom is present, a successfully applied
- // payload was marked as ready immediately before the last reboot, and we
- // need to check if such payload successfully rebooted or not.
- if (prefs_->Exists(kPrefsTargetVersionInstalledFrom)) {
- int64_t installed_from = 0;
- if (!prefs_->GetInt64(kPrefsTargetVersionInstalledFrom, &installed_from)) {
- LOG(ERROR) << "Error reading TargetVersionInstalledFrom on reboot.";
- return;
- }
- // Old Chrome OS devices will write 2 or 4 in this setting, with the
- // partition number. We are now using slot numbers (0 or 1) instead, so
- // the following comparison will not match if we are comparing an old
- // partition number against a new slot number, which is the correct outcome
- // since we successfully booted the new update in that case. If the boot
- // failed, we will read this value from the same version, so it will always
- // be compatible.
- if (installed_from == system_state_->boot_control()->GetCurrentSlot()) {
- // A reboot was pending, but the chromebook is again in the same
- // BootDevice where the update was installed from.
- int64_t target_attempt;
- if (!prefs_->GetInt64(kPrefsTargetVersionAttempt, &target_attempt)) {
- LOG(ERROR) << "Error reading TargetVersionAttempt when "
- "TargetVersionInstalledFrom was present.";
- target_attempt = 1;
- }
- // Report the UMA metric of the current boot failure.
- system_state_->metrics_reporter()->ReportFailedUpdateCount(
- target_attempt);
- } else {
- prefs_->Delete(kPrefsTargetVersionAttempt);
- prefs_->Delete(kPrefsTargetVersionUniqueId);
- }
- prefs_->Delete(kPrefsTargetVersionInstalledFrom);
- }
- }
- void PayloadState::ExpectRebootInNewVersion(const string& target_version_uid) {
- // Expect to boot into the new partition in the next reboot setting the
- // TargetVersion* flags in the Prefs.
- string stored_target_version_uid;
- string target_version_id;
- string target_partition;
- int64_t target_attempt;
- if (prefs_->Exists(kPrefsTargetVersionUniqueId) &&
- prefs_->GetString(kPrefsTargetVersionUniqueId,
- &stored_target_version_uid) &&
- stored_target_version_uid == target_version_uid) {
- if (!prefs_->GetInt64(kPrefsTargetVersionAttempt, &target_attempt))
- target_attempt = 0;
- } else {
- prefs_->SetString(kPrefsTargetVersionUniqueId, target_version_uid);
- target_attempt = 0;
- }
- prefs_->SetInt64(kPrefsTargetVersionAttempt, target_attempt + 1);
- prefs_->SetInt64(kPrefsTargetVersionInstalledFrom,
- system_state_->boot_control()->GetCurrentSlot());
- }
- void PayloadState::ResetUpdateStatus() {
- // Remove the TargetVersionInstalledFrom pref so that if the machine is
- // rebooted the next boot is not flagged as failed to rebooted into the
- // new applied payload.
- prefs_->Delete(kPrefsTargetVersionInstalledFrom);
- // Also decrement the attempt number if it exists.
- int64_t target_attempt;
- if (prefs_->GetInt64(kPrefsTargetVersionAttempt, &target_attempt))
- prefs_->SetInt64(kPrefsTargetVersionAttempt, target_attempt - 1);
- }
- int PayloadState::GetP2PNumAttempts() {
- return p2p_num_attempts_;
- }
- void PayloadState::SetP2PNumAttempts(int value) {
- p2p_num_attempts_ = value;
- LOG(INFO) << "p2p Num Attempts = " << p2p_num_attempts_;
- CHECK(prefs_);
- prefs_->SetInt64(kPrefsP2PNumAttempts, value);
- }
- void PayloadState::LoadP2PNumAttempts() {
- SetP2PNumAttempts(GetPersistedValue(kPrefsP2PNumAttempts, prefs_));
- }
- Time PayloadState::GetP2PFirstAttemptTimestamp() {
- return p2p_first_attempt_timestamp_;
- }
- void PayloadState::SetP2PFirstAttemptTimestamp(const Time& time) {
- p2p_first_attempt_timestamp_ = time;
- LOG(INFO) << "p2p First Attempt Timestamp = "
- << utils::ToString(p2p_first_attempt_timestamp_);
- CHECK(prefs_);
- int64_t stored_value = time.ToInternalValue();
- prefs_->SetInt64(kPrefsP2PFirstAttemptTimestamp, stored_value);
- }
- void PayloadState::LoadP2PFirstAttemptTimestamp() {
- int64_t stored_value =
- GetPersistedValue(kPrefsP2PFirstAttemptTimestamp, prefs_);
- Time stored_time = Time::FromInternalValue(stored_value);
- SetP2PFirstAttemptTimestamp(stored_time);
- }
- void PayloadState::P2PNewAttempt() {
- CHECK(prefs_);
- // Set timestamp, if it hasn't been set already
- if (p2p_first_attempt_timestamp_.is_null()) {
- SetP2PFirstAttemptTimestamp(system_state_->clock()->GetWallclockTime());
- }
- // Increase number of attempts
- SetP2PNumAttempts(GetP2PNumAttempts() + 1);
- }
- bool PayloadState::P2PAttemptAllowed() {
- if (p2p_num_attempts_ > kMaxP2PAttempts) {
- LOG(INFO) << "Number of p2p attempts is " << p2p_num_attempts_
- << " which is greater than " << kMaxP2PAttempts
- << " - disallowing p2p.";
- return false;
- }
- if (!p2p_first_attempt_timestamp_.is_null()) {
- Time now = system_state_->clock()->GetWallclockTime();
- TimeDelta time_spent_attempting_p2p = now - p2p_first_attempt_timestamp_;
- if (time_spent_attempting_p2p.InSeconds() < 0) {
- LOG(ERROR) << "Time spent attempting p2p is negative"
- << " - disallowing p2p.";
- return false;
- }
- if (time_spent_attempting_p2p.InSeconds() > kMaxP2PAttemptTimeSeconds) {
- LOG(INFO) << "Time spent attempting p2p is "
- << utils::FormatTimeDelta(time_spent_attempting_p2p)
- << " which is greater than "
- << utils::FormatTimeDelta(
- TimeDelta::FromSeconds(kMaxP2PAttemptTimeSeconds))
- << " - disallowing p2p.";
- return false;
- }
- }
- return true;
- }
- int64_t PayloadState::GetPayloadSize() {
- int64_t payload_size = 0;
- for (const auto& package : response_.packages)
- payload_size += package.size;
- return payload_size;
- }
- } // namespace chromeos_update_engine
|