15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "win8/delegate_execute/chrome_util.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <windows.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <atlbase.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shlobj.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/md5.h"
18bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/kill.h"
19bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/launch.h"
20bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/process_handle.h"
217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h"
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/registry.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_comptr.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_handle.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/win_util.h"
27d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/installer/util/browser_distribution.h"
28d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/installer/util/install_util.h"
29d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/installer/util/util_constants.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_update/google_update_idl.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(GOOGLE_CHROME_BUILD)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(grt): These constants live in installer_util.  Consider moving them
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// into common_constants to allow for reuse.
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::CharType kNewChromeExe[] =
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FILE_PATH_LITERAL("new_chrome.exe");
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kRenameCommandValue[] = L"cmd";
41d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const wchar_t kRegPathChromeClientBase[] =
42d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    L"Software\\Google\\Update\\Clients\\";
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the name of the global event used to detect if |chrome_exe| is in
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// use by a browser process.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(grt): Move this somewhere central so it can be used by both this
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// IsBrowserRunning (below) and IsBrowserAlreadyRunning (browser_util_win.cc).
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 GetEventName(const base::FilePath& chrome_exe) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static wchar_t const kEventPrefix[] = L"Global\\";
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t prefix_len = arraysize(kEventPrefix) - 1;
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 name;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  name.reserve(prefix_len + chrome_exe.value().size());
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  name.assign(kEventPrefix, prefix_len);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  name.append(chrome_exe.value());
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::replace(name.begin() + prefix_len, name.end(), '\\', '!');
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::transform(name.begin() + prefix_len, name.end(),
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 name.begin() + prefix_len, tolower);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return name;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if |chrome_exe| is in use by a browser process. In this case,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "in use" means past ChromeBrowserMainParts::PreMainMessageLoopRunImpl.
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsBrowserRunning(const base::FilePath& chrome_exe) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle handle(::OpenEvent(
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SYNCHRONIZE, FALSE, GetEventName(chrome_exe).c_str()));
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handle.IsValid())
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD last_error = ::GetLastError();
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (last_error != ERROR_FILE_NOT_FOUND) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AtlTrace("%hs. Failed to open browser event; error %u.\n", __FUNCTION__,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             last_error);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if the file new_chrome.exe exists in the same directory as
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |chrome_exe|.
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool NewChromeExeExists(const base::FilePath& chrome_exe) {
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath new_chrome_exe(chrome_exe.DirName().Append(kNewChromeExe));
807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return base::PathExists(new_chrome_exe);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GetUpdateCommand(bool is_per_user, base::string16* update_command) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const HKEY root = is_per_user ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
85d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 reg_path_chrome_client = kRegPathChromeClientBase;
87d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  reg_path_chrome_client.append(dist->GetAppGuid());
88d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::win::RegKey key(root, reg_path_chrome_client.c_str(), KEY_QUERY_VALUE);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return key.ReadValue(kRenameCommandValue, update_command) == ERROR_SUCCESS;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // GOOGLE_CHROME_BUILD
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace delegate_execute {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void UpdateChromeIfNeeded(const base::FilePath& chrome_exe) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(GOOGLE_CHROME_BUILD)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Nothing to do if a browser is already running or if there's no
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // new_chrome.exe.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsBrowserRunning(chrome_exe) || !NewChromeExeExists(chrome_exe))
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::win::ScopedHandle process_handle;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
108d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Read the update command from the registry.
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 update_command;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GetUpdateCommand(true, &update_command)) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AtlTrace("%hs. Failed to read update command from registry.\n",
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               __FUNCTION__);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Run the update command.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::LaunchOptions launch_options;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      launch_options.start_hidden = true;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!base::LaunchProcess(update_command, launch_options,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               &process_handle)) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        AtlTrace("%hs. Failed to launch command to finalize update; "
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 "error %u.\n", __FUNCTION__, ::GetLastError());
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Run the update command via Google Update.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HRESULT hr = S_OK;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::win::ScopedComPtr<IProcessLauncher> process_launcher;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = process_launcher.CreateInstance(__uuidof(ProcessLauncherClass));
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr)) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AtlTrace("%hs. Failed to Create ProcessLauncher; hr=0x%X.\n",
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               __FUNCTION__, hr);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ULONG_PTR handle = 0;
134d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      BrowserDistribution* dist = BrowserDistribution::GetDistribution();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hr = process_launcher->LaunchCmdElevated(
136d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          dist->GetAppGuid().c_str(), kRenameCommandValue,
137d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          GetCurrentProcessId(), &handle);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (FAILED(hr)) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        AtlTrace("%hs. Failed to launch command to finalize update; "
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 "hr=0x%X.\n", __FUNCTION__, hr);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        process_handle.Set(reinterpret_cast<base::ProcessHandle>(handle));
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Wait for the update to complete and report the results.
148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (process_handle.IsValid()) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int exit_code = 0;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // WaitForExitCode will close the handle in all cases.
151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!base::WaitForExitCode(process_handle.Take(), &exit_code)) {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AtlTrace("%hs. Failed to get result when finalizing update.\n",
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               __FUNCTION__);
154d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    } else if (exit_code != installer::RENAME_SUCCESSFUL) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AtlTrace("%hs. Failed to finalize update with exit code %d.\n",
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               __FUNCTION__, exit_code);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AtlTrace("%hs. Finalized pending update.\n", __FUNCTION__);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // delegate_execute
165