1 // 2 // Copyright (C) 2012 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/common_service.h" 18 19 #include <set> 20 #include <string> 21 22 #include <base/bind.h> 23 #include <base/location.h> 24 #include <base/logging.h> 25 #include <base/strings/stringprintf.h> 26 #include <brillo/message_loops/message_loop.h> 27 #include <brillo/strings/string_utils.h> 28 #include <policy/device_policy.h> 29 30 #include "update_engine/common/clock_interface.h" 31 #include "update_engine/common/hardware_interface.h" 32 #include "update_engine/common/prefs.h" 33 #include "update_engine/common/utils.h" 34 #include "update_engine/connection_manager_interface.h" 35 #include "update_engine/omaha_request_params.h" 36 #include "update_engine/omaha_utils.h" 37 #include "update_engine/p2p_manager.h" 38 #include "update_engine/payload_state_interface.h" 39 #include "update_engine/update_attempter.h" 40 41 using base::StringPrintf; 42 using brillo::ErrorPtr; 43 using brillo::string_utils::ToString; 44 using std::set; 45 using std::string; 46 using update_engine::UpdateAttemptFlags; 47 using update_engine::UpdateEngineStatus; 48 49 namespace chromeos_update_engine { 50 51 namespace { 52 // Log and set the error on the passed ErrorPtr. 53 void LogAndSetError(ErrorPtr* error, 54 const tracked_objects::Location& location, 55 const string& reason) { 56 brillo::Error::AddTo(error, 57 location, 58 UpdateEngineService::kErrorDomain, 59 UpdateEngineService::kErrorFailed, 60 reason); 61 LOG(ERROR) << "Sending Update Engine Failure: " << location.ToString() << ": " 62 << reason; 63 } 64 } // namespace 65 66 const char* const UpdateEngineService::kErrorDomain = "update_engine"; 67 const char* const UpdateEngineService::kErrorFailed = 68 "org.chromium.UpdateEngine.Error.Failed"; 69 70 UpdateEngineService::UpdateEngineService(SystemState* system_state) 71 : system_state_(system_state) { 72 } 73 74 // org::chromium::UpdateEngineInterfaceInterface methods implementation. 75 76 bool UpdateEngineService::SetUpdateAttemptFlags(ErrorPtr* /* error */, 77 int32_t in_flags_as_int) { 78 auto flags = static_cast<UpdateAttemptFlags>(in_flags_as_int); 79 LOG(INFO) << "Setting Update Attempt Flags: " 80 << "flags=0x" << std::hex << flags << " " 81 << "RestrictDownload=" 82 << ((flags & UpdateAttemptFlags::kFlagRestrictDownload) ? "yes" 83 : "no"); 84 system_state_->update_attempter()->SetUpdateAttemptFlags(flags); 85 return true; 86 } 87 88 bool UpdateEngineService::AttemptUpdate(ErrorPtr* /* error */, 89 const string& in_app_version, 90 const string& in_omaha_url, 91 int32_t in_flags_as_int, 92 bool* out_result) { 93 auto flags = static_cast<UpdateAttemptFlags>(in_flags_as_int); 94 bool interactive = !(flags & UpdateAttemptFlags::kFlagNonInteractive); 95 bool restrict_downloads = (flags & UpdateAttemptFlags::kFlagRestrictDownload); 96 97 LOG(INFO) << "Attempt update: app_version=\"" << in_app_version << "\" " 98 << "omaha_url=\"" << in_omaha_url << "\" " 99 << "flags=0x" << std::hex << flags << " " 100 << "interactive=" << (interactive ? "yes " : "no ") 101 << "RestrictDownload=" << (restrict_downloads ? "yes " : "no "); 102 103 *out_result = system_state_->update_attempter()->CheckForUpdate( 104 in_app_version, in_omaha_url, flags); 105 return true; 106 } 107 108 bool UpdateEngineService::AttemptRollback(ErrorPtr* error, bool in_powerwash) { 109 LOG(INFO) << "Attempting rollback to non-active partitions."; 110 111 if (!system_state_->update_attempter()->Rollback(in_powerwash)) { 112 // TODO(dgarrett): Give a more specific error code/reason. 113 LogAndSetError(error, FROM_HERE, "Rollback attempt failed."); 114 return false; 115 } 116 return true; 117 } 118 119 bool UpdateEngineService::CanRollback(ErrorPtr* /* error */, 120 bool* out_can_rollback) { 121 bool can_rollback = system_state_->update_attempter()->CanRollback(); 122 LOG(INFO) << "Checking to see if we can rollback . Result: " << can_rollback; 123 *out_can_rollback = can_rollback; 124 return true; 125 } 126 127 bool UpdateEngineService::ResetStatus(ErrorPtr* error) { 128 if (!system_state_->update_attempter()->ResetStatus()) { 129 // TODO(dgarrett): Give a more specific error code/reason. 130 LogAndSetError(error, FROM_HERE, "ResetStatus failed."); 131 return false; 132 } 133 return true; 134 } 135 136 bool UpdateEngineService::GetStatus(ErrorPtr* error, 137 UpdateEngineStatus* out_status) { 138 if (!system_state_->update_attempter()->GetStatus(out_status)) { 139 LogAndSetError(error, FROM_HERE, "GetStatus failed."); 140 return false; 141 } 142 return true; 143 } 144 145 bool UpdateEngineService::RebootIfNeeded(ErrorPtr* error) { 146 if (!system_state_->update_attempter()->RebootIfNeeded()) { 147 // TODO(dgarrett): Give a more specific error code/reason. 148 LogAndSetError(error, FROM_HERE, "Reboot not needed, or attempt failed."); 149 return false; 150 } 151 return true; 152 } 153 154 bool UpdateEngineService::SetChannel(ErrorPtr* error, 155 const string& in_target_channel, 156 bool in_is_powerwash_allowed) { 157 const policy::DevicePolicy* device_policy = system_state_->device_policy(); 158 159 // The device_policy is loaded in a lazy way before an update check. Load it 160 // now from the libbrillo cache if it wasn't already loaded. 161 if (!device_policy) { 162 UpdateAttempter* update_attempter = system_state_->update_attempter(); 163 if (update_attempter) { 164 update_attempter->RefreshDevicePolicy(); 165 device_policy = system_state_->device_policy(); 166 } 167 } 168 169 bool delegated = false; 170 if (device_policy && device_policy->GetReleaseChannelDelegated(&delegated) && 171 !delegated) { 172 LogAndSetError(error, 173 FROM_HERE, 174 "Cannot set target channel explicitly when channel " 175 "policy/settings is not delegated"); 176 return false; 177 } 178 179 LOG(INFO) << "Setting destination channel to: " << in_target_channel; 180 string error_message; 181 if (!system_state_->request_params()->SetTargetChannel( 182 in_target_channel, in_is_powerwash_allowed, &error_message)) { 183 LogAndSetError(error, FROM_HERE, error_message); 184 return false; 185 } 186 return true; 187 } 188 189 bool UpdateEngineService::GetChannel(ErrorPtr* /* error */, 190 bool in_get_current_channel, 191 string* out_channel) { 192 OmahaRequestParams* rp = system_state_->request_params(); 193 *out_channel = 194 (in_get_current_channel ? rp->current_channel() : rp->target_channel()); 195 return true; 196 } 197 198 bool UpdateEngineService::SetCohortHint(ErrorPtr* error, 199 string in_cohort_hint) { 200 PrefsInterface* prefs = system_state_->prefs(); 201 202 // It is ok to override the cohort hint with an invalid value since it is 203 // stored in stateful partition. The code reading it should sanitize it 204 // anyway. 205 if (!prefs->SetString(kPrefsOmahaCohortHint, in_cohort_hint)) { 206 LogAndSetError( 207 error, 208 FROM_HERE, 209 StringPrintf("Error setting the cohort hint value to \"%s\".", 210 in_cohort_hint.c_str())); 211 return false; 212 } 213 return true; 214 } 215 216 bool UpdateEngineService::GetCohortHint(ErrorPtr* error, 217 string* out_cohort_hint) { 218 PrefsInterface* prefs = system_state_->prefs(); 219 220 *out_cohort_hint = ""; 221 if (prefs->Exists(kPrefsOmahaCohortHint) && 222 !prefs->GetString(kPrefsOmahaCohortHint, out_cohort_hint)) { 223 LogAndSetError(error, FROM_HERE, "Error getting the cohort hint."); 224 return false; 225 } 226 return true; 227 } 228 229 bool UpdateEngineService::SetP2PUpdatePermission(ErrorPtr* error, 230 bool in_enabled) { 231 PrefsInterface* prefs = system_state_->prefs(); 232 233 if (!prefs->SetBoolean(kPrefsP2PEnabled, in_enabled)) { 234 LogAndSetError( 235 error, 236 FROM_HERE, 237 StringPrintf("Error setting the update via p2p permission to %s.", 238 ToString(in_enabled).c_str())); 239 return false; 240 } 241 return true; 242 } 243 244 bool UpdateEngineService::GetP2PUpdatePermission(ErrorPtr* error, 245 bool* out_enabled) { 246 PrefsInterface* prefs = system_state_->prefs(); 247 248 bool p2p_pref = false; // Default if no setting is present. 249 if (prefs->Exists(kPrefsP2PEnabled) && 250 !prefs->GetBoolean(kPrefsP2PEnabled, &p2p_pref)) { 251 LogAndSetError(error, FROM_HERE, "Error getting the P2PEnabled setting."); 252 return false; 253 } 254 255 *out_enabled = p2p_pref; 256 return true; 257 } 258 259 bool UpdateEngineService::SetUpdateOverCellularPermission(ErrorPtr* error, 260 bool in_allowed) { 261 set<string> allowed_types; 262 const policy::DevicePolicy* device_policy = system_state_->device_policy(); 263 264 // The device_policy is loaded in a lazy way before an update check. Load it 265 // now from the libbrillo cache if it wasn't already loaded. 266 if (!device_policy) { 267 UpdateAttempter* update_attempter = system_state_->update_attempter(); 268 if (update_attempter) { 269 update_attempter->RefreshDevicePolicy(); 270 device_policy = system_state_->device_policy(); 271 } 272 } 273 274 // Check if this setting is allowed by the device policy. 275 if (device_policy && 276 device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) { 277 LogAndSetError(error, 278 FROM_HERE, 279 "Ignoring the update over cellular setting since there's " 280 "a device policy enforcing this setting."); 281 return false; 282 } 283 284 // If the policy wasn't loaded yet, then it is still OK to change the local 285 // setting because the policy will be checked again during the update check. 286 287 PrefsInterface* prefs = system_state_->prefs(); 288 289 if (!prefs->SetBoolean(kPrefsUpdateOverCellularPermission, in_allowed)) { 290 LogAndSetError(error, 291 FROM_HERE, 292 string("Error setting the update over cellular to ") + 293 (in_allowed ? "true" : "false")); 294 return false; 295 } 296 return true; 297 } 298 299 bool UpdateEngineService::GetUpdateOverCellularPermission(ErrorPtr* /* error */, 300 bool* out_allowed) { 301 ConnectionManagerInterface* cm = system_state_->connection_manager(); 302 303 // The device_policy is loaded in a lazy way before an update check and is 304 // used to determine if an update is allowed over cellular. Load the device 305 // policy now from the libbrillo cache if it wasn't already loaded. 306 if (!system_state_->device_policy()) { 307 UpdateAttempter* update_attempter = system_state_->update_attempter(); 308 if (update_attempter) 309 update_attempter->RefreshDevicePolicy(); 310 } 311 312 // Return the current setting based on the same logic used while checking for 313 // updates. A log message could be printed as the result of this test. 314 LOG(INFO) << "Checking if updates over cellular networks are allowed:"; 315 *out_allowed = cm->IsUpdateAllowedOver(ConnectionType::kCellular, 316 ConnectionTethering::kUnknown); 317 return true; 318 } 319 320 bool UpdateEngineService::GetDurationSinceUpdate(ErrorPtr* error, 321 int64_t* out_usec_wallclock) { 322 base::Time time; 323 if (!system_state_->update_attempter()->GetBootTimeAtUpdate(&time)) { 324 LogAndSetError(error, FROM_HERE, "No pending update."); 325 return false; 326 } 327 328 ClockInterface* clock = system_state_->clock(); 329 *out_usec_wallclock = (clock->GetBootTime() - time).InMicroseconds(); 330 return true; 331 } 332 333 bool UpdateEngineService::GetPrevVersion(ErrorPtr* /* error */, 334 string* out_prev_version) { 335 *out_prev_version = system_state_->update_attempter()->GetPrevVersion(); 336 return true; 337 } 338 339 bool UpdateEngineService::GetRollbackPartition( 340 ErrorPtr* /* error */, string* out_rollback_partition_name) { 341 BootControlInterface::Slot rollback_slot = 342 system_state_->update_attempter()->GetRollbackSlot(); 343 344 if (rollback_slot == BootControlInterface::kInvalidSlot) { 345 out_rollback_partition_name->clear(); 346 return true; 347 } 348 349 string name; 350 if (!system_state_->boot_control()->GetPartitionDevice( 351 "KERNEL", rollback_slot, &name)) { 352 LOG(ERROR) << "Invalid rollback device"; 353 return false; 354 } 355 356 LOG(INFO) << "Getting rollback partition name. Result: " << name; 357 *out_rollback_partition_name = name; 358 return true; 359 } 360 361 bool UpdateEngineService::GetLastAttemptError(ErrorPtr* /* error */, 362 int32_t* out_last_attempt_error) { 363 ErrorCode error_code = system_state_->payload_state()->GetAttemptErrorCode(); 364 *out_last_attempt_error = static_cast<int>(error_code); 365 return true; 366 } 367 368 bool UpdateEngineService::GetEolStatus(ErrorPtr* error, 369 int32_t* out_eol_status) { 370 PrefsInterface* prefs = system_state_->prefs(); 371 372 string str_eol_status; 373 if (prefs->Exists(kPrefsOmahaEolStatus) && 374 !prefs->GetString(kPrefsOmahaEolStatus, &str_eol_status)) { 375 LogAndSetError(error, FROM_HERE, "Error getting the end-of-life status."); 376 return false; 377 } 378 379 // StringToEolStatus will return kSupported for invalid values. 380 *out_eol_status = static_cast<int32_t>(StringToEolStatus(str_eol_status)); 381 return true; 382 } 383 384 } // namespace chromeos_update_engine 385