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