Home | History | Annotate | Download | only in setup
      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/installer/setup/chrome_frame_ready_mode.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/files/file_path.h"
      9 #include "base/logging.h"
     10 #include "base/memory/ref_counted.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "base/time/time.h"
     14 #include "base/win/registry.h"
     15 #include "chrome/installer/setup/install.h"
     16 #include "chrome/installer/setup/install_worker.h"
     17 #include "chrome/installer/util/browser_distribution.h"
     18 #include "chrome/installer/util/google_update_constants.h"
     19 #include "chrome/installer/util/helper.h"
     20 #include "chrome/installer/util/install_util.h"
     21 #include "chrome/installer/util/installation_state.h"
     22 #include "chrome/installer/util/installer_state.h"
     23 #include "chrome/installer/util/master_preferences.h"
     24 #include "chrome/installer/util/master_preferences_constants.h"
     25 #include "chrome/installer/util/product.h"
     26 #include "chrome/installer/util/util_constants.h"
     27 #include "chrome/installer/util/work_item.h"
     28 #include "chrome/installer/util/work_item_list.h"
     29 
     30 namespace installer {
     31 
     32 // If Chrome is not multi-installed at the appropriate level, error.
     33 // If Chrome Frame is already multi-installed at the appropriate level, noop.
     34 // If Chrome Frame is single-installed at the appropriate level, error.
     35 // Add uninstall for Chrome Frame.
     36 // Update uninstall for Chrome.
     37 // Update ChannelInfo for all multi-installed products.
     38 // Remove ready-mode.
     39 InstallStatus ChromeFrameReadyModeOptIn(
     40     const InstallationState& machine_state,
     41     const InstallerState& installer_state) {
     42   VLOG(1) << "Opting into Chrome Frame";
     43   InstallStatus status = INSTALL_REPAIRED;
     44 
     45   // Make sure Chrome and Chrome Frame are both multi-installed.
     46   const ProductState* chrome_state =
     47       machine_state.GetProductState(installer_state.system_install(),
     48                                     BrowserDistribution::CHROME_BROWSER);
     49   const ProductState* cf_state =
     50       machine_state.GetProductState(installer_state.system_install(),
     51                                     BrowserDistribution::CHROME_FRAME);
     52   if (chrome_state == NULL) {
     53     LOG(ERROR) << "Chrome Frame opt-in requires multi-install of Chrome.";
     54     return CHROME_NOT_INSTALLED;
     55   }
     56   if (!chrome_state->is_multi_install()) {
     57     LOG(ERROR) << "Chrome Frame opt-in requires multi-install of Chrome.";
     58     return NON_MULTI_INSTALLATION_EXISTS;
     59   }
     60   if (cf_state == NULL) {
     61     LOG(ERROR) << "Chrome Frame opt-in requires multi-install of Chrome Frame.";
     62     return CHROME_NOT_INSTALLED;
     63   }
     64   if (!cf_state->is_multi_install()) {
     65     LOG(ERROR) << "Chrome Frame opt-in requires multi-install of Chrome Frame.";
     66     return NON_MULTI_INSTALLATION_EXISTS;
     67   }
     68 
     69   // Create a new InstallerState to be used for this operation.
     70   InstallerState opt_in_state(installer_state.level());
     71 
     72   // Add the two products we're going to operate on.
     73   const Product* chrome =
     74       opt_in_state.AddProductFromState(BrowserDistribution::CHROME_BROWSER,
     75                                        *chrome_state);
     76   Product* cf =
     77       opt_in_state.AddProductFromState(BrowserDistribution::CHROME_FRAME,
     78                                        *cf_state);
     79   // DCHECKs will fire in this case if it ever happens (it won't).
     80   if (chrome == NULL || cf == NULL)
     81     return READY_MODE_OPT_IN_FAILED;
     82 
     83   // Turn off ready-mode on Chrome Frame, thereby making it fully installed.
     84   if (!cf->SetOption(kOptionReadyMode, false)) {
     85     LOG(WARNING)
     86         << "Chrome Frame is already fully installed; opting-in nonetheless.";
     87   }
     88 
     89   // Update Chrome's uninstallation commands to only uninstall Chrome, and add
     90   // an entry to the Add/Remove Programs dialog for GCF.
     91   DCHECK(cf->ShouldCreateUninstallEntry() || opt_in_state.is_msi());
     92 
     93   scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList());
     94 
     95   // This creates the uninstallation entry for GCF.
     96   AddUninstallShortcutWorkItems(opt_in_state, cf_state->GetSetupPath(),
     97       cf_state->version(), *cf, item_list.get());
     98   // This updates the Chrome uninstallation entries.
     99   AddUninstallShortcutWorkItems(opt_in_state, chrome_state->GetSetupPath(),
    100       chrome_state->version(), *chrome, item_list.get());
    101 
    102   // Add a work item to delete the ChromeFrameReadyMode registry value.
    103   HKEY root = opt_in_state.root_key();
    104   item_list->AddDeleteRegValueWorkItem(root,
    105       opt_in_state.multi_package_binaries_distribution()->GetStateKey(),
    106       kChromeFrameReadyModeField);
    107 
    108   // Update the Google Update channel ("ap") value.
    109   AddGoogleUpdateWorkItems(machine_state, opt_in_state, item_list.get());
    110 
    111   // Delete the command elevation registry keys
    112   std::wstring version_key(cf->distribution()->GetVersionKey());
    113   item_list->AddDeleteRegValueWorkItem(
    114       root, version_key, google_update::kRegCFTempOptOutCmdField);
    115   item_list->AddDeleteRegValueWorkItem(
    116       root, version_key, google_update::kRegCFEndTempOptOutCmdField);
    117   item_list->AddDeleteRegValueWorkItem(root, version_key,
    118                                        google_update::kRegCFOptOutCmdField);
    119   item_list->AddDeleteRegValueWorkItem(root, version_key,
    120                                        google_update::kRegCFOptInCmdField);
    121 
    122   if (!item_list->Do()) {
    123     LOG(ERROR) << "Failed to opt into GCF";
    124     item_list->Rollback();
    125     status = READY_MODE_OPT_IN_FAILED;
    126   }
    127 
    128   return status;
    129 }
    130 
    131 const wchar_t kPostPlatformUAKey[] =
    132     L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\"
    133     L"User Agent\\Post Platform";
    134 const wchar_t kChromeFramePrefix[] = L"chromeframe/";
    135 
    136 InstallStatus ChromeFrameReadyModeTempOptOut(
    137     const InstallationState& machine_state,
    138     const InstallerState& installer_state) {
    139   VLOG(1) << "Temporarily opting out of Chrome Frame";
    140   InstallStatus status = INSTALL_REPAIRED;
    141 
    142   // Make sure Chrome Frame is multi-installed.
    143   const ProductState* cf_state =
    144       machine_state.GetProductState(installer_state.system_install(),
    145                                     BrowserDistribution::CHROME_FRAME);
    146   if (cf_state == NULL) {
    147     LOG(ERROR)
    148         << "Chrome Frame temp opt-out requires multi-install of Chrome Frame.";
    149     return CHROME_NOT_INSTALLED;
    150   }
    151   if (!cf_state->is_multi_install()) {
    152     LOG(ERROR)
    153         << "Chrome Frame temp opt-out requires multi-install of Chrome Frame.";
    154     return NON_MULTI_INSTALLATION_EXISTS;
    155   }
    156 
    157   scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList());
    158 
    159   HKEY root = installer_state.root_key();
    160 
    161   // Add a work item to delete the ChromeFrame user agent registry value.
    162   base::win::RegistryValueIterator values(root, kPostPlatformUAKey);
    163   while (values.Valid()) {
    164     const wchar_t* name = values.Name();
    165     if (StartsWith(name, kChromeFramePrefix, true)) {
    166       item_list->AddDeleteRegValueWorkItem(root, kPostPlatformUAKey, name);
    167     }
    168     ++values;
    169   }
    170 
    171   // Add a work item to update the Ready Mode state flag
    172   int64 timestamp = base::Time::Now().ToInternalValue();
    173   BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
    174       BrowserDistribution::CHROME_BINARIES);
    175   item_list->AddSetRegValueWorkItem(root, dist->GetStateKey(),
    176                                     kChromeFrameReadyModeField, timestamp,
    177                                     true);
    178 
    179   if (!item_list->Do()) {
    180     LOG(ERROR) << "Failed to temporarily opt out of GCF";
    181     item_list->Rollback();
    182     status = READY_MODE_TEMP_OPT_OUT_FAILED;
    183   }
    184 
    185   return status;
    186 }
    187 
    188 InstallStatus ChromeFrameReadyModeEndTempOptOut(
    189     const InstallationState& machine_state,
    190     const InstallerState& installer_state) {
    191   VLOG(1) << "Ending temporary opt-out of Chrome Frame";
    192   InstallStatus status = INSTALL_REPAIRED;
    193 
    194   // Make sure Chrome Frame is multi-installed.
    195   const ProductState* cf_state =
    196       machine_state.GetProductState(installer_state.system_install(),
    197                                     BrowserDistribution::CHROME_FRAME);
    198   if (cf_state == NULL) {
    199     LOG(ERROR)
    200         << "Chrome Frame temp opt-out requires multi-install of Chrome Frame.";
    201     return CHROME_NOT_INSTALLED;
    202   }
    203   if (!cf_state->is_multi_install()) {
    204     LOG(ERROR)
    205         << "Chrome Frame temp opt-out requires multi-install of Chrome Frame.";
    206     return NON_MULTI_INSTALLATION_EXISTS;
    207   }
    208 
    209   // Replace the ChromeFrame user agent string in the registry, modify the
    210   // ReadyMode state flag.
    211   const Version& installed_version = cf_state->version();
    212 
    213   scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList());
    214 
    215   HKEY root = installer_state.root_key();
    216 
    217   std::wstring chrome_frame_ua_value_name(kChromeFramePrefix);
    218   chrome_frame_ua_value_name += ASCIIToWide(installed_version.GetString());
    219 
    220   // Store the Chrome Frame user agent string
    221   item_list->AddSetRegValueWorkItem(root, kPostPlatformUAKey,
    222                                     chrome_frame_ua_value_name, L"", true);
    223   // Add a work item to update the Ready Mode state flag
    224   BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
    225       BrowserDistribution::CHROME_BINARIES);
    226   item_list->AddSetRegValueWorkItem(root, dist->GetStateKey(),
    227                                     kChromeFrameReadyModeField,
    228                                     static_cast<int64>(1), true);
    229 
    230   if (!item_list->Do()) {
    231     LOG(ERROR) << "Failed to end temporary opt out of GCF";
    232     item_list->Rollback();
    233     status = READY_MODE_END_TEMP_OPT_OUT_FAILED;
    234   }
    235 
    236   return status;
    237 }
    238 
    239 }  // namespace installer
    240