Home | History | Annotate | Download | only in google
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/google/google_update_win.h"
      6 
      7 #include <atlbase.h>
      8 #include <atlcom.h>
      9 
     10 #include "base/bind.h"
     11 #include "base/files/file_path.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/path_service.h"
     14 #include "base/strings/string_util.h"
     15 #include "base/strings/stringprintf.h"
     16 #include "base/threading/thread.h"
     17 #include "base/win/scoped_comptr.h"
     18 #include "base/win/windows_version.h"
     19 #include "chrome/installer/util/browser_distribution.h"
     20 #include "chrome/installer/util/google_update_settings.h"
     21 #include "chrome/installer/util/helper.h"
     22 #include "chrome/installer/util/install_util.h"
     23 #include "content/public/browser/browser_thread.h"
     24 #include "google_update/google_update_idl.h"
     25 #include "grit/generated_resources.h"
     26 #include "ui/base/l10n/l10n_util.h"
     27 #include "ui/base/win/atl_module.h"
     28 #include "ui/views/widget/widget.h"
     29 
     30 using content::BrowserThread;
     31 
     32 namespace {
     33 
     34 // Check if the currently running instance can be updated by Google Update.
     35 // Returns GOOGLE_UPDATE_NO_ERROR only if the instance running is a Google
     36 // Chrome distribution installed in a standard location.
     37 GoogleUpdateErrorCode CanUpdateCurrentChrome(
     38     const base::FilePath& chrome_exe_path) {
     39 #if !defined(GOOGLE_CHROME_BUILD)
     40   return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
     41 #else
     42   // TODO(tommi): Check if using the default distribution is always the right
     43   // thing to do.
     44   BrowserDistribution* dist = BrowserDistribution::GetDistribution();
     45   base::FilePath user_exe_path = installer::GetChromeInstallPath(false, dist);
     46   base::FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist);
     47   if (!base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
     48                                         user_exe_path.value()) &&
     49       !base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
     50                                         machine_exe_path.value())) {
     51     LOG(ERROR) << L"Google Update cannot update Chrome installed in a "
     52                << L"non-standard location: " << chrome_exe_path.value().c_str()
     53                << L". The standard location is: "
     54                    << user_exe_path.value().c_str()
     55                << L" or " << machine_exe_path.value().c_str() << L".";
     56     return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
     57   }
     58 
     59   base::string16 app_guid = installer::GetAppGuidForUpdates(
     60       !InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str()));
     61   DCHECK(!app_guid.empty());
     62 
     63   GoogleUpdateSettings::UpdatePolicy update_policy =
     64       GoogleUpdateSettings::GetAppUpdatePolicy(app_guid, NULL);
     65 
     66   if (update_policy == GoogleUpdateSettings::UPDATES_DISABLED)
     67     return GOOGLE_UPDATE_DISABLED_BY_POLICY;
     68 
     69   if (update_policy == GoogleUpdateSettings::AUTO_UPDATES_ONLY)
     70     return GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY;
     71 
     72   return GOOGLE_UPDATE_NO_ERROR;
     73 #endif
     74 }
     75 
     76 // Creates an instance of a COM Local Server class using either plain vanilla
     77 // CoCreateInstance, or using the Elevation moniker if running on Vista.
     78 // hwnd must refer to a foregound window in order to get the UAC prompt
     79 // showing up in the foreground if running on Vista. It can also be NULL if
     80 // background UAC prompts are desired.
     81 HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id,
     82                                 HWND hwnd, void** interface_ptr) {
     83   if (!interface_ptr)
     84     return E_POINTER;
     85 
     86   // For Vista, need to instantiate the COM server via the elevation
     87   // moniker. This ensures that the UAC dialog shows up.
     88   if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
     89     wchar_t class_id_as_string[MAX_PATH] = {0};
     90     StringFromGUID2(class_id, class_id_as_string,
     91                     arraysize(class_id_as_string));
     92 
     93     base::string16 elevation_moniker_name =
     94         base::StringPrintf(L"Elevation:Administrator!new:%ls",
     95                            class_id_as_string);
     96 
     97     BIND_OPTS3 bind_opts;
     98     memset(&bind_opts, 0, sizeof(bind_opts));
     99     bind_opts.cbStruct = sizeof(bind_opts);
    100     bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER;
    101     bind_opts.hwnd = hwnd;
    102 
    103     return CoGetObject(elevation_moniker_name.c_str(), &bind_opts,
    104                        interface_id, reinterpret_cast<void**>(interface_ptr));
    105   }
    106 
    107   return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER,
    108                           interface_id,
    109                           reinterpret_cast<void**>(interface_ptr));
    110 }
    111 
    112 
    113 }  // namespace
    114 
    115 // The GoogleUpdateJobObserver COM class is responsible for receiving status
    116 // reports from google Update. It keeps track of the progress as GoogleUpdate
    117 // notifies this observer and ends the message loop that is spinning in once
    118 // GoogleUpdate reports that it is done.
    119 class GoogleUpdateJobObserver
    120   : public CComObjectRootEx<CComSingleThreadModel>,
    121     public IJobObserver {
    122  public:
    123   BEGIN_COM_MAP(GoogleUpdateJobObserver)
    124     COM_INTERFACE_ENTRY(IJobObserver)
    125   END_COM_MAP()
    126 
    127   GoogleUpdateJobObserver()
    128     : result_(UPGRADE_ERROR) {
    129   }
    130   virtual ~GoogleUpdateJobObserver() {}
    131 
    132   // Notifications from Google Update:
    133   STDMETHOD(OnShow)() {
    134     return S_OK;
    135   }
    136   STDMETHOD(OnCheckingForUpdate)() {
    137     result_ = UPGRADE_CHECK_STARTED;
    138     return S_OK;
    139   }
    140   STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) {
    141     result_ = UPGRADE_IS_AVAILABLE;
    142     new_version_ = version_string;
    143     return S_OK;
    144   }
    145   STDMETHOD(OnWaitingToDownload)() {
    146     return S_OK;
    147   }
    148   STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) {
    149     return S_OK;
    150   }
    151   STDMETHOD(OnWaitingToInstall)() {
    152     return S_OK;
    153   }
    154   STDMETHOD(OnInstalling)() {
    155     result_ = UPGRADE_STARTED;
    156     return S_OK;
    157   }
    158   STDMETHOD(OnPause)() {
    159     return S_OK;
    160   }
    161   STDMETHOD(OnComplete)(LegacyCompletionCodes code, const TCHAR* text) {
    162     switch (code) {
    163       case COMPLETION_CODE_SUCCESS_CLOSE_UI:
    164       case COMPLETION_CODE_SUCCESS: {
    165         if (result_ == UPGRADE_STARTED)
    166           result_ = UPGRADE_SUCCESSFUL;
    167         else if (result_ == UPGRADE_CHECK_STARTED)
    168           result_ = UPGRADE_ALREADY_UP_TO_DATE;
    169         break;
    170       }
    171       case COMPLETION_CODE_ERROR:
    172         error_message_ = text;
    173       default: {
    174         NOTREACHED();
    175         result_ = UPGRADE_ERROR;
    176         break;
    177       }
    178     }
    179 
    180     event_sink_ = NULL;
    181 
    182     // No longer need to spin the message loop that started spinning in
    183     // InitiateGoogleUpdateCheck.
    184     base::MessageLoop::current()->Quit();
    185     return S_OK;
    186   }
    187   STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) {
    188     event_sink_ = event_sink;
    189     return S_OK;
    190   }
    191 
    192   // Returns the results of the update operation.
    193   STDMETHOD(GetResult)(GoogleUpdateUpgradeResult* result) {
    194     // Intermediary steps should never be reported to the client.
    195     DCHECK(result_ != UPGRADE_STARTED && result_ != UPGRADE_CHECK_STARTED);
    196 
    197     *result = result_;
    198     return S_OK;
    199   }
    200 
    201   // Returns which version Google Update found on the server (if a more
    202   // recent version was found). Otherwise, this will be blank.
    203   STDMETHOD(GetVersionInfo)(base::string16* version_string) {
    204     *version_string = new_version_;
    205     return S_OK;
    206   }
    207 
    208   // Returns the Google Update supplied error string that describes the error
    209   // that occurred during the update check/upgrade.
    210   STDMETHOD(GetErrorMessage)(base::string16* error_message) {
    211     *error_message = error_message_;
    212     return S_OK;
    213   }
    214 
    215  private:
    216   // The status/result of the Google Update operation.
    217   GoogleUpdateUpgradeResult result_;
    218 
    219   // The version string Google Update found.
    220   base::string16 new_version_;
    221 
    222   // An error message, if any.
    223   base::string16 error_message_;
    224 
    225   // Allows us control the upgrade process to a small degree. After OnComplete
    226   // has been called, this object can not be used.
    227   base::win::ScopedComPtr<IProgressWndEvents> event_sink_;
    228 };
    229 
    230 ////////////////////////////////////////////////////////////////////////////////
    231 // GoogleUpdate, public:
    232 
    233 GoogleUpdate::GoogleUpdate()
    234     : listener_(NULL) {
    235 }
    236 
    237 GoogleUpdate::~GoogleUpdate() {
    238 }
    239 
    240 void GoogleUpdate::CheckForUpdate(bool install_if_newer, HWND window) {
    241   // Need to shunt this request over to InitiateGoogleUpdateCheck and have
    242   // it run in the file thread.
    243   BrowserThread::PostTask(
    244       BrowserThread::FILE, FROM_HERE,
    245       base::Bind(&GoogleUpdate::InitiateGoogleUpdateCheck, this,
    246                  install_if_newer, window, base::MessageLoop::current()));
    247 }
    248 
    249 ////////////////////////////////////////////////////////////////////////////////
    250 // GoogleUpdate, private:
    251 
    252 void GoogleUpdate::InitiateGoogleUpdateCheck(bool install_if_newer,
    253                                              HWND window,
    254                                              base::MessageLoop* main_loop) {
    255   base::FilePath chrome_exe;
    256   if (!PathService::Get(base::DIR_EXE, &chrome_exe))
    257     NOTREACHED();
    258 
    259   GoogleUpdateErrorCode error_code = CanUpdateCurrentChrome(chrome_exe);
    260   if (error_code != GOOGLE_UPDATE_NO_ERROR) {
    261     main_loop->PostTask(
    262         FROM_HERE,
    263         base::Bind(&GoogleUpdate::ReportResults, this,
    264                    UPGRADE_ERROR, error_code, base::string16()));
    265     return;
    266   }
    267 
    268   // Make sure ATL is initialized in this module.
    269   ui::win::CreateATLModuleIfNeeded();
    270 
    271   CComObject<GoogleUpdateJobObserver>* job_observer;
    272   HRESULT hr =
    273       CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer);
    274   if (hr != S_OK) {
    275     // Most of the error messages come straight from Google Update. This one is
    276     // deemed worthy enough to also warrant its own error.
    277     GoogleUpdateErrorCode error = GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED;
    278     base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr);
    279     ReportFailure(
    280         hr, error,
    281         l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED,
    282                                    error_code),
    283         main_loop);
    284     return;
    285   }
    286 
    287   base::win::ScopedComPtr<IJobObserver> job_holder(job_observer);
    288 
    289   base::win::ScopedComPtr<IGoogleUpdate> on_demand;
    290 
    291   bool system_level = false;
    292 
    293   if (InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())) {
    294     hr = on_demand.CreateInstance(CLSID_OnDemandUserAppsClass);
    295   } else {
    296     // The Update operation needs Admin privileges for writing
    297     // to %ProgramFiles%. On Vista, need to elevate before instantiating
    298     // the updater instance.
    299     if (!install_if_newer) {
    300       hr = on_demand.CreateInstance(CLSID_OnDemandMachineAppsClass);
    301     } else {
    302       hr = CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass,
    303           IID_IGoogleUpdate, window,
    304           reinterpret_cast<void**>(on_demand.Receive()));
    305     }
    306     system_level = true;
    307   }
    308 
    309   if (hr != S_OK) {
    310     GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND;
    311     base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr);
    312     if (system_level)
    313       error_code += L" -- system level";
    314     ReportFailure(hr, error,
    315                   l10n_util::GetStringFUTF16(
    316                       IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED,
    317                       error_code),
    318                   main_loop);
    319     return;
    320   }
    321 
    322   base::string16 app_guid = installer::GetAppGuidForUpdates(system_level);
    323   DCHECK(!app_guid.empty());
    324 
    325   if (!install_if_newer)
    326     hr = on_demand->CheckForUpdate(app_guid.c_str(), job_observer);
    327   else
    328     hr = on_demand->Update(app_guid.c_str(), job_observer);
    329 
    330   if (hr != S_OK) {
    331     GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
    332     base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr);
    333     ReportFailure(hr, error,
    334                   l10n_util::GetStringFUTF16(
    335                       IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED,
    336                       error_code),
    337                   main_loop);
    338     return;
    339   }
    340 
    341   // Need to spin the message loop while Google Update is running so that it
    342   // can report back to us through GoogleUpdateJobObserver. This message loop
    343   // will terminate once Google Update sends us the completion status
    344   // (success/error). See OnComplete().
    345   base::MessageLoop::current()->Run();
    346 
    347   GoogleUpdateUpgradeResult results;
    348   hr = job_observer->GetResult(&results);
    349 
    350   if (hr != S_OK) {
    351     GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_RESULT_CALL_FAILED;
    352     base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr);
    353     ReportFailure(hr, error,
    354                   l10n_util::GetStringFUTF16(
    355                       IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED,
    356                       error_code),
    357                   main_loop);
    358     return;
    359   }
    360 
    361   if (results == UPGRADE_ERROR) {
    362     base::string16 error_message;
    363     job_observer->GetErrorMessage(&error_message);
    364     ReportFailure(hr, GOOGLE_UPDATE_ERROR_UPDATING, error_message, main_loop);
    365     return;
    366   }
    367 
    368   hr = job_observer->GetVersionInfo(&version_available_);
    369   if (hr != S_OK) {
    370     GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_VERSION_INFO_FAILED;
    371     base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr);
    372     ReportFailure(hr, error,
    373                   l10n_util::GetStringFUTF16(
    374                       IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED,
    375                       error_code),
    376                   main_loop);
    377     return;
    378   }
    379 
    380   main_loop->PostTask(
    381       FROM_HERE,
    382       base::Bind(&GoogleUpdate::ReportResults, this,
    383                  results, GOOGLE_UPDATE_NO_ERROR, base::string16()));
    384   job_holder = NULL;
    385   on_demand = NULL;
    386 }
    387 
    388 void GoogleUpdate::ReportResults(GoogleUpdateUpgradeResult results,
    389                                  GoogleUpdateErrorCode error_code,
    390                                  const base::string16& error_message) {
    391   // If there is an error, then error code must not be blank, and vice versa.
    392   DCHECK(results == UPGRADE_ERROR ? error_code != GOOGLE_UPDATE_NO_ERROR :
    393                                     error_code == GOOGLE_UPDATE_NO_ERROR);
    394   if (listener_) {
    395     listener_->OnReportResults(
    396         results, error_code, error_message, version_available_);
    397   }
    398 }
    399 
    400 bool GoogleUpdate::ReportFailure(HRESULT hr,
    401                                  GoogleUpdateErrorCode error_code,
    402                                  const base::string16& error_message,
    403                                  base::MessageLoop* main_loop) {
    404   NOTREACHED() << "Communication with Google Update failed: " << hr
    405                << " error: " << error_code
    406                << ", message: " << error_message.c_str();
    407   main_loop->PostTask(
    408       FROM_HERE,
    409       base::Bind(&GoogleUpdate::ReportResults, this,
    410                  UPGRADE_ERROR, error_code, error_message));
    411   return false;
    412 }
    413