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)// This file declares util functions for setup project.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/setup/setup_util.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/cpu.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_enumerator.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
17a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/kill.h"
18a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/launch.h"
19a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/process_handle.h"
207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h"
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/version.h"
23558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "base/win/registry.h"
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/win/windows_version.h"
25ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "chrome/installer/setup/setup_constants.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/copy_tree_work_item.h"
27558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "chrome/installer/util/google_update_constants.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/installation_state.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/installer_state.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/master_preferences.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/util_constants.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/work_item.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "courgette/courgette.h"
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "courgette/third_party/bsdiff.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/bspatch/mbspatch.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace installer {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Launches |setup_exe| with |command_line|, save --install-archive and its
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// value if present. Returns false if the process failed to launch. Otherwise,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// waits indefinitely for it to exit and populates |exit_code| as expected. On
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the off chance that waiting itself fails, |exit_code| is set to
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WAIT_FOR_EXISTING_FAILED.
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool LaunchAndWaitForExistingInstall(const base::FilePath& setup_exe,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const CommandLine& command_line,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     int* exit_code) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(exit_code);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine new_cl(setup_exe);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Copy over all switches but --install-archive.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine::SwitchMap switches(command_line.GetSwitches());
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switches.erase(switches::kInstallArchive);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (CommandLine::SwitchMap::const_iterator i = switches.begin();
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != switches.end(); ++i) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i->second.empty())
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_cl.AppendSwitch(i->first);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_cl.AppendSwitchNative(i->first, i->second);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Copy over all arguments.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine::StringVector args(command_line.GetArgs());
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (CommandLine::StringVector::const_iterator i = args.begin();
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != args.end(); ++i) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_cl.AppendArgNative(*i);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Launch the process and wait for it to exit.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Launching existing installer with command: "
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << new_cl.GetCommandLineString();
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ProcessHandle handle = INVALID_HANDLE_VALUE;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::LaunchProcess(new_cl, base::LaunchOptions(), &handle)) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PLOG(ERROR) << "Failed to launch existing installer with command: "
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                << new_cl.GetCommandLineString();
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::WaitForExitCode(handle, exit_code)) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PLOG(DFATAL) << "Failed to get exit code from existing installer";
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *exit_code = WAIT_FOR_EXISTING_FAILED;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "Existing installer returned exit code " << *exit_code;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns true if product |type| cam be meaningfully installed without the
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// --multi-install flag.
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SupportsSingleInstall(BrowserDistribution::Type type) {
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (type == BrowserDistribution::CHROME_BROWSER ||
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          type == BrowserDistribution::CHROME_FRAME);
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint CourgettePatchFiles(const base::FilePath& src,
98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                        const base::FilePath& patch,
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                        const base::FilePath& dest) {
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  VLOG(1) << "Applying Courgette patch " << patch.value()
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          << " to file " << src.value()
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          << " and generating file " << dest.value();
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (src.empty() || patch.empty() || dest.empty())
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return installer::PATCH_INVALID_ARGUMENTS;
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const courgette::Status patch_status =
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      courgette::ApplyEnsemblePatch(src.value().c_str(),
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                    patch.value().c_str(),
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                    dest.value().c_str());
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const int exit_code = (patch_status != courgette::C_OK) ?
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      static_cast<int>(patch_status) + kCourgetteErrorOffset : 0;
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  LOG_IF(ERROR, exit_code)
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      << "Failed to apply Courgette patch " << patch.value()
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      << " to file " << src.value() << " and generating file " << dest.value()
117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      << ". err=" << exit_code;
118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return exit_code;
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint BsdiffPatchFiles(const base::FilePath& src,
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     const base::FilePath& patch,
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     const base::FilePath& dest) {
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  VLOG(1) << "Applying bsdiff patch " << patch.value()
126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          << " to file " << src.value()
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          << " and generating file " << dest.value();
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (src.empty() || patch.empty() || dest.empty())
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return installer::PATCH_INVALID_ARGUMENTS;
131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const int patch_status = courgette::ApplyBinaryPatch(src, patch, dest);
133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const int exit_code = patch_status != OK ?
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                        patch_status + kBsdiffErrorOffset : 0;
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  LOG_IF(ERROR, exit_code)
137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      << "Failed to apply bsdiff patch " << patch.value()
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      << " to file " << src.value() << " and generating file " << dest.value()
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      << ". err=" << exit_code;
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return exit_code;
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Version* GetMaxVersionFromArchiveDir(const base::FilePath& chrome_path) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Looking for Chrome version folder under " << chrome_path.value();
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::FileEnumerator version_enum(chrome_path, false,
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      base::FileEnumerator::DIRECTORIES);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(tommi): The version directory really should match the version of
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // setup.exe.  To begin with, we should at least DCHECK that that's true.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Version> max_version(new Version("0.0.0.0"));
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool version_found = false;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!version_enum.Next().empty()) {
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    base::FileEnumerator::FileInfo find_data = version_enum.GetInfo();
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    VLOG(1) << "directory found: " << find_data.GetName().value();
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<Version> found_version(
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        new Version(base::UTF16ToASCII(find_data.GetName().value())));
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (found_version->IsValid() &&
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        found_version->CompareTo(*max_version.get()) > 0) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max_version.reset(found_version.release());
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_found = true;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (version_found ? max_version.release() : NULL);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
170ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbase::FilePath FindArchiveToPatch(const InstallationState& original_state,
171ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                  const InstallerState& installer_state) {
172ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Check based on the version number advertised to Google Update, since that
173ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // is the value used to select a specific differential update. If an archive
174ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // can't be found using that, fallback to using the newest version present.
175ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::FilePath patch_source;
176ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  const ProductState* product =
177ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      original_state.GetProductState(installer_state.system_install(),
178ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                     installer_state.state_type());
179ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (product) {
180ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    patch_source = installer_state.GetInstallerDirectory(product->version())
181ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .Append(installer::kChromeArchive);
182ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (base::PathExists(patch_source))
183ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      return patch_source;
184ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
185ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  scoped_ptr<Version> version(
186ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      installer::GetMaxVersionFromArchiveDir(installer_state.target_path()));
187ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (version) {
188ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    patch_source = installer_state.GetInstallerDirectory(*version)
189ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .Append(installer::kChromeArchive);
190ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (base::PathExists(patch_source))
191ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      return patch_source;
192ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
193ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return base::FilePath();
194ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
195ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DeleteFileFromTempProcess(const base::FilePath& path,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               uint32 delay_before_delete_ms) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const wchar_t kRunDll32Path[] =
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      L"%SystemRoot%\\System32\\rundll32.exe";
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t rundll32[MAX_PATH];
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD size =
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ExpandEnvironmentStrings(kRunDll32Path, rundll32, arraysize(rundll32));
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!size || size >= MAX_PATH)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STARTUPINFO startup = { sizeof(STARTUPINFO) };
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PROCESS_INFORMATION pi = {0};
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL ok = ::CreateProcess(NULL, rundll32, NULL, NULL, FALSE, CREATE_SUSPENDED,
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            NULL, NULL, &startup, &pi);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ok) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We use the main thread of the new process to run:
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //   Sleep(delay_before_delete_ms);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //   DeleteFile(path);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //   ExitProcess(0);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This runs before the main routine of the process runs, so it doesn't
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // matter much which executable we choose except that we don't want to
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // use e.g. a console app that causes a window to be created.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size = (path.value().length() + 1) * sizeof(path.value()[0]);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void* mem = ::VirtualAllocEx(pi.hProcess, NULL, size, MEM_COMMIT,
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 PAGE_READWRITE);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mem) {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SIZE_T written = 0;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ::WriteProcessMemory(
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          pi.hProcess, mem, path.value().c_str(),
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (path.value().size() + 1) * sizeof(path.value()[0]), &written);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HMODULE kernel32 = ::GetModuleHandle(L"kernel32.dll");
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PAPCFUNC sleep = reinterpret_cast<PAPCFUNC>(
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ::GetProcAddress(kernel32, "Sleep"));
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PAPCFUNC delete_file = reinterpret_cast<PAPCFUNC>(
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ::GetProcAddress(kernel32, "DeleteFileW"));
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PAPCFUNC exit_process = reinterpret_cast<PAPCFUNC>(
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ::GetProcAddress(kernel32, "ExitProcess"));
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!sleep || !delete_file || !exit_process) {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ok = FALSE;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ::QueueUserAPC(sleep, pi.hThread, delay_before_delete_ms);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ::QueueUserAPC(delete_file, pi.hThread,
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       reinterpret_cast<ULONG_PTR>(mem));
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ::QueueUserAPC(exit_process, pi.hThread, 0);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ::ResumeThread(pi.hThread);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PLOG(ERROR) << "VirtualAllocEx";
245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ::TerminateProcess(pi.hProcess, ~static_cast<UINT>(0));
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::CloseHandle(pi.hThread);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::CloseHandle(pi.hProcess);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ok != FALSE;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetExistingHigherInstaller(
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const InstallationState& original_state,
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool system_install,
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Version& installer_version,
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath* setup_exe) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(setup_exe);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool trying_single_browser = false;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ProductState* existing_state =
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      original_state.GetProductState(system_install,
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     BrowserDistribution::CHROME_BINARIES);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!existing_state) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The binaries aren't installed, but perhaps a single-install Chrome is.
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    trying_single_browser = true;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    existing_state =
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        original_state.GetProductState(system_install,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       BrowserDistribution::CHROME_BROWSER);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!existing_state ||
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      existing_state->version().CompareTo(installer_version) <= 0) {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *setup_exe = existing_state->GetSetupPath();
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG_IF(1, !setup_exe->empty()) << "Found a higher version of "
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << (trying_single_browser ? "single-install Chrome."
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          : "multi-install Chrome binaries.");
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !setup_exe->empty();
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DeferToExistingInstall(const base::FilePath& setup_exe,
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            const CommandLine& command_line,
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            const InstallerState& installer_state,
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            const base::FilePath& temp_path,
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            InstallStatus* install_status) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Copy a master_preferences file if there is one.
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath prefs_source_path(command_line.GetSwitchValueNative(
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      switches::kInstallerData));
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath prefs_dest_path(installer_state.target_path().AppendASCII(
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kDefaultMasterPrefs));
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<WorkItem> copy_prefs(WorkItem::CreateCopyTreeWorkItem(
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      prefs_source_path, prefs_dest_path, temp_path, WorkItem::ALWAYS,
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::FilePath()));
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There's nothing to rollback if the copy fails, so punt if so.
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!copy_prefs->Do())
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    copy_prefs.reset();
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int exit_code = 0;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!LaunchAndWaitForExistingInstall(setup_exe, command_line, &exit_code)) {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (copy_prefs)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      copy_prefs->Rollback();
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *install_status = static_cast<InstallStatus>(exit_code);
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// There are 4 disjoint cases => return values {false,true}:
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// (1) Product is being uninstalled => false.
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// (2) Product is being installed => true.
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// (3) Current operation ignores product, product is absent => false.
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// (4) Current operation ignores product, product is present => true.
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool WillProductBePresentAfterSetup(
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const installer::InstallerState& installer_state,
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const installer::InstallationState& machine_state,
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserDistribution::Type type) {
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(SupportsSingleInstall(type) || installer_state.is_multi_install());
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const ProductState* product_state =
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      machine_state.GetProductState(installer_state.system_install(), type);
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Determine if the product is present prior to the current operation.
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool is_present = (product_state != NULL);
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_uninstall = installer_state.operation() == InstallerState::UNINSTALL;
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Determine if current operation affects the product.
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const Product* product = installer_state.FindProduct(type);
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool is_affected = (product != NULL);
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Decide among {(1),(2),(3),(4)}.
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return is_affected ? !is_uninstall : is_present;
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
339868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool AdjustProcessPriority() {
340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
341868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DWORD priority_class = ::GetPriorityClass(::GetCurrentProcess());
342868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (priority_class == 0) {
343868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PLOG(WARNING) << "Failed to get the process's priority class.";
344868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    } else if (priority_class == BELOW_NORMAL_PRIORITY_CLASS ||
345868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)               priority_class == IDLE_PRIORITY_CLASS) {
346868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      BOOL result = ::SetPriorityClass(::GetCurrentProcess(),
347868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                       PROCESS_MODE_BACKGROUND_BEGIN);
348868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PLOG_IF(WARNING, !result) << "Failed to enter background mode.";
349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return !!result;
350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
352868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return false;
353868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
354868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
355558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid MigrateGoogleUpdateStateMultiToSingle(
356558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    bool system_level,
357558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    BrowserDistribution::Type to_migrate,
358558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    const installer::InstallationState& machine_state) {
359558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  const HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
360558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  const ProductState* product = NULL;
361558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  BrowserDistribution* dist = NULL;
362558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  LONG result = ERROR_SUCCESS;
363558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  base::win::RegKey state_key;
364558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
365558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  Product product_to_migrate(
366558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      BrowserDistribution::GetSpecificDistribution(to_migrate));
367558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
368558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // Copy usagestats from the binaries to the product's ClientState key.
369558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  product = machine_state.GetProductState(system_level,
370558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                          BrowserDistribution::CHROME_BINARIES);
371558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DWORD usagestats = 0;
372558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (product && product->GetUsageStats(&usagestats)) {
373558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    dist = product_to_migrate.distribution();
374558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    result = state_key.Open(root, dist->GetStateKey().c_str(),
375558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                            KEY_SET_VALUE);
376558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (result != ERROR_SUCCESS) {
377558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      LOG(ERROR) << "Failed opening ClientState key for "
3783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 << dist->GetDisplayName() << " to migrate usagestats.";
379558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    } else {
380558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      state_key.WriteValue(google_update::kRegUsageStatsField, usagestats);
381558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    }
382558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
383558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
384558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // Remove the migrating product from the "ap" value of other multi-install
385558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // products.
386558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  for (int i = 0; i < BrowserDistribution::NUM_TYPES; ++i) {
387558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    BrowserDistribution::Type type =
388558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        static_cast<BrowserDistribution::Type>(i);
389558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (type == to_migrate)
390558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      continue;
391558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    product = machine_state.GetProductState(system_level, type);
392558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (product && product->is_multi_install()) {
393558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      installer::ChannelInfo channel_info;
394558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      dist = BrowserDistribution::GetSpecificDistribution(type);
395558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      result = state_key.Open(root, dist->GetStateKey().c_str(),
396558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                              KEY_QUERY_VALUE | KEY_SET_VALUE);
397558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      if (result == ERROR_SUCCESS &&
398558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          channel_info.Initialize(state_key) &&
399558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          product_to_migrate.SetChannelFlags(false, &channel_info)) {
4003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        VLOG(1) << "Moving " << dist->GetDisplayName()
401558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                << " to channel: " << channel_info.value();
402558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        channel_info.Write(&state_key);
403558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      }
404558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    }
405558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
406558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
407558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // Remove -multi, all product modifiers, and everything else but the channel
408558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // name from the "ap" value of the product to migrate.
409558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  dist = product_to_migrate.distribution();
410558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  result = state_key.Open(root, dist->GetStateKey().c_str(),
411558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                          KEY_QUERY_VALUE | KEY_SET_VALUE);
412558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (result == ERROR_SUCCESS) {
413558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    installer::ChannelInfo channel_info;
414558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (!channel_info.Initialize(state_key)) {
4153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      LOG(ERROR) << "Failed reading " << dist->GetDisplayName()
416558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                 << " channel info.";
417558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    } else if (channel_info.RemoveAllModifiersAndSuffixes()) {
4183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      VLOG(1) << "Moving " << dist->GetDisplayName()
419558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch              << " to channel: " << channel_info.value();
420558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      channel_info.Write(&state_key);
421558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    }
422558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
423558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
424558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
4254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool IsUninstallSuccess(InstallStatus install_status) {
4264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // The following status values represent failed uninstalls:
4274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // 15: CHROME_NOT_INSTALLED
4284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // 20: UNINSTALL_FAILED
4294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // 21: UNINSTALL_CANCELLED
4304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return (install_status == UNINSTALL_SUCCESSFUL ||
4314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          install_status == UNINSTALL_REQUIRES_REBOOT);
4324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ContainsUnsupportedSwitch(const CommandLine& cmd_line) {
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const char* const kLegacySwitches[] = {
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Chrome Frame ready-mode.
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "ready-mode",
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "ready-mode-opt-in",
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "ready-mode-temp-opt-out",
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "ready-mode-end-temp-opt-out",
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Chrome Frame quick-enable.
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "quick-enable-cf",
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Installation of Chrome Frame.
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "chrome-frame",
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "migrate-chrome-frame",
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  };
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < arraysize(kLegacySwitches); ++i) {
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (cmd_line.HasSwitch(kLegacySwitches[i]))
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return true;
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
454a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool IsProcessorSupported() {
455a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return base::CPU().has_sse2();
456a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
457a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ScopedTokenPrivilege::ScopedTokenPrivilege(const wchar_t* privilege_name)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : is_enabled_(false) {
460f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  HANDLE temp_handle;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!::OpenProcessToken(::GetCurrentProcess(),
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
463f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                          &temp_handle)) {
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
466f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  token_.Set(temp_handle);
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LUID privilege_luid;
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!::LookupPrivilegeValue(NULL, privilege_name, &privilege_luid)) {
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token_.Close();
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Adjust the token's privileges to enable |privilege_name|. If this privilege
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // was already enabled, |previous_privileges_|.PrivilegeCount will be set to 0
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and we then know not to disable this privilege upon destruction.
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TOKEN_PRIVILEGES tp;
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp.PrivilegeCount = 1;
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp.Privileges[0].Luid = privilege_luid;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD return_length;
4821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!::AdjustTokenPrivileges(token_.Get(), FALSE, &tp,
4831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                               sizeof(TOKEN_PRIVILEGES),
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               &previous_privileges_, &return_length)) {
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token_.Close();
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_enabled_ = true;
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ScopedTokenPrivilege::~ScopedTokenPrivilege() {
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_enabled_ && previous_privileges_.PrivilegeCount != 0) {
4941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ::AdjustTokenPrivileges(token_.Get(), FALSE, &previous_privileges_,
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            sizeof(TOKEN_PRIVILEGES), NULL, NULL);
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace installer
500