Home | History | Annotate | Download | only in help
      1 // Copyright (c) 2012 The Chromium 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 "chrome/browser/ui/webui/help/version_updater_chromeos.h"
      6 
      7 #include <cmath>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "chrome/browser/browser_process.h"
     12 #include "chrome/browser/chromeos/login/startup_utils.h"
     13 #include "chrome/browser/chromeos/login/wizard_controller.h"
     14 #include "chrome/browser/chromeos/settings/cros_settings.h"
     15 #include "chrome/browser/ui/webui/help/help_utils_chromeos.h"
     16 #include "chrome/grit/generated_resources.h"
     17 #include "chromeos/dbus/dbus_thread_manager.h"
     18 #include "chromeos/dbus/power_manager_client.h"
     19 #include "chromeos/network/network_handler.h"
     20 #include "chromeos/network/network_state.h"
     21 #include "chromeos/network/network_state_handler.h"
     22 #include "chromeos/settings/cros_settings_names.h"
     23 #include "components/user_manager/user_manager.h"
     24 #include "third_party/cros_system_api/dbus/service_constants.h"
     25 #include "ui/base/l10n/l10n_util.h"
     26 
     27 using chromeos::CrosSettings;
     28 using chromeos::DBusThreadManager;
     29 using chromeos::UpdateEngineClient;
     30 using user_manager::UserManager;
     31 using chromeos::WizardController;
     32 
     33 namespace {
     34 
     35 // Network status in the context of device update.
     36 enum NetworkStatus {
     37   // It's allowed in device policy to use current network for update.
     38   NETWORK_STATUS_ALLOWED = 0,
     39   // It's disallowed in device policy to use current network for update.
     40   NETWORK_STATUS_DISALLOWED,
     41   // Device is in offline state.
     42   NETWORK_STATUS_OFFLINE
     43 };
     44 
     45 const bool kDefaultAutoUpdateDisabled = false;
     46 
     47 NetworkStatus GetNetworkStatus(const chromeos::NetworkState* network) {
     48   if (!network || !network->IsConnectedState())  // Offline state.
     49     return NETWORK_STATUS_OFFLINE;
     50 
     51   // The connection type checking strategy must be the same as the one
     52   // used in update engine.
     53   if (network->type() == shill::kTypeBluetooth)
     54     return NETWORK_STATUS_DISALLOWED;
     55   if (network->type() == shill::kTypeCellular &&
     56       !help_utils_chromeos::IsUpdateOverCellularAllowed()) {
     57     return NETWORK_STATUS_DISALLOWED;
     58   }
     59   return NETWORK_STATUS_ALLOWED;
     60 }
     61 
     62 // Returns true if auto-update is disabled by the system administrator.
     63 bool IsAutoUpdateDisabled() {
     64   bool update_disabled = kDefaultAutoUpdateDisabled;
     65   chromeos::CrosSettings* settings = chromeos::CrosSettings::Get();
     66   if (!settings)
     67     return update_disabled;
     68   const base::Value* update_disabled_value =
     69       settings->GetPref(chromeos::kUpdateDisabled);
     70   if (update_disabled_value)
     71     CHECK(update_disabled_value->GetAsBoolean(&update_disabled));
     72   return update_disabled;
     73 }
     74 
     75 // Returns whether an update is allowed. If not, it calls the callback with
     76 // the appropriate status.
     77 bool EnsureCanUpdate(const VersionUpdater::StatusCallback& callback) {
     78   if (IsAutoUpdateDisabled()) {
     79     callback.Run(VersionUpdater::FAILED, 0,
     80                  l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY));
     81     return false;
     82   }
     83 
     84   chromeos::NetworkStateHandler* network_state_handler =
     85       chromeos::NetworkHandler::Get()->network_state_handler();
     86   const chromeos::NetworkState* network =
     87       network_state_handler->DefaultNetwork();
     88 
     89   // Don't allow an update if we're currently offline or connected
     90   // to a network for which updates are disallowed.
     91   NetworkStatus status = GetNetworkStatus(network);
     92   if (status == NETWORK_STATUS_OFFLINE) {
     93     callback.Run(VersionUpdater::FAILED_OFFLINE, 0,
     94                   l10n_util::GetStringUTF16(IDS_UPGRADE_OFFLINE));
     95     return false;
     96   } else if (status == NETWORK_STATUS_DISALLOWED) {
     97     base::string16 message =
     98         l10n_util::GetStringFUTF16(
     99             IDS_UPGRADE_DISALLOWED,
    100             help_utils_chromeos::GetConnectionTypeAsUTF16(network->type()));
    101     callback.Run(VersionUpdater::FAILED_CONNECTION_TYPE_DISALLOWED, 0, message);
    102     return false;
    103   }
    104 
    105   return true;
    106 }
    107 
    108 }  // namespace
    109 
    110 VersionUpdater* VersionUpdater::Create() {
    111   return new VersionUpdaterCros;
    112 }
    113 
    114 void VersionUpdaterCros::GetUpdateStatus(const StatusCallback& callback) {
    115   callback_ = callback;
    116 
    117   if (!EnsureCanUpdate(callback))
    118     return;
    119 
    120   UpdateEngineClient* update_engine_client =
    121       DBusThreadManager::Get()->GetUpdateEngineClient();
    122   if (!update_engine_client->HasObserver(this))
    123     update_engine_client->AddObserver(this);
    124 
    125   this->UpdateStatusChanged(
    126       DBusThreadManager::Get()->GetUpdateEngineClient()->GetLastStatus());
    127 }
    128 
    129 void VersionUpdaterCros::CheckForUpdate(const StatusCallback& callback) {
    130   callback_ = callback;
    131 
    132   if (!EnsureCanUpdate(callback))
    133     return;
    134 
    135   UpdateEngineClient* update_engine_client =
    136       DBusThreadManager::Get()->GetUpdateEngineClient();
    137   if (!update_engine_client->HasObserver(this))
    138     update_engine_client->AddObserver(this);
    139 
    140   if (update_engine_client->GetLastStatus().status !=
    141       UpdateEngineClient::UPDATE_STATUS_IDLE) {
    142     check_for_update_when_idle_ = true;
    143     return;
    144   }
    145   check_for_update_when_idle_ = false;
    146 
    147   // Make sure that libcros is loaded and OOBE is complete.
    148   if (!WizardController::default_controller() ||
    149       chromeos::StartupUtils::IsDeviceRegistered()) {
    150     update_engine_client->RequestUpdateCheck(base::Bind(
    151         &VersionUpdaterCros::OnUpdateCheck, weak_ptr_factory_.GetWeakPtr()));
    152   }
    153 }
    154 
    155 void VersionUpdaterCros::RelaunchBrowser() const {
    156   DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
    157 }
    158 
    159 void VersionUpdaterCros::SetChannel(const std::string& channel,
    160                                     bool is_powerwash_allowed) {
    161   if (user_manager::UserManager::Get()->IsCurrentUserOwner()) {
    162     // For local owner set the field in the policy blob.
    163     CrosSettings::Get()->SetString(chromeos::kReleaseChannel, channel);
    164   }
    165   DBusThreadManager::Get()->GetUpdateEngineClient()->
    166       SetChannel(channel, is_powerwash_allowed);
    167 }
    168 
    169 void VersionUpdaterCros::GetChannel(bool get_current_channel,
    170                                     const ChannelCallback& cb) {
    171   UpdateEngineClient* update_engine_client =
    172       DBusThreadManager::Get()->GetUpdateEngineClient();
    173 
    174   // Request the channel information.
    175   update_engine_client->GetChannel(get_current_channel, cb);
    176 }
    177 
    178 VersionUpdaterCros::VersionUpdaterCros()
    179     : last_operation_(UpdateEngineClient::UPDATE_STATUS_IDLE),
    180       check_for_update_when_idle_(false),
    181       weak_ptr_factory_(this) {
    182 }
    183 
    184 VersionUpdaterCros::~VersionUpdaterCros() {
    185   UpdateEngineClient* update_engine_client =
    186       DBusThreadManager::Get()->GetUpdateEngineClient();
    187   update_engine_client->RemoveObserver(this);
    188 }
    189 
    190 void VersionUpdaterCros::UpdateStatusChanged(
    191     const UpdateEngineClient::Status& status) {
    192   Status my_status = UPDATED;
    193   int progress = 0;
    194   base::string16 message;
    195 
    196   // If the updater is currently idle, just show the last operation (unless it
    197   // was previously checking for an update -- in that case, the system is
    198   // up-to-date now).  See http://crbug.com/120063 for details.
    199   UpdateEngineClient::UpdateStatusOperation operation_to_show = status.status;
    200   if (status.status == UpdateEngineClient::UPDATE_STATUS_IDLE &&
    201       last_operation_ !=
    202       UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE) {
    203     operation_to_show = last_operation_;
    204   }
    205 
    206   switch (operation_to_show) {
    207     case UpdateEngineClient::UPDATE_STATUS_ERROR:
    208     case UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT:
    209     case UpdateEngineClient::UPDATE_STATUS_ATTEMPTING_ROLLBACK:
    210       // This path previously used the FAILED status and IDS_UPGRADE_ERROR, but
    211       // the update engine reports errors for some conditions that shouldn't
    212       // actually be displayed as errors to users: http://crbug.com/146919.
    213       // Just use the UPDATED status instead.
    214       break;
    215     case UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE:
    216       my_status = CHECKING;
    217       break;
    218     case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING:
    219       progress = static_cast<int>(round(status.download_progress * 100));
    220       // Fall through.
    221     case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE:
    222       my_status = UPDATING;
    223       break;
    224     case UpdateEngineClient::UPDATE_STATUS_VERIFYING:
    225     case UpdateEngineClient::UPDATE_STATUS_FINALIZING:
    226       // Once the download is finished, keep the progress at 100; it shouldn't
    227       // go down while the status is the same.
    228       progress = 100;
    229       my_status = UPDATING;
    230       break;
    231     case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT:
    232       my_status = NEARLY_UPDATED;
    233       break;
    234     default:
    235       break;
    236   }
    237 
    238   callback_.Run(my_status, progress, message);
    239   last_operation_ = status.status;
    240 
    241   if (check_for_update_when_idle_ &&
    242       status.status == UpdateEngineClient::UPDATE_STATUS_IDLE) {
    243     CheckForUpdate(callback_);
    244   }
    245 }
    246 
    247 void VersionUpdaterCros::OnUpdateCheck(
    248     UpdateEngineClient::UpdateCheckResult result) {
    249   // If version updating is not implemented, this binary is the most up-to-date
    250   // possible with respect to automatic updating.
    251   if (result == UpdateEngineClient::UPDATE_RESULT_NOTIMPLEMENTED)
    252     callback_.Run(UPDATED, 0, base::string16());
    253 }
    254