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