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