| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/installer/util/product.h" | 5 #include "chrome/installer/util/product.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/process_util.h" | 11 #include "base/process_util.h" |
| 12 #include "base/win/registry.h" | 12 #include "base/win/registry.h" |
| 13 #include "chrome/installer/util/chrome_browser_operations.h" |
| 14 #include "chrome/installer/util/chrome_browser_sxs_operations.h" |
| 15 #include "chrome/installer/util/chrome_frame_operations.h" |
| 13 #include "chrome/installer/util/google_update_constants.h" | 16 #include "chrome/installer/util/google_update_constants.h" |
| 14 #include "chrome/installer/util/helper.h" | 17 #include "chrome/installer/util/helper.h" |
| 15 #include "chrome/installer/util/install_util.h" | 18 #include "chrome/installer/util/install_util.h" |
| 16 #include "chrome/installer/util/master_preferences.h" | 19 #include "chrome/installer/util/master_preferences.h" |
| 17 #include "chrome/installer/util/master_preferences_constants.h" | 20 #include "chrome/installer/util/master_preferences_constants.h" |
| 18 #include "chrome/installer/util/package_properties.h" | 21 #include "chrome/installer/util/product_operations.h" |
| 19 | 22 |
| 20 using base::win::RegKey; | 23 using base::win::RegKey; |
| 21 using installer::MasterPreferences; | 24 using installer::MasterPreferences; |
| 22 | 25 |
| 23 namespace { | |
| 24 class ProductIsOfType { | |
| 25 public: | |
| 26 explicit ProductIsOfType(BrowserDistribution::Type type) | |
| 27 : type_(type) { } | |
| 28 bool operator()( | |
| 29 const scoped_refptr<const installer::Product>& pi) const { | |
| 30 return pi->distribution()->GetType() == type_; | |
| 31 } | |
| 32 private: | |
| 33 BrowserDistribution::Type type_; | |
| 34 }; // class ProductIsOfType | |
| 35 } // end namespace | |
| 36 | |
| 37 namespace installer { | 26 namespace installer { |
| 38 | 27 |
| 39 const Product* FindProduct(const Products& products, | 28 Product::Product(BrowserDistribution* distribution) |
| 40 BrowserDistribution::Type type) { | 29 : distribution_(distribution) { |
| 41 Products::const_iterator i = | 30 switch (distribution->GetType()) { |
| 42 std::find_if(products.begin(), products.end(), ProductIsOfType(type)); | 31 case BrowserDistribution::CHROME_BROWSER: |
| 43 return i == products.end() ? NULL : *i; | 32 operations_.reset(InstallUtil::IsChromeSxSProcess() ? |
| 33 new ChromeBrowserSxSOperations() : |
| 34 new ChromeBrowserOperations()); |
| 35 break; |
| 36 case BrowserDistribution::CHROME_FRAME: |
| 37 operations_.reset(new ChromeFrameOperations()); |
| 38 break; |
| 39 default: |
| 40 NOTREACHED() << "Unsupported BrowserDistribution::Type: " |
| 41 << distribution->GetType(); |
| 42 } |
| 44 } | 43 } |
| 45 | 44 |
| 46 //////////////////////////////////////////////////////////////////////////////// | 45 Product::~Product() { |
| 47 | |
| 48 Product::Product(BrowserDistribution* distribution, Package* package) | |
| 49 : distribution_(distribution), | |
| 50 package_(package), | |
| 51 msi_(false), | |
| 52 cache_state_(0) { | |
| 53 package_->AssociateProduct(this); | |
| 54 } | 46 } |
| 55 | 47 |
| 56 const Package& Product::package() const { | 48 void Product::InitializeFromPreferences(const MasterPreferences& prefs) { |
| 57 return *package_.get(); | 49 operations_->ReadOptions(prefs, &options_); |
| 50 } |
| 51 |
| 52 void Product::InitializeFromUninstallCommand( |
| 53 const CommandLine& uninstall_command) { |
| 54 operations_->ReadOptions(uninstall_command, &options_); |
| 58 } | 55 } |
| 59 | 56 |
| 60 FilePath Product::GetUserDataPath() const { | 57 FilePath Product::GetUserDataPath() const { |
| 61 return GetChromeUserDataPath(distribution_); | 58 return GetChromeUserDataPath(distribution_); |
| 62 } | 59 } |
| 63 | 60 |
| 64 bool Product::LaunchChrome() const { | 61 bool Product::LaunchChrome(const FilePath& application_path) const { |
| 65 const FilePath& install_package = package_->path(); | 62 bool success = !application_path.empty(); |
| 66 bool success = !install_package.empty(); | |
| 67 if (success) { | 63 if (success) { |
| 68 CommandLine cmd(install_package.Append(installer::kChromeExe)); | 64 CommandLine cmd(application_path.Append(installer::kChromeExe)); |
| 69 success = base::LaunchApp(cmd, false, false, NULL); | 65 success = base::LaunchApp(cmd, false, false, NULL); |
| 70 } | 66 } |
| 71 return success; | 67 return success; |
| 72 } | 68 } |
| 73 | 69 |
| 74 bool Product::LaunchChromeAndWait(const CommandLine& options, | 70 bool Product::LaunchChromeAndWait(const FilePath& application_path, |
| 71 const CommandLine& options, |
| 75 int32* exit_code) const { | 72 int32* exit_code) const { |
| 76 const FilePath& install_package = package_->path(); | 73 if (application_path.empty()) |
| 77 if (install_package.empty()) | |
| 78 return false; | 74 return false; |
| 79 | 75 |
| 80 CommandLine cmd(install_package.Append(installer::kChromeExe)); | 76 CommandLine cmd(application_path.Append(installer::kChromeExe)); |
| 81 cmd.AppendArguments(options, false); | 77 cmd.AppendArguments(options, false); |
| 82 | 78 |
| 83 bool success = false; | 79 bool success = false; |
| 84 STARTUPINFOW si = { sizeof(si) }; | 80 STARTUPINFOW si = { sizeof(si) }; |
| 85 PROCESS_INFORMATION pi = {0}; | 81 PROCESS_INFORMATION pi = {0}; |
| 86 // Cast away constness of the command_line_string() since CreateProcess | 82 // Cast away constness of the command_line_string() since CreateProcess |
| 87 // might modify the string (insert \0 to separate the program from the | 83 // might modify the string (insert \0 to separate the program from the |
| 88 // arguments). Since we're not using the cmd variable beyond this point | 84 // arguments). Since we're not using the cmd variable beyond this point |
| 89 // we don't care. | 85 // we don't care. |
| 90 if (!::CreateProcess(cmd.GetProgram().value().c_str(), | 86 if (!::CreateProcess(cmd.GetProgram().value().c_str(), |
| (...skipping 15 matching lines...) Expand all Loading... |
| 106 } else { | 102 } else { |
| 107 PLOG(ERROR) << "GetExitCodeProcess failed"; | 103 PLOG(ERROR) << "GetExitCodeProcess failed"; |
| 108 } | 104 } |
| 109 | 105 |
| 110 ::CloseHandle(pi.hProcess); | 106 ::CloseHandle(pi.hProcess); |
| 111 } | 107 } |
| 112 | 108 |
| 113 return success; | 109 return success; |
| 114 } | 110 } |
| 115 | 111 |
| 116 bool Product::IsMsi() const { | 112 bool Product::SetMsiMarker(bool system_install, bool set) const { |
| 117 if ((cache_state_ & MSI_STATE) == 0) { | 113 HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; |
| 118 msi_ = false; // Covers failure cases below. | |
| 119 | |
| 120 const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess(); | |
| 121 | |
| 122 bool is_msi = false; | |
| 123 prefs.GetBool(installer::master_preferences::kMsi, &is_msi); | |
| 124 | |
| 125 if (!is_msi) { | |
| 126 // We didn't find it in the preferences, try looking in the registry. | |
| 127 HKEY reg_root = system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | |
| 128 RegKey key; | |
| 129 if (key.Open(reg_root, distribution_->GetStateKey().c_str(), | |
| 130 KEY_READ) == ERROR_SUCCESS) { | |
| 131 DWORD msi_value = 0; | |
| 132 key.ReadValueDW(google_update::kRegMSIField, &msi_value); | |
| 133 msi_ = msi_value != 0; | |
| 134 } | |
| 135 } else { | |
| 136 msi_ = true; | |
| 137 } | |
| 138 cache_state_ |= MSI_STATE; | |
| 139 } | |
| 140 | |
| 141 return msi_; | |
| 142 } | |
| 143 | |
| 144 bool Product::SetMsiMarker(bool set) const { | |
| 145 HKEY reg_root = system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | |
| 146 RegKey client_state_key; | 114 RegKey client_state_key; |
| 147 LONG result = client_state_key.Open(reg_root, | 115 LONG result = client_state_key.Open(reg_root, |
| 148 distribution_->GetStateKey().c_str(), KEY_READ | KEY_WRITE); | 116 distribution_->GetStateKey().c_str(), KEY_READ | KEY_WRITE); |
| 149 if (result == ERROR_SUCCESS) { | 117 if (result == ERROR_SUCCESS) { |
| 150 result = client_state_key.WriteValue(google_update::kRegMSIField, | 118 result = client_state_key.WriteValue(google_update::kRegMSIField, |
| 151 set ? 1 : 0); | 119 set ? 1 : 0); |
| 152 } | 120 } |
| 153 | 121 |
| 154 LOG_IF(ERROR, result != ERROR_SUCCESS) << "Failed to Open or Write MSI value" | 122 LOG_IF(ERROR, result != ERROR_SUCCESS) << "Failed to Open or Write MSI value" |
| 155 "to client state key. error: " << result; | 123 "to client state key. error: " << result; |
| 156 | 124 |
| 157 return (result == ERROR_SUCCESS); | 125 return (result == ERROR_SUCCESS); |
| 158 } | 126 } |
| 159 | 127 |
| 160 bool Product::ShouldCreateUninstallEntry() const { | 128 bool Product::ShouldCreateUninstallEntry() const { |
| 161 if (IsMsi()) { | 129 return operations_->ShouldCreateUninstallEntry(options_); |
| 162 // MSI installations will manage their own uninstall shortcuts. | |
| 163 return false; | |
| 164 } | |
| 165 | |
| 166 return distribution_->ShouldCreateUninstallEntry(); | |
| 167 } | 130 } |
| 168 | 131 |
| 169 /////////////////////////////////////////////////////////////////////////////// | 132 void Product::AddKeyFiles(std::vector<FilePath>* key_files) const { |
| 170 ProductPackageMapping::ProductPackageMapping(bool multi_install, | 133 operations_->AddKeyFiles(options_, key_files); |
| 171 bool system_level) | |
| 172 : package_properties_(new ActivePackageProperties()), | |
| 173 multi_install_(multi_install), | |
| 174 system_level_(system_level) { | |
| 175 } | 134 } |
| 176 | 135 |
| 177 const Packages& ProductPackageMapping::packages() const { | 136 void Product::AddComDllList(std::vector<FilePath>* com_dll_list) const { |
| 178 return packages_; | 137 operations_->AddComDllList(options_, com_dll_list); |
| 179 } | 138 } |
| 180 | 139 |
| 181 const Products& ProductPackageMapping::products() const { | 140 void Product::AppendProductFlags(CommandLine* command_line) const { |
| 182 return products_; | 141 operations_->AppendProductFlags(options_, command_line); |
| 183 } | 142 } |
| 184 | 143 |
| 185 bool ProductPackageMapping::AddDistribution(BrowserDistribution* distribution) { | 144 bool Product::SetChannelFlags(bool set, ChannelInfo* channel_info) const { |
| 186 DCHECK(distribution); | 145 return operations_->SetChannelFlags(options_, set, channel_info); |
| 187 // Each product type can be added exactly once. | |
| 188 DCHECK(FindProduct(products_, distribution->GetType()) == NULL); | |
| 189 | |
| 190 FilePath install_package; | |
| 191 if (distribution->GetType() == BrowserDistribution::CHROME_BROWSER) { | |
| 192 install_package = GetChromeInstallPath(system_level_, distribution); | |
| 193 } else { | |
| 194 DCHECK_EQ(BrowserDistribution::CHROME_FRAME, distribution->GetType()); | |
| 195 install_package = GetChromeFrameInstallPath(multi_install_, system_level_, | |
| 196 distribution); | |
| 197 } | |
| 198 | |
| 199 if (install_package.empty()) { | |
| 200 LOG(ERROR) << "Got an empty installation path for " | |
| 201 << distribution->GetApplicationName() | |
| 202 << ". It's likely that there's a conflicting " | |
| 203 "installation present"; | |
| 204 return false; | |
| 205 } | |
| 206 | |
| 207 scoped_refptr<Package> target_package; | |
| 208 for (size_t i = 0; i < packages_.size(); ++i) { | |
| 209 if (packages_[i]->IsEqual(install_package)) { | |
| 210 // Use an existing Package. | |
| 211 target_package = packages_[i]; | |
| 212 break; | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 if (!target_package.get()) { | |
| 217 DCHECK(packages_.empty()) << "Multiple packages per run unsupported."; | |
| 218 // create new one and add. | |
| 219 target_package = new Package(multi_install_, system_level_, install_package, | |
| 220 package_properties_.get()); | |
| 221 packages_.push_back(target_package); | |
| 222 } | |
| 223 | |
| 224 scoped_refptr<Product> product(new Product(distribution, target_package)); | |
| 225 #ifndef NDEBUG | |
| 226 for (size_t i = 0; i < products_.size(); ++i) { | |
| 227 DCHECK_EQ(product->IsMsi(), products_[i]->IsMsi()); | |
| 228 } | |
| 229 #endif | |
| 230 products_.push_back(product); | |
| 231 | |
| 232 return true; | |
| 233 } | |
| 234 | |
| 235 bool ProductPackageMapping::AddDistribution( | |
| 236 BrowserDistribution::Type type, | |
| 237 const MasterPreferences& prefs) { | |
| 238 BrowserDistribution* distribution = | |
| 239 BrowserDistribution::GetSpecificDistribution(type, prefs); | |
| 240 if (!distribution) { | |
| 241 NOTREACHED(); | |
| 242 return false; | |
| 243 } | |
| 244 | |
| 245 return AddDistribution(distribution); | |
| 246 } | 146 } |
| 247 | 147 |
| 248 } // namespace installer | 148 } // namespace installer |
| 249 | |
| OLD | NEW |