version_updater_chromeos.cc revision a36e5920737c6adbddd3e43b760e5de8431db6e0
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/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/chromeos/settings/cros_settings_names.h"
17#include "chrome/browser/policy/browser_policy_connector.h"
18#include "chrome/browser/ui/webui/help/help_utils_chromeos.h"
19#include "chromeos/dbus/dbus_thread_manager.h"
20#include "chromeos/dbus/power_manager_client.h"
21#include "chromeos/network/network_handler.h"
22#include "chromeos/network/network_state.h"
23#include "chromeos/network/network_state_handler.h"
24#include "grit/chromium_strings.h"
25#include "grit/generated_resources.h"
26#include "third_party/cros_system_api/dbus/service_constants.h"
27#include "ui/base/l10n/l10n_util.h"
28
29using chromeos::CrosSettings;
30using chromeos::DBusThreadManager;
31using chromeos::UpdateEngineClient;
32using chromeos::UserManager;
33using chromeos::WizardController;
34
35namespace {
36
37// Network status in the context of device update.
38enum NetworkStatus {
39  // It's allowed in device policy to use current network for update.
40  NETWORK_STATUS_ALLOWED = 0,
41  // It's disallowed in device policy to use current network for update.
42  NETWORK_STATUS_DISALLOWED,
43  // Device is in offline state.
44  NETWORK_STATUS_OFFLINE
45};
46
47const bool kDefaultAutoUpdateDisabled = false;
48
49NetworkStatus GetNetworkStatus(const chromeos::NetworkState* network) {
50  if (!network || !network->IsConnectedState())  // Offline state.
51    return NETWORK_STATUS_OFFLINE;
52
53  // The connection type checking strategy must be the same as the one
54  // used in update engine.
55  if (network->type() == flimflam::kTypeBluetooth)
56    return NETWORK_STATUS_DISALLOWED;
57  if (network->type() == flimflam::kTypeCellular &&
58      !help_utils_chromeos::IsUpdateOverCellularAllowed()) {
59    return NETWORK_STATUS_DISALLOWED;
60  }
61  return NETWORK_STATUS_ALLOWED;
62}
63
64// Returns true if auto-update is disabled by the system administrator.
65bool IsAutoUpdateDisabled() {
66  bool update_disabled = kDefaultAutoUpdateDisabled;
67  chromeos::CrosSettings* settings = chromeos::CrosSettings::Get();
68  if (!settings)
69    return update_disabled;
70  const base::Value* update_disabled_value =
71      settings->GetPref(chromeos::kUpdateDisabled);
72  if (update_disabled_value)
73    CHECK(update_disabled_value->GetAsBoolean(&update_disabled));
74  return update_disabled;
75}
76
77}  // namespace
78
79VersionUpdater* VersionUpdater::Create() {
80  return new VersionUpdaterCros;
81}
82
83void VersionUpdaterCros::CheckForUpdate(const StatusCallback& callback) {
84  callback_ = callback;
85
86  if (IsAutoUpdateDisabled()) {
87    callback_.Run(FAILED, 0,
88                  l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY));
89    return;
90  }
91
92  chromeos::NetworkStateHandler* network_state_handler =
93      chromeos::NetworkHandler::Get()->network_state_handler();
94  const chromeos::NetworkState* network =
95      network_state_handler->DefaultNetwork();
96
97  // Don't proceed to update if we're currently offline or connected
98  // to a network for which updates are disallowed.
99  NetworkStatus status = GetNetworkStatus(network);
100  if (status == NETWORK_STATUS_OFFLINE) {
101    callback_.Run(FAILED_OFFLINE, 0,
102                  l10n_util::GetStringUTF16(IDS_UPGRADE_OFFLINE));
103    return;
104  } else if (status == NETWORK_STATUS_DISALLOWED) {
105    string16 message =
106        l10n_util::GetStringFUTF16(
107            IDS_UPGRADE_DISALLOWED,
108            help_utils_chromeos::GetConnectionTypeAsUTF16(network->type()));
109    callback_.Run(FAILED_CONNECTION_TYPE_DISALLOWED, 0, message);
110    return;
111  }
112
113  UpdateEngineClient* update_engine_client =
114      DBusThreadManager::Get()->GetUpdateEngineClient();
115  update_engine_client->AddObserver(this);
116
117  // Make sure that libcros is loaded and OOBE is complete.
118  if (!WizardController::default_controller() ||
119      chromeos::StartupUtils::IsDeviceRegistered()) {
120    update_engine_client->RequestUpdateCheck(
121        base::Bind(&VersionUpdaterCros::OnUpdateCheck,
122                   weak_ptr_factory_.GetWeakPtr()));
123  }
124}
125
126void VersionUpdaterCros::RelaunchBrowser() const {
127  DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
128}
129
130void VersionUpdaterCros::SetChannel(const std::string& channel,
131                                    bool is_powerwash_allowed) {
132  if (UserManager::Get()->IsCurrentUserOwner()) {
133    // For local owner set the field in the policy blob.
134    CrosSettings::Get()->SetString(chromeos::kReleaseChannel, channel);
135  }
136  DBusThreadManager::Get()->GetUpdateEngineClient()->
137      SetChannel(channel, is_powerwash_allowed);
138}
139
140void VersionUpdaterCros::GetChannel(bool get_current_channel,
141                                    const ChannelCallback& cb) {
142  UpdateEngineClient* update_engine_client =
143      DBusThreadManager::Get()->GetUpdateEngineClient();
144
145  // Request the channel information.
146  update_engine_client->GetChannel(get_current_channel, cb);
147}
148
149VersionUpdaterCros::VersionUpdaterCros()
150    : last_operation_(UpdateEngineClient::UPDATE_STATUS_IDLE),
151      weak_ptr_factory_(this) {
152}
153
154VersionUpdaterCros::~VersionUpdaterCros() {
155  UpdateEngineClient* update_engine_client =
156      DBusThreadManager::Get()->GetUpdateEngineClient();
157  update_engine_client->RemoveObserver(this);
158}
159
160void VersionUpdaterCros::UpdateStatusChanged(
161    const UpdateEngineClient::Status& status) {
162  Status my_status = UPDATED;
163  int progress = 0;
164  string16 message;
165
166  // If the updater is currently idle, just show the last operation (unless it
167  // was previously checking for an update -- in that case, the system is
168  // up-to-date now).  See http://crbug.com/120063 for details.
169  UpdateEngineClient::UpdateStatusOperation operation_to_show = status.status;
170  if (status.status == UpdateEngineClient::UPDATE_STATUS_IDLE &&
171      last_operation_ !=
172      UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE) {
173    operation_to_show = last_operation_;
174  }
175
176  switch (operation_to_show) {
177    case UpdateEngineClient::UPDATE_STATUS_ERROR:
178    case UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT:
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
211void 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, string16());
217}
218