| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 1 | // | 
 | 2 | // Copyright (C) 2019 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 |  | 
| Amin Hassani | ec7bc11 | 2020-10-29 16:47:58 -0700 | [diff] [blame] | 17 | #include "update_engine/cros/omaha_request_builder_xml.h" | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 18 |  | 
 | 19 | #include <inttypes.h> | 
 | 20 |  | 
 | 21 | #include <string> | 
 | 22 |  | 
| Jae Hoon Kim | 6ada591 | 2019-06-14 10:11:34 -0700 | [diff] [blame] | 23 | #include <base/guid.h> | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 24 | #include <base/logging.h> | 
 | 25 | #include <base/strings/string_number_conversions.h> | 
 | 26 | #include <base/strings/string_util.h> | 
 | 27 | #include <base/strings/stringprintf.h> | 
 | 28 | #include <base/time/time.h> | 
 | 29 |  | 
 | 30 | #include "update_engine/common/constants.h" | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 31 | #include "update_engine/common/system_state.h" | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 32 | #include "update_engine/common/utils.h" | 
| Amin Hassani | ec7bc11 | 2020-10-29 16:47:58 -0700 | [diff] [blame] | 33 | #include "update_engine/cros/omaha_request_params.h" | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 34 |  | 
 | 35 | using std::string; | 
 | 36 |  | 
 | 37 | namespace chromeos_update_engine { | 
 | 38 |  | 
| Jae Hoon Kim | 5fc00a2 | 2020-01-08 20:15:42 -0800 | [diff] [blame] | 39 | const char kNoVersion[] = "0.0.0.0"; | 
| Andrew | e045aef | 2020-01-08 16:29:22 -0800 | [diff] [blame] | 40 | const int kPingNeverPinged = -1; | 
 | 41 | const int kPingUnknownValue = -2; | 
 | 42 | const int kPingActiveValue = 1; | 
 | 43 | const int kPingInactiveValue = 0; | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 44 |  | 
 | 45 | bool XmlEncode(const string& input, string* output) { | 
 | 46 |   if (std::find_if(input.begin(), input.end(), [](const char c) { | 
 | 47 |         return c & 0x80; | 
 | 48 |       }) != input.end()) { | 
 | 49 |     LOG(WARNING) << "Invalid ASCII-7 string passed to the XML encoder:"; | 
 | 50 |     utils::HexDumpString(input); | 
 | 51 |     return false; | 
 | 52 |   } | 
 | 53 |   output->clear(); | 
 | 54 |   // We need at least input.size() space in the output, but the code below will | 
 | 55 |   // handle it if we need more. | 
 | 56 |   output->reserve(input.size()); | 
 | 57 |   for (char c : input) { | 
 | 58 |     switch (c) { | 
 | 59 |       case '\"': | 
 | 60 |         output->append("""); | 
 | 61 |         break; | 
 | 62 |       case '\'': | 
 | 63 |         output->append("'"); | 
 | 64 |         break; | 
 | 65 |       case '&': | 
 | 66 |         output->append("&"); | 
 | 67 |         break; | 
 | 68 |       case '<': | 
 | 69 |         output->append("<"); | 
 | 70 |         break; | 
 | 71 |       case '>': | 
 | 72 |         output->append(">"); | 
 | 73 |         break; | 
 | 74 |       default: | 
 | 75 |         output->push_back(c); | 
 | 76 |     } | 
 | 77 |   } | 
 | 78 |   return true; | 
 | 79 | } | 
 | 80 |  | 
 | 81 | string XmlEncodeWithDefault(const string& input, const string& default_value) { | 
 | 82 |   string output; | 
 | 83 |   if (XmlEncode(input, &output)) | 
 | 84 |     return output; | 
 | 85 |   return default_value; | 
 | 86 | } | 
 | 87 |  | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 88 | string OmahaRequestBuilderXml::GetPing() const { | 
 | 89 |   // Returns an XML ping element attribute assignment with attribute | 
 | 90 |   // |name| and value |ping_days| if |ping_days| has a value that needs | 
 | 91 |   // to be sent, or an empty string otherwise. | 
 | 92 |   auto GetPingAttribute = [](const char* name, int ping_days) -> string { | 
| Andrew | e045aef | 2020-01-08 16:29:22 -0800 | [diff] [blame] | 93 |     if (ping_days > 0 || ping_days == kPingNeverPinged) | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 94 |       return base::StringPrintf(" %s=\"%d\"", name, ping_days); | 
 | 95 |     return ""; | 
 | 96 |   }; | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 97 |  | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 98 |   string ping_active = GetPingAttribute("a", ping_active_days_); | 
 | 99 |   string ping_roll_call = GetPingAttribute("r", ping_roll_call_days_); | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 100 |   if (!ping_active.empty() || !ping_roll_call.empty()) { | 
 | 101 |     return base::StringPrintf("        <ping active=\"1\"%s%s></ping>\n", | 
 | 102 |                               ping_active.c_str(), | 
 | 103 |                               ping_roll_call.c_str()); | 
 | 104 |   } | 
 | 105 |   return ""; | 
 | 106 | } | 
 | 107 |  | 
| Andrew | e045aef | 2020-01-08 16:29:22 -0800 | [diff] [blame] | 108 | string OmahaRequestBuilderXml::GetPingDateBased( | 
 | 109 |     const OmahaRequestParams::AppParams& app_params) const { | 
 | 110 |   if (!app_params.send_ping) | 
 | 111 |     return ""; | 
 | 112 |   string ping_active = ""; | 
 | 113 |   string ping_ad = ""; | 
 | 114 |   if (app_params.ping_active == kPingActiveValue) { | 
 | 115 |     ping_active = | 
 | 116 |         base::StringPrintf(" active=\"%" PRId64 "\"", app_params.ping_active); | 
 | 117 |     ping_ad = base::StringPrintf(" ad=\"%" PRId64 "\"", | 
 | 118 |                                  app_params.ping_date_last_active); | 
 | 119 |   } | 
 | 120 |  | 
 | 121 |   string ping_rd = base::StringPrintf(" rd=\"%" PRId64 "\"", | 
 | 122 |                                       app_params.ping_date_last_rollcall); | 
 | 123 |  | 
 | 124 |   return base::StringPrintf("        <ping%s%s%s></ping>\n", | 
 | 125 |                             ping_active.c_str(), | 
 | 126 |                             ping_ad.c_str(), | 
 | 127 |                             ping_rd.c_str()); | 
 | 128 | } | 
 | 129 |  | 
 | 130 | string OmahaRequestBuilderXml::GetAppBody(const OmahaAppData& app_data) const { | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 131 |   string app_body; | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 132 |   if (event_ == nullptr) { | 
| Andrew | e045aef | 2020-01-08 16:29:22 -0800 | [diff] [blame] | 133 |     if (app_data.app_params.send_ping) { | 
 | 134 |       switch (app_data.app_params.active_counting_type) { | 
 | 135 |         case OmahaRequestParams::kDayBased: | 
 | 136 |           app_body = GetPing(); | 
 | 137 |           break; | 
 | 138 |         case OmahaRequestParams::kDateBased: | 
 | 139 |           app_body = GetPingDateBased(app_data.app_params); | 
 | 140 |           break; | 
 | 141 |         default: | 
 | 142 |           NOTREACHED(); | 
 | 143 |       } | 
 | 144 |     } | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 145 |     if (!ping_only_) { | 
| Andrew | e045aef | 2020-01-08 16:29:22 -0800 | [diff] [blame] | 146 |       if (!app_data.skip_update) { | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 147 |         const auto* params = SystemState::Get()->request_params(); | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 148 |         app_body += "        <updatecheck"; | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 149 |         if (!params->target_version_prefix().empty()) { | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 150 |           app_body += base::StringPrintf( | 
 | 151 |               " targetversionprefix=\"%s\"", | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 152 |               XmlEncodeWithDefault(params->target_version_prefix()).c_str()); | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 153 |           // Rollback requires target_version_prefix set. | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 154 |           if (params->rollback_allowed()) { | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 155 |             app_body += " rollback_allowed=\"true\""; | 
 | 156 |           } | 
 | 157 |         } | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 158 |         if (!params->lts_tag().empty()) { | 
| Amin Hassani | 37b6723 | 2020-08-13 09:29:48 -0700 | [diff] [blame] | 159 |           app_body += base::StringPrintf( | 
 | 160 |               " ltstag=\"%s\"", | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 161 |               XmlEncodeWithDefault(params->lts_tag()).c_str()); | 
| Amin Hassani | 37b6723 | 2020-08-13 09:29:48 -0700 | [diff] [blame] | 162 |         } | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 163 |         app_body += "></updatecheck>\n"; | 
 | 164 |       } | 
 | 165 |  | 
 | 166 |       // If this is the first update check after a reboot following a previous | 
 | 167 |       // update, generate an event containing the previous version number. If | 
 | 168 |       // the previous version preference file doesn't exist the event is still | 
 | 169 |       // generated with a previous version of 0.0.0.0 -- this is relevant for | 
 | 170 |       // older clients or new installs. The previous version event is not sent | 
 | 171 |       // for ping-only requests because they come before the client has | 
 | 172 |       // rebooted. The previous version event is also not sent if it was already | 
 | 173 |       // sent for this new version with a previous updatecheck. | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 174 |       auto* prefs = SystemState::Get()->prefs(); | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 175 |       string prev_version; | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 176 |       if (!prefs->GetString(kPrefsPreviousVersion, &prev_version)) { | 
| Jae Hoon Kim | 5fc00a2 | 2020-01-08 20:15:42 -0800 | [diff] [blame] | 177 |         prev_version = kNoVersion; | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 178 |       } | 
 | 179 |       // We only store a non-empty previous version value after a successful | 
 | 180 |       // update in the previous boot. After reporting it back to the server, | 
 | 181 |       // we clear the previous version value so it doesn't get reported again. | 
 | 182 |       if (!prev_version.empty()) { | 
 | 183 |         app_body += base::StringPrintf( | 
 | 184 |             "        <event eventtype=\"%d\" eventresult=\"%d\" " | 
 | 185 |             "previousversion=\"%s\"></event>\n", | 
 | 186 |             OmahaEvent::kTypeRebootedAfterUpdate, | 
 | 187 |             OmahaEvent::kResultSuccess, | 
| Jae Hoon Kim | 5fc00a2 | 2020-01-08 20:15:42 -0800 | [diff] [blame] | 188 |             XmlEncodeWithDefault(prev_version, kNoVersion).c_str()); | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 189 |         LOG_IF(WARNING, !prefs->SetString(kPrefsPreviousVersion, "")) | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 190 |             << "Unable to reset the previous version."; | 
 | 191 |       } | 
 | 192 |     } | 
 | 193 |   } else { | 
| Jae Hoon Kim | 3e69b4c | 2020-06-16 09:23:39 -0700 | [diff] [blame] | 194 |     int event_result = event_->result; | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 195 |     // The error code is an optional attribute so append it only if the result | 
 | 196 |     // is not success. | 
 | 197 |     string error_code; | 
| Jae Hoon Kim | 3e69b4c | 2020-06-16 09:23:39 -0700 | [diff] [blame] | 198 |     if (event_result != OmahaEvent::kResultSuccess) { | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 199 |       error_code = base::StringPrintf(" errorcode=\"%d\"", | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 200 |                                       static_cast<int>(event_->error_code)); | 
| Jae Hoon Kim | 3e69b4c | 2020-06-16 09:23:39 -0700 | [diff] [blame] | 201 |     } else if (app_data.is_dlc && !app_data.app_params.updated) { | 
 | 202 |       // On a |OmahaEvent::kResultSuccess|, if the event is for an update | 
 | 203 |       // completion and the App is a DLC, send error for excluded DLCs as they | 
 | 204 |       // did not update. | 
 | 205 |       event_result = OmahaEvent::Result::kResultError; | 
 | 206 |       error_code = base::StringPrintf( | 
 | 207 |           " errorcode=\"%d\"", | 
 | 208 |           static_cast<int>(ErrorCode::kPackageExcludedFromUpdate)); | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 209 |     } | 
 | 210 |     app_body = base::StringPrintf( | 
 | 211 |         "        <event eventtype=\"%d\" eventresult=\"%d\"%s></event>\n", | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 212 |         event_->type, | 
| Jae Hoon Kim | 3e69b4c | 2020-06-16 09:23:39 -0700 | [diff] [blame] | 213 |         event_result, | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 214 |         error_code.c_str()); | 
 | 215 |   } | 
 | 216 |  | 
 | 217 |   return app_body; | 
 | 218 | } | 
 | 219 |  | 
| Jae Hoon Kim | e2cac61 | 2020-11-02 18:30:29 -0800 | [diff] [blame] | 220 | string OmahaRequestBuilderXml::GetCohortArg( | 
 | 221 |     const string& arg_name, | 
 | 222 |     const string& prefs_key, | 
 | 223 |     const string& override_value) const { | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 224 |   string cohort_value; | 
| Askar Aitzhan | 18fff84 | 2019-06-21 23:24:37 +0200 | [diff] [blame] | 225 |   if (!override_value.empty()) { | 
 | 226 |     // |override_value| take precedence over pref value. | 
 | 227 |     cohort_value = override_value; | 
 | 228 |   } else { | 
 | 229 |     // There's nothing wrong with not having a given cohort setting, so we check | 
 | 230 |     // existence first to avoid the warning log message. | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 231 |     const auto* prefs = SystemState::Get()->prefs(); | 
 | 232 |     if (!prefs->Exists(prefs_key)) | 
| Askar Aitzhan | 18fff84 | 2019-06-21 23:24:37 +0200 | [diff] [blame] | 233 |       return ""; | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 234 |     if (!prefs->GetString(prefs_key, &cohort_value) || cohort_value.empty()) | 
| Askar Aitzhan | 18fff84 | 2019-06-21 23:24:37 +0200 | [diff] [blame] | 235 |       return ""; | 
 | 236 |   } | 
| Kelvin Zhang | ebd5e25 | 2020-07-22 18:27:06 -0400 | [diff] [blame] | 237 |   // This is a validity check to avoid sending a huge XML file back to Ohama due | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 238 |   // to a compromised stateful partition making the update check fail in low | 
 | 239 |   // network environments envent after a reboot. | 
 | 240 |   if (cohort_value.size() > 1024) { | 
 | 241 |     LOG(WARNING) << "The omaha cohort setting " << arg_name | 
 | 242 |                  << " has a too big value, which must be an error or an " | 
 | 243 |                     "attacker trying to inhibit updates."; | 
 | 244 |     return ""; | 
 | 245 |   } | 
 | 246 |  | 
 | 247 |   string escaped_xml_value; | 
 | 248 |   if (!XmlEncode(cohort_value, &escaped_xml_value)) { | 
 | 249 |     LOG(WARNING) << "The omaha cohort setting " << arg_name | 
 | 250 |                  << " is ASCII-7 invalid, ignoring it."; | 
 | 251 |     return ""; | 
 | 252 |   } | 
 | 253 |  | 
 | 254 |   return base::StringPrintf( | 
 | 255 |       "%s=\"%s\" ", arg_name.c_str(), escaped_xml_value.c_str()); | 
 | 256 | } | 
 | 257 |  | 
 | 258 | bool IsValidComponentID(const string& id) { | 
 | 259 |   for (char c : id) { | 
 | 260 |     if (!isalnum(c) && c != '-' && c != '_' && c != '.') | 
 | 261 |       return false; | 
 | 262 |   } | 
 | 263 |   return true; | 
 | 264 | } | 
 | 265 |  | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 266 | string OmahaRequestBuilderXml::GetApp(const OmahaAppData& app_data) const { | 
| Andrew | e045aef | 2020-01-08 16:29:22 -0800 | [diff] [blame] | 267 |   string app_body = GetAppBody(app_data); | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 268 |   string app_versions; | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 269 |   const auto* params = SystemState::Get()->request_params(); | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 270 |  | 
 | 271 |   // If we are downgrading to a more stable channel and we are allowed to do | 
 | 272 |   // powerwash, then pass 0.0.0.0 as the version. This is needed to get the | 
 | 273 |   // highest-versioned payload on the destination channel. | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 274 |   if (params->ShouldPowerwash()) { | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 275 |     LOG(INFO) << "Passing OS version as 0.0.0.0 as we are set to powerwash " | 
 | 276 |               << "on downgrading to the version in the more stable channel"; | 
| Jae Hoon Kim | 5fc00a2 | 2020-01-08 20:15:42 -0800 | [diff] [blame] | 277 |     app_versions = "version=\"" + string(kNoVersion) + "\" from_version=\"" + | 
 | 278 |                    XmlEncodeWithDefault(app_data.version, kNoVersion) + "\" "; | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 279 |   } else { | 
 | 280 |     app_versions = "version=\"" + | 
| Jae Hoon Kim | 5fc00a2 | 2020-01-08 20:15:42 -0800 | [diff] [blame] | 281 |                    XmlEncodeWithDefault(app_data.version, kNoVersion) + "\" "; | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 282 |   } | 
 | 283 |  | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 284 |   string download_channel = params->download_channel(); | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 285 |   string app_channels = | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 286 |       "track=\"" + XmlEncodeWithDefault(download_channel) + "\" "; | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 287 |   if (params->current_channel() != download_channel) { | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 288 |     app_channels += "from_track=\"" + | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 289 |                     XmlEncodeWithDefault(params->current_channel()) + "\" "; | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 290 |   } | 
 | 291 |  | 
| Jae Hoon Kim | 5fc00a2 | 2020-01-08 20:15:42 -0800 | [diff] [blame] | 292 |   string delta_okay_str = | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 293 |       params->delta_okay() && !params->is_install() ? "true" : "false"; | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 294 |  | 
 | 295 |   // If install_date_days is not set (e.g. its value is -1 ), don't | 
 | 296 |   // include the attribute. | 
 | 297 |   string install_date_in_days_str = ""; | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 298 |   if (install_date_in_days_ >= 0) { | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 299 |     install_date_in_days_str = | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 300 |         base::StringPrintf("installdate=\"%d\" ", install_date_in_days_); | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 301 |   } | 
 | 302 |  | 
 | 303 |   string app_cohort_args; | 
| Jae Hoon Kim | e2cac61 | 2020-11-02 18:30:29 -0800 | [diff] [blame] | 304 |   string cohort_key = kPrefsOmahaCohort; | 
 | 305 |   string cohortname_key = kPrefsOmahaCohortName; | 
 | 306 |   string cohorthint_key = kPrefsOmahaCohortHint; | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 307 |  | 
| Jae Hoon Kim | e2cac61 | 2020-11-02 18:30:29 -0800 | [diff] [blame] | 308 |   // Override the cohort keys for DLC App IDs. | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 309 |   const auto& dlc_apps_params = params->dlc_apps_params(); | 
| Jae Hoon Kim | e2cac61 | 2020-11-02 18:30:29 -0800 | [diff] [blame] | 310 |   auto itr = dlc_apps_params.find(app_data.id); | 
 | 311 |   if (itr != dlc_apps_params.end()) { | 
 | 312 |     auto dlc_id = itr->second.name; | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 313 |     const auto* prefs = SystemState::Get()->prefs(); | 
| Jae Hoon Kim | e2cac61 | 2020-11-02 18:30:29 -0800 | [diff] [blame] | 314 |     cohort_key = | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 315 |         prefs->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsOmahaCohort}); | 
| Jae Hoon Kim | e2cac61 | 2020-11-02 18:30:29 -0800 | [diff] [blame] | 316 |     cohortname_key = | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 317 |         prefs->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsOmahaCohortName}); | 
| Jae Hoon Kim | e2cac61 | 2020-11-02 18:30:29 -0800 | [diff] [blame] | 318 |     cohorthint_key = | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 319 |         prefs->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsOmahaCohortHint}); | 
| Jae Hoon Kim | e2cac61 | 2020-11-02 18:30:29 -0800 | [diff] [blame] | 320 |   } | 
 | 321 |  | 
 | 322 |   app_cohort_args += GetCohortArg("cohort", cohort_key); | 
 | 323 |   app_cohort_args += GetCohortArg("cohortname", cohortname_key); | 
| Askar Aitzhan | 18fff84 | 2019-06-21 23:24:37 +0200 | [diff] [blame] | 324 |   // Policy provided value overrides pref. | 
| Jae Hoon Kim | e2cac61 | 2020-11-02 18:30:29 -0800 | [diff] [blame] | 325 |   app_cohort_args += | 
 | 326 |       GetCohortArg("cohorthint", | 
 | 327 |                    cohorthint_key, | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 328 |                    params->autoupdate_token() /* override_value */); | 
| Askar Aitzhan | 18fff84 | 2019-06-21 23:24:37 +0200 | [diff] [blame] | 329 |  | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 330 |   string fingerprint_arg; | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 331 |   if (!params->os_build_fingerprint().empty()) { | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 332 |     fingerprint_arg = "fingerprint=\"" + | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 333 |                       XmlEncodeWithDefault(params->os_build_fingerprint()) + | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 334 |                       "\" "; | 
 | 335 |   } | 
 | 336 |  | 
 | 337 |   string buildtype_arg; | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 338 |   if (!params->os_build_type().empty()) { | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 339 |     buildtype_arg = "os_build_type=\"" + | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 340 |                     XmlEncodeWithDefault(params->os_build_type()) + "\" "; | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 341 |   } | 
 | 342 |  | 
 | 343 |   string product_components_args; | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 344 |   if (!params->ShouldPowerwash() && !app_data.product_components.empty()) { | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 345 |     brillo::KeyValueStore store; | 
 | 346 |     if (store.LoadFromString(app_data.product_components)) { | 
 | 347 |       for (const string& key : store.GetKeys()) { | 
 | 348 |         if (!IsValidComponentID(key)) { | 
 | 349 |           LOG(ERROR) << "Invalid component id: " << key; | 
 | 350 |           continue; | 
 | 351 |         } | 
 | 352 |         string version; | 
 | 353 |         if (!store.GetString(key, &version)) { | 
 | 354 |           LOG(ERROR) << "Failed to get version for " << key | 
 | 355 |                      << " in product_components."; | 
 | 356 |           continue; | 
 | 357 |         } | 
 | 358 |         product_components_args += | 
 | 359 |             base::StringPrintf("_%s.version=\"%s\" ", | 
 | 360 |                                key.c_str(), | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 361 |                                XmlEncodeWithDefault(version).c_str()); | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 362 |       } | 
 | 363 |     } else { | 
 | 364 |       LOG(ERROR) << "Failed to parse product_components:\n" | 
 | 365 |                  << app_data.product_components; | 
 | 366 |     } | 
 | 367 |   } | 
 | 368 |  | 
| Matt Ziegelbaum | aa8e1a4 | 2019-05-09 21:41:58 -0400 | [diff] [blame] | 369 |   string requisition_arg; | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 370 |   if (!params->device_requisition().empty()) { | 
| Matt Ziegelbaum | aa8e1a4 | 2019-05-09 21:41:58 -0400 | [diff] [blame] | 371 |     requisition_arg = "requisition=\"" + | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 372 |                       XmlEncodeWithDefault(params->device_requisition()) + | 
| Matt Ziegelbaum | aa8e1a4 | 2019-05-09 21:41:58 -0400 | [diff] [blame] | 373 |                       "\" "; | 
 | 374 |   } | 
 | 375 |  | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 376 |   // clang-format off | 
 | 377 |   string app_xml = "    <app " | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 378 |       "appid=\"" + XmlEncodeWithDefault(app_data.id) + "\" " + | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 379 |       app_cohort_args + | 
 | 380 |       app_versions + | 
 | 381 |       app_channels + | 
 | 382 |       product_components_args + | 
 | 383 |       fingerprint_arg + | 
 | 384 |       buildtype_arg + | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 385 |       "board=\"" + XmlEncodeWithDefault(params->os_board()) + "\" " + | 
 | 386 |       "hardware_class=\"" + XmlEncodeWithDefault(params->hwid()) + "\" " + | 
| Jae Hoon Kim | 37d1537 | 2020-01-08 18:11:26 -0800 | [diff] [blame] | 387 |       "delta_okay=\"" + delta_okay_str + "\" " + | 
 | 388 |       install_date_in_days_str + | 
 | 389 |  | 
 | 390 |       // DLC excluded for installs and updates. | 
 | 391 |       (app_data.is_dlc ? "" : | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 392 |       "lang=\"" + XmlEncodeWithDefault(params->app_lang(), "en-US") + "\" " + | 
| Jae Hoon Kim | 37d1537 | 2020-01-08 18:11:26 -0800 | [diff] [blame] | 393 |       requisition_arg) + | 
 | 394 |  | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 395 |       ">\n" + | 
 | 396 |          app_body + | 
 | 397 |       "    </app>\n"; | 
 | 398 |   // clang-format on | 
 | 399 |   return app_xml; | 
 | 400 | } | 
 | 401 |  | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 402 | string OmahaRequestBuilderXml::GetOs() const { | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 403 |   const auto* params = SystemState::Get()->request_params(); | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 404 |   string os_xml = | 
 | 405 |       "    <os " | 
 | 406 |       "version=\"" + | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 407 |       XmlEncodeWithDefault(params->os_version()) + "\" " + "platform=\"" + | 
 | 408 |       XmlEncodeWithDefault(params->os_platform()) + "\" " + "sp=\"" + | 
 | 409 |       XmlEncodeWithDefault(params->os_sp()) + | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 410 |       "\">" | 
 | 411 |       "</os>\n"; | 
 | 412 |   return os_xml; | 
 | 413 | } | 
 | 414 |  | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 415 | string OmahaRequestBuilderXml::GetRequest() const { | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 416 |   const auto* params = SystemState::Get()->request_params(); | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 417 |   string os_xml = GetOs(); | 
 | 418 |   string app_xml = GetApps(); | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 419 |  | 
 | 420 |   string request_xml = base::StringPrintf( | 
 | 421 |       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" | 
| Jae Hoon Kim | edb6550 | 2019-06-14 11:52:17 -0700 | [diff] [blame] | 422 |       "<request requestid=\"%s\" sessionid=\"%s\"" | 
| Jae Hoon Kim | 6ada591 | 2019-06-14 10:11:34 -0700 | [diff] [blame] | 423 |       " protocol=\"3.0\" updater=\"%s\" updaterversion=\"%s\"" | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 424 |       " installsource=\"%s\" ismachine=\"1\">\n%s%s</request>\n", | 
| Jae Hoon Kim | 6ada591 | 2019-06-14 10:11:34 -0700 | [diff] [blame] | 425 |       base::GenerateGUID().c_str() /* requestid */, | 
| Jae Hoon Kim | edb6550 | 2019-06-14 11:52:17 -0700 | [diff] [blame] | 426 |       session_id_.c_str(), | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 427 |       constants::kOmahaUpdaterID, | 
 | 428 |       kOmahaUpdaterVersion, | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 429 |       params->interactive() ? "ondemandupdate" : "scheduler", | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 430 |       os_xml.c_str(), | 
 | 431 |       app_xml.c_str()); | 
 | 432 |  | 
 | 433 |   return request_xml; | 
 | 434 | } | 
 | 435 |  | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 436 | string OmahaRequestBuilderXml::GetApps() const { | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 437 |   const auto* params = SystemState::Get()->request_params(); | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 438 |   string app_xml = ""; | 
 | 439 |   OmahaAppData product_app = { | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 440 |       .id = params->GetAppId(), | 
 | 441 |       .version = params->app_version(), | 
 | 442 |       .product_components = params->product_components(), | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 443 |       // Skips updatecheck for platform app in case of an install operation. | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 444 |       .skip_update = params->is_install(), | 
| Andrew | e045aef | 2020-01-08 16:29:22 -0800 | [diff] [blame] | 445 |       .is_dlc = false, | 
 | 446 |  | 
 | 447 |       .app_params = {.active_counting_type = OmahaRequestParams::kDayBased, | 
 | 448 |                      .send_ping = include_ping_}}; | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 449 |   app_xml += GetApp(product_app); | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 450 |   for (const auto& it : params->dlc_apps_params()) { | 
| Amin Hassani | 2b68e6b | 2020-04-17 10:49:12 -0700 | [diff] [blame] | 451 |     OmahaAppData dlc_app_data = { | 
| Andrew | e045aef | 2020-01-08 16:29:22 -0800 | [diff] [blame] | 452 |         .id = it.first, | 
| Amin Hassani | 9ed2cee | 2020-11-13 18:40:35 -0800 | [diff] [blame] | 453 |         .version = params->is_install() ? kNoVersion : params->app_version(), | 
| Jae Hoon Kim | 37d1537 | 2020-01-08 18:11:26 -0800 | [diff] [blame] | 454 |         .skip_update = false, | 
| Andrew | e045aef | 2020-01-08 16:29:22 -0800 | [diff] [blame] | 455 |         .is_dlc = true, | 
 | 456 |         .app_params = it.second}; | 
| Amin Hassani | 2b68e6b | 2020-04-17 10:49:12 -0700 | [diff] [blame] | 457 |     app_xml += GetApp(dlc_app_data); | 
| Jae Hoon Kim | b7ee387 | 2019-06-06 14:59:03 -0700 | [diff] [blame] | 458 |   } | 
 | 459 |   return app_xml; | 
 | 460 | } | 
 | 461 |  | 
| Amin Hassani | 7fca286 | 2019-03-28 16:09:22 -0700 | [diff] [blame] | 462 | }  // namespace chromeos_update_engine |