omaha_request_params.cc revision 6a9d3497bcf57b8b9f5765a2909a51c9f8119cd1
1// Copyright (c) 2011 The Chromium OS Authors. All rights reserved. 2// 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> 13#include <vector> 14 15#include <base/files/file_util.h> 16#include <base/strings/string_util.h> 17#include <chromeos/key_value_store.h> 18#include <policy/device_policy.h> 19 20#include "update_engine/constants.h" 21#include "update_engine/hardware_interface.h" 22#include "update_engine/system_state.h" 23#include "update_engine/utils.h" 24 25#define CALL_MEMBER_FN(object, member) ((object).*(member)) 26 27using std::map; 28using std::string; 29using std::vector; 30 31namespace chromeos_update_engine { 32 33const char kProductionOmahaUrl[] = 34 "https://tools.google.com/service/update2"; 35const char kAUTestOmahaUrl[] = 36 "https://omaha.sandbox.google.com/service/update2"; 37 38const char OmahaRequestParams::kAppId[] = 39 "{87efface-864d-49a5-9bb3-4b050a7c227a}"; 40const char OmahaRequestParams::kOsPlatform[] = "Chrome OS"; 41const char OmahaRequestParams::kOsVersion[] = "Indy"; 42const char OmahaRequestParams::kUpdateChannelKey[] = "CHROMEOS_RELEASE_TRACK"; 43const char OmahaRequestParams::kIsPowerwashAllowedKey[] = 44 "CHROMEOS_IS_POWERWASH_ALLOWED"; 45const char OmahaRequestParams::kAutoUpdateServerKey[] = "CHROMEOS_AUSERVER"; 46 47const char* kChannelsByStability[] = { 48 // This list has to be sorted from least stable to most stable channel. 49 "canary-channel", 50 "dev-channel", 51 "beta-channel", 52 "stable-channel", 53}; 54 55bool OmahaRequestParams::Init(const string& in_app_version, 56 const string& in_update_url, 57 bool in_interactive) { 58 LOG(INFO) << "Initializing parameters for this update attempt"; 59 InitFromLsbValue(); 60 bool stateful_override = !ShouldLockDown(); 61 os_platform_ = OmahaRequestParams::kOsPlatform; 62 os_version_ = OmahaRequestParams::kOsVersion; 63 app_version_ = in_app_version.empty() ? 64 GetLsbValue("CHROMEOS_RELEASE_VERSION", "", nullptr, stateful_override) : 65 in_app_version; 66 os_sp_ = app_version_ + "_" + GetMachineType(); 67 os_board_ = GetLsbValue("CHROMEOS_RELEASE_BOARD", 68 "", 69 nullptr, 70 stateful_override); 71 string release_app_id = GetLsbValue("CHROMEOS_RELEASE_APPID", 72 OmahaRequestParams::kAppId, 73 nullptr, 74 stateful_override); 75 board_app_id_ = GetLsbValue("CHROMEOS_BOARD_APPID", 76 release_app_id, 77 nullptr, 78 stateful_override); 79 canary_app_id_ = GetLsbValue("CHROMEOS_CANARY_APPID", 80 release_app_id, 81 nullptr, 82 stateful_override); 83 app_lang_ = "en-US"; 84 hwid_ = system_state_->hardware()->GetHardwareClass(); 85 if (CollectECFWVersions()) { 86 fw_version_ = system_state_->hardware()->GetFirmwareVersion(); 87 ec_version_ = system_state_->hardware()->GetECVersion(); 88 } 89 90 if (current_channel_ == target_channel_) { 91 // deltas are only okay if the /.nodelta file does not exist. if we don't 92 // know (i.e. stat() returns some unexpected error), then err on the side of 93 // caution and say deltas are not okay. 94 struct stat stbuf; 95 delta_okay_ = (stat((root_ + "/.nodelta").c_str(), &stbuf) < 0) && 96 (errno == ENOENT); 97 98 } else { 99 LOG(INFO) << "Disabling deltas as a channel change is pending"; 100 // For now, disable delta updates if the current channel is different from 101 // the channel that we're sending to the update server because such updates 102 // are destined to fail -- the current rootfs hash will be different than 103 // the expected hash due to the different channel in /etc/lsb-release. 104 delta_okay_ = false; 105 } 106 107 if (in_update_url.empty()) 108 update_url_ = GetLsbValue(kAutoUpdateServerKey, kProductionOmahaUrl, 109 nullptr, stateful_override); 110 else 111 update_url_ = in_update_url; 112 113 // Set the interactive flag accordingly. 114 interactive_ = in_interactive; 115 return true; 116} 117 118bool OmahaRequestParams::IsUpdateUrlOfficial() const { 119 return (update_url_ == kAUTestOmahaUrl || 120 update_url_ == GetLsbValue(kAutoUpdateServerKey, kProductionOmahaUrl, 121 nullptr, !ShouldLockDown())); 122} 123 124bool OmahaRequestParams::CollectECFWVersions() const { 125 return base::StartsWithASCII(hwid_, string("SAMS ALEX"), true) || 126 base::StartsWithASCII(hwid_, string("BUTTERFLY"), true) || 127 base::StartsWithASCII(hwid_, string("LUMPY"), true) || 128 base::StartsWithASCII(hwid_, string("PARROT"), true) || 129 base::StartsWithASCII(hwid_, string("SPRING"), true) || 130 base::StartsWithASCII(hwid_, string("SNOW"), true); 131} 132 133bool OmahaRequestParams::SetTargetChannel(const string& new_target_channel, 134 bool is_powerwash_allowed) { 135 LOG(INFO) << "SetTargetChannel called with " << new_target_channel 136 << ", Is Powerwash Allowed = " 137 << utils::ToString(is_powerwash_allowed) 138 << ". Current channel = " << current_channel_ 139 << ", existing target channel = " << target_channel_ 140 << ", download channel = " << download_channel_; 141 TEST_AND_RETURN_FALSE(IsValidChannel(new_target_channel)); 142 chromeos::KeyValueStore lsb_release; 143 base::FilePath kFile(root_ + kStatefulPartition + "/etc/lsb-release"); 144 145 lsb_release.Load(kFile); 146 lsb_release.SetString(kUpdateChannelKey, new_target_channel); 147 lsb_release.SetBoolean(kIsPowerwashAllowedKey, is_powerwash_allowed); 148 149 TEST_AND_RETURN_FALSE(base::CreateDirectory(kFile.DirName())); 150 TEST_AND_RETURN_FALSE(lsb_release.Save(kFile)); 151 target_channel_ = new_target_channel; 152 is_powerwash_allowed_ = is_powerwash_allowed; 153 return true; 154} 155 156void OmahaRequestParams::SetTargetChannelFromLsbValue() { 157 string target_channel_new_value = GetLsbValue( 158 kUpdateChannelKey, 159 current_channel_, 160 &chromeos_update_engine::OmahaRequestParams::IsValidChannel, 161 true); // stateful_override 162 163 if (target_channel_ != target_channel_new_value) { 164 target_channel_ = target_channel_new_value; 165 LOG(INFO) << "Target Channel set to " << target_channel_ 166 << " from LSB file"; 167 } 168} 169 170void OmahaRequestParams::SetCurrentChannelFromLsbValue() { 171 string current_channel_new_value = GetLsbValue( 172 kUpdateChannelKey, 173 current_channel_, 174 nullptr, // No need to validate the read-only rootfs channel. 175 false); // stateful_override is false so we get the current channel. 176 177 if (current_channel_ != current_channel_new_value) { 178 current_channel_ = current_channel_new_value; 179 LOG(INFO) << "Current Channel set to " << current_channel_ 180 << " from LSB file in rootfs"; 181 } 182} 183 184void OmahaRequestParams::SetIsPowerwashAllowedFromLsbValue() { 185 string is_powerwash_allowed_str = GetLsbValue( 186 kIsPowerwashAllowedKey, 187 "false", 188 nullptr, // no need to validate 189 true); // always get it from stateful, as that's the only place it'll be 190 bool is_powerwash_allowed_new_value = (is_powerwash_allowed_str == "true"); 191 if (is_powerwash_allowed_ != is_powerwash_allowed_new_value) { 192 is_powerwash_allowed_ = is_powerwash_allowed_new_value; 193 LOG(INFO) << "Powerwash Allowed set to " 194 << utils::ToString(is_powerwash_allowed_) 195 << " from LSB file in stateful"; 196 } 197} 198 199void OmahaRequestParams::UpdateDownloadChannel() { 200 if (download_channel_ != target_channel_) { 201 download_channel_ = target_channel_; 202 LOG(INFO) << "Download channel for this attempt = " << download_channel_; 203 } 204} 205 206void OmahaRequestParams::InitFromLsbValue() { 207 SetCurrentChannelFromLsbValue(); 208 SetTargetChannelFromLsbValue(); 209 SetIsPowerwashAllowedFromLsbValue(); 210 UpdateDownloadChannel(); 211} 212 213string OmahaRequestParams::GetLsbValue(const string& key, 214 const string& default_value, 215 ValueValidator validator, 216 bool stateful_override) const { 217 vector<string> files; 218 if (stateful_override) { 219 files.push_back(string(kStatefulPartition) + "/etc/lsb-release"); 220 } 221 files.push_back("/etc/lsb-release"); 222 for (vector<string>::const_iterator it = files.begin(); 223 it != files.end(); ++it) { 224 // TODO(adlr): make sure files checked are owned as root (and all their 225 // parents are recursively, too). 226 chromeos::KeyValueStore data; 227 if (!data.Load(base::FilePath(root_ + *it))) 228 continue; 229 230 string value; 231 if (data.GetString(key, &value)) { 232 if (validator && !CALL_MEMBER_FN(*this, validator)(value)) { 233 continue; 234 } 235 return value; 236 } 237 } 238 // not found 239 return default_value; 240} 241 242string OmahaRequestParams::GetMachineType() const { 243 struct utsname buf; 244 string ret; 245 if (uname(&buf) == 0) 246 ret = buf.machine; 247 return ret; 248} 249 250bool OmahaRequestParams::ShouldLockDown() const { 251 if (force_lock_down_) { 252 return forced_lock_down_; 253 } 254 return system_state_->hardware()->IsOfficialBuild() && 255 system_state_->hardware()->IsNormalBootMode(); 256} 257 258bool OmahaRequestParams::IsValidChannel(const string& channel) const { 259 return GetChannelIndex(channel) >= 0; 260} 261 262void OmahaRequestParams::set_root(const string& root) { 263 root_ = root; 264 InitFromLsbValue(); 265} 266 267void OmahaRequestParams::SetLockDown(bool lock) { 268 force_lock_down_ = true; 269 forced_lock_down_ = lock; 270} 271 272int OmahaRequestParams::GetChannelIndex(const string& channel) const { 273 for (size_t t = 0; t < arraysize(kChannelsByStability); ++t) 274 if (channel == kChannelsByStability[t]) 275 return t; 276 277 return -1; 278} 279 280bool OmahaRequestParams::to_more_stable_channel() const { 281 int current_channel_index = GetChannelIndex(current_channel_); 282 int download_channel_index = GetChannelIndex(download_channel_); 283 284 return download_channel_index > current_channel_index; 285} 286 287string OmahaRequestParams::GetAppId() const { 288 return download_channel_ == "canary-channel" ? canary_app_id_ : board_app_id_; 289} 290 291} // namespace chromeos_update_engine 292