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