Home | History | Annotate | Download | only in first_run
      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/first_run/upgrade_util.h"
      6 
      7 #include <algorithm>
      8 #include <string>
      9 
     10 #include "base/base_paths.h"
     11 #include "base/command_line.h"
     12 #include "base/environment.h"
     13 #include "base/file_path.h"
     14 #include "base/file_util.h"
     15 #include "base/logging.h"
     16 #include "base/path_service.h"
     17 #include "base/process_util.h"
     18 #include "base/win/registry.h"
     19 #include "base/win/scoped_comptr.h"
     20 #include "chrome/browser/first_run/upgrade_util_win.h"
     21 #include "chrome/common/chrome_constants.h"
     22 #include "chrome/installer/util/browser_distribution.h"
     23 #include "chrome/installer/util/google_update_constants.h"
     24 #include "chrome/installer/util/install_util.h"
     25 #include "chrome/installer/util/shell_util.h"
     26 #include "chrome/installer/util/util_constants.h"
     27 #include "google_update_idl.h"
     28 
     29 namespace {
     30 
     31 bool GetNewerChromeFile(FilePath* path) {
     32   if (!PathService::Get(base::DIR_EXE, path))
     33     return false;
     34   *path = path->Append(installer::kChromeNewExe);
     35   return true;
     36 }
     37 
     38 bool InvokeGoogleUpdateForRename() {
     39   base::win::ScopedComPtr<IProcessLauncher> ipl;
     40   if (!FAILED(ipl.CreateInstance(__uuidof(ProcessLauncherClass)))) {
     41     ULONG_PTR phandle = NULL;
     42     DWORD id = GetCurrentProcessId();
     43     BrowserDistribution* dist = BrowserDistribution::GetDistribution();
     44     if (!FAILED(ipl->LaunchCmdElevated(dist->GetAppGuid().c_str(),
     45                                        google_update::kRegRenameCmdField,
     46                                        id,
     47                                        &phandle))) {
     48       HANDLE handle = HANDLE(phandle);
     49       WaitForSingleObject(handle, INFINITE);
     50       DWORD exit_code;
     51       ::GetExitCodeProcess(handle, &exit_code);
     52       ::CloseHandle(handle);
     53       if (exit_code == installer::RENAME_SUCCESSFUL)
     54         return true;
     55     }
     56   }
     57   return false;
     58 }
     59 
     60 }  // namespace
     61 
     62 namespace upgrade_util {
     63 
     64 bool RelaunchChromeBrowser(const CommandLine& command_line) {
     65   scoped_ptr<base::Environment> env(base::Environment::Create());
     66   env->UnSetVar(chrome::kChromeVersionEnvVar);
     67   return base::LaunchApp(
     68       command_line.command_line_string(), false, false, NULL);
     69 }
     70 
     71 bool IsUpdatePendingRestart() {
     72   FilePath new_chrome_exe;
     73   if (!GetNewerChromeFile(&new_chrome_exe))
     74     return false;
     75   return file_util::PathExists(new_chrome_exe);
     76 }
     77 
     78 bool SwapNewChromeExeIfPresent() {
     79   FilePath new_chrome_exe;
     80   if (!GetNewerChromeFile(&new_chrome_exe))
     81     return false;
     82   if (!file_util::PathExists(new_chrome_exe))
     83     return false;
     84   FilePath cur_chrome_exe;
     85   if (!PathService::Get(base::FILE_EXE, &cur_chrome_exe))
     86     return false;
     87 
     88   // First try to rename exe by launching rename command ourselves.
     89   bool user_install =
     90       InstallUtil::IsPerUserInstall(cur_chrome_exe.value().c_str());
     91   HKEY reg_root = user_install ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
     92   BrowserDistribution *dist = BrowserDistribution::GetDistribution();
     93   base::win::RegKey key;
     94   std::wstring rename_cmd;
     95   if ((key.Open(reg_root, dist->GetVersionKey().c_str(),
     96                 KEY_READ) == ERROR_SUCCESS) &&
     97       (key.ReadValue(google_update::kRegRenameCmdField,
     98                      &rename_cmd) == ERROR_SUCCESS)) {
     99     base::ProcessHandle handle;
    100     if (base::LaunchApp(rename_cmd, true, true, &handle)) {
    101       DWORD exit_code;
    102       ::GetExitCodeProcess(handle, &exit_code);
    103       ::CloseHandle(handle);
    104       if (exit_code == installer::RENAME_SUCCESSFUL)
    105         return true;
    106     }
    107   }
    108 
    109   // Rename didn't work so try to rename by calling Google Update
    110   return InvokeGoogleUpdateForRename();
    111 }
    112 
    113 bool DoUpgradeTasks(const CommandLine& command_line) {
    114   if (!SwapNewChromeExeIfPresent())
    115     return false;
    116   // At this point the chrome.exe has been swapped with the new one.
    117   if (!RelaunchChromeBrowser(command_line)) {
    118     // The re-launch fails. Feel free to panic now.
    119     NOTREACHED();
    120   }
    121   return true;
    122 }
    123 
    124 }  // namespace upgrade_util
    125