OLD | NEW |
| (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 | |
OLD | NEW |