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

Side by Side Diff: goopdate/worker.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/worker.h ('k') | goopdate/worker_internal.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2007-2010 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15
16 #include "omaha/goopdate/worker.h"
17 #include "omaha/goopdate/worker_internal.h"
18 #include <atlbase.h>
19 #include <atlstr.h>
20 #include "omaha/base/app_util.h"
21 #include "omaha/base/const_object_names.h"
22 #include "omaha/base/debug.h"
23 #include "omaha/base/error.h"
24 #include "omaha/base/file.h"
25 #include "omaha/base/firewall_product_detection.h"
26 #include "omaha/base/logging.h"
27 #include "omaha/base/path.h"
28 #include "omaha/base/reactor.h"
29 #include "omaha/base/safe_format.h"
30 #include "omaha/base/scoped_impersonation.h"
31 #include "omaha/base/system.h"
32 #include "omaha/base/utils.h"
33 #include "omaha/base/thread_pool_callback.h"
34 #include "omaha/base/vistautil.h"
35 #include "omaha/common/app_registry_utils.h"
36 #include "omaha/common/config_manager.h"
37 #include "omaha/common/event_logger.h"
38 #include "omaha/common/goopdate_utils.h"
39 #include "omaha/common/ping.h"
40 #include "omaha/common/update_request.h"
41 #include "omaha/common/update_response.h"
42 #include "omaha/common/web_services_client.h"
43 #include "omaha/goopdate/app_manager.h"
44 #include "omaha/goopdate/download_manager.h"
45 #include "omaha/goopdate/goopdate.h"
46 #include "omaha/goopdate/install_manager.h"
47 #include "omaha/goopdate/model.h"
48 #include "omaha/goopdate/offline_utils.h"
49 #include "omaha/goopdate/server_resource.h"
50 #include "omaha/goopdate/string_formatter.h"
51 #include "omaha/goopdate/update_request_utils.h"
52 #include "omaha/goopdate/update_response_utils.h"
53 #include "omaha/goopdate/worker_metrics.h"
54 #include "omaha/goopdate/worker_utils.h"
55
56 namespace omaha {
57
58 namespace internal {
59
60 void RecordUpdateAvailableUsageStats() {
61 AppManager& app_manager = *AppManager::Instance();
62
63 DWORD update_responses(0);
64 DWORD64 time_since_first_response_ms(0);
65 app_manager.ReadUpdateAvailableStats(kGoopdateGuid,
66 &update_responses,
67 &time_since_first_response_ms);
68 if (update_responses) {
69 metric_worker_self_update_responses = update_responses;
70 }
71 if (time_since_first_response_ms) {
72 metric_worker_self_update_response_time_since_first_ms =
73 time_since_first_response_ms;
74 }
75
76 AppIdVector registered_app_ids;
77 HRESULT hr = app_manager.GetRegisteredApps(&registered_app_ids);
78 if (FAILED(hr)) {
79 ASSERT1(false);
80 return;
81 }
82
83 // These store information about the app with the most update responses.
84 GUID max_responses_app(GUID_NULL);
85 DWORD max_responses(0);
86 DWORD64 max_responses_time_since_first_response_ms(0);
87
88 for (size_t i = 0; i < registered_app_ids.size(); ++i) {
89 const CString& app_id = registered_app_ids[i];
90 GUID app_guid = GUID_NULL;
91
92 if (FAILED(StringToGuidSafe(app_id, &app_guid))) {
93 ASSERT(false, (_T("Invalid App ID: %s"), app_id));
94 continue;
95 }
96
97 if (::IsEqualGUID(kGoopdateGuid, app_guid)) {
98 continue;
99 }
100
101 DWORD update_responses(0);
102 DWORD64 time_since_first_response_ms(0);
103 app_manager.ReadUpdateAvailableStats(app_guid,
104 &update_responses,
105 &time_since_first_response_ms);
106
107 if (max_responses < update_responses) {
108 max_responses_app = app_guid;
109 max_responses = update_responses;
110 max_responses_time_since_first_response_ms = time_since_first_response_ms;
111 }
112 }
113
114 if (max_responses) {
115 metric_worker_app_max_update_responses_app_high =
116 GetGuidMostSignificantUint64(max_responses_app);
117 metric_worker_app_max_update_responses = max_responses;
118 metric_worker_app_max_update_responses_ms_since_first =
119 max_responses_time_since_first_response_ms;
120 }
121 }
122
123 // Will block if any apps are being installed.
124 HRESULT AddUninstalledAppsPings(AppBundle* app_bundle) {
125 CORE_LOG(L3, (_T("[AddUninstalledAppsPings]")));
126 ASSERT1(app_bundle);
127
128 AppManager& app_manager = *AppManager::Instance();
129
130 // Ensure that no installers are running while determining uninstalled apps
131 // and information about them.
132 __mutexScope(app_manager.GetRegistryStableStateLock());
133
134 AppIdVector uninstalled_app_ids;
135 HRESULT hr = app_manager.GetUninstalledApps(&uninstalled_app_ids);
136 if (FAILED(hr)) {
137 CORE_LOG(LE, (_T("[GetUninstalledApps failed][0x%08x]"), hr));
138 return hr;
139 }
140
141 if (!uninstalled_app_ids.size()) {
142 return S_OK;
143 }
144
145 for (size_t i = 0; i < uninstalled_app_ids.size(); ++i) {
146 CString app_id = uninstalled_app_ids[i];
147 CORE_LOG(L3, (_T("[found uninstalled product][%s]"), app_id));
148
149 // Omaha uninstall ping is sent by the Uninstall function in setup.
150 if (app_id == kGoogleUpdateAppId) {
151 CORE_LOG(L3, (_T("[skipping Omaha]")));
152 continue;
153 }
154
155 App* app = NULL;
156 hr = app_bundle->CreateUninstalledApp(app_id, &app);
157 if (FAILED(hr)) {
158 return hr;
159 }
160
161 PingEventPtr ping_event(
162 new PingEvent(PingEvent::EVENT_UNINSTALL,
163 PingEvent::EVENT_RESULT_SUCCESS,
164 0, // error code
165 0)); // extra code 1
166 app->AddPingEvent(ping_event);
167
168 // TODO(omaha3) It would be nice to call RemoveClientState() only after the
169 // uninstall ping is sent so that the values are not deleted if the ping
170 // fails. However, this would allow race conditions between installers
171 // and the uninstall ping unless app_manager.GetRegistryStableStateLock() is
172 // held from the ping building through the send, which is not currently
173 // feasible since the ping is sent in the AppBundle destructor, and the
174 // AppBundle's lifetime is controlled by the client. Improving the ping
175 // architecture, such as having a ping queue managed by the Worker, may
176 // enable this.
177 VERIFY1(SUCCEEDED(app_manager.RemoveClientState(app->app_guid())));
178 }
179
180 return S_OK;
181 }
182
183 HRESULT SendOemInstalledPing(bool is_machine, const CString& session_id) {
184 CORE_LOG(L3, (_T("[SendOemInstalledPing]")));
185
186 std::vector<CString> oem_installed_apps;
187 HRESULT hr = AppManager::Instance()->GetOemInstalledAndEulaAcceptedApps(
188 &oem_installed_apps);
189 if (FAILED(hr)) {
190 return hr;
191 }
192
193 PingEventPtr oem_ping_event(
194 new PingEvent(PingEvent::EVENT_INSTALL_OEM_FIRST_CHECK,
195 PingEvent::EVENT_RESULT_SUCCESS,
196 0,
197 0));
198 Ping ping(is_machine, session_id, CString());
199 ping.LoadAppDataFromRegistry(oem_installed_apps);
200 ping.BuildAppsPing(oem_ping_event);
201 hr = ping.Send(false);
202 if (FAILED(hr)) {
203 CORE_LOG(L3, (_T("[SendOemInstalledPing failed][0x%08x]"), hr));
204 return hr;
205 }
206
207 AppManager::Instance()->ClearOemInstalled(oem_installed_apps);
208
209 return S_OK;
210 }
211
212 } // namespace internal
213
214 Worker::Worker()
215 : is_machine_(false) {
216 CORE_LOG(L1, (_T("[Worker::Worker]")));
217 }
218
219 Worker::~Worker() {
220 CORE_LOG(L1, (_T("[Worker::~Worker]")));
221
222 // TODO(omaha3): Remove when Run() is used. See TODO in GoogleUpdate::Main().
223 Stop();
224
225 AppManager::DeleteInstance();
226 }
227
228 Worker* const Worker::kInvalidInstance = reinterpret_cast<Worker* const>(-1);
229 Worker* Worker::instance_ = NULL;
230
231 Worker& Worker::Instance() {
232 // Getting the instance after the instance has been deleted is a bug in
233 // the logic of the program.
234 ASSERT1(instance_ != kInvalidInstance);
235 if (!instance_) {
236 instance_ = new Worker();
237 }
238 return *instance_;
239 }
240
241 int Worker::Lock() {
242 return _pAtlModule->Lock();
243 }
244
245 int Worker::Unlock() {
246 return _pAtlModule->Unlock();
247 }
248
249 HRESULT Worker::Initialize(bool is_machine) {
250 CORE_LOG(L1, (_T("[Worker::Initialize][%d]"), is_machine));
251
252 is_machine_ = is_machine;
253
254 reactor_.reset(new Reactor);
255 shutdown_handler_.reset(new ShutdownHandler);
256 model_.reset(new Model(this));
257
258 ASSERT1(!single_instance_.get());
259 NamedObjectAttributes attr;
260 GetNamedObjectAttributes(kGoogleUpdate3SingleInstance, is_machine, &attr);
261 single_instance_.reset(new ProgramInstance(attr.name));
262 if (!single_instance_.get()) {
263 CORE_LOG(LE, (_T("[Failed to create Worker Single Instance]")));
264 return E_OUTOFMEMORY;
265 }
266
267 if (!single_instance_->EnsureSingleInstance()) {
268 CORE_LOG(LW, (_T("[Another Worker instance already running]")));
269 return GOOPDATE_E_INSTANCES_RUNNING;
270 }
271
272 HRESULT hr = AppManager::CreateInstance(is_machine_);
273 if (FAILED(hr)) {
274 return hr;
275 }
276
277 download_manager_.reset(new DownloadManager(is_machine_));
278
279 hr = download_manager_->Initialize();
280 if (FAILED(hr)) {
281 return hr;
282 }
283
284 install_manager_.reset(new InstallManager(&model_->lock(), is_machine_));
285 hr = install_manager_->Initialize();
286 if (FAILED(hr)) {
287 return hr;
288 }
289
290 return S_OK;
291 }
292
293 void Worker::Stop() {
294 // Stop the concurrent objects to avoid spurious events.
295 shutdown_handler_.reset();
296 reactor_.reset();
297
298 // TODO(omaha3): Remove when Run() is used. See TODO in GoogleUpdate::Main().
299 // Until then this call is necessary to wait for threads to complete on
300 // destruction.
301 // TODO(omaha3): Is it correct that the thread pool does not wait for the
302 // threads if !shutdown_event_?
303 Goopdate::Instance().Stop();
304 }
305
306 HRESULT Worker::Run() {
307 HRESULT hr = DoRun();
308 Stop();
309
310 return hr;
311 }
312
313 HRESULT Worker::DoRun() {
314 CORE_LOG(L1, (_T("[Worker::DoRun]")));
315
316 HRESULT hr = InitializeShutDownHandler();
317 if (FAILED(hr)) {
318 return hr;
319 }
320
321 return hr;
322 }
323
324 HRESULT Worker::InitializeShutDownHandler() {
325 CORE_LOG(L3, (_T("[InitializeShutDownHandler]")));
326 return shutdown_handler_->Initialize(reactor_.get(), this, is_machine_);
327 }
328
329 HRESULT Worker::Shutdown() {
330 CORE_LOG(L2, (_T("[Worker::Shutdown]")));
331 return S_OK;
332 }
333
334 void Worker::CollectAmbientUsageStats() {
335 #if 0
336 // The firewall detection code has been proved to block on some
337 // computers in the IWbemLocator::ConnectServer call even though a
338 // timeout was specified in the call.
339 CString name, version;
340 HRESULT hr = firewall_detection::Detect(&name, &version);
341 bool has_software_firewall = SUCCEEDED(hr) && !name.IsEmpty();
342 metric_worker_has_software_firewall.Set(has_software_firewall);
343 #endif
344
345 if (System::IsRunningOnBatteries()) {
346 ++metric_worker_silent_update_running_on_batteries;
347 }
348
349 metric_worker_shell_version = app_util::GetVersionFromModule(NULL);
350
351 metric_worker_is_windows_installing.Set(IsWindowsInstalling());
352 metric_worker_is_uac_disabled.Set(vista_util::IsVistaOrLater() &&
353 !vista_util::IsUACMaybeOn());
354 metric_worker_is_clickonce_disabled.Set(IsClickOnceDisabled());
355 }
356
357 HRESULT Worker::CheckForUpdateAsync(AppBundle* app_bundle) {
358 CORE_LOG(L3, (_T("[Worker::CheckForUpdateAsync][0x%p]"), app_bundle));
359
360 ASSERT1(app_bundle);
361 ASSERT1(model_->IsLockedByCaller());
362
363 HRESULT hr = QueueDeferredFunctionCall0(app_bundle, &Worker::CheckForUpdate);
364 if (FAILED(hr)) {
365 return hr;
366 }
367
368 for (size_t i = 0; i != app_bundle->GetNumberOfApps(); ++i) {
369 App* app = app_bundle->GetApp(i);
370 app->QueueUpdateCheck();
371 }
372
373 return S_OK;
374 }
375
376 void Worker::CheckForUpdate(shared_ptr<AppBundle> app_bundle) {
377 CORE_LOG(L3, (_T("[Worker::CheckForUpdate][0x%p]"), app_bundle.get()));
378 ASSERT1(app_bundle.get());
379
380 bool is_check_successful = false;
381 CheckForUpdateHelper(app_bundle.get(), &is_check_successful);
382
383 app_bundle->CompleteAsyncCall();
384 }
385
386 // *is_check_successful is true if the network request was successful and the
387 // response was successfully parsed. The elements' status need not be success,
388 // but an invalid response, such as HTML from a proxy, should result in false.
389 // TODO(omaha): Unit test this by mocking update_check_client.
390 void Worker::CheckForUpdateHelper(AppBundle* app_bundle,
391 bool* is_check_successful) {
392 ASSERT1(app_bundle);
393 ASSERT1(is_check_successful);
394 *is_check_successful = false;
395
396 if (ConfigManager::Instance()->CanUseNetwork(is_machine_)) {
397 VERIFY1(SUCCEEDED(internal::SendOemInstalledPing(
398 is_machine_, app_bundle->session_id())));
399 }
400
401 scoped_impersonation impersonate_user(app_bundle->impersonation_token());
402 HRESULT hr = impersonate_user.result();
403 if (FAILED(hr)) {
404 CORE_LOG(LE, (_T("[Impersonation failed][0x%08x]"), hr));
405 return;
406 }
407
408 scoped_ptr<xml::UpdateRequest> update_request(
409 xml::UpdateRequest::Create(is_machine_,
410 app_bundle->session_id(),
411 app_bundle->install_source(),
412 app_bundle->origin_url()));
413
414 scoped_ptr<xml::UpdateResponse> update_response(
415 xml::UpdateResponse::Create());
416
417 CallAsSelfAndImpersonate2(this,
418 &Worker::DoPreUpdateCheck,
419 app_bundle,
420 update_request.get());
421
422 // This is a blocking call on the network.
423 hr = DoUpdateCheck(app_bundle,
424 update_request.get(),
425 update_response.get());
426 if (FAILED(hr)) {
427 CORE_LOG(LW, (_T("[DoUpdateCheck failed][0x%08x]"), hr));
428 }
429 *is_check_successful = SUCCEEDED(hr);
430
431 CallAsSelfAndImpersonate3(this,
432 &Worker::DoPostUpdateCheck,
433 app_bundle,
434 hr,
435 update_response.get());
436
437 CString event_description;
438 event_description.Format(_T("Update check. Status = 0x%08x"), hr);
439 CString event_text;
440 CString url;
441 VERIFY1(SUCCEEDED(ConfigManager::Instance()->GetUpdateCheckUrl(&url)));
442 SafeCStringFormat(&event_text, _T("url=%s\n%s"),
443 url,
444 app_bundle->FetchAndResetLogText());
445
446 WriteEventLog(EVENTLOG_INFORMATION_TYPE,
447 kUpdateEventId,
448 event_description,
449 event_text);
450 }
451
452 HRESULT Worker::DownloadAsync(AppBundle* app_bundle) {
453 CORE_LOG(L3, (_T("[Worker::DownloadAsync][0x%p]"), app_bundle));
454
455 ASSERT1(app_bundle);
456 ASSERT1(model_->IsLockedByCaller());
457
458 HRESULT hr = QueueDeferredFunctionCall0(app_bundle, &Worker::Download);
459 if (FAILED(hr)) {
460 return hr;
461 }
462
463 for (size_t i = 0; i != app_bundle->GetNumberOfApps(); ++i) {
464 App* app = app_bundle->GetApp(i);
465 app->QueueDownload();
466 }
467
468 return S_OK;
469 }
470
471 void Worker::Download(shared_ptr<AppBundle> app_bundle) {
472 CORE_LOG(L3, (_T("[Worker::Download][0x%p]"), app_bundle.get()));
473 ASSERT1(app_bundle.get());
474
475 scoped_impersonation impersonate_user(app_bundle->impersonation_token());
476 HRESULT hr = impersonate_user.result();
477 if (FAILED(hr)) {
478 CORE_LOG(LE, (_T("[Impersonation failed][0x%08x]"), hr));
479 return;
480 }
481
482 const size_t num_apps = app_bundle->GetNumberOfApps();
483
484 for (size_t i = 0; i != num_apps; ++i) {
485 App* app = app_bundle->GetApp(i);
486
487 ASSERT1(app->state() == STATE_WAITING_TO_DOWNLOAD ||
488 app->state() == STATE_NO_UPDATE ||
489 app->state() == STATE_ERROR);
490
491 // This is a blocking call on the network.
492 app->Download(download_manager_.get());
493
494 ASSERT1(app->state() == STATE_READY_TO_INSTALL ||
495 app->state() == STATE_NO_UPDATE ||
496 app->state() == STATE_ERROR);
497 }
498
499 WriteEventLog(EVENTLOG_INFORMATION_TYPE,
500 kDownloadEventId,
501 _T("Bundle download"),
502 app_bundle->FetchAndResetLogText());
503 app_bundle->CompleteAsyncCall();
504 }
505
506 HRESULT Worker::DownloadAndInstallAsync(AppBundle* app_bundle) {
507 CORE_LOG(L3, (_T("[Worker::DownloadAndInstallAsync][0x%p]"), app_bundle));
508
509 ASSERT1(app_bundle);
510 ASSERT1(model_->IsLockedByCaller());
511
512 HRESULT hr = QueueDeferredFunctionCall0(app_bundle,
513 &Worker::DownloadAndInstall);
514 if (FAILED(hr)) {
515 return hr;
516 }
517
518 for (size_t i = 0; i != app_bundle->GetNumberOfApps(); ++i) {
519 App* app = app_bundle->GetApp(i);
520 // Queue the download or install depending on the current state. The correct
521 // one must be queued so that all apps are moved into waiting now and remain
522 // there until the download or install starts for that app.
523 app->QueueDownloadOrInstall();
524 }
525
526 return S_OK;
527 }
528
529 void Worker::DownloadAndInstall(shared_ptr<AppBundle> app_bundle) {
530 CORE_LOG(L3, (_T("[Worker::DownloadAndInstall][0x%p]"), app_bundle.get()));
531 ASSERT1(app_bundle.get());
532
533 DownloadAndInstallHelper(app_bundle.get());
534
535 app_bundle->CompleteAsyncCall();
536 }
537
538 void Worker::DownloadAndInstallHelper(AppBundle* app_bundle) {
539 ASSERT1(app_bundle);
540
541 scoped_impersonation impersonate_user(app_bundle->impersonation_token());
542 HRESULT hr = impersonate_user.result();
543 if (FAILED(hr)) {
544 CORE_LOG(LE, (_T("[Impersonation failed][0x%08x]"), hr));
545 return;
546 }
547
548 const size_t num_apps = app_bundle->GetNumberOfApps();
549
550 for (size_t i = 0; i != num_apps; ++i) {
551 App* app = app_bundle->GetApp(i);
552
553 ASSERT1(app->state() == STATE_WAITING_TO_DOWNLOAD ||
554 app->state() == STATE_WAITING_TO_INSTALL ||
555 app->state() == STATE_NO_UPDATE ||
556 app->state() == STATE_ERROR);
557
558 // Download the app if it has not already been downloaded.
559 // This is a blocking call on the network.
560 app->Download(download_manager_.get());
561
562 ASSERT1(app->state() == STATE_READY_TO_INSTALL || // Downloaded above.
563 app->state() == STATE_WAITING_TO_INSTALL || // Downloaded earlier.
564 app->state() == STATE_NO_UPDATE ||
565 app->state() == STATE_ERROR);
566
567 app->QueueInstall();
568
569 // This is a blocking call on the app installer.
570 CallAsSelfAndImpersonate1(
571 app,
572 &App::Install,
573 install_manager_.get());
574
575 ASSERT1(app->state() == STATE_INSTALL_COMPLETE ||
576 app->state() == STATE_NO_UPDATE ||
577 app->state() == STATE_ERROR);
578 }
579
580 WriteEventLog(EVENTLOG_INFORMATION_TYPE,
581 kUpdateEventId,
582 _T("Application update/install"),
583 app_bundle->FetchAndResetLogText());
584 }
585
586
587 HRESULT Worker::UpdateAllAppsAsync(AppBundle* app_bundle) {
588 CORE_LOG(L3, (_T("[Worker::UpdateAllAppsAsync][0x%p]"), app_bundle));
589
590 ASSERT1(app_bundle);
591 ASSERT1(model_->IsLockedByCaller());
592
593 HRESULT hr = QueueDeferredFunctionCall0(app_bundle, &Worker::UpdateAllApps);
594 if (FAILED(hr)) {
595 return hr;
596 }
597
598 for (size_t i = 0; i != app_bundle->GetNumberOfApps(); ++i) {
599 App* app = app_bundle->GetApp(i);
600 app->QueueUpdateCheck();
601 }
602
603 return S_OK;
604 }
605
606 // Runs through all steps regardless of error. App state machine handles errors.
607 void Worker::UpdateAllApps(shared_ptr<AppBundle> app_bundle) {
608 CORE_LOG(L3, (_T("[Worker::UpdateAllApps][0x%p]"), app_bundle.get()));
609 ASSERT1(app_bundle.get());
610
611 bool is_check_successful = false;
612 CheckForUpdateHelper(app_bundle.get(), &is_check_successful);
613
614 if (is_check_successful) {
615 HRESULT hr = goopdate_utils::UpdateLastChecked(is_machine_);
616 ASSERT(SUCCEEDED(hr), (_T("UpdateLastChecked failed with 0x%08x"), hr));
617 }
618
619 for (size_t i = 0; i != app_bundle->GetNumberOfApps(); ++i) {
620 App* app = app_bundle->GetApp(i);
621 app->QueueDownloadOrInstall();
622 }
623
624 DownloadAndInstallHelper(app_bundle.get());
625
626 internal::RecordUpdateAvailableUsageStats();
627 CollectAmbientUsageStats();
628
629 HRESULT hr = internal::AddUninstalledAppsPings(app_bundle.get());
630 if (FAILED(hr)) {
631 CORE_LOG(LW, (_T("[AddUninstalledAppsPings failed][0x%08x]"), hr));
632 }
633
634 app_bundle->CompleteAsyncCall();
635 }
636
637 HRESULT Worker::DownloadPackageAsync(Package* package) {
638 ASSERT1(package);
639 AppBundle* app_bundle = package->app_version()->app()->app_bundle();
640 ASSERT1(app_bundle);
641
642 ASSERT1(model_->IsLockedByCaller());
643
644 CORE_LOG(L3, (_T("[Worker::DownloadPackageAsync][0x%p][0x%p]"),
645 app_bundle, package));
646
647 HRESULT hr = QueueDeferredFunctionCall1<Package*>(app_bundle,
648 package,
649 &Worker::DownloadPackage);
650 if (FAILED(hr)) {
651 return hr;
652 }
653
654 App* app = package->app_version()->app();
655 app->QueueDownload();
656
657 return S_OK;
658 }
659
660 void Worker::DownloadPackage(shared_ptr<AppBundle> app_bundle,
661 Package* package) {
662 CORE_LOG(L3, (_T("[Worker::DownloadPackage][0x%p][0x%p]"),
663 app_bundle.get(), package));
664 ASSERT1(app_bundle.get());
665 ASSERT1(package);
666
667 scoped_impersonation impersonate_user(app_bundle->impersonation_token());
668 HRESULT hr = impersonate_user.result();
669 if (FAILED(hr)) {
670 CORE_LOG(LE, (_T("[Impersonation failed][0x%08x]"), hr));
671 return;
672 }
673
674 UNREFERENCED_PARAMETER(package);
675
676 // TODO(omaha): implement downloading a package.
677
678 // TODO(omaha): The event log function should be modified depends on
679 // how the download is implemented.
680 // * whether HRESULT is needed.
681 // * whether the app_bundle has the log text.
682 // * additional information needed?
683 CString event_text;
684 SafeCStringFormat(&event_text, _T("Package: %s\n%s"),
685 package->filename(),
686 app_bundle->FetchAndResetLogText());
687
688 WriteEventLog(EVENTLOG_INFORMATION_TYPE,
689 kDownloadEventId,
690 _T("Package download"),
691 event_text);
692 app_bundle->CompleteAsyncCall();
693 }
694
695 // TODO(omaha3): Implement this and enforce the postcondition that the
696 // bundle object is not busy before the function returns.
697 HRESULT Worker::Stop(AppBundle* app_bundle) {
698 CORE_LOG(L3, (_T("[Worker::Stop][0x%p]"), app_bundle));
699
700 ASSERT1(app_bundle);
701 ASSERT1(model_->IsLockedByCaller());
702
703 // Cancels update check client but not the ping client since we need to send
704 // cancellation ping.
705 WebServicesClientInterface* update_check_client(
706 app_bundle->update_check_client());
707 if (update_check_client) {
708 update_check_client->Cancel();
709 }
710
711 // TODO(omaha3): What do we do with active installs? We can at least cancel
712 // the InstallManager/InstallerWrapper if it has not started.
713
714 // Cancel any apps that might have pending operations.
715 for (size_t i = 0; i != app_bundle->GetNumberOfApps(); ++i) {
716 App* app = app_bundle->GetApp(i);
717 download_manager_->Cancel(app);
718 app->Cancel();
719 }
720
721 return S_OK;
722 }
723
724 HRESULT Worker::Pause(AppBundle* app_bundle) {
725 CORE_LOG(L3, (_T("[Worker::Pause][0x%p]"), app_bundle));
726 ASSERT1(app_bundle);
727 ASSERT1(model_->IsLockedByCaller());
728 UNREFERENCED_PARAMETER(app_bundle);
729
730 return E_NOTIMPL;
731 }
732
733 HRESULT Worker::Resume(AppBundle* app_bundle) {
734 CORE_LOG(L3, (_T("[Worker::Resume][0x%p]"), app_bundle));
735 ASSERT1(app_bundle);
736 ASSERT1(model_->IsLockedByCaller());
737 UNREFERENCED_PARAMETER(app_bundle);
738
739 return E_NOTIMPL;
740 }
741
742 HRESULT Worker::GetPackage(const Package* package, const CString& dir) {
743 CORE_LOG(L3, (_T("[Worker::GetPackage]")));
744 ASSERT1(model_->IsLockedByCaller());
745 return download_manager_->GetPackage(package, dir);
746 }
747
748 bool Worker::IsPackageAvailable(const Package* package) const {
749 CORE_LOG(L3, (_T("[Worker::IsPackageAvailable]")));
750 ASSERT1(model_->IsLockedByCaller());
751 return download_manager_->IsPackageAvailable(package);
752 }
753
754 HRESULT Worker::CacheOfflinePackages(AppBundle* app_bundle) {
755 CORE_LOG(L3, (_T("[Worker::CacheOfflinePackages]")));
756 ASSERT1(app_bundle);
757
758 for (size_t i = 0; i != app_bundle->GetNumberOfApps(); ++i) {
759 App* app = app_bundle->GetApp(i);
760 AppVersion* app_version = app->working_version();
761 const size_t num_packages = app_version->GetNumberOfPackages();
762
763 for (size_t i = 0; i < num_packages; ++i) {
764 Package* package(app_version->GetPackage(i));
765 if (download_manager_->IsPackageAvailable(package)) {
766 continue;
767 }
768
769 CString offline_app_dir = ConcatenatePath(app_bundle->offline_dir(),
770 app->app_guid_string());
771 CString offline_package_path = ConcatenatePath(offline_app_dir,
772 package->filename());
773 if (!File::Exists(offline_package_path)) {
774 HRESULT hr = offline_utils::FindV2OfflinePackagePath(
775 offline_app_dir, &offline_package_path);
776 if (FAILED(hr)) {
777 CORE_LOG(LE, (_T("[FindOfflinePackagePath failed][0x%x]"), hr));
778 return hr;
779 }
780 }
781
782 HRESULT hr = download_manager_->CachePackage(package,
783 &offline_package_path);
784 if (FAILED(hr)) {
785 CORE_LOG(LE, (_T("[CachePackage failed][%s][%s][0x%x][%Iu]"),
786 app->app_guid_string(), offline_package_path, hr, i));
787 return hr;
788 }
789 }
790 }
791
792 return S_OK;
793 }
794
795 HRESULT Worker::PurgeAppLowerVersions(const CString& app_id,
796 const CString& version) {
797 return download_manager_->PurgeAppLowerVersions(app_id, version);
798 }
799
800 // metric_worker_apps_not_*ed_group_policy are integers, not a counter, so they
801 // should be set to a value, not incremented. Otherwise the same app could be
802 // counted twice if the same COM server instance was used for multiple bundles
803 // of the same app(s). For this reason and to avoid overwriting valid counts
804 // with 0, the number of disabled apps is accumulated then the appropriate
805 // metric is set only if the count is non-zero.
806 void Worker::DoPreUpdateCheck(AppBundle* app_bundle,
807 xml::UpdateRequest* update_request) {
808 ASSERT1(app_bundle);
809 ASSERT1(update_request);
810
811 for (size_t i = 0; i != app_bundle->GetNumberOfApps(); ++i) {
812 App* app = app_bundle->GetApp(i);
813 app->PreUpdateCheck(update_request);
814 }
815
816 size_t num_disabled_apps = 0;
817 const std::vector<xml::request::App>& apps = update_request->request().apps;
818
819 // apps.size is 0 if update check was cancelled. Its size can also be less
820 // than the number of apps in app_bundle if EULA is not accepted for some
821 // apps.
822 ASSERT1(apps.size() <= app_bundle->GetNumberOfApps());
823
824 for (size_t i = 0; i != apps.size(); ++i) {
825 ASSERT1(apps[i].update_check.is_valid);
826 if (apps[i].update_check.is_update_disabled) {
827 ++num_disabled_apps;
828 }
829 }
830
831 if (num_disabled_apps) {
832 // Assumes that all apps are either updates or installs.
833 if (app_bundle->GetNumberOfApps() && app_bundle->GetApp(0)->is_update()) {
834 metric_worker_apps_not_updated_group_policy = num_disabled_apps;
835 } else {
836 metric_worker_apps_not_installed_group_policy = num_disabled_apps;
837 }
838 }
839 }
840
841 HRESULT Worker::DoUpdateCheck(AppBundle* app_bundle,
842 const xml::UpdateRequest* update_request,
843 xml::UpdateResponse* update_response) {
844 ASSERT1(app_bundle);
845 ASSERT1(update_request);
846 ASSERT1(update_response);
847
848 ASSERT1(app_bundle->GetNumberOfApps() > 0);
849
850 if (app_bundle->is_offline_install()) {
851 return offline_utils::ParseOfflineManifest(
852 app_bundle->GetApp(0)->app_guid_string(), app_bundle->offline_dir(),
853 update_response);
854 }
855
856 if (!ConfigManager::Instance()->CanUseNetwork(is_machine_)) {
857 CORE_LOG(L1, (_T("[Update check failed because network use prohibited]")));
858 return GOOPDATE_E_CANNOT_USE_NETWORK;
859 }
860
861 const bool is_update = app_bundle->is_auto_update();
862
863 if (is_update) {
864 ++metric_worker_update_check_total;
865 }
866
867 // This is a blocking call on the network.
868 HRESULT hr = app_bundle->update_check_client()->Send(update_request,
869 update_response);
870 if (FAILED(hr)) {
871 CORE_LOG(LE, (_T("[Send failed][0x%08x]"), hr));
872 worker_utils::AddHttpRequestDataToEventLog(
873 hr,
874 app_bundle->update_check_client()->http_status_code(),
875 app_bundle->update_check_client()->http_trace(),
876 is_machine_);
877
878 // TODO(omaha3): Omaha 2 would launch a web browser here for installs by
879 // calling goopdate_utils::LaunchBrowser(). Browser launch needs to be in
880 // the client but it currently has no way of knowing that it was a network
881 // error. Even here, we don't know that the it wasn't a parsing, etc. error.
882 return hr;
883 }
884
885 if (is_update) {
886 ++metric_worker_update_check_succeeded;
887 }
888
889 return S_OK;
890 }
891
892 void Worker::DoPostUpdateCheck(AppBundle* app_bundle,
893 HRESULT update_check_result,
894 xml::UpdateResponse* update_response) {
895 ASSERT1(app_bundle);
896 ASSERT1(update_response);
897
898 VERIFY1(SUCCEEDED(update_response_utils::ApplyExperimentLabelDeltas(
899 is_machine_,
900 update_response)));
901
902 for (size_t i = 0; i != app_bundle->GetNumberOfApps(); ++i) {
903 App* app = app_bundle->GetApp(i);
904 app->PostUpdateCheck(update_check_result, update_response);
905
906 ASSERT(app->state() == STATE_UPDATE_AVAILABLE ||
907 app->state() == STATE_NO_UPDATE ||
908 app->state() == STATE_ERROR,
909 (_T("App %Iu state is %u"), i, app->state()));
910 }
911
912 if (app_bundle->is_offline_install()) {
913 VERIFY1(SUCCEEDED(CacheOfflinePackages(app_bundle)));
914 VERIFY1(SUCCEEDED(DeleteDirectory(app_bundle->offline_dir())));
915 }
916 }
917
918 // Creates a thread pool work item for deferred execution of deferred_function.
919 // The thread pool owns this callback object.
920 HRESULT Worker::QueueDeferredFunctionCall0(
921 AppBundle* app_bundle,
922 void (Worker::*deferred_function)(shared_ptr<AppBundle>)) {
923 ASSERT1(app_bundle);
924 ASSERT1(deferred_function);
925
926 typedef ThreadPoolCallBack1<Worker, shared_ptr<AppBundle> > Callback;
927 scoped_ptr<Callback> callback(new Callback(this,
928 deferred_function,
929 app_bundle->controlling_ptr()));
930 HRESULT hr = Goopdate::Instance().QueueUserWorkItem(callback.get(),
931 WT_EXECUTELONGFUNCTION);
932 if (FAILED(hr)) {
933 return hr;
934 }
935
936 // Transfers the ownership of the callback from Worker to ThreadPool.
937 app_bundle->set_user_work_item(callback.release());
938 return S_OK;
939 }
940
941 // Creates a thread pool work item for deferred execution of deferred_function.
942 // The thread pool owns this callback object.
943 template <typename P1>
944 HRESULT Worker::QueueDeferredFunctionCall1(
945 AppBundle* app_bundle,
946 P1 p1,
947 void (Worker::*deferred_function)(shared_ptr<AppBundle>, P1)) {
948 ASSERT1(app_bundle);
949 ASSERT1(deferred_function);
950
951 typedef ThreadPoolCallBack2<Worker, shared_ptr<AppBundle>, P1> Callback;
952 scoped_ptr<Callback> callback(new Callback(this,
953 deferred_function,
954 app_bundle->controlling_ptr(),
955 p1));
956 HRESULT hr = Goopdate::Instance().QueueUserWorkItem(callback.get(),
957 WT_EXECUTELONGFUNCTION);
958 if (FAILED(hr)) {
959 return hr;
960 }
961
962 // Transfers the ownership of the callback from Worker to ThreadPool.
963 app_bundle->set_user_work_item(callback.release());
964 return S_OK;
965 }
966
967 void Worker::WriteEventLog(int event_type,
968 int event_id,
969 const CString& event_description,
970 const CString& event_text) {
971 GoogleUpdateLogEvent log_event(event_type, event_id, is_machine_);
972 log_event.set_event_desc(event_description);
973 log_event.set_event_text(event_text);
974 log_event.WriteEvent();
975 }
976
977 } // namespace omaha
OLDNEW
« no previous file with comments | « goopdate/worker.h ('k') | goopdate/worker_internal.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698