Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/memory/ref_counted.h" | |
| 6 #include "base/memory/scoped_ptr.h" | |
| 7 #include "base/memory/weak_ptr.h" | 5 #include "base/memory/weak_ptr.h" |
| 8 #include "base/strings/string16.h" | 6 #include "base/strings/string16.h" |
| 9 #include "base/version.h" | |
| 10 #include "base/win/win_util.h" | 7 #include "base/win/win_util.h" |
| 11 #include "base/win/windows_version.h" | 8 #include "base/win/windows_version.h" |
| 9 #include "chrome/browser/browser_process.h" | |
| 10 #include "chrome/browser/first_run/upgrade_util_win.h" | |
| 12 #include "chrome/browser/google/google_update_win.h" | 11 #include "chrome/browser/google/google_update_win.h" |
| 13 #include "chrome/browser/lifetime/application_lifetime.h" | 12 #include "chrome/browser/lifetime/application_lifetime.h" |
| 14 #include "chrome/browser/ui/browser.h" | |
| 15 #include "chrome/browser/ui/webui/help/version_updater.h" | 13 #include "chrome/browser/ui/webui/help/version_updater.h" |
| 16 #include "chrome/common/chrome_version_info.h" | |
| 17 #include "chrome/grit/chromium_strings.h" | |
| 18 #include "chrome/grit/generated_resources.h" | 14 #include "chrome/grit/generated_resources.h" |
| 19 #include "chrome/installer/util/browser_distribution.h" | |
| 20 #include "chrome/installer/util/install_util.h" | |
| 21 #include "content/public/browser/browser_thread.h" | 15 #include "content/public/browser/browser_thread.h" |
| 22 #include "ui/base/l10n/l10n_util.h" | 16 #include "ui/base/l10n/l10n_util.h" |
| 23 #include "ui/gfx/native_widget_types.h" | 17 #include "ui/gfx/native_widget_types.h" |
| 24 #include "ui/views/widget/widget.h" | |
| 25 | |
| 26 using content::BrowserThread; | |
| 27 | 18 |
| 28 namespace { | 19 namespace { |
| 29 | 20 |
| 21 // An EnumThreadWndProc that returns the first visible window via |param|, | |
| 22 // stopping the enumeration when one is found. | |
| 23 BOOL CALLBACK WindowEnumeration(HWND window, LPARAM param) { | |
| 24 if (!IsWindowVisible(window)) | |
| 25 return TRUE; | |
| 26 HWND* returned_window = reinterpret_cast<HWND*>(param); | |
|
Peter Kasting
2015/05/09 02:19:02
Nit: I'd probably just inline this into the next l
grt (UTC plus 2)
2015/05/12 20:21:52
Done.
| |
| 27 *returned_window = window; | |
| 28 return FALSE; | |
| 29 } | |
| 30 | |
| 31 // Returns a visible Chrome Window, or null if none is found. | |
| 32 gfx::AcceleratedWidget FindVisibleWindow() { | |
| 33 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 34 HWND window = nullptr; | |
| 35 EnumThreadWindows(GetCurrentThreadId(), &WindowEnumeration, | |
|
Peter Kasting
2015/05/09 02:19:02
It makes me uncomfortable to have Windows calls do
grt (UTC plus 2)
2015/05/12 20:21:52
Done. There's a slight change in behavior, but aft
| |
| 36 reinterpret_cast<LPARAM>(&window)); | |
| 37 return window; | |
| 38 } | |
| 39 | |
| 30 // Windows implementation of version update functionality, used by the WebUI | 40 // Windows implementation of version update functionality, used by the WebUI |
| 31 // About/Help page. | 41 // About/Help page. |
| 32 class VersionUpdaterWin : public VersionUpdater { | 42 class VersionUpdaterWin : public VersionUpdater, public UpdateCheckDelegate { |
| 33 private: | 43 public: |
| 34 friend class VersionReader; | |
| 35 friend class VersionUpdater; | |
| 36 | |
| 37 // Clients must use VersionUpdater::Create(). | |
| 38 VersionUpdaterWin(); | 44 VersionUpdaterWin(); |
| 39 ~VersionUpdaterWin() override; | 45 ~VersionUpdaterWin() override; |
| 40 | 46 |
| 41 // VersionUpdater implementation. | 47 // VersionUpdater |
|
Peter Kasting
2015/05/09 02:19:02
Tiny nit: I'd put a colon after these base class n
grt (UTC plus 2)
2015/05/12 20:21:52
Done.
| |
| 42 void CheckForUpdate(const StatusCallback& callback) override; | 48 void CheckForUpdate(const StatusCallback& callback) override; |
| 43 void RelaunchBrowser() const override; | 49 void RelaunchBrowser() const override; |
| 44 | 50 |
| 45 // chrome::UpdateCheckCallback. | 51 // UpdateCheckDelegate |
| 46 void OnUpdateCheckResults(GoogleUpdateUpgradeResult result, | 52 void OnUpdateCheckComplete(const base::string16& new_version) override; |
| 47 GoogleUpdateErrorCode error_code, | 53 void OnUpgradeProgress(int progress, |
| 48 const base::string16& error_message, | 54 const base::string16& new_version) override; |
| 49 const base::string16& version); | 55 void OnUpgradeComplete(const base::string16& new_version) override; |
| 56 void OnError(GoogleUpdateErrorCode error_code, | |
| 57 const base::string16& error_message, | |
| 58 const base::string16& new_version) override; | |
| 50 | 59 |
| 51 // Update the UI to show the status of the upgrade. | 60 private: |
| 52 void UpdateStatus(GoogleUpdateUpgradeResult result, | |
| 53 GoogleUpdateErrorCode error_code, | |
| 54 const base::string16& error_message); | |
| 55 | |
| 56 // Got the intalled version so the handling of the UPGRADE_ALREADY_UP_TO_DATE | |
| 57 // result case can now be completeb on the UI thread. | |
| 58 void GotInstalledVersion(const Version& version); | |
| 59 | |
| 60 // Returns a window that can be used for elevation. | |
| 61 gfx::AcceleratedWidget GetElevationParent(); | |
| 62 | |
| 63 void BeginUpdateCheckOnFileThread(bool install_if_newer); | 61 void BeginUpdateCheckOnFileThread(bool install_if_newer); |
|
Peter Kasting
2015/05/09 02:19:02
Nit: Probably want to change the name of |install_
grt (UTC plus 2)
2015/05/12 20:21:52
Done.
| |
| 64 | 62 |
| 65 // Callback used to communicate update status to the client. | 63 // Callback used to communicate update status to the client. |
| 66 StatusCallback callback_; | 64 StatusCallback callback_; |
| 67 | 65 |
| 68 // Used for callbacks. | 66 // Used for callbacks. |
| 69 base::WeakPtrFactory<VersionUpdaterWin> weak_factory_; | 67 base::WeakPtrFactory<VersionUpdaterWin> weak_factory_; |
| 70 | 68 |
| 71 DISALLOW_COPY_AND_ASSIGN(VersionUpdaterWin); | 69 DISALLOW_COPY_AND_ASSIGN(VersionUpdaterWin); |
| 72 }; | 70 }; |
| 73 | 71 |
| 74 // This class is used to read the version on the FILE thread and then call back | |
| 75 // the version updater in the UI thread. Using a class helps better control | |
| 76 // the lifespan of the Version independently of the lifespan of the version | |
| 77 // updater, which may die while asynchonicity is happening, thus the usage of | |
| 78 // the WeakPtr, which can only be used from the thread that created it. | |
| 79 class VersionReader | |
| 80 : public base::RefCountedThreadSafe<VersionReader> { | |
| 81 public: | |
| 82 explicit VersionReader( | |
| 83 const base::WeakPtr<VersionUpdaterWin>& version_updater) | |
| 84 : version_updater_(version_updater) { | |
| 85 } | |
| 86 | |
| 87 void GetVersionFromFileThread() { | |
| 88 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | |
| 89 InstallUtil::GetChromeVersion(dist, false, &installed_version_); | |
| 90 if (!installed_version_.IsValid()) { | |
| 91 // User-level Chrome is not installed, check system-level. | |
| 92 InstallUtil::GetChromeVersion(dist, true, &installed_version_); | |
| 93 } | |
| 94 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | |
| 95 &VersionReader::SetVersionInUIThread, this)); | |
| 96 } | |
| 97 | |
| 98 void SetVersionInUIThread() { | |
| 99 if (version_updater_.get() != NULL) | |
| 100 version_updater_->GotInstalledVersion(installed_version_); | |
| 101 } | |
| 102 | |
| 103 private: | |
| 104 friend class base::RefCountedThreadSafe<VersionReader>; | |
| 105 | |
| 106 ~VersionReader() {} | |
| 107 | |
| 108 // The version updater that must be called back when we are done. | |
| 109 // We use a weak pointer in case the updater gets destroyed while waiting. | |
| 110 base::WeakPtr<VersionUpdaterWin> version_updater_; | |
| 111 | |
| 112 // This is the version that gets read in the FILE thread and set on the | |
| 113 // the updater in the UI thread. | |
| 114 Version installed_version_; | |
| 115 }; | |
| 116 | |
| 117 VersionUpdaterWin::VersionUpdaterWin() | 72 VersionUpdaterWin::VersionUpdaterWin() |
| 118 : weak_factory_(this) { | 73 : weak_factory_(this) { |
| 119 } | 74 } |
| 120 | 75 |
| 121 VersionUpdaterWin::~VersionUpdaterWin() { | 76 VersionUpdaterWin::~VersionUpdaterWin() { |
| 122 } | 77 } |
| 123 | 78 |
| 124 void VersionUpdaterWin::CheckForUpdate(const StatusCallback& callback) { | 79 void VersionUpdaterWin::CheckForUpdate(const StatusCallback& callback) { |
| 125 callback_ = callback; | 80 callback_ = callback; |
| 126 | 81 |
| 127 // On-demand updates for Chrome don't work in Vista RTM when UAC is turned | 82 // On-demand updates for Chrome don't work in Vista RTM when UAC is turned |
| 128 // off. So, in this case, the version updater must not mention | 83 // off. So, in this case, the version updater must not mention |
| 129 // on-demand updates. Silent updates (in the background) should still | 84 // on-demand updates. Silent updates (in the background) should still |
| 130 // work as before - enabling UAC or installing the latest service pack | 85 // work as before - enabling UAC or installing the latest service pack |
| 131 // for Vista is another option. | 86 // for Vista is another option. |
| 132 if (!(base::win::GetVersion() == base::win::VERSION_VISTA && | 87 if (!(base::win::GetVersion() == base::win::VERSION_VISTA && |
| 133 (base::win::OSInfo::GetInstance()->service_pack().major == 0) && | 88 (base::win::OSInfo::GetInstance()->service_pack().major == 0) && |
| 134 !base::win::UserAccountControlIsEnabled())) { | 89 !base::win::UserAccountControlIsEnabled())) { |
| 135 UpdateStatus(UPGRADE_CHECK_STARTED, GOOGLE_UPDATE_NO_ERROR, | 90 callback_.Run(CHECKING, 0, base::string16()); |
| 136 base::string16()); | 91 BeginUpdateCheckOnFileThread(false /* !install_if_newer */); |
|
Peter Kasting
2015/05/09 02:19:02
Nit: I'm not in love with these comments when ther
grt (UTC plus 2)
2015/05/12 20:21:52
I've been asked by other reviewers to add these co
| |
| 137 // Specify false to not upgrade yet. | |
| 138 BeginUpdateCheckOnFileThread(false); | |
| 139 } | 92 } |
| 140 } | 93 } |
| 141 | 94 |
| 142 void VersionUpdaterWin::RelaunchBrowser() const { | 95 void VersionUpdaterWin::RelaunchBrowser() const { |
| 143 chrome::AttemptRestart(); | 96 chrome::AttemptRestart(); |
| 144 } | 97 } |
| 145 | 98 |
| 146 void VersionUpdaterWin::OnUpdateCheckResults( | 99 void VersionUpdaterWin::OnUpdateCheckComplete( |
| 147 GoogleUpdateUpgradeResult result, | 100 const base::string16& new_version) { |
| 148 GoogleUpdateErrorCode error_code, | 101 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 149 const base::string16& error_message, | 102 Status status = CHECKING; |
| 150 const base::string16& version) { | 103 if (new_version.empty()) { |
| 151 UpdateStatus(result, error_code, error_message); | 104 // Google Update says that no new version is available. Check to see if a |
| 105 // restart is needed for it to take effect. | |
|
Peter Kasting
2015/05/09 02:19:02
Nit: Maybe "Check if we need to restart to pick up
grt (UTC plus 2)
2015/05/12 20:21:52
Done.
| |
| 106 status = upgrade_util::IsRunningOldChrome() ? NEARLY_UPDATED : UPDATED; | |
| 107 } else { | |
| 108 // Notify the caller that the update is now beginning and initiate it. | |
| 109 status = UPDATING; | |
| 110 BeginUpdateCheckOnFileThread(true /* install_if_newer */); | |
| 111 } | |
| 112 callback_.Run(status, 0, base::string16()); | |
| 152 } | 113 } |
| 153 | 114 |
| 154 void VersionUpdaterWin::UpdateStatus(GoogleUpdateUpgradeResult result, | 115 void VersionUpdaterWin::OnUpgradeProgress(int progress, |
| 155 GoogleUpdateErrorCode error_code, | 116 const base::string16& new_version) { |
| 156 const base::string16& error_message) { | 117 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 157 // For Chromium builds it would show an error message. | 118 callback_.Run(UPDATING, progress, base::string16()); |
| 158 // But it looks weird because in fact there is no error, | 119 } |
| 159 // just the update server is not available for non-official builds. | 120 |
| 121 void VersionUpdaterWin::OnUpgradeComplete(const base::string16& new_version) { | |
| 122 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 123 callback_.Run(NEARLY_UPDATED, 0, base::string16()); | |
| 124 } | |
| 125 | |
| 126 void VersionUpdaterWin::OnError(GoogleUpdateErrorCode error_code, | |
| 127 const base::string16& error_message, | |
| 128 const base::string16& new_version) { | |
| 129 // Chromium builds will unconditionally get a | |
| 130 // CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY error since there is no supported | |
| 131 // integration with Google Update for Chromium. Ignore the error notification | |
| 132 // so that the spinner just spins rather than show an error message when there | |
|
Peter Kasting
2015/05/09 02:19:02
Nit: showing
grt (UTC plus 2)
2015/05/12 20:21:52
Done.
| |
| 133 // is, in fact, no error. | |
|
Peter Kasting
2015/05/09 02:19:02
Is there a way to not spin but instead show the "n
grt (UTC plus 2)
2015/05/12 20:21:52
I make a chromium-branded build and found that I w
| |
| 160 #if defined(GOOGLE_CHROME_BUILD) | 134 #if defined(GOOGLE_CHROME_BUILD) |
| 161 Status status = UPDATED; | 135 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 162 base::string16 message; | 136 base::string16 message; |
| 163 | 137 |
| 164 switch (result) { | 138 // Google Update provides a nice message for the policy case. Use this |
|
Peter Kasting
2015/05/09 02:19:02
Nit: "usually provides"? (If it always provided t
grt (UTC plus 2)
2015/05/12 20:21:52
Just being defensive here. I don't believe Google
| |
| 165 case UPGRADE_CHECK_STARTED: { | 139 // generic error for the policy case only if no message from Google Update |
| 166 status = CHECKING; | 140 // is present. |
| 167 break; | 141 if (error_code != GOOGLE_UPDATE_DISABLED_BY_POLICY || error_message.empty()) |
| 168 } | 142 message = l10n_util::GetStringFUTF16Int(IDS_UPGRADE_ERROR, error_code); |
| 169 case UPGRADE_STARTED: { | |
| 170 status = UPDATING; | |
| 171 break; | |
| 172 } | |
| 173 case UPGRADE_IS_AVAILABLE: { | |
| 174 UpdateStatus(UPGRADE_STARTED, GOOGLE_UPDATE_NO_ERROR, base::string16()); | |
| 175 // Specify true to upgrade now. | |
| 176 BeginUpdateCheckOnFileThread(true); | |
| 177 return; | |
| 178 } | |
| 179 case UPGRADE_ALREADY_UP_TO_DATE: { | |
| 180 // Google Update reported that Chrome is up-to-date. | |
| 181 // To confirm the updated version is running, the reading | |
| 182 // must be done on the file thread. The rest of this case | |
| 183 // will be handled within GotInstalledVersion. | |
| 184 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind( | |
| 185 &VersionReader::GetVersionFromFileThread, | |
| 186 new VersionReader(weak_factory_.GetWeakPtr()))); | |
| 187 return; | |
| 188 } | |
| 189 case UPGRADE_SUCCESSFUL: { | |
| 190 status = NEARLY_UPDATED; | |
| 191 break; | |
| 192 } | |
| 193 case UPGRADE_ERROR: { | |
| 194 status = FAILED; | |
| 195 if (error_code == GOOGLE_UPDATE_DISABLED_BY_POLICY) { | |
| 196 message = | |
| 197 l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY); | |
| 198 } else if (error_code == GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY) { | |
| 199 message = | |
| 200 l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY_MANUAL); | |
| 201 } else { | |
| 202 message = | |
| 203 l10n_util::GetStringFUTF16Int(IDS_UPGRADE_ERROR, error_code); | |
| 204 } | |
| 205 | 143 |
| 206 if (!error_message.empty()) { | 144 if (!error_message.empty()) { |
| 207 message += | 145 message += l10n_util::GetStringFUTF16( |
| 208 l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_DURING_UPDATE_CHECK, | 146 IDS_ABOUT_BOX_ERROR_DURING_UPDATE_CHECK, error_message); |
| 209 error_message); | |
| 210 } | |
| 211 break; | |
| 212 } | |
| 213 } | 147 } |
| 214 | 148 callback_.Run(FAILED, 0, message); |
| 215 // TODO(mad): Get proper progress value instead of passing 0. | 149 #endif |
| 216 // http://crbug.com/136117 | |
| 217 callback_.Run(status, 0, message); | |
| 218 #endif // defined(GOOGLE_CHROME_BUILD) | |
| 219 } | |
| 220 | |
| 221 void VersionUpdaterWin::GotInstalledVersion(const Version& version) { | |
| 222 // This must be called on the UI thread so that callback_ can be called. | |
| 223 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 224 | |
| 225 // Make sure that the latest version is running and if not, | |
| 226 // notify the user by setting the status to NEARLY_UPDATED. | |
| 227 // | |
| 228 // The extra version check is necessary on Windows because the application | |
| 229 // may be already up to date on disk though the running app is still | |
| 230 // out of date. | |
| 231 chrome::VersionInfo version_info; | |
| 232 Version running_version(version_info.Version()); | |
| 233 callback_.Run((version.IsValid() && version.CompareTo(running_version) > 0) | |
| 234 ? NEARLY_UPDATED | |
| 235 : UPDATED, | |
| 236 0, | |
| 237 base::string16()); | |
| 238 } | |
| 239 | |
| 240 BOOL CALLBACK WindowEnumeration(HWND window, LPARAM param) { | |
| 241 if (IsWindowVisible(window)) { | |
| 242 HWND* returned_window = reinterpret_cast<HWND*>(param); | |
| 243 *returned_window = window; | |
| 244 return FALSE; | |
| 245 } | |
| 246 return TRUE; | |
| 247 } | |
| 248 | |
| 249 gfx::AcceleratedWidget VersionUpdaterWin::GetElevationParent() { | |
| 250 // Look for a visible window belonging to the UI thread. | |
| 251 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 252 HWND window = NULL; | |
| 253 EnumThreadWindows(GetCurrentThreadId(), | |
| 254 WindowEnumeration, | |
| 255 reinterpret_cast<LPARAM>(&window)); | |
| 256 return window; | |
| 257 } | 150 } |
| 258 | 151 |
| 259 void VersionUpdaterWin::BeginUpdateCheckOnFileThread(bool install_if_newer) { | 152 void VersionUpdaterWin::BeginUpdateCheckOnFileThread(bool install_if_newer) { |
| 260 scoped_refptr<base::TaskRunner> task_runner( | 153 BeginUpdateCheck(content::BrowserThread::GetMessageLoopProxyForThread( |
| 261 content::BrowserThread::GetMessageLoopProxyForThread( | 154 content::BrowserThread::FILE), |
| 262 content::BrowserThread::FILE)); | 155 g_browser_process->GetApplicationLocale(), install_if_newer, |
| 263 BeginUpdateCheck(task_runner, install_if_newer, GetElevationParent(), | 156 FindVisibleWindow(), weak_factory_.GetWeakPtr()); |
| 264 base::Bind(&VersionUpdaterWin::OnUpdateCheckResults, | |
| 265 weak_factory_.GetWeakPtr())); | |
| 266 } | 157 } |
| 267 | 158 |
| 268 } // namespace | 159 } // namespace |
| 269 | 160 |
| 270 VersionUpdater* VersionUpdater::Create(content::BrowserContext* /* context */) { | 161 VersionUpdater* VersionUpdater::Create(content::BrowserContext* /* context */) { |
| 271 return new VersionUpdaterWin; | 162 return new VersionUpdaterWin; |
| 272 } | 163 } |
| OLD | NEW |