1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678 |
- //
- // 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/update_attempter.h"
- #include <stdint.h>
- #include <algorithm>
- #include <memory>
- #include <string>
- #include <utility>
- #include <vector>
- #include <base/bind.h>
- #include <base/files/file_util.h>
- #include <base/logging.h>
- #include <base/rand_util.h>
- #include <base/strings/string_util.h>
- #include <base/strings/stringprintf.h>
- #include <base/time/time.h>
- #include <brillo/data_encoding.h>
- #include <brillo/errors/error_codes.h>
- #include <brillo/message_loops/message_loop.h>
- #include <policy/device_policy.h>
- #include <policy/libpolicy.h>
- #include <update_engine/dbus-constants.h>
- #include "update_engine/certificate_checker.h"
- #include "update_engine/common/boot_control_interface.h"
- #include "update_engine/common/clock_interface.h"
- #include "update_engine/common/constants.h"
- #include "update_engine/common/dlcservice_interface.h"
- #include "update_engine/common/hardware_interface.h"
- #include "update_engine/common/platform_constants.h"
- #include "update_engine/common/prefs_interface.h"
- #include "update_engine/common/subprocess.h"
- #include "update_engine/common/utils.h"
- #include "update_engine/libcurl_http_fetcher.h"
- #include "update_engine/metrics_reporter_interface.h"
- #include "update_engine/omaha_request_action.h"
- #include "update_engine/omaha_request_params.h"
- #include "update_engine/omaha_response_handler_action.h"
- #include "update_engine/p2p_manager.h"
- #include "update_engine/payload_consumer/download_action.h"
- #include "update_engine/payload_consumer/filesystem_verifier_action.h"
- #include "update_engine/payload_consumer/postinstall_runner_action.h"
- #include "update_engine/payload_state_interface.h"
- #include "update_engine/power_manager_interface.h"
- #include "update_engine/system_state.h"
- #include "update_engine/update_boot_flags_action.h"
- #include "update_engine/update_manager/policy.h"
- #include "update_engine/update_manager/policy_utils.h"
- #include "update_engine/update_manager/update_manager.h"
- #include "update_engine/update_status_utils.h"
- using base::Bind;
- using base::Callback;
- using base::Time;
- using base::TimeDelta;
- using base::TimeTicks;
- using brillo::MessageLoop;
- using chromeos_update_manager::CalculateStagingCase;
- using chromeos_update_manager::EvalStatus;
- using chromeos_update_manager::Policy;
- using chromeos_update_manager::StagingCase;
- using chromeos_update_manager::UpdateCheckParams;
- using std::string;
- using std::vector;
- using update_engine::UpdateAttemptFlags;
- using update_engine::UpdateEngineStatus;
- namespace chromeos_update_engine {
- const int UpdateAttempter::kMaxDeltaUpdateFailures = 3;
- namespace {
- const int kMaxConsecutiveObeyProxyRequests = 20;
- // Minimum threshold to broadcast an status update in progress and time.
- const double kBroadcastThresholdProgress = 0.01; // 1%
- const int kBroadcastThresholdSeconds = 10;
- // By default autest bypasses scattering. If we want to test scattering,
- // use kScheduledAUTestURLRequest. The URL used is same in both cases, but
- // different params are passed to CheckForUpdate().
- const char kAUTestURLRequest[] = "autest";
- const char kScheduledAUTestURLRequest[] = "autest-scheduled";
- } // namespace
- ErrorCode GetErrorCodeForAction(AbstractAction* action, ErrorCode code) {
- if (code != ErrorCode::kError)
- return code;
- const string type = action->Type();
- if (type == OmahaRequestAction::StaticType())
- return ErrorCode::kOmahaRequestError;
- if (type == OmahaResponseHandlerAction::StaticType())
- return ErrorCode::kOmahaResponseHandlerError;
- if (type == FilesystemVerifierAction::StaticType())
- return ErrorCode::kFilesystemVerifierError;
- if (type == PostinstallRunnerAction::StaticType())
- return ErrorCode::kPostinstallRunnerError;
- return code;
- }
- UpdateAttempter::UpdateAttempter(SystemState* system_state,
- CertificateChecker* cert_checker)
- : processor_(new ActionProcessor()),
- system_state_(system_state),
- cert_checker_(cert_checker),
- is_install_(false) {}
- UpdateAttempter::~UpdateAttempter() {
- // CertificateChecker might not be initialized in unittests.
- if (cert_checker_)
- cert_checker_->SetObserver(nullptr);
- // Release ourselves as the ActionProcessor's delegate to prevent
- // re-scheduling the updates due to the processing stopped.
- processor_->set_delegate(nullptr);
- }
- void UpdateAttempter::Init() {
- // Pulling from the SystemState can only be done after construction, since
- // this is an aggregate of various objects (such as the UpdateAttempter),
- // which requires them all to be constructed prior to it being used.
- prefs_ = system_state_->prefs();
- omaha_request_params_ = system_state_->request_params();
- if (cert_checker_)
- cert_checker_->SetObserver(this);
- // In case of update_engine restart without a reboot we need to restore the
- // reboot needed state.
- if (GetBootTimeAtUpdate(nullptr))
- status_ = UpdateStatus::UPDATED_NEED_REBOOT;
- else
- status_ = UpdateStatus::IDLE;
- }
- bool UpdateAttempter::ScheduleUpdates() {
- if (IsUpdateRunningOrScheduled())
- return false;
- chromeos_update_manager::UpdateManager* const update_manager =
- system_state_->update_manager();
- CHECK(update_manager);
- Callback<void(EvalStatus, const UpdateCheckParams&)> callback =
- Bind(&UpdateAttempter::OnUpdateScheduled, base::Unretained(this));
- // We limit the async policy request to a reasonably short time, to avoid a
- // starvation due to a transient bug.
- update_manager->AsyncPolicyRequest(callback, &Policy::UpdateCheckAllowed);
- waiting_for_scheduled_check_ = true;
- return true;
- }
- void UpdateAttempter::CertificateChecked(ServerToCheck server_to_check,
- CertificateCheckResult result) {
- system_state_->metrics_reporter()->ReportCertificateCheckMetrics(
- server_to_check, result);
- }
- bool UpdateAttempter::CheckAndReportDailyMetrics() {
- int64_t stored_value;
- Time now = system_state_->clock()->GetWallclockTime();
- if (system_state_->prefs()->Exists(kPrefsDailyMetricsLastReportedAt) &&
- system_state_->prefs()->GetInt64(kPrefsDailyMetricsLastReportedAt,
- &stored_value)) {
- Time last_reported_at = Time::FromInternalValue(stored_value);
- TimeDelta time_reported_since = now - last_reported_at;
- if (time_reported_since.InSeconds() < 0) {
- LOG(WARNING) << "Last reported daily metrics "
- << utils::FormatTimeDelta(time_reported_since) << " ago "
- << "which is negative. Either the system clock is wrong or "
- << "the kPrefsDailyMetricsLastReportedAt state variable "
- << "is wrong.";
- // In this case, report daily metrics to reset.
- } else {
- if (time_reported_since.InSeconds() < 24 * 60 * 60) {
- LOG(INFO) << "Last reported daily metrics "
- << utils::FormatTimeDelta(time_reported_since) << " ago.";
- return false;
- }
- LOG(INFO) << "Last reported daily metrics "
- << utils::FormatTimeDelta(time_reported_since) << " ago, "
- << "which is more than 24 hours ago.";
- }
- }
- LOG(INFO) << "Reporting daily metrics.";
- system_state_->prefs()->SetInt64(kPrefsDailyMetricsLastReportedAt,
- now.ToInternalValue());
- ReportOSAge();
- return true;
- }
- void UpdateAttempter::ReportOSAge() {
- struct stat sb;
- if (system_state_ == nullptr)
- return;
- if (stat("/etc/lsb-release", &sb) != 0) {
- PLOG(ERROR) << "Error getting file status for /etc/lsb-release "
- << "(Note: this may happen in some unit tests)";
- return;
- }
- Time lsb_release_timestamp = Time::FromTimeSpec(sb.st_ctim);
- Time now = system_state_->clock()->GetWallclockTime();
- TimeDelta age = now - lsb_release_timestamp;
- if (age.InSeconds() < 0) {
- LOG(ERROR) << "The OS age (" << utils::FormatTimeDelta(age)
- << ") is negative. Maybe the clock is wrong? "
- << "(Note: this may happen in some unit tests.)";
- return;
- }
- system_state_->metrics_reporter()->ReportDailyMetrics(age);
- }
- void UpdateAttempter::Update(const string& app_version,
- const string& omaha_url,
- const string& target_channel,
- const string& target_version_prefix,
- bool rollback_allowed,
- bool obey_proxies,
- bool interactive) {
- // This is normally called frequently enough so it's appropriate to use as a
- // hook for reporting daily metrics.
- // TODO(garnold) This should be hooked to a separate (reliable and consistent)
- // timeout event.
- CheckAndReportDailyMetrics();
- fake_update_success_ = false;
- if (status_ == UpdateStatus::UPDATED_NEED_REBOOT) {
- // Although we have applied an update, we still want to ping Omaha
- // to ensure the number of active statistics is accurate.
- //
- // Also convey to the UpdateEngine.Check.Result metric that we're
- // not performing an update check because of this.
- LOG(INFO) << "Not updating b/c we already updated and we're waiting for "
- << "reboot, we'll ping Omaha instead";
- system_state_->metrics_reporter()->ReportUpdateCheckMetrics(
- system_state_,
- metrics::CheckResult::kRebootPending,
- metrics::CheckReaction::kUnset,
- metrics::DownloadErrorCode::kUnset);
- PingOmaha();
- return;
- }
- if (status_ != UpdateStatus::IDLE) {
- // Update in progress. Do nothing
- return;
- }
- if (!CalculateUpdateParams(app_version,
- omaha_url,
- target_channel,
- target_version_prefix,
- rollback_allowed,
- obey_proxies,
- interactive)) {
- return;
- }
- BuildUpdateActions(interactive);
- SetStatusAndNotify(UpdateStatus::CHECKING_FOR_UPDATE);
- // Update the last check time here; it may be re-updated when an Omaha
- // response is received, but this will prevent us from repeatedly scheduling
- // checks in the case where a response is not received.
- UpdateLastCheckedTime();
- ScheduleProcessingStart();
- }
- void UpdateAttempter::RefreshDevicePolicy() {
- // Lazy initialize the policy provider, or reload the latest policy data.
- if (!policy_provider_.get())
- policy_provider_.reset(new policy::PolicyProvider());
- policy_provider_->Reload();
- const policy::DevicePolicy* device_policy = nullptr;
- if (policy_provider_->device_policy_is_loaded())
- device_policy = &policy_provider_->GetDevicePolicy();
- if (device_policy)
- LOG(INFO) << "Device policies/settings present";
- else
- LOG(INFO) << "No device policies/settings present.";
- system_state_->set_device_policy(device_policy);
- system_state_->p2p_manager()->SetDevicePolicy(device_policy);
- }
- void UpdateAttempter::CalculateP2PParams(bool interactive) {
- bool use_p2p_for_downloading = false;
- bool use_p2p_for_sharing = false;
- // Never use p2p for downloading in interactive checks unless the developer
- // has opted in for it via a marker file.
- //
- // (Why would a developer want to opt in? If they are working on the
- // update_engine or p2p codebases so they can actually test their code.)
- if (system_state_ != nullptr) {
- if (!system_state_->p2p_manager()->IsP2PEnabled()) {
- LOG(INFO) << "p2p is not enabled - disallowing p2p for both"
- << " downloading and sharing.";
- } else {
- // Allow p2p for sharing, even in interactive checks.
- use_p2p_for_sharing = true;
- if (!interactive) {
- LOG(INFO) << "Non-interactive check - allowing p2p for downloading";
- use_p2p_for_downloading = true;
- } else {
- LOG(INFO) << "Forcibly disabling use of p2p for downloading "
- << "since this update attempt is interactive.";
- }
- }
- }
- PayloadStateInterface* const payload_state = system_state_->payload_state();
- payload_state->SetUsingP2PForDownloading(use_p2p_for_downloading);
- payload_state->SetUsingP2PForSharing(use_p2p_for_sharing);
- }
- bool UpdateAttempter::CalculateUpdateParams(const string& app_version,
- const string& omaha_url,
- const string& target_channel,
- const string& target_version_prefix,
- bool rollback_allowed,
- bool obey_proxies,
- bool interactive) {
- http_response_code_ = 0;
- PayloadStateInterface* const payload_state = system_state_->payload_state();
- // Refresh the policy before computing all the update parameters.
- RefreshDevicePolicy();
- // Check whether we need to clear the rollback-happened preference after
- // policy is available again.
- UpdateRollbackHappened();
- // Update the target version prefix.
- omaha_request_params_->set_target_version_prefix(target_version_prefix);
- // Set whether rollback is allowed.
- omaha_request_params_->set_rollback_allowed(rollback_allowed);
- CalculateStagingParams(interactive);
- // If staging_wait_time_ wasn't set, staging is off, use scattering instead.
- if (staging_wait_time_.InSeconds() == 0) {
- CalculateScatteringParams(interactive);
- }
- CalculateP2PParams(interactive);
- if (payload_state->GetUsingP2PForDownloading() ||
- payload_state->GetUsingP2PForSharing()) {
- // OK, p2p is to be used - start it and perform housekeeping.
- if (!StartP2PAndPerformHousekeeping()) {
- // If this fails, disable p2p for this attempt
- LOG(INFO) << "Forcibly disabling use of p2p since starting p2p or "
- << "performing housekeeping failed.";
- payload_state->SetUsingP2PForDownloading(false);
- payload_state->SetUsingP2PForSharing(false);
- }
- }
- if (!omaha_request_params_->Init(app_version, omaha_url, interactive)) {
- LOG(ERROR) << "Unable to initialize Omaha request params.";
- return false;
- }
- // Set the target channel, if one was provided.
- if (target_channel.empty()) {
- LOG(INFO) << "No target channel mandated by policy.";
- } else {
- LOG(INFO) << "Setting target channel as mandated: " << target_channel;
- // Pass in false for powerwash_allowed until we add it to the policy
- // protobuf.
- string error_message;
- if (!omaha_request_params_->SetTargetChannel(
- target_channel, false, &error_message)) {
- LOG(ERROR) << "Setting the channel failed: " << error_message;
- }
- // Since this is the beginning of a new attempt, update the download
- // channel. The download channel won't be updated until the next attempt,
- // even if target channel changes meanwhile, so that how we'll know if we
- // should cancel the current download attempt if there's such a change in
- // target channel.
- omaha_request_params_->UpdateDownloadChannel();
- }
- // Set the DLC module ID list.
- omaha_request_params_->set_dlc_module_ids(dlc_module_ids_);
- omaha_request_params_->set_is_install(is_install_);
- LOG(INFO) << "target_version_prefix = "
- << omaha_request_params_->target_version_prefix()
- << ", rollback_allowed = "
- << omaha_request_params_->rollback_allowed()
- << ", scatter_factor_in_seconds = "
- << utils::FormatSecs(scatter_factor_.InSeconds());
- LOG(INFO) << "Wall Clock Based Wait Enabled = "
- << omaha_request_params_->wall_clock_based_wait_enabled()
- << ", Update Check Count Wait Enabled = "
- << omaha_request_params_->update_check_count_wait_enabled()
- << ", Waiting Period = "
- << utils::FormatSecs(
- omaha_request_params_->waiting_period().InSeconds());
- LOG(INFO) << "Use p2p For Downloading = "
- << payload_state->GetUsingP2PForDownloading()
- << ", Use p2p For Sharing = "
- << payload_state->GetUsingP2PForSharing();
- obeying_proxies_ = true;
- if (obey_proxies || proxy_manual_checks_ == 0) {
- LOG(INFO) << "forced to obey proxies";
- // If forced to obey proxies, every 20th request will not use proxies
- proxy_manual_checks_++;
- LOG(INFO) << "proxy manual checks: " << proxy_manual_checks_;
- if (proxy_manual_checks_ >= kMaxConsecutiveObeyProxyRequests) {
- proxy_manual_checks_ = 0;
- obeying_proxies_ = false;
- }
- } else if (base::RandInt(0, 4) == 0) {
- obeying_proxies_ = false;
- }
- LOG_IF(INFO, !obeying_proxies_)
- << "To help ensure updates work, this update check we are ignoring the "
- << "proxy settings and using direct connections.";
- DisableDeltaUpdateIfNeeded();
- return true;
- }
- void UpdateAttempter::CalculateScatteringParams(bool interactive) {
- // Take a copy of the old scatter value before we update it, as
- // we need to update the waiting period if this value changes.
- TimeDelta old_scatter_factor = scatter_factor_;
- const policy::DevicePolicy* device_policy = system_state_->device_policy();
- if (device_policy) {
- int64_t new_scatter_factor_in_secs = 0;
- device_policy->GetScatterFactorInSeconds(&new_scatter_factor_in_secs);
- if (new_scatter_factor_in_secs < 0) // sanitize input, just in case.
- new_scatter_factor_in_secs = 0;
- scatter_factor_ = TimeDelta::FromSeconds(new_scatter_factor_in_secs);
- }
- bool is_scatter_enabled = false;
- if (scatter_factor_.InSeconds() == 0) {
- LOG(INFO) << "Scattering disabled since scatter factor is set to 0";
- } else if (interactive) {
- LOG(INFO) << "Scattering disabled as this is an interactive update check";
- } else if (system_state_->hardware()->IsOOBEEnabled() &&
- !system_state_->hardware()->IsOOBEComplete(nullptr)) {
- LOG(INFO) << "Scattering disabled since OOBE is enabled but not complete "
- "yet";
- } else {
- is_scatter_enabled = true;
- LOG(INFO) << "Scattering is enabled";
- }
- if (is_scatter_enabled) {
- // This means the scattering policy is turned on.
- // Now check if we need to update the waiting period. The two cases
- // in which we'd need to update the waiting period are:
- // 1. First time in process or a scheduled check after a user-initiated one.
- // (omaha_request_params_->waiting_period will be zero in this case).
- // 2. Admin has changed the scattering policy value.
- // (new scattering value will be different from old one in this case).
- int64_t wait_period_in_secs = 0;
- if (omaha_request_params_->waiting_period().InSeconds() == 0) {
- // First case. Check if we have a suitable value to set for
- // the waiting period.
- if (prefs_->GetInt64(kPrefsWallClockScatteringWaitPeriod,
- &wait_period_in_secs) &&
- wait_period_in_secs > 0 &&
- wait_period_in_secs <= scatter_factor_.InSeconds()) {
- // This means:
- // 1. There's a persisted value for the waiting period available.
- // 2. And that persisted value is still valid.
- // So, in this case, we should reuse the persisted value instead of
- // generating a new random value to improve the chances of a good
- // distribution for scattering.
- omaha_request_params_->set_waiting_period(
- TimeDelta::FromSeconds(wait_period_in_secs));
- LOG(INFO) << "Using persisted wall-clock waiting period: "
- << utils::FormatSecs(
- omaha_request_params_->waiting_period().InSeconds());
- } else {
- // This means there's no persisted value for the waiting period
- // available or its value is invalid given the new scatter_factor value.
- // So, we should go ahead and regenerate a new value for the
- // waiting period.
- LOG(INFO) << "Persisted value not present or not valid ("
- << utils::FormatSecs(wait_period_in_secs)
- << ") for wall-clock waiting period.";
- GenerateNewWaitingPeriod();
- }
- } else if (scatter_factor_ != old_scatter_factor) {
- // This means there's already a waiting period value, but we detected
- // a change in the scattering policy value. So, we should regenerate the
- // waiting period to make sure it's within the bounds of the new scatter
- // factor value.
- GenerateNewWaitingPeriod();
- } else {
- // Neither the first time scattering is enabled nor the scattering value
- // changed. Nothing to do.
- LOG(INFO) << "Keeping current wall-clock waiting period: "
- << utils::FormatSecs(
- omaha_request_params_->waiting_period().InSeconds());
- }
- // The invariant at this point is that omaha_request_params_->waiting_period
- // is non-zero no matter which path we took above.
- LOG_IF(ERROR, omaha_request_params_->waiting_period().InSeconds() == 0)
- << "Waiting Period should NOT be zero at this point!!!";
- // Since scattering is enabled, wall clock based wait will always be
- // enabled.
- omaha_request_params_->set_wall_clock_based_wait_enabled(true);
- // If we don't have any issues in accessing the file system to update
- // the update check count value, we'll turn that on as well.
- bool decrement_succeeded = DecrementUpdateCheckCount();
- omaha_request_params_->set_update_check_count_wait_enabled(
- decrement_succeeded);
- } else {
- // This means the scattering feature is turned off or disabled for
- // this particular update check. Make sure to disable
- // all the knobs and artifacts so that we don't invoke any scattering
- // related code.
- omaha_request_params_->set_wall_clock_based_wait_enabled(false);
- omaha_request_params_->set_update_check_count_wait_enabled(false);
- omaha_request_params_->set_waiting_period(TimeDelta::FromSeconds(0));
- prefs_->Delete(kPrefsWallClockScatteringWaitPeriod);
- prefs_->Delete(kPrefsUpdateCheckCount);
- // Don't delete the UpdateFirstSeenAt file as we don't want manual checks
- // that result in no-updates (e.g. due to server side throttling) to
- // cause update starvation by having the client generate a new
- // UpdateFirstSeenAt for each scheduled check that follows a manual check.
- }
- }
- void UpdateAttempter::GenerateNewWaitingPeriod() {
- omaha_request_params_->set_waiting_period(
- TimeDelta::FromSeconds(base::RandInt(1, scatter_factor_.InSeconds())));
- LOG(INFO) << "Generated new wall-clock waiting period: "
- << utils::FormatSecs(
- omaha_request_params_->waiting_period().InSeconds());
- // Do a best-effort to persist this in all cases. Even if the persistence
- // fails, we'll still be able to scatter based on our in-memory value.
- // The persistence only helps in ensuring a good overall distribution
- // across multiple devices if they tend to reboot too often.
- system_state_->payload_state()->SetScatteringWaitPeriod(
- omaha_request_params_->waiting_period());
- }
- void UpdateAttempter::CalculateStagingParams(bool interactive) {
- bool oobe_complete = system_state_->hardware()->IsOOBEEnabled() &&
- system_state_->hardware()->IsOOBEComplete(nullptr);
- auto device_policy = system_state_->device_policy();
- StagingCase staging_case = StagingCase::kOff;
- if (device_policy && !interactive && oobe_complete) {
- staging_wait_time_ = omaha_request_params_->waiting_period();
- staging_case = CalculateStagingCase(
- device_policy, prefs_, &staging_wait_time_, &staging_schedule_);
- }
- switch (staging_case) {
- case StagingCase::kOff:
- // Staging is off, get rid of persisted value.
- prefs_->Delete(kPrefsWallClockStagingWaitPeriod);
- // Set |staging_wait_time_| to its default value so scattering can still
- // be turned on
- staging_wait_time_ = TimeDelta();
- break;
- // Let the cases fall through since they just add, and never remove, steps
- // to turning staging on.
- case StagingCase::kNoSavedValue:
- prefs_->SetInt64(kPrefsWallClockStagingWaitPeriod,
- staging_wait_time_.InDays());
- case StagingCase::kSetStagingFromPref:
- omaha_request_params_->set_waiting_period(staging_wait_time_);
- case StagingCase::kNoAction:
- // Staging is on, enable wallclock based wait so that its values get used.
- omaha_request_params_->set_wall_clock_based_wait_enabled(true);
- // Use UpdateCheckCount if possible to prevent devices updating all at
- // once.
- omaha_request_params_->set_update_check_count_wait_enabled(
- DecrementUpdateCheckCount());
- // Scattering should not be turned on if staging is on, delete the
- // existing scattering configuration.
- prefs_->Delete(kPrefsWallClockScatteringWaitPeriod);
- scatter_factor_ = TimeDelta();
- }
- }
- void UpdateAttempter::BuildUpdateActions(bool interactive) {
- CHECK(!processor_->IsRunning());
- processor_->set_delegate(this);
- // Actions:
- auto update_check_fetcher = std::make_unique<LibcurlHttpFetcher>(
- GetProxyResolver(), system_state_->hardware());
- update_check_fetcher->set_server_to_check(ServerToCheck::kUpdate);
- // Try harder to connect to the network, esp when not interactive.
- // See comment in libcurl_http_fetcher.cc.
- update_check_fetcher->set_no_network_max_retries(interactive ? 1 : 3);
- auto update_check_action = std::make_unique<OmahaRequestAction>(
- system_state_, nullptr, std::move(update_check_fetcher), false);
- auto response_handler_action =
- std::make_unique<OmahaResponseHandlerAction>(system_state_);
- auto update_boot_flags_action =
- std::make_unique<UpdateBootFlagsAction>(system_state_->boot_control());
- auto download_started_action = std::make_unique<OmahaRequestAction>(
- system_state_,
- new OmahaEvent(OmahaEvent::kTypeUpdateDownloadStarted),
- std::make_unique<LibcurlHttpFetcher>(GetProxyResolver(),
- system_state_->hardware()),
- false);
- LibcurlHttpFetcher* download_fetcher =
- new LibcurlHttpFetcher(GetProxyResolver(), system_state_->hardware());
- download_fetcher->set_server_to_check(ServerToCheck::kDownload);
- if (interactive)
- download_fetcher->set_max_retry_count(kDownloadMaxRetryCountInteractive);
- auto download_action =
- std::make_unique<DownloadAction>(prefs_,
- system_state_->boot_control(),
- system_state_->hardware(),
- system_state_,
- download_fetcher, // passes ownership
- interactive);
- download_action->set_delegate(this);
- auto download_finished_action = std::make_unique<OmahaRequestAction>(
- system_state_,
- new OmahaEvent(OmahaEvent::kTypeUpdateDownloadFinished),
- std::make_unique<LibcurlHttpFetcher>(GetProxyResolver(),
- system_state_->hardware()),
- false);
- auto filesystem_verifier_action =
- std::make_unique<FilesystemVerifierAction>();
- auto update_complete_action = std::make_unique<OmahaRequestAction>(
- system_state_,
- new OmahaEvent(OmahaEvent::kTypeUpdateComplete),
- std::make_unique<LibcurlHttpFetcher>(GetProxyResolver(),
- system_state_->hardware()),
- false);
- auto postinstall_runner_action = std::make_unique<PostinstallRunnerAction>(
- system_state_->boot_control(), system_state_->hardware());
- postinstall_runner_action->set_delegate(this);
- // Bond them together. We have to use the leaf-types when calling
- // BondActions().
- BondActions(update_check_action.get(), response_handler_action.get());
- BondActions(response_handler_action.get(), download_action.get());
- BondActions(download_action.get(), filesystem_verifier_action.get());
- BondActions(filesystem_verifier_action.get(),
- postinstall_runner_action.get());
- processor_->EnqueueAction(std::move(update_check_action));
- processor_->EnqueueAction(std::move(response_handler_action));
- processor_->EnqueueAction(std::move(update_boot_flags_action));
- processor_->EnqueueAction(std::move(download_started_action));
- processor_->EnqueueAction(std::move(download_action));
- processor_->EnqueueAction(std::move(download_finished_action));
- processor_->EnqueueAction(std::move(filesystem_verifier_action));
- processor_->EnqueueAction(std::move(postinstall_runner_action));
- processor_->EnqueueAction(std::move(update_complete_action));
- }
- bool UpdateAttempter::Rollback(bool powerwash) {
- is_install_ = false;
- if (!CanRollback()) {
- return false;
- }
- // Extra check for enterprise-enrolled devices since they don't support
- // powerwash.
- if (powerwash) {
- // Enterprise-enrolled devices have an empty owner in their device policy.
- string owner;
- RefreshDevicePolicy();
- const policy::DevicePolicy* device_policy = system_state_->device_policy();
- if (device_policy && (!device_policy->GetOwner(&owner) || owner.empty())) {
- LOG(ERROR) << "Enterprise device detected. "
- << "Cannot perform a powerwash for enterprise devices.";
- return false;
- }
- }
- processor_->set_delegate(this);
- // Initialize the default request params.
- if (!omaha_request_params_->Init("", "", true)) {
- LOG(ERROR) << "Unable to initialize Omaha request params.";
- return false;
- }
- LOG(INFO) << "Setting rollback options.";
- install_plan_.reset(new InstallPlan());
- install_plan_->target_slot = GetRollbackSlot();
- install_plan_->source_slot = system_state_->boot_control()->GetCurrentSlot();
- TEST_AND_RETURN_FALSE(
- install_plan_->LoadPartitionsFromSlots(system_state_->boot_control()));
- install_plan_->powerwash_required = powerwash;
- LOG(INFO) << "Using this install plan:";
- install_plan_->Dump();
- auto install_plan_action =
- std::make_unique<InstallPlanAction>(*install_plan_);
- auto postinstall_runner_action = std::make_unique<PostinstallRunnerAction>(
- system_state_->boot_control(), system_state_->hardware());
- postinstall_runner_action->set_delegate(this);
- BondActions(install_plan_action.get(), postinstall_runner_action.get());
- processor_->EnqueueAction(std::move(install_plan_action));
- processor_->EnqueueAction(std::move(postinstall_runner_action));
- // Update the payload state for Rollback.
- system_state_->payload_state()->Rollback();
- SetStatusAndNotify(UpdateStatus::ATTEMPTING_ROLLBACK);
- ScheduleProcessingStart();
- return true;
- }
- bool UpdateAttempter::CanRollback() const {
- // We can only rollback if the update_engine isn't busy and we have a valid
- // rollback partition.
- return (status_ == UpdateStatus::IDLE &&
- GetRollbackSlot() != BootControlInterface::kInvalidSlot);
- }
- BootControlInterface::Slot UpdateAttempter::GetRollbackSlot() const {
- LOG(INFO) << "UpdateAttempter::GetRollbackSlot";
- const unsigned int num_slots = system_state_->boot_control()->GetNumSlots();
- const BootControlInterface::Slot current_slot =
- system_state_->boot_control()->GetCurrentSlot();
- LOG(INFO) << " Installed slots: " << num_slots;
- LOG(INFO) << " Booted from slot: "
- << BootControlInterface::SlotName(current_slot);
- if (current_slot == BootControlInterface::kInvalidSlot || num_slots < 2) {
- LOG(INFO) << "Device is not updateable.";
- return BootControlInterface::kInvalidSlot;
- }
- vector<BootControlInterface::Slot> bootable_slots;
- for (BootControlInterface::Slot slot = 0; slot < num_slots; slot++) {
- if (slot != current_slot &&
- system_state_->boot_control()->IsSlotBootable(slot)) {
- LOG(INFO) << "Found bootable slot "
- << BootControlInterface::SlotName(slot);
- return slot;
- }
- }
- LOG(INFO) << "No other bootable slot found.";
- return BootControlInterface::kInvalidSlot;
- }
- bool UpdateAttempter::CheckForUpdate(const string& app_version,
- const string& omaha_url,
- UpdateAttemptFlags flags) {
- dlc_module_ids_.clear();
- is_install_ = false;
- bool interactive = !(flags & UpdateAttemptFlags::kFlagNonInteractive);
- if (interactive && status_ != UpdateStatus::IDLE) {
- // An update check is either in-progress, or an update has completed and the
- // system is in UPDATED_NEED_REBOOT. Either way, don't do an interactive
- // update at this time
- LOG(INFO) << "Refusing to do an interactive update with an update already "
- "in progress";
- return false;
- }
- LOG(INFO) << "Forced update check requested.";
- forced_app_version_.clear();
- forced_omaha_url_.clear();
- // Certain conditions must be met to allow setting custom version and update
- // server URLs. However, kScheduledAUTestURLRequest and kAUTestURLRequest are
- // always allowed regardless of device state.
- if (IsAnyUpdateSourceAllowed()) {
- forced_app_version_ = app_version;
- forced_omaha_url_ = omaha_url;
- }
- if (omaha_url == kScheduledAUTestURLRequest) {
- forced_omaha_url_ = constants::kOmahaDefaultAUTestURL;
- // Pretend that it's not user-initiated even though it is,
- // so as to test scattering logic, etc. which get kicked off
- // only in scheduled update checks.
- interactive = false;
- } else if (omaha_url == kAUTestURLRequest) {
- forced_omaha_url_ = constants::kOmahaDefaultAUTestURL;
- }
- if (interactive) {
- // Use the passed-in update attempt flags for this update attempt instead
- // of the previously set ones.
- current_update_attempt_flags_ = flags;
- // Note: The caching for non-interactive update checks happens in
- // OnUpdateScheduled().
- }
- if (forced_update_pending_callback_.get()) {
- if (!system_state_->dlcservice()->GetInstalled(&dlc_module_ids_)) {
- dlc_module_ids_.clear();
- }
- // Make sure that a scheduling request is made prior to calling the forced
- // update pending callback.
- ScheduleUpdates();
- forced_update_pending_callback_->Run(true, interactive);
- }
- return true;
- }
- bool UpdateAttempter::CheckForInstall(const vector<string>& dlc_module_ids,
- const string& omaha_url) {
- dlc_module_ids_ = dlc_module_ids;
- is_install_ = true;
- forced_omaha_url_.clear();
- // Certain conditions must be met to allow setting custom version and update
- // server URLs. However, kScheduledAUTestURLRequest and kAUTestURLRequest are
- // always allowed regardless of device state.
- if (IsAnyUpdateSourceAllowed()) {
- forced_omaha_url_ = omaha_url;
- }
- if (omaha_url == kScheduledAUTestURLRequest) {
- forced_omaha_url_ = constants::kOmahaDefaultAUTestURL;
- } else if (omaha_url == kAUTestURLRequest) {
- forced_omaha_url_ = constants::kOmahaDefaultAUTestURL;
- }
- if (!ScheduleUpdates()) {
- if (forced_update_pending_callback_.get()) {
- // Make sure that a scheduling request is made prior to calling the forced
- // update pending callback.
- ScheduleUpdates();
- forced_update_pending_callback_->Run(true, true);
- return true;
- }
- return false;
- }
- return true;
- }
- bool UpdateAttempter::RebootIfNeeded() {
- #ifdef __ANDROID__
- if (status_ != UpdateStatus::UPDATED_NEED_REBOOT) {
- LOG(INFO) << "Reboot requested, but status is "
- << UpdateStatusToString(status_) << ", so not rebooting.";
- return false;
- }
- #endif // __ANDROID__
- if (system_state_->power_manager()->RequestReboot())
- return true;
- return RebootDirectly();
- }
- void UpdateAttempter::WriteUpdateCompletedMarker() {
- string boot_id;
- if (!utils::GetBootId(&boot_id))
- return;
- prefs_->SetString(kPrefsUpdateCompletedOnBootId, boot_id);
- int64_t value = system_state_->clock()->GetBootTime().ToInternalValue();
- prefs_->SetInt64(kPrefsUpdateCompletedBootTime, value);
- }
- bool UpdateAttempter::RebootDirectly() {
- vector<string> command;
- command.push_back("/sbin/shutdown");
- command.push_back("-r");
- command.push_back("now");
- LOG(INFO) << "Running \"" << base::JoinString(command, " ") << "\"";
- int rc = 0;
- Subprocess::SynchronousExec(command, &rc, nullptr);
- return rc == 0;
- }
- void UpdateAttempter::OnUpdateScheduled(EvalStatus status,
- const UpdateCheckParams& params) {
- waiting_for_scheduled_check_ = false;
- if (status == EvalStatus::kSucceeded) {
- if (!params.updates_enabled) {
- LOG(WARNING) << "Updates permanently disabled.";
- // Signal disabled status, then switch right back to idle. This is
- // necessary for ensuring that observers waiting for a signal change will
- // actually notice one on subsequent calls. Note that we don't need to
- // re-schedule a check in this case as updates are permanently disabled;
- // further (forced) checks may still initiate a scheduling call.
- SetStatusAndNotify(UpdateStatus::DISABLED);
- SetStatusAndNotify(UpdateStatus::IDLE);
- return;
- }
- LOG(INFO) << "Running " << (params.interactive ? "interactive" : "periodic")
- << " update.";
- if (!params.interactive) {
- // Cache the update attempt flags that will be used by this update attempt
- // so that they can't be changed mid-way through.
- current_update_attempt_flags_ = update_attempt_flags_;
- }
- LOG(INFO) << "Update attempt flags in use = 0x" << std::hex
- << current_update_attempt_flags_;
- Update(forced_app_version_,
- forced_omaha_url_,
- params.target_channel,
- params.target_version_prefix,
- params.rollback_allowed,
- /*obey_proxies=*/false,
- params.interactive);
- // Always clear the forced app_version and omaha_url after an update attempt
- // so the next update uses the defaults.
- forced_app_version_.clear();
- forced_omaha_url_.clear();
- } else {
- LOG(WARNING)
- << "Update check scheduling failed (possibly timed out); retrying.";
- ScheduleUpdates();
- }
- // This check ensures that future update checks will be or are already
- // scheduled. The check should never fail. A check failure means that there's
- // a bug that will most likely prevent further automatic update checks. It
- // seems better to crash in such cases and restart the update_engine daemon
- // into, hopefully, a known good state.
- CHECK(IsUpdateRunningOrScheduled());
- }
- void UpdateAttempter::UpdateLastCheckedTime() {
- last_checked_time_ = system_state_->clock()->GetWallclockTime().ToTimeT();
- }
- void UpdateAttempter::UpdateRollbackHappened() {
- DCHECK(system_state_);
- DCHECK(system_state_->payload_state());
- DCHECK(policy_provider_);
- if (system_state_->payload_state()->GetRollbackHappened() &&
- (policy_provider_->device_policy_is_loaded() ||
- policy_provider_->IsConsumerDevice())) {
- // Rollback happened, but we already went through OOBE and policy is
- // present or it's a consumer device.
- system_state_->payload_state()->SetRollbackHappened(false);
- }
- }
- // Delegate methods:
- void UpdateAttempter::ProcessingDone(const ActionProcessor* processor,
- ErrorCode code) {
- LOG(INFO) << "Processing Done.";
- // Reset cpu shares back to normal.
- cpu_limiter_.StopLimiter();
- // reset the state that's only valid for a single update pass
- current_update_attempt_flags_ = UpdateAttemptFlags::kNone;
- if (forced_update_pending_callback_.get())
- // Clear prior interactive requests once the processor is done.
- forced_update_pending_callback_->Run(false, false);
- if (status_ == UpdateStatus::REPORTING_ERROR_EVENT) {
- LOG(INFO) << "Error event sent.";
- // Inform scheduler of new status;
- SetStatusAndNotify(UpdateStatus::IDLE);
- ScheduleUpdates();
- if (!fake_update_success_) {
- return;
- }
- LOG(INFO) << "Booted from FW B and tried to install new firmware, "
- "so requesting reboot from user.";
- }
- attempt_error_code_ = utils::GetBaseErrorCode(code);
- if (code == ErrorCode::kSuccess) {
- // For install operation, we do not mark update complete since we do not
- // need reboot.
- if (!is_install_)
- WriteUpdateCompletedMarker();
- ReportTimeToUpdateAppliedMetric();
- prefs_->SetInt64(kPrefsDeltaUpdateFailures, 0);
- prefs_->SetString(kPrefsPreviousVersion,
- omaha_request_params_->app_version());
- DeltaPerformer::ResetUpdateProgress(prefs_, false);
- system_state_->payload_state()->UpdateSucceeded();
- // Since we're done with scattering fully at this point, this is the
- // safest point delete the state files, as we're sure that the status is
- // set to reboot (which means no more updates will be applied until reboot)
- // This deletion is required for correctness as we want the next update
- // check to re-create a new random number for the update check count.
- // Similarly, we also delete the wall-clock-wait period that was persisted
- // so that we start with a new random value for the next update check
- // after reboot so that the same device is not favored or punished in any
- // way.
- prefs_->Delete(kPrefsUpdateCheckCount);
- system_state_->payload_state()->SetScatteringWaitPeriod(TimeDelta());
- system_state_->payload_state()->SetStagingWaitPeriod(TimeDelta());
- prefs_->Delete(kPrefsUpdateFirstSeenAt);
- if (is_install_) {
- LOG(INFO) << "DLC successfully installed, no reboot needed.";
- SetStatusAndNotify(UpdateStatus::IDLE);
- ScheduleUpdates();
- return;
- }
- SetStatusAndNotify(UpdateStatus::UPDATED_NEED_REBOOT);
- ScheduleUpdates();
- LOG(INFO) << "Update successfully applied, waiting to reboot.";
- // |install_plan_| is null during rollback operations, and the stats don't
- // make much sense then anyway.
- if (install_plan_) {
- // Generate an unique payload identifier.
- string target_version_uid;
- for (const auto& payload : install_plan_->payloads) {
- target_version_uid +=
- brillo::data_encoding::Base64Encode(payload.hash) + ":" +
- payload.metadata_signature + ":";
- }
- // If we just downloaded a rollback image, we should preserve this fact
- // over the following powerwash.
- if (install_plan_->is_rollback) {
- system_state_->payload_state()->SetRollbackHappened(true);
- system_state_->metrics_reporter()->ReportEnterpriseRollbackMetrics(
- /*success=*/true, install_plan_->version);
- }
- // Expect to reboot into the new version to send the proper metric during
- // next boot.
- system_state_->payload_state()->ExpectRebootInNewVersion(
- target_version_uid);
- } else {
- // If we just finished a rollback, then we expect to have no Omaha
- // response. Otherwise, it's an error.
- if (system_state_->payload_state()->GetRollbackVersion().empty()) {
- LOG(ERROR) << "Can't send metrics because there was no Omaha response";
- }
- }
- return;
- }
- if (ScheduleErrorEventAction()) {
- return;
- }
- LOG(INFO) << "No update.";
- SetStatusAndNotify(UpdateStatus::IDLE);
- ScheduleUpdates();
- }
- void UpdateAttempter::ProcessingStopped(const ActionProcessor* processor) {
- // Reset cpu shares back to normal.
- cpu_limiter_.StopLimiter();
- download_progress_ = 0.0;
- if (forced_update_pending_callback_.get())
- // Clear prior interactive requests once the processor is done.
- forced_update_pending_callback_->Run(false, false);
- SetStatusAndNotify(UpdateStatus::IDLE);
- ScheduleUpdates();
- error_event_.reset(nullptr);
- }
- // Called whenever an action has finished processing, either successfully
- // or otherwise.
- void UpdateAttempter::ActionCompleted(ActionProcessor* processor,
- AbstractAction* action,
- ErrorCode code) {
- // Reset download progress regardless of whether or not the download
- // action succeeded. Also, get the response code from HTTP request
- // actions (update download as well as the initial update check
- // actions).
- const string type = action->Type();
- if (type == DownloadAction::StaticType()) {
- download_progress_ = 0.0;
- DownloadAction* download_action = static_cast<DownloadAction*>(action);
- http_response_code_ = download_action->GetHTTPResponseCode();
- } else if (type == OmahaRequestAction::StaticType()) {
- OmahaRequestAction* omaha_request_action =
- static_cast<OmahaRequestAction*>(action);
- // If the request is not an event, then it's the update-check.
- if (!omaha_request_action->IsEvent()) {
- http_response_code_ = omaha_request_action->GetHTTPResponseCode();
- // Record the number of consecutive failed update checks.
- if (http_response_code_ == kHttpResponseInternalServerError ||
- http_response_code_ == kHttpResponseServiceUnavailable) {
- consecutive_failed_update_checks_++;
- } else {
- consecutive_failed_update_checks_ = 0;
- }
- const OmahaResponse& omaha_response =
- omaha_request_action->GetOutputObject();
- // Store the server-dictated poll interval, if any.
- server_dictated_poll_interval_ =
- std::max(0, omaha_response.poll_interval);
- // This update is ignored by omaha request action because update over
- // cellular connection is not allowed. Needs to ask for user's permissions
- // to update.
- if (code == ErrorCode::kOmahaUpdateIgnoredOverCellular) {
- new_version_ = omaha_response.version;
- new_payload_size_ = 0;
- for (const auto& package : omaha_response.packages) {
- new_payload_size_ += package.size;
- }
- SetStatusAndNotify(UpdateStatus::NEED_PERMISSION_TO_UPDATE);
- }
- }
- } else if (type == OmahaResponseHandlerAction::StaticType()) {
- // Depending on the returned error code, note that an update is available.
- if (code == ErrorCode::kOmahaUpdateDeferredPerPolicy ||
- code == ErrorCode::kSuccess) {
- // Note that the status will be updated to DOWNLOADING when some bytes
- // get actually downloaded from the server and the BytesReceived
- // callback is invoked. This avoids notifying the user that a download
- // has started in cases when the server and the client are unable to
- // initiate the download.
- auto omaha_response_handler_action =
- static_cast<OmahaResponseHandlerAction*>(action);
- install_plan_.reset(
- new InstallPlan(omaha_response_handler_action->install_plan()));
- UpdateLastCheckedTime();
- new_version_ = install_plan_->version;
- new_system_version_ = install_plan_->system_version;
- new_payload_size_ = 0;
- for (const auto& payload : install_plan_->payloads)
- new_payload_size_ += payload.size;
- cpu_limiter_.StartLimiter();
- SetStatusAndNotify(UpdateStatus::UPDATE_AVAILABLE);
- }
- }
- // General failure cases.
- if (code != ErrorCode::kSuccess) {
- // If the current state is at or past the download phase, count the failure
- // in case a switch to full update becomes necessary. Ignore network
- // transfer timeouts and failures.
- if (code != ErrorCode::kDownloadTransferError) {
- switch (status_) {
- case UpdateStatus::IDLE:
- case UpdateStatus::CHECKING_FOR_UPDATE:
- case UpdateStatus::UPDATE_AVAILABLE:
- case UpdateStatus::NEED_PERMISSION_TO_UPDATE:
- break;
- case UpdateStatus::DOWNLOADING:
- case UpdateStatus::VERIFYING:
- case UpdateStatus::FINALIZING:
- case UpdateStatus::UPDATED_NEED_REBOOT:
- case UpdateStatus::REPORTING_ERROR_EVENT:
- case UpdateStatus::ATTEMPTING_ROLLBACK:
- case UpdateStatus::DISABLED:
- MarkDeltaUpdateFailure();
- break;
- }
- }
- if (code != ErrorCode::kNoUpdate) {
- // On failure, schedule an error event to be sent to Omaha.
- CreatePendingErrorEvent(action, code);
- }
- return;
- }
- // Find out which action completed (successfully).
- if (type == DownloadAction::StaticType()) {
- SetStatusAndNotify(UpdateStatus::FINALIZING);
- } else if (type == FilesystemVerifierAction::StaticType()) {
- // Log the system properties before the postinst and after the file system
- // is verified. It used to be done in the postinst itself. But postinst
- // cannot do this anymore. On the other hand, these logs are frequently
- // looked at and it is preferable not to scatter them in random location in
- // the log and rather log it right before the postinst. The reason not do
- // this in the |PostinstallRunnerAction| is to prevent dependency from
- // libpayload_consumer to libupdate_engine.
- LogImageProperties();
- }
- }
- void UpdateAttempter::BytesReceived(uint64_t bytes_progressed,
- uint64_t bytes_received,
- uint64_t total) {
- // The PayloadState keeps track of how many bytes were actually downloaded
- // from a given URL for the URL skipping logic.
- system_state_->payload_state()->DownloadProgress(bytes_progressed);
- double progress = 0;
- if (total)
- progress = static_cast<double>(bytes_received) / static_cast<double>(total);
- if (status_ != UpdateStatus::DOWNLOADING || bytes_received == total) {
- download_progress_ = progress;
- SetStatusAndNotify(UpdateStatus::DOWNLOADING);
- } else {
- ProgressUpdate(progress);
- }
- }
- void UpdateAttempter::DownloadComplete() {
- system_state_->payload_state()->DownloadComplete();
- }
- void UpdateAttempter::ProgressUpdate(double progress) {
- // Self throttle based on progress. Also send notifications if progress is
- // too slow.
- if (progress == 1.0 ||
- progress - download_progress_ >= kBroadcastThresholdProgress ||
- TimeTicks::Now() - last_notify_time_ >=
- TimeDelta::FromSeconds(kBroadcastThresholdSeconds)) {
- download_progress_ = progress;
- BroadcastStatus();
- }
- }
- bool UpdateAttempter::ResetStatus() {
- LOG(INFO) << "Attempting to reset state from "
- << UpdateStatusToString(status_) << " to UpdateStatus::IDLE";
- switch (status_) {
- case UpdateStatus::IDLE:
- // no-op.
- return true;
- case UpdateStatus::UPDATED_NEED_REBOOT: {
- bool ret_value = true;
- status_ = UpdateStatus::IDLE;
- // Remove the reboot marker so that if the machine is rebooted
- // after resetting to idle state, it doesn't go back to
- // UpdateStatus::UPDATED_NEED_REBOOT state.
- ret_value = prefs_->Delete(kPrefsUpdateCompletedOnBootId) && ret_value;
- ret_value = prefs_->Delete(kPrefsUpdateCompletedBootTime) && ret_value;
- // Update the boot flags so the current slot has higher priority.
- BootControlInterface* boot_control = system_state_->boot_control();
- if (!boot_control->SetActiveBootSlot(boot_control->GetCurrentSlot()))
- ret_value = false;
- // Mark the current slot as successful again, since marking it as active
- // may reset the successful bit. We ignore the result of whether marking
- // the current slot as successful worked.
- if (!boot_control->MarkBootSuccessfulAsync(Bind([](bool successful) {})))
- ret_value = false;
- // Notify the PayloadState that the successful payload was canceled.
- system_state_->payload_state()->ResetUpdateStatus();
- // The previous version is used to report back to omaha after reboot that
- // we actually rebooted into the new version from this "prev-version". We
- // need to clear out this value now to prevent it being sent on the next
- // updatecheck request.
- ret_value = prefs_->SetString(kPrefsPreviousVersion, "") && ret_value;
- LOG(INFO) << "Reset status " << (ret_value ? "successful" : "failed");
- return ret_value;
- }
- default:
- LOG(ERROR) << "Reset not allowed in this state.";
- return false;
- }
- }
- bool UpdateAttempter::GetStatus(UpdateEngineStatus* out_status) {
- out_status->last_checked_time = last_checked_time_;
- out_status->status = status_;
- out_status->current_version = omaha_request_params_->app_version();
- out_status->current_system_version = omaha_request_params_->system_version();
- out_status->progress = download_progress_;
- out_status->new_size_bytes = new_payload_size_;
- out_status->new_version = new_version_;
- out_status->new_system_version = new_system_version_;
- return true;
- }
- void UpdateAttempter::BroadcastStatus() {
- UpdateEngineStatus broadcast_status;
- // Use common method for generating the current status.
- GetStatus(&broadcast_status);
- for (const auto& observer : service_observers_) {
- observer->SendStatusUpdate(broadcast_status);
- }
- last_notify_time_ = TimeTicks::Now();
- }
- uint32_t UpdateAttempter::GetErrorCodeFlags() {
- uint32_t flags = 0;
- if (!system_state_->hardware()->IsNormalBootMode())
- flags |= static_cast<uint32_t>(ErrorCode::kDevModeFlag);
- if (install_plan_ && install_plan_->is_resume)
- flags |= static_cast<uint32_t>(ErrorCode::kResumedFlag);
- if (!system_state_->hardware()->IsOfficialBuild())
- flags |= static_cast<uint32_t>(ErrorCode::kTestImageFlag);
- if (!omaha_request_params_->IsUpdateUrlOfficial()) {
- flags |= static_cast<uint32_t>(ErrorCode::kTestOmahaUrlFlag);
- }
- return flags;
- }
- bool UpdateAttempter::ShouldCancel(ErrorCode* cancel_reason) {
- // Check if the channel we're attempting to update to is the same as the
- // target channel currently chosen by the user.
- OmahaRequestParams* params = system_state_->request_params();
- if (params->download_channel() != params->target_channel()) {
- LOG(ERROR) << "Aborting download as target channel: "
- << params->target_channel()
- << " is different from the download channel: "
- << params->download_channel();
- *cancel_reason = ErrorCode::kUpdateCanceledByChannelChange;
- return true;
- }
- return false;
- }
- void UpdateAttempter::SetStatusAndNotify(UpdateStatus status) {
- status_ = status;
- BroadcastStatus();
- }
- void UpdateAttempter::CreatePendingErrorEvent(AbstractAction* action,
- ErrorCode code) {
- if (error_event_.get() || status_ == UpdateStatus::REPORTING_ERROR_EVENT) {
- // This shouldn't really happen.
- LOG(WARNING) << "There's already an existing pending error event.";
- return;
- }
- // Classify the code to generate the appropriate result so that
- // the Borgmon charts show up the results correctly.
- // Do this before calling GetErrorCodeForAction which could potentially
- // augment the bit representation of code and thus cause no matches for
- // the switch cases below.
- OmahaEvent::Result event_result;
- switch (code) {
- case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
- case ErrorCode::kOmahaUpdateDeferredPerPolicy:
- case ErrorCode::kOmahaUpdateDeferredForBackoff:
- event_result = OmahaEvent::kResultUpdateDeferred;
- break;
- default:
- event_result = OmahaEvent::kResultError;
- break;
- }
- code = GetErrorCodeForAction(action, code);
- fake_update_success_ = code == ErrorCode::kPostinstallBootedFromFirmwareB;
- // Compute the final error code with all the bit flags to be sent to Omaha.
- code =
- static_cast<ErrorCode>(static_cast<uint32_t>(code) | GetErrorCodeFlags());
- error_event_.reset(
- new OmahaEvent(OmahaEvent::kTypeUpdateComplete, event_result, code));
- }
- bool UpdateAttempter::ScheduleErrorEventAction() {
- if (error_event_.get() == nullptr)
- return false;
- LOG(ERROR) << "Update failed.";
- system_state_->payload_state()->UpdateFailed(error_event_->error_code);
- // Send metrics if it was a rollback.
- if (install_plan_ && install_plan_->is_rollback) {
- system_state_->metrics_reporter()->ReportEnterpriseRollbackMetrics(
- /*success=*/false, install_plan_->version);
- }
- // Send it to Omaha.
- LOG(INFO) << "Reporting the error event";
- auto error_event_action = std::make_unique<OmahaRequestAction>(
- system_state_,
- error_event_.release(), // Pass ownership.
- std::make_unique<LibcurlHttpFetcher>(GetProxyResolver(),
- system_state_->hardware()),
- false);
- processor_->EnqueueAction(std::move(error_event_action));
- SetStatusAndNotify(UpdateStatus::REPORTING_ERROR_EVENT);
- processor_->StartProcessing();
- return true;
- }
- void UpdateAttempter::ScheduleProcessingStart() {
- LOG(INFO) << "Scheduling an action processor start.";
- MessageLoop::current()->PostTask(
- FROM_HERE,
- Bind([](ActionProcessor* processor) { processor->StartProcessing(); },
- base::Unretained(processor_.get())));
- }
- void UpdateAttempter::DisableDeltaUpdateIfNeeded() {
- int64_t delta_failures;
- if (omaha_request_params_->delta_okay() &&
- prefs_->GetInt64(kPrefsDeltaUpdateFailures, &delta_failures) &&
- delta_failures >= kMaxDeltaUpdateFailures) {
- LOG(WARNING) << "Too many delta update failures, forcing full update.";
- omaha_request_params_->set_delta_okay(false);
- }
- }
- void UpdateAttempter::MarkDeltaUpdateFailure() {
- // Don't try to resume a failed delta update.
- DeltaPerformer::ResetUpdateProgress(prefs_, false);
- int64_t delta_failures;
- if (!prefs_->GetInt64(kPrefsDeltaUpdateFailures, &delta_failures) ||
- delta_failures < 0) {
- delta_failures = 0;
- }
- prefs_->SetInt64(kPrefsDeltaUpdateFailures, ++delta_failures);
- }
- void UpdateAttempter::PingOmaha() {
- if (!processor_->IsRunning()) {
- auto ping_action = std::make_unique<OmahaRequestAction>(
- system_state_,
- nullptr,
- std::make_unique<LibcurlHttpFetcher>(GetProxyResolver(),
- system_state_->hardware()),
- true);
- processor_->set_delegate(nullptr);
- processor_->EnqueueAction(std::move(ping_action));
- // Call StartProcessing() synchronously here to avoid any race conditions
- // caused by multiple outstanding ping Omaha requests. If we call
- // StartProcessing() asynchronously, the device can be suspended before we
- // get a chance to callback to StartProcessing(). When the device resumes
- // (assuming the device sleeps longer than the next update check period),
- // StartProcessing() is called back and at the same time, the next update
- // check is fired which eventually invokes StartProcessing(). A crash
- // can occur because StartProcessing() checks to make sure that the
- // processor is idle which it isn't due to the two concurrent ping Omaha
- // requests.
- processor_->StartProcessing();
- } else {
- LOG(WARNING) << "Action processor running, Omaha ping suppressed.";
- }
- // Update the last check time here; it may be re-updated when an Omaha
- // response is received, but this will prevent us from repeatedly scheduling
- // checks in the case where a response is not received.
- UpdateLastCheckedTime();
- // Update the status which will schedule the next update check
- SetStatusAndNotify(UpdateStatus::UPDATED_NEED_REBOOT);
- ScheduleUpdates();
- }
- bool UpdateAttempter::DecrementUpdateCheckCount() {
- int64_t update_check_count_value;
- if (!prefs_->Exists(kPrefsUpdateCheckCount)) {
- // This file does not exist. This means we haven't started our update
- // check count down yet, so nothing more to do. This file will be created
- // later when we first satisfy the wall-clock-based-wait period.
- LOG(INFO) << "No existing update check count. That's normal.";
- return true;
- }
- if (prefs_->GetInt64(kPrefsUpdateCheckCount, &update_check_count_value)) {
- // Only if we're able to read a proper integer value, then go ahead
- // and decrement and write back the result in the same file, if needed.
- LOG(INFO) << "Update check count = " << update_check_count_value;
- if (update_check_count_value == 0) {
- // It could be 0, if, for some reason, the file didn't get deleted
- // when we set our status to waiting for reboot. so we just leave it
- // as is so that we can prevent another update_check wait for this client.
- LOG(INFO) << "Not decrementing update check count as it's already 0.";
- return true;
- }
- if (update_check_count_value > 0)
- update_check_count_value--;
- else
- update_check_count_value = 0;
- // Write out the new value of update_check_count_value.
- if (prefs_->SetInt64(kPrefsUpdateCheckCount, update_check_count_value)) {
- // We successfully wrote out the new value, so enable the
- // update check based wait.
- LOG(INFO) << "New update check count = " << update_check_count_value;
- return true;
- }
- }
- LOG(INFO) << "Deleting update check count state due to read/write errors.";
- // We cannot read/write to the file, so disable the update check based wait
- // so that we don't get stuck in this OS version by any chance (which could
- // happen if there's some bug that causes to read/write incorrectly).
- // Also attempt to delete the file to do our best effort to cleanup.
- prefs_->Delete(kPrefsUpdateCheckCount);
- return false;
- }
- void UpdateAttempter::UpdateEngineStarted() {
- // If we just booted into a new update, keep the previous OS version
- // in case we rebooted because of a crash of the old version, so we
- // can do a proper crash report with correct information.
- // This must be done before calling
- // system_state_->payload_state()->UpdateEngineStarted() since it will
- // delete SystemUpdated marker file.
- if (system_state_->system_rebooted() &&
- prefs_->Exists(kPrefsSystemUpdatedMarker)) {
- if (!prefs_->GetString(kPrefsPreviousVersion, &prev_version_)) {
- // If we fail to get the version string, make sure it stays empty.
- prev_version_.clear();
- }
- }
- system_state_->payload_state()->UpdateEngineStarted();
- StartP2PAtStartup();
- }
- bool UpdateAttempter::StartP2PAtStartup() {
- if (system_state_ == nullptr ||
- !system_state_->p2p_manager()->IsP2PEnabled()) {
- LOG(INFO) << "Not starting p2p at startup since it's not enabled.";
- return false;
- }
- if (system_state_->p2p_manager()->CountSharedFiles() < 1) {
- LOG(INFO) << "Not starting p2p at startup since our application "
- << "is not sharing any files.";
- return false;
- }
- return StartP2PAndPerformHousekeeping();
- }
- bool UpdateAttempter::StartP2PAndPerformHousekeeping() {
- if (system_state_ == nullptr)
- return false;
- if (!system_state_->p2p_manager()->IsP2PEnabled()) {
- LOG(INFO) << "Not starting p2p since it's not enabled.";
- return false;
- }
- LOG(INFO) << "Ensuring that p2p is running.";
- if (!system_state_->p2p_manager()->EnsureP2PRunning()) {
- LOG(ERROR) << "Error starting p2p.";
- return false;
- }
- LOG(INFO) << "Performing p2p housekeeping.";
- if (!system_state_->p2p_manager()->PerformHousekeeping()) {
- LOG(ERROR) << "Error performing housekeeping for p2p.";
- return false;
- }
- LOG(INFO) << "Done performing p2p housekeeping.";
- return true;
- }
- bool UpdateAttempter::GetBootTimeAtUpdate(Time* out_boot_time) {
- // In case of an update_engine restart without a reboot, we stored the boot_id
- // when the update was completed by setting a pref, so we can check whether
- // the last update was on this boot or a previous one.
- string boot_id;
- TEST_AND_RETURN_FALSE(utils::GetBootId(&boot_id));
- string update_completed_on_boot_id;
- if (!prefs_->Exists(kPrefsUpdateCompletedOnBootId) ||
- !prefs_->GetString(kPrefsUpdateCompletedOnBootId,
- &update_completed_on_boot_id) ||
- update_completed_on_boot_id != boot_id)
- return false;
- // Short-circuit avoiding the read in case out_boot_time is nullptr.
- if (out_boot_time) {
- int64_t boot_time = 0;
- // Since the kPrefsUpdateCompletedOnBootId was correctly set, this pref
- // should not fail.
- TEST_AND_RETURN_FALSE(
- prefs_->GetInt64(kPrefsUpdateCompletedBootTime, &boot_time));
- *out_boot_time = Time::FromInternalValue(boot_time);
- }
- return true;
- }
- bool UpdateAttempter::IsUpdateRunningOrScheduled() {
- return ((status_ != UpdateStatus::IDLE &&
- status_ != UpdateStatus::UPDATED_NEED_REBOOT) ||
- waiting_for_scheduled_check_);
- }
- bool UpdateAttempter::IsAnyUpdateSourceAllowed() const {
- // We allow updates from any source if either of these are true:
- // * The device is running an unofficial (dev/test) image.
- // * The debugd dev features are accessible (i.e. in devmode with no owner).
- // This protects users running a base image, while still allowing a specific
- // window (gated by the debug dev features) where `cros flash` is usable.
- if (!system_state_->hardware()->IsOfficialBuild()) {
- LOG(INFO) << "Non-official build; allowing any update source.";
- return true;
- }
- if (system_state_->hardware()->AreDevFeaturesEnabled()) {
- LOG(INFO) << "Developer features enabled; allowing custom update sources.";
- return true;
- }
- LOG(INFO)
- << "Developer features disabled; disallowing custom update sources.";
- return false;
- }
- void UpdateAttempter::ReportTimeToUpdateAppliedMetric() {
- const policy::DevicePolicy* device_policy = system_state_->device_policy();
- if (device_policy && device_policy->IsEnterpriseEnrolled()) {
- vector<policy::DevicePolicy::WeeklyTimeInterval> parsed_intervals;
- bool has_time_restrictions =
- device_policy->GetDisallowedTimeIntervals(&parsed_intervals);
- int64_t update_first_seen_at_int;
- if (system_state_->prefs()->Exists(kPrefsUpdateFirstSeenAt)) {
- if (system_state_->prefs()->GetInt64(kPrefsUpdateFirstSeenAt,
- &update_first_seen_at_int)) {
- TimeDelta update_delay =
- system_state_->clock()->GetWallclockTime() -
- Time::FromInternalValue(update_first_seen_at_int);
- system_state_->metrics_reporter()
- ->ReportEnterpriseUpdateSeenToDownloadDays(has_time_restrictions,
- update_delay.InDays());
- }
- }
- }
- }
- } // namespace chromeos_update_engine
|