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