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