OLD | NEW |
| (Empty) |
1 // Copyright 2009-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/app.h" | |
17 #include "omaha/base/error.h" | |
18 #include "omaha/base/debug.h" | |
19 #include "omaha/base/logging.h" | |
20 #include "omaha/base/safe_format.h" | |
21 #include "omaha/base/scoped_ptr_address.h" | |
22 #include "omaha/base/synchronized.h" | |
23 #include "omaha/base/time.h" | |
24 #include "omaha/common/config_manager.h" | |
25 #include "omaha/common/experiment_labels.h" | |
26 #include "omaha/goopdate/app_manager.h" | |
27 #include "omaha/goopdate/app_state.h" | |
28 #include "omaha/goopdate/app_state_init.h" | |
29 #include "omaha/goopdate/current_state.h" | |
30 #include "omaha/goopdate/model.h" | |
31 #include "omaha/goopdate/server_resource.h" | |
32 #include "omaha/goopdate/string_formatter.h" | |
33 | |
34 namespace omaha { | |
35 | |
36 App::App(const GUID& app_guid, bool is_update, AppBundle* app_bundle) | |
37 : ModelObject(app_bundle->model()), | |
38 app_bundle_(app_bundle), | |
39 is_update_(is_update), | |
40 has_update_available_(false), | |
41 app_guid_(app_guid), | |
42 iid_(GUID_NULL), | |
43 install_time_diff_sec_(0), | |
44 is_eula_accepted_(TRISTATE_NONE), // Cannot ping until set true. | |
45 browser_type_(BROWSER_UNKNOWN), | |
46 days_since_last_active_ping_(0), | |
47 days_since_last_roll_call_(0), | |
48 usage_stats_enable_(TRISTATE_NONE), | |
49 did_run_(ACTIVE_UNKNOWN), | |
50 is_canceled_(false), | |
51 completion_result_(PingEvent::EVENT_RESULT_SUCCESS), | |
52 installer_result_code_(0), | |
53 installer_result_extra_code1_(0), | |
54 post_install_action_(POST_INSTALL_ACTION_DEFAULT), | |
55 previous_total_download_bytes_(0), | |
56 download_start_time_ms_(0), | |
57 download_complete_time_ms_(0), | |
58 num_bytes_downloaded_(0) { | |
59 ASSERT1(!::IsEqualGUID(GUID_NULL, app_guid_)); | |
60 | |
61 current_version_.reset(new AppVersion(this)); | |
62 next_version_.reset(new AppVersion(this)); | |
63 | |
64 // TODO(omaha): set the working_version_ correctly to indicate which | |
65 // version of the app is modified: current version for components and | |
66 // next version for install/updates. The code do not support components yet | |
67 // and the working version in set to next always. | |
68 working_version_ = next_version_.get(); | |
69 app_state_.reset(new fsm::AppStateInit); | |
70 } | |
71 | |
72 // Destruction of App objects happens within the scope of their parent, | |
73 // which controls the locking. | |
74 App::~App() { | |
75 ASSERT1(model()->IsLockedByCaller()); | |
76 working_version_ = NULL; | |
77 app_bundle_ = NULL; | |
78 } | |
79 | |
80 STDMETHODIMP App::get_appId(BSTR* app_id) { | |
81 __mutexScope(model()->lock()); | |
82 ASSERT1(app_id); | |
83 *app_id = GuidToString(app_guid_).AllocSysString(); | |
84 return S_OK; | |
85 } | |
86 | |
87 STDMETHODIMP App::get_language(BSTR* language) { | |
88 __mutexScope(model()->lock()); | |
89 ASSERT1(language); | |
90 *language = language_.AllocSysString(); | |
91 return S_OK; | |
92 } | |
93 | |
94 STDMETHODIMP App::put_language(BSTR language) { | |
95 __mutexScope(model()->lock()); | |
96 language_ = language; | |
97 return S_OK; | |
98 } | |
99 | |
100 STDMETHODIMP App::get_ap(BSTR* ap) { | |
101 __mutexScope(model()->lock()); | |
102 ASSERT1(ap); | |
103 *ap = ap_.AllocSysString(); | |
104 return S_OK; | |
105 } | |
106 | |
107 STDMETHODIMP App::put_ap(BSTR ap) { | |
108 __mutexScope(model()->lock()); | |
109 ap_ = ap; | |
110 return S_OK; | |
111 } | |
112 | |
113 STDMETHODIMP App::get_pv(BSTR* pv) { | |
114 __mutexScope(model()->lock()); | |
115 ASSERT1(pv); | |
116 *pv = pv_.AllocSysString(); | |
117 return S_OK; | |
118 } | |
119 | |
120 STDMETHODIMP App::put_pv(BSTR pv) { | |
121 __mutexScope(model()->lock()); | |
122 pv_ = pv; | |
123 return S_OK; | |
124 } | |
125 | |
126 STDMETHODIMP App::get_ttToken(BSTR* tt_token) { | |
127 __mutexScope(model()->lock()); | |
128 ASSERT1(tt_token); | |
129 *tt_token = tt_token_.AllocSysString(); | |
130 return S_OK; | |
131 } | |
132 | |
133 STDMETHODIMP App::put_ttToken(BSTR tt_token) { | |
134 __mutexScope(model()->lock()); | |
135 tt_token_ = tt_token; | |
136 return S_OK; | |
137 } | |
138 | |
139 STDMETHODIMP App::get_iid(BSTR* iid) { | |
140 __mutexScope(model()->lock()); | |
141 ASSERT1(iid); | |
142 *iid = GuidToString(iid_).AllocSysString(); | |
143 return S_OK; | |
144 } | |
145 | |
146 STDMETHODIMP App::put_iid(BSTR iid) { | |
147 __mutexScope(model()->lock()); | |
148 return StringToGuidSafe(iid, &iid_); | |
149 } | |
150 | |
151 STDMETHODIMP App::get_brandCode(BSTR* brand_code) { | |
152 __mutexScope(model()->lock()); | |
153 ASSERT1(brand_code); | |
154 *brand_code = brand_code_.AllocSysString(); | |
155 return S_OK; | |
156 } | |
157 | |
158 STDMETHODIMP App::put_brandCode(BSTR brand_code) { | |
159 __mutexScope(model()->lock()); | |
160 brand_code_ = brand_code; | |
161 return S_OK; | |
162 } | |
163 | |
164 STDMETHODIMP App::get_clientId(BSTR* client_id) { | |
165 __mutexScope(model()->lock()); | |
166 ASSERT1(client_id); | |
167 *client_id = client_id_.AllocSysString(); | |
168 return S_OK; | |
169 } | |
170 | |
171 STDMETHODIMP App::put_clientId(BSTR client_id) { | |
172 __mutexScope(model()->lock()); | |
173 client_id_ = client_id; | |
174 return S_OK; | |
175 } | |
176 | |
177 STDMETHODIMP App::get_labels(BSTR* labels) { | |
178 __mutexScope(model()->lock()); | |
179 ASSERT1(labels); | |
180 *labels = GetExperimentLabels().AllocSysString(); | |
181 return S_OK; | |
182 } | |
183 | |
184 STDMETHODIMP App::put_labels(BSTR labels) { | |
185 __mutexScope(model()->lock()); | |
186 ExperimentLabels decoded_labels; | |
187 if (!decoded_labels.Deserialize(labels)) { | |
188 return E_INVALIDARG; | |
189 } | |
190 return decoded_labels.WriteToRegistry(app_bundle_->is_machine(), | |
191 app_guid_string()); | |
192 } | |
193 | |
194 STDMETHODIMP App::get_referralId(BSTR* referral_id) { | |
195 __mutexScope(model()->lock()); | |
196 ASSERT1(referral_id); | |
197 *referral_id = referral_id_.AllocSysString(); | |
198 return S_OK; | |
199 } | |
200 | |
201 STDMETHODIMP App::put_referralId(BSTR referral_id) { | |
202 __mutexScope(model()->lock()); | |
203 referral_id_ = referral_id; | |
204 return S_OK; | |
205 } | |
206 | |
207 STDMETHODIMP App::get_installTimeDiffSec(UINT* install_time_diff_sec) { | |
208 __mutexScope(model()->lock()); | |
209 ASSERT1(install_time_diff_sec); | |
210 *install_time_diff_sec = install_time_diff_sec_; | |
211 return S_OK; | |
212 } | |
213 | |
214 STDMETHODIMP App::get_isEulaAccepted(VARIANT_BOOL* is_eula_accepted) { | |
215 __mutexScope(model()->lock()); | |
216 ASSERT1(is_eula_accepted); | |
217 *is_eula_accepted = App::is_eula_accepted() ? VARIANT_TRUE : VARIANT_FALSE; | |
218 return S_OK; | |
219 } | |
220 | |
221 STDMETHODIMP App::put_isEulaAccepted(VARIANT_BOOL is_eula_accepted) { | |
222 __mutexScope(model()->lock()); | |
223 is_eula_accepted_ = is_eula_accepted ? TRISTATE_TRUE : TRISTATE_FALSE; | |
224 return S_OK; | |
225 } | |
226 | |
227 STDMETHODIMP App::get_displayName(BSTR* display_name) { | |
228 __mutexScope(model()->lock()); | |
229 ASSERT1(display_name); | |
230 *display_name = display_name_.AllocSysString(); | |
231 return S_OK; | |
232 } | |
233 | |
234 STDMETHODIMP App::put_displayName(BSTR display_name) { | |
235 __mutexScope(model()->lock()); | |
236 display_name_ = display_name; | |
237 return S_OK; | |
238 } | |
239 | |
240 STDMETHODIMP App::get_browserType(UINT* browser_type) { | |
241 __mutexScope(model()->lock()); | |
242 ASSERT1(browser_type); | |
243 *browser_type = browser_type_; | |
244 return S_OK; | |
245 } | |
246 | |
247 STDMETHODIMP App::put_browserType(UINT browser_type) { | |
248 __mutexScope(model()->lock()); | |
249 if (browser_type >= BROWSER_MAX) { | |
250 return E_INVALIDARG; | |
251 } | |
252 browser_type_ = static_cast<BrowserType>(browser_type); | |
253 return S_OK; | |
254 } | |
255 | |
256 STDMETHODIMP App::get_clientInstallData(BSTR* data) { | |
257 __mutexScope(model()->lock()); | |
258 ASSERT1(data); | |
259 *data = client_install_data_.AllocSysString(); | |
260 return S_OK; | |
261 } | |
262 | |
263 STDMETHODIMP App::put_clientInstallData(BSTR data) { | |
264 __mutexScope(model()->lock()); | |
265 client_install_data_ = data; | |
266 return S_OK; | |
267 } | |
268 | |
269 STDMETHODIMP App::get_serverInstallDataIndex(BSTR* index) { | |
270 __mutexScope(model()->lock()); | |
271 ASSERT1(index); | |
272 *index = server_install_data_index_.AllocSysString(); | |
273 return S_OK; | |
274 } | |
275 | |
276 STDMETHODIMP App::put_serverInstallDataIndex(BSTR index) { | |
277 __mutexScope(model()->lock()); | |
278 server_install_data_index_ = index; | |
279 return S_OK; | |
280 } | |
281 | |
282 STDMETHODIMP App::get_usageStatsEnable(UINT* usage_stats_enable) { | |
283 __mutexScope(model()->lock()); | |
284 ASSERT1(usage_stats_enable); | |
285 *usage_stats_enable = usage_stats_enable_; | |
286 return S_OK; | |
287 } | |
288 | |
289 STDMETHODIMP App::put_usageStatsEnable(UINT usage_stats_enable) { | |
290 __mutexScope(model()->lock()); | |
291 if (usage_stats_enable > TRISTATE_NONE) { | |
292 return E_INVALIDARG; | |
293 } | |
294 usage_stats_enable_ = static_cast<Tristate>(usage_stats_enable); | |
295 return S_OK; | |
296 } | |
297 | |
298 // TODO(omaha3): Replace decisions based on state() with calls to AppState. | |
299 // In this case, there should be a GetCurrentState() method on AppState. | |
300 STDMETHODIMP App::get_currentState(IDispatch** current_state) { | |
301 __mutexScope(model()->lock()); | |
302 | |
303 CORE_LOG(L3, (_T("[App::get_currentState][0x%p]"), this)); | |
304 ASSERT1(current_state); | |
305 | |
306 ULONGLONG bytes_downloaded = 0; | |
307 ULONGLONG total_bytes_to_download = 0; | |
308 ULONGLONG next_download_retry_time = 0; | |
309 LONG download_time_remaining_ms = kCurrentStateProgressUnknown; | |
310 LONG install_progress_percentage = kCurrentStateProgressUnknown; | |
311 LONG install_time_remaining_ms = kCurrentStateProgressUnknown; | |
312 | |
313 HRESULT hr = S_OK; | |
314 switch (state()) { | |
315 case STATE_INIT: | |
316 break; | |
317 case STATE_WAITING_TO_CHECK_FOR_UPDATE: | |
318 break; | |
319 case STATE_CHECKING_FOR_UPDATE: | |
320 break; | |
321 case STATE_UPDATE_AVAILABLE: | |
322 break; | |
323 case STATE_NO_UPDATE: | |
324 ASSERT1(error_code() == S_OK || | |
325 error_code() == GOOPDATE_E_UPDATE_DEFERRED); | |
326 ASSERT1(!completion_message_.IsEmpty()); | |
327 ASSERT1(completion_result_ == PingEvent::EVENT_RESULT_SUCCESS || | |
328 completion_result_ == PingEvent::EVENT_RESULT_UPDATE_DEFERRED); | |
329 ASSERT1(installer_result_code_ == 0); | |
330 break; | |
331 case STATE_WAITING_TO_DOWNLOAD: | |
332 case STATE_RETRYING_DOWNLOAD: | |
333 case STATE_DOWNLOADING: | |
334 case STATE_DOWNLOAD_COMPLETE: | |
335 case STATE_EXTRACTING: | |
336 case STATE_APPLYING_DIFFERENTIAL_PATCH: | |
337 case STATE_READY_TO_INSTALL: | |
338 hr = GetDownloadProgress(&bytes_downloaded, | |
339 &total_bytes_to_download, | |
340 &download_time_remaining_ms, | |
341 &next_download_retry_time); | |
342 break; | |
343 case STATE_WAITING_TO_INSTALL: | |
344 break; | |
345 case STATE_INSTALLING: | |
346 // TODO(omaha3): Obtain install_progress_percentage and | |
347 // install_time_remaining_ms. | |
348 break; | |
349 case STATE_INSTALL_COMPLETE: | |
350 install_progress_percentage = 100; | |
351 install_time_remaining_ms = 0; | |
352 | |
353 ASSERT1(error_code() == S_OK); | |
354 ASSERT1(!completion_message_.IsEmpty()); | |
355 ASSERT1(completion_result_ == PingEvent::EVENT_RESULT_SUCCESS || | |
356 completion_result_ == PingEvent::EVENT_RESULT_SUCCESS_REBOOT); | |
357 break; | |
358 case STATE_PAUSED: | |
359 break; | |
360 case STATE_ERROR: | |
361 ASSERT1(error_code() != S_OK); | |
362 ASSERT1(!completion_message_.IsEmpty()); | |
363 ASSERT1( | |
364 completion_result_ == PingEvent::EVENT_RESULT_ERROR || | |
365 completion_result_ == PingEvent::EVENT_RESULT_CANCELLED || | |
366 completion_result_ == PingEvent::EVENT_RESULT_INSTALLER_ERROR_MSI || | |
367 completion_result_ == PingEvent::EVENT_RESULT_INSTALLER_ERROR_OTHER || | |
368 completion_result_ == PingEvent::EVENT_RESULT_INSTALLER_ERROR_SYSTEM); | |
369 break; | |
370 default: | |
371 ASSERT1(false); | |
372 hr = E_FAIL; | |
373 break; | |
374 } | |
375 | |
376 if (FAILED(hr)) { | |
377 return hr; | |
378 } | |
379 | |
380 CComObject<CurrentAppState>* state_object = NULL; | |
381 hr = CurrentAppState::Create(state(), | |
382 next_version()->version(), | |
383 bytes_downloaded, | |
384 total_bytes_to_download, | |
385 download_time_remaining_ms, | |
386 next_download_retry_time, | |
387 install_progress_percentage, | |
388 install_time_remaining_ms, | |
389 is_canceled_, | |
390 error_context_.error_code, | |
391 error_context_.extra_code1, | |
392 completion_message_, | |
393 installer_result_code_, | |
394 installer_result_extra_code1_, | |
395 post_install_launch_command_line_, | |
396 post_install_url_, | |
397 post_install_action_, | |
398 &state_object); | |
399 if (FAILED(hr)) { | |
400 return hr; | |
401 } | |
402 | |
403 return state_object->QueryInterface(current_state); | |
404 } | |
405 | |
406 // TODO(omaha3): If some packages are already cached, there may be awkward jumps | |
407 // in progress if we don't filter those out of bytes_total from the beginning. | |
408 // TODO(omaha3): For now we use the package's expected_size to calculate | |
409 // bytes_total. This may or may not be what we want. See the TODO for | |
410 // Package::OnProgress(). | |
411 // TODO(omaha3): Maybe optimize, especially in states other than | |
412 // STATE_DOWNLOADING. | |
413 HRESULT App::GetDownloadProgress(uint64* bytes_downloaded, | |
414 uint64* bytes_total, | |
415 LONG* time_remaining_ms, | |
416 uint64* next_retry_time) { | |
417 ASSERT1(model()->IsLockedByCaller()); | |
418 | |
419 ASSERT1(bytes_downloaded); | |
420 ASSERT1(bytes_total); | |
421 ASSERT1(time_remaining_ms); | |
422 ASSERT1(next_retry_time); | |
423 | |
424 *bytes_downloaded = 0; | |
425 *bytes_total = 0; | |
426 *next_retry_time = 0; | |
427 | |
428 *time_remaining_ms = kCurrentStateProgressUnknown; | |
429 | |
430 for (size_t i = 0; i < working_version_->GetNumberOfPackages(); ++i) { | |
431 const Package* package = working_version_->GetPackage(i); | |
432 | |
433 const uint64 package_bytes = package->bytes_downloaded(); | |
434 ASSERT1((*bytes_downloaded + package_bytes > *bytes_downloaded) || | |
435 package_bytes == 0); | |
436 *bytes_downloaded += package_bytes; | |
437 | |
438 const uint64 package_size = package->expected_size(); | |
439 ASSERT1(0 < package_size); | |
440 ASSERT1(*bytes_total + package_size > *bytes_total); | |
441 *bytes_total += package_size; | |
442 | |
443 LONG package_remaining_time_ms = | |
444 package->GetEstimatedRemainingDownloadTimeMs(); | |
445 if (*time_remaining_ms < package_remaining_time_ms) { | |
446 *time_remaining_ms = package_remaining_time_ms; | |
447 } | |
448 | |
449 uint64 package_next_retry_time = package->next_download_retry_time(); | |
450 if (package_bytes < package_size && package_next_retry_time != 0 && | |
451 (*next_retry_time == 0 || *next_retry_time > package_next_retry_time)) { | |
452 *next_retry_time = package_next_retry_time; | |
453 } | |
454 } | |
455 | |
456 ASSERT1(*bytes_downloaded <= *bytes_total); | |
457 | |
458 ASSERT1(previous_total_download_bytes_ == *bytes_total || | |
459 previous_total_download_bytes_ == 0); | |
460 previous_total_download_bytes_ = *bytes_total; | |
461 | |
462 return S_OK; | |
463 } | |
464 | |
465 AppBundle* App::app_bundle() { | |
466 __mutexScope(model()->lock()); | |
467 return app_bundle_; | |
468 } | |
469 | |
470 const AppBundle* App::app_bundle() const { | |
471 __mutexScope(model()->lock()); | |
472 return app_bundle_; | |
473 } | |
474 | |
475 AppVersion* App::current_version() { | |
476 __mutexScope(model()->lock()); | |
477 return current_version_.get(); | |
478 } | |
479 | |
480 const AppVersion* App::current_version() const { | |
481 __mutexScope(model()->lock()); | |
482 return current_version_.get(); | |
483 } | |
484 | |
485 AppVersion* App::next_version() { | |
486 __mutexScope(model()->lock()); | |
487 return next_version_.get(); | |
488 } | |
489 | |
490 const AppVersion* App::next_version() const { | |
491 __mutexScope(model()->lock()); | |
492 return next_version_.get(); | |
493 } | |
494 | |
495 CString App::app_guid_string() const { | |
496 return GuidToString(app_guid()); | |
497 } | |
498 | |
499 GUID App::app_guid() const { | |
500 __mutexScope(model()->lock()); | |
501 return app_guid_; | |
502 } | |
503 | |
504 void App::set_app_guid(const GUID& app_guid) { | |
505 __mutexScope(model()->lock()); | |
506 app_guid_ = app_guid; | |
507 } | |
508 | |
509 CString App::language() const { | |
510 __mutexScope(model()->lock()); | |
511 return language_; | |
512 } | |
513 | |
514 bool App::is_eula_accepted() const { | |
515 __mutexScope(model()->lock()); | |
516 return is_eula_accepted_ == TRISTATE_TRUE; | |
517 } | |
518 | |
519 CString App::display_name() const { | |
520 __mutexScope(model()->lock()); | |
521 return display_name_; | |
522 } | |
523 | |
524 CurrentState App::state() const { | |
525 __mutexScope(model()->lock()); | |
526 return app_state_->state(); | |
527 } | |
528 | |
529 bool App::is_update() const { | |
530 __mutexScope(model()->lock()); | |
531 ASSERT1(current_version_->version().IsEmpty() != is_update_); | |
532 return is_update_; | |
533 } | |
534 | |
535 bool App::has_update_available() const { | |
536 __mutexScope(model()->lock()); | |
537 return has_update_available_; | |
538 } | |
539 | |
540 void App::set_has_update_available(bool has_update_available) { | |
541 __mutexScope(model()->lock()); | |
542 has_update_available_ = has_update_available; | |
543 } | |
544 | |
545 GUID App::iid() const { | |
546 __mutexScope(model()->lock()); | |
547 return iid_; | |
548 } | |
549 | |
550 CString App::client_id() const { | |
551 __mutexScope(model()->lock()); | |
552 return client_id_; | |
553 } | |
554 | |
555 CString App::GetExperimentLabels() const { | |
556 __mutexScope(model()->lock()); | |
557 ExperimentLabels stored_labels; | |
558 VERIFY1(SUCCEEDED(stored_labels.ReadFromRegistry(app_bundle_->is_machine(), | |
559 app_guid_string()))); | |
560 return stored_labels.Serialize(); | |
561 } | |
562 | |
563 CString App::referral_id() const { | |
564 __mutexScope(model()->lock()); | |
565 return referral_id_; | |
566 } | |
567 | |
568 BrowserType App::browser_type() const { | |
569 __mutexScope(model()->lock()); | |
570 return browser_type_; | |
571 } | |
572 | |
573 Tristate App::usage_stats_enable() const { | |
574 __mutexScope(model()->lock()); | |
575 return usage_stats_enable_; | |
576 } | |
577 | |
578 CString App::client_install_data() const { | |
579 __mutexScope(model()->lock()); | |
580 return client_install_data_; | |
581 } | |
582 | |
583 CString App::server_install_data() const { | |
584 __mutexScope(model()->lock()); | |
585 return server_install_data_; | |
586 } | |
587 | |
588 void App::set_server_install_data(const CString& server_install_data) { | |
589 __mutexScope(model()->lock()); | |
590 server_install_data_ = server_install_data; | |
591 } | |
592 | |
593 CString App::brand_code() const { | |
594 __mutexScope(model()->lock()); | |
595 return brand_code_; | |
596 } | |
597 | |
598 // TODO(omaha): for better accuracy, compute the value when used. | |
599 uint32 App::install_time_diff_sec() const { | |
600 __mutexScope(model()->lock()); | |
601 return install_time_diff_sec_; | |
602 } | |
603 | |
604 ActiveStates App::did_run() const { | |
605 __mutexScope(model()->lock()); | |
606 return did_run_; | |
607 } | |
608 | |
609 int App::days_since_last_active_ping() const { | |
610 __mutexScope(model()->lock()); | |
611 return days_since_last_active_ping_; | |
612 } | |
613 | |
614 void App::set_days_since_last_active_ping(int days) { | |
615 __mutexScope(model()->lock()); | |
616 days_since_last_active_ping_ = days; | |
617 } | |
618 | |
619 int App::days_since_last_roll_call() const { | |
620 __mutexScope(model()->lock()); | |
621 return days_since_last_roll_call_; | |
622 } | |
623 | |
624 void App::set_days_since_last_roll_call(int days) { | |
625 __mutexScope(model()->lock()); | |
626 days_since_last_roll_call_ = days; | |
627 } | |
628 | |
629 CString App::ap() const { | |
630 __mutexScope(model()->lock()); | |
631 return ap_; | |
632 } | |
633 | |
634 CString App::tt_token() const { | |
635 __mutexScope(model()->lock()); | |
636 return tt_token_; | |
637 } | |
638 | |
639 CString App::server_install_data_index() const { | |
640 __mutexScope(model()->lock()); | |
641 return server_install_data_index_; | |
642 } | |
643 | |
644 HRESULT App::error_code() const { | |
645 __mutexScope(model()->lock()); | |
646 return error_context_.error_code; | |
647 } | |
648 | |
649 ErrorContext App::error_context() const { | |
650 __mutexScope(model()->lock()); | |
651 return error_context_; | |
652 } | |
653 | |
654 int App::installer_result_code() const { | |
655 __mutexScope(model()->lock()); | |
656 return installer_result_code_; | |
657 } | |
658 | |
659 int App::installer_result_extra_code1() const { | |
660 __mutexScope(model()->lock()); | |
661 return installer_result_extra_code1_; | |
662 } | |
663 | |
664 const PingEventVector& App::ping_events() const { | |
665 __mutexScope(model()->lock()); | |
666 return ping_events_; | |
667 } | |
668 | |
669 AppVersion* App::working_version() { | |
670 __mutexScope(model()->lock()); | |
671 return working_version_; | |
672 } | |
673 | |
674 const AppVersion* App::working_version() const { | |
675 __mutexScope(model()->lock()); | |
676 return working_version_; | |
677 } | |
678 | |
679 CString App::FetchAndResetLogText() { | |
680 __mutexScope(model()->lock()); | |
681 CString event_log_text(event_log_text_); | |
682 event_log_text_.Empty(); | |
683 | |
684 return event_log_text; | |
685 } | |
686 | |
687 void App::LogTextAppendFormat(const TCHAR* format, ...) { | |
688 ASSERT1(format); | |
689 | |
690 CString log_string; | |
691 | |
692 va_list arguments; | |
693 va_start(arguments, format); | |
694 SafeCStringFormatV(&log_string, format, arguments); | |
695 va_end(arguments); | |
696 | |
697 __mutexScope(model()->lock()); | |
698 SafeCStringAppendFormat(&event_log_text_, _T("App=%s, Ver=%s, %s\n"), | |
699 app_guid_string().GetString(), | |
700 current_version()->version().GetString(), | |
701 log_string.GetString()); | |
702 } | |
703 | |
704 void App::AddPingEvent(const PingEventPtr& ping_event) { | |
705 __mutexScope(model()->lock()); | |
706 ping_events_.push_back(ping_event); | |
707 CORE_LOG(L3, (_T("[ping event added][%s]"), ping_event->ToString())); | |
708 } | |
709 | |
710 HRESULT App::CheckGroupPolicy() const { | |
711 __mutexScope(model()->lock()); | |
712 | |
713 bool is_auto_update = false; | |
714 | |
715 if (is_update_) { | |
716 if (!ConfigManager::Instance()->CanUpdateApp( | |
717 app_guid_, | |
718 !app_bundle_->is_auto_update())) { | |
719 return GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY; | |
720 } | |
721 } else { | |
722 ASSERT1(!is_auto_update); | |
723 if (!ConfigManager::Instance()->CanInstallApp(app_guid_)) { | |
724 return GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY; | |
725 } | |
726 } | |
727 | |
728 return S_OK; | |
729 } | |
730 | |
731 void App::SetDownloadStartTime() { | |
732 __mutexScope(model()->lock()); | |
733 ASSERT1(download_complete_time_ms_ == 0); | |
734 ASSERT1(num_bytes_downloaded_ == 0); | |
735 | |
736 download_start_time_ms_ = GetCurrentMsTime(); | |
737 } | |
738 | |
739 void App::SetDownloadCompleteTime() { | |
740 __mutexScope(model()->lock()); | |
741 download_complete_time_ms_ = GetCurrentMsTime(); | |
742 } | |
743 | |
744 void App::UpdateNumBytesDownloaded(uint64 num_bytes) { | |
745 __mutexScope(model()->lock()); | |
746 | |
747 CORE_LOG(L3, (_T("[RecordDownloadedBytes][new bytes downloaded: %llu]"), | |
748 num_bytes)); | |
749 num_bytes_downloaded_ += num_bytes; | |
750 } | |
751 | |
752 int App::GetDownloadTimeMs() const { | |
753 __mutexScope(model()->lock()); | |
754 | |
755 if (download_complete_time_ms_ < download_start_time_ms_) { | |
756 return 0; | |
757 } | |
758 | |
759 return static_cast<int>(download_complete_time_ms_ - download_start_time_ms_); | |
760 } | |
761 | |
762 uint64 App::num_bytes_downloaded() const { | |
763 __mutexScope(model()->lock()); | |
764 return num_bytes_downloaded_; | |
765 } | |
766 | |
767 uint64 App::GetPackagesTotalSize() const { | |
768 __mutexScope(model()->lock()); | |
769 | |
770 uint64 total_size = 0; | |
771 const size_t num_packages = working_version_->GetNumberOfPackages(); | |
772 for (size_t i = 0; i < num_packages; ++i) { | |
773 total_size += working_version_->GetPackage(i)->expected_size(); | |
774 } | |
775 | |
776 return total_size; | |
777 } | |
778 | |
779 // | |
780 // State transition methods. | |
781 // These should not do anything except acquire the lock if appropriate and call | |
782 // the corresponding AppState method. | |
783 // | |
784 | |
785 // This is the first transition. EULA acceptance must have been set by now. | |
786 // Fail so that client developers realize quickly that something is wrong. | |
787 // Otherwise, they might ship a client that installs apps that never update. | |
788 void App::QueueUpdateCheck() { | |
789 __mutexScope(model()->lock()); | |
790 | |
791 ASSERT1(is_eula_accepted_ != TRISTATE_NONE); | |
792 if (is_eula_accepted_ == TRISTATE_NONE) { | |
793 CString message; | |
794 StringFormatter formatter(app_bundle_->display_language()); | |
795 VERIFY1(SUCCEEDED(formatter.LoadString(IDS_INSTALL_FAILED, &message))); | |
796 Error(ErrorContext(GOOPDATE_E_CALL_UNEXPECTED), message); | |
797 } | |
798 | |
799 app_state_->QueueUpdateCheck(this); | |
800 } | |
801 | |
802 void App::PreUpdateCheck(xml::UpdateRequest* update_request) { | |
803 ASSERT1(update_request); | |
804 __mutexScope(model()->lock()); | |
805 app_state_->PreUpdateCheck(this, update_request); | |
806 } | |
807 | |
808 void App::PostUpdateCheck(HRESULT result, | |
809 xml::UpdateResponse* update_response) { | |
810 ASSERT1(update_response); | |
811 __mutexScope(model()->lock()); | |
812 app_state_->PostUpdateCheck(this, result, update_response); | |
813 } | |
814 | |
815 void App::QueueDownload() { | |
816 __mutexScope(model()->lock()); | |
817 app_state_->QueueDownload(this); | |
818 } | |
819 | |
820 void App::QueueDownloadOrInstall() { | |
821 __mutexScope(model()->lock()); | |
822 app_state_->QueueDownloadOrInstall(this); | |
823 } | |
824 | |
825 // Does not take the lock because this is a blocking call. | |
826 void App::Download(DownloadManagerInterface* download_manager) { | |
827 app_state_->Download(this, download_manager); | |
828 } | |
829 | |
830 void App::Downloading() { | |
831 __mutexScope(model()->lock()); | |
832 app_state_->Downloading(this); | |
833 } | |
834 | |
835 void App::DownloadComplete() { | |
836 __mutexScope(model()->lock()); | |
837 app_state_->DownloadComplete(this); | |
838 } | |
839 | |
840 void App::MarkReadyToInstall() { | |
841 __mutexScope(model()->lock()); | |
842 app_state_->MarkReadyToInstall(this); | |
843 } | |
844 | |
845 void App::QueueInstall() { | |
846 __mutexScope(model()->lock()); | |
847 app_state_->QueueInstall(this); | |
848 } | |
849 | |
850 // Does not take the lock because this is a blocking call. | |
851 void App::Install(InstallManagerInterface* install_manager) { | |
852 app_state_->Install(this, install_manager); | |
853 } | |
854 | |
855 void App::Installing() { | |
856 __mutexScope(model()->lock()); | |
857 app_state_->Installing(this); | |
858 } | |
859 | |
860 void App::ReportInstallerComplete(const InstallerResultInfo& result_info) { | |
861 __mutexScope(model()->lock()); | |
862 app_state_->ReportInstallerComplete(this, | |
863 result_info); | |
864 } | |
865 | |
866 void App::Pause() { | |
867 __mutexScope(model()->lock()); | |
868 return app_state_->Pause(this); | |
869 } | |
870 | |
871 void App::Cancel() { | |
872 __mutexScope(model()->lock()); | |
873 return app_state_->Cancel(this); | |
874 } | |
875 | |
876 void App::Error(const ErrorContext& error_context, const CString& message) { | |
877 __mutexScope(model()->lock()); | |
878 app_state_->Error(this, error_context, message); | |
879 } | |
880 | |
881 void App::ChangeState(fsm::AppState* app_state) { | |
882 ASSERT1(app_state); | |
883 ASSERT1(model()->IsLockedByCaller()); | |
884 CurrentState existing_state = app_state_->state(); | |
885 app_state_.reset(app_state); | |
886 PingEventPtr ping_event( | |
887 app_state->CreatePingEvent(this, existing_state)); | |
888 if (ping_event.get()) { | |
889 AddPingEvent(ping_event); | |
890 } | |
891 } | |
892 | |
893 void App::SetError(const ErrorContext& error_context, const CString& message) { | |
894 ASSERT1(FAILED(error_context.error_code)); | |
895 ASSERT1(!message.IsEmpty()); | |
896 ASSERT1(model()->IsLockedByCaller()); | |
897 | |
898 error_context_ = error_context; | |
899 completion_message_ = message; | |
900 | |
901 is_canceled_ = (error_context_.error_code == GOOPDATE_E_CANCELLED); | |
902 completion_result_ = is_canceled_ ? PingEvent::EVENT_RESULT_CANCELLED : | |
903 PingEvent::EVENT_RESULT_ERROR; | |
904 } | |
905 | |
906 void App::SetNoUpdate(const ErrorContext& error_context, | |
907 const CString& message) { | |
908 ASSERT1(!message.IsEmpty()); | |
909 ASSERT1(model()->IsLockedByCaller()); | |
910 | |
911 error_context_ = error_context; | |
912 completion_message_ = message; | |
913 | |
914 const bool is_deferred_update = | |
915 (error_context_.error_code == GOOPDATE_E_UPDATE_DEFERRED); | |
916 completion_result_ = is_deferred_update ? | |
917 PingEvent::EVENT_RESULT_UPDATE_DEFERRED : | |
918 PingEvent::EVENT_RESULT_SUCCESS; | |
919 } | |
920 | |
921 void App::SetInstallerResult(const InstallerResultInfo& result_info) { | |
922 ASSERT1(result_info.type != INSTALLER_RESULT_UNKNOWN); | |
923 ASSERT1(!result_info.text.IsEmpty()); | |
924 ASSERT1(model()->IsLockedByCaller()); | |
925 | |
926 completion_message_ = result_info.text; | |
927 installer_result_code_ = result_info.code; | |
928 installer_result_extra_code1_ = result_info.extra_code1; | |
929 post_install_launch_command_line_ = | |
930 result_info.post_install_launch_command_line; | |
931 post_install_url_ = result_info.post_install_url; | |
932 post_install_action_ = result_info.post_install_action; | |
933 | |
934 switch (result_info.type) { | |
935 case INSTALLER_RESULT_SUCCESS: { | |
936 error_context_.error_code = S_OK; | |
937 | |
938 // TODO(omaha3): Determine whether a reboot is required. See TODO in | |
939 // InstallerWrapper. | |
940 const bool is_reboot_required = false; | |
941 completion_result_ = is_reboot_required ? | |
942 PingEvent::EVENT_RESULT_SUCCESS_REBOOT : | |
943 PingEvent::EVENT_RESULT_SUCCESS; | |
944 | |
945 // We do not know whether Goopdate has succeeded because its installer has | |
946 // not completed. | |
947 if (!::IsEqualGUID(kGoopdateGuid, app_guid_)) { | |
948 AppManager::Instance()->PersistSuccessfulInstall(*this); | |
949 } | |
950 break; | |
951 } | |
952 case INSTALLER_RESULT_ERROR_MSI: | |
953 completion_result_ = PingEvent::EVENT_RESULT_INSTALLER_ERROR_MSI; | |
954 error_context_.error_code = GOOPDATEINSTALL_E_INSTALLER_FAILED; | |
955 break; | |
956 case INSTALLER_RESULT_ERROR_SYSTEM: | |
957 completion_result_ = PingEvent::EVENT_RESULT_INSTALLER_ERROR_SYSTEM; | |
958 error_context_.error_code = GOOPDATEINSTALL_E_INSTALLER_FAILED; | |
959 break; | |
960 case INSTALLER_RESULT_ERROR_OTHER: | |
961 completion_result_ = PingEvent::EVENT_RESULT_INSTALLER_ERROR_OTHER; | |
962 error_context_.error_code = GOOPDATEINSTALL_E_INSTALLER_FAILED; | |
963 break; | |
964 case INSTALLER_RESULT_UNKNOWN: | |
965 default: | |
966 ASSERT1(false); | |
967 completion_result_ = PingEvent::EVENT_RESULT_ERROR; | |
968 error_context_.error_code = E_FAIL; | |
969 } | |
970 } | |
971 | |
972 CString App::GetInstallData() const { | |
973 __mutexScope(model()->lock()); | |
974 | |
975 ASSERT1(state() >= STATE_UPDATE_AVAILABLE && | |
976 state() <= STATE_INSTALL_COMPLETE); | |
977 | |
978 if (!client_install_data_.IsEmpty()) { | |
979 return client_install_data_; | |
980 } | |
981 | |
982 return server_install_data_; | |
983 } | |
984 | |
985 // IApp. | |
986 STDMETHODIMP AppWrapper::get_currentVersion(IDispatch** current_version) { | |
987 __mutexScope(model()->lock()); | |
988 return AppVersionWrapper::Create(controlling_ptr(), | |
989 wrapped_obj()->current_version(), | |
990 current_version); | |
991 } | |
992 | |
993 STDMETHODIMP AppWrapper::get_nextVersion(IDispatch** next_version) { | |
994 __mutexScope(model()->lock()); | |
995 return AppVersionWrapper::Create(controlling_ptr(), | |
996 wrapped_obj()->next_version(), | |
997 next_version); | |
998 } | |
999 | |
1000 // IApp. | |
1001 STDMETHODIMP AppWrapper::get_appId(BSTR* app_id) { | |
1002 __mutexScope(model()->lock()); | |
1003 return wrapped_obj()->get_appId(app_id); | |
1004 } | |
1005 | |
1006 STDMETHODIMP AppWrapper::get_pv(BSTR* pv) { | |
1007 __mutexScope(model()->lock()); | |
1008 return wrapped_obj()->get_pv(pv); | |
1009 } | |
1010 | |
1011 STDMETHODIMP AppWrapper::put_pv(BSTR pv) { | |
1012 __mutexScope(model()->lock()); | |
1013 return wrapped_obj()->put_pv(pv); | |
1014 } | |
1015 | |
1016 STDMETHODIMP AppWrapper::get_language(BSTR* language) { | |
1017 __mutexScope(model()->lock()); | |
1018 return wrapped_obj()->get_language(language); | |
1019 } | |
1020 | |
1021 STDMETHODIMP AppWrapper::put_language(BSTR language) { | |
1022 __mutexScope(model()->lock()); | |
1023 return wrapped_obj()->put_language(language); | |
1024 } | |
1025 | |
1026 STDMETHODIMP AppWrapper::get_ap(BSTR* ap) { | |
1027 __mutexScope(model()->lock()); | |
1028 return wrapped_obj()->get_ap(ap); | |
1029 } | |
1030 | |
1031 STDMETHODIMP AppWrapper::put_ap(BSTR ap) { | |
1032 __mutexScope(model()->lock()); | |
1033 return wrapped_obj()->put_ap(ap); | |
1034 } | |
1035 | |
1036 STDMETHODIMP AppWrapper::get_ttToken(BSTR* tt_token) { | |
1037 __mutexScope(model()->lock()); | |
1038 return wrapped_obj()->get_ttToken(tt_token); | |
1039 } | |
1040 | |
1041 STDMETHODIMP AppWrapper::put_ttToken(BSTR tt_token) { | |
1042 __mutexScope(model()->lock()); | |
1043 return wrapped_obj()->put_ttToken(tt_token); | |
1044 } | |
1045 | |
1046 STDMETHODIMP AppWrapper::get_iid(BSTR* iid) { | |
1047 __mutexScope(model()->lock()); | |
1048 return wrapped_obj()->get_iid(iid); | |
1049 } | |
1050 | |
1051 STDMETHODIMP AppWrapper::put_iid(BSTR iid) { | |
1052 __mutexScope(model()->lock()); | |
1053 return wrapped_obj()->put_iid(iid); | |
1054 } | |
1055 | |
1056 STDMETHODIMP AppWrapper::get_brandCode(BSTR* brand_code) { | |
1057 __mutexScope(model()->lock()); | |
1058 return wrapped_obj()->get_brandCode(brand_code); | |
1059 } | |
1060 | |
1061 STDMETHODIMP AppWrapper::put_brandCode(BSTR brand_code) { | |
1062 __mutexScope(model()->lock()); | |
1063 return wrapped_obj()->put_brandCode(brand_code); | |
1064 } | |
1065 | |
1066 STDMETHODIMP AppWrapper::get_clientId(BSTR* client_id) { | |
1067 __mutexScope(model()->lock()); | |
1068 return wrapped_obj()->get_clientId(client_id); | |
1069 } | |
1070 | |
1071 STDMETHODIMP AppWrapper::put_clientId(BSTR client_id) { | |
1072 __mutexScope(model()->lock()); | |
1073 return wrapped_obj()->put_clientId(client_id); | |
1074 } | |
1075 | |
1076 STDMETHODIMP AppWrapper::get_labels(BSTR* labels) { | |
1077 __mutexScope(model()->lock()); | |
1078 return wrapped_obj()->get_labels(labels); | |
1079 } | |
1080 | |
1081 STDMETHODIMP AppWrapper::put_labels(BSTR labels) { | |
1082 __mutexScope(model()->lock()); | |
1083 return wrapped_obj()->put_labels(labels); | |
1084 } | |
1085 | |
1086 STDMETHODIMP AppWrapper::get_referralId(BSTR* referral_id) { | |
1087 __mutexScope(model()->lock()); | |
1088 return wrapped_obj()->get_referralId(referral_id); | |
1089 } | |
1090 | |
1091 STDMETHODIMP AppWrapper::put_referralId(BSTR referral_id) { | |
1092 __mutexScope(model()->lock()); | |
1093 return wrapped_obj()->put_referralId(referral_id); | |
1094 } | |
1095 | |
1096 STDMETHODIMP AppWrapper::get_installTimeDiffSec(UINT* install_time_diff_sec) { | |
1097 __mutexScope(model()->lock()); | |
1098 return wrapped_obj()->get_installTimeDiffSec(install_time_diff_sec); | |
1099 } | |
1100 | |
1101 STDMETHODIMP AppWrapper::get_isEulaAccepted(VARIANT_BOOL* is_eula_accepted) { | |
1102 __mutexScope(model()->lock()); | |
1103 return wrapped_obj()->get_isEulaAccepted(is_eula_accepted); | |
1104 } | |
1105 | |
1106 STDMETHODIMP AppWrapper::put_isEulaAccepted(VARIANT_BOOL is_eula_accepted) { | |
1107 __mutexScope(model()->lock()); | |
1108 return wrapped_obj()->put_isEulaAccepted(is_eula_accepted); | |
1109 } | |
1110 | |
1111 STDMETHODIMP AppWrapper::get_displayName(BSTR* display_name) { | |
1112 __mutexScope(model()->lock()); | |
1113 return wrapped_obj()->get_displayName(display_name); | |
1114 } | |
1115 | |
1116 STDMETHODIMP AppWrapper::put_displayName(BSTR display_name) { | |
1117 __mutexScope(model()->lock()); | |
1118 return wrapped_obj()->put_displayName(display_name); | |
1119 } | |
1120 | |
1121 STDMETHODIMP AppWrapper::get_browserType(UINT* browser_type) { | |
1122 __mutexScope(model()->lock()); | |
1123 return wrapped_obj()->get_browserType(browser_type); | |
1124 } | |
1125 | |
1126 STDMETHODIMP AppWrapper::put_browserType(UINT browser_type) { | |
1127 __mutexScope(model()->lock()); | |
1128 return wrapped_obj()->put_browserType(browser_type); | |
1129 } | |
1130 | |
1131 STDMETHODIMP AppWrapper::get_clientInstallData(BSTR* data) { | |
1132 __mutexScope(model()->lock()); | |
1133 return wrapped_obj()->get_clientInstallData(data); | |
1134 } | |
1135 | |
1136 STDMETHODIMP AppWrapper::put_clientInstallData(BSTR data) { | |
1137 __mutexScope(model()->lock()); | |
1138 return wrapped_obj()->put_clientInstallData(data); | |
1139 } | |
1140 | |
1141 STDMETHODIMP AppWrapper::get_serverInstallDataIndex(BSTR* index) { | |
1142 __mutexScope(model()->lock()); | |
1143 return wrapped_obj()->get_serverInstallDataIndex(index); | |
1144 } | |
1145 | |
1146 STDMETHODIMP AppWrapper::put_serverInstallDataIndex(BSTR index) { | |
1147 __mutexScope(model()->lock()); | |
1148 return wrapped_obj()->put_serverInstallDataIndex(index); | |
1149 } | |
1150 | |
1151 STDMETHODIMP AppWrapper::get_usageStatsEnable(UINT* usage_stats_enable) { | |
1152 __mutexScope(model()->lock()); | |
1153 return wrapped_obj()->get_usageStatsEnable(usage_stats_enable); | |
1154 } | |
1155 | |
1156 STDMETHODIMP AppWrapper::put_usageStatsEnable(UINT usage_stats_enable) { | |
1157 __mutexScope(model()->lock()); | |
1158 return wrapped_obj()->put_usageStatsEnable(usage_stats_enable); | |
1159 } | |
1160 | |
1161 STDMETHODIMP AppWrapper::get_currentState(IDispatch** current_state_disp) { | |
1162 __mutexScope(model()->lock()); | |
1163 return wrapped_obj()->get_currentState(current_state_disp); | |
1164 } | |
1165 | |
1166 | |
1167 // Sets app's app_state to state. Used by unit tests to set up the state to the | |
1168 // correct precondition for the test case. App friends this function, allowing | |
1169 // it to call the private member function. | |
1170 void SetAppStateForUnitTest(App* app, fsm::AppState* state) { | |
1171 ASSERT1(app); | |
1172 ASSERT1(state); | |
1173 __mutexScope(app->model()->lock()); | |
1174 app->ChangeState(state); | |
1175 } | |
1176 | |
1177 } // namespace omaha | |
OLD | NEW |