1 // 2 // Copyright (C) 2012 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #ifndef UPDATE_ENGINE_OMAHA_REQUEST_ACTION_H_ 18 #define UPDATE_ENGINE_OMAHA_REQUEST_ACTION_H_ 19 20 #include <fcntl.h> 21 #include <sys/stat.h> 22 #include <sys/types.h> 23 24 #include <map> 25 #include <memory> 26 #include <string> 27 #include <vector> 28 29 #include <gtest/gtest_prod.h> // for FRIEND_TEST 30 31 #include <brillo/secure_blob.h> 32 #include <curl/curl.h> 33 34 #include "update_engine/common/action.h" 35 #include "update_engine/common/http_fetcher.h" 36 #include "update_engine/omaha_response.h" 37 #include "update_engine/system_state.h" 38 39 // The Omaha Request action makes a request to Omaha and can output 40 // the response on the output ActionPipe. 41 42 namespace chromeos_update_engine { 43 44 // Encodes XML entities in a given string. Input must be ASCII-7 valid. If 45 // the input is invalid, the default value is used instead. 46 std::string XmlEncodeWithDefault(const std::string& input, 47 const std::string& default_value); 48 49 // Escapes text so it can be included as character data and attribute 50 // values. The |input| string must be valid ASCII-7, no UTF-8 supported. 51 // Returns whether the |input| was valid and escaped properly in |output|. 52 bool XmlEncode(const std::string& input, std::string* output); 53 54 // This struct encapsulates the Omaha event information. For a 55 // complete list of defined event types and results, see 56 // http://code.google.com/p/omaha/wiki/ServerProtocol#event 57 struct OmahaEvent { 58 // The Type values correspond to EVENT_TYPE values of Omaha. 59 enum Type { 60 kTypeUnknown = 0, 61 kTypeDownloadComplete = 1, 62 kTypeInstallComplete = 2, 63 kTypeUpdateComplete = 3, 64 kTypeUpdateDownloadStarted = 13, 65 kTypeUpdateDownloadFinished = 14, 66 // Chromium OS reserved type sent after the first reboot following an update 67 // completed. 68 kTypeRebootedAfterUpdate = 54, 69 }; 70 71 // The Result values correspond to EVENT_RESULT values of Omaha. 72 enum Result { 73 kResultError = 0, 74 kResultSuccess = 1, 75 kResultUpdateDeferred = 9, // When we ignore/defer updates due to policy. 76 }; 77 OmahaEventOmahaEvent78 OmahaEvent() 79 : type(kTypeUnknown), 80 result(kResultError), 81 error_code(ErrorCode::kError) {} OmahaEventOmahaEvent82 explicit OmahaEvent(Type in_type) 83 : type(in_type), 84 result(kResultSuccess), 85 error_code(ErrorCode::kSuccess) {} OmahaEventOmahaEvent86 OmahaEvent(Type in_type, Result in_result, ErrorCode in_error_code) 87 : type(in_type), 88 result(in_result), 89 error_code(in_error_code) {} 90 91 Type type; 92 Result result; 93 ErrorCode error_code; 94 }; 95 96 class NoneType; 97 class OmahaRequestAction; 98 class OmahaRequestParams; 99 class PrefsInterface; 100 101 // This struct is declared in the .cc file. 102 struct OmahaParserData; 103 104 template<> 105 class ActionTraits<OmahaRequestAction> { 106 public: 107 // Takes parameters on the input pipe. 108 typedef NoneType InputObjectType; 109 // On UpdateCheck success, puts the Omaha response on output. Event 110 // requests do not have an output pipe. 111 typedef OmahaResponse OutputObjectType; 112 }; 113 114 class OmahaRequestAction : public Action<OmahaRequestAction>, 115 public HttpFetcherDelegate { 116 public: 117 static const int kNeverPinged = -1; 118 static const int kPingTimeJump = -2; 119 // We choose this value of 10 as a heuristic for a work day in trying 120 // each URL, assuming we check roughly every 45 mins. This is a good time to 121 // wait - neither too long nor too little - so we don't give up the preferred 122 // URLs that appear earlier in list too quickly before moving on to the 123 // fallback ones. 124 static const int kDefaultMaxFailureCountPerUrl = 10; 125 126 // These are the possible outcome upon checking whether we satisfied 127 // the wall-clock-based-wait. 128 enum WallClockWaitResult { 129 kWallClockWaitNotSatisfied, 130 kWallClockWaitDoneButUpdateCheckWaitRequired, 131 kWallClockWaitDoneAndUpdateCheckWaitNotRequired, 132 }; 133 134 // The ctor takes in all the parameters that will be used for making 135 // the request to Omaha. For some of them we have constants that 136 // should be used. 137 // 138 // Takes ownership of the passed in HttpFetcher. Useful for testing. 139 // 140 // Takes ownership of the passed in OmahaEvent. If |event| is null, 141 // this is an UpdateCheck request, otherwise it's an Event request. 142 // Event requests always succeed. 143 // 144 // A good calling pattern is: 145 // OmahaRequestAction(..., new OmahaEvent(...), new WhateverHttpFetcher); 146 // or 147 // OmahaRequestAction(..., nullptr, new WhateverHttpFetcher); 148 OmahaRequestAction(SystemState* system_state, 149 OmahaEvent* event, 150 std::unique_ptr<HttpFetcher> http_fetcher, 151 bool ping_only); 152 ~OmahaRequestAction() override; 153 typedef ActionTraits<OmahaRequestAction>::InputObjectType InputObjectType; 154 typedef ActionTraits<OmahaRequestAction>::OutputObjectType OutputObjectType; 155 void PerformAction() override; 156 void TerminateProcessing() override; 157 void ActionCompleted(ErrorCode code) override; 158 GetHTTPResponseCode()159 int GetHTTPResponseCode() { return http_fetcher_->http_response_code(); } 160 161 // Debugging/logging StaticType()162 static std::string StaticType() { return "OmahaRequestAction"; } Type()163 std::string Type() const override { return StaticType(); } 164 165 // Delegate methods (see http_fetcher.h) 166 void ReceivedBytes(HttpFetcher *fetcher, 167 const void* bytes, size_t length) override; 168 169 void TransferComplete(HttpFetcher *fetcher, bool successful) override; 170 171 // Returns true if this is an Event request, false if it's an UpdateCheck. IsEvent()172 bool IsEvent() const { return event_.get() != nullptr; } 173 174 private: 175 FRIEND_TEST(OmahaRequestActionTest, GetInstallDateWhenNoPrefsNorOOBE); 176 FRIEND_TEST(OmahaRequestActionTest, 177 GetInstallDateWhenOOBECompletedWithInvalidDate); 178 FRIEND_TEST(OmahaRequestActionTest, 179 GetInstallDateWhenOOBECompletedWithValidDate); 180 FRIEND_TEST(OmahaRequestActionTest, 181 GetInstallDateWhenOOBECompletedDateChanges); 182 183 // Enumeration used in PersistInstallDate(). 184 enum InstallDateProvisioningSource { 185 kProvisionedFromOmahaResponse, 186 kProvisionedFromOOBEMarker, 187 188 // kProvisionedMax is the count of the number of enums above. Add 189 // any new enums above this line only. 190 kProvisionedMax 191 }; 192 193 // Gets the install date, expressed as the number of PST8PDT 194 // calendar weeks since January 1st 2007, times seven. Returns -1 if 195 // unknown. See http://crbug.com/336838 for details about this value. 196 static int GetInstallDate(SystemState* system_state); 197 198 // Parses the Omaha Response in |doc| and sets the 199 // |install_date_days| field of |output_object| to the value of the 200 // elapsed_days attribute of the daystart element. Returns True if 201 // the value was set, False if it wasn't found. 202 static bool ParseInstallDate(OmahaParserData* parser_data, 203 OmahaResponse* output_object); 204 205 // Returns True if the kPrefsInstallDateDays state variable is set, 206 // False otherwise. 207 static bool HasInstallDate(SystemState *system_state); 208 209 // Writes |install_date_days| into the kPrefsInstallDateDays state 210 // variable and emits an UMA stat for the |source| used. Returns 211 // True if the value was written, False if an error occurred. 212 static bool PersistInstallDate(SystemState *system_state, 213 int install_date_days, 214 InstallDateProvisioningSource source); 215 216 // Persist the new cohort* value received in the XML file in the |prefs_key| 217 // preference file. If the |new_value| is empty, the currently stored value 218 // will be deleted. Don't call this function with an empty |new_value| if the 219 // value was not set in the XML, since that would delete the stored value. 220 bool PersistCohortData(const std::string& prefs_key, 221 const std::string& new_value); 222 223 // Parse and persist the end-of-life status flag sent back in the updatecheck 224 // tag attributes. The flag will be validated and stored in the Prefs. 225 bool PersistEolStatus(const std::map<std::string, std::string>& attrs); 226 227 // If this is an update check request, initializes 228 // |ping_active_days_| and |ping_roll_call_days_| to values that may 229 // be sent as pings to Omaha. 230 void InitPingDays(); 231 232 // Based on the persistent preference store values, calculates the 233 // number of days since the last ping sent for |key|. 234 int CalculatePingDays(const std::string& key); 235 236 // Returns whether we have "active_days" or "roll_call_days" ping values to 237 // send to Omaha and thus we should include them in the response. 238 bool ShouldPing() const; 239 240 // Returns true if the download of a new update should be deferred. 241 // False if the update can be downloaded. 242 bool ShouldDeferDownload(OmahaResponse* output_object); 243 244 // Returns true if the basic wall-clock-based waiting period has been 245 // satisfied based on the scattering policy setting. False otherwise. 246 // If true, it also indicates whether the additional update-check-count-based 247 // waiting period also needs to be satisfied before the download can begin. 248 WallClockWaitResult IsWallClockBasedWaitingSatisfied( 249 OmahaResponse* output_object); 250 251 // Returns true if the update-check-count-based waiting period has been 252 // satisfied. False otherwise. 253 bool IsUpdateCheckCountBasedWaitingSatisfied(); 254 255 // Parses the response from Omaha that's available in |doc| using the other 256 // helper methods below and populates the |output_object| with the relevant 257 // values. Returns true if we should continue the parsing. False otherwise, 258 // in which case it sets any error code using |completer|. 259 bool ParseResponse(OmahaParserData* parser_data, 260 OmahaResponse* output_object, 261 ScopedActionCompleter* completer); 262 263 // Parses the status property in the given update_check_node and populates 264 // |output_object| if valid. Returns true if we should continue the parsing. 265 // False otherwise, in which case it sets any error code using |completer|. 266 bool ParseStatus(OmahaParserData* parser_data, 267 OmahaResponse* output_object, 268 ScopedActionCompleter* completer); 269 270 // Parses the URL nodes in the given XML document and populates 271 // |output_object| if valid. Returns true if we should continue the parsing. 272 // False otherwise, in which case it sets any error code using |completer|. 273 bool ParseUrls(OmahaParserData* parser_data, 274 OmahaResponse* output_object, 275 ScopedActionCompleter* completer); 276 277 // Parses the package node in the given XML document and populates 278 // |output_object| if valid. Returns true if we should continue the parsing. 279 // False otherwise, in which case it sets any error code using |completer|. 280 bool ParsePackage(OmahaParserData* parser_data, 281 OmahaResponse* output_object, 282 ScopedActionCompleter* completer); 283 284 // Parses the other parameters in the given XML document and populates 285 // |output_object| if valid. Returns true if we should continue the parsing. 286 // False otherwise, in which case it sets any error code using |completer|. 287 bool ParseParams(OmahaParserData* parser_data, 288 OmahaResponse* output_object, 289 ScopedActionCompleter* completer); 290 291 // Called by TransferComplete() to complete processing, either 292 // asynchronously after looking up resources via p2p or directly. 293 void CompleteProcessing(); 294 295 // Helper to asynchronously look up payload on the LAN. 296 void LookupPayloadViaP2P(const OmahaResponse& response); 297 298 // Callback used by LookupPayloadViaP2P(). 299 void OnLookupPayloadViaP2PCompleted(const std::string& url); 300 301 // Returns true if the current update should be ignored. 302 bool ShouldIgnoreUpdate(const OmahaResponse& response) const; 303 304 // Returns true if updates are allowed over the current type of connection. 305 // False otherwise. 306 bool IsUpdateAllowedOverCurrentConnection() const; 307 308 // Global system context. 309 SystemState* system_state_; 310 311 // Contains state that is relevant in the processing of the Omaha request. 312 OmahaRequestParams* params_; 313 314 // Pointer to the OmahaEvent info. This is an UpdateCheck request if null. 315 std::unique_ptr<OmahaEvent> event_; 316 317 // pointer to the HttpFetcher that does the http work 318 std::unique_ptr<HttpFetcher> http_fetcher_; 319 320 // If true, only include the <ping> element in the request. 321 bool ping_only_; 322 323 // Stores the response from the omaha server 324 brillo::Blob response_buffer_; 325 326 // Initialized by InitPingDays to values that may be sent to Omaha 327 // as part of a ping message. Note that only positive values and -1 328 // are sent to Omaha. 329 int ping_active_days_; 330 int ping_roll_call_days_; 331 332 DISALLOW_COPY_AND_ASSIGN(OmahaRequestAction); 333 }; 334 335 } // namespace chromeos_update_engine 336 337 #endif // UPDATE_ENGINE_OMAHA_REQUEST_ACTION_H_ 338