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