blob: df6b92154fb597328ffbf2fb91e5146a2f78ec74 [file] [log] [blame]
Alex Deymoc705cc82014-02-19 11:15:00 -08001// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Alex Deymo0d11c602014-04-23 20:12:20 -07005#include "update_engine/policy_manager/chromeos_policy.h"
Alex Deymo0d11c602014-04-23 20:12:20 -07006
Gilad Arnolde1218812014-05-07 12:21:36 -07007#include <algorithm>
Alex Deymoc705cc82014-02-19 11:15:00 -08008#include <string>
9
Gilad Arnoldf62a4b82014-05-01 07:41:07 -070010#include <base/logging.h>
11#include <base/time/time.h>
12
13#include "update_engine/policy_manager/device_policy_provider.h"
14#include "update_engine/policy_manager/policy_utils.h"
15
Alex Deymo0d11c602014-04-23 20:12:20 -070016using base::Time;
17using base::TimeDelta;
Gilad Arnoldf62a4b82014-05-01 07:41:07 -070018using std::min;
Alex Deymoc705cc82014-02-19 11:15:00 -080019using std::string;
20
21namespace chromeos_policy_manager {
22
Alex Deymo0d11c602014-04-23 20:12:20 -070023EvalStatus ChromeOSPolicy::UpdateCheckAllowed(
24 EvaluationContext* ec, State* state, string* error,
25 UpdateCheckParams* result) const {
26 Time next_update_check;
27 if (NextUpdateCheckTime(ec, state, error, &next_update_check) !=
28 EvalStatus::kSucceeded) {
29 return EvalStatus::kFailed;
30 }
31
32 if (!ec->IsTimeGreaterThan(next_update_check))
33 return EvalStatus::kAskMeAgainLater;
34
35 // It is time to check for an update.
36 result->updates_enabled = true;
Alex Deymoe636c3c2014-03-11 19:02:08 -070037 return EvalStatus::kSucceeded;
Alex Deymoc705cc82014-02-19 11:15:00 -080038}
39
Gilad Arnoldf62a4b82014-05-01 07:41:07 -070040EvalStatus ChromeOSPolicy::UpdateCanStart(
41 EvaluationContext* ec,
42 State* state,
43 string* error,
44 UpdateCanStartResult* result,
45 const bool interactive,
46 const UpdateState& update_state) const {
47 // Set the default return values.
48 result->update_can_start = true;
49 result->http_allowed = true;
50 result->p2p_allowed = false;
51 result->target_channel.clear();
52 result->cannot_start_reason = UpdateCannotStartReason::kUndefined;
53 result->scatter_wait_period = kZeroInterval;
54 result->scatter_check_threshold = 0;
55
56 // Make sure that we're not due for an update check.
57 UpdateCheckParams check_result;
58 EvalStatus check_status = UpdateCheckAllowed(ec, state, error, &check_result);
59 if (check_status == EvalStatus::kFailed)
60 return EvalStatus::kFailed;
61 if (check_status == EvalStatus::kSucceeded &&
62 check_result.updates_enabled == true) {
63 result->update_can_start = false;
64 result->cannot_start_reason = UpdateCannotStartReason::kCheckDue;
65 return EvalStatus::kSucceeded;
66 }
67
68 DevicePolicyProvider* const dp_provider = state->device_policy_provider();
69
70 const bool* device_policy_is_loaded_p = ec->GetValue(
71 dp_provider->var_device_policy_is_loaded());
72 if (device_policy_is_loaded_p && *device_policy_is_loaded_p) {
73 // Ensure that update is enabled.
74 const bool* update_disabled_p = ec->GetValue(
75 dp_provider->var_update_disabled());
76 if (update_disabled_p && *update_disabled_p) {
77 result->update_can_start = false;
78 result->cannot_start_reason = UpdateCannotStartReason::kDisabledByPolicy;
79 return EvalStatus::kAskMeAgainLater;
80 }
81
82 // Check whether scattering applies to this update attempt.
83 // TODO(garnold) We should not be scattering during OOBE. We'll need to read
84 // the OOBE status (via SystemProvider) and only scatter if not enacted.
85 // TODO(garnold) Current code further suppresses scattering if a "deadline"
86 // attribute is found in the Omaha response. However, it appears that the
87 // presence of this attribute is merely indicative of an OOBE update, which
88 // we should support anyway (see above).
89 if (!interactive) {
90 UpdateScatteringResult scatter_result;
91 EvalStatus scattering_status = UpdateScattering(
92 ec, state, error, &scatter_result, update_state);
93 if (scattering_status != EvalStatus::kSucceeded ||
94 scatter_result.is_scattering) {
95 if (scattering_status != EvalStatus::kFailed) {
96 result->update_can_start = false;
97 result->cannot_start_reason = UpdateCannotStartReason::kScattering;
98 result->scatter_wait_period = scatter_result.wait_period;
99 result->scatter_check_threshold = scatter_result.check_threshold;
100 }
101 return scattering_status;
102 }
103 }
104
105 // Determine whether HTTP downloads are forbidden by policy. This only
106 // applies to official system builds; otherwise, HTTP is always enabled.
107 const bool* is_official_build_p = ec->GetValue(
108 state->system_provider()->var_is_official_build());
109 if (is_official_build_p && *is_official_build_p) {
110 const bool* policy_http_downloads_enabled_p = ec->GetValue(
111 dp_provider->var_http_downloads_enabled());
112 result->http_allowed =
113 !policy_http_downloads_enabled_p || *policy_http_downloads_enabled_p;
114 }
115
116 // Determine whether use of P2P is allowed by policy.
117 const bool* policy_au_p2p_enabled_p = ec->GetValue(
118 dp_provider->var_au_p2p_enabled());
119 result->p2p_allowed = policy_au_p2p_enabled_p && *policy_au_p2p_enabled_p;
120
121 // Determine whether a target channel is dictated by policy.
122 const bool* release_channel_delegated_p = ec->GetValue(
123 dp_provider->var_release_channel_delegated());
124 if (release_channel_delegated_p && !(*release_channel_delegated_p)) {
125 const string* release_channel_p = ec->GetValue(
126 dp_provider->var_release_channel());
127 if (release_channel_p)
128 result->target_channel = *release_channel_p;
129 }
130 }
131
132 // Enable P2P, if so mandated by the updater configuration.
133 if (!result->p2p_allowed) {
134 const bool* updater_p2p_enabled_p = ec->GetValue(
135 state->updater_provider()->var_p2p_enabled());
136 result->p2p_allowed = updater_p2p_enabled_p && *updater_p2p_enabled_p;
137 }
138
Gilad Arnoldaf2f6ae2014-04-28 14:14:52 -0700139 return EvalStatus::kSucceeded;
140}
141
Alex Deymo0d11c602014-04-23 20:12:20 -0700142EvalStatus ChromeOSPolicy::NextUpdateCheckTime(EvaluationContext* ec,
143 State* state, string* error,
144 Time* next_update_check) const {
145 // Don't check for updates too often. We limit the update checks to once every
146 // some interval. The interval is kTimeoutInitialInterval the first time and
147 // kTimeoutPeriodicInterval for the subsequent update checks. If the update
148 // check fails, we increase the interval between the update checks
149 // exponentially until kTimeoutMaxBackoffInterval. Finally, to avoid having
150 // many chromebooks running update checks at the exact same time, we add some
151 // fuzz to the interval.
152 const Time* updater_started_time =
153 ec->GetValue(state->updater_provider()->var_updater_started_time());
154 POLICY_CHECK_VALUE_AND_FAIL(updater_started_time, error);
155
156 const base::Time* last_checked_time =
157 ec->GetValue(state->updater_provider()->var_last_checked_time());
158
159 const uint64_t* seed = ec->GetValue(state->random_provider()->var_seed());
160 POLICY_CHECK_VALUE_AND_FAIL(seed, error);
161
162 PRNG prng(*seed);
163
164 if (!last_checked_time || *last_checked_time < *updater_started_time) {
165 // First attempt.
166 *next_update_check = *updater_started_time + FuzzedInterval(
167 &prng, kTimeoutInitialInterval, kTimeoutRegularFuzz);
168 return EvalStatus::kSucceeded;
169 }
170 // Check for previous failed attempts to implement the exponential backoff.
171 const unsigned int* consecutive_failed_update_checks = ec->GetValue(
172 state->updater_provider()->var_consecutive_failed_update_checks());
173 POLICY_CHECK_VALUE_AND_FAIL(consecutive_failed_update_checks, error);
174
175 int interval = kTimeoutInitialInterval;
176 for (unsigned int i = 0; i < *consecutive_failed_update_checks; ++i) {
177 interval *= 2;
178 if (interval > kTimeoutMaxBackoffInterval) {
179 interval = kTimeoutMaxBackoffInterval;
180 break;
181 }
182 }
183
184 *next_update_check = *last_checked_time + FuzzedInterval(
185 &prng, interval, kTimeoutRegularFuzz);
186 return EvalStatus::kSucceeded;
187}
188
189TimeDelta ChromeOSPolicy::FuzzedInterval(PRNG* prng, int interval, int fuzz) {
Gilad Arnolde1218812014-05-07 12:21:36 -0700190 DCHECK_GE(interval, 0);
191 DCHECK_GE(fuzz, 0);
Alex Deymo0d11c602014-04-23 20:12:20 -0700192 int half_fuzz = fuzz / 2;
Alex Deymo0d11c602014-04-23 20:12:20 -0700193 // This guarantees the output interval is non negative.
Gilad Arnolde1218812014-05-07 12:21:36 -0700194 int interval_min = std::max(interval - half_fuzz, 0);
195 int interval_max = interval + half_fuzz;
196 return TimeDelta::FromSeconds(prng->RandMinMax(interval_min, interval_max));
Alex Deymo0d11c602014-04-23 20:12:20 -0700197}
198
Gilad Arnoldf62a4b82014-05-01 07:41:07 -0700199EvalStatus ChromeOSPolicy::UpdateScattering(
200 EvaluationContext* ec,
201 State* state,
202 string* error,
203 UpdateScatteringResult* result,
204 const UpdateState& update_state) const {
205 // Preconditions. These stem from the postconditions and usage contract.
206 DCHECK(update_state.scatter_wait_period >= kZeroInterval);
207 DCHECK_GE(update_state.scatter_check_threshold, 0);
208
209 // Set default result values.
210 result->is_scattering = false;
211 result->wait_period = kZeroInterval;
212 result->check_threshold = 0;
213
214 DevicePolicyProvider* const dp_provider = state->device_policy_provider();
215
216 // Ensure that a device policy is loaded.
217 const bool* device_policy_is_loaded_p = ec->GetValue(
218 dp_provider->var_device_policy_is_loaded());
219 if (!(device_policy_is_loaded_p && *device_policy_is_loaded_p))
220 return EvalStatus::kSucceeded;
221
222 // Is scattering enabled by policy?
223 const TimeDelta* scatter_factor_p = ec->GetValue(
224 dp_provider->var_scatter_factor());
225 if (!scatter_factor_p || *scatter_factor_p == kZeroInterval)
226 return EvalStatus::kSucceeded;
227
228 // Obtain a pseudo-random number generator.
229 const uint64_t* seed = ec->GetValue(state->random_provider()->var_seed());
230 POLICY_CHECK_VALUE_AND_FAIL(seed, error);
231 PRNG prng(*seed);
232
233 // Step 1: Maintain the scattering wait period.
234 //
235 // If no wait period was previously determined, or it no longer fits in the
236 // scatter factor, then generate a new one. Otherwise, keep the one we have.
237 // TODO(garnold) Current code (UpdateAttempter::GenerateNewWaitingPeriod())
238 // always generates a non-zero value, which seems to imply that *some*
239 // scattering always happens. Yet to validate whether this is intentional.
240 TimeDelta wait_period = update_state.scatter_wait_period;
241 if (wait_period == kZeroInterval || wait_period > *scatter_factor_p) {
242 wait_period = TimeDelta::FromSeconds(
243 prng.RandMinMax(1, scatter_factor_p->InSeconds()));
244 }
245
246 // If we surpass the wait period or the max scatter period associated with
247 // the update, then no wait is needed.
248 Time wait_expires = (update_state.first_seen +
249 min(wait_period, update_state.scatter_wait_period_max));
250 if (ec->IsTimeGreaterThan(wait_expires))
251 wait_period = kZeroInterval;
252
253 // Step 2: Maintain the update check threshold count.
254 //
255 // If an update check threshold is not specified then generate a new
256 // one.
257 int check_threshold = update_state.scatter_check_threshold;
258 if (check_threshold == 0) {
259 check_threshold = prng.RandMinMax(
260 update_state.scatter_check_threshold_min,
261 update_state.scatter_check_threshold_max);
262 }
263
264 // If the update check threshold is not within allowed range then nullify it.
265 // TODO(garnold) This is compliant with current logic found in
266 // OmahaRequestAction::IsUpdateCheckCountBasedWaitingSatisfied(). We may want
267 // to change it so that it behaves similarly to the wait period case, namely
268 // if the current value exceeds the maximum, we set a new one within range.
269 if (check_threshold > update_state.scatter_check_threshold_max)
270 check_threshold = 0;
271
272 // If the update check threshold is non-zero and satisfied, then nullify it.
273 if (check_threshold > 0 && update_state.num_checks >= check_threshold)
274 check_threshold = 0;
275
276 bool is_scattering = (wait_period != kZeroInterval || check_threshold);
277 EvalStatus ret = EvalStatus::kSucceeded;
278 if (is_scattering && wait_period == update_state.scatter_wait_period &&
279 check_threshold == update_state.scatter_check_threshold)
280 ret = EvalStatus::kAskMeAgainLater;
281 result->is_scattering = is_scattering;
282 result->wait_period = wait_period;
283 result->check_threshold = check_threshold;
284 return ret;
285}
286
Alex Deymoc705cc82014-02-19 11:15:00 -0800287} // namespace chromeos_policy_manager