version_updater_chromeos.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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
28using chromeos::CrosSettings;
29using chromeos::DBusThreadManager;
30using chromeos::UpdateEngineClient;
31using chromeos::UserManager;
32using chromeos::WizardController;
33
34namespace {
35
36// Network status in the context of device update.
37enum 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
46const bool kDefaultAutoUpdateDisabled = false;
47
48NetworkStatus 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.
64bool 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
78VersionUpdater* VersionUpdater::Create() {
79  return new VersionUpdaterCros;
80}
81
82void 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
125void VersionUpdaterCros::RelaunchBrowser() const {
126  DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
127}
128
129void 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
139void 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
148VersionUpdaterCros::VersionUpdaterCros()
149    : last_operation_(UpdateEngineClient::UPDATE_STATUS_IDLE),
150      weak_ptr_factory_(this) {
151}
152
153VersionUpdaterCros::~VersionUpdaterCros() {
154  UpdateEngineClient* update_engine_client =
155      DBusThreadManager::Get()->GetUpdateEngineClient();
156  update_engine_client->RemoveObserver(this);
157}
158
159void 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      // This path previously used the FAILED status and IDS_UPGRADE_ERROR, but
179      // the update engine reports errors for some conditions that shouldn't
180      // actually be displayed as errors to users: http://crbug.com/146919.
181      // Just use the UPDATED status instead.
182      break;
183    case UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE:
184      my_status = CHECKING;
185      break;
186    case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING:
187      progress = static_cast<int>(round(status.download_progress * 100));
188      // Fall through.
189    case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE:
190      my_status = UPDATING;
191      break;
192    case UpdateEngineClient::UPDATE_STATUS_VERIFYING:
193    case UpdateEngineClient::UPDATE_STATUS_FINALIZING:
194      // Once the download is finished, keep the progress at 100; it shouldn't
195      // go down while the status is the same.
196      progress = 100;
197      my_status = UPDATING;
198      break;
199    case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT:
200      my_status = NEARLY_UPDATED;
201      break;
202    default:
203      break;
204  }
205
206  callback_.Run(my_status, progress, message);
207  last_operation_ = status.status;
208}
209
210void VersionUpdaterCros::OnUpdateCheck(
211    UpdateEngineClient::UpdateCheckResult result) {
212  // If version updating is not implemented, this binary is the most up-to-date
213  // possible with respect to automatic updating.
214  if (result == UpdateEngineClient::UPDATE_RESULT_NOTIMPLEMENTED)
215    callback_.Run(UPDATED, 0, base::string16());
216}
217