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