1cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood// 2cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood// Copyright (C) 2017 The Android Open Source Project 3cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood// 4cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood// Licensed under the Apache License, Version 2.0 (the "License"); 5cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood// you may not use this file except in compliance with the License. 6cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood// You may obtain a copy of the License at 7cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood// 8cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood// http://www.apache.org/licenses/LICENSE-2.0 9cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood// 10cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood// Unless required by applicable law or agreed to in writing, software 11cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood// distributed under the License is distributed on an "AS IS" BASIS, 12cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood// See the License for the specific language governing permissions and 14cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood// limitations under the License. 15cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood// 16cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 17cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood#include "update_engine/update_manager/next_update_check_policy_impl.h" 18cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 19cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood#include <algorithm> 20cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 21cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood#include "update_engine/common/utils.h" 22cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 23cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Woodusing base::Time; 24cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Woodusing base::TimeDelta; 25cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Woodusing std::max; 26cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Woodusing std::string; 27cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 28cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Woodnamespace chromeos_update_manager { 29cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 30cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron WoodNextUpdateCheckTimePolicyImpl::NextUpdateCheckTimePolicyImpl( 31cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood const NextUpdateCheckPolicyConstants& constants) 32cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood : policy_constants_(constants) {} 33cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 34cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron WoodEvalStatus NextUpdateCheckTimePolicyImpl::UpdateCheckAllowed( 35cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood EvaluationContext* ec, 36cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood State* state, 37cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood string* error, 38cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood UpdateCheckParams* result) const { 39cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // Ensure that periodic update checks are timed properly. 40cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood Time next_update_check; 41cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 42cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood if (NextUpdateCheckTime( 43cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood ec, state, error, &next_update_check, policy_constants_) != 44cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood EvalStatus::kSucceeded) { 45cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood return EvalStatus::kFailed; 46cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood } 47cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood if (!ec->IsWallclockTimeGreaterThan(next_update_check)) { 48cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood LOG(INFO) << "Periodic check interval not satisfied, blocking until " 49cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood << chromeos_update_engine::utils::ToString(next_update_check); 50cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood return EvalStatus::kAskMeAgainLater; 51cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood } 52cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 53cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood return EvalStatus::kContinue; 54cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood} 55cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 56cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron WoodEvalStatus NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime( 57cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood EvaluationContext* ec, 58cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood State* state, 59cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood string* error, 60cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood Time* next_update_check, 61cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood const NextUpdateCheckPolicyConstants& constants) { 62cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood UpdaterProvider* const updater_provider = state->updater_provider(); 63cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 64cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // Don't check for updates too often. We limit the update checks to once every 65cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // some interval. The interval is kTimeoutInitialInterval the first time and 66cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // kTimeoutPeriodicInterval for the subsequent update checks. If the update 67cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // check fails, we increase the interval between the update checks 68cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // exponentially until kTimeoutMaxBackoffInterval. Finally, to avoid having 69cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // many chromebooks running update checks at the exact same time, we add some 70cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // fuzz to the interval. 71cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood const Time* updater_started_time = 72cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood ec->GetValue(updater_provider->var_updater_started_time()); 73cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood POLICY_CHECK_VALUE_AND_FAIL(updater_started_time, error); 74cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 75cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood const Time* last_checked_time = 76cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood ec->GetValue(updater_provider->var_last_checked_time()); 77cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 78cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood const auto* seed = ec->GetValue(state->random_provider()->var_seed()); 79cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood POLICY_CHECK_VALUE_AND_FAIL(seed, error); 80cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 81cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood PRNG prng(*seed); 82cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 83cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // If this is the first attempt, compute and return an initial value. 84cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood if (last_checked_time == nullptr || 85cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood *last_checked_time < *updater_started_time) { 86cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood *next_update_check = *updater_started_time + 87cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood FuzzedInterval(&prng, 88cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood constants.timeout_initial_interval, 89cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood constants.timeout_regular_fuzz); 90cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood return EvalStatus::kSucceeded; 91cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood } 92cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 93cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // Check whether the server is enforcing a poll interval; if not, this value 94cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // will be zero. 95cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood const unsigned int* server_dictated_poll_interval = 96cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood ec->GetValue(updater_provider->var_server_dictated_poll_interval()); 97cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood POLICY_CHECK_VALUE_AND_FAIL(server_dictated_poll_interval, error); 98cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 99cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood int interval = *server_dictated_poll_interval; 100cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood int fuzz = 0; 101cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 102cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // If no poll interval was dictated by server compute a back-off period, 103cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // starting from a predetermined base periodic interval and increasing 104cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // exponentially by the number of consecutive failed attempts. 105cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood if (interval == 0) { 106cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood const unsigned int* consecutive_failed_update_checks = 107cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood ec->GetValue(updater_provider->var_consecutive_failed_update_checks()); 108cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood POLICY_CHECK_VALUE_AND_FAIL(consecutive_failed_update_checks, error); 109cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 110cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood interval = constants.timeout_periodic_interval; 111cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood unsigned int num_failures = *consecutive_failed_update_checks; 112cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood while (interval < constants.timeout_max_backoff_interval && num_failures) { 113cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood interval *= 2; 114cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood num_failures--; 115cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood } 116cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood } 117cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 118cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // We cannot back off longer than the predetermined maximum interval. 119cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood if (interval > constants.timeout_max_backoff_interval) 120cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood interval = constants.timeout_max_backoff_interval; 121cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 122cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // We cannot back off shorter than the predetermined periodic interval. Also, 123cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // in this case set the fuzz to a predetermined regular value. 124cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood if (interval <= constants.timeout_periodic_interval) { 125cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood interval = constants.timeout_periodic_interval; 126cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood fuzz = constants.timeout_regular_fuzz; 127cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood } 128cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 129cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // If not otherwise determined, defer to a fuzz of +/-(interval / 2). 130cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood if (fuzz == 0) 131cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood fuzz = interval; 132cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 133cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood *next_update_check = 134cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood *last_checked_time + FuzzedInterval(&prng, interval, fuzz); 135cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood return EvalStatus::kSucceeded; 136cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood} 137cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 138cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron WoodTimeDelta NextUpdateCheckTimePolicyImpl::FuzzedInterval(PRNG* prng, 139cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood int interval, 140cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood int fuzz) { 141cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood DCHECK_GE(interval, 0); 142cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood DCHECK_GE(fuzz, 0); 143cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood int half_fuzz = fuzz / 2; 144cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood // This guarantees the output interval is non negative. 145cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood int interval_min = max(interval - half_fuzz, 0); 146cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood int interval_max = interval + half_fuzz; 147cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood return TimeDelta::FromSeconds(prng->RandMinMax(interval_min, interval_max)); 148cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood} 149cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood 150cdd6bab2e1071f440db5d99eece02fe7ae8acf90Aaron Wood} // namespace chromeos_update_manager 151