1 //
2 // Copyright (C) 2012 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "update_engine/omaha_request_action.h"
18 
19 #include <inttypes.h>
20 
21 #include <limits>
22 #include <map>
23 #include <sstream>
24 #include <string>
25 #include <utility>
26 #include <vector>
27 
28 #include <base/bind.h>
29 #include <base/files/file_util.h>
30 #include <base/logging.h>
31 #include <base/optional.h>
32 #include <base/rand_util.h>
33 #include <base/strings/string_number_conversions.h>
34 #include <base/strings/string_split.h>
35 #include <base/strings/string_util.h>
36 #include <base/strings/stringprintf.h>
37 #include <base/time/time.h>
38 #include <brillo/key_value_store.h>
39 #include <expat.h>
40 #include <metrics/metrics_library.h>
41 #include <policy/libpolicy.h>
42 
43 #include "update_engine/common/action_pipe.h"
44 #include "update_engine/common/constants.h"
45 #include "update_engine/common/hardware_interface.h"
46 #include "update_engine/common/hash_calculator.h"
47 #include "update_engine/common/platform_constants.h"
48 #include "update_engine/common/prefs.h"
49 #include "update_engine/common/prefs_interface.h"
50 #include "update_engine/common/utils.h"
51 #include "update_engine/connection_manager_interface.h"
52 #include "update_engine/metrics_reporter_interface.h"
53 #include "update_engine/metrics_utils.h"
54 #include "update_engine/omaha_request_builder_xml.h"
55 #include "update_engine/omaha_request_params.h"
56 #include "update_engine/p2p_manager.h"
57 #include "update_engine/payload_state_interface.h"
58 #include "update_engine/update_attempter.h"
59 
60 using base::Optional;
61 using base::Time;
62 using base::TimeDelta;
63 using chromeos_update_manager::kRollforwardInfinity;
64 using std::map;
65 using std::string;
66 using std::vector;
67 
68 namespace chromeos_update_engine {
69 
70 // List of custom attributes that we interpret in the Omaha response:
71 constexpr char kAttrDeadline[] = "deadline";
72 constexpr char kAttrDisableP2PForDownloading[] = "DisableP2PForDownloading";
73 constexpr char kAttrDisableP2PForSharing[] = "DisableP2PForSharing";
74 constexpr char kAttrDisablePayloadBackoff[] = "DisablePayloadBackoff";
75 constexpr char kAttrVersion[] = "version";
76 // Deprecated: "IsDelta"
77 constexpr char kAttrIsDeltaPayload[] = "IsDeltaPayload";
78 constexpr char kAttrMaxFailureCountPerUrl[] = "MaxFailureCountPerUrl";
79 constexpr char kAttrMaxDaysToScatter[] = "MaxDaysToScatter";
80 // Deprecated: "ManifestSignatureRsa"
81 // Deprecated: "ManifestSize"
82 constexpr char kAttrMetadataSignatureRsa[] = "MetadataSignatureRsa";
83 constexpr char kAttrMetadataSize[] = "MetadataSize";
84 constexpr char kAttrMoreInfo[] = "MoreInfo";
85 constexpr char kAttrNoUpdate[] = "noupdate";
86 // Deprecated: "NeedsAdmin"
87 constexpr char kAttrPollInterval[] = "PollInterval";
88 constexpr char kAttrPowerwash[] = "Powerwash";
89 constexpr char kAttrPrompt[] = "Prompt";
90 constexpr char kAttrPublicKeyRsa[] = "PublicKeyRsa";
91 
92 // List of attributes that we interpret in the Omaha response:
93 constexpr char kAttrAppId[] = "appid";
94 constexpr char kAttrCodeBase[] = "codebase";
95 constexpr char kAttrCohort[] = "cohort";
96 constexpr char kAttrCohortHint[] = "cohorthint";
97 constexpr char kAttrCohortName[] = "cohortname";
98 constexpr char kAttrElapsedDays[] = "elapsed_days";
99 constexpr char kAttrElapsedSeconds[] = "elapsed_seconds";
100 constexpr char kAttrEvent[] = "event";
101 constexpr char kAttrHashSha256[] = "hash_sha256";
102 // Deprecated: "hash"; Although we still need to pass it from the server for
103 // backward compatibility.
104 constexpr char kAttrName[] = "name";
105 // Deprecated: "sha256"; Although we still need to pass it from the server for
106 // backward compatibility.
107 constexpr char kAttrSize[] = "size";
108 constexpr char kAttrStatus[] = "status";
109 
110 // List of values that we interpret in the Omaha response:
111 constexpr char kValPostInstall[] = "postinstall";
112 constexpr char kValNoUpdate[] = "noupdate";
113 
114 // updatecheck attributes (without the underscore prefix).
115 // Deprecated: "eol"
116 constexpr char kAttrEolDate[] = "eol_date";
117 constexpr char kAttrRollback[] = "rollback";
118 constexpr char kAttrFirmwareVersion[] = "firmware_version";
119 constexpr char kAttrKernelVersion[] = "kernel_version";
120 
121 // Struct used for holding data obtained when parsing the XML.
122 struct OmahaParserData {
OmahaParserDatachromeos_update_engine::OmahaParserData123   explicit OmahaParserData(XML_Parser _xml_parser) : xml_parser(_xml_parser) {}
124 
125   // Pointer to the expat XML_Parser object.
126   XML_Parser xml_parser;
127 
128   // This is the state of the parser as it's processing the XML.
129   bool failed = false;
130   bool entity_decl = false;
131   string current_path;
132 
133   // These are the values extracted from the XML.
134   string updatecheck_poll_interval;
135   map<string, string> updatecheck_attrs;
136   string daystart_elapsed_days;
137   string daystart_elapsed_seconds;
138 
139   struct App {
140     string id;
141     vector<string> url_codebase;
142     string manifest_version;
143     map<string, string> action_postinstall_attrs;
144     string updatecheck_status;
145     Optional<string> cohort;
146     Optional<string> cohorthint;
147     Optional<string> cohortname;
148 
149     struct Package {
150       string name;
151       string size;
152       string hash;
153     };
154     vector<Package> packages;
155   };
156   vector<App> apps;
157 };
158 
159 namespace {
160 
161 // Callback function invoked by expat.
ParserHandlerStart(void * user_data,const XML_Char * element,const XML_Char ** attr)162 void ParserHandlerStart(void* user_data,
163                         const XML_Char* element,
164                         const XML_Char** attr) {
165   OmahaParserData* data = reinterpret_cast<OmahaParserData*>(user_data);
166 
167   if (data->failed)
168     return;
169 
170   data->current_path += string("/") + element;
171 
172   map<string, string> attrs;
173   if (attr != nullptr) {
174     for (int n = 0; attr[n] != nullptr && attr[n + 1] != nullptr; n += 2) {
175       string key = attr[n];
176       string value = attr[n + 1];
177       attrs[key] = value;
178     }
179   }
180 
181   if (data->current_path == "/response/app") {
182     OmahaParserData::App app;
183     if (attrs.find(kAttrAppId) != attrs.end())
184       app.id = attrs[kAttrAppId];
185     if (attrs.find(kAttrCohort) != attrs.end())
186       app.cohort = attrs[kAttrCohort];
187     if (attrs.find(kAttrCohortHint) != attrs.end())
188       app.cohorthint = attrs[kAttrCohortHint];
189     if (attrs.find(kAttrCohortName) != attrs.end())
190       app.cohortname = attrs[kAttrCohortName];
191     data->apps.push_back(std::move(app));
192   } else if (data->current_path == "/response/app/updatecheck") {
193     if (!data->apps.empty())
194       data->apps.back().updatecheck_status = attrs[kAttrStatus];
195     if (data->updatecheck_poll_interval.empty())
196       data->updatecheck_poll_interval = attrs[kAttrPollInterval];
197     // Omaha sends arbitrary key-value pairs as extra attributes starting with
198     // an underscore.
199     for (const auto& attr : attrs) {
200       if (!attr.first.empty() && attr.first[0] == '_')
201         data->updatecheck_attrs[attr.first.substr(1)] = attr.second;
202     }
203   } else if (data->current_path == "/response/daystart") {
204     // Get the install-date.
205     data->daystart_elapsed_days = attrs[kAttrElapsedDays];
206     data->daystart_elapsed_seconds = attrs[kAttrElapsedSeconds];
207   } else if (data->current_path == "/response/app/updatecheck/urls/url") {
208     // Look at all <url> elements.
209     if (!data->apps.empty())
210       data->apps.back().url_codebase.push_back(attrs[kAttrCodeBase]);
211   } else if (data->current_path ==
212              "/response/app/updatecheck/manifest/packages/package") {
213     // Look at all <package> elements.
214     if (!data->apps.empty())
215       data->apps.back().packages.push_back({.name = attrs[kAttrName],
216                                             .size = attrs[kAttrSize],
217                                             .hash = attrs[kAttrHashSha256]});
218   } else if (data->current_path == "/response/app/updatecheck/manifest") {
219     // Get the version.
220     if (!data->apps.empty())
221       data->apps.back().manifest_version = attrs[kAttrVersion];
222   } else if (data->current_path ==
223              "/response/app/updatecheck/manifest/actions/action") {
224     // We only care about the postinstall action.
225     if (attrs[kAttrEvent] == kValPostInstall && !data->apps.empty()) {
226       data->apps.back().action_postinstall_attrs = std::move(attrs);
227     }
228   }
229 }
230 
231 // Callback function invoked by expat.
ParserHandlerEnd(void * user_data,const XML_Char * element)232 void ParserHandlerEnd(void* user_data, const XML_Char* element) {
233   OmahaParserData* data = reinterpret_cast<OmahaParserData*>(user_data);
234   if (data->failed)
235     return;
236 
237   const string path_suffix = string("/") + element;
238 
239   if (!base::EndsWith(
240           data->current_path, path_suffix, base::CompareCase::SENSITIVE)) {
241     LOG(ERROR) << "Unexpected end element '" << element
242                << "' with current_path='" << data->current_path << "'";
243     data->failed = true;
244     return;
245   }
246   data->current_path.resize(data->current_path.size() - path_suffix.size());
247 }
248 
249 // Callback function invoked by expat.
250 //
251 // This is called for entity declarations. Since Omaha is guaranteed
252 // to never return any XML with entities our course of action is to
253 // just stop parsing. This avoids potential resource exhaustion
254 // problems AKA the "billion laughs". CVE-2013-0340.
ParserHandlerEntityDecl(void * user_data,const XML_Char * entity_name,int is_parameter_entity,const XML_Char * value,int value_length,const XML_Char * base,const XML_Char * system_id,const XML_Char * public_id,const XML_Char * notation_name)255 void ParserHandlerEntityDecl(void* user_data,
256                              const XML_Char* entity_name,
257                              int is_parameter_entity,
258                              const XML_Char* value,
259                              int value_length,
260                              const XML_Char* base,
261                              const XML_Char* system_id,
262                              const XML_Char* public_id,
263                              const XML_Char* notation_name) {
264   OmahaParserData* data = reinterpret_cast<OmahaParserData*>(user_data);
265 
266   LOG(ERROR) << "XML entities are not supported. Aborting parsing.";
267   data->failed = true;
268   data->entity_decl = true;
269   XML_StopParser(data->xml_parser, false);
270 }
271 
272 }  // namespace
273 
OmahaRequestAction(SystemState * system_state,OmahaEvent * event,std::unique_ptr<HttpFetcher> http_fetcher,bool ping_only,const string & session_id)274 OmahaRequestAction::OmahaRequestAction(
275     SystemState* system_state,
276     OmahaEvent* event,
277     std::unique_ptr<HttpFetcher> http_fetcher,
278     bool ping_only,
279     const string& session_id)
280     : system_state_(system_state),
281       params_(system_state->request_params()),
282       event_(event),
283       http_fetcher_(std::move(http_fetcher)),
284       policy_provider_(std::make_unique<policy::PolicyProvider>()),
285       ping_only_(ping_only),
286       ping_active_days_(0),
287       ping_roll_call_days_(0),
288       session_id_(session_id) {
289   policy_provider_->Reload();
290 }
291 
~OmahaRequestAction()292 OmahaRequestAction::~OmahaRequestAction() {}
293 
294 // Calculates the value to use for the ping days parameter.
CalculatePingDays(const string & key)295 int OmahaRequestAction::CalculatePingDays(const string& key) {
296   int days = kPingNeverPinged;
297   int64_t last_ping = 0;
298   if (system_state_->prefs()->GetInt64(key, &last_ping) && last_ping >= 0) {
299     days = (Time::Now() - Time::FromInternalValue(last_ping)).InDays();
300     if (days < 0) {
301       // If |days| is negative, then the system clock must have jumped
302       // back in time since the ping was sent. Mark the value so that
303       // it doesn't get sent to the server but we still update the
304       // last ping daystart preference. This way the next ping time
305       // will be correct, hopefully.
306       days = kPingTimeJump;
307       LOG(WARNING)
308           << "System clock jumped back in time. Resetting ping daystarts.";
309     }
310   }
311   return days;
312 }
313 
InitPingDays()314 void OmahaRequestAction::InitPingDays() {
315   // We send pings only along with update checks, not with events.
316   if (IsEvent()) {
317     return;
318   }
319   // TODO(petkov): Figure a way to distinguish active use pings
320   // vs. roll call pings. Currently, the two pings are identical. A
321   // fix needs to change this code as well as UpdateLastPingDays and ShouldPing.
322   ping_active_days_ = CalculatePingDays(kPrefsLastActivePingDay);
323   ping_roll_call_days_ = CalculatePingDays(kPrefsLastRollCallPingDay);
324 }
325 
ShouldPing() const326 bool OmahaRequestAction::ShouldPing() const {
327   if (ping_active_days_ == kPingNeverPinged &&
328       ping_roll_call_days_ == kPingNeverPinged) {
329     int powerwash_count = system_state_->hardware()->GetPowerwashCount();
330     if (powerwash_count > 0) {
331       LOG(INFO) << "Not sending ping with a=-1 r=-1 to omaha because "
332                 << "powerwash_count is " << powerwash_count;
333       return false;
334     }
335     if (system_state_->hardware()->GetFirstActiveOmahaPingSent()) {
336       LOG(INFO) << "Not sending ping with a=-1 r=-1 to omaha because "
337                 << "the first_active_omaha_ping_sent is true";
338       return false;
339     }
340     return true;
341   }
342   return ping_active_days_ > 0 || ping_roll_call_days_ > 0;
343 }
344 
345 // static
GetInstallDate(SystemState * system_state)346 int OmahaRequestAction::GetInstallDate(SystemState* system_state) {
347   PrefsInterface* prefs = system_state->prefs();
348   if (prefs == nullptr)
349     return -1;
350 
351   // If we have the value stored on disk, just return it.
352   int64_t stored_value;
353   if (prefs->GetInt64(kPrefsInstallDateDays, &stored_value)) {
354     // Convert and validity-check.
355     int install_date_days = static_cast<int>(stored_value);
356     if (install_date_days >= 0)
357       return install_date_days;
358     LOG(ERROR) << "Dropping stored Omaha InstallData since its value num_days="
359                << install_date_days << " looks suspicious.";
360     prefs->Delete(kPrefsInstallDateDays);
361   }
362 
363   // Otherwise, if OOBE is not complete then do nothing and wait for
364   // ParseResponse() to call ParseInstallDate() and then
365   // PersistInstallDate() to set the kPrefsInstallDateDays state
366   // variable. Once that is done, we'll then report back in future
367   // Omaha requests.  This works exactly because OOBE triggers an
368   // update check.
369   //
370   // However, if OOBE is complete and the kPrefsInstallDateDays state
371   // variable is not set, there are two possibilities
372   //
373   //   1. The update check in OOBE failed so we never got a response
374   //      from Omaha (no network etc.); or
375   //
376   //   2. OOBE was done on an older version that didn't write to the
377   //      kPrefsInstallDateDays state variable.
378   //
379   // In both cases, we approximate the install date by simply
380   // inspecting the timestamp of when OOBE happened.
381 
382   Time time_of_oobe;
383   if (!system_state->hardware()->IsOOBEEnabled() ||
384       !system_state->hardware()->IsOOBEComplete(&time_of_oobe)) {
385     LOG(INFO) << "Not generating Omaha InstallData as we have "
386               << "no prefs file and OOBE is not complete or not enabled.";
387     return -1;
388   }
389 
390   int num_days;
391   if (!utils::ConvertToOmahaInstallDate(time_of_oobe, &num_days)) {
392     LOG(ERROR) << "Not generating Omaha InstallData from time of OOBE "
393                << "as its value '" << utils::ToString(time_of_oobe)
394                << "' looks suspicious.";
395     return -1;
396   }
397 
398   // Persist this to disk, for future use.
399   if (!OmahaRequestAction::PersistInstallDate(
400           system_state, num_days, kProvisionedFromOOBEMarker))
401     return -1;
402 
403   LOG(INFO) << "Set the Omaha InstallDate from OOBE time-stamp to " << num_days
404             << " days";
405 
406   return num_days;
407 }
408 
StorePingReply(const OmahaParserData & parser_data) const409 void OmahaRequestAction::StorePingReply(
410     const OmahaParserData& parser_data) const {
411   for (const auto& app : parser_data.apps) {
412     auto it = params_->dlc_apps_params().find(app.id);
413     if (it == params_->dlc_apps_params().end())
414       continue;
415 
416     const OmahaRequestParams::AppParams& dlc_params = it->second;
417     const string& dlc_id = dlc_params.name;
418     // Skip if the ping for this DLC was not sent.
419     if (!dlc_params.send_ping)
420       continue;
421 
422     PrefsInterface* prefs = system_state_->prefs();
423     // Reset the active metadata value to |kPingInactiveValue|.
424     auto active_key =
425         prefs->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsPingActive});
426     if (!prefs->SetInt64(active_key, kPingInactiveValue))
427       LOG(ERROR) << "Failed to set the value of ping metadata '" << active_key
428                  << "'.";
429 
430     auto last_rollcall_key =
431         prefs->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsPingLastRollcall});
432     if (!prefs->SetString(last_rollcall_key, parser_data.daystart_elapsed_days))
433       LOG(ERROR) << "Failed to set the value of ping metadata '"
434                  << last_rollcall_key << "'.";
435 
436     if (dlc_params.ping_active) {
437       // Write the value of elapsed_days into |kPrefsPingLastActive| only if
438       // the previous ping was an active one.
439       auto last_active_key =
440           prefs->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsPingLastActive});
441       if (!prefs->SetString(last_active_key, parser_data.daystart_elapsed_days))
442         LOG(ERROR) << "Failed to set the value of ping metadata '"
443                    << last_active_key << "'.";
444     }
445   }
446 }
447 
PerformAction()448 void OmahaRequestAction::PerformAction() {
449   http_fetcher_->set_delegate(this);
450   InitPingDays();
451   if (ping_only_ && !ShouldPing()) {
452     processor_->ActionComplete(this, ErrorCode::kSuccess);
453     return;
454   }
455 
456   OmahaRequestBuilderXml omaha_request(event_.get(),
457                                        params_,
458                                        ping_only_,
459                                        ShouldPing(),  // include_ping
460                                        ping_active_days_,
461                                        ping_roll_call_days_,
462                                        GetInstallDate(system_state_),
463                                        system_state_->prefs(),
464                                        session_id_);
465   string request_post = omaha_request.GetRequest();
466 
467   // Set X-Goog-Update headers.
468   http_fetcher_->SetHeader(kXGoogleUpdateInteractivity,
469                            params_->interactive() ? "fg" : "bg");
470   http_fetcher_->SetHeader(kXGoogleUpdateAppId, params_->GetAppId());
471   http_fetcher_->SetHeader(
472       kXGoogleUpdateUpdater,
473       base::StringPrintf(
474           "%s-%s", constants::kOmahaUpdaterID, kOmahaUpdaterVersion));
475 
476   http_fetcher_->SetPostData(
477       request_post.data(), request_post.size(), kHttpContentTypeTextXml);
478   LOG(INFO) << "Posting an Omaha request to " << params_->update_url();
479   LOG(INFO) << "Request: " << request_post;
480   http_fetcher_->BeginTransfer(params_->update_url());
481 }
482 
TerminateProcessing()483 void OmahaRequestAction::TerminateProcessing() {
484   http_fetcher_->TerminateTransfer();
485 }
486 
487 // We just store the response in the buffer. Once we've received all bytes,
488 // we'll look in the buffer and decide what to do.
ReceivedBytes(HttpFetcher * fetcher,const void * bytes,size_t length)489 bool OmahaRequestAction::ReceivedBytes(HttpFetcher* fetcher,
490                                        const void* bytes,
491                                        size_t length) {
492   const uint8_t* byte_ptr = reinterpret_cast<const uint8_t*>(bytes);
493   response_buffer_.insert(response_buffer_.end(), byte_ptr, byte_ptr + length);
494   return true;
495 }
496 
497 namespace {
498 
499 // Parses a 64 bit base-10 int from a string and returns it. Returns 0
500 // on error. If the string contains "0", that's indistinguishable from
501 // error.
ParseInt(const string & str)502 off_t ParseInt(const string& str) {
503   off_t ret = 0;
504   int rc = sscanf(str.c_str(), "%" PRIi64, &ret);  // NOLINT(runtime/printf)
505   if (rc < 1) {
506     // failure
507     return 0;
508   }
509   return ret;
510 }
511 
512 // Parses |str| and returns |true| if, and only if, its value is "true".
ParseBool(const string & str)513 bool ParseBool(const string& str) {
514   return str == "true";
515 }
516 
517 // Update the last ping day preferences based on the server daystart
518 // response. Returns true on success, false otherwise.
UpdateLastPingDays(OmahaParserData * parser_data,PrefsInterface * prefs)519 bool UpdateLastPingDays(OmahaParserData* parser_data, PrefsInterface* prefs) {
520   int64_t elapsed_seconds = 0;
521   TEST_AND_RETURN_FALSE(base::StringToInt64(
522       parser_data->daystart_elapsed_seconds, &elapsed_seconds));
523   TEST_AND_RETURN_FALSE(elapsed_seconds >= 0);
524 
525   // Remember the local time that matches the server's last midnight
526   // time.
527   Time daystart = Time::Now() - TimeDelta::FromSeconds(elapsed_seconds);
528   prefs->SetInt64(kPrefsLastActivePingDay, daystart.ToInternalValue());
529   prefs->SetInt64(kPrefsLastRollCallPingDay, daystart.ToInternalValue());
530   return true;
531 }
532 
533 // Parses the package node in the given XML document and populates
534 // |output_object| if valid. Returns true if we should continue the parsing.
535 // False otherwise, in which case it sets any error code using |completer|.
ParsePackage(OmahaParserData::App * app,OmahaResponse * output_object,bool can_exclude,ScopedActionCompleter * completer)536 bool ParsePackage(OmahaParserData::App* app,
537                   OmahaResponse* output_object,
538                   bool can_exclude,
539                   ScopedActionCompleter* completer) {
540   if (app->updatecheck_status.empty() ||
541       app->updatecheck_status == kValNoUpdate) {
542     if (!app->packages.empty()) {
543       LOG(ERROR) << "No update in this <app> but <package> is not empty.";
544       completer->set_code(ErrorCode::kOmahaResponseInvalid);
545       return false;
546     }
547     return true;
548   }
549   if (app->packages.empty()) {
550     LOG(ERROR) << "Omaha Response has no packages";
551     completer->set_code(ErrorCode::kOmahaResponseInvalid);
552     return false;
553   }
554   if (app->url_codebase.empty()) {
555     LOG(ERROR) << "No Omaha Response URLs";
556     completer->set_code(ErrorCode::kOmahaResponseInvalid);
557     return false;
558   }
559   LOG(INFO) << "Found " << app->url_codebase.size() << " url(s)";
560   vector<string> metadata_sizes =
561       base::SplitString(app->action_postinstall_attrs[kAttrMetadataSize],
562                         ":",
563                         base::TRIM_WHITESPACE,
564                         base::SPLIT_WANT_ALL);
565   vector<string> metadata_signatures = base::SplitString(
566       app->action_postinstall_attrs[kAttrMetadataSignatureRsa],
567       ":",
568       base::TRIM_WHITESPACE,
569       base::SPLIT_WANT_ALL);
570   vector<string> is_delta_payloads =
571       base::SplitString(app->action_postinstall_attrs[kAttrIsDeltaPayload],
572                         ":",
573                         base::TRIM_WHITESPACE,
574                         base::SPLIT_WANT_ALL);
575   for (size_t i = 0; i < app->packages.size(); i++) {
576     const auto& package = app->packages[i];
577     if (package.name.empty()) {
578       LOG(ERROR) << "Omaha Response has empty package name";
579       completer->set_code(ErrorCode::kOmahaResponseInvalid);
580       return false;
581     }
582     LOG(INFO) << "Found package " << package.name;
583 
584     OmahaResponse::Package out_package;
585     out_package.can_exclude = can_exclude;
586     for (const string& codebase : app->url_codebase) {
587       if (codebase.empty()) {
588         LOG(ERROR) << "Omaha Response URL has empty codebase";
589         completer->set_code(ErrorCode::kOmahaResponseInvalid);
590         return false;
591       }
592       out_package.payload_urls.push_back(codebase + package.name);
593     }
594     // Parse the payload size.
595     base::StringToUint64(package.size, &out_package.size);
596     if (out_package.size <= 0) {
597       LOG(ERROR) << "Omaha Response has invalid payload size: " << package.size;
598       completer->set_code(ErrorCode::kOmahaResponseInvalid);
599       return false;
600     }
601     LOG(INFO) << "Payload size = " << out_package.size << " bytes";
602 
603     if (i < metadata_sizes.size())
604       base::StringToUint64(metadata_sizes[i], &out_package.metadata_size);
605     LOG(INFO) << "Payload metadata size = " << out_package.metadata_size
606               << " bytes";
607 
608     if (i < metadata_signatures.size())
609       out_package.metadata_signature = metadata_signatures[i];
610     LOG(INFO) << "Payload metadata signature = "
611               << out_package.metadata_signature;
612 
613     out_package.hash = package.hash;
614     if (out_package.hash.empty()) {
615       LOG(ERROR) << "Omaha Response has empty hash_sha256 value";
616       completer->set_code(ErrorCode::kOmahaResponseInvalid);
617       return false;
618     }
619     LOG(INFO) << "Payload hash = " << out_package.hash;
620 
621     if (i < is_delta_payloads.size())
622       out_package.is_delta = ParseBool(is_delta_payloads[i]);
623     LOG(INFO) << "Payload is delta = " << utils::ToString(out_package.is_delta);
624 
625     output_object->packages.push_back(std::move(out_package));
626   }
627 
628   return true;
629 }
630 
631 // Removes the candidate URLs which are excluded within packages, if all the
632 // candidate URLs are excluded within a package, the package will be excluded.
ProcessExclusions(OmahaResponse * output_object,ExcluderInterface * excluder)633 void ProcessExclusions(OmahaResponse* output_object,
634                        ExcluderInterface* excluder) {
635   for (auto package_it = output_object->packages.begin();
636        package_it != output_object->packages.end();
637        /* Increment logic in loop */) {
638     // If package cannot be excluded, quickly continue.
639     if (!package_it->can_exclude) {
640       ++package_it;
641       continue;
642     }
643     // Remove the excluded payload URLs.
644     for (auto payload_url_it = package_it->payload_urls.begin();
645          payload_url_it != package_it->payload_urls.end();
646          /* Increment logic in loop */) {
647       auto exclusion_name = utils::GetExclusionName(*payload_url_it);
648       // If payload URL is not excluded, quickly continue.
649       if (!excluder->IsExcluded(exclusion_name)) {
650         ++payload_url_it;
651         continue;
652       }
653       LOG(INFO) << "Excluding payload URL=" << *payload_url_it
654                 << " for payload hash=" << package_it->hash;
655       payload_url_it = package_it->payload_urls.erase(payload_url_it);
656     }
657     // If there are no candidate payload URLs, remove the package.
658     if (package_it->payload_urls.empty()) {
659       LOG(INFO) << "Excluding payload hash=" << package_it->hash;
660       package_it = output_object->packages.erase(package_it);
661       continue;
662     }
663     ++package_it;
664   }
665 }
666 
667 // Parses the 2 key version strings kernel_version and firmware_version. If the
668 // field is not present, or cannot be parsed the values default to 0xffff.
ParseRollbackVersions(int allowed_milestones,OmahaParserData * parser_data,OmahaResponse * output_object)669 void ParseRollbackVersions(int allowed_milestones,
670                            OmahaParserData* parser_data,
671                            OmahaResponse* output_object) {
672   utils::ParseRollbackKeyVersion(
673       parser_data->updatecheck_attrs[kAttrFirmwareVersion],
674       &output_object->rollback_key_version.firmware_key,
675       &output_object->rollback_key_version.firmware);
676   utils::ParseRollbackKeyVersion(
677       parser_data->updatecheck_attrs[kAttrKernelVersion],
678       &output_object->rollback_key_version.kernel_key,
679       &output_object->rollback_key_version.kernel);
680 
681   // Create the attribute name strings for milestone N - allowed_milestones.
682   const string firmware_max_rollforward_attr =
683       base::StringPrintf("%s_%i", kAttrFirmwareVersion, allowed_milestones);
684   const string kernel_max_rollforward_attr =
685       base::StringPrintf("%s_%i", kAttrKernelVersion, allowed_milestones);
686 
687   const bool max_firmware_and_kernel_exist =
688       parser_data->updatecheck_attrs.count(firmware_max_rollforward_attr) > 0 &&
689       parser_data->updatecheck_attrs.count(kernel_max_rollforward_attr) > 0;
690 
691   string firmware_version;
692   string kernel_version;
693   if (max_firmware_and_kernel_exist) {
694     firmware_version =
695         parser_data->updatecheck_attrs[firmware_max_rollforward_attr];
696     kernel_version =
697         parser_data->updatecheck_attrs[kernel_max_rollforward_attr];
698   }
699 
700   LOG(INFO) << "For milestone N-" << allowed_milestones
701             << " firmware_key_version=" << firmware_version
702             << " kernel_key_version=" << kernel_version;
703 
704   OmahaResponse::RollbackKeyVersion version;
705   utils::ParseRollbackKeyVersion(
706       firmware_version, &version.firmware_key, &version.firmware);
707   utils::ParseRollbackKeyVersion(
708       kernel_version, &version.kernel_key, &version.kernel);
709 
710   output_object->past_rollback_key_version = std::move(version);
711 }
712 
713 }  // namespace
714 
ParseResponse(OmahaParserData * parser_data,OmahaResponse * output_object,ScopedActionCompleter * completer)715 bool OmahaRequestAction::ParseResponse(OmahaParserData* parser_data,
716                                        OmahaResponse* output_object,
717                                        ScopedActionCompleter* completer) {
718   if (parser_data->apps.empty()) {
719     completer->set_code(ErrorCode::kOmahaResponseInvalid);
720     return false;
721   }
722   LOG(INFO) << "Found " << parser_data->apps.size() << " <app>.";
723 
724   // chromium-os:37289: The PollInterval is not supported by Omaha server
725   // currently.  But still keeping this existing code in case we ever decide to
726   // slow down the request rate from the server-side. Note that the PollInterval
727   // is not persisted, so it has to be sent by the server on every response to
728   // guarantee that the scheduler uses this value (otherwise, if the device got
729   // rebooted after the last server-indicated value, it'll revert to the default
730   // value). Also kDefaultMaxUpdateChecks value for the scattering logic is
731   // based on the assumption that we perform an update check every hour so that
732   // the max value of 8 will roughly be equivalent to one work day. If we decide
733   // to use PollInterval permanently, we should update the
734   // max_update_checks_allowed to take PollInterval into account.  Note: The
735   // parsing for PollInterval happens even before parsing of the status because
736   // we may want to specify the PollInterval even when there's no update.
737   base::StringToInt(parser_data->updatecheck_poll_interval,
738                     &output_object->poll_interval);
739 
740   // Check for the "elapsed_days" attribute in the "daystart"
741   // element. This is the number of days since Jan 1 2007, 0:00
742   // PST. If we don't have a persisted value of the Omaha InstallDate,
743   // we'll use it to calculate it and then persist it.
744   if (ParseInstallDate(parser_data, output_object) &&
745       !HasInstallDate(system_state_)) {
746     // Since output_object->install_date_days is never negative, the
747     // elapsed_days -> install-date calculation is reduced to simply
748     // rounding down to the nearest number divisible by 7.
749     int remainder = output_object->install_date_days % 7;
750     int install_date_days_rounded =
751         output_object->install_date_days - remainder;
752     if (PersistInstallDate(system_state_,
753                            install_date_days_rounded,
754                            kProvisionedFromOmahaResponse)) {
755       LOG(INFO) << "Set the Omaha InstallDate from Omaha Response to "
756                 << install_date_days_rounded << " days";
757     }
758   }
759 
760   // We persist the cohorts sent by omaha even if the status is "noupdate".
761   for (const auto& app : parser_data->apps) {
762     if (app.id == params_->GetAppId()) {
763       if (app.cohort)
764         PersistCohortData(kPrefsOmahaCohort, app.cohort.value());
765       if (app.cohorthint)
766         PersistCohortData(kPrefsOmahaCohortHint, app.cohorthint.value());
767       if (app.cohortname)
768         PersistCohortData(kPrefsOmahaCohortName, app.cohortname.value());
769       break;
770     }
771   }
772 
773   PersistEolInfo(parser_data->updatecheck_attrs);
774 
775   // Rollback-related updatecheck attributes.
776   // Defaults to false if attribute is not present.
777   output_object->is_rollback =
778       ParseBool(parser_data->updatecheck_attrs[kAttrRollback]);
779 
780   // Parses the rollback versions of the current image. If the fields do not
781   // exist they default to 0xffff for the 4 key versions.
782   ParseRollbackVersions(
783       params_->rollback_allowed_milestones(), parser_data, output_object);
784 
785   if (!ParseStatus(parser_data, output_object, completer))
786     return false;
787 
788   if (!ParseParams(parser_data, output_object, completer))
789     return false;
790 
791   // Package has to be parsed after Params now because ParseParams need to make
792   // sure that postinstall action exists.
793   for (auto& app : parser_data->apps) {
794     // Only allow exclusions for a non-critical package during an update. For
795     // non-critical package installations, let the errors propagate instead
796     // of being handled inside update_engine as installations are a dlcservice
797     // specific feature.
798     bool can_exclude = !params_->is_install() && params_->IsDlcAppId(app.id);
799     if (!ParsePackage(&app, output_object, can_exclude, completer))
800       return false;
801   }
802 
803   return true;
804 }
805 
ParseStatus(OmahaParserData * parser_data,OmahaResponse * output_object,ScopedActionCompleter * completer)806 bool OmahaRequestAction::ParseStatus(OmahaParserData* parser_data,
807                                      OmahaResponse* output_object,
808                                      ScopedActionCompleter* completer) {
809   output_object->update_exists = false;
810   for (const auto& app : parser_data->apps) {
811     const string& status = app.updatecheck_status;
812     if (status == kValNoUpdate) {
813       // If the app is a DLC, allow status "noupdate" to support DLC
814       // deprecations.
815       if (params_->IsDlcAppId(app.id)) {
816         LOG(INFO) << "No update for <app> " << app.id
817                   << " but update continuing since a DLC.";
818         params_->SetDlcNoUpdate(app.id);
819         continue;
820       }
821       // Don't update if any app has status="noupdate".
822       LOG(INFO) << "No update for <app> " << app.id;
823       output_object->update_exists = false;
824       break;
825     } else if (status == "ok") {
826       auto const& attr_no_update =
827           app.action_postinstall_attrs.find(kAttrNoUpdate);
828       if (attr_no_update != app.action_postinstall_attrs.end() &&
829           attr_no_update->second == "true") {
830         // noupdate="true" in postinstall attributes means it's an update to
831         // self, only update if there's at least one app really have update.
832         LOG(INFO) << "Update to self for <app> " << app.id;
833       } else {
834         LOG(INFO) << "Update for <app> " << app.id;
835         output_object->update_exists = true;
836       }
837     } else if (status.empty() && params_->is_install() &&
838                params_->GetAppId() == app.id) {
839       // Skips the platform app for install operation.
840       LOG(INFO) << "No payload (and ignore) for <app> " << app.id;
841     } else {
842       LOG(ERROR) << "Unknown Omaha response status: " << status;
843       completer->set_code(ErrorCode::kOmahaResponseInvalid);
844       return false;
845     }
846   }
847   if (!output_object->update_exists) {
848     SetOutputObject(*output_object);
849     completer->set_code(ErrorCode::kSuccess);
850   }
851 
852   return output_object->update_exists;
853 }
854 
ParseParams(OmahaParserData * parser_data,OmahaResponse * output_object,ScopedActionCompleter * completer)855 bool OmahaRequestAction::ParseParams(OmahaParserData* parser_data,
856                                      OmahaResponse* output_object,
857                                      ScopedActionCompleter* completer) {
858   map<string, string> attrs;
859   for (auto& app : parser_data->apps) {
860     if (app.id == params_->GetAppId()) {
861       // this is the app (potentially the only app)
862       output_object->version = app.manifest_version;
863     } else if (!params_->system_app_id().empty() &&
864                app.id == params_->system_app_id()) {
865       // this is the system app (this check is intentionally skipped if there is
866       // no system_app_id set)
867       output_object->system_version = app.manifest_version;
868     } else if (params_->is_install() &&
869                app.manifest_version != params_->app_version()) {
870       LOG(WARNING) << "An app has a different version (" << app.manifest_version
871                    << ") that is different than platform app version ("
872                    << params_->app_version() << ")";
873     }
874     if (!app.action_postinstall_attrs.empty() && attrs.empty()) {
875       attrs = app.action_postinstall_attrs;
876     }
877   }
878   if (params_->is_install()) {
879     LOG(INFO) << "Use request version for Install operation.";
880     output_object->version = params_->app_version();
881   }
882   if (output_object->version.empty()) {
883     LOG(ERROR) << "Omaha Response does not have version in manifest!";
884     completer->set_code(ErrorCode::kOmahaResponseInvalid);
885     return false;
886   }
887 
888   LOG(INFO) << "Received omaha response to update to version "
889             << output_object->version;
890 
891   if (attrs.empty()) {
892     LOG(ERROR) << "Omaha Response has no postinstall event action";
893     completer->set_code(ErrorCode::kOmahaResponseInvalid);
894     return false;
895   }
896 
897   // Get the optional properties one by one.
898   output_object->more_info_url = attrs[kAttrMoreInfo];
899   output_object->prompt = ParseBool(attrs[kAttrPrompt]);
900   output_object->deadline = attrs[kAttrDeadline];
901   output_object->max_days_to_scatter = ParseInt(attrs[kAttrMaxDaysToScatter]);
902   output_object->disable_p2p_for_downloading =
903       ParseBool(attrs[kAttrDisableP2PForDownloading]);
904   output_object->disable_p2p_for_sharing =
905       ParseBool(attrs[kAttrDisableP2PForSharing]);
906   output_object->public_key_rsa = attrs[kAttrPublicKeyRsa];
907 
908   string max = attrs[kAttrMaxFailureCountPerUrl];
909   if (!base::StringToUint(max, &output_object->max_failure_count_per_url))
910     output_object->max_failure_count_per_url = kDefaultMaxFailureCountPerUrl;
911 
912   output_object->disable_payload_backoff =
913       ParseBool(attrs[kAttrDisablePayloadBackoff]);
914   output_object->powerwash_required = ParseBool(attrs[kAttrPowerwash]);
915 
916   return true;
917 }
918 
919 // If the transfer was successful, this uses expat to parse the response
920 // and fill in the appropriate fields of the output object. Also, notifies
921 // the processor that we're done.
TransferComplete(HttpFetcher * fetcher,bool successful)922 void OmahaRequestAction::TransferComplete(HttpFetcher* fetcher,
923                                           bool successful) {
924   ScopedActionCompleter completer(processor_, this);
925   string current_response(response_buffer_.begin(), response_buffer_.end());
926   LOG(INFO) << "Omaha request response: " << current_response;
927 
928   PayloadStateInterface* const payload_state = system_state_->payload_state();
929 
930   // Set the max kernel key version based on whether rollback is allowed.
931   SetMaxKernelKeyVersionForRollback();
932 
933   // Events are best effort transactions -- assume they always succeed.
934   if (IsEvent()) {
935     CHECK(!HasOutputPipe()) << "No output pipe allowed for event requests.";
936     completer.set_code(ErrorCode::kSuccess);
937     return;
938   }
939 
940   ErrorCode aux_error_code = fetcher->GetAuxiliaryErrorCode();
941   if (aux_error_code != ErrorCode::kSuccess) {
942     metrics::DownloadErrorCode download_error_code =
943         metrics_utils::GetDownloadErrorCode(aux_error_code);
944     system_state_->metrics_reporter()->ReportUpdateCheckMetrics(
945         system_state_,
946         metrics::CheckResult::kUnset,
947         metrics::CheckReaction::kUnset,
948         download_error_code);
949   }
950 
951   if (!successful) {
952     int code = GetHTTPResponseCode();
953     LOG(ERROR) << "Omaha request network transfer failed with HTTPResponseCode="
954                << code;
955     // Makes sure we send proper error values.
956     if (code < 0 || code >= 1000) {
957       code = 999;
958       LOG(WARNING) << "Converting to proper HTTPResponseCode=" << code;
959     }
960     completer.set_code(static_cast<ErrorCode>(
961         static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase) + code));
962     return;
963   }
964 
965   XML_Parser parser = XML_ParserCreate(nullptr);
966   OmahaParserData parser_data(parser);
967   XML_SetUserData(parser, &parser_data);
968   XML_SetElementHandler(parser, ParserHandlerStart, ParserHandlerEnd);
969   XML_SetEntityDeclHandler(parser, ParserHandlerEntityDecl);
970   XML_Status res =
971       XML_Parse(parser,
972                 reinterpret_cast<const char*>(response_buffer_.data()),
973                 response_buffer_.size(),
974                 XML_TRUE);
975 
976   if (res != XML_STATUS_OK || parser_data.failed) {
977     LOG(ERROR) << "Omaha response not valid XML: "
978                << XML_ErrorString(XML_GetErrorCode(parser)) << " at line "
979                << XML_GetCurrentLineNumber(parser) << " col "
980                << XML_GetCurrentColumnNumber(parser);
981     XML_ParserFree(parser);
982     ErrorCode error_code = ErrorCode::kOmahaRequestXMLParseError;
983     if (response_buffer_.empty()) {
984       error_code = ErrorCode::kOmahaRequestEmptyResponseError;
985     } else if (parser_data.entity_decl) {
986       error_code = ErrorCode::kOmahaRequestXMLHasEntityDecl;
987     }
988     completer.set_code(error_code);
989     return;
990   }
991   XML_ParserFree(parser);
992 
993   // Update the last ping day preferences based on the server daystart response
994   // even if we didn't send a ping. Omaha always includes the daystart in the
995   // response, but log the error if it didn't.
996   LOG_IF(ERROR, !UpdateLastPingDays(&parser_data, system_state_->prefs()))
997       << "Failed to update the last ping day preferences!";
998 
999   // Sets first_active_omaha_ping_sent to true (vpd in CrOS). We only do this if
1000   // we have got a response from omaha and if its value has never been set to
1001   // true before. Failure of this function should be ignored. There should be no
1002   // need to check if a=-1 has been sent because older devices have already sent
1003   // their a=-1 in the past and we have to set first_active_omaha_ping_sent for
1004   // future checks.
1005   if (!system_state_->hardware()->GetFirstActiveOmahaPingSent()) {
1006     if (!system_state_->hardware()->SetFirstActiveOmahaPingSent()) {
1007       system_state_->metrics_reporter()->ReportInternalErrorCode(
1008           ErrorCode::kFirstActiveOmahaPingSentPersistenceError);
1009     }
1010   }
1011 
1012   // Create/update the metadata files for each DLC app received.
1013   StorePingReply(parser_data);
1014 
1015   if (!HasOutputPipe()) {
1016     // Just set success to whether or not the http transfer succeeded,
1017     // which must be true at this point in the code.
1018     completer.set_code(ErrorCode::kSuccess);
1019     return;
1020   }
1021 
1022   OmahaResponse output_object;
1023   if (!ParseResponse(&parser_data, &output_object, &completer))
1024     return;
1025   ProcessExclusions(&output_object,
1026                     system_state_->update_attempter()->GetExcluder());
1027   output_object.update_exists = true;
1028   SetOutputObject(output_object);
1029 
1030   LoadOrPersistUpdateFirstSeenAtPref();
1031 
1032   ErrorCode error = ErrorCode::kSuccess;
1033   if (ShouldIgnoreUpdate(output_object, &error)) {
1034     // No need to change output_object.update_exists here, since the value
1035     // has been output to the pipe.
1036     completer.set_code(error);
1037     return;
1038   }
1039 
1040   // If Omaha says to disable p2p, respect that
1041   if (output_object.disable_p2p_for_downloading) {
1042     LOG(INFO) << "Forcibly disabling use of p2p for downloading as "
1043               << "requested by Omaha.";
1044     payload_state->SetUsingP2PForDownloading(false);
1045   }
1046   if (output_object.disable_p2p_for_sharing) {
1047     LOG(INFO) << "Forcibly disabling use of p2p for sharing as "
1048               << "requested by Omaha.";
1049     payload_state->SetUsingP2PForSharing(false);
1050   }
1051 
1052   // Update the payload state with the current response. The payload state
1053   // will automatically reset all stale state if this response is different
1054   // from what's stored already. We are updating the payload state as late
1055   // as possible in this method so that if a new release gets pushed and then
1056   // got pulled back due to some issues, we don't want to clear our internal
1057   // state unnecessarily.
1058   payload_state->SetResponse(output_object);
1059 
1060   // It could be we've already exceeded the deadline for when p2p is
1061   // allowed or that we've tried too many times with p2p. Check that.
1062   if (payload_state->GetUsingP2PForDownloading()) {
1063     payload_state->P2PNewAttempt();
1064     if (!payload_state->P2PAttemptAllowed()) {
1065       LOG(INFO) << "Forcibly disabling use of p2p for downloading because "
1066                 << "of previous failures when using p2p.";
1067       payload_state->SetUsingP2PForDownloading(false);
1068     }
1069   }
1070 
1071   // From here on, we'll complete stuff in CompleteProcessing() so
1072   // disable |completer| since we'll create a new one in that
1073   // function.
1074   completer.set_should_complete(false);
1075 
1076   // If we're allowed to use p2p for downloading we do not pay
1077   // attention to wall-clock-based waiting if the URL is indeed
1078   // available via p2p. Therefore, check if the file is available via
1079   // p2p before deferring...
1080   if (payload_state->GetUsingP2PForDownloading()) {
1081     LookupPayloadViaP2P(output_object);
1082   } else {
1083     CompleteProcessing();
1084   }
1085 }
1086 
CompleteProcessing()1087 void OmahaRequestAction::CompleteProcessing() {
1088   ScopedActionCompleter completer(processor_, this);
1089   OmahaResponse& output_object = const_cast<OmahaResponse&>(GetOutputObject());
1090   PayloadStateInterface* payload_state = system_state_->payload_state();
1091 
1092   if (ShouldDeferDownload(&output_object)) {
1093     output_object.update_exists = false;
1094     LOG(INFO) << "Ignoring Omaha updates as updates are deferred by policy.";
1095     completer.set_code(ErrorCode::kOmahaUpdateDeferredPerPolicy);
1096     return;
1097   }
1098 
1099   if (payload_state->ShouldBackoffDownload()) {
1100     output_object.update_exists = false;
1101     LOG(INFO) << "Ignoring Omaha updates in order to backoff our retry "
1102               << "attempts";
1103     completer.set_code(ErrorCode::kOmahaUpdateDeferredForBackoff);
1104     return;
1105   }
1106   completer.set_code(ErrorCode::kSuccess);
1107 }
1108 
OnLookupPayloadViaP2PCompleted(const string & url)1109 void OmahaRequestAction::OnLookupPayloadViaP2PCompleted(const string& url) {
1110   LOG(INFO) << "Lookup complete, p2p-client returned URL '" << url << "'";
1111   if (!url.empty()) {
1112     system_state_->payload_state()->SetP2PUrl(url);
1113   } else {
1114     LOG(INFO) << "Forcibly disabling use of p2p for downloading "
1115               << "because no suitable peer could be found.";
1116     system_state_->payload_state()->SetUsingP2PForDownloading(false);
1117   }
1118   CompleteProcessing();
1119 }
1120 
LookupPayloadViaP2P(const OmahaResponse & response)1121 void OmahaRequestAction::LookupPayloadViaP2P(const OmahaResponse& response) {
1122   // If the device is in the middle of an update, the state variables
1123   // kPrefsUpdateStateNextDataOffset, kPrefsUpdateStateNextDataLength
1124   // tracks the offset and length of the operation currently in
1125   // progress. The offset is based from the end of the manifest which
1126   // is kPrefsManifestMetadataSize bytes long.
1127   //
1128   // To make forward progress and avoid deadlocks, we need to find a
1129   // peer that has at least the entire operation we're currently
1130   // working on. Otherwise we may end up in a situation where two
1131   // devices bounce back and forth downloading from each other,
1132   // neither making any forward progress until one of them decides to
1133   // stop using p2p (via kMaxP2PAttempts and kMaxP2PAttemptTimeSeconds
1134   // safe-guards). See http://crbug.com/297170 for an example)
1135   size_t minimum_size = 0;
1136   int64_t manifest_metadata_size = 0;
1137   int64_t manifest_signature_size = 0;
1138   int64_t next_data_offset = 0;
1139   int64_t next_data_length = 0;
1140   if (system_state_ &&
1141       system_state_->prefs()->GetInt64(kPrefsManifestMetadataSize,
1142                                        &manifest_metadata_size) &&
1143       manifest_metadata_size != -1 &&
1144       system_state_->prefs()->GetInt64(kPrefsManifestSignatureSize,
1145                                        &manifest_signature_size) &&
1146       manifest_signature_size != -1 &&
1147       system_state_->prefs()->GetInt64(kPrefsUpdateStateNextDataOffset,
1148                                        &next_data_offset) &&
1149       next_data_offset != -1 &&
1150       system_state_->prefs()->GetInt64(kPrefsUpdateStateNextDataLength,
1151                                        &next_data_length)) {
1152     minimum_size = manifest_metadata_size + manifest_signature_size +
1153                    next_data_offset + next_data_length;
1154   }
1155 
1156   // TODO(senj): Fix P2P for multiple package.
1157   brillo::Blob raw_hash;
1158   if (!base::HexStringToBytes(response.packages[0].hash, &raw_hash))
1159     return;
1160   string file_id =
1161       utils::CalculateP2PFileId(raw_hash, response.packages[0].size);
1162   if (system_state_->p2p_manager()) {
1163     LOG(INFO) << "Checking if payload is available via p2p, file_id=" << file_id
1164               << " minimum_size=" << minimum_size;
1165     system_state_->p2p_manager()->LookupUrlForFile(
1166         file_id,
1167         minimum_size,
1168         TimeDelta::FromSeconds(kMaxP2PNetworkWaitTimeSeconds),
1169         base::Bind(&OmahaRequestAction::OnLookupPayloadViaP2PCompleted,
1170                    base::Unretained(this)));
1171   }
1172 }
1173 
ShouldDeferDownload(OmahaResponse * output_object)1174 bool OmahaRequestAction::ShouldDeferDownload(OmahaResponse* output_object) {
1175   if (params_->interactive()) {
1176     LOG(INFO) << "Not deferring download because update is interactive.";
1177     return false;
1178   }
1179 
1180   // If we're using p2p to download _and_ we have a p2p URL, we never
1181   // defer the download. This is because the download will always
1182   // happen from a peer on the LAN and we've been waiting in line for
1183   // our turn.
1184   const PayloadStateInterface* payload_state = system_state_->payload_state();
1185   if (payload_state->GetUsingP2PForDownloading() &&
1186       !payload_state->GetP2PUrl().empty()) {
1187     LOG(INFO) << "Download not deferred because download "
1188               << "will happen from a local peer (via p2p).";
1189     return false;
1190   }
1191 
1192   // We should defer the downloads only if we've first satisfied the
1193   // wall-clock-based-waiting period and then the update-check-based waiting
1194   // period, if required.
1195   if (!params_->wall_clock_based_wait_enabled()) {
1196     LOG(INFO) << "Wall-clock-based waiting period is not enabled,"
1197               << " so no deferring needed.";
1198     return false;
1199   }
1200 
1201   switch (IsWallClockBasedWaitingSatisfied(output_object)) {
1202     case kWallClockWaitNotSatisfied:
1203       // We haven't even satisfied the first condition, passing the
1204       // wall-clock-based waiting period, so we should defer the downloads
1205       // until that happens.
1206       LOG(INFO) << "wall-clock-based-wait not satisfied.";
1207       return true;
1208 
1209     case kWallClockWaitDoneButUpdateCheckWaitRequired:
1210       LOG(INFO) << "wall-clock-based-wait satisfied and "
1211                 << "update-check-based-wait required.";
1212       return !IsUpdateCheckCountBasedWaitingSatisfied();
1213 
1214     case kWallClockWaitDoneAndUpdateCheckWaitNotRequired:
1215       // Wall-clock-based waiting period is satisfied, and it's determined
1216       // that we do not need the update-check-based wait. so no need to
1217       // defer downloads.
1218       LOG(INFO) << "wall-clock-based-wait satisfied and "
1219                 << "update-check-based-wait is not required.";
1220       return false;
1221 
1222     default:
1223       // Returning false for this default case so we err on the
1224       // side of downloading updates than deferring in case of any bugs.
1225       NOTREACHED();
1226       return false;
1227   }
1228 }
1229 
1230 OmahaRequestAction::WallClockWaitResult
IsWallClockBasedWaitingSatisfied(OmahaResponse * output_object)1231 OmahaRequestAction::IsWallClockBasedWaitingSatisfied(
1232     OmahaResponse* output_object) {
1233   Time update_first_seen_at = LoadOrPersistUpdateFirstSeenAtPref();
1234   if (update_first_seen_at == base::Time()) {
1235     LOG(INFO) << "Not scattering as UpdateFirstSeenAt value cannot be read or "
1236                  "persisted";
1237     return kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
1238   }
1239 
1240   TimeDelta elapsed_time =
1241       system_state_->clock()->GetWallclockTime() - update_first_seen_at;
1242   TimeDelta max_scatter_period =
1243       TimeDelta::FromDays(output_object->max_days_to_scatter);
1244   int64_t staging_wait_time_in_days = 0;
1245   // Use staging and its default max value if staging is on.
1246   if (system_state_->prefs()->GetInt64(kPrefsWallClockStagingWaitPeriod,
1247                                        &staging_wait_time_in_days) &&
1248       staging_wait_time_in_days > 0)
1249     max_scatter_period = TimeDelta::FromDays(kMaxWaitTimeStagingInDays);
1250 
1251   LOG(INFO) << "Waiting Period = "
1252             << utils::FormatSecs(params_->waiting_period().InSeconds())
1253             << ", Time Elapsed = "
1254             << utils::FormatSecs(elapsed_time.InSeconds())
1255             << ", MaxDaysToScatter = " << max_scatter_period.InDays();
1256 
1257   if (!output_object->deadline.empty()) {
1258     // The deadline is set for all rules which serve a delta update from a
1259     // previous FSI, which means this update will be applied mostly in OOBE
1260     // cases. For these cases, we shouldn't scatter so as to finish the OOBE
1261     // quickly.
1262     LOG(INFO) << "Not scattering as deadline flag is set";
1263     return kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
1264   }
1265 
1266   if (max_scatter_period.InDays() == 0) {
1267     // This means the Omaha rule creator decides that this rule
1268     // should not be scattered irrespective of the policy.
1269     LOG(INFO) << "Not scattering as MaxDaysToScatter in rule is 0.";
1270     return kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
1271   }
1272 
1273   if (elapsed_time > max_scatter_period) {
1274     // This means we've waited more than the upperbound wait in the rule
1275     // from the time we first saw a valid update available to us.
1276     // This will prevent update starvation.
1277     LOG(INFO) << "Not scattering as we're past the MaxDaysToScatter limit.";
1278     return kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
1279   }
1280 
1281   // This means we are required to participate in scattering.
1282   // See if our turn has arrived now.
1283   TimeDelta remaining_wait_time = params_->waiting_period() - elapsed_time;
1284   if (remaining_wait_time.InSeconds() <= 0) {
1285     // Yes, it's our turn now.
1286     LOG(INFO) << "Successfully passed the wall-clock-based-wait.";
1287 
1288     // But we can't download until the update-check-count-based wait is also
1289     // satisfied, so mark it as required now if update checks are enabled.
1290     return params_->update_check_count_wait_enabled()
1291                ? kWallClockWaitDoneButUpdateCheckWaitRequired
1292                : kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
1293   }
1294 
1295   // Not our turn yet, so we have to wait until our turn to
1296   // help scatter the downloads across all clients of the enterprise.
1297   LOG(INFO) << "Update deferred for another "
1298             << utils::FormatSecs(remaining_wait_time.InSeconds())
1299             << " per policy.";
1300   return kWallClockWaitNotSatisfied;
1301 }
1302 
IsUpdateCheckCountBasedWaitingSatisfied()1303 bool OmahaRequestAction::IsUpdateCheckCountBasedWaitingSatisfied() {
1304   int64_t update_check_count_value;
1305 
1306   if (system_state_->prefs()->Exists(kPrefsUpdateCheckCount)) {
1307     if (!system_state_->prefs()->GetInt64(kPrefsUpdateCheckCount,
1308                                           &update_check_count_value)) {
1309       // We are unable to read the update check count from file for some reason.
1310       // So let's proceed anyway so as to not stall the update.
1311       LOG(ERROR) << "Unable to read update check count. "
1312                  << "Skipping update-check-count-based-wait.";
1313       return true;
1314     }
1315   } else {
1316     // This file does not exist. This means we haven't started our update
1317     // check count down yet, so this is the right time to start the count down.
1318     update_check_count_value =
1319         base::RandInt(params_->min_update_checks_needed(),
1320                       params_->max_update_checks_allowed());
1321 
1322     LOG(INFO) << "Randomly picked update check count value = "
1323               << update_check_count_value;
1324 
1325     // Write out the initial value of update_check_count_value.
1326     if (!system_state_->prefs()->SetInt64(kPrefsUpdateCheckCount,
1327                                           update_check_count_value)) {
1328       // We weren't able to write the update check count file for some reason.
1329       // So let's proceed anyway so as to not stall the update.
1330       LOG(ERROR) << "Unable to write update check count. "
1331                  << "Skipping update-check-count-based-wait.";
1332       return true;
1333     }
1334   }
1335 
1336   if (update_check_count_value == 0) {
1337     LOG(INFO) << "Successfully passed the update-check-based-wait.";
1338     return true;
1339   }
1340 
1341   if (update_check_count_value < 0 ||
1342       update_check_count_value > params_->max_update_checks_allowed()) {
1343     // We err on the side of skipping scattering logic instead of stalling
1344     // a machine from receiving any updates in case of any unexpected state.
1345     LOG(ERROR) << "Invalid value for update check count detected. "
1346                << "Skipping update-check-count-based-wait.";
1347     return true;
1348   }
1349 
1350   // Legal value, we need to wait for more update checks to happen
1351   // until this becomes 0.
1352   LOG(INFO) << "Deferring Omaha updates for another "
1353             << update_check_count_value << " update checks per policy";
1354   return false;
1355 }
1356 
1357 // static
ParseInstallDate(OmahaParserData * parser_data,OmahaResponse * output_object)1358 bool OmahaRequestAction::ParseInstallDate(OmahaParserData* parser_data,
1359                                           OmahaResponse* output_object) {
1360   int64_t elapsed_days = 0;
1361   if (!base::StringToInt64(parser_data->daystart_elapsed_days, &elapsed_days))
1362     return false;
1363 
1364   if (elapsed_days < 0)
1365     return false;
1366 
1367   output_object->install_date_days = elapsed_days;
1368   return true;
1369 }
1370 
1371 // static
HasInstallDate(SystemState * system_state)1372 bool OmahaRequestAction::HasInstallDate(SystemState* system_state) {
1373   PrefsInterface* prefs = system_state->prefs();
1374   if (prefs == nullptr)
1375     return false;
1376 
1377   return prefs->Exists(kPrefsInstallDateDays);
1378 }
1379 
1380 // static
PersistInstallDate(SystemState * system_state,int install_date_days,InstallDateProvisioningSource source)1381 bool OmahaRequestAction::PersistInstallDate(
1382     SystemState* system_state,
1383     int install_date_days,
1384     InstallDateProvisioningSource source) {
1385   TEST_AND_RETURN_FALSE(install_date_days >= 0);
1386 
1387   PrefsInterface* prefs = system_state->prefs();
1388   if (prefs == nullptr)
1389     return false;
1390 
1391   if (!prefs->SetInt64(kPrefsInstallDateDays, install_date_days))
1392     return false;
1393 
1394   system_state->metrics_reporter()->ReportInstallDateProvisioningSource(
1395       static_cast<int>(source),  // Sample.
1396       kProvisionedMax);          // Maximum.
1397   return true;
1398 }
1399 
PersistCohortData(const string & prefs_key,const string & new_value)1400 bool OmahaRequestAction::PersistCohortData(const string& prefs_key,
1401                                            const string& new_value) {
1402   if (new_value.empty() && system_state_->prefs()->Exists(prefs_key)) {
1403     LOG(INFO) << "Removing stored " << prefs_key << " value.";
1404     return system_state_->prefs()->Delete(prefs_key);
1405   } else if (!new_value.empty()) {
1406     LOG(INFO) << "Storing new setting " << prefs_key << " as " << new_value;
1407     return system_state_->prefs()->SetString(prefs_key, new_value);
1408   }
1409   return true;
1410 }
1411 
PersistEolInfo(const map<string,string> & attrs)1412 bool OmahaRequestAction::PersistEolInfo(const map<string, string>& attrs) {
1413   // If EOL date attribute is not sent, don't delete the old persisted EOL
1414   // date information.
1415   auto eol_date_attr = attrs.find(kAttrEolDate);
1416   if (eol_date_attr != attrs.end()) {
1417     const auto& eol_date = eol_date_attr->second;
1418     if (!system_state_->prefs()->SetString(kPrefsOmahaEolDate, eol_date)) {
1419       LOG(ERROR) << "Setting EOL date failed.";
1420       return false;
1421     }
1422     LOG(INFO) << "Set EOL date to " << eol_date;
1423   }
1424   return true;
1425 }
1426 
ActionCompleted(ErrorCode code)1427 void OmahaRequestAction::ActionCompleted(ErrorCode code) {
1428   // We only want to report this on "update check".
1429   if (ping_only_ || event_ != nullptr)
1430     return;
1431 
1432   metrics::CheckResult result = metrics::CheckResult::kUnset;
1433   metrics::CheckReaction reaction = metrics::CheckReaction::kUnset;
1434   metrics::DownloadErrorCode download_error_code =
1435       metrics::DownloadErrorCode::kUnset;
1436 
1437   // Regular update attempt.
1438   switch (code) {
1439     case ErrorCode::kSuccess:
1440       // OK, we parsed the response successfully but that does
1441       // necessarily mean that an update is available.
1442       if (HasOutputPipe()) {
1443         const OmahaResponse& response = GetOutputObject();
1444         if (response.update_exists) {
1445           result = metrics::CheckResult::kUpdateAvailable;
1446           reaction = metrics::CheckReaction::kUpdating;
1447         } else {
1448           result = metrics::CheckResult::kNoUpdateAvailable;
1449         }
1450       } else {
1451         result = metrics::CheckResult::kNoUpdateAvailable;
1452       }
1453       break;
1454 
1455     case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
1456     case ErrorCode::kOmahaUpdateIgnoredOverCellular:
1457       result = metrics::CheckResult::kUpdateAvailable;
1458       reaction = metrics::CheckReaction::kIgnored;
1459       break;
1460 
1461     case ErrorCode::kOmahaUpdateDeferredPerPolicy:
1462       result = metrics::CheckResult::kUpdateAvailable;
1463       reaction = metrics::CheckReaction::kDeferring;
1464       break;
1465 
1466     case ErrorCode::kOmahaUpdateDeferredForBackoff:
1467       result = metrics::CheckResult::kUpdateAvailable;
1468       reaction = metrics::CheckReaction::kBackingOff;
1469       break;
1470 
1471     default:
1472       // We report two flavors of errors, "Download errors" and "Parsing
1473       // error". Try to convert to the former and if that doesn't work
1474       // we know it's the latter.
1475       metrics::DownloadErrorCode tmp_error =
1476           metrics_utils::GetDownloadErrorCode(code);
1477       if (tmp_error != metrics::DownloadErrorCode::kInputMalformed) {
1478         result = metrics::CheckResult::kDownloadError;
1479         download_error_code = tmp_error;
1480       } else {
1481         result = metrics::CheckResult::kParsingError;
1482       }
1483       break;
1484   }
1485 
1486   system_state_->metrics_reporter()->ReportUpdateCheckMetrics(
1487       system_state_, result, reaction, download_error_code);
1488 }
1489 
ShouldIgnoreUpdate(const OmahaResponse & response,ErrorCode * error) const1490 bool OmahaRequestAction::ShouldIgnoreUpdate(const OmahaResponse& response,
1491                                             ErrorCode* error) const {
1492   // Note: policy decision to not update to a version we rolled back from.
1493   string rollback_version =
1494       system_state_->payload_state()->GetRollbackVersion();
1495   if (!rollback_version.empty()) {
1496     LOG(INFO) << "Detected previous rollback from version " << rollback_version;
1497     if (rollback_version == response.version) {
1498       LOG(INFO) << "Received version that we rolled back from. Ignoring.";
1499       *error = ErrorCode::kOmahaUpdateIgnoredPerPolicy;
1500       return true;
1501     }
1502   }
1503 
1504   if (system_state_->hardware()->IsOOBEEnabled() &&
1505       !system_state_->hardware()->IsOOBEComplete(nullptr) &&
1506       (response.deadline.empty() ||
1507        system_state_->payload_state()->GetRollbackHappened()) &&
1508       params_->app_version() != "ForcedUpdate") {
1509     LOG(INFO) << "Ignoring a non-critical Omaha update before OOBE completion.";
1510     *error = ErrorCode::kNonCriticalUpdateInOOBE;
1511     return true;
1512   }
1513 
1514   if (!IsUpdateAllowedOverCurrentConnection(error, response)) {
1515     LOG(INFO) << "Update is not allowed over current connection.";
1516     return true;
1517   }
1518 
1519   // Currently non-critical updates always update alongside the platform update
1520   // (a critical update) so this case should never actually be hit if the
1521   // request to Omaha for updates are correct. In other words, stop the update
1522   // from happening as there are no packages in the response to process.
1523   if (response.packages.empty()) {
1524     LOG(ERROR) << "All packages were excluded.";
1525   }
1526 
1527   // Note: We could technically delete the UpdateFirstSeenAt state when we
1528   // return true. If we do, it'll mean a device has to restart the
1529   // UpdateFirstSeenAt and thus help scattering take effect when the AU is
1530   // turned on again. On the other hand, it also increases the chance of update
1531   // starvation if an admin turns AU on/off more frequently. We choose to err on
1532   // the side of preventing starvation at the cost of not applying scattering in
1533   // those cases.
1534   return false;
1535 }
1536 
IsUpdateAllowedOverCellularByPrefs(const OmahaResponse & response) const1537 bool OmahaRequestAction::IsUpdateAllowedOverCellularByPrefs(
1538     const OmahaResponse& response) const {
1539   PrefsInterface* prefs = system_state_->prefs();
1540 
1541   if (!prefs) {
1542     LOG(INFO) << "Disabling updates over cellular as the preferences are "
1543                  "not available.";
1544     return false;
1545   }
1546 
1547   bool is_allowed;
1548 
1549   if (prefs->Exists(kPrefsUpdateOverCellularPermission) &&
1550       prefs->GetBoolean(kPrefsUpdateOverCellularPermission, &is_allowed) &&
1551       is_allowed) {
1552     LOG(INFO) << "Allowing updates over cellular as permission preference is "
1553                  "set to true.";
1554     return true;
1555   }
1556 
1557   if (!prefs->Exists(kPrefsUpdateOverCellularTargetVersion) ||
1558       !prefs->Exists(kPrefsUpdateOverCellularTargetSize)) {
1559     LOG(INFO) << "Disabling updates over cellular as permission preference is "
1560                  "set to false or does not exist while target does not exist.";
1561     return false;
1562   }
1563 
1564   std::string target_version;
1565   int64_t target_size;
1566 
1567   if (!prefs->GetString(kPrefsUpdateOverCellularTargetVersion,
1568                         &target_version) ||
1569       !prefs->GetInt64(kPrefsUpdateOverCellularTargetSize, &target_size)) {
1570     LOG(INFO) << "Disabling updates over cellular as the target version or "
1571                  "size is not accessible.";
1572     return false;
1573   }
1574 
1575   uint64_t total_packages_size = 0;
1576   for (const auto& package : response.packages) {
1577     total_packages_size += package.size;
1578   }
1579   if (target_version == response.version &&
1580       static_cast<uint64_t>(target_size) == total_packages_size) {
1581     LOG(INFO) << "Allowing updates over cellular as the target matches the"
1582                  "omaha response.";
1583     return true;
1584   } else {
1585     LOG(INFO) << "Disabling updates over cellular as the target does not"
1586                  "match the omaha response.";
1587     return false;
1588   }
1589 }
1590 
IsUpdateAllowedOverCurrentConnection(ErrorCode * error,const OmahaResponse & response) const1591 bool OmahaRequestAction::IsUpdateAllowedOverCurrentConnection(
1592     ErrorCode* error, const OmahaResponse& response) const {
1593   ConnectionType type;
1594   ConnectionTethering tethering;
1595   ConnectionManagerInterface* connection_manager =
1596       system_state_->connection_manager();
1597   if (!connection_manager->GetConnectionProperties(&type, &tethering)) {
1598     LOG(INFO) << "We could not determine our connection type. "
1599               << "Defaulting to allow updates.";
1600     return true;
1601   }
1602 
1603   bool is_allowed = connection_manager->IsUpdateAllowedOver(type, tethering);
1604   bool is_device_policy_set =
1605       connection_manager->IsAllowedConnectionTypesForUpdateSet();
1606   // Treats tethered connection as if it is cellular connection.
1607   bool is_over_cellular = type == ConnectionType::kCellular ||
1608                           tethering == ConnectionTethering::kConfirmed;
1609 
1610   if (!is_over_cellular) {
1611     // There's no need to further check user preferences as we are not over
1612     // cellular connection.
1613     if (!is_allowed)
1614       *error = ErrorCode::kOmahaUpdateIgnoredPerPolicy;
1615   } else if (is_device_policy_set) {
1616     // There's no need to further check user preferences as the device policy
1617     // is set regarding updates over cellular.
1618     if (!is_allowed)
1619       *error = ErrorCode::kOmahaUpdateIgnoredPerPolicy;
1620   } else {
1621     // Deivce policy is not set, so user preferences overwrite whether to
1622     // allow updates over cellular.
1623     is_allowed = IsUpdateAllowedOverCellularByPrefs(response);
1624     if (!is_allowed)
1625       *error = ErrorCode::kOmahaUpdateIgnoredOverCellular;
1626   }
1627 
1628   LOG(INFO) << "We are connected via "
1629             << connection_utils::StringForConnectionType(type)
1630             << ", Updates allowed: " << (is_allowed ? "Yes" : "No");
1631   return is_allowed;
1632 }
1633 
IsRollbackEnabled() const1634 bool OmahaRequestAction::IsRollbackEnabled() const {
1635   if (policy_provider_->IsConsumerDevice()) {
1636     LOG(INFO) << "Rollback is not enabled for consumer devices.";
1637     return false;
1638   }
1639 
1640   if (!policy_provider_->device_policy_is_loaded()) {
1641     LOG(INFO) << "No device policy is loaded. Assuming rollback enabled.";
1642     return true;
1643   }
1644 
1645   int allowed_milestones;
1646   if (!policy_provider_->GetDevicePolicy().GetRollbackAllowedMilestones(
1647           &allowed_milestones)) {
1648     LOG(INFO) << "RollbackAllowedMilestones policy can't be read. "
1649                  "Defaulting to rollback enabled.";
1650     return true;
1651   }
1652 
1653   LOG(INFO) << "Rollback allows " << allowed_milestones << " milestones.";
1654   return allowed_milestones > 0;
1655 }
1656 
SetMaxKernelKeyVersionForRollback() const1657 void OmahaRequestAction::SetMaxKernelKeyVersionForRollback() const {
1658   int max_kernel_rollforward;
1659   int min_kernel_version = system_state_->hardware()->GetMinKernelKeyVersion();
1660   if (IsRollbackEnabled()) {
1661     // If rollback is enabled, set the max kernel key version to the current
1662     // kernel key version. This has the effect of freezing kernel key roll
1663     // forwards.
1664     //
1665     // TODO(zentaro): This behavior is temporary, and ensures that no kernel
1666     // key roll forward happens until the server side components of rollback
1667     // are implemented. Future changes will allow the Omaha server to return
1668     // the kernel key version from max_rollback_versions in the past. At that
1669     // point the max kernel key version will be set to that value, creating a
1670     // sliding window of versions that can be rolled back to.
1671     LOG(INFO) << "Rollback is enabled. Setting kernel_max_rollforward to "
1672               << min_kernel_version;
1673     max_kernel_rollforward = min_kernel_version;
1674   } else {
1675     // For devices that are not rollback enabled (ie. consumer devices), the
1676     // max kernel key version is set to 0xfffffffe, which is logically
1677     // infinity. This maintains the previous behavior that that kernel key
1678     // versions roll forward each time they are incremented.
1679     LOG(INFO) << "Rollback is disabled. Setting kernel_max_rollforward to "
1680               << kRollforwardInfinity;
1681     max_kernel_rollforward = kRollforwardInfinity;
1682   }
1683 
1684   bool max_rollforward_set =
1685       system_state_->hardware()->SetMaxKernelKeyRollforward(
1686           max_kernel_rollforward);
1687   if (!max_rollforward_set) {
1688     LOG(ERROR) << "Failed to set kernel_max_rollforward";
1689   }
1690   // Report metrics
1691   system_state_->metrics_reporter()->ReportKeyVersionMetrics(
1692       min_kernel_version, max_kernel_rollforward, max_rollforward_set);
1693 }
1694 
LoadOrPersistUpdateFirstSeenAtPref() const1695 base::Time OmahaRequestAction::LoadOrPersistUpdateFirstSeenAtPref() const {
1696   Time update_first_seen_at;
1697   int64_t update_first_seen_at_int;
1698   if (system_state_->prefs()->Exists(kPrefsUpdateFirstSeenAt)) {
1699     if (system_state_->prefs()->GetInt64(kPrefsUpdateFirstSeenAt,
1700                                          &update_first_seen_at_int)) {
1701       // Note: This timestamp could be that of ANY update we saw in the past
1702       // (not necessarily this particular update we're considering to apply)
1703       // but never got to apply because of some reason (e.g. stop AU policy,
1704       // updates being pulled out from Omaha, changes in target version prefix,
1705       // new update being rolled out, etc.). But for the purposes of scattering
1706       // it doesn't matter which update the timestamp corresponds to. i.e.
1707       // the clock starts ticking the first time we see an update and we're
1708       // ready to apply when the random wait period is satisfied relative to
1709       // that first seen timestamp.
1710       update_first_seen_at = Time::FromInternalValue(update_first_seen_at_int);
1711       LOG(INFO) << "Using persisted value of UpdateFirstSeenAt: "
1712                 << utils::ToString(update_first_seen_at);
1713     } else {
1714       // This seems like an unexpected error where the persisted value exists
1715       // but it's not readable for some reason.
1716       LOG(INFO) << "UpdateFirstSeenAt value cannot be read";
1717       return base::Time();
1718     }
1719   } else {
1720     update_first_seen_at = system_state_->clock()->GetWallclockTime();
1721     update_first_seen_at_int = update_first_seen_at.ToInternalValue();
1722     if (system_state_->prefs()->SetInt64(kPrefsUpdateFirstSeenAt,
1723                                          update_first_seen_at_int)) {
1724       LOG(INFO) << "Persisted the new value for UpdateFirstSeenAt: "
1725                 << utils::ToString(update_first_seen_at);
1726     } else {
1727       // This seems like an unexpected error where the value cannot be
1728       // persisted for some reason.
1729       LOG(INFO) << "UpdateFirstSeenAt value "
1730                 << utils::ToString(update_first_seen_at)
1731                 << " cannot be persisted";
1732       return base::Time();
1733     }
1734   }
1735   return update_first_seen_at;
1736 }
1737 
1738 }  // namespace chromeos_update_engine
1739