Home | History | Annotate | Download | only in update_engine
      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