blob: 9a729f05c5690b319f005ff7402fa35dd46a9586 [file] [log] [blame]
Darin Petkovf2065b42011-05-17 16:36:27 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
Darin Petkova4a8a8c2010-07-15 22:21:12 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "update_engine/omaha_request_params.h"
6
7#include <errno.h>
8#include <fcntl.h>
9#include <sys/utsname.h>
10
11#include <map>
12#include <string>
Darin Petkova3df55b2010-11-15 13:33:55 -080013#include <vector>
Darin Petkova4a8a8c2010-07-15 22:21:12 -070014
Darin Petkov49d91322010-10-25 16:34:58 -070015#include <base/file_util.h>
Chris Sosac1972482013-04-30 22:31:10 -070016#include <base/string_util.h>
Patrick Dubroy7fbbe8a2011-08-01 17:28:22 +020017#include <policy/device_policy.h>
Darin Petkov49d91322010-10-25 16:34:58 -070018
Chris Sosabe45bef2013-04-09 18:25:12 -070019#include "update_engine/constants.h"
Darin Petkova4a8a8c2010-07-15 22:21:12 -070020#include "update_engine/simple_key_value_store.h"
Jay Srinivasanae4697c2013-03-18 17:08:08 -070021#include "update_engine/system_state.h"
Darin Petkova4a8a8c2010-07-15 22:21:12 -070022#include "update_engine/utils.h"
23
Darin Petkov49d91322010-10-25 16:34:58 -070024#define CALL_MEMBER_FN(object, member) ((object).*(member))
25
Darin Petkova4a8a8c2010-07-15 22:21:12 -070026using std::map;
27using std::string;
Darin Petkova3df55b2010-11-15 13:33:55 -080028using std::vector;
Darin Petkova4a8a8c2010-07-15 22:21:12 -070029
Darin Petkova4a8a8c2010-07-15 22:21:12 -070030namespace chromeos_update_engine {
31
Darin Petkov5a7f5652010-07-22 21:40:09 -070032const char* const OmahaRequestParams::kAppId(
33 "{87efface-864d-49a5-9bb3-4b050a7c227a}");
34const char* const OmahaRequestParams::kOsPlatform("Chrome OS");
35const char* const OmahaRequestParams::kOsVersion("Indy");
Jay Srinivasan55f50c22013-01-10 19:24:35 -080036const char* const kProductionOmahaUrl(
Darin Petkov5a7f5652010-07-22 21:40:09 -070037 "https://tools.google.com/service/update2");
38
Jay Srinivasanae4697c2013-03-18 17:08:08 -070039const char* const OmahaRequestParams::kUpdateChannelKey(
40 "CHROMEOS_RELEASE_TRACK");
41const char* const OmahaRequestParams::kIsPowerwashAllowedKey(
42 "CHROMEOS_IS_POWERWASH_ALLOWED");
Patrick Dubroy7fbbe8a2011-08-01 17:28:22 +020043
Jay Srinivasanae4697c2013-03-18 17:08:08 -070044const char* kChannelsByStability[] = {
45 // This list has to be sorted from least stable to most stable channel.
46 "canary-channel",
47 "dev-channel",
48 "beta-channel",
49 "stable-channel",
50};
Darin Petkov49d91322010-10-25 16:34:58 -070051
Jay Srinivasanae4697c2013-03-18 17:08:08 -070052bool OmahaRequestParams::Init(const std::string& in_app_version,
53 const std::string& in_update_url,
54 bool in_interactive) {
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070055 LOG(INFO) << "Initializing parameters for this update attempt";
Jay Srinivasanae4697c2013-03-18 17:08:08 -070056 InitFromLsbValue();
Darin Petkov10d02dd2011-01-10 14:57:39 -080057 bool stateful_override = !ShouldLockDown();
Jay Srinivasanae4697c2013-03-18 17:08:08 -070058 os_platform_ = OmahaRequestParams::kOsPlatform;
59 os_version_ = OmahaRequestParams::kOsVersion;
60 app_version_ = in_app_version.empty() ?
Darin Petkov10d02dd2011-01-10 14:57:39 -080061 GetLsbValue("CHROMEOS_RELEASE_VERSION", "", NULL, stateful_override) :
62 in_app_version;
Jay Srinivasanae4697c2013-03-18 17:08:08 -070063 os_sp_ = app_version_ + "_" + GetMachineType();
64 os_board_ = GetLsbValue("CHROMEOS_RELEASE_BOARD",
65 "",
66 NULL,
67 stateful_override);
Jay Srinivasandb0acdf2013-04-02 14:47:45 -070068 string release_app_id = GetLsbValue("CHROMEOS_RELEASE_APPID",
69 OmahaRequestParams::kAppId,
70 NULL,
71 stateful_override);
Jay Srinivasanae4697c2013-03-18 17:08:08 -070072 board_app_id_ = GetLsbValue("CHROMEOS_BOARD_APPID",
Jay Srinivasandb0acdf2013-04-02 14:47:45 -070073 release_app_id,
Jay Srinivasanae4697c2013-03-18 17:08:08 -070074 NULL,
75 stateful_override);
Jay Srinivasandb0acdf2013-04-02 14:47:45 -070076 canary_app_id_ = GetLsbValue("CHROMEOS_CANARY_APPID",
77 release_app_id,
78 NULL,
79 stateful_override);
Jay Srinivasanae4697c2013-03-18 17:08:08 -070080 app_lang_ = "en-US";
81 hwid_ = utils::GetHardwareClass();
Chris Sosac1972482013-04-30 22:31:10 -070082 if (CollectECFWVersions()) {
83 fw_version_ = utils::GetFirmwareVersion();
84 ec_version_ = utils::GetECVersion(NULL);
85 }
Patrick Dubroy7fbbe8a2011-08-01 17:28:22 +020086
Jay Srinivasanae4697c2013-03-18 17:08:08 -070087 if (current_channel_ == target_channel_) {
88 // deltas are only okay if the /.nodelta file does not exist. if we don't
89 // know (i.e. stat() returns some unexpected error), then err on the side of
90 // caution and say deltas are not okay.
91 struct stat stbuf;
92 delta_okay_ = (stat((root_ + "/.nodelta").c_str(), &stbuf) < 0) &&
93 (errno == ENOENT);
94
Patrick Dubroy7fbbe8a2011-08-01 17:28:22 +020095 } else {
Jay Srinivasanae4697c2013-03-18 17:08:08 -070096 LOG(INFO) << "Disabling deltas as a channel change is pending";
97 // For now, disable delta updates if the current channel is different from
98 // the channel that we're sending to the update server because such updates
99 // are destined to fail -- the current rootfs hash will be different than
100 // the expected hash due to the different channel in /etc/lsb-release.
101 delta_okay_ = false;
Patrick Dubroy7fbbe8a2011-08-01 17:28:22 +0200102 }
103
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700104 if (in_update_url.empty())
105 update_url_ = GetLsbValue("CHROMEOS_AUSERVER", kProductionOmahaUrl, NULL,
106 stateful_override);
107 else
108 update_url_ = in_update_url;
Gilad Arnoldbbdd4902013-01-10 16:06:30 -0800109
110 // Set the interactive flag accordingly.
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700111 interactive_ = in_interactive;
Darin Petkova4a8a8c2010-07-15 22:21:12 -0700112 return true;
113}
114
Chris Sosac1972482013-04-30 22:31:10 -0700115bool OmahaRequestParams::CollectECFWVersions() const {
116 return (
117 StartsWithASCII(hwid_, string("SAMS ALEX"), true) ||
118 StartsWithASCII(hwid_, string("BUTTERFLY"), true) ||
119 StartsWithASCII(hwid_, string("LUMPY"), true) ||
120 StartsWithASCII(hwid_, string("PARROT"), true) ||
121 StartsWithASCII(hwid_, string("SPRING"), true) ||
122 StartsWithASCII(hwid_, string("SNOW"), true)
123 );
124}
125
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700126bool OmahaRequestParams::SetTargetChannel(const std::string& new_target_channel,
127 bool is_powerwash_allowed) {
128 LOG(INFO) << "SetTargetChannel called with " << new_target_channel
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700129 << ", Is Powerwash Allowed = "
130 << utils::ToString(is_powerwash_allowed)
131 << ". Current channel = " << current_channel_
132 << ", existing target channel = " << target_channel_
133 << ", download channel = " << download_channel_;
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700134 TEST_AND_RETURN_FALSE(IsValidChannel(new_target_channel));
Chris Sosabe45bef2013-04-09 18:25:12 -0700135 FilePath kFile(root_ + kStatefulPartition + "/etc/lsb-release");
Darin Petkov49d91322010-10-25 16:34:58 -0700136 string file_data;
137 map<string, string> data;
138 if (file_util::ReadFileToString(kFile, &file_data)) {
139 data = simple_key_value_store::ParseString(file_data);
140 }
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700141 data[kUpdateChannelKey] = new_target_channel;
142 data[kIsPowerwashAllowedKey] = is_powerwash_allowed ? "true" : "false";
Darin Petkov49d91322010-10-25 16:34:58 -0700143 file_data = simple_key_value_store::AssembleString(data);
144 TEST_AND_RETURN_FALSE(file_util::CreateDirectory(kFile.DirName()));
145 TEST_AND_RETURN_FALSE(
146 file_util::WriteFile(kFile, file_data.data(), file_data.size()) ==
147 static_cast<int>(file_data.size()));
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700148 target_channel_ = new_target_channel;
149 is_powerwash_allowed_ = is_powerwash_allowed;
Darin Petkov49d91322010-10-25 16:34:58 -0700150 return true;
151}
152
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700153void OmahaRequestParams::SetTargetChannelFromLsbValue() {
154 string target_channel_new_value = GetLsbValue(
155 kUpdateChannelKey,
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700156 current_channel_,
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700157 &chromeos_update_engine::OmahaRequestParams::IsValidChannel,
158 true); // stateful_override
159
160 if (target_channel_ != target_channel_new_value) {
161 target_channel_ = target_channel_new_value;
162 LOG(INFO) << "Target Channel set to " << target_channel_
163 << " from LSB file";
164 }
Darin Petkov49d91322010-10-25 16:34:58 -0700165}
166
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700167void OmahaRequestParams::SetCurrentChannelFromLsbValue() {
168 string current_channel_new_value = GetLsbValue(
169 kUpdateChannelKey,
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700170 current_channel_,
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700171 NULL, // No need to validate the read-only rootfs channel.
172 false); // stateful_override is false so we get the current channel.
173
174 if (current_channel_ != current_channel_new_value) {
175 current_channel_ = current_channel_new_value;
176 LOG(INFO) << "Current Channel set to " << current_channel_
177 << " from LSB file in rootfs";
178 }
Satoru Takabayashi583667b2010-10-27 13:09:57 +0900179}
180
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700181void OmahaRequestParams::SetIsPowerwashAllowedFromLsbValue() {
182 string is_powerwash_allowed_str = GetLsbValue(
183 kIsPowerwashAllowedKey,
184 "false",
185 NULL, // no need to validate
186 true); // always get it from stateful, as that's the only place it'll be
187 bool is_powerwash_allowed_new_value = (is_powerwash_allowed_str == "true");
188 if (is_powerwash_allowed_ != is_powerwash_allowed_new_value) {
189 is_powerwash_allowed_ = is_powerwash_allowed_new_value;
190 LOG(INFO) << "Powerwash Allowed set to "
191 << utils::ToString(is_powerwash_allowed_)
192 << " from LSB file in stateful";
193 }
194}
195
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700196void OmahaRequestParams::UpdateDownloadChannel() {
197 if (download_channel_ != target_channel_) {
198 download_channel_ = target_channel_;
199 LOG(INFO) << "Download channel for this attempt = " << download_channel_;
200 }
201}
202
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700203void OmahaRequestParams::InitFromLsbValue() {
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700204 SetCurrentChannelFromLsbValue();
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700205 SetTargetChannelFromLsbValue();
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700206 SetIsPowerwashAllowedFromLsbValue();
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700207 UpdateDownloadChannel();
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700208}
209
210string OmahaRequestParams::GetLsbValue(const string& key,
211 const string& default_value,
212 ValueValidator validator,
213 bool stateful_override) const {
Darin Petkova3df55b2010-11-15 13:33:55 -0800214 vector<string> files;
215 if (stateful_override) {
Chris Sosabe45bef2013-04-09 18:25:12 -0700216 files.push_back(string(kStatefulPartition) + "/etc/lsb-release");
Darin Petkova3df55b2010-11-15 13:33:55 -0800217 }
218 files.push_back("/etc/lsb-release");
219 for (vector<string>::const_iterator it = files.begin();
220 it != files.end(); ++it) {
221 // TODO(adlr): make sure files checked are owned as root (and all their
222 // parents are recursively, too).
Darin Petkova4a8a8c2010-07-15 22:21:12 -0700223 string file_data;
Gilad Arnold19a45f02012-07-19 12:36:10 -0700224 if (!utils::ReadFile(root_ + *it, &file_data))
Darin Petkova4a8a8c2010-07-15 22:21:12 -0700225 continue;
226
227 map<string, string> data = simple_key_value_store::ParseString(file_data);
Darin Petkov49d91322010-10-25 16:34:58 -0700228 if (utils::MapContainsKey(data, key)) {
229 const string& value = data[key];
230 if (validator && !CALL_MEMBER_FN(*this, validator)(value)) {
231 continue;
232 }
233 return value;
234 }
Darin Petkova4a8a8c2010-07-15 22:21:12 -0700235 }
236 // not found
237 return default_value;
238}
239
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700240string OmahaRequestParams::GetMachineType() const {
Darin Petkova4a8a8c2010-07-15 22:21:12 -0700241 struct utsname buf;
242 string ret;
243 if (uname(&buf) == 0)
244 ret = buf.machine;
245 return ret;
246}
247
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700248bool OmahaRequestParams::ShouldLockDown() const {
Darin Petkov10d02dd2011-01-10 14:57:39 -0800249 if (force_lock_down_) {
250 return forced_lock_down_;
251 }
252 return utils::IsOfficialBuild() && utils::IsNormalBootMode();
Darin Petkov49d91322010-10-25 16:34:58 -0700253}
254
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700255bool OmahaRequestParams::IsValidChannel(const std::string& channel) const {
256 return GetChannelIndex(channel) >= 0;
Darin Petkov49d91322010-10-25 16:34:58 -0700257}
258
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700259void OmahaRequestParams::set_root(const std::string& root) {
260 root_ = root;
261 InitFromLsbValue();
262}
263
264void OmahaRequestParams::SetLockDown(bool lock) {
Darin Petkov10d02dd2011-01-10 14:57:39 -0800265 force_lock_down_ = true;
266 forced_lock_down_ = lock;
Darin Petkov49d91322010-10-25 16:34:58 -0700267}
268
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700269int OmahaRequestParams::GetChannelIndex(const std::string& channel) const {
270 for (size_t t = 0; t < arraysize(kChannelsByStability); ++t)
271 if (channel == kChannelsByStability[t])
272 return t;
273
274 return -1;
275}
276
277bool OmahaRequestParams::to_more_stable_channel() const {
278 int current_channel_index = GetChannelIndex(current_channel_);
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700279 int download_channel_index = GetChannelIndex(download_channel_);
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700280
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700281 return download_channel_index > current_channel_index;
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700282}
283
Jay Srinivasandb0acdf2013-04-02 14:47:45 -0700284string OmahaRequestParams::GetAppId() const {
285 return download_channel_ == "canary-channel" ? canary_app_id_ : board_app_id_;
286}
287
Darin Petkova4a8a8c2010-07-15 22:21:12 -0700288} // namespace chromeos_update_engine