blob: 38262a92b42eec7919d10a1598d06724c3a05a59 [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
135 if (current_channel_ == "canary-channel") {
136 // TODO(jaysri): chromium-os:39751: We don't have the UI warnings yet. So,
137 // enable the powerwash-on-changing-to-more-stable-channel behavior for now
138 // only on canary-channel devices.
139 is_powerwash_allowed = true;
140 LOG(INFO) << "Is Powerwash Allowed set to true as we are in canary-channel";
141 } else if (!utils::IsOfficialBuild() &&
142 current_channel_ == "testimage-channel") {
143 // Also, allow test builds to have the powerwash behavior so we can always
144 // test channel changing behavior on them, without having to first get them
145 // on an official channel.
146 is_powerwash_allowed = true;
147 LOG(INFO) << "Is Powerwash Allowed set to true as we are running an "
148 "unofficial build";
149 }
150
151 TEST_AND_RETURN_FALSE(IsValidChannel(new_target_channel));
Chris Sosabe45bef2013-04-09 18:25:12 -0700152 FilePath kFile(root_ + kStatefulPartition + "/etc/lsb-release");
Darin Petkov49d91322010-10-25 16:34:58 -0700153 string file_data;
154 map<string, string> data;
155 if (file_util::ReadFileToString(kFile, &file_data)) {
156 data = simple_key_value_store::ParseString(file_data);
157 }
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700158 data[kUpdateChannelKey] = new_target_channel;
159 data[kIsPowerwashAllowedKey] = is_powerwash_allowed ? "true" : "false";
Darin Petkov49d91322010-10-25 16:34:58 -0700160 file_data = simple_key_value_store::AssembleString(data);
161 TEST_AND_RETURN_FALSE(file_util::CreateDirectory(kFile.DirName()));
162 TEST_AND_RETURN_FALSE(
163 file_util::WriteFile(kFile, file_data.data(), file_data.size()) ==
164 static_cast<int>(file_data.size()));
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700165 target_channel_ = new_target_channel;
166 is_powerwash_allowed_ = is_powerwash_allowed;
Darin Petkov49d91322010-10-25 16:34:58 -0700167 return true;
168}
169
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700170void OmahaRequestParams::SetTargetChannelFromLsbValue() {
171 string target_channel_new_value = GetLsbValue(
172 kUpdateChannelKey,
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700173 current_channel_,
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700174 &chromeos_update_engine::OmahaRequestParams::IsValidChannel,
175 true); // stateful_override
176
177 if (target_channel_ != target_channel_new_value) {
178 target_channel_ = target_channel_new_value;
179 LOG(INFO) << "Target Channel set to " << target_channel_
180 << " from LSB file";
181 }
Darin Petkov49d91322010-10-25 16:34:58 -0700182}
183
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700184void OmahaRequestParams::SetCurrentChannelFromLsbValue() {
185 string current_channel_new_value = GetLsbValue(
186 kUpdateChannelKey,
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700187 current_channel_,
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700188 NULL, // No need to validate the read-only rootfs channel.
189 false); // stateful_override is false so we get the current channel.
190
191 if (current_channel_ != current_channel_new_value) {
192 current_channel_ = current_channel_new_value;
193 LOG(INFO) << "Current Channel set to " << current_channel_
194 << " from LSB file in rootfs";
195 }
Satoru Takabayashi583667b2010-10-27 13:09:57 +0900196}
197
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700198void OmahaRequestParams::SetIsPowerwashAllowedFromLsbValue() {
199 string is_powerwash_allowed_str = GetLsbValue(
200 kIsPowerwashAllowedKey,
201 "false",
202 NULL, // no need to validate
203 true); // always get it from stateful, as that's the only place it'll be
204 bool is_powerwash_allowed_new_value = (is_powerwash_allowed_str == "true");
205 if (is_powerwash_allowed_ != is_powerwash_allowed_new_value) {
206 is_powerwash_allowed_ = is_powerwash_allowed_new_value;
207 LOG(INFO) << "Powerwash Allowed set to "
208 << utils::ToString(is_powerwash_allowed_)
209 << " from LSB file in stateful";
210 }
211}
212
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700213void OmahaRequestParams::UpdateDownloadChannel() {
214 if (download_channel_ != target_channel_) {
215 download_channel_ = target_channel_;
216 LOG(INFO) << "Download channel for this attempt = " << download_channel_;
217 }
218}
219
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700220void OmahaRequestParams::InitFromLsbValue() {
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700221 SetCurrentChannelFromLsbValue();
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700222 SetTargetChannelFromLsbValue();
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700223 SetIsPowerwashAllowedFromLsbValue();
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700224 UpdateDownloadChannel();
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700225}
226
227string OmahaRequestParams::GetLsbValue(const string& key,
228 const string& default_value,
229 ValueValidator validator,
230 bool stateful_override) const {
Darin Petkova3df55b2010-11-15 13:33:55 -0800231 vector<string> files;
232 if (stateful_override) {
Chris Sosabe45bef2013-04-09 18:25:12 -0700233 files.push_back(string(kStatefulPartition) + "/etc/lsb-release");
Darin Petkova3df55b2010-11-15 13:33:55 -0800234 }
235 files.push_back("/etc/lsb-release");
236 for (vector<string>::const_iterator it = files.begin();
237 it != files.end(); ++it) {
238 // TODO(adlr): make sure files checked are owned as root (and all their
239 // parents are recursively, too).
Darin Petkova4a8a8c2010-07-15 22:21:12 -0700240 string file_data;
Gilad Arnold19a45f02012-07-19 12:36:10 -0700241 if (!utils::ReadFile(root_ + *it, &file_data))
Darin Petkova4a8a8c2010-07-15 22:21:12 -0700242 continue;
243
244 map<string, string> data = simple_key_value_store::ParseString(file_data);
Darin Petkov49d91322010-10-25 16:34:58 -0700245 if (utils::MapContainsKey(data, key)) {
246 const string& value = data[key];
247 if (validator && !CALL_MEMBER_FN(*this, validator)(value)) {
248 continue;
249 }
250 return value;
251 }
Darin Petkova4a8a8c2010-07-15 22:21:12 -0700252 }
253 // not found
254 return default_value;
255}
256
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700257string OmahaRequestParams::GetMachineType() const {
Darin Petkova4a8a8c2010-07-15 22:21:12 -0700258 struct utsname buf;
259 string ret;
260 if (uname(&buf) == 0)
261 ret = buf.machine;
262 return ret;
263}
264
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700265bool OmahaRequestParams::ShouldLockDown() const {
Darin Petkov10d02dd2011-01-10 14:57:39 -0800266 if (force_lock_down_) {
267 return forced_lock_down_;
268 }
269 return utils::IsOfficialBuild() && utils::IsNormalBootMode();
Darin Petkov49d91322010-10-25 16:34:58 -0700270}
271
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700272bool OmahaRequestParams::IsValidChannel(const std::string& channel) const {
273 return GetChannelIndex(channel) >= 0;
Darin Petkov49d91322010-10-25 16:34:58 -0700274}
275
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700276void OmahaRequestParams::set_root(const std::string& root) {
277 root_ = root;
278 InitFromLsbValue();
279}
280
281void OmahaRequestParams::SetLockDown(bool lock) {
Darin Petkov10d02dd2011-01-10 14:57:39 -0800282 force_lock_down_ = true;
283 forced_lock_down_ = lock;
Darin Petkov49d91322010-10-25 16:34:58 -0700284}
285
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700286int OmahaRequestParams::GetChannelIndex(const std::string& channel) const {
287 for (size_t t = 0; t < arraysize(kChannelsByStability); ++t)
288 if (channel == kChannelsByStability[t])
289 return t;
290
291 return -1;
292}
293
294bool OmahaRequestParams::to_more_stable_channel() const {
295 int current_channel_index = GetChannelIndex(current_channel_);
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700296 int download_channel_index = GetChannelIndex(download_channel_);
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700297
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700298 return download_channel_index > current_channel_index;
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700299}
300
Jay Srinivasandb0acdf2013-04-02 14:47:45 -0700301string OmahaRequestParams::GetAppId() const {
302 return download_channel_ == "canary-channel" ? canary_app_id_ : board_app_id_;
303}
304
Darin Petkova4a8a8c2010-07-15 22:21:12 -0700305} // namespace chromeos_update_engine