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