Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(269)

Side by Side Diff: client/install.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « client/install.h ('k') | client/install_apps.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2007-2010 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15
16 #include "omaha/client/install.h"
17 #include "omaha/client/install_internal.h"
18 #include "omaha/base/app_util.h"
19 #include "omaha/base/const_object_names.h"
20 #include "omaha/base/debug.h"
21 #include "omaha/base/error.h"
22 #include "omaha/base/file.h"
23 #include "omaha/base/logging.h"
24 #include "omaha/base/omaha_version.h"
25 #include "omaha/base/path.h"
26 #include "omaha/base/process.h"
27 #include "omaha/base/reg_key.h"
28 #include "omaha/base/scoped_any.h"
29 #include "omaha/base/string.h"
30 #include "omaha/base/time.h"
31 #include "omaha/base/utils.h"
32 #include "omaha/base/vistautil.h"
33 #include "omaha/client/client_utils.h"
34 #include "omaha/client/install_self.h"
35 #include "omaha/client/resource.h"
36 #include "omaha/common/app_registry_utils.h"
37 #include "omaha/common/command_line_builder.h"
38 #include "omaha/common/config_manager.h"
39 #include "omaha/common/const_cmd_line.h"
40 #include "omaha/common/const_goopdate.h"
41 #include "omaha/common/goopdate_utils.h"
42 #include "omaha/common/oem_install_utils.h"
43 #include "omaha/common/ping.h"
44 #include "omaha/setup/setup_metrics.h"
45 #include "omaha/ui/splash_screen.h"
46
47 namespace omaha {
48
49 namespace {
50
51 // Returns whether elevation is required.
52 bool IsElevationRequired(bool is_machine) {
53 return is_machine && !vista_util::IsUserAdmin();
54 }
55
56 } // namespace
57
58 namespace internal {
59
60 // TODO(omaha3): Make this elevate the metainstaller instead of
61 // GoogleUpdate.exe so the files are extracted to a secure location.
62 // May need to add all languages to the metainstaller's version resources so
63 // the user sees the localized string in the UAC.
64 // TODO(omaha3): We will need to save the metainstaller for OneClick
65 // cross-installs. We may need to change the metainstaller behavior to not
66 // use the tag if any command line args are provided. This will allow us to
67 // reuse a tagged metainstaller that we saved for other purposes, such as
68 // OneClick cross-installs.
69 // TODO(omaha3): The "metainstaller" may also be some type of wrapper around
70 // a differential update. We'll address that later. This wrapper should not
71 // need localized resource strings since it always runs silently.
72 HRESULT DoElevation(bool is_interactive,
73 bool is_install_elevated_instance,
74 const CString& cmd_line,
75 DWORD* exit_code) {
76 ASSERT1(exit_code);
77 ASSERT1(IsElevationRequired(true));
78
79 if (!is_interactive) {
80 return GOOPDATE_E_SILENT_INSTALL_NEEDS_ELEVATION;
81 }
82
83 if (is_install_elevated_instance) {
84 // This can happen if UAC is disabled. See http://b/1187784.
85 CORE_LOG(LE, (_T("[Install elevated process requires elevation]")));
86 return GOOPDATE_E_INSTALL_ELEVATED_PROCESS_NEEDS_ELEVATION;
87 }
88
89 HRESULT hr = ElevateAndWait(cmd_line, exit_code);
90 if (FAILED(hr)) {
91 CORE_LOG(LE, (_T("[ElevateAndWait failed][%s][0x%08x]"), cmd_line, hr));
92 }
93
94 return hr;
95 }
96
97 // Assumes it is running with the necessary privileges.
98 HRESULT DoInstall(bool is_machine,
99 bool is_app_install,
100 bool is_eula_required,
101 bool is_oem_install,
102 const CString& current_version,
103 const CommandLineArgs& args,
104 const CString& session_id,
105 SplashScreen* splash_screen,
106 int* extra_code1,
107 bool* has_setup_succeeded,
108 bool* has_launched_handoff,
109 bool* has_ui_been_displayed) {
110 ASSERT1(!IsElevationRequired(is_machine));
111 ASSERT1(extra_code1);
112 ASSERT1(splash_screen);
113 ASSERT1(has_setup_succeeded);
114 ASSERT1(has_launched_handoff);
115 ASSERT1(has_ui_been_displayed);
116
117 *extra_code1 = 0;
118
119 // TODO(omaha3): We may need to take an "installing apps" lock here if
120 // is_app_install. There was code in Omaha 2 that relied on the fact that
121 // the Setup lock was held while the install worker was launched, even in
122 // handoff scenarios. This allowed checking for the Setup lock and running
123 // install workers to be sufficient to ensure that the number of Clients keys
124 // was stable. Note that Omaha 2 also held the shutdown event while the worker
125 // was launched.
126 // TODO(omaha3): Consider taking the Setup lock in this file (via a public
127 // method in Setup) and releasing it. This would allow us to address the above
128 // issue and maybe the EULA not accepted issue.
129 // TODO(omaha3): We may also want to call ShouldInstall after a Lock(0) to
130 // determine whether we even need to display the splash screen or we can skip
131 // it and Setup altogether and just launch the /handoff process.
132
133 HRESULT hr = install_self::InstallSelf(is_machine,
134 is_eula_required,
135 is_oem_install,
136 current_version,
137 args.install_source,
138 args.extra,
139 session_id,
140 extra_code1);
141 *has_setup_succeeded = SUCCEEDED(hr);
142 if (FAILED(hr)) {
143 OPT_LOG(LE, (_T("[InstallSelf failed][0x%08x]"), hr));
144 return hr;
145 }
146
147 if (!is_app_install) {
148 return S_OK;
149 }
150
151 hr = InstallApplications(is_machine,
152 is_eula_required,
153 args,
154 session_id,
155 splash_screen,
156 has_ui_been_displayed,
157 has_launched_handoff);
158 if (FAILED(hr)) {
159 OPT_LOG(LE, (_T("[InstallApplications failed][0x%08x]"), hr));
160 return hr;
161 }
162
163 return S_OK;
164 };
165
166 HRESULT InstallApplications(bool is_machine,
167 bool is_eula_required,
168 const CommandLineArgs& args,
169 const CString& session_id,
170 SplashScreen* splash_screen,
171 bool* has_ui_been_displayed,
172 bool* has_launched_handoff) {
173 ASSERT1(has_ui_been_displayed);
174 ASSERT1(has_launched_handoff);
175
176 *has_launched_handoff = false;
177
178 CString offline_dir;
179 const bool is_offline_install = CopyOfflineFiles(is_machine,
180 args.extra.apps,
181 &offline_dir);
182 if (!is_offline_install && oem_install_utils::IsOemInstalling(is_machine)) {
183 return GOOPDATE_E_OEM_WITH_ONLINE_INSTALLER;
184 }
185 if (!is_offline_install && is_eula_required) {
186 return GOOPDATE_E_EULA_REQURED_WITH_ONLINE_INSTALLER;
187 }
188
189 // Start the handoff to install the app.
190 scoped_process handoff_process;
191 HRESULT hr = LaunchHandoffProcess(is_machine,
192 offline_dir,
193 args,
194 session_id,
195 address(handoff_process));
196 if (FAILED(hr)) {
197 OPT_LOG(LE, (_T("[Failed to launch installed instance][0x%08x]"), hr));
198 return hr;
199 }
200
201 *has_launched_handoff = true;
202
203 OPT_LOG(L1, (_T("[Waiting for application install to complete]")));
204 uint32 exit_code(0);
205 hr = WaitForProcessExit(get(handoff_process),
206 splash_screen,
207 has_ui_been_displayed,
208 &exit_code);
209
210 if (FAILED(hr)) {
211 OPT_LOG(LE, (_T("[Failed waiting for app install][0x%08x]"), hr));
212 return hr;
213 }
214 if (exit_code) {
215 OPT_LOG(LE, (_T("[Handoff exited with error][0x%08x]"), exit_code));
216 ASSERT1(FAILED(exit_code));
217 return exit_code;
218 }
219
220 return S_OK;
221 }
222
223 // The behavior depends on the OS:
224 // 1. OS < Vista : Fail.
225 // 2. OS >= Vista : Try to elevate - causes a UAC dialog.
226 // We should be here only in case of initial machine installs when the user is
227 // not an elevated admin.
228 HRESULT ElevateAndWait(const CString& cmd_line, DWORD* exit_code) {
229 OPT_LOG(L1, (_T("[Elevating][%s]"), cmd_line));
230 ASSERT1(!vista_util::IsUserAdmin());
231 ASSERT1(exit_code);
232
233 if (!vista_util::IsVistaOrLater()) {
234 // TODO(omaha): We could consider to ask for credentials here.
235 // This TODO existed in Omaha 1. How would we even do this?
236 CORE_LOG(LE, (_T("[Non Admin trying to install admin app]")));
237 ++metric_setup_machine_app_non_admin;
238 return GOOPDATE_E_NONADMIN_INSTALL_ADMIN_APP;
239 }
240
241 CString cmd_line_elevated(GetCmdLineTail(cmd_line));
242 cmd_line_elevated.AppendFormat(_T(" /%s"), kCmdLineInstallElevated);
243
244 HRESULT hr = goopdate_utils::StartElevatedSelfWithArgsAndWait(
245 cmd_line_elevated, exit_code);
246 if (FAILED(hr)) {
247 OPT_LOG(LE, (_T("[Starting elevated GoogleUpdate.exe failed][%s][0x%08x]"),
248 cmd_line, hr));
249
250 // TODO(omaha3): Report hr somehow. Was reported in extra code in Omaha 2.
251 if (vista_util::IsUserNonElevatedAdmin()) {
252 return GOOPDATE_E_ELEVATION_FAILED_ADMIN;
253 } else {
254 return GOOPDATE_E_ELEVATION_FAILED_NON_ADMIN;
255 }
256 }
257
258 return S_OK;
259 }
260
261 bool CopyOfflineFiles(bool is_machine,
262 const std::vector<CommandLineAppArgs>& apps,
263 CString* offline_dir) {
264 ASSERT1(offline_dir);
265 offline_dir->Empty();
266
267 if (apps.empty()) {
268 return false;
269 }
270
271 GUID guid(GUID_NULL);
272 VERIFY1(SUCCEEDED(::CoCreateGuid(&guid)));
273 CString parent_offline_dir(
274 is_machine ?
275 ConfigManager::Instance()->GetMachineSecureOfflineStorageDir() :
276 ConfigManager::Instance()->GetUserOfflineStorageDir());
277 CString unique_offline_dir =
278 ConcatenatePath(parent_offline_dir, GuidToString(guid));
279 VERIFY1(SUCCEEDED(CreateDir(unique_offline_dir, NULL)));
280
281 HRESULT hr = CopyOfflineManifest(unique_offline_dir);
282 if (FAILED(hr)) {
283 CORE_LOG(L3, (_T("[CopyOfflineManifest failed][0x%08x]"), hr));
284 return false;
285 }
286
287 for (size_t i = 0; i < apps.size(); ++i) {
288 const GUID& app_id = apps[i].app_guid;
289 HRESULT hr = CopyOfflineFilesForApp(GuidToString(app_id),
290 unique_offline_dir);
291 if (FAILED(hr)) {
292 ASSERT(false, (_T("[CopyOfflineFilesForApp failed][0x%08x]"), hr));
293 return false;
294 }
295 }
296
297 CORE_LOG(L3, (_T("[CopyOfflineFiles done][%s]"), unique_offline_dir));
298 *offline_dir = unique_offline_dir;
299 return true;
300 }
301
302 HRESULT CopyOfflineManifest(const CString& offline_dir) {
303 CORE_LOG(L3, (_T("[CopyOfflineManifest][%s]"), offline_dir));
304
305 // Copy offline manifest into "<offline_dir>\<kOfflineManifestFileName>".
306 CString setup_temp_dir(app_util::GetCurrentModuleDirectory());
307 CString source_manifest_path = ConcatenatePath(setup_temp_dir,
308 kOfflineManifestFileName);
309 if (!File::Exists(source_manifest_path)) {
310 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
311 }
312 CString dest_manifest_path = ConcatenatePath(offline_dir,
313 kOfflineManifestFileName);
314 HRESULT hr = File::Copy(source_manifest_path, dest_manifest_path, true);
315 if (FAILED(hr)) {
316 CORE_LOG(LE, (_T("[File copy failed][%s][%s][0x%08x]"),
317 source_manifest_path, dest_manifest_path, hr));
318 return hr;
319 }
320
321 return S_OK;
322 }
323
324 HRESULT CopyOfflineFilesForApp(const CString& app_id,
325 const CString& offline_dir) {
326 CORE_LOG(L3, (_T("[CopyOfflineFilesForApp][%s][%s]"),
327 app_id, offline_dir));
328
329 CString setup_temp_dir(app_util::GetCurrentModuleDirectory());
330 CString pattern;
331 // Copy the installer files that are named with the pattern "*.<app_id>" to
332 // the directory "<offline_dir>\<app_id>".
333 pattern.Format(_T("*.%s"), app_id);
334 std::vector<CString> files;
335 HRESULT hr = FindFiles(setup_temp_dir, pattern, &files);
336 if (FAILED(hr)) {
337 CORE_LOG(LE, (_T("[FindFiles failed][0x%08x]"), hr));
338 return hr;
339 }
340 if (files.empty()) {
341 CORE_LOG(LE, (_T("[FindFiles found no files]")));
342 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
343 }
344
345 CString offline_app_dir = ConcatenatePath(offline_dir, app_id);
346 if (File::IsDirectory(offline_app_dir)) {
347 VERIFY1(SUCCEEDED(DeleteDirectoryFiles(offline_app_dir)));
348 } else {
349 hr = CreateDir(offline_app_dir, NULL);
350 if (FAILED(hr)) {
351 CORE_LOG(LE, (_T("[CreateDir failed][%s]"), offline_app_dir));
352 return hr;
353 }
354 }
355
356 for (size_t i = 0; i < files.size(); ++i) {
357 const CString& file_name = files[i];
358 ASSERT1(file_name.GetLength() > app_id.GetLength());
359
360 CPath renamed_file_name(file_name);
361 renamed_file_name.RemoveExtension();
362 ASSERT1(file_name.Left(file_name.GetLength() - app_id.GetLength() - 1) ==
363 static_cast<const CString&>(renamed_file_name));
364 CString new_file_path = ConcatenatePath(offline_app_dir, renamed_file_name);
365 CORE_LOG(L4, (_T("[new_file_path][%s]"), new_file_path));
366
367 CString source_file_path = ConcatenatePath(setup_temp_dir, file_name);
368 hr = File::Copy(source_file_path, new_file_path, true);
369 if (FAILED(hr)) {
370 CORE_LOG(LE, (_T("[Copy failed][%s][%s]"),
371 source_file_path, new_file_path));
372 return hr;
373 }
374 }
375
376 return S_OK;
377 }
378
379
380 // TODO(omaha3): This implementation requires updating this code whenever a
381 // new option is added. We could do a string replace of "/install" with
382 // "/handoff", but we'd need to remove things such as /oem. Alternatively,
383 // allow a CommandLineBuilder to be populated with existing args. Doing
384 // replacement would allow us to only pass one copy of the command line to
385 // Install() instead of passing both the string and struct. Be sure to handle
386 // /appargs when making any changes.
387 // TODO(omaha): Extract the command line building and unit test it.
388 HRESULT LaunchHandoffProcess(bool is_machine,
389 const CString& offline_dir,
390 const CommandLineArgs& install_args,
391 const CString& session_id,
392 HANDLE* process) { // process can be NULL.
393 CORE_LOG(L2, (_T("[LaunchHandoffProcess]")));
394
395 // The install source has been either specified or set to a default value by
396 // the time the execution flow reaches this function. The install source is
397 // propagated to the handoff process except in certain offline install cases,
398 // such as a tagged offline installer or an offline installer that did not
399 // have an install source.
400 //
401 // TODO(omaha): refactor so that the handling of the install source is
402 // encapsulated in just one module.
403 ASSERT1(!install_args.install_source.IsEmpty());
404 ASSERT1(!install_args.extra_args_str.IsEmpty());
405
406 CommandLineBuilder builder(COMMANDLINE_MODE_HANDOFF_INSTALL);
407
408 builder.set_is_silent_set(install_args.is_silent_set);
409 builder.set_is_eula_required_set(install_args.is_eula_required_set);
410 builder.set_extra_args(install_args.extra_args_str);
411 builder.set_app_args(install_args.app_args_str);
412 builder.set_install_source(install_args.install_source);
413 builder.set_session_id(session_id);
414
415 if (!offline_dir.IsEmpty()) {
416 builder.SetOfflineDir(offline_dir);
417 const CString& install_source(install_args.install_source);
418 if (install_source == kCmdLineInstallSource_InstallDefault ||
419 install_source == kCmdLineInstallSource_TaggedMetainstaller) {
420 builder.set_install_source(kCmdLineInstallSource_Offline);
421 }
422 }
423
424 CString cmd_line = builder.GetCommandLineArgs();
425
426 HRESULT hr = goopdate_utils::StartGoogleUpdateWithArgs(is_machine,
427 cmd_line,
428 process);
429 if (FAILED(hr)) {
430 OPT_LOG(LE, (_T("[Google Update hand off failed][%s][0x%08x]"),
431 cmd_line, hr));
432 // TODO(omaha3): Report hr somehow. Was reported in extra code in Omaha 2.
433 return GOOPDATE_E_HANDOFF_FAILED;
434 }
435
436 return S_OK;
437 }
438
439 HRESULT WaitForProcessExit(HANDLE process,
440 SplashScreen* splash_screen,
441 bool* has_ui_been_displayed,
442 uint32* exit_code) {
443 CORE_LOG(L3, (_T("[WaitForProcessExit]")));
444 ASSERT1(process);
445 ASSERT1(exit_code);
446 ASSERT1(has_ui_been_displayed);
447 *exit_code = 0;
448
449 int res = ::WaitForInputIdle(process, INFINITE);
450 if (res == 0) {
451 *has_ui_been_displayed = true;
452 }
453 if (splash_screen) {
454 splash_screen->Dismiss();
455 }
456
457 res = ::WaitForSingleObject(process, INFINITE);
458 ASSERT1(WAIT_OBJECT_0 == res);
459 if (WAIT_FAILED == res) {
460 DWORD error = ::GetLastError();
461 CORE_LOG(LE, (_T("[::WaitForMultipleObjects failed][%u]"), error));
462 return HRESULT_FROM_WIN32(error);
463 }
464
465 // Get the exit code.
466 DWORD local_exit_code = 0;
467 if (::GetExitCodeProcess(process, &local_exit_code)) {
468 CORE_LOG(L2, (_T("[process exited][PID %u][exit code 0x%08x]"),
469 Process::GetProcessIdFromHandle(process), local_exit_code));
470 *exit_code = local_exit_code;
471 } else {
472 DWORD error = ::GetLastError();
473 CORE_LOG(LE, (_T("[::GetExitCodeProcess failed][%u]"), error));
474 return HRESULT_FROM_WIN32(error);
475 }
476
477 return S_OK;
478 }
479
480 // TODO(omaha): needs to handle errors when loading the strings.
481 CString GetErrorText(HRESULT error, const CString& bundle_name) {
482 ASSERT1(!bundle_name.IsEmpty());
483
484 CString error_text;
485
486 switch (error) {
487 case GOOPDATE_E_INSTALL_ELEVATED_PROCESS_NEEDS_ELEVATION:
488 case GOOPDATE_E_NONADMIN_INSTALL_ADMIN_APP:
489 error_text.FormatMessage(IDS_NEED_ADMIN_TO_INSTALL, bundle_name);
490 break;
491 case GOOPDATE_E_ELEVATION_FAILED_ADMIN:
492 case GOOPDATE_E_ELEVATION_FAILED_NON_ADMIN:
493 error_text.FormatMessage(IDS_ELEVATION_FAILED, bundle_name);
494 break;
495 case GOOPDATE_E_FAILED_TO_GET_LOCK:
496 case GOOPDATE_E_FAILED_TO_GET_LOCK_MATCHING_INSTALL_PROCESS_RUNNING:
497 case GOOPDATE_E_FAILED_TO_GET_LOCK_NONMATCHING_INSTALL_PROCESS_RUNNING:
498 case GOOPDATE_E_FAILED_TO_GET_LOCK_UPDATE_PROCESS_RUNNING:
499 {
500 CString company_name;
501 VERIFY1(company_name.LoadString(IDS_FRIENDLY_COMPANY_NAME));
502 error_text.FormatMessage(IDS_APPLICATION_INSTALLING_GOOGLE_UPDATE,
503 company_name,
504 bundle_name);
505 }
506 break;
507 case GOOPDATE_E_INSTANCES_RUNNING:
508 {
509 CString company_name;
510 VERIFY1(company_name.LoadString(IDS_FRIENDLY_COMPANY_NAME));
511 error_text.FormatMessage(IDS_INSTANCES_RUNNING_AFTER_SHUTDOWN,
512 company_name,
513 bundle_name);
514 }
515 break;
516 case GOOPDATE_E_RUNNING_INFERIOR_MSXML:
517 error_text.FormatMessage(IDS_WINDOWS_IS_NOT_UP_TO_DATE, bundle_name);
518 break;
519 case GOOPDATE_E_HANDOFF_FAILED:
520 error_text.FormatMessage(IDS_HANDOFF_FAILED, bundle_name);
521 break;
522 default:
523 {
524 CString product_name;
525 VERIFY1(product_name.LoadString(IDS_PRODUCT_DISPLAY_NAME));
526 error_text.FormatMessage(IDS_SETUP_FAILED, product_name, error);
527 }
528 break;
529 }
530
531 return error_text;
532 }
533
534 // Displays an error in the Google Update UI and sends a ping if allowed.
535 void HandleInstallError(HRESULT error,
536 int extra_code1,
537 const CString& session_id,
538 bool is_machine,
539 bool is_interactive,
540 bool is_eula_required,
541 bool is_oem_install,
542 const CString& current_version,
543 const CString& install_source,
544 const CommandLineExtraArgs& extra_args,
545 bool has_setup_succeeded,
546 bool has_launched_handoff,
547 bool* has_ui_been_displayed) {
548 ASSERT1(FAILED(error));
549 ASSERT1(has_ui_been_displayed);
550
551 const CString& bundle_name(extra_args.bundle_name);
552 const CString error_text(GetErrorText(error, bundle_name));
553
554 OPT_LOG(LE, (_T("[Failed to install][0x%08x][%s]"), error, error_text));
555
556 if (is_interactive && !*has_ui_been_displayed) {
557 CString primary_app_id;
558 if (!extra_args.apps.empty()) {
559 primary_app_id = GuidToString(extra_args.apps[0].app_guid);
560 }
561 *has_ui_been_displayed = client_utils::DisplayError(
562 is_machine,
563 bundle_name,
564 error,
565 extra_code1,
566 error_text,
567 primary_app_id,
568 extra_args.language,
569 extra_args.installation_id,
570 extra_args.brand_code);
571 }
572
573 // Send an EVENT_INSTALL_COMPLETE ping for Omaha and wait for the ping to be
574 // sent. This ping may cause a firewall prompt since the process sending the
575 // ping may run from a temporary directory.
576 //
577 // An EVENT_INSTALL_COMPLETE ping for the apps is also sent in the case the
578 /// handoff process did not launch successfully, otherwise, the handoff
579 // process is responsible for sending this ping.
580 //
581 // Setup can fail before setting either eula or oem states in the
582 // registry. Therefore, ConfigManager::CanUseNetwork can't be called yet.
583 if (is_eula_required || is_oem_install) {
584 return;
585 }
586 Ping ping(is_machine, session_id, install_source);
587 ping.LoadAppDataFromExtraArgs(extra_args);
588 if (!has_setup_succeeded) {
589 PingEventPtr setup_install_complete_ping_event(
590 new PingEvent(PingEvent::EVENT_INSTALL_COMPLETE, // Type 2.
591 PingEvent::EVENT_RESULT_ERROR,
592 error,
593 extra_code1));
594 const CString next_version(GetVersionString());
595 ping.BuildOmahaPing(current_version,
596 next_version,
597 setup_install_complete_ping_event);
598 }
599 if (!has_launched_handoff) {
600 PingEventPtr install_complete_ping_event(
601 new PingEvent(PingEvent::EVENT_INSTALL_COMPLETE, // Type 2.
602 PingEvent::EVENT_RESULT_ERROR,
603 error,
604 extra_code1));
605 ping.BuildAppsPing(install_complete_ping_event);
606 }
607 HRESULT hr = ping.Send(false);
608 if (FAILED(hr)) {
609 CORE_LOG(LW, (_T("[Ping::Send failed][0x%x]"), hr));
610 }
611 }
612
613 } // namespace internal
614
615 // This function handles command-line installs. This is the only function that
616 // can install Omaha in non-update cases. If elevation is required, the function
617 // elevates an instance of Omaha and waits for that instance to exit before
618 // returning. If needed, the function starts a handoff process to install the
619 // applications and waits for the handoff process to exit.
620 //
621 // 'install_cmd_line' parameter is the command line for the current instance and
622 // used to elevate if necessary.
623 // 'args' parameter is the parsed args corresponding to install_cmd_line and it
624 // is used to build the handoff command line if necessary.
625 HRESULT Install(bool is_interactive,
626 bool is_app_install,
627 bool is_eula_required,
628 bool is_oem_install,
629 bool is_install_elevated_instance,
630 const CString& install_cmd_line,
631 const CommandLineArgs& args,
632 bool* is_machine,
633 bool* has_ui_been_displayed) {
634 ASSERT1(!install_cmd_line.IsEmpty());
635 ASSERT1(is_machine);
636 ASSERT1(has_ui_been_displayed);
637
638 CORE_LOG(L2, (_T("[Install][%d][%d][%s]"),
639 *is_machine, is_interactive, install_cmd_line));
640 ++metric_setup_install_total;
641 if (is_install_elevated_instance) {
642 ++metric_setup_uac_succeeded;
643 }
644
645 if (!*is_machine &&
646 vista_util::IsVistaOrLater() &&
647 vista_util::IsUserAdmin()) {
648 ++metric_setup_user_app_admin;
649 }
650
651 // Allocate a session ID to connect all update checks and pings involved
652 // with this run of Omaha. This will need to be passed along to any child
653 // processes we create.
654 CString session_id;
655 VERIFY1(SUCCEEDED(GetGuid(&session_id)));
656
657 // 'current_version' corresponds to the value of 'pv' read from
658 // registry. This value is either empty, in the case of a new install or
659 // the version of the installed Omaha before the setup code ran.
660 CString current_version;
661 app_registry_utils::GetAppVersion(*is_machine,
662 kGoogleUpdateAppId,
663 &current_version);
664
665 bool has_setup_succeeded = false;
666 bool has_launched_handoff = false;
667
668 if (IsElevationRequired(*is_machine)) {
669 ASSERT1(!ConfigManager::Instance()->IsWindowsInstalling());
670
671 DWORD exit_code = 0;
672 HRESULT hr = internal::DoElevation(is_interactive,
673 is_install_elevated_instance,
674 install_cmd_line,
675 &exit_code);
676
677 if (FAILED(hr)) {
678 CORE_LOG(LE, (_T("[DoElevation failed][%s][0x%08x]"),
679 install_cmd_line, hr));
680
681 bool attempt_per_user_install = false;
682 if (is_interactive &&
683 args.extra.apps[0].needs_admin == NEEDS_ADMIN_PREFERS) {
684 if (hr == GOOPDATE_E_NONADMIN_INSTALL_ADMIN_APP ||
685 hr == GOOPDATE_E_INSTALL_ELEVATED_PROCESS_NEEDS_ELEVATION) {
686 attempt_per_user_install = true;
687 } else {
688 *has_ui_been_displayed = client_utils::DisplayContinueAsNonAdmin(
689 args.extra.bundle_name, &attempt_per_user_install);
690 }
691 }
692
693 if (attempt_per_user_install) {
694 *is_machine = false;
695 CString no_admin_cmd_line(String_ReplaceIgnoreCase(install_cmd_line,
696 kNeedsAdminPrefers,
697 kNeedsAdminNo));
698 CommandLineArgs no_admin_args = args;
699 no_admin_args.extra.apps[0].needs_admin = NEEDS_ADMIN_NO;
700 no_admin_args.extra_args_str = String_ReplaceIgnoreCase(
701 no_admin_args.extra_args_str, kNeedsAdminPrefers, kNeedsAdminNo);
702
703 return Install(is_interactive,
704 is_app_install,
705 is_eula_required,
706 is_oem_install,
707 is_install_elevated_instance,
708 no_admin_cmd_line,
709 no_admin_args,
710 is_machine,
711 has_ui_been_displayed);
712 }
713
714 internal::HandleInstallError(hr,
715 0,
716 session_id,
717 *is_machine,
718 is_interactive,
719 is_eula_required,
720 is_oem_install,
721 current_version,
722 args.install_source,
723 args.extra,
724 has_setup_succeeded,
725 has_launched_handoff,
726 has_ui_been_displayed);
727 return hr;
728 }
729
730 // TODO(omaha): waiting for input idle of an elevated process fails if the
731 // caller is not elevated. The code assumes that the elevated process
732 // displays UI if the elevation succeeded. It is possible that the elevated
733 // process ran but had terminated before displaying UI. This is an uncommon
734 // case and for simplicity, it is not handled here.
735 *has_ui_been_displayed = true;
736
737 return exit_code;
738 }
739
740 SplashScreen splash_screen(args.extra.bundle_name);
741 if (is_interactive) {
742 splash_screen.Show();
743 }
744
745 int extra_code1 = 0;
746 HRESULT hr = internal::DoInstall(*is_machine,
747 is_app_install,
748 is_eula_required,
749 is_oem_install,
750 current_version,
751 args,
752 session_id,
753 &splash_screen,
754 &extra_code1,
755 &has_setup_succeeded,
756 &has_launched_handoff,
757 has_ui_been_displayed);
758 if (is_interactive) {
759 splash_screen.Dismiss();
760 }
761
762 if (FAILED(hr)) {
763 CORE_LOG(LE, (_T("[DoInstall failed][0x%08x]"), hr));
764 internal::HandleInstallError(hr,
765 extra_code1,
766 session_id,
767 *is_machine,
768 is_interactive,
769 is_eula_required,
770 is_oem_install,
771 current_version,
772 args.install_source,
773 args.extra,
774 has_setup_succeeded,
775 has_launched_handoff,
776 has_ui_been_displayed);
777 return hr;
778 }
779
780 if (!is_app_install) {
781 // TODO(omaha): Display UI if we want to support interactive Omaha-only
782 // installs.
783 ASSERT1(!is_interactive);
784 // TODO(omaha3): Figure out a way to send a ping from the installed location
785 // for Omaha-only install success.
786 }
787
788 ++metric_setup_install_succeeded;
789 return S_OK;
790 }
791
792 HRESULT OemInstall(bool is_interactive,
793 bool is_app_install,
794 bool is_eula_required,
795 bool is_install_elevated_instance,
796 const CString& install_cmd_line,
797 const CommandLineArgs& args,
798 bool* is_machine,
799 bool* has_ui_been_displayed) {
800 ASSERT1(is_machine);
801 ASSERT1(has_ui_been_displayed);
802
803 // OEM is handled as a special case, and the state must be correct before
804 // calling Install().
805 HRESULT hr = oem_install_utils::SetOemInstallState(*is_machine);
806 if (FAILED(hr)) {
807 CORE_LOG(LE, (_T("[SetOemInstallState failed][0x%x]"), hr));
808 return hr;
809 }
810
811 hr = Install(is_interactive,
812 is_app_install,
813 is_eula_required,
814 true,
815 is_install_elevated_instance,
816 install_cmd_line,
817 args,
818 is_machine,
819 has_ui_been_displayed);
820
821 if (FAILED(hr)) {
822 VERIFY1(SUCCEEDED(oem_install_utils::ResetOemInstallState(*is_machine)));
823 return hr;
824 }
825
826 ASSERT1(oem_install_utils::IsOemInstalling(*is_machine));
827 return S_OK;
828 }
829
830 } // namespace omaha
OLDNEW
« no previous file with comments | « client/install.h ('k') | client/install_apps.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698