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