summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/webui/help/version_updater_win.cc
blob: b62c7afed5bf1c694509b0dbbbf7b9ff55c952c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "base/task_runner_util.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/first_run/upgrade_util.h"
#include "chrome/browser/google/google_update_win.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/ui/webui/help/version_updater.h"
#include "chrome/grit/generated_resources.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/native_widget_types.h"

namespace {

// Windows implementation of version update functionality, used by the WebUI
// About/Help page.
class VersionUpdaterWin : public VersionUpdater, public UpdateCheckDelegate {
 public:
  // |owner_widget| is the parent widget hosting the update check UI. Any UI
  // needed to install an update (e.g., a UAC prompt for a system-level install)
  // will be parented to this widget.
  explicit VersionUpdaterWin(gfx::AcceleratedWidget owner_widget);
  ~VersionUpdaterWin() override;

  // VersionUpdater:
  void CheckForUpdate(const StatusCallback& callback) override;
  void RelaunchBrowser() const override;

  // UpdateCheckDelegate:
  void OnUpdateCheckComplete(const base::string16& new_version) override;
  void OnUpgradeProgress(int progress,
                         const base::string16& new_version) override;
  void OnUpgradeComplete(const base::string16& new_version) override;
  void OnError(GoogleUpdateErrorCode error_code,
               const base::string16& error_message,
               const base::string16& new_version) override;

 private:
  void BeginUpdateCheckOnFileThread(bool install_update_if_possible);

  // A task run on the UI thread with the result of checking for a pending
  // restart.
  void OnPendingRestartCheck(bool is_update_pending_restart);

  // The widget owning the UI for the update check.
  gfx::AcceleratedWidget owner_widget_;

  // Callback used to communicate update status to the client.
  StatusCallback callback_;

  // Used for callbacks.
  base::WeakPtrFactory<VersionUpdaterWin> weak_factory_;

  DISALLOW_COPY_AND_ASSIGN(VersionUpdaterWin);
};

VersionUpdaterWin::VersionUpdaterWin(gfx::AcceleratedWidget owner_widget)
    : owner_widget_(owner_widget), weak_factory_(this) {
}

VersionUpdaterWin::~VersionUpdaterWin() {
}

void VersionUpdaterWin::CheckForUpdate(const StatusCallback& callback) {
  // There is no supported integration with Google Update for Chromium.
  callback_ = callback;

  // On-demand updates for Chrome don't work in Vista RTM when UAC is turned
  // off. So, in this case, the version updater must not mention
  // on-demand updates. Silent updates (in the background) should still
  // work as before - enabling UAC or installing the latest service pack
  // for Vista is another option.
  if (!(base::win::GetVersion() == base::win::VERSION_VISTA &&
        (base::win::OSInfo::GetInstance()->service_pack().major == 0) &&
        !base::win::UserAccountControlIsEnabled())) {
    callback_.Run(CHECKING, 0, base::string16());
    BeginUpdateCheckOnFileThread(false /* !install_update_if_possible */);
  }
}

void VersionUpdaterWin::RelaunchBrowser() const {
  chrome::AttemptRestart();
}

void VersionUpdaterWin::OnUpdateCheckComplete(
    const base::string16& new_version) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  Status status = CHECKING;
  if (new_version.empty()) {
    // Google Update says that no new version is available. Check to see if a
    // restart is needed for a previously-applied update to take effect.
    if (base::PostTaskAndReplyWithResult(
            content::BrowserThread::GetBlockingPool(),
            FROM_HERE,
            base::Bind(&upgrade_util::IsUpdatePendingRestart),
            base::Bind(&VersionUpdaterWin::OnPendingRestartCheck,
                       weak_factory_.GetWeakPtr()))) {
      // Early exit since callback_ will be Run in OnPendingRestartCheck.
      return;
    }
    // Failure to post the task means that Chrome is shutting down. A pending
    // update (if there is one) will be applied as Chrome exits, so tell the
    // caller that it is up to date in either case.
    status = UPDATED;
  } else {
    // Notify the caller that the update is now beginning and initiate it.
    status = UPDATING;
    BeginUpdateCheckOnFileThread(true /* install_update_if_possible */);
  }
  callback_.Run(status, 0, base::string16());
}

void VersionUpdaterWin::OnUpgradeProgress(int progress,
                                          const base::string16& new_version) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  callback_.Run(UPDATING, progress, base::string16());
}

void VersionUpdaterWin::OnUpgradeComplete(const base::string16& new_version) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  callback_.Run(NEARLY_UPDATED, 0, base::string16());
}

void VersionUpdaterWin::OnError(GoogleUpdateErrorCode error_code,
                                const base::string16& error_message,
                                const base::string16& new_version) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  base::string16 message;

  // Current versions of Google Update provide a nice message for the policy
  // case. Use this generic error for the policy case only if no message from
  // Google Update is present.
  if (error_code != GOOGLE_UPDATE_DISABLED_BY_POLICY || error_message.empty())
    message = l10n_util::GetStringFUTF16Int(IDS_UPGRADE_ERROR, error_code);

  if (!error_message.empty()) {
    message += l10n_util::GetStringFUTF16(
        IDS_ABOUT_BOX_ERROR_DURING_UPDATE_CHECK, error_message);
  }
  callback_.Run(FAILED, 0, message);
}

void VersionUpdaterWin::BeginUpdateCheckOnFileThread(
    bool install_update_if_possible) {
  BeginUpdateCheck(content::BrowserThread::GetMessageLoopProxyForThread(
                       content::BrowserThread::FILE),
                   g_browser_process->GetApplicationLocale(),
                   install_update_if_possible, owner_widget_,
                   weak_factory_.GetWeakPtr());
}

void VersionUpdaterWin::OnPendingRestartCheck(bool is_update_pending_restart) {
  callback_.Run(is_update_pending_restart ? NEARLY_UPDATED : UPDATED, 0,
                base::string16());
}

}  // namespace

VersionUpdater* VersionUpdater::Create(content::WebContents* web_contents) {
  // Retrieve the HWND for the browser window that is hosting the update check.
  // This will be used as the parent for a UAC prompt, if needed. It's possible
  // this this window will no longer have focus by the time UAC is needed. In
  // that case, the UAC prompt will appear in the taskbar and will require a
  // user click. This is the least surprising thing we can do for the user, and
  // is the intended behavior for Windows applications. It's also possible that
  // the browser window hosting the update check will have been closed by the
  // time the UAC prompt is needed. This will behave similarly.
  return new VersionUpdaterWin(web_contents->GetTopLevelNativeWindow()
                                   ->GetHost()
                                   ->GetAcceleratedWidget());
}