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/setup/install.h" | 5 #include "chrome/installer/setup/install.h" |
6 | 6 |
7 #include <shlobj.h> | 7 #include <shlobj.h> |
8 #include <time.h> | 8 #include <time.h> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/file_path.h" | 12 #include "base/file_path.h" |
13 #include "base/file_util.h" | 13 #include "base/file_util.h" |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
15 #include "base/path_service.h" | 15 #include "base/path_service.h" |
16 #include "base/scoped_ptr.h" | 16 #include "base/scoped_ptr.h" |
17 #include "base/string_util.h" | 17 #include "base/string_util.h" |
18 #include "base/utf_string_conversions.h" | 18 #include "base/utf_string_conversions.h" |
19 #include "base/win/registry.h" | 19 #include "base/win/registry.h" |
20 #include "chrome/installer/setup/setup_constants.h" | 20 #include "chrome/installer/setup/setup_constants.h" |
| 21 #include "chrome/installer/setup/install_worker.h" |
21 #include "chrome/installer/util/browser_distribution.h" | 22 #include "chrome/installer/util/browser_distribution.h" |
22 #include "chrome/installer/util/channel_info.h" | 23 #include "chrome/installer/util/channel_info.h" |
23 #include "chrome/installer/util/chrome_frame_distribution.h" | 24 #include "chrome/installer/util/chrome_frame_distribution.h" |
24 #include "chrome/installer/util/conditional_work_item_list.h" | 25 #include "chrome/installer/util/conditional_work_item_list.h" |
25 #include "chrome/installer/util/create_reg_key_work_item.h" | 26 #include "chrome/installer/util/create_reg_key_work_item.h" |
26 #include "chrome/installer/util/delete_after_reboot_helper.h" | 27 #include "chrome/installer/util/delete_after_reboot_helper.h" |
27 #include "chrome/installer/util/google_update_constants.h" | 28 #include "chrome/installer/util/google_update_constants.h" |
28 #include "chrome/installer/util/helper.h" | 29 #include "chrome/installer/util/helper.h" |
29 #include "chrome/installer/util/install_util.h" | 30 #include "chrome/installer/util/install_util.h" |
30 #include "chrome/installer/util/installation_state.h" | 31 #include "chrome/installer/util/installation_state.h" |
(...skipping 30 matching lines...) Expand all Loading... |
61 file_util::AppendToPath(®_path, installer::kChromeExe); | 62 file_util::AppendToPath(®_path, installer::kChromeExe); |
62 VLOG(1) << "Adding Chrome to Media player list at " << reg_path; | 63 VLOG(1) << "Adding Chrome to Media player list at " << reg_path; |
63 scoped_ptr<WorkItem> work_item(WorkItem::CreateCreateRegKeyWorkItem( | 64 scoped_ptr<WorkItem> work_item(WorkItem::CreateCreateRegKeyWorkItem( |
64 HKEY_LOCAL_MACHINE, reg_path)); | 65 HKEY_LOCAL_MACHINE, reg_path)); |
65 | 66 |
66 // if the operation fails we log the error but still continue | 67 // if the operation fails we log the error but still continue |
67 if (!work_item.get()->Do()) | 68 if (!work_item.get()->Do()) |
68 LOG(ERROR) << "Could not add Chrome to media player inclusion list."; | 69 LOG(ERROR) << "Could not add Chrome to media player inclusion list."; |
69 } | 70 } |
70 | 71 |
71 void AddInstallerCopyTasks(const FilePath& setup_path, | |
72 const FilePath& archive_path, | |
73 const FilePath& temp_path, | |
74 const Version& new_version, | |
75 WorkItemList* install_list, | |
76 const Package& package) { | |
77 DCHECK(install_list); | |
78 FilePath installer_dir(package.GetInstallerDirectory(new_version)); | |
79 install_list->AddCreateDirWorkItem(installer_dir); | |
80 | |
81 FilePath exe_dst(installer_dir.Append(setup_path.BaseName())); | |
82 FilePath archive_dst(installer_dir.Append(archive_path.BaseName())); | |
83 | |
84 install_list->AddCopyTreeWorkItem(setup_path.value(), exe_dst.value(), | |
85 temp_path.value(), WorkItem::ALWAYS); | |
86 if (package.system_level()) { | |
87 install_list->AddCopyTreeWorkItem(archive_path.value(), archive_dst.value(), | |
88 temp_path.value(), WorkItem::ALWAYS); | |
89 } else { | |
90 install_list->AddMoveTreeWorkItem(archive_path.value(), archive_dst.value(), | |
91 temp_path.value()); | |
92 } | |
93 } | |
94 | |
95 void AppendUninstallCommandLineFlags(CommandLine* uninstall_cmd, | |
96 const Product& product) { | |
97 DCHECK(uninstall_cmd); | |
98 | |
99 uninstall_cmd->AppendSwitch(installer::switches::kUninstall); | |
100 | |
101 // Append the product-specific uninstall flags. | |
102 product.distribution()->AppendUninstallCommandLineFlags(uninstall_cmd); | |
103 if (product.IsMsi()) { | |
104 uninstall_cmd->AppendSwitch(installer::switches::kMsi); | |
105 // See comment in uninstall.cc where we check for the kDeleteProfile switch. | |
106 if (product.is_chrome_frame()) { | |
107 uninstall_cmd->AppendSwitch(installer::switches::kDeleteProfile); | |
108 } | |
109 } | |
110 if (product.system_level()) | |
111 uninstall_cmd->AppendSwitch(installer::switches::kSystemLevel); | |
112 | |
113 // Propagate switches obtained from preferences as well. | |
114 const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess(); | |
115 if (prefs.is_multi_install()) { | |
116 uninstall_cmd->AppendSwitch(installer::switches::kMultiInstall); | |
117 } | |
118 bool value = false; | |
119 if (prefs.GetBool(installer::master_preferences::kVerboseLogging, | |
120 &value) && value) | |
121 uninstall_cmd->AppendSwitch(installer::switches::kVerboseLogging); | |
122 } | |
123 | |
124 // This method adds work items to create (or update) Chrome uninstall entry in | |
125 // either the Control Panel->Add/Remove Programs list or in the Omaha client | |
126 // state key if running under an MSI installer. | |
127 void AddUninstallShortcutWorkItems(const FilePath& setup_path, | |
128 const Version& new_version, | |
129 WorkItemList* install_list, | |
130 const Product& product) { | |
131 HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE : | |
132 HKEY_CURRENT_USER; | |
133 BrowserDistribution* browser_dist = product.distribution(); | |
134 DCHECK(browser_dist); | |
135 | |
136 // When we are installed via an MSI, we need to store our uninstall strings | |
137 // in the Google Update client state key. We do this even for non-MSI | |
138 // managed installs to avoid breaking the edge case whereby an MSI-managed | |
139 // install is updated by a non-msi installer (which would confuse the MSI | |
140 // machinery if these strings were not also updated). | |
141 // Do not quote the command line for the MSI invocation. | |
142 FilePath install_path(product.package().path()); | |
143 FilePath installer_path( | |
144 product.package().GetInstallerDirectory(new_version)); | |
145 installer_path = installer_path.Append(setup_path.BaseName()); | |
146 | |
147 CommandLine uninstall_arguments(CommandLine::NO_PROGRAM); | |
148 AppendUninstallCommandLineFlags(&uninstall_arguments, product); | |
149 | |
150 if (product.is_chrome()) { | |
151 // The Chrome uninstallation command serves as the master uninstall | |
152 // command for Chrome + all other products (i.e. Chrome Frame) that do | |
153 // not have an uninstall entry in the Add/Remove Programs dialog. | |
154 const Products& products = product.package().products(); | |
155 for (size_t i = 0; i < products.size(); ++i) { | |
156 const Product& p = *products[i]; | |
157 if (!p.is_chrome() && !p.ShouldCreateUninstallEntry()) { | |
158 p.distribution()->AppendUninstallCommandLineFlags(&uninstall_arguments); | |
159 } | |
160 } | |
161 } | |
162 | |
163 std::wstring update_state_key(browser_dist->GetStateKey()); | |
164 install_list->AddCreateRegKeyWorkItem(reg_root, update_state_key); | |
165 install_list->AddSetRegValueWorkItem(reg_root, update_state_key, | |
166 installer::kUninstallStringField, installer_path.value(), true); | |
167 install_list->AddSetRegValueWorkItem(reg_root, update_state_key, | |
168 installer::kUninstallArgumentsField, | |
169 uninstall_arguments.command_line_string(), true); | |
170 | |
171 if (product.ShouldCreateUninstallEntry()) { | |
172 // We need to quote the command line for the Add/Remove Programs dialog. | |
173 CommandLine quoted_uninstall_cmd(installer_path); | |
174 DCHECK_EQ(quoted_uninstall_cmd.command_line_string()[0], '"'); | |
175 quoted_uninstall_cmd.AppendArguments(uninstall_arguments, false); | |
176 | |
177 std::wstring uninstall_reg = browser_dist->GetUninstallRegPath(); | |
178 install_list->AddCreateRegKeyWorkItem(reg_root, uninstall_reg); | |
179 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, | |
180 installer::kUninstallDisplayNameField, | |
181 browser_dist->GetAppShortCutName(), true); | |
182 install_list->AddSetRegValueWorkItem(reg_root, | |
183 uninstall_reg, installer::kUninstallStringField, | |
184 quoted_uninstall_cmd.command_line_string(), true); | |
185 install_list->AddSetRegValueWorkItem(reg_root, | |
186 uninstall_reg, | |
187 L"InstallLocation", | |
188 install_path.value(), | |
189 true); | |
190 | |
191 // DisplayIcon, NoModify and NoRepair | |
192 FilePath chrome_icon(install_path.Append(installer::kChromeExe)); | |
193 ShellUtil::GetChromeIcon(product.distribution(), chrome_icon.value()); | |
194 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, | |
195 L"DisplayIcon", chrome_icon.value(), | |
196 true); | |
197 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, | |
198 L"NoModify", 1, true); | |
199 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, | |
200 L"NoRepair", 1, true); | |
201 | |
202 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, | |
203 L"Publisher", | |
204 browser_dist->GetPublisherName(), | |
205 true); | |
206 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, | |
207 L"Version", | |
208 UTF8ToWide(new_version.GetString()), | |
209 true); | |
210 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, | |
211 L"DisplayVersion", | |
212 UTF8ToWide(new_version.GetString()), | |
213 true); | |
214 time_t rawtime = time(NULL); | |
215 struct tm timeinfo = {0}; | |
216 localtime_s(&timeinfo, &rawtime); | |
217 wchar_t buffer[9]; | |
218 if (wcsftime(buffer, 9, L"%Y%m%d", &timeinfo) == 8) { | |
219 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, | |
220 L"InstallDate", | |
221 buffer, false); | |
222 } | |
223 } | |
224 } | |
225 | |
226 // Adds work items that make registry adjustments for Google Update. When a | |
227 // product is installed (including overinstall), Google Update will write the | |
228 // channel ("ap") value into either Chrome or Chrome Frame's ClientState key. | |
229 // In the multi-install case, this value is used as the basis upon which the | |
230 // package's channel value is built (by adding the ordered list of installed | |
231 // products and their options). | |
232 void AddGoogleUpdateWorkItems(const InstallationState& original_state, | |
233 const InstallerState& installer_state, | |
234 const Package& package, | |
235 WorkItemList* install_list) { | |
236 // Is a multi-install product being installed or over-installed? | |
237 if (installer_state.operation() != InstallerState::MULTI_INSTALL) | |
238 return; | |
239 | |
240 const HKEY reg_root = package.system_level() ? HKEY_LOCAL_MACHINE : | |
241 HKEY_CURRENT_USER; | |
242 const std::wstring key_path = installer_state.state_key(); | |
243 ChannelInfo channel_info; | |
244 | |
245 // Update the "ap" value for the product being installed/updated. | |
246 // It is completely acceptable for there to be no "ap" value or even no | |
247 // ClientState key. Note that we check the registry rather than | |
248 // original_state since on a fresh install the "ap" value will be present | |
249 // sans "pv" value. | |
250 channel_info.Initialize(RegKey(reg_root, key_path.c_str(), KEY_QUERY_VALUE)); | |
251 | |
252 // This is a multi-install product. | |
253 bool modified = channel_info.SetMultiInstall(true); | |
254 | |
255 // Add the appropriate modifiers for all products and their options. | |
256 Products::const_iterator scan = package.products().begin(); | |
257 const Products::const_iterator end = package.products().end(); | |
258 for (; scan != end; ++scan) { | |
259 modified |= scan->get()->distribution()->SetChannelFlags(true, | |
260 &channel_info); | |
261 } | |
262 | |
263 // Write the results if needed. | |
264 if (modified) { | |
265 install_list->AddSetRegValueWorkItem(reg_root, key_path, | |
266 google_update::kRegApField, | |
267 channel_info.value(), true); | |
268 } | |
269 | |
270 // Synchronize the other products and the package with this one. | |
271 std::wstring other_key; | |
272 std::vector<std::wstring> keys; | |
273 | |
274 keys.reserve(package.products().size()); | |
275 other_key = package.properties()->GetStateKey(); | |
276 if (other_key != key_path) | |
277 keys.push_back(other_key); | |
278 scan = package.products().begin(); | |
279 for (; scan != end; ++scan) { | |
280 other_key = scan->get()->distribution()->GetStateKey(); | |
281 if (other_key != key_path) | |
282 keys.push_back(other_key); | |
283 } | |
284 | |
285 RegKey key; | |
286 ChannelInfo other_info; | |
287 std::vector<std::wstring>::const_iterator kscan = keys.begin(); | |
288 std::vector<std::wstring>::const_iterator kend = keys.end(); | |
289 for (; kscan != kend; ++kscan) { | |
290 // Handle the case where the ClientState key doesn't exist by creating it. | |
291 // This takes care of the multi-installer's package key, which is not | |
292 // created by Google Update for us. | |
293 if (!key.Open(reg_root, kscan->c_str(), KEY_QUERY_VALUE) || | |
294 !other_info.Initialize(key)) { | |
295 other_info.set_value(std::wstring()); | |
296 } | |
297 if (!other_info.Equals(channel_info)) { | |
298 if (!key.Valid()) | |
299 install_list->AddCreateRegKeyWorkItem(reg_root, *kscan); | |
300 install_list->AddSetRegValueWorkItem(reg_root, *kscan, | |
301 google_update::kRegApField, | |
302 channel_info.value(), true); | |
303 } | |
304 } | |
305 // TODO(grt): check for other keys/values we should put in the package's | |
306 // ClientState and/or Clients key. | |
307 } | |
308 | |
309 // This is called when an MSI installation is run. It may be that a user is | |
310 // attempting to install the MSI on top of a non-MSI managed installation. | |
311 // If so, try and remove any existing uninstallation shortcuts, as we want the | |
312 // uninstall to be managed entirely by the MSI machinery (accessible via the | |
313 // Add/Remove programs dialog). | |
314 void AddDeleteUninstallShortcutsForMSIWorkItems(const Product& product, | |
315 WorkItemList* work_item_list) { | |
316 DCHECK(product.IsMsi()) << "This must only be called for MSI installations!"; | |
317 | |
318 // First attempt to delete the old installation's ARP dialog entry. | |
319 HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE : | |
320 HKEY_CURRENT_USER; | |
321 base::win::RegKey root_key(reg_root, L"", KEY_ALL_ACCESS); | |
322 std::wstring uninstall_reg(product.distribution()->GetUninstallRegPath()); | |
323 | |
324 WorkItem* delete_reg_key = work_item_list->AddDeleteRegKeyWorkItem( | |
325 reg_root, uninstall_reg); | |
326 delete_reg_key->set_ignore_failure(true); | |
327 | |
328 // Then attempt to delete the old installation's start menu shortcut. | |
329 FilePath uninstall_link; | |
330 if (product.system_level()) { | |
331 PathService::Get(base::DIR_COMMON_START_MENU, &uninstall_link); | |
332 } else { | |
333 PathService::Get(base::DIR_START_MENU, &uninstall_link); | |
334 } | |
335 | |
336 if (uninstall_link.empty()) { | |
337 LOG(ERROR) << "Failed to get location for shortcut."; | |
338 } else { | |
339 uninstall_link = uninstall_link.Append( | |
340 product.distribution()->GetAppShortCutName()); | |
341 uninstall_link = uninstall_link.Append( | |
342 product.distribution()->GetUninstallLinkName() + L".lnk"); | |
343 VLOG(1) << "Deleting old uninstall shortcut (if present): " | |
344 << uninstall_link.value(); | |
345 WorkItem* delete_link = work_item_list->AddDeleteTreeWorkItem( | |
346 uninstall_link); | |
347 delete_link->set_ignore_failure(true); | |
348 delete_link->set_log_message( | |
349 "Failed to delete old uninstall shortcut."); | |
350 } | |
351 } | |
352 | |
353 // Copy master preferences file provided to installer, in the same folder | 72 // Copy master preferences file provided to installer, in the same folder |
354 // as chrome.exe so Chrome first run can find it. This function will be called | 73 // as chrome.exe so Chrome first run can find it. This function will be called |
355 // only on the first install of Chrome. | 74 // only on the first install of Chrome. |
356 void CopyPreferenceFileForFirstRun(const Package& package, | 75 void CopyPreferenceFileForFirstRun(const Package& package, |
357 const FilePath& prefs_source_path) { | 76 const FilePath& prefs_source_path) { |
358 FilePath prefs_dest_path(package.path().AppendASCII( | 77 FilePath prefs_dest_path(package.path().AppendASCII( |
359 installer::kDefaultMasterPrefs)); | 78 installer::kDefaultMasterPrefs)); |
360 if (!file_util::CopyFile(prefs_source_path, prefs_dest_path)) { | 79 if (!file_util::CopyFile(prefs_source_path, prefs_dest_path)) { |
361 VLOG(1) << "Failed to copy master preferences from:" | 80 VLOG(1) << "Failed to copy master preferences from:" |
362 << prefs_source_path.value() << " gle: " << ::GetLastError(); | 81 << prefs_source_path.value() << " gle: " << ::GetLastError(); |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 ret = ShellUtil::CreateChromeQuickLaunchShortcut( | 209 ret = ShellUtil::CreateChromeQuickLaunchShortcut( |
491 product.distribution(), chrome_exe.value(), ShellUtil::CURRENT_USER, | 210 product.distribution(), chrome_exe.value(), ShellUtil::CURRENT_USER, |
492 create_all_shortcut); | 211 create_all_shortcut); |
493 } | 212 } |
494 } | 213 } |
495 } | 214 } |
496 | 215 |
497 return ret; | 216 return ret; |
498 } | 217 } |
499 | 218 |
500 // Local helper to call AddRegisterComDllWorkItems for all DLLs in a set of | |
501 // products managed by a given package. | |
502 void AddRegisterComDllWorkItemsForPackage(const Package& package, | |
503 const Version* old_version, | |
504 const Version& new_version, | |
505 WorkItemList* work_item_list) { | |
506 // First collect the list of DLLs to be registered from each product. | |
507 const Products& products = package.products(); | |
508 Products::const_iterator product_iter(products.begin()); | |
509 std::vector<FilePath> com_dll_list; | |
510 for (; product_iter != products.end(); ++product_iter) { | |
511 BrowserDistribution* dist = product_iter->get()->distribution(); | |
512 std::vector<FilePath> dist_dll_list(dist->GetComDllList()); | |
513 com_dll_list.insert(com_dll_list.end(), dist_dll_list.begin(), | |
514 dist_dll_list.end()); | |
515 } | |
516 | |
517 // Then, if we got some, attempt to unregister the DLLs from the old | |
518 // version directory and then re-register them in the new one. | |
519 // Note that if we are migrating the install directory then we will not | |
520 // successfully unregister the old DLLs. | |
521 // TODO(robertshield): See whether we need to fix the migration case. | |
522 // TODO(robertshield): If we ever remove a DLL from a product, this will | |
523 // not unregister it on update. We should build the unregistration list from | |
524 // saved state instead of assuming it is the same as the registration list. | |
525 if (!com_dll_list.empty()) { | |
526 if (old_version) { | |
527 FilePath old_dll_path( | |
528 package.path().Append(UTF8ToWide(old_version->GetString()))); | |
529 | |
530 installer::AddRegisterComDllWorkItems(old_dll_path, | |
531 com_dll_list, | |
532 package.system_level(), | |
533 false, // Unregister | |
534 true, // May fail | |
535 work_item_list); | |
536 } | |
537 | |
538 FilePath dll_path( | |
539 package.path().Append(UTF8ToWide(new_version.GetString()))); | |
540 installer::AddRegisterComDllWorkItems(dll_path, | |
541 com_dll_list, | |
542 package.system_level(), | |
543 true, // Register | |
544 false, // Must succeed. | |
545 work_item_list); | |
546 } | |
547 } | |
548 | |
549 // After a successful copying of all the files, this function is called to | |
550 // do a few post install tasks: | |
551 // - Handle the case of in-use-update by updating "opv" (old version) key or | |
552 // deleting it if not required. | |
553 // - Register any new dlls and unregister old dlls. | |
554 // - If this is an MSI install, ensures that the MSI marker is set, and sets | |
555 // it if not. | |
556 // If these operations are successful, the function returns true, otherwise | |
557 // false. | |
558 bool AppendPostInstallTasks(bool multi_install, | |
559 const FilePath& setup_path, | |
560 const FilePath& new_chrome_exe, | |
561 const Version* current_version, | |
562 const Version& new_version, | |
563 const Package& package, | |
564 WorkItemList* post_install_task_list) { | |
565 DCHECK(post_install_task_list); | |
566 HKEY root = package.system_level() ? HKEY_LOCAL_MACHINE : | |
567 HKEY_CURRENT_USER; | |
568 const Products& products = package.products(); | |
569 | |
570 | |
571 // Append work items that will only be executed if this was an update. | |
572 // We update the 'opv' key with the current version that is active and 'cmd' | |
573 // key with the rename command to run. | |
574 { | |
575 scoped_ptr<WorkItemList> in_use_update_work_items( | |
576 WorkItem::CreateConditionalWorkItemList( | |
577 new ConditionRunIfFileExists(new_chrome_exe))); | |
578 in_use_update_work_items->set_log_message("InUseUpdateWorkItemList"); | |
579 | |
580 FilePath installer_path(package.GetInstallerDirectory(new_version) | |
581 .Append(setup_path.BaseName())); | |
582 | |
583 CommandLine rename(installer_path); | |
584 rename.AppendSwitch(installer::switches::kRenameChromeExe); | |
585 if (package.system_level()) | |
586 rename.AppendSwitch(installer::switches::kSystemLevel); | |
587 | |
588 if (InstallUtil::IsChromeSxSProcess()) | |
589 rename.AppendSwitch(installer::switches::kChromeSxS); | |
590 | |
591 if (multi_install) | |
592 rename.AppendSwitch(installer::switches::kMultiInstall); | |
593 | |
594 std::wstring version_key; | |
595 for (size_t i = 0; i < products.size(); ++i) { | |
596 BrowserDistribution* dist = products[i]->distribution(); | |
597 version_key = dist->GetVersionKey(); | |
598 | |
599 if (current_version != NULL) { | |
600 in_use_update_work_items->AddSetRegValueWorkItem(root, version_key, | |
601 google_update::kRegOldVersionField, | |
602 UTF8ToWide(current_version->GetString()), true); | |
603 } | |
604 | |
605 // Adding this registry entry for all products is overkill. | |
606 // However, as it stands, we don't have a way to know which distribution | |
607 // will check the key and run the command, so we add it for all. | |
608 // After the first run, the subsequent runs should just be noops. | |
609 // (see Upgrade::SwapNewChromeExeIfPresent). | |
610 in_use_update_work_items->AddSetRegValueWorkItem( | |
611 root, | |
612 version_key, | |
613 google_update::kRegRenameCmdField, | |
614 rename.command_line_string(), | |
615 true); | |
616 } | |
617 | |
618 if (multi_install) { | |
619 PackageProperties* props = package.properties(); | |
620 if (props->ReceivesUpdates() && current_version != NULL) { | |
621 in_use_update_work_items->AddSetRegValueWorkItem( | |
622 root, | |
623 props->GetVersionKey(), | |
624 google_update::kRegOldVersionField, | |
625 UTF8ToWide(current_version->GetString()), | |
626 true); | |
627 // TODO(tommi): We should move the rename command here. We also need to | |
628 // update Upgrade::SwapNewChromeExeIfPresent. | |
629 } | |
630 } | |
631 | |
632 post_install_task_list->AddWorkItem(in_use_update_work_items.release()); | |
633 } | |
634 | |
635 | |
636 // Append work items that will be executed if this was NOT an in-use update. | |
637 { | |
638 scoped_ptr<WorkItemList> regular_update_work_items( | |
639 WorkItem::CreateConditionalWorkItemList( | |
640 new Not(new ConditionRunIfFileExists(new_chrome_exe)))); | |
641 regular_update_work_items->set_log_message( | |
642 "RegularUpdateWorkItemList"); | |
643 | |
644 // Since this was not an in-use-update, delete 'opv' and 'cmd' keys. | |
645 for (size_t i = 0; i < products.size(); ++i) { | |
646 BrowserDistribution* dist = products[i]->distribution(); | |
647 std::wstring version_key(dist->GetVersionKey()); | |
648 regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key, | |
649 google_update::kRegOldVersionField, | |
650 true); | |
651 regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key, | |
652 google_update::kRegRenameCmdField, | |
653 true); | |
654 } | |
655 | |
656 post_install_task_list->AddWorkItem(regular_update_work_items.release()); | |
657 } | |
658 | |
659 AddRegisterComDllWorkItemsForPackage(package, current_version, new_version, | |
660 post_install_task_list); | |
661 | |
662 for (size_t i = 0; i < products.size(); ++i) { | |
663 const Product* product = products[i]; | |
664 // If we're told that we're an MSI install, make sure to set the marker | |
665 // in the client state key so that future updates do the right thing. | |
666 if (product->IsMsi()) { | |
667 AddSetMsiMarkerWorkItem(*product, true, post_install_task_list); | |
668 | |
669 // We want MSI installs to take over the Add/Remove Programs shortcut. | |
670 // Make a best-effort attempt to delete any shortcuts left over from | |
671 // previous non-MSI installations for the same type of install (system or | |
672 // per user). | |
673 AddDeleteUninstallShortcutsForMSIWorkItems(*product, | |
674 post_install_task_list); | |
675 } | |
676 } | |
677 | |
678 return true; | |
679 } | |
680 | |
681 // This method tells if we are running on 64 bit platform so that we can copy | |
682 // one extra exe. If the API call to determine 64 bit fails, we play it safe | |
683 // and return true anyway so that the executable can be copied. | |
684 bool Is64bit() { | |
685 typedef BOOL (WINAPI *WOW_FUNC)(HANDLE, PBOOL); | |
686 BOOL is64 = FALSE; | |
687 | |
688 HANDLE handle = GetCurrentProcess(); | |
689 HMODULE module = GetModuleHandle(L"kernel32.dll"); | |
690 WOW_FUNC p = reinterpret_cast<WOW_FUNC>(GetProcAddress(module, | |
691 "IsWow64Process")); | |
692 if ((p != NULL) && (!(p)(handle, &is64) || (is64 != FALSE))) { | |
693 return true; | |
694 } | |
695 | |
696 return false; | |
697 } | |
698 | 219 |
699 void RegisterChromeOnMachine(const Product& product, | 220 void RegisterChromeOnMachine(const Product& product, |
700 bool make_chrome_default) { | 221 bool make_chrome_default) { |
701 DCHECK(product.is_chrome()); | 222 DCHECK(product.is_chrome()); |
702 | 223 |
703 // Try to add Chrome to Media Player shim inclusion list. We don't do any | 224 // Try to add Chrome to Media Player shim inclusion list. We don't do any |
704 // error checking here because this operation will fail if user doesn't | 225 // error checking here because this operation will fail if user doesn't |
705 // have admin rights and we want to ignore the error. | 226 // have admin rights and we want to ignore the error. |
706 AddChromeToMediaPlayerList(); | 227 AddChromeToMediaPlayerList(); |
707 | 228 |
708 // Is --make-chrome-default option is given we make Chrome default browser | 229 // Is --make-chrome-default option is given we make Chrome default browser |
709 // otherwise we only register it on the machine as a valid browser. | 230 // otherwise we only register it on the machine as a valid browser. |
710 FilePath chrome_exe( | 231 FilePath chrome_exe( |
711 product.package().path().Append(installer::kChromeExe)); | 232 product.package().path().Append(installer::kChromeExe)); |
712 VLOG(1) << "Registering Chrome as browser: " << chrome_exe.value(); | 233 VLOG(1) << "Registering Chrome as browser: " << chrome_exe.value(); |
713 if (make_chrome_default) { | 234 if (make_chrome_default) { |
714 int level = ShellUtil::CURRENT_USER; | 235 int level = ShellUtil::CURRENT_USER; |
715 if (product.system_level()) | 236 if (product.system_level()) |
716 level = level | ShellUtil::SYSTEM_LEVEL; | 237 level = level | ShellUtil::SYSTEM_LEVEL; |
717 ShellUtil::MakeChromeDefault(product.distribution(), level, | 238 ShellUtil::MakeChromeDefault(product.distribution(), level, |
718 chrome_exe.value(), true); | 239 chrome_exe.value(), true); |
719 } else { | 240 } else { |
720 ShellUtil::RegisterChromeBrowser(product.distribution(), chrome_exe.value(), | 241 ShellUtil::RegisterChromeBrowser(product.distribution(), chrome_exe.value(), |
721 L"", false); | 242 L"", false); |
722 } | 243 } |
723 } | 244 } |
724 | 245 |
725 // Create Version key for a product (if not already present) and sets the new | |
726 // product version as the last step. | |
727 void AddVersionKeyWorkItems(HKEY root, | |
728 const Product& product, | |
729 const Version& new_version, | |
730 WorkItemList* list) { | |
731 // Create Version key for each distribution (if not already present) and set | |
732 // the new product version as the last step. | |
733 std::wstring version_key(product.distribution()->GetVersionKey()); | |
734 list->AddCreateRegKeyWorkItem(root, version_key); | |
735 | |
736 std::wstring product_name(product.distribution()->GetAppShortCutName()); | |
737 list->AddSetRegValueWorkItem(root, version_key, google_update::kRegNameField, | |
738 product_name, true); // overwrite name also | |
739 list->AddSetRegValueWorkItem(root, version_key, | |
740 google_update::kRegOopcrashesField, 1, | |
741 false); // set during first install | |
742 list->AddSetRegValueWorkItem(root, version_key, | |
743 google_update::kRegVersionField, | |
744 UTF8ToWide(new_version.GetString()), | |
745 true); // overwrite version | |
746 } | |
747 | |
748 void AddProductSpecificWorkItems(bool install, | |
749 const FilePath& setup_path, | |
750 const Version& new_version, | |
751 const Package& package, | |
752 WorkItemList* list) { | |
753 const Products& products = package.products(); | |
754 for (size_t i = 0; i < products.size(); ++i) { | |
755 const Product& p = *products[i]; | |
756 if (p.is_chrome_frame()) { | |
757 AddChromeFrameWorkItems(install, setup_path, new_version, p, list); | |
758 } | |
759 } | |
760 } | |
761 | |
762 // This function installs a new version of Chrome to the specified location. | 246 // This function installs a new version of Chrome to the specified location. |
763 // | 247 // |
764 // setup_path: Path to the executable (setup.exe) as it will be copied | 248 // setup_path: Path to the executable (setup.exe) as it will be copied |
765 // to Chrome install folder after install is complete | 249 // to Chrome install folder after install is complete |
766 // archive_path: Path to the archive (chrome.7z) as it will be copied | 250 // archive_path: Path to the archive (chrome.7z) as it will be copied |
767 // to Chrome install folder after install is complete | 251 // to Chrome install folder after install is complete |
768 // src_path: the path that contains a complete and unpacked Chrome package | 252 // src_path: the path that contains a complete and unpacked Chrome package |
769 // to be installed. | 253 // to be installed. |
770 // temp_dir: the path of working directory used during installation. This path | 254 // temp_dir: the path of working directory used during installation. This path |
771 // does not need to exist. | 255 // does not need to exist. |
772 // new_version: new Chrome version that needs to be installed | 256 // new_version: new Chrome version that needs to be installed |
773 // oldest_installed_version: returns the oldest active version (if any) | 257 // current_version: returns the current active version (if any) |
774 // | 258 // |
775 // This function makes best effort to do installation in a transactional | 259 // This function makes best effort to do installation in a transactional |
776 // manner. If failed it tries to rollback all changes on the file system | 260 // manner. If failed it tries to rollback all changes on the file system |
777 // and registry. For example, if package exists before calling the | 261 // and registry. For example, if package exists before calling the |
778 // function, it rolls back all new file and directory changes under | 262 // function, it rolls back all new file and directory changes under |
779 // package. If package does not exist before calling the function | 263 // package. If package does not exist before calling the function |
780 // (typical new install), the function creates package during install | 264 // (typical new install), the function creates package during install |
781 // and removes the whole directory during rollback. | 265 // and removes the whole directory during rollback. |
782 installer::InstallStatus InstallNewVersion( | 266 installer::InstallStatus InstallNewVersion( |
783 const InstallationState& original_state, | 267 const InstallationState& original_state, |
784 const InstallerState& installer_state, | 268 const InstallerState& installer_state, |
785 bool multi_install, | 269 bool multi_install, |
786 const FilePath& setup_path, | 270 const FilePath& setup_path, |
787 const FilePath& archive_path, | 271 const FilePath& archive_path, |
788 const FilePath& src_path, | 272 const FilePath& src_path, |
789 const FilePath& temp_dir, | 273 const FilePath& temp_dir, |
790 const Version& new_version, | 274 const Version& new_version, |
791 scoped_ptr<Version>* current_version, | 275 scoped_ptr<Version>* current_version, |
792 const Package& package) { | 276 const Package& package) { |
793 DCHECK(current_version); | 277 DCHECK(current_version); |
794 | 278 |
795 const Products& products = package.products(); | 279 current_version->reset(package.GetCurrentVersion()); |
796 DCHECK(products.size()); | 280 scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList()); |
797 | 281 |
798 if (FindProduct(products, BrowserDistribution::CHROME_FRAME)) { | 282 AddInstallWorkItems(original_state, |
799 // Make sure that we don't end up deleting installed files on next reboot. | 283 installer_state, |
800 if (!RemoveFromMovesPendingReboot(package.path().value().c_str())) { | 284 multi_install, |
801 LOG(ERROR) << "Error accessing pending moves value."; | 285 setup_path, |
802 } | 286 archive_path, |
803 } | 287 src_path, |
| 288 temp_dir, |
| 289 new_version, |
| 290 current_version, |
| 291 package, |
| 292 install_list.get()); |
804 | 293 |
805 current_version->reset(package.GetCurrentVersion()); | |
806 | |
807 scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList()); | |
808 // A temp directory that work items need and the actual install directory. | |
809 install_list->AddCreateDirWorkItem(temp_dir); | |
810 install_list->AddCreateDirWorkItem(package.path()); | |
811 | |
812 // Delete any new_chrome.exe if present (we will end up creating a new one | |
813 // if required) and then copy chrome.exe | |
814 FilePath new_chrome_exe( | 294 FilePath new_chrome_exe( |
815 package.path().Append(installer::kChromeNewExe)); | 295 package.path().Append(installer::kChromeNewExe)); |
816 | 296 |
817 install_list->AddDeleteTreeWorkItem(new_chrome_exe); | |
818 install_list->AddCopyTreeWorkItem( | |
819 src_path.Append(installer::kChromeExe).value(), | |
820 package.path().Append(installer::kChromeExe).value(), | |
821 temp_dir.value(), WorkItem::NEW_NAME_IF_IN_USE, new_chrome_exe.value()); | |
822 | |
823 // Extra executable for 64 bit systems. | |
824 if (Is64bit()) { | |
825 install_list->AddCopyTreeWorkItem( | |
826 src_path.Append(installer::kWowHelperExe).value(), | |
827 package.path().Append(installer::kWowHelperExe).value(), | |
828 temp_dir.value(), WorkItem::ALWAYS); | |
829 } | |
830 | |
831 // If it is system level install copy the version folder (since we want to | |
832 // take the permissions of %ProgramFiles% folder) otherwise just move it. | |
833 if (package.system_level()) { | |
834 install_list->AddCopyTreeWorkItem( | |
835 src_path.Append(UTF8ToWide(new_version.GetString())).value(), | |
836 package.path().Append(UTF8ToWide(new_version.GetString())).value(), | |
837 temp_dir.value(), WorkItem::ALWAYS); | |
838 } else { | |
839 install_list->AddMoveTreeWorkItem( | |
840 src_path.Append(UTF8ToWide(new_version.GetString())).value(), | |
841 package.path().Append(UTF8ToWide(new_version.GetString())).value(), | |
842 temp_dir.value()); | |
843 } | |
844 | |
845 // Copy the default Dictionaries only if the folder doesn't exist already. | |
846 install_list->AddCopyTreeWorkItem( | |
847 src_path.Append(installer::kDictionaries).value(), | |
848 package.path().Append(installer::kDictionaries).value(), | |
849 temp_dir.value(), WorkItem::IF_NOT_PRESENT); | |
850 | |
851 // Delete any old_chrome.exe if present. | |
852 install_list->AddDeleteTreeWorkItem( | |
853 package.path().Append(installer::kChromeOldExe)); | |
854 | |
855 // Copy installer in install directory and | |
856 // add shortcut in Control Panel->Add/Remove Programs. | |
857 AddInstallerCopyTasks(setup_path, archive_path, temp_dir, new_version, | |
858 install_list.get(), package); | |
859 | |
860 HKEY root = package.system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | |
861 | |
862 for (size_t i = 0; i < products.size(); ++i) { | |
863 const Product* product = products[i]; | |
864 | |
865 AddUninstallShortcutWorkItems(setup_path, new_version, install_list.get(), | |
866 *product); | |
867 | |
868 AddVersionKeyWorkItems(root, *product, new_version, install_list.get()); | |
869 } | |
870 | |
871 if (multi_install) { | |
872 PackageProperties* props = package.properties(); | |
873 if (props->ReceivesUpdates()) { | |
874 std::wstring version_key(props->GetVersionKey()); | |
875 install_list->AddCreateRegKeyWorkItem(root, version_key); | |
876 install_list->AddSetRegValueWorkItem(root, version_key, | |
877 google_update::kRegVersionField, | |
878 UTF8ToWide(new_version.GetString()), | |
879 true); // overwrite version | |
880 install_list->AddSetRegValueWorkItem(root, version_key, | |
881 google_update::kRegNameField, | |
882 ASCIIToWide(installer::PackageProperties::kPackageProductName), | |
883 true); // overwrite name also | |
884 } | |
885 } | |
886 | |
887 // Add any remaining work items that involve special settings for | |
888 // each product. | |
889 AddProductSpecificWorkItems(true, setup_path, new_version, package, | |
890 install_list.get()); | |
891 | |
892 AddGoogleUpdateWorkItems(original_state, installer_state, package, | |
893 install_list.get()); | |
894 | |
895 // Append the tasks that run after the installation. | |
896 AppendPostInstallTasks(multi_install, | |
897 setup_path, | |
898 new_chrome_exe, | |
899 current_version->get(), | |
900 new_version, | |
901 package, | |
902 install_list.get()); | |
903 | |
904 if (!install_list->Do()) { | 297 if (!install_list->Do()) { |
905 installer::InstallStatus result = | 298 installer::InstallStatus result = |
906 file_util::PathExists(new_chrome_exe) && current_version->get() && | 299 file_util::PathExists(new_chrome_exe) && current_version->get() && |
907 new_version.Equals(**current_version) ? | 300 new_version.Equals(*current_version->get()) ? |
908 installer::SAME_VERSION_REPAIR_FAILED : | 301 installer::SAME_VERSION_REPAIR_FAILED : |
909 installer::INSTALL_FAILED; | 302 installer::INSTALL_FAILED; |
910 LOG(ERROR) << "Install failed, rolling back... result: " << result; | 303 LOG(ERROR) << "Install failed, rolling back... result: " << result; |
911 install_list->Rollback(); | 304 install_list->Rollback(); |
912 LOG(ERROR) << "Rollback complete. "; | 305 LOG(ERROR) << "Rollback complete. "; |
913 return result; | 306 return result; |
914 } | 307 } |
915 | 308 |
916 if (!current_version->get()) { | 309 if (!current_version->get()) { |
917 VLOG(1) << "First install of version " << new_version.GetString(); | 310 VLOG(1) << "First install of version " << new_version.GetString(); |
(...skipping 29 matching lines...) Expand all Loading... |
947 installer::InstallStatus InstallOrUpdateProduct( | 340 installer::InstallStatus InstallOrUpdateProduct( |
948 const InstallationState& original_state, | 341 const InstallationState& original_state, |
949 const InstallerState& installer_state, | 342 const InstallerState& installer_state, |
950 const FilePath& setup_path, const FilePath& archive_path, | 343 const FilePath& setup_path, const FilePath& archive_path, |
951 const FilePath& install_temp_path, const FilePath& prefs_path, | 344 const FilePath& install_temp_path, const FilePath& prefs_path, |
952 const installer::MasterPreferences& prefs, const Version& new_version, | 345 const installer::MasterPreferences& prefs, const Version& new_version, |
953 const Package& install) { | 346 const Package& install) { |
954 FilePath src_path(install_temp_path); | 347 FilePath src_path(install_temp_path); |
955 src_path = src_path.Append(kInstallSourceDir).Append(kInstallSourceChromeDir); | 348 src_path = src_path.Append(kInstallSourceDir).Append(kInstallSourceChromeDir); |
956 | 349 |
| 350 // TODO(robertshield): Removing the pending on-reboot moves should be done |
| 351 // elsewhere. |
| 352 const Products& products = install.products(); |
| 353 DCHECK(products.size()); |
| 354 if (FindProduct(products, BrowserDistribution::CHROME_FRAME)) { |
| 355 // Make sure that we don't end up deleting installed files on next reboot. |
| 356 if (!RemoveFromMovesPendingReboot(install.path().value().c_str())) { |
| 357 LOG(ERROR) << "Error accessing pending moves value."; |
| 358 } |
| 359 } |
| 360 |
957 scoped_ptr<Version> existing_version; | 361 scoped_ptr<Version> existing_version; |
958 installer::InstallStatus result = InstallNewVersion(original_state, | 362 installer::InstallStatus result = InstallNewVersion(original_state, |
959 installer_state, prefs.is_multi_install(), setup_path, archive_path, | 363 installer_state, prefs.is_multi_install(), setup_path, archive_path, |
960 src_path, install_temp_path, new_version, &existing_version, install); | 364 src_path, install_temp_path, new_version, &existing_version, install); |
961 | 365 |
| 366 // TODO(robertshield): Everything below this line should instead be captured |
| 367 // by WorkItems. |
962 if (!InstallUtil::GetInstallReturnCode(result)) { | 368 if (!InstallUtil::GetInstallReturnCode(result)) { |
963 if (result == installer::FIRST_INSTALL_SUCCESS && !prefs_path.empty()) | 369 if (result == installer::FIRST_INSTALL_SUCCESS && !prefs_path.empty()) |
964 CopyPreferenceFileForFirstRun(install, prefs_path); | 370 CopyPreferenceFileForFirstRun(install, prefs_path); |
965 | 371 |
966 bool do_not_create_shortcuts = false; | 372 bool do_not_create_shortcuts = false; |
967 prefs.GetBool(installer::master_preferences::kDoNotCreateShortcuts, | 373 prefs.GetBool(installer::master_preferences::kDoNotCreateShortcuts, |
968 &do_not_create_shortcuts); | 374 &do_not_create_shortcuts); |
969 | 375 |
970 // Currently this only creates shortcuts for Chrome, but for other products | 376 // Currently this only creates shortcuts for Chrome, but for other products |
971 // we might want to create shortcuts. | 377 // we might want to create shortcuts. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1004 make_chrome_default || force_chrome_default_for_user); | 410 make_chrome_default || force_chrome_default_for_user); |
1005 } | 411 } |
1006 | 412 |
1007 install.RemoveOldVersionDirectories(existing_version.get() ? | 413 install.RemoveOldVersionDirectories(existing_version.get() ? |
1008 *existing_version.get() : new_version); | 414 *existing_version.get() : new_version); |
1009 } | 415 } |
1010 | 416 |
1011 return result; | 417 return result; |
1012 } | 418 } |
1013 | 419 |
1014 void AddRegisterComDllWorkItems(const FilePath& dll_folder, | |
1015 const std::vector<FilePath>& dll_list, | |
1016 bool system_level, | |
1017 bool do_register, | |
1018 bool ignore_failures, | |
1019 WorkItemList* work_item_list) { | |
1020 DCHECK(work_item_list); | |
1021 if (dll_list.empty()) { | |
1022 VLOG(1) << "No COM DLLs to register"; | |
1023 } else { | |
1024 std::vector<FilePath>::const_iterator dll_iter(dll_list.begin()); | |
1025 for (; dll_iter != dll_list.end(); ++dll_iter) { | |
1026 FilePath dll_path = dll_folder.Append(*dll_iter); | |
1027 WorkItem* work_item = work_item_list->AddSelfRegWorkItem( | |
1028 dll_path.value(), do_register, !system_level); | |
1029 DCHECK(work_item); | |
1030 work_item->set_ignore_failure(ignore_failures); | |
1031 } | |
1032 } | |
1033 } | |
1034 | |
1035 void AddSetMsiMarkerWorkItem(const Product& product, | |
1036 bool set, | |
1037 WorkItemList* work_item_list) { | |
1038 DCHECK(work_item_list); | |
1039 BrowserDistribution* dist = product.distribution(); | |
1040 HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE : | |
1041 HKEY_CURRENT_USER; | |
1042 DWORD msi_value = set ? 1 : 0; | |
1043 WorkItem* set_msi_work_item = work_item_list->AddSetRegValueWorkItem( | |
1044 reg_root, dist->GetStateKey(), google_update::kRegMSIField, | |
1045 msi_value, true); | |
1046 DCHECK(set_msi_work_item); | |
1047 set_msi_work_item->set_ignore_failure(true); | |
1048 set_msi_work_item->set_log_message("Could not write MSI marker!"); | |
1049 } | |
1050 | |
1051 void AddChromeFrameWorkItems(bool install, | |
1052 const FilePath& setup_path, | |
1053 const Version& new_version, | |
1054 const Product& product, | |
1055 WorkItemList* list) { | |
1056 DCHECK(product.is_chrome_frame()); | |
1057 if (!product.package().multi_install()) { | |
1058 VLOG(1) << "Not adding GCF specific work items for single install."; | |
1059 return; | |
1060 } | |
1061 | |
1062 // TODO(tommi): This assumes we know exactly how ShouldCreateUninstallEntry | |
1063 // is implemented. Since there is logic in ChromeFrameDistribution for how | |
1064 // to determine when this is enabled, this is how we have to figure out if | |
1065 // this feature is enabled right now, but it's a hack and we need a cleaner | |
1066 // way to figure this out. | |
1067 // Note that we cannot just check the master preferences for | |
1068 // kChromeFrameReadyMode, since there are other things that need to be correct | |
1069 // in the environment in order to enable this feature. | |
1070 bool ready_mode = !product.distribution()->ShouldCreateUninstallEntry(); | |
1071 | |
1072 HKEY root = product.package().system_level() ? HKEY_LOCAL_MACHINE : | |
1073 HKEY_CURRENT_USER; | |
1074 bool update_chrome_uninstall_command = false; | |
1075 if (ready_mode) { | |
1076 // If GCF is being installed in ready mode, we write an entry to the | |
1077 // multi-install state key. If the value already exists, we will not | |
1078 // overwrite it since the user might have opted out. | |
1079 list->AddCreateRegKeyWorkItem(root, | |
1080 product.package().properties()->GetStateKey()); | |
1081 list->AddSetRegValueWorkItem(root, | |
1082 product.package().properties()->GetStateKey(), | |
1083 installer::kChromeFrameReadyModeField, | |
1084 install ? 1 : 0, // The value we want to set. | |
1085 install ? false : true); // Overwrite existing value. | |
1086 if (!install) { | |
1087 // If Chrome is not also being uninstalled, we need to update its command | |
1088 // line so that it doesn't include uninstalling Chrome Frame now. | |
1089 update_chrome_uninstall_command = | |
1090 (installer::FindProduct(product.package().products(), | |
1091 BrowserDistribution::CHROME_BROWSER) == NULL); | |
1092 } | |
1093 } else { | |
1094 // It doesn't matter here if we're installing or uninstalling Chrome Frame. | |
1095 // If ready mode isn't specified on the command line for installs, we need | |
1096 // to delete the ready mode flag from the registry if it exists - this | |
1097 // constitutes an opt-in for the user. If we're uninstalling CF and ready | |
1098 // mode isn't specified on the command line, that means that CF wasn't | |
1099 // installed with ready mode enabled (the --ready-mode switch should be set | |
1100 // in the registry) so deleting the value should have no effect. | |
1101 // In both cases (install/uninstall), we need to make sure that Chrome's | |
1102 // uninstallation command line does not include the --chrome-frame switch | |
1103 // so that uninstalling Chrome will no longer uninstall Chrome Frame. | |
1104 | |
1105 if (RegKey(root, product.package().properties()->GetStateKey().c_str(), | |
1106 KEY_QUERY_VALUE).Valid()) { | |
1107 list->AddDeleteRegValueWorkItem(root, | |
1108 product.package().properties()->GetStateKey(), | |
1109 installer::kChromeFrameReadyModeField, false); | |
1110 } | |
1111 | |
1112 const Product* chrome = installer::FindProduct(product.package().products(), | |
1113 BrowserDistribution::CHROME_BROWSER); | |
1114 if (chrome) { | |
1115 // Chrome is already a part of this installation run, so we can assume | |
1116 // that the uninstallation arguments will be updated correctly. | |
1117 } else { | |
1118 // Chrome is not a part of this installation run, so we have to explicitly | |
1119 // check if Chrome is installed, and if so, update its uninstallation | |
1120 // command lines. | |
1121 BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution( | |
1122 BrowserDistribution::CHROME_BROWSER, | |
1123 MasterPreferences::ForCurrentProcess()); | |
1124 update_chrome_uninstall_command = | |
1125 IsInstalledAsMulti(product.system_level(), dist); | |
1126 } | |
1127 } | |
1128 | |
1129 if (update_chrome_uninstall_command) { | |
1130 // Chrome is not a part of this installation run, so we have to explicitly | |
1131 // check if Chrome is installed, and if so, update its uninstallation | |
1132 // command lines. | |
1133 const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess(); | |
1134 BrowserDistribution* chrome_dist = | |
1135 BrowserDistribution::GetSpecificDistribution( | |
1136 BrowserDistribution::CHROME_BROWSER, prefs); | |
1137 const Package& pack = product.package(); | |
1138 scoped_refptr<Package> package(new Package(pack.multi_install(), | |
1139 pack.system_level(), pack.path(), pack.properties())); | |
1140 scoped_refptr<Product> chrome_product(new Product(chrome_dist, package)); | |
1141 AddUninstallShortcutWorkItems(setup_path, new_version, list, | |
1142 *chrome_product.get()); | |
1143 } | |
1144 } | |
1145 | |
1146 InstallStatus ChromeFrameReadyModeOptIn(const InstallerState& installer_state, | 420 InstallStatus ChromeFrameReadyModeOptIn(const InstallerState& installer_state, |
1147 const CommandLine& cmd_line) { | 421 const CommandLine& cmd_line) { |
1148 VLOG(1) << "Opting into Chrome Frame"; | 422 VLOG(1) << "Opting into Chrome Frame"; |
1149 InstallStatus status = INSTALL_REPAIRED; | 423 InstallStatus status = INSTALL_REPAIRED; |
1150 | 424 |
1151 const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess(); | 425 const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess(); |
1152 bool system_install = false; | 426 bool system_install = false; |
1153 prefs.GetBool(master_preferences::kSystemLevel, &system_install); | 427 prefs.GetBool(master_preferences::kSystemLevel, &system_install); |
1154 BrowserDistribution* cf = BrowserDistribution::GetSpecificDistribution( | 428 BrowserDistribution* cf = BrowserDistribution::GetSpecificDistribution( |
1155 BrowserDistribution::CHROME_FRAME, prefs); | 429 BrowserDistribution::CHROME_FRAME, prefs); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1201 LOG(ERROR) << "Failed to opt into GCF"; | 475 LOG(ERROR) << "Failed to opt into GCF"; |
1202 item_list->Rollback(); | 476 item_list->Rollback(); |
1203 status = READY_MODE_OPT_IN_FAILED; | 477 status = READY_MODE_OPT_IN_FAILED; |
1204 } | 478 } |
1205 } | 479 } |
1206 | 480 |
1207 return status; | 481 return status; |
1208 } | 482 } |
1209 | 483 |
1210 } // namespace installer | 484 } // namespace installer |
OLD | NEW |