blob: 1c869667d3f821aa2e5f93b0374f6fb6e4639aee [file] [log] [blame]
// 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 "chrome/browser/ui/webui/help/version_updater_win.h"
#include "base/memory/weak_ptr.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/lifetime/application_lifetime.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"
VersionUpdaterWin::VersionUpdaterWin(gfx::AcceleratedWidget owner_widget)
: owner_widget_(owner_widget), weak_factory_(this) {
}
VersionUpdaterWin::~VersionUpdaterWin() {
}
void VersionUpdaterWin::CheckForUpdate(const StatusCallback& callback,
const PromoteCallback&) {
// 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& html_error_message,
const base::string16& new_version) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
base::string16 message;
Status status = FAILED;
switch (error_code) {
case GOOGLE_UPDATE_DISABLED_BY_POLICY:
status = DISABLED_BY_ADMIN;
message =
l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY);
break;
case GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY:
status = DISABLED_BY_ADMIN;
message =
l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY_MANUAL);
break;
default:
// html_error_message mentions error_code so don't combine messages.
if (html_error_message.empty()) {
message = l10n_util::GetStringFUTF16Int(IDS_UPGRADE_ERROR, error_code);
} else {
message = l10n_util::GetStringFUTF16(
IDS_ABOUT_BOX_ERROR_DURING_UPDATE_CHECK, html_error_message);
}
break;
}
callback_.Run(status, 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());
}
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. In this case, the
// web contents may no longer be hosted in a window, leading either
// GetTopLevelNativeWindow or GetHost to return null. Passing nullptr to
// VersionUpdaterWin will then also cause the UAC prompt to appear in the task
// bar.
gfx::NativeWindow window = web_contents->GetTopLevelNativeWindow();
aura::WindowTreeHost* window_tree_host = window ? window->GetHost() : nullptr;
return new VersionUpdaterWin(
window_tree_host ? window_tree_host->GetAcceleratedWidget() : nullptr);
}