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
|
// Copyright 2012 The Chromium Authors
// 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.h"
#include <memory>
#include <string>
#include "base/functional/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/task/thread_pool.h"
#include "base/win/win_util.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/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. |owner_widget| may be given a value of
// nullptr in which case the UAC prompt will be parented to the desktop.
explicit VersionUpdaterWin(gfx::AcceleratedWidget owner_widget)
: owner_widget_(owner_widget), weak_factory_(this) {}
VersionUpdaterWin(const VersionUpdaterWin&) = delete;
VersionUpdaterWin& operator=(const VersionUpdaterWin&) = delete;
~VersionUpdaterWin() override = default;
// VersionUpdater:
void CheckForUpdate(StatusCallback callback, PromoteCallback) override {
// There is no supported integration with Google Update for Chromium.
callback_ = std::move(callback);
callback_.Run(CHECKING, 0, false, false, std::string(), 0,
std::u16string());
DoBeginUpdateCheck(false /* !install_update_if_possible */);
}
// UpdateCheckDelegate:
void OnUpdateCheckComplete(const std::u16string& new_version) override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
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.
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::BindOnce(&upgrade_util::IsUpdatePendingRestart),
base::BindOnce(&VersionUpdaterWin::OnPendingRestartCheck,
weak_factory_.GetWeakPtr()));
// Early exit since callback_ will be Run in OnPendingRestartCheck.
return;
}
// Notify the caller that the update is now beginning and initiate it.
DoBeginUpdateCheck(true /* install_update_if_possible */);
callback_.Run(UPDATING, 0, false, false, std::string(), 0,
std::u16string());
}
void OnUpgradeProgress(int progress,
const std::u16string& new_version) override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
callback_.Run(UPDATING, progress, false, false, std::string(), 0,
std::u16string());
}
void OnUpgradeComplete(const std::u16string& new_version) override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
callback_.Run(NEARLY_UPDATED, 0, false, false, std::string(), 0,
std::u16string());
}
void OnError(GoogleUpdateErrorCode error_code,
const std::u16string& html_error_message,
const std::u16string& new_version) override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::u16string 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, false, false, std::string(), 0, message);
}
private:
void DoBeginUpdateCheck(bool install_update_if_possible) {
// Disconnect from any previous attempts to avoid redundant callbacks.
weak_factory_.InvalidateWeakPtrs();
BeginUpdateCheck(g_browser_process->GetApplicationLocale(),
install_update_if_possible, owner_widget_,
weak_factory_.GetWeakPtr());
}
// A task run on the UI thread with the result of checking for a pending
// restart.
void OnPendingRestartCheck(bool is_update_pending_restart) {
callback_.Run(is_update_pending_restart ? NEARLY_UPDATED : UPDATED, 0,
false, false, std::string(), 0, std::u16string());
}
// 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_;
};
} // namespace
std::unique_ptr<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 std::make_unique<VersionUpdaterWin>(
window_tree_host ? window_tree_host->GetAcceleratedWidget() : nullptr);
}
|