This source file includes following definitions.
- CanUpdateCurrentChrome
- CoCreateInstanceAsAdmin
- BEGIN_COM_MAP
- STDMETHOD
- STDMETHOD
- STDMETHOD
- STDMETHOD
- STDMETHOD
- STDMETHOD
- STDMETHOD
- STDMETHOD
- STDMETHOD
- STDMETHOD
- STDMETHOD
- STDMETHOD
- STDMETHOD
- CheckForUpdate
- InitiateGoogleUpdateCheck
- ReportResults
- ReportFailure
#include "chrome/browser/google/google_update_win.h"
#include <atlbase.h>
#include <atlcom.h>
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread.h"
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_settings.h"
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/install_util.h"
#include "content/public/browser/browser_thread.h"
#include "google_update/google_update_idl.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/win/atl_module.h"
#include "ui/views/widget/widget.h"
using content::BrowserThread;
namespace {
GoogleUpdateErrorCode CanUpdateCurrentChrome(
const base::FilePath& chrome_exe_path) {
#if !defined(GOOGLE_CHROME_BUILD)
return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
#else
BrowserDistribution* dist = BrowserDistribution::GetDistribution();
base::FilePath user_exe_path = installer::GetChromeInstallPath(false, dist);
base::FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist);
if (!base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
user_exe_path.value()) &&
!base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
machine_exe_path.value())) {
LOG(ERROR) << L"Google Update cannot update Chrome installed in a "
<< L"non-standard location: " << chrome_exe_path.value().c_str()
<< L". The standard location is: "
<< user_exe_path.value().c_str()
<< L" or " << machine_exe_path.value().c_str() << L".";
return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
}
base::string16 app_guid = installer::GetAppGuidForUpdates(
!InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str()));
DCHECK(!app_guid.empty());
GoogleUpdateSettings::UpdatePolicy update_policy =
GoogleUpdateSettings::GetAppUpdatePolicy(app_guid, NULL);
if (update_policy == GoogleUpdateSettings::UPDATES_DISABLED)
return GOOGLE_UPDATE_DISABLED_BY_POLICY;
if (update_policy == GoogleUpdateSettings::AUTO_UPDATES_ONLY)
return GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY;
return GOOGLE_UPDATE_NO_ERROR;
#endif
}
HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id,
HWND hwnd, void** interface_ptr) {
if (!interface_ptr)
return E_POINTER;
if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
wchar_t class_id_as_string[MAX_PATH] = {0};
StringFromGUID2(class_id, class_id_as_string,
arraysize(class_id_as_string));
base::string16 elevation_moniker_name =
base::StringPrintf(L"Elevation:Administrator!new:%ls",
class_id_as_string);
BIND_OPTS3 bind_opts;
memset(&bind_opts, 0, sizeof(bind_opts));
bind_opts.cbStruct = sizeof(bind_opts);
bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER;
bind_opts.hwnd = hwnd;
return CoGetObject(elevation_moniker_name.c_str(), &bind_opts,
interface_id, reinterpret_cast<void**>(interface_ptr));
}
return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER,
interface_id,
reinterpret_cast<void**>(interface_ptr));
}
}
class GoogleUpdateJobObserver
: public CComObjectRootEx<CComSingleThreadModel>,
public IJobObserver {
public:
BEGIN_COM_MAP(GoogleUpdateJobObserver)
COM_INTERFACE_ENTRY(IJobObserver)
END_COM_MAP()
GoogleUpdateJobObserver()
: result_(UPGRADE_ERROR) {
}
virtual ~GoogleUpdateJobObserver() {}
STDMETHOD(OnShow)() {
return S_OK;
}
STDMETHOD(OnCheckingForUpdate)() {
result_ = UPGRADE_CHECK_STARTED;
return S_OK;
}
STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) {
result_ = UPGRADE_IS_AVAILABLE;
new_version_ = version_string;
return S_OK;
}
STDMETHOD(OnWaitingToDownload)() {
return S_OK;
}
STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) {
return S_OK;
}
STDMETHOD(OnWaitingToInstall)() {
return S_OK;
}
STDMETHOD(OnInstalling)() {
result_ = UPGRADE_STARTED;
return S_OK;
}
STDMETHOD(OnPause)() {
return S_OK;
}
STDMETHOD(OnComplete)(LegacyCompletionCodes code, const TCHAR* text) {
switch (code) {
case COMPLETION_CODE_SUCCESS_CLOSE_UI:
case COMPLETION_CODE_SUCCESS: {
if (result_ == UPGRADE_STARTED)
result_ = UPGRADE_SUCCESSFUL;
else if (result_ == UPGRADE_CHECK_STARTED)
result_ = UPGRADE_ALREADY_UP_TO_DATE;
break;
}
case COMPLETION_CODE_ERROR:
error_message_ = text;
default: {
NOTREACHED();
result_ = UPGRADE_ERROR;
break;
}
}
event_sink_ = NULL;
base::MessageLoop::current()->Quit();
return S_OK;
}
STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) {
event_sink_ = event_sink;
return S_OK;
}
STDMETHOD(GetResult)(GoogleUpdateUpgradeResult* result) {
DCHECK(result_ != UPGRADE_STARTED && result_ != UPGRADE_CHECK_STARTED);
*result = result_;
return S_OK;
}
STDMETHOD(GetVersionInfo)(base::string16* version_string) {
*version_string = new_version_;
return S_OK;
}
STDMETHOD(GetErrorMessage)(base::string16* error_message) {
*error_message = error_message_;
return S_OK;
}
private:
GoogleUpdateUpgradeResult result_;
base::string16 new_version_;
base::string16 error_message_;
base::win::ScopedComPtr<IProgressWndEvents> event_sink_;
};
GoogleUpdate::GoogleUpdate()
: listener_(NULL) {
}
GoogleUpdate::~GoogleUpdate() {
}
void GoogleUpdate::CheckForUpdate(bool install_if_newer, HWND window) {
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
base::Bind(&GoogleUpdate::InitiateGoogleUpdateCheck, this,
install_if_newer, window, base::MessageLoop::current()));
}
void GoogleUpdate::InitiateGoogleUpdateCheck(bool install_if_newer,
HWND window,
base::MessageLoop* main_loop) {
base::FilePath chrome_exe;
if (!PathService::Get(base::DIR_EXE, &chrome_exe))
NOTREACHED();
GoogleUpdateErrorCode error_code = CanUpdateCurrentChrome(chrome_exe);
if (error_code != GOOGLE_UPDATE_NO_ERROR) {
main_loop->PostTask(
FROM_HERE,
base::Bind(&GoogleUpdate::ReportResults, this,
UPGRADE_ERROR, error_code, base::string16()));
return;
}
ui::win::CreateATLModuleIfNeeded();
CComObject<GoogleUpdateJobObserver>* job_observer;
HRESULT hr =
CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer);
if (hr != S_OK) {
GoogleUpdateErrorCode error = GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED;
base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr);
ReportFailure(
hr, error,
l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED,
error_code),
main_loop);
return;
}
base::win::ScopedComPtr<IJobObserver> job_holder(job_observer);
base::win::ScopedComPtr<IGoogleUpdate> on_demand;
bool system_level = false;
if (InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())) {
hr = on_demand.CreateInstance(CLSID_OnDemandUserAppsClass);
} else {
if (!install_if_newer) {
hr = on_demand.CreateInstance(CLSID_OnDemandMachineAppsClass);
} else {
hr = CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass,
IID_IGoogleUpdate, window,
reinterpret_cast<void**>(on_demand.Receive()));
}
system_level = true;
}
if (hr != S_OK) {
GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND;
base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr);
if (system_level)
error_code += L" -- system level";
ReportFailure(hr, error,
l10n_util::GetStringFUTF16(
IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED,
error_code),
main_loop);
return;
}
base::string16 app_guid = installer::GetAppGuidForUpdates(system_level);
DCHECK(!app_guid.empty());
if (!install_if_newer)
hr = on_demand->CheckForUpdate(app_guid.c_str(), job_observer);
else
hr = on_demand->Update(app_guid.c_str(), job_observer);
if (hr != S_OK) {
GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr);
ReportFailure(hr, error,
l10n_util::GetStringFUTF16(
IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED,
error_code),
main_loop);
return;
}
base::MessageLoop::current()->Run();
GoogleUpdateUpgradeResult results;
hr = job_observer->GetResult(&results);
if (hr != S_OK) {
GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_RESULT_CALL_FAILED;
base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr);
ReportFailure(hr, error,
l10n_util::GetStringFUTF16(
IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED,
error_code),
main_loop);
return;
}
if (results == UPGRADE_ERROR) {
base::string16 error_message;
job_observer->GetErrorMessage(&error_message);
ReportFailure(hr, GOOGLE_UPDATE_ERROR_UPDATING, error_message, main_loop);
return;
}
hr = job_observer->GetVersionInfo(&version_available_);
if (hr != S_OK) {
GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_VERSION_INFO_FAILED;
base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr);
ReportFailure(hr, error,
l10n_util::GetStringFUTF16(
IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED,
error_code),
main_loop);
return;
}
main_loop->PostTask(
FROM_HERE,
base::Bind(&GoogleUpdate::ReportResults, this,
results, GOOGLE_UPDATE_NO_ERROR, base::string16()));
job_holder = NULL;
on_demand = NULL;
}
void GoogleUpdate::ReportResults(GoogleUpdateUpgradeResult results,
GoogleUpdateErrorCode error_code,
const base::string16& error_message) {
DCHECK(results == UPGRADE_ERROR ? error_code != GOOGLE_UPDATE_NO_ERROR :
error_code == GOOGLE_UPDATE_NO_ERROR);
if (listener_) {
listener_->OnReportResults(
results, error_code, error_message, version_available_);
}
}
bool GoogleUpdate::ReportFailure(HRESULT hr,
GoogleUpdateErrorCode error_code,
const base::string16& error_message,
base::MessageLoop* main_loop) {
NOTREACHED() << "Communication with Google Update failed: " << hr
<< " error: " << error_code
<< ", message: " << error_message.c_str();
main_loop->PostTask(
FROM_HERE,
base::Bind(&GoogleUpdate::ReportResults, this,
UPGRADE_ERROR, error_code, error_message));
return false;
}