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

Side by Side Diff: goopdate/goopdate.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 | « goopdate/goopdate.h ('k') | goopdate/goopdate.def » ('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 // For interactive instances, do not access the network before displaying the
17 // UI. This provides a better user experience - quick UI - when the network is
18 // slow. It is also required to ensure that UI displayed event is signaled
19 // before potentially waiting on a firewall prompt.
20 //
21 // Debugging notes:
22 // * Omaha initial install:
23 // /install "appguid={8A69D345-D564-463C-AFF1-A69D9E530F96}&appname=Google% 20Chrome&needsadmin=False&lang=en" // NOLINT
24 // /install "appguid={283EAF47-8817-4c2b-A801-AD1FADFB7BAA}&appname=Gears&n eedsadmin=True&lang=en" // NOLINT
25 // * App install:
26 // /handoff "appguid={8A69D345-D564-463C-AFF1-A69D9E530F96}&appname=Google% 20Chrome&needsadmin=False&lang=en" // NOLINT
27 // /handoff "appguid={283EAF47-8817-4c2b-A801-AD1FADFB7BAA}&appname=Gears&n eedsadmin=True&lang=en" // NOLINT
28 // * Silent install:
29 // * Add "/silent" to any of the above command lines (not to the tag).
30 // * Google Update self-update:
31 // /update
32 // * Update check for apps that need it:
33 // /ua
34 // * Core:
35 // /c
36 // * Cod Red check:
37 // /cr
38 // * Cod Red repair:
39 // /recover [/machine]
40 // * OneClick:
41 // /pi "http://www.google.com/" "/install%20%22appguid=%7B8A69D345-D564-463 C-AFF1-A69D9E530F96%7D%26lang=en%26appname=Google%2520Chrome%26needsadmin=false" /installsource oneclick // NOLINT
42 // * COM server:
43 // -Embedding
44
45 #include "omaha/goopdate/goopdate.h"
46
47 #include <atlstr.h>
48 #include <new>
49 #include "base/scoped_ptr.h"
50 #include "omaha/base/app_util.h"
51 #include "omaha/base/const_object_names.h"
52 #include "omaha/base/crash_if_specific_error.h"
53 #include "omaha/base/debug.h"
54 #include "omaha/base/error.h"
55 #include "omaha/base/file.h"
56 #include "omaha/base/logging.h"
57 #include "omaha/base/module_utils.h"
58 #include "omaha/base/omaha_version.h"
59 #include "omaha/base/proc_utils.h"
60 #include "omaha/base/reg_key.h"
61 #include "omaha/base/safe_format.h"
62 #include "omaha/base/scoped_any.h"
63 #include "omaha/base/scoped_ptr_address.h"
64 #include "omaha/base/system_info.h"
65 #include "omaha/base/utils.h"
66 #include "omaha/base/vistautil.h"
67 #include "omaha/client/client_utils.h"
68 #include "omaha/client/install.h"
69 #include "omaha/client/install_apps.h"
70 #include "omaha/client/install_self.h"
71 #include "omaha/client/resource.h" // IDS_* are used in client modes only.
72 #include "omaha/client/ua.h"
73 #include "omaha/common/app_registry_utils.h"
74 #include "omaha/common/command_line.h"
75 #include "omaha/common/config_manager.h"
76 #include "omaha/common/const_cmd_line.h"
77 #include "omaha/common/const_goopdate.h"
78 #include "omaha/common/goopdate_utils.h"
79 #include "omaha/common/ping.h"
80 #include "omaha/common/lang.h"
81 #include "omaha/common/oem_install_utils.h"
82 #include "omaha/common/stats_uploader.h"
83 #include "omaha/common/webplugin_utils.h"
84 #include "omaha/core/core.h"
85 #include "omaha/core/crash_handler.h"
86 #include "omaha/goopdate/code_red_check.h"
87 #include "omaha/goopdate/crash.h"
88 #include "omaha/goopdate/google_update.h"
89 #include "omaha/goopdate/goopdate_internal.h"
90 #include "omaha/goopdate/goopdate_metrics.h"
91 #include "omaha/goopdate/resource_manager.h"
92 #include "omaha/net/net_diags.h"
93 #include "omaha/service/service_main.h"
94 #include "omaha/setup/setup_service.h"
95 #include "third_party/breakpad/src/client/windows/sender/crash_report_sender.h"
96 #include "third_party/breakpad/src/client/windows/handler/exception_handler.h"
97
98 // TODO(omaha3): Where should we put this? In Omaha 2, it was in worker.cc.
99 // TODO(omaha): fix this clunkiness and require explicit registration of the
100 // http creators with the factory. Not ideal but better then linker options.
101 #pragma comment(linker, "/INCLUDE:_kRegisterWinHttp")
102
103 namespace omaha {
104
105 namespace {
106
107 #if DEBUG
108 const TCHAR* const kBuildType = _T("dbg");
109 #else
110 const TCHAR* const kBuildType = _T("opt");
111 #endif
112
113 #if OFFICIAL_BUILD
114 const TCHAR* const kOfficialBuild = _T("official");
115 #else
116 const TCHAR* const kOfficialBuild = _T("dev");
117 #endif
118
119 #if DEBUG
120 // Returns true if the binary's version matches the installed version or this
121 // mode does not require the versions to match.
122 bool CheckRegisteredVersion(const CString& version,
123 bool is_machine,
124 CommandLineMode mode) {
125 switch (mode) {
126 // Modes that may run before or during installation or otherwise do not
127 // need to match the installed version.
128 case COMMANDLINE_MODE_UNKNOWN:
129 case COMMANDLINE_MODE_NOARGS:
130 case COMMANDLINE_MODE_REGSERVER:
131 case COMMANDLINE_MODE_UNREGSERVER:
132 case COMMANDLINE_MODE_NETDIAGS:
133 case COMMANDLINE_MODE_CRASH:
134 case COMMANDLINE_MODE_REPORTCRASH:
135 case COMMANDLINE_MODE_INSTALL:
136 case COMMANDLINE_MODE_UPDATE:
137 case COMMANDLINE_MODE_RECOVER:
138 case COMMANDLINE_MODE_WEBPLUGIN:
139 case COMMANDLINE_MODE_REGISTER_PRODUCT:
140 case COMMANDLINE_MODE_UNREGISTER_PRODUCT:
141 case COMMANDLINE_MODE_SERVICE_REGISTER:
142 case COMMANDLINE_MODE_SERVICE_UNREGISTER:
143 case COMMANDLINE_MODE_PING:
144 return true;
145
146 // COM servers and services that should only run after installation.
147 case COMMANDLINE_MODE_CORE:
148 case COMMANDLINE_MODE_SERVICE:
149 case COMMANDLINE_MODE_CODE_RED_CHECK:
150 case COMMANDLINE_MODE_COMSERVER:
151 case COMMANDLINE_MODE_CRASH_HANDLER:
152 case COMMANDLINE_MODE_COMBROKER:
153 case COMMANDLINE_MODE_ONDEMAND:
154 case COMMANDLINE_MODE_MEDIUM_SERVICE:
155
156 // Clients that should only run after installation and should match the
157 // installed version.
158 case COMMANDLINE_MODE_HANDOFF_INSTALL:
159 case COMMANDLINE_MODE_UA:
160 case COMMANDLINE_MODE_UNINSTALL:
161
162 default:
163 // This binary's version should be the installed version.
164 CString installed_version;
165 VERIFY1(SUCCEEDED(RegKey::GetValue(
166 ConfigManager::Instance()->registry_update(is_machine),
167 kRegValueInstalledVersion,
168 &installed_version)));
169 return version == installed_version;
170 }
171 }
172 #endif
173
174 } // namespace
175
176 namespace detail {
177
178 class GoopdateImpl {
179 public:
180 GoopdateImpl(Goopdate* goopdate, bool is_local_system);
181 ~GoopdateImpl();
182
183 HRESULT Main(HINSTANCE instance, const TCHAR* cmd_line, int cmd_show);
184
185 HRESULT QueueUserWorkItem(UserWorkItem* work_item, uint32 flags);
186
187 void Stop();
188
189 bool is_local_system() const { return is_local_system_; }
190
191 private:
192 HRESULT DoMain(HINSTANCE instance, const TCHAR* cmd_line, int cmd_show);
193
194 // Performs initialization that must be done as soon as the command line has
195 // been parsed and loads the resources. If this method succeeds, we can use
196 // the resources - for example, to display error messagse.
197 HRESULT InitializeGoopdateAndLoadResources();
198
199 // Executes the mode determined by DoMain().
200 HRESULT ExecuteMode(bool* has_ui_been_displayed);
201
202 // Returns whether a process is a machine process.
203 // Does not determine whether the process has the appropriate privileges.
204 bool IsMachineProcess();
205
206 bool ShouldCheckShutdownEvent(CommandLineMode mode);
207 bool IsShutdownEventSet();
208
209 HRESULT LoadResourceDllIfNecessary(CommandLineMode mode,
210 const CString& resource_dir);
211
212 HRESULT SetUsageStatsEnable();
213
214 // Handles error conditions by showing UI if appropriate.
215 void HandleError(HRESULT hr, bool has_ui_been_displayed);
216
217 // Handles response to /pi command.
218 HRESULT HandleWebPlugin();
219
220 // Handles responses to /cr command.
221 HRESULT HandleCodeRedCheck();
222
223 // Handles /report command.
224 HRESULT HandleReportCrash();
225
226 // Installs apps for the /handoff instance.
227 HRESULT DoHandoff(bool* has_ui_been_displayed);
228
229 // Updates all registered apps for the /ua instance.
230 HRESULT DoUpdateAllApps(bool* has_ui_been_displayed);
231
232 // Generates a divide by zero to trigger breakpad dump.
233 // Is only enabled in debug builds.
234 HRESULT DoCrash();
235
236 // Install Omaha.
237 HRESULT DoInstall(bool* has_ui_been_displayed);
238
239 // Silently update Omaha.
240 HRESULT DoSelfUpdate();
241
242 // Handles the recover command in Google Update.
243 HRESULT DoRecover();
244
245 // Uninstalls Omaha if appropriate.
246 HRESULT HandleUninstall();
247
248 // Pings the Omaha server with a string.
249 HRESULT HandlePing();
250
251 // TODO(omaha): Reconcile the two uninstall functions and paths.
252 void MaybeUninstallGoogleUpdate();
253
254 // Uninstalls Google Update if a /install process failed to install itself
255 // or the app and there are no other apps registered.
256 HRESULT UninstallIfNecessary();
257
258 // Called by operator new or operator new[] when they cannot satisfy
259 // a request for additional storage.
260 static void OutOfMemoryHandler();
261
262 static HRESULT CaptureOSMetrics();
263
264 HINSTANCE module_instance_; // Current module instance.
265 CString cmd_line_; // Command line, as provided by the OS.
266 int cmd_show_;
267
268 CommandLineArgs args_; // Command line options and flags.
269
270 // True if the process belongs to a machine Omaha "session".
271 bool is_machine_;
272 bool is_local_system_; // True if running as LOCAL_SYSTEM.
273 CString this_version_; // Version of this Goopdate DLL.
274
275 // True if Omaha has been uninstalled by the Worker.
276 bool has_uninstalled_;
277
278 // Language identifier for the current user locale.
279 CString user_default_language_id_;
280
281 scoped_ptr<ThreadPool> thread_pool_;
282
283 Goopdate* goopdate_;
284
285 DISALLOW_EVIL_CONSTRUCTORS(GoopdateImpl);
286 };
287
288 GoopdateImpl::GoopdateImpl(Goopdate* goopdate, bool is_local_system)
289 : module_instance_(NULL),
290 cmd_show_(0),
291 is_local_system_(is_local_system),
292 has_uninstalled_(false),
293 goopdate_(goopdate) {
294 ASSERT1(goopdate);
295
296 ++metric_goopdate_constructor;
297
298 // The command line needs to be parsed to accurately determine if the current
299 // process is a machine process or not. Take an upfront guess before that.
300 is_machine_ = vista_util::IsUserAdmin() &&
301 goopdate_utils::IsRunningFromOfficialGoopdateDir(true);
302
303 // Install an error-handling mechanism which gets called when new operator
304 // fails to allocate memory.
305 VERIFY1(set_new_handler(&GoopdateImpl::OutOfMemoryHandler) == 0);
306
307 // Install the exception handler.
308 VERIFY1(SUCCEEDED(Crash::InstallCrashHandler(is_machine_)));
309
310 // Hints network configure manager how to create its singleton.
311 NetworkConfigManager::set_is_machine(is_machine_);
312
313 // Initialize the global metrics collection.
314 stats_report::g_global_metrics.Initialize();
315
316 // TODO(omaha): Support multiple HRESULT codes to crash on.
317 // TODO(omaha): Support passing in HRESULT codes via the command line,
318 // especially for "/update".
319 DWORD crash_specific_error = 0;
320 if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
321 kRegValueNameCrashIfSpecificError,
322 &crash_specific_error))) {
323 omaha::g_crash_specific_error = static_cast<HRESULT>(crash_specific_error);
324 }
325
326 static const int kThreadPoolShutdownDelayMs = 60000;
327 thread_pool_.reset(new ThreadPool);
328 HRESULT hr = thread_pool_->Initialize(kThreadPoolShutdownDelayMs);
329 if (FAILED(hr)) {
330 CORE_LOG(LE, (_T("[thread_pool_->Initialize failed][0x%08x]"), hr));
331 }
332 }
333
334 GoopdateImpl::~GoopdateImpl() {
335 CORE_LOG(L2, (_T("[GoopdateImpl::~GoopdateImpl]")));
336
337 ++metric_goopdate_destructor;
338
339 Stop();
340
341 // Bug 994348 does not repro anymore.
342 // If the assert fires, clean up the key, and fix the code if we have unit
343 // tests or application code that create the key.
344 ASSERT(!RegKey::HasKey(_T("HKEY_USERS\\.DEFAULT\\Software\\Google\\Update")),
345 (_T("This assert has fired because it has found the registry key at ")
346 _T("'HKEY_USERS\\.DEFAULT\\Software\\Google\\Update'. ")
347 _T("Please delete the key and report to omaha-core team if ")
348 _T("the assert fires again.")));
349
350 // The global metrics collection must be uninitialized before the metrics
351 // destructors are called.
352 stats_report::g_global_metrics.Uninitialize();
353
354 // Uninstall the exception handler. Program crashes are handled by Windows
355 // Error Reporting (WER) beyond this point.
356 Crash::UninstallCrashHandler();
357
358 // Reset the new handler.
359 set_new_handler(NULL);
360 }
361
362 HRESULT GoopdateImpl::QueueUserWorkItem(UserWorkItem* work_item, uint32 flags) {
363 CORE_LOG(L3, (_T("[GoopdateImpl::QueueUserWorkItem]")));
364 ASSERT1(work_item);
365
366 ASSERT1(thread_pool_.get());
367
368 return thread_pool_->QueueUserWorkItem(work_item, flags);
369 }
370
371 void GoopdateImpl::Stop() {
372 // The thread pool destructor waits for any remaining jobs to complete.
373 thread_pool_.reset();
374 }
375
376 // Assumes the resources are loaded and members are initialized.
377 void GoopdateImpl::HandleError(HRESULT hr, bool has_ui_been_displayed) {
378 CORE_LOG(L3, (_T("[GoopdateImpl::HandleError][0x%x][%u]"),
379 hr, has_ui_been_displayed));
380
381 if (has_ui_been_displayed ||
382 !internal::CanDisplayUi(args_.mode, args_.is_silent_set)) {
383 return;
384 }
385
386 const CString& bundle_name = args_.extra.bundle_name;
387 CString primary_app_guid;
388 if (!args_.extra.apps.empty()) {
389 primary_app_guid = GuidToString(args_.extra.apps[0].app_guid);
390 }
391
392 CString error_text;
393 switch (hr) {
394 case GOOPDATE_E_UA_ALREADY_RUNNING:
395 error_text.FormatMessage(IDS_APPLICATION_ALREADY_INSTALLING,
396 client_utils::GetUpdateAllAppsBundleName());
397 break;
398 case OMAHA_NET_E_WINHTTP_NOT_AVAILABLE:
399 ASSERT1(!bundle_name.IsEmpty());
400 error_text.FormatMessage(IDS_WINDOWS_IS_NOT_UP_TO_DATE,
401 bundle_name);
402 break;
403 default:
404 // TODO(omaha3): This currently assumes that any error returned here is
405 // related to Setup.
406 CString product_name;
407 VERIFY1(product_name.LoadString(IDS_PRODUCT_DISPLAY_NAME));
408 error_text.FormatMessage(IDS_SETUP_FAILED, product_name, hr);
409 break;
410 }
411
412 VERIFY1(client_utils::DisplayError(is_machine_,
413 bundle_name,
414 hr,
415 0,
416 error_text,
417 primary_app_guid,
418 args_.extra.language,
419 args_.extra.installation_id,
420 args_.extra.brand_code));
421 }
422
423 HRESULT GoopdateImpl::Main(HINSTANCE instance,
424 const TCHAR* cmd_line,
425 int cmd_show) {
426 ++metric_goopdate_main;
427
428 HRESULT hr = DoMain(instance, cmd_line, cmd_show);
429
430 CORE_LOG(L2, (_T("[has_uninstalled_ is %d]"), has_uninstalled_));
431
432 // For install processes, verify the Google Update EULA has been accepted and
433 // we can use the network unless a) the command line specifies EULA is
434 // required or b) in OEM installing mode, which also prevents network use.
435 if ((COMMANDLINE_MODE_INSTALL == args_.mode ||
436 COMMANDLINE_MODE_HANDOFF_INSTALL == args_.mode) &&
437 SUCCEEDED(hr)) {
438 ASSERT1(args_.is_eula_required_set ||
439 ConfigManager::Instance()->CanUseNetwork(is_machine_) ||
440 oem_install_utils::IsOemInstalling(is_machine_));
441 }
442
443 // In the /install case, clean up if Google Update and/or app install did not
444 // complete successfully.
445 // Only aggregate the metrics if there is no chance that Google Update has
446 // or may be uninstalled and the process has the appropriate permissions.
447 // Uninstall will aggregate and report the metrics as appropriate.
448 bool did_install_uninstall_fail = false;
449 if (COMMANDLINE_MODE_INSTALL == args_.mode) {
450 did_install_uninstall_fail = FAILED(UninstallIfNecessary());
451 } else if (!has_uninstalled_) {
452 if (args_.mode == COMMANDLINE_MODE_UA) {
453 VERIFY1(SUCCEEDED(AggregateAndReportMetrics(is_machine_, false)));
454 } else if (!is_machine_ || vista_util::IsUserAdmin()) {
455 VERIFY1(SUCCEEDED(AggregateMetrics(is_machine_)));
456 }
457 }
458
459 Worker::DeleteInstance();
460
461 // Uninitializing the network configuration must happen after reporting the
462 // metrics. The call succeeds even if the network has not been initialized
463 // due to errors up the execution path.
464 NetworkConfigManager::DeleteInstance();
465
466 if (COMMANDLINE_MODE_INSTALL == args_.mode &&
467 args_.is_oem_set &&
468 SUCCEEDED(hr) &&
469 !oem_install_utils::IsOemInstalling(is_machine_)) {
470 ASSERT1(false);
471 hr = GOOPDATE_E_OEM_INSTALL_SUCCEEDED_BUT_NOT_IN_OEM_INSTALLING_MODE;
472 }
473
474 // Verify that Google Update is either completely installed or uninstalled.
475 // Do not check in the following cases:
476 // * Modes that may exit during Setup, during uninstall, or while Omaha
477 // is partially installed.
478 // * The mode is unknown, which means the args were not be parsed.
479 // * /cr instance, which may exit after Omaha is uninstalled.
480 // * /install instance that would not have called Setup.Uninstall().
481 // * /install instance when Uninstall failed for some reason since the
482 // the consistency check may expect the wrong state.
483 // * /update instance that failed due to an install/uninstall in progress.
484 if (COMMANDLINE_MODE_REGSERVER != args_.mode &&
485 COMMANDLINE_MODE_UNREGSERVER != args_.mode &&
486 COMMANDLINE_MODE_COMSERVER != args_.mode &&
487 COMMANDLINE_MODE_CODE_RED_CHECK != args_.mode &&
488 COMMANDLINE_MODE_SERVICE_REGISTER != args_.mode &&
489 COMMANDLINE_MODE_SERVICE_UNREGISTER != args_.mode &&
490 COMMANDLINE_MODE_UNKNOWN != args_.mode &&
491 !(COMMANDLINE_MODE_INSTALL == args_.mode &&
492 is_machine_ &&
493 !vista_util::IsUserAdmin()) &&
494 !(COMMANDLINE_MODE_UPDATE == args_.mode &&
495 GOOPDATE_E_FAILED_TO_GET_LOCK == hr) &&
496 !did_install_uninstall_fail) {
497 install_self::CheckInstallStateConsistency(is_machine_);
498 }
499
500 ResourceManager::Delete();
501
502 return hr;
503 }
504
505 HRESULT GoopdateImpl::DoMain(HINSTANCE instance,
506 const TCHAR* cmd_line,
507 int cmd_show) {
508 module_instance_ = instance;
509 cmd_line_ = cmd_line;
510 cmd_show_ = cmd_show;
511
512 // The system terminates the process without displaying a retry dialog box
513 // for the user. GoogleUpdate has no user state to be saved, therefore
514 // prompting the user for input is meaningless.
515 VERIFY1(SUCCEEDED(SetProcessSilentShutdown()));
516
517 VERIFY1(SUCCEEDED(CaptureOSMetrics()));
518
519 InitializeVersionFromModule(module_instance_);
520 this_version_ = GetVersionString();
521
522 TCHAR path[MAX_PATH] = {0};
523 VERIFY1(::GetModuleFileName(module_instance_, path, MAX_PATH));
524 OPT_LOG(L1, (_T("[%s][version %s][%s][%s]"),
525 path, this_version_, kBuildType, kOfficialBuild));
526
527 CORE_LOG(L2, (_T("[is system %d]")
528 _T("[elevated admin %d]")
529 _T("[non-elevated admin %d]")
530 _T("[testsource %s]"),
531 is_local_system_,
532 vista_util::IsUserAdmin(),
533 vista_util::IsUserNonElevatedAdmin(),
534 ConfigManager::Instance()->GetTestSource()));
535
536 HRESULT parse_hr = omaha::ParseCommandLine(cmd_line_, &args_);
537 if (FAILED(parse_hr)) {
538 CORE_LOG(LE, (_T("[Parse cmd line failed][0x%08x]"), parse_hr));
539 args_.mode = COMMANDLINE_MODE_UNKNOWN;
540 // Continue because we want to load the resources and display an error.
541 }
542
543 // TODO(omaha3): Interactive updates might be useful for debugging or even
544 // on-demand updates of all apps. Figure out how to expose this. For now, no
545 // install source, which should not happen normally, is used as the trigger.
546 // The simplest way to make this work is to set args_.is_silent_set
547 // accordingly. However, we also need a way for this to work for per-machine
548 // instances since IsMachineProcess() relies on being Local System. When we
549 // settle on a mechanism, we should update the parser and remove this.
550 if (args_.mode == COMMANDLINE_MODE_UA) {
551 args_.is_silent_set = !args_.install_source.IsEmpty();
552 }
553
554 HRESULT hr = InitializeGoopdateAndLoadResources();
555 if (FAILED(hr)) {
556 CORE_LOG(LE,
557 (_T("[InitializeGoopdateAndLoadResources failed][0x%08x]"), hr));
558 if (internal::CanDisplayUi(args_.mode, args_.is_silent_set)) {
559 // The resources are unavaliable, so we must use hard-coded text.
560 const TCHAR* const kMsgBoxTitle = _T("Google Installer");
561 CString message;
562 message.Format(_T("Installation failed with error 0x%08x."), hr);
563 VERIFY1(IDOK == ::MessageBox(NULL, message, kMsgBoxTitle, MB_OK));
564 }
565 return hr;
566 }
567 // The resources are now loaded and available if applicable for this instance.
568 // If there was no bundle name specified on the command line, we take the
569 // bundle name from the first app's name; if that has no name (or if there is
570 // no apps, as in a runtime-only install) it will be an empty string.
571 // Replace it with the localized installer name.
572 if (args_.extra.bundle_name.IsEmpty()) {
573 args_.extra.bundle_name.LoadString(IDS_PRODUCT_DISPLAY_NAME);
574 }
575
576 CORE_LOG(L2, (_T("[can use network %d]")
577 _T("[can collect stats %d]"),
578 ConfigManager::Instance()->CanUseNetwork(is_machine_),
579 ConfigManager::Instance()->CanCollectStats(is_machine_)));
580
581 bool has_ui_been_displayed = false;
582
583 if (!is_machine_ && vista_util::IsElevatedWithUACMaybeOn()) {
584 CORE_LOG(LW, (_T("User GoogleUpdate is possibly running in an unsupported ")
585 _T("way, at High integrity with UAC possibly enabled.")));
586 }
587
588 if (FAILED(parse_hr)) {
589 ASSERT1(args_.mode == COMMANDLINE_MODE_UNKNOWN);
590 hr = parse_hr;
591 } else {
592 ASSERT1(args_.mode != COMMANDLINE_MODE_UNKNOWN);
593 // TODO(omaha): I would like to pass the mode as an argument, but there
594 // are so many uses for args_.mode and they could easily creep in. Consider
595 // eliminating the args_ member.
596 hr = ExecuteMode(&has_ui_been_displayed);
597 if (FAILED(hr)) {
598 CORE_LOG(LE, (_T("[ExecuteMode failed][0x%08x]"), hr));
599 // Continue and display error.
600 }
601 }
602
603 if (FAILED(hr)) {
604 HandleError(hr, has_ui_been_displayed);
605 return hr;
606 }
607
608 return S_OK;
609 }
610
611 // Assumes the command line has been parsed.
612 HRESULT GoopdateImpl::InitializeGoopdateAndLoadResources() {
613 // IsMachineProcess requires the command line be parsed first.
614 is_machine_ = IsMachineProcess();
615 OPT_LOG(L1, (_T("[is machine: %d]"), is_machine_));
616
617 if (!::SetEnvironmentVariable(kEnvVariableIsMachine,
618 is_machine_ ? _T("1") : _T("0"))) {
619 HRESULT hr = HRESULTFromLastError();
620 CORE_LOG(LW, (_T("[::SetEnvironmentVariable failed][%s][0x%x]"),
621 kEnvVariableIsMachine, hr));
622 }
623
624 // After parsing the command line, reinstall the crash handler to match the
625 // state of the process.
626 if (is_machine_ != Crash::is_machine()) {
627 VERIFY1(SUCCEEDED(Crash::InstallCrashHandler(is_machine_)));
628 }
629
630 // We have parsed the command line, and we are now resetting is_machine.
631 NetworkConfigManager::set_is_machine(
632 is_machine_ && vista_util::IsUserAdmin());
633
634 // Set the current directory to be the one that the DLL was launched from.
635 TCHAR module_directory[MAX_PATH] = {0};
636 if (!GetModuleDirectory(module_instance_, module_directory)) {
637 return HRESULTFromLastError();
638 }
639 if (!::SetCurrentDirectory(module_directory)) {
640 return HRESULTFromLastError();
641 }
642 OPT_LOG(L3, (_T("[Current dir][%s]"), module_directory));
643
644 // Set the usage stats as soon as possible, which is after the command line
645 // has been parsed, so that we can report crashes and other stats.
646 VERIFY1(SUCCEEDED(SetUsageStatsEnable()));
647
648 VERIFY1(SUCCEEDED(internal::PromoteAppEulaAccepted(is_machine_)));
649
650 if (ShouldCheckShutdownEvent(args_.mode) && IsShutdownEventSet()) {
651 return GOOPDATE_E_SHUTDOWN_SIGNALED;
652 }
653
654 HRESULT hr = LoadResourceDllIfNecessary(args_.mode, module_directory);
655 if (FAILED(hr)) {
656 CORE_LOG(LE, (_T("[LoadResourceDllIfNecessary failed][0x%08x]"), hr));
657 return hr;
658 }
659
660 return S_OK;
661 }
662
663 // Assumes Goopdate is initialized and resources are loaded.
664 HRESULT GoopdateImpl::ExecuteMode(bool* has_ui_been_displayed) {
665 ASSERT1(has_ui_been_displayed);
666
667 // Save the mode on the stack for post-mortem debugging purposes.
668 volatile CommandLineMode mode = args_.mode;
669
670 user_default_language_id_ = lang::GetDefaultLanguage(is_local_system_);
671
672 ASSERT1(CheckRegisteredVersion(GetVersionString(), is_machine_, mode));
673
674 #pragma warning(push)
675 // C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by
676 // a case label.
677 #pragma warning(disable : 4061)
678 switch (mode) {
679 // Delegate to the service or the core. Both have reliability requirements
680 // and resource constraints. Generally speaking, they do not use COM nor
681 // networking code.
682 case COMMANDLINE_MODE_SERVICE:
683 return omaha::Update3ServiceModule().Main(SW_HIDE);
684
685 case COMMANDLINE_MODE_MEDIUM_SERVICE:
686 return omaha::UpdateMediumServiceModule().Main(SW_HIDE);
687
688 case COMMANDLINE_MODE_SERVICE_REGISTER: {
689 HRESULT hr = SetupUpdate3Service::InstallService(
690 app_util::GetModulePath(NULL));
691 if (FAILED(hr)) {
692 return hr;
693 }
694 return SetupUpdateMediumService::InstallService(
695 app_util::GetModulePath(NULL));
696 }
697
698 case COMMANDLINE_MODE_SERVICE_UNREGISTER: {
699 HRESULT hr = SetupUpdate3Service::UninstallService();
700 if (FAILED(hr)) {
701 return hr;
702 }
703 return SetupUpdateMediumService::UninstallService();
704 }
705
706 default: {
707 scoped_co_init init_com_apt(COINIT_MULTITHREADED);
708 HRESULT hr = init_com_apt.hresult();
709 if (FAILED(hr)) {
710 return hr;
711 }
712
713 switch (mode) {
714 case COMMANDLINE_MODE_CORE:
715 return omaha::Core().Main(is_local_system_,
716 !args_.is_crash_handler_disabled);
717
718 case COMMANDLINE_MODE_CRASH_HANDLER:
719 return omaha::CrashHandler().Main(is_local_system_);
720
721 case COMMANDLINE_MODE_NOARGS:
722 return GOOPDATE_E_NO_ARGS;
723
724 case COMMANDLINE_MODE_UNREGISTER_PRODUCT:
725 // TODO(omaha3): Eliminate the need for this mode.
726 return E_FAIL;
727
728 case COMMANDLINE_MODE_COMBROKER:
729 return omaha::GoogleUpdate(is_machine_,
730 omaha::GoogleUpdate::kBrokerMode).Main();
731
732 case COMMANDLINE_MODE_ONDEMAND:
733 return omaha::GoogleUpdate(
734 is_machine_,
735 omaha::GoogleUpdate::kOnDemandMode).Main();
736
737 default: {
738 // Reference the network instance here so the singleton can be
739 // created before possible impersonation.
740 NetworkConfigManager::Instance();
741
742 switch (mode) {
743 case COMMANDLINE_MODE_WEBPLUGIN:
744 return HandleWebPlugin();
745
746 case COMMANDLINE_MODE_CODE_RED_CHECK:
747 return HandleCodeRedCheck();
748
749 case COMMANDLINE_MODE_NETDIAGS:
750 return NetDiags().Main();
751
752 case COMMANDLINE_MODE_REGISTER_PRODUCT:
753 // TODO(omaha3): Eliminate the need for this mode.
754 return E_FAIL;
755
756 case COMMANDLINE_MODE_INSTALL:
757 return DoInstall(has_ui_been_displayed);
758
759 case COMMANDLINE_MODE_UPDATE:
760 return DoSelfUpdate();
761
762 case COMMANDLINE_MODE_RECOVER:
763 return DoRecover();
764
765 case COMMANDLINE_MODE_HANDOFF_INSTALL:
766 return DoHandoff(has_ui_been_displayed);
767
768 case COMMANDLINE_MODE_UA:
769 return DoUpdateAllApps(has_ui_been_displayed);
770
771 case COMMANDLINE_MODE_CRASH:
772 return DoCrash();
773
774 case COMMANDLINE_MODE_REPORTCRASH:
775 return HandleReportCrash();
776
777 case COMMANDLINE_MODE_REGSERVER:
778 case COMMANDLINE_MODE_UNREGSERVER: {
779 hr = omaha::GoogleUpdate(
780 is_machine_, omaha::GoogleUpdate::kUpdate3Mode).Main();
781 if (FAILED(hr)) {
782 return hr;
783 }
784 hr = omaha::GoogleUpdate(
785 is_machine_, omaha::GoogleUpdate::kBrokerMode).Main();
786 if (FAILED(hr)) {
787 return hr;
788 }
789 return omaha::GoogleUpdate(
790 is_machine_, omaha::GoogleUpdate::kOnDemandMode).Main();
791 }
792
793 case COMMANDLINE_MODE_COMSERVER:
794 return omaha::GoogleUpdate(
795 is_machine_, omaha::GoogleUpdate::kUpdate3Mode).Main();
796
797 case COMMANDLINE_MODE_UNINSTALL:
798 return HandleUninstall();
799
800 case COMMANDLINE_MODE_PING:
801 return HandlePing();
802
803 default:
804 // We have a COMMANDLINE_MODE_ that isn't being handled.
805 ASSERT1(false);
806 OPT_LOG(LE, (_T("[Command line has unhandled mode]")));
807 return E_UNEXPECTED;
808 }
809 }
810 }
811 }
812 }
813 #pragma warning(pop)
814 }
815
816 bool GoopdateImpl::IsMachineProcess() {
817 Tristate needs_admin(TRISTATE_NONE);
818 if (!args_.extra.apps.empty()) {
819 needs_admin = args_.extra.apps[0].needs_admin != NEEDS_ADMIN_NO ?
820 TRISTATE_TRUE : TRISTATE_FALSE;
821 }
822
823 return internal::IsMachineProcess(
824 args_.mode,
825 goopdate_utils::IsRunningFromOfficialGoopdateDir(true),
826 is_local_system_,
827 args_.is_machine_set,
828 needs_admin);
829 }
830
831
832 HRESULT GoopdateImpl::HandleReportCrash() {
833 ++metric_goopdate_handle_report_crash;
834 VERIFY1(SUCCEEDED(AggregateMetrics(is_machine_)));
835
836 // Catch exceptions to avoid reporting crashes when handling a crash.
837 // TODO(omaha): maybe let Windows handle the crashes when reporting crashes
838 // in certain interactive modes.
839 HRESULT hr = S_OK;
840 __try {
841 // Crashes are uploaded always in the out-of-process case.
842 //
843 // Google Update internal crashes are handled in-process. They are uploaded
844 // only for the users that have opted in sending usage stats and when
845 // network use is allowed, and from systems that are not development
846 // nor test.
847 // This default behavior can be overriden by an UpdatedDev parameter that
848 // allows crashes to be uploaded always.
849 //
850 // All GoogleUpdate crashes are logged in the Windows event log for
851 // applications, unless the logging is disabled by the administrator.
852 ConfigManager* cm = ConfigManager::Instance();
853 const bool can_upload_in_process = cm->AlwaysAllowCrashUploads() ||
854 (cm->CanCollectStats(is_machine_) &&
855 cm->CanUseNetwork(is_machine_) &&
856 !goopdate_utils::IsTestSource());
857 hr = Crash::Report(can_upload_in_process,
858 args_.crash_filename,
859 args_.custom_info_filename,
860 user_default_language_id_);
861 }
862 __except(EXCEPTION_EXECUTE_HANDLER) {
863 hr = E_FAIL;
864 }
865 return hr;
866 }
867
868 bool GoopdateImpl::ShouldCheckShutdownEvent(CommandLineMode mode) {
869 switch (mode) {
870 // Modes that may run before or during installation or otherwise do not
871 // need to listen to shutdown.
872 case COMMANDLINE_MODE_UNKNOWN:
873 case COMMANDLINE_MODE_NOARGS:
874 case COMMANDLINE_MODE_REGSERVER:
875 case COMMANDLINE_MODE_UNREGSERVER:
876 case COMMANDLINE_MODE_NETDIAGS:
877 case COMMANDLINE_MODE_CRASH:
878 case COMMANDLINE_MODE_REPORTCRASH:
879 case COMMANDLINE_MODE_RECOVER:
880 case COMMANDLINE_MODE_SERVICE_REGISTER:
881 case COMMANDLINE_MODE_SERVICE_UNREGISTER:
882
883 case COMMANDLINE_MODE_INSTALL:
884 case COMMANDLINE_MODE_UPDATE:
885 case COMMANDLINE_MODE_WEBPLUGIN:
886 case COMMANDLINE_MODE_CODE_RED_CHECK:
887 case COMMANDLINE_MODE_REGISTER_PRODUCT:
888 case COMMANDLINE_MODE_UNREGISTER_PRODUCT:
889 case COMMANDLINE_MODE_PING:
890 return false;
891
892 // Modes that should honor shutdown.
893 case COMMANDLINE_MODE_CORE:
894 case COMMANDLINE_MODE_SERVICE:
895 case COMMANDLINE_MODE_COMSERVER:
896 case COMMANDLINE_MODE_CRASH_HANDLER:
897 case COMMANDLINE_MODE_COMBROKER:
898 case COMMANDLINE_MODE_ONDEMAND:
899 case COMMANDLINE_MODE_MEDIUM_SERVICE:
900
901 case COMMANDLINE_MODE_HANDOFF_INSTALL:
902 case COMMANDLINE_MODE_UA:
903 case COMMANDLINE_MODE_UNINSTALL:
904 return true;
905
906 default:
907 ASSERT1(false);
908 return true;
909 }
910 }
911
912 bool GoopdateImpl::IsShutdownEventSet() {
913 NamedObjectAttributes attr;
914 GetNamedObjectAttributes(kShutdownEvent, is_machine_, &attr);
915 scoped_event shutdown_event(::OpenEvent(SYNCHRONIZE, false, attr.name));
916 if (!shutdown_event) {
917 return false;
918 }
919
920 return WAIT_OBJECT_0 == ::WaitForSingleObject(get(shutdown_event), 0);
921 }
922
923 // The resource dll is loaded only in the following cases:
924 // 1. Initial setup: /install
925 // 2. Handoff install: /handoff
926 // 3. App update worker: /ua
927 // 4. Various registrations.
928 // 5. Modes where an error message needs to be displayed.
929 HRESULT GoopdateImpl::LoadResourceDllIfNecessary(CommandLineMode mode,
930 const CString& resource_dir) {
931 switch (mode) {
932 case COMMANDLINE_MODE_UNKNOWN: // Displays an error using UI.
933 case COMMANDLINE_MODE_NOARGS: // Displays an error using UI.
934 case COMMANDLINE_MODE_INSTALL: // Has UI on errors.
935 case COMMANDLINE_MODE_UPDATE: // Task and Service descriptions.
936 case COMMANDLINE_MODE_RECOVER: // Writes strings to registry.
937 case COMMANDLINE_MODE_HANDOFF_INSTALL: // Has optional UI.
938 case COMMANDLINE_MODE_UA: // Has optional UI.
939 case COMMANDLINE_MODE_COMSERVER: // Returns strings to caller.
940 case COMMANDLINE_MODE_SERVICE: // Returns strings to caller.
941 case COMMANDLINE_MODE_MEDIUM_SERVICE: // TODO(omaha): Check & explain.
942 case COMMANDLINE_MODE_SERVICE_REGISTER: // Requires the RGS resources.
943 case COMMANDLINE_MODE_SERVICE_UNREGISTER: // Requires the RGS resources.
944 case COMMANDLINE_MODE_ONDEMAND: // Worker, etc. load strings.
945 // Load the resource DLL for these modes.
946 break;
947
948 // For the Core, the resource DLL needs to be loaded when the Core is
949 // servicing IGoogleUpdate3. The Core loads the resource DLL after the Code
950 // Red kickoff, from within core.cc.
951 case COMMANDLINE_MODE_CORE:
952 case COMMANDLINE_MODE_REGSERVER:
953 case COMMANDLINE_MODE_UNREGSERVER:
954 case COMMANDLINE_MODE_NETDIAGS:
955 case COMMANDLINE_MODE_CRASH:
956 case COMMANDLINE_MODE_REPORTCRASH:
957 case COMMANDLINE_MODE_WEBPLUGIN:
958 case COMMANDLINE_MODE_CODE_RED_CHECK:
959 case COMMANDLINE_MODE_REGISTER_PRODUCT:
960 case COMMANDLINE_MODE_UNREGISTER_PRODUCT:
961 case COMMANDLINE_MODE_CRASH_HANDLER:
962 case COMMANDLINE_MODE_COMBROKER:
963 case COMMANDLINE_MODE_UNINSTALL:
964 case COMMANDLINE_MODE_PING:
965 default:
966 // These modes do not need the resource DLL.
967 ASSERT1(!internal::CanDisplayUi(mode, false));
968 return S_OK;
969 }
970
971 // TODO(omaha3): Consider not using ResourceManager in this file.
972 HRESULT hr = ResourceManager::Create(
973 is_machine_,
974 resource_dir,
975 lang::GetLanguageForProcess(args_.extra.language));
976 if (FAILED(hr)) {
977 ASSERT(false, (_T("ResourceManager::Create failed with 0x%08x"), hr));
978 return hr;
979 }
980
981 return S_OK;
982 }
983
984 // Writes the information for the primary app to enable Omaha to send usage
985 // stats now. It will be set for each app in the args when they are installed.
986 HRESULT GoopdateImpl::SetUsageStatsEnable() {
987 if (args_.extra.apps.empty()) {
988 return S_OK;
989 }
990
991 HRESULT hr = app_registry_utils::SetUsageStatsEnable(
992 args_.extra.apps[0].needs_admin != NEEDS_ADMIN_NO,
993 GuidToString(args_.extra.apps[0].app_guid),
994 args_.extra.usage_stats_enable);
995 if (FAILED(hr)) {
996 CORE_LOG(LW, (_T("[SetUsageStatsEnable failed][0x%08x]"), hr));
997
998 if ((HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr) &&
999 args_.extra.apps[0].needs_admin &&
1000 !vista_util::IsUserAdmin()) {
1001 CORE_LOG(L3, (_T("[Process does not have permission to HKLM]")));
1002 return S_OK;
1003 }
1004 return hr;
1005 }
1006
1007 return S_OK;
1008 }
1009
1010 HRESULT GoopdateImpl::HandleCodeRedCheck() {
1011 CORE_LOG(L2, (_T("[GoopdateImpl::HandleCodeRedCheck]")));
1012 ++metric_cr_process_total;
1013
1014 // Call the utils method instead of member method because we want to execute
1015 // as little code as possible.
1016 bool is_machine = internal::IsMachineProcess(args_.mode,
1017 false, // machine dir
1018 is_local_system_,
1019 args_.is_machine_set,
1020 TRISTATE_NONE);
1021 ASSERT1(IsMachineProcess() == is_machine);
1022
1023 if (!ConfigManager::Instance()->CanUseNetwork(is_machine)) {
1024 CORE_LOG(L1,
1025 (_T("[Code Red check not sent because network use prohibited]")));
1026 return GOOPDATE_E_CANNOT_USE_NETWORK;
1027 }
1028
1029 CheckForCodeRed(is_machine, this_version_);
1030 return S_OK;
1031 }
1032
1033 // Even though http://b/1135173 is fixed, there is still a possibility that only
1034 // some of the files will be copied if Setup is currently running.
1035 // TODO(omaha3): If we save and use the metainstaller for OneClick, that may
1036 // address this.
1037
1038 // If we're called with the /webplugin command, we need to handle it and exit.
1039 // This is called from the browser and the command line arguments come from the
1040 // website so we need to be restrictive of what we let past. If everything from
1041 // the plugin is valid, we'll relaunch goopdate with the proper commands.
1042 HRESULT GoopdateImpl::HandleWebPlugin() {
1043 return webplugin_utils::DoOneClickInstall(args_);
1044 }
1045
1046 HRESULT GoopdateImpl::DoInstall(bool* has_ui_been_displayed) {
1047 OPT_LOG(L1, (_T("[GoopdateImpl::DoInstall]")));
1048 ASSERT1(has_ui_been_displayed);
1049
1050 // Some /install command lines, such as /silent /install will not necessarily
1051 // have an install source. To differentiate these from other sources, such as
1052 // other clients using the COM API, specify a generic source for /install.
1053 // TODO(omaha3): Updating two types of command line/args is undesirable, and
1054 // this does not use CommandLineBuilder. This could be addressed in several
1055 // ways. See the TODO above install.cc::LaunchHandoffProcess().
1056 ASSERT1(args_.mode == COMMANDLINE_MODE_INSTALL);
1057 CString install_command_line = cmd_line_;
1058 CommandLineArgs install_args = args_;
1059 if (args_.install_source.IsEmpty()) {
1060 ASSERT1(-1 == cmd_line_.Find(kCmdLineInstallSource));
1061 SafeCStringAppendFormat(&install_command_line, _T(" /%s %s"),
1062 kCmdLineInstallSource,
1063 kCmdLineInstallSource_InstallDefault);
1064 install_args.install_source = kCmdLineInstallSource_InstallDefault;
1065 }
1066
1067 HRESULT hr = S_OK;
1068 if (args_.is_oem_set) {
1069 hr = OemInstall(!args_.is_silent_set, // is_interactive
1070 !args_.extra.runtime_only, // is_app_install
1071 args_.is_eula_required_set,
1072 args_.is_install_elevated,
1073 install_command_line,
1074 install_args,
1075 &is_machine_,
1076 has_ui_been_displayed);
1077 } else {
1078 hr = Install(!args_.is_silent_set, // is_interactive
1079 !args_.extra.runtime_only, // is_app_install
1080 args_.is_eula_required_set,
1081 false,
1082 args_.is_install_elevated,
1083 install_command_line,
1084 install_args,
1085 &is_machine_,
1086 has_ui_been_displayed);
1087 }
1088
1089 if (FAILED(hr)) {
1090 CORE_LOG(LE, (_T("[Install failed][0x%08x]"), hr));
1091 return hr;
1092 }
1093
1094 return S_OK;
1095 }
1096
1097 HRESULT GoopdateImpl::DoSelfUpdate() {
1098 OPT_LOG(L1, (_T("[GoopdateImpl::DoSelfUpdate]")));
1099
1100 HRESULT hr = install_self::UpdateSelf(is_machine_, args_.session_id);
1101 if (FAILED(hr)) {
1102 CORE_LOG(LE, (_T("[UpdateSelf failed][0x%08x]"), hr));
1103 return hr;
1104 }
1105
1106 return S_OK;
1107 }
1108
1109 // Attempts to launch the repair file elevated using the MSP. If elevation is
1110 // not needed or fails, attempts to install without elevating.
1111 // The code_red_metainstaller_path arg is the repair file.
1112 HRESULT GoopdateImpl::DoRecover() {
1113 OPT_LOG(L1, (_T("[GoopdateImpl::DoRecover()]")));
1114
1115 // TODO(omaha3): Enable. Maybe build without the builder.
1116 #if 0
1117 CommandLineBuilder builder(COMMANDLINE_MODE_UPDATE);
1118
1119 HRESULT hr = S_OK;
1120 if (LaunchRepairFileElevated(is_machine_,
1121 args_.code_red_metainstaller_path,
1122 builder.GetCommandLineArgs(),
1123 &hr)) {
1124 ASSERT1(SUCCEEDED(hr));
1125 return S_OK;
1126 }
1127 #else
1128 HRESULT hr = S_OK;
1129 #endif
1130
1131 if (FAILED(hr)) {
1132 OPT_LOG(LW, (_T("[LaunchRepairFileElevated failed][0x%08x]"), hr));
1133 }
1134
1135 hr = install_self::Repair(is_machine_);
1136 if (FAILED(hr)) {
1137 OPT_LOG(LE, (_T("[Non-elevated repair failed][0x%08x]"), hr));
1138 return hr;
1139 }
1140
1141 return S_OK;
1142 }
1143
1144 // Clears the EULA flag in the handoff instance in case an older installer that
1145 // does not know about the EULA flag is used to launch the install.
1146 // Failing to clear flag fails installation because this would prevent updates.
1147 HRESULT GoopdateImpl::DoHandoff(bool* has_ui_been_displayed) {
1148 OPT_LOG(L1, (_T("[GoopdateImpl::DoHandoff]")));
1149 ASSERT1(has_ui_been_displayed);
1150
1151 if (!args_.is_eula_required_set) {
1152 HRESULT hr = install_self::SetEulaAccepted(is_machine_);
1153 if (FAILED(hr)) {
1154 CORE_LOG(LE, (_T("[install_self::SetEulaAccepted failed][0x%08x]"), hr));
1155 return hr;
1156 }
1157 }
1158
1159 HRESULT hr = InitializeClientSecurity();
1160 if (FAILED(hr)) {
1161 return hr;
1162 }
1163
1164 // If /sessionid wasn't specified on the command line, generate a random GUID
1165 // to use for the session ID. (This can happen if a metainstaller from the
1166 // prior version does a handoff to a newer version.)
1167 CString session_id = args_.session_id;
1168 if (session_id.IsEmpty()) {
1169 VERIFY1(SUCCEEDED(GetGuid(&session_id)));
1170 }
1171
1172 hr = InstallApps(is_machine_,
1173 !args_.is_silent_set, // is_interactive.
1174 !args_.is_eula_required_set, // is_eula_accepted.
1175 args_.is_oem_set,
1176 args_.is_offline_set,
1177 args_.offline_dir,
1178 args_.extra,
1179 args_.install_source,
1180 session_id,
1181 has_ui_been_displayed);
1182 if (FAILED(hr)) {
1183 CORE_LOG(LE, (_T("[Install failed][0x%08x]"), hr));
1184 return hr;
1185 }
1186
1187 return S_OK;
1188 }
1189
1190 HRESULT GoopdateImpl::DoUpdateAllApps(bool* has_ui_been_displayed ) {
1191 OPT_LOG(L1, (_T("[GoopdateImpl::DoUpdateAllApps]")));
1192 ASSERT1(has_ui_been_displayed);
1193
1194 bool is_interactive_update = !args_.is_silent_set;
1195
1196 // TODO(omaha3): Interactive is used as an indication of an on-demand request.
1197 // It might also be useful to allow on-demand silent update requests.
1198 // This was a request when we added the ability to disable updates.
1199 // TODO(omaha3): These on-demand requests should also allow updates if the
1200 // app update policy is set to on-demand in addition to silent auto.
1201 const bool is_on_demand = is_interactive_update;
1202
1203 CString install_source = args_.install_source;
1204
1205 if (is_on_demand && install_source.IsEmpty()) {
1206 // Set an install source for interactive/on-demand update all apps.
1207 install_source = kCmdLineInstallSource_OnDemandUA;
1208 }
1209
1210 // TODO(omaha): Consider moving InitializeClientSecurity calls inside
1211 // install_apps.cc or maybe to update3_utils::CreateGoogleUpdate3Class().
1212 HRESULT hr = InitializeClientSecurity();
1213 if (FAILED(hr)) {
1214 ASSERT1(false);
1215 return is_interactive_update ? hr : S_OK;
1216 }
1217
1218 hr = UpdateApps(is_machine_,
1219 is_interactive_update,
1220 is_on_demand,
1221 install_source,
1222 args_.extra.language,
1223 has_ui_been_displayed);
1224 OPT_LOG(L2, (_T("[Update all apps process finished][0x%x]"), hr));
1225
1226 // The UA worker always returns S_OK. UA can be launched by the scheduled task
1227 // or the core, neither of which wait for a return code. On Vista, returning
1228 // an error code from the scheduled task reportedly causes issues with the
1229 // task scheduler in rare cases, so returning S_OK helps with that as well.
1230 // However, in interactive cases, we should return the actual error so that it
1231 // can be reported to the user if necessary.
1232 return is_interactive_update ? hr : S_OK;
1233 }
1234
1235 HRESULT GoopdateImpl::DoCrash() {
1236 #if DEBUG
1237 return static_cast<HRESULT>(Crash::CrashNow());
1238 #else
1239 return S_OK;
1240 #endif
1241 }
1242
1243 HRESULT GoopdateImpl::HandleUninstall() {
1244 // TODO(omaha3): Why don't we always acquire this lock before uninstalling?
1245 // We don't in the /install case. I guess it's important that we uninstall
1246 // the first time in that case, but there's a chance that the case in the
1247 // referenced bug could occur while a user is installing.
1248
1249 // Attempt a conditional uninstall and always return S_OK to avoid
1250 // executing error handling code in the case of an actual uninstall.
1251 // Do not attempt to uninstall if MSI is busy to avoid spurious uninstalls.
1252 // See http://b/1436223. The call to WaitForMSIExecute blocks with a
1253 // timeout. It is better to block here than block while holding the setup
1254 // lock.
1255 HRESULT hr = WaitForMSIExecute(kWaitForMSIExecuteMs);
1256 CORE_LOG(L2, (_T("[WaitForMSIExecute returned 0x%08x]"), hr));
1257 if (SUCCEEDED(hr)) {
1258 MaybeUninstallGoogleUpdate();
1259 }
1260 return S_OK;
1261 }
1262
1263 HRESULT GoopdateImpl::HandlePing() {
1264 return Ping::HandlePing(is_machine_, args_.ping_string);
1265 }
1266
1267 // TODO(omaha3): In Omaha 2, this was also called when /ig failed. There is a
1268 // separate call to UninstallSelf for /install in goopdate.cc. Should we call
1269 // this instead to ensure we ping? Should we try to only call from one location?
1270 // If we move it, make sure it is called regardless of LastChecked. See
1271 // http://b/2663423.
1272
1273 // Uninstall is a tricky use case. Uninstall can primarily happen in three cases
1274 // and there are two mechanisms to uninstall. The cases in which Omaha
1275 // uninstalls are:
1276 // 1. The last registered application uninstalls. If Omaha is long-running,
1277 // Omaha monitors the Client keys and it will trigger an immediate uninstall in
1278 // this case.
1279 // 2. The core starts an update worker, if there are no registered
1280 // applications, the update worker will do the uninstall.
1281 // 3. An error, including user cancel, happens during Omaha or app installation
1282 // and there are no registered applications.
1283 // The uninstall is implemented in terms of the following mechanisms:
1284 // * An update worker launched with "/ua /uninstalled" by the core, in the
1285 // first two cases above.
1286 // * A direct uninstall, in the case of errors or user cancellations, in the
1287 // last case above.
1288 //
1289 // Omaha can uninstall only if there are no install workers running and no
1290 // registered applications. This check is done under the setup lock protection.
1291 // In addition, the uninstall worker takes the update worker lock. Acquiring
1292 // this lock is important since the silent installers can modify the
1293 // registration of apps and trigger uninstalls workers. Therefore, both
1294 // setup lock and the update worker locks are needed.
1295 //
1296 // In the direct uninstall case there is a small race condition, since there is
1297 // no other single lock that can be acquired to prevent changes to the
1298 // application registration. The code looks for install workers but the test is
1299 // racy if not protected by locks.
1300 void GoopdateImpl::MaybeUninstallGoogleUpdate() {
1301 CORE_LOG(L1, (_T("[MaybeUninstallGoogleUpdate]")));
1302 has_uninstalled_ =
1303 !!SUCCEEDED(install_self::UninstallSelf(is_machine_, true));
1304 }
1305
1306 // In dbg builds, also checks the post conditions of a /install process to
1307 // ensure that the registry is correctly populated or has been cleaned up.
1308 HRESULT GoopdateImpl::UninstallIfNecessary() {
1309 ASSERT1(COMMANDLINE_MODE_INSTALL == args_.mode);
1310 ASSERT(!has_uninstalled_, (_T("Worker doesn't uninstall in /install mode")));
1311
1312 if (is_machine_ && !vista_util::IsUserAdmin()) {
1313 // The non-elevated instance, so do not try to uninstall.
1314 return S_OK;
1315 } else {
1316 CORE_LOG(L2, (_T("[GoopdateImpl::Main /install][Uninstall if necessary]")));
1317 // COM must be initialized in order to uninstall the scheduled task(s).
1318 scoped_co_init init_com_apt(COINIT_MULTITHREADED);
1319 return install_self::UninstallSelf(is_machine_, false);
1320 }
1321 }
1322
1323 void GoopdateImpl::OutOfMemoryHandler() {
1324 ::RaiseException(EXCEPTION_ACCESS_VIOLATION,
1325 EXCEPTION_NONCONTINUABLE,
1326 0,
1327 NULL);
1328 }
1329
1330 HRESULT GoopdateImpl::CaptureOSMetrics() {
1331 int major_version(0);
1332 int minor_version(0);
1333 int service_pack_major(0);
1334 int service_pack_minor(0);
1335 TCHAR name[MAX_PATH] = {0};
1336
1337 HRESULT hr = SystemInfo::GetSystemVersion(&major_version,
1338 &minor_version,
1339 &service_pack_major,
1340 &service_pack_minor,
1341 name,
1342 arraysize(name));
1343 if (SUCCEEDED(hr)) {
1344 metric_windows_major_version = major_version;
1345 metric_windows_minor_version = minor_version;
1346 metric_windows_sp_major_version = service_pack_major;
1347 metric_windows_sp_minor_version = service_pack_minor;
1348 }
1349
1350 return hr;
1351 }
1352
1353 } // namespace detail
1354
1355 namespace internal {
1356
1357 // TODO(omaha3): Consider moving to app_registry_utils.
1358 // Returns early if Google Update's EULA is already accepted, as indicated by
1359 // the lack of eulaaccepted in the Update key.
1360 // The apps' values are not modified or deleted.
1361 HRESULT PromoteAppEulaAccepted(bool is_machine) {
1362 const TCHAR* update_key_name =
1363 ConfigManager::Instance()->registry_update(is_machine);
1364 if (!RegKey::HasValue(update_key_name, kRegValueOmahaEulaAccepted)) {
1365 return S_OK;
1366 }
1367
1368 const TCHAR* state_key_name =
1369 ConfigManager::Instance()->registry_client_state(is_machine);
1370
1371 RegKey state_key;
1372 HRESULT hr = state_key.Open(state_key_name, KEY_READ);
1373 if (FAILED(hr)) {
1374 if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) {
1375 return S_FALSE;
1376 }
1377 return hr;
1378 }
1379
1380 // TODO(omaha): This should actually be iterating over registered products
1381 // rather than present ClientState keys. These are identical in most cases.
1382 int num_sub_keys = state_key.GetSubkeyCount();
1383 for (int i = 0; i < num_sub_keys; ++i) {
1384 CString sub_key_name;
1385 if (FAILED(state_key.GetSubkeyNameAt(i, &sub_key_name))) {
1386 continue;
1387 }
1388
1389 if (app_registry_utils::IsAppEulaAccepted(is_machine, sub_key_name, true)) {
1390 ASSERT1(kGoogleUpdateAppId != sub_key_name);
1391 return install_self::SetEulaAccepted(is_machine);
1392 }
1393 }
1394
1395 return S_OK;
1396 }
1397
1398 // TODO(omaha): Use a registry override instead.
1399 #if !OFFICIAL_BUILD
1400 bool IsOmahaShellRunningFromStaging() {
1401 return !app_util::GetModuleName(NULL).CompareNoCase(kOmahaShellFileName) &&
1402 app_util::GetModuleDirectory(NULL).Right(_tcslen(_T("staging"))) ==
1403 _T("staging");
1404 }
1405 #endif
1406
1407 // TODO(omaha): needs_admin is only used for one case. Can we avoid it?
1408 bool IsMachineProcess(CommandLineMode mode,
1409 bool is_running_from_official_machine_directory,
1410 bool is_local_system,
1411 bool is_machine_override,
1412 Tristate needs_admin) {
1413 switch (mode) {
1414 // These "install" operations may not be running from the installed
1415 // location.
1416 case COMMANDLINE_MODE_INSTALL:
1417 case COMMANDLINE_MODE_HANDOFF_INSTALL:
1418 case COMMANDLINE_MODE_REGISTER_PRODUCT:
1419 case COMMANDLINE_MODE_UNREGISTER_PRODUCT:
1420 ASSERT1(TRISTATE_NONE != needs_admin);
1421 return TRISTATE_TRUE == needs_admin;
1422
1423 // The following is a Code Red repair executable, which runs from temp dir.
1424 case COMMANDLINE_MODE_RECOVER:
1425 return is_machine_override;
1426
1427 // The following always runs as the user and may provide UI for on-demand
1428 // installs and browser launches.
1429 // The install location determines user vs. machine.
1430 case COMMANDLINE_MODE_COMSERVER:
1431 case COMMANDLINE_MODE_ONDEMAND:
1432 #if !OFFICIAL_BUILD
1433 // Return machine == true. This is to facilitate unit tests such as
1434 // GoogleUpdateCoreTest.LaunchCmdElevated_LocalServerRegistered.
1435 if (IsOmahaShellRunningFromStaging()) {
1436 return true;
1437 }
1438 #endif
1439
1440 ASSERT1(goopdate_utils::IsRunningFromOfficialGoopdateDir(false) ||
1441 goopdate_utils::IsRunningFromOfficialGoopdateDir(true) ||
1442 _T("omaha_unittest.exe") == app_util::GetCurrentModuleName() ||
1443 _T("GoogleUpdate_unsigned.exe") ==
1444 app_util::GetModuleName(NULL)); // Running in debugger.
1445 return is_running_from_official_machine_directory;
1446
1447 // The broker forwarder is elevatable and always runs as the user it was
1448 // created as.
1449 case COMMANDLINE_MODE_COMBROKER:
1450 return is_running_from_official_machine_directory;
1451
1452 // The following always runs as the user and is user-initiated.
1453 case COMMANDLINE_MODE_WEBPLUGIN:
1454 // The install location determines user vs. machine.
1455 // This may not be the desired value when doing a cross-install or using
1456 // the opposite plugin (i.e. user plugin is often used before the machine
1457 // one).
1458 ASSERT1(goopdate_utils::IsRunningFromOfficialGoopdateDir(false) ||
1459 goopdate_utils::IsRunningFromOfficialGoopdateDir(true) ||
1460 _T("omaha_unittest.exe") == app_util::GetCurrentModuleName());
1461 return is_running_from_official_machine_directory;
1462
1463 // The following all run silently as the user for user installs or Local
1464 // System for machine installs.
1465 case COMMANDLINE_MODE_UPDATE:
1466 case COMMANDLINE_MODE_CODE_RED_CHECK:
1467 return is_local_system;
1468
1469 // The following all run silently as the user for user installs or Local
1470 // System for machine installs.
1471 case COMMANDLINE_MODE_UA:
1472 return is_local_system ? true : is_machine_override;
1473
1474 // /ua runs silently as the user for user installs or Local System for
1475 // machine installs. Interactive machine /ua may be run as the user if
1476 // /machine is specified.
1477 case COMMANDLINE_MODE_CORE:
1478 case COMMANDLINE_MODE_CRASH_HANDLER:
1479 return is_local_system;
1480
1481 // The following runs silently as Local System.
1482 case COMMANDLINE_MODE_SERVICE:
1483 case COMMANDLINE_MODE_MEDIUM_SERVICE:
1484 ASSERT1(is_local_system);
1485 return is_local_system;
1486
1487 // The following run as machine for all installs.
1488 case COMMANDLINE_MODE_SERVICE_REGISTER:
1489 case COMMANDLINE_MODE_SERVICE_UNREGISTER:
1490 return true;
1491
1492 // The crashing process determines whether it was a machine or user omaha
1493 // and correctly sets the /machine switch.
1494 case COMMANDLINE_MODE_REPORTCRASH:
1495 return is_machine_override;
1496
1497 // The following all run silently as the user for all installs.
1498 case COMMANDLINE_MODE_REGSERVER:
1499 case COMMANDLINE_MODE_UNREGSERVER:
1500 #if !OFFICIAL_BUILD
1501 // Return machine == true. This is to facilitate unit tests such as
1502 // GoogleUpdateCoreTest.LaunchCmdElevated_LocalServerRegistered.
1503 if (IsOmahaShellRunningFromStaging()) {
1504 return true;
1505 }
1506 #endif
1507
1508 ASSERT1(goopdate_utils::IsRunningFromOfficialGoopdateDir(false) ||
1509 goopdate_utils::IsRunningFromOfficialGoopdateDir(true) ||
1510 _T("omaha_unittest.exe") == app_util::GetCurrentModuleName());
1511 return is_running_from_official_machine_directory;
1512
1513 // The following may run as user or Local System. Thus, use the directory.
1514 case COMMANDLINE_MODE_UNINSTALL:
1515 case COMMANDLINE_MODE_PING:
1516 ASSERT1(goopdate_utils::IsRunningFromOfficialGoopdateDir(false) ||
1517 goopdate_utils::IsRunningFromOfficialGoopdateDir(true) ||
1518 _T("omaha_unittest.exe") == app_util::GetCurrentModuleName());
1519 return is_running_from_official_machine_directory;
1520
1521 // The following are miscellaneous modes that we do not expect to be running
1522 // in the wild.
1523 case COMMANDLINE_MODE_NOARGS:
1524 case COMMANDLINE_MODE_UNKNOWN:
1525 case COMMANDLINE_MODE_NETDIAGS:
1526 case COMMANDLINE_MODE_CRASH:
1527 default:
1528 return is_running_from_official_machine_directory;
1529 }
1530 }
1531
1532 bool CanDisplayUi(CommandLineMode mode, bool is_silent) {
1533 switch (mode) {
1534 case COMMANDLINE_MODE_UNKNOWN:
1535 // This mode is not one of our known silent modes. Therefore, we can
1536 // display an error UI.
1537 return true;
1538
1539 case COMMANDLINE_MODE_INSTALL:
1540 case COMMANDLINE_MODE_HANDOFF_INSTALL:
1541 case COMMANDLINE_MODE_UA:
1542 // These modes have UI unless they are silent.
1543 // UA is usually silent, but follows the same logic.
1544 return !is_silent;
1545
1546 case COMMANDLINE_MODE_NOARGS:
1547 case COMMANDLINE_MODE_CORE:
1548 case COMMANDLINE_MODE_SERVICE:
1549 case COMMANDLINE_MODE_REGSERVER:
1550 case COMMANDLINE_MODE_UNREGSERVER:
1551 case COMMANDLINE_MODE_NETDIAGS:
1552 case COMMANDLINE_MODE_CRASH:
1553 case COMMANDLINE_MODE_REPORTCRASH:
1554 case COMMANDLINE_MODE_UPDATE:
1555 case COMMANDLINE_MODE_RECOVER:
1556 case COMMANDLINE_MODE_WEBPLUGIN:
1557 case COMMANDLINE_MODE_CODE_RED_CHECK:
1558 case COMMANDLINE_MODE_COMSERVER:
1559 case COMMANDLINE_MODE_REGISTER_PRODUCT:
1560 case COMMANDLINE_MODE_UNREGISTER_PRODUCT:
1561 case COMMANDLINE_MODE_SERVICE_REGISTER:
1562 case COMMANDLINE_MODE_SERVICE_UNREGISTER:
1563 case COMMANDLINE_MODE_CRASH_HANDLER:
1564 case COMMANDLINE_MODE_COMBROKER:
1565 case COMMANDLINE_MODE_ONDEMAND:
1566 case COMMANDLINE_MODE_MEDIUM_SERVICE:
1567 case COMMANDLINE_MODE_UNINSTALL:
1568 case COMMANDLINE_MODE_PING:
1569 default:
1570 // These modes are always silent.
1571 return false;
1572 }
1573 }
1574
1575 } // namespace internal
1576
1577 Goopdate* Goopdate::instance_ = NULL;
1578
1579 Goopdate& Goopdate::Instance() {
1580 ASSERT1(instance_);
1581 return *instance_;
1582 }
1583
1584 Goopdate::Goopdate(bool is_local_system) {
1585 CORE_LOG(L2, (_T("[Goopdate::Goopdate]")));
1586 impl_.reset(new detail::GoopdateImpl(this, is_local_system));
1587
1588 ASSERT1(!instance_);
1589 instance_ = this;
1590 }
1591
1592 Goopdate::~Goopdate() {
1593 CORE_LOG(L2, (_T("[Goopdate::~Goopdate]")));
1594
1595 Stop();
1596
1597 instance_ = NULL;
1598 }
1599
1600 HRESULT Goopdate::Main(HINSTANCE instance,
1601 const TCHAR* cmd_line,
1602 int cmd_show) {
1603 return impl_->Main(instance, cmd_line, cmd_show);
1604 }
1605
1606 HRESULT Goopdate::QueueUserWorkItem(UserWorkItem* work_item, uint32 flags) {
1607 return impl_->QueueUserWorkItem(work_item, flags);
1608 }
1609
1610 void Goopdate::Stop() {
1611 return impl_->Stop();
1612 }
1613
1614 bool Goopdate::is_local_system() const {
1615 return impl_->is_local_system();
1616 }
1617
1618 } // namespace omaha
OLDNEW
« no previous file with comments | « goopdate/goopdate.h ('k') | goopdate/goopdate.def » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698