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