| 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_bundle.h" | |
| 17 #include <atlsafe.h> | |
| 18 #include "omaha/base/debug.h" | |
| 19 #include "omaha/base/error.h" | |
| 20 #include "omaha/base/logging.h" | |
| 21 #include "omaha/base/scoped_impersonation.h" | |
| 22 #include "omaha/base/user_rights.h" | |
| 23 #include "omaha/base/utils.h" | |
| 24 #include "omaha/common/config_manager.h" | |
| 25 #include "omaha/common/lang.h" | |
| 26 #include "omaha/common/ping.h" | |
| 27 #include "omaha/common/update_request.h" | |
| 28 #include "omaha/common/update_response.h" | |
| 29 #include "omaha/common/web_services_client.h" | |
| 30 #include "omaha/goopdate/app_bundle_state_init.h" | |
| 31 #include "omaha/goopdate/app_manager.h" | |
| 32 #include "omaha/goopdate/model.h" | |
| 33 #include "omaha/goopdate/update_request_utils.h" | |
| 34 | |
| 35 namespace omaha { | |
| 36 | |
| 37 namespace { | |
| 38 | |
| 39 const TCHAR* const kDefaultInstallSource = _T("unknown"); | |
| 40 | |
| 41 } // namespace | |
| 42 | |
| 43 AppBundle::AppBundle(bool is_machine, Model* model) | |
| 44 : ModelObject(model), | |
| 45 install_source_(kDefaultInstallSource), | |
| 46 is_machine_(is_machine), | |
| 47 is_auto_update_(false), | |
| 48 priority_(INSTALL_PRIORITY_HIGH), | |
| 49 parent_hwnd_(NULL), | |
| 50 user_work_item_(NULL), | |
| 51 display_language_(lang::GetDefaultLanguage(is_machine)) { | |
| 52 CORE_LOG(L3, (_T("[AppBundle::AppBundle][0x%p]"), this)); | |
| 53 app_bundle_state_.reset(new fsm::AppBundleStateInit); | |
| 54 } | |
| 55 | |
| 56 AppBundle::~AppBundle() { | |
| 57 CORE_LOG(L3, (_T("[AppBundle::~AppBundle][0x%p]"), this)); | |
| 58 | |
| 59 // Destruction of this object is not serialized. The lifetime of AppBundle | |
| 60 // objects is controlled by the client and multiple objects can destruct at | |
| 61 // the same time. | |
| 62 ASSERT1(!model()->IsLockedByCaller()); | |
| 63 | |
| 64 HRESULT hr = SendPingEvents(); | |
| 65 CORE_LOG(L3, (_T("[SendPingEvents returned 0x%x]"), hr)); | |
| 66 | |
| 67 __mutexScope(model()->lock()); | |
| 68 for (size_t i = 0; i < apps_.size(); ++i) { | |
| 69 delete apps_[i]; | |
| 70 } | |
| 71 | |
| 72 // If the thread running this AppBundle does not exit before the | |
| 73 // NetworkConfigManager::DeleteInstance() happens in GoopdateImpl::Main, the | |
| 74 // update_check_client_ destructor will crash. Resetting here explicitly. | |
| 75 update_check_client_.reset(); | |
| 76 | |
| 77 // Garbage-collect everything that has expired, including this object. | |
| 78 // The model holds weak references to AppBundle objects. Those weak | |
| 79 // references expire before the destructor for the object runs. Therefore, it | |
| 80 // is not possible to associate this object with any of the weak references | |
| 81 // in the model. Those weak references must be garbage collected. | |
| 82 model()->CleanupExpiredAppBundles(); | |
| 83 } | |
| 84 | |
| 85 ControllingPtr AppBundle::controlling_ptr() { | |
| 86 __mutexScope(model()->lock()); | |
| 87 return shared_from_this(); | |
| 88 } | |
| 89 | |
| 90 bool AppBundle::is_pending_non_blocking_call() const { | |
| 91 __mutexScope(model()->lock()); | |
| 92 return user_work_item_ != NULL; | |
| 93 } | |
| 94 | |
| 95 void AppBundle::set_user_work_item(UserWorkItem* user_work_item) { | |
| 96 ASSERT(user_work_item, (_T("Use CompleteAsyncCall() instead."))); | |
| 97 __mutexScope(model()->lock()); | |
| 98 | |
| 99 user_work_item_ = user_work_item; | |
| 100 } | |
| 101 | |
| 102 HANDLE AppBundle::impersonation_token() const { | |
| 103 __mutexScope(model()->lock()); | |
| 104 return alt_impersonation_token_.GetHandle() ? | |
| 105 alt_impersonation_token_.GetHandle() : | |
| 106 impersonation_token_.GetHandle(); | |
| 107 } | |
| 108 | |
| 109 HANDLE AppBundle::primary_token() const { | |
| 110 __mutexScope(model()->lock()); | |
| 111 return alt_primary_token_.GetHandle() ? alt_primary_token_.GetHandle() : | |
| 112 primary_token_.GetHandle(); | |
| 113 } | |
| 114 | |
| 115 HRESULT AppBundle::CaptureCallerImpersonationToken() { | |
| 116 __mutexScope(model()->lock()); | |
| 117 | |
| 118 if (!is_machine_) { | |
| 119 return S_OK; | |
| 120 } | |
| 121 | |
| 122 if (impersonation_token_.GetHandle()) { | |
| 123 ::CloseHandle(impersonation_token_.Detach()); | |
| 124 } | |
| 125 | |
| 126 HRESULT hr = UserRights::GetCallerToken(&impersonation_token_); | |
| 127 if (FAILED(hr)) { | |
| 128 CORE_LOG(LE, (_T("[CaptureCallerImpersonationToken failed][0x%x]"), hr)); | |
| 129 return hr; | |
| 130 } | |
| 131 | |
| 132 return S_OK; | |
| 133 } | |
| 134 | |
| 135 HRESULT AppBundle::CaptureCallerPrimaryToken() { | |
| 136 __mutexScope(model()->lock()); | |
| 137 | |
| 138 if (!is_machine_) { | |
| 139 return S_OK; | |
| 140 } | |
| 141 | |
| 142 ASSERT1(impersonation_token_.GetHandle()); | |
| 143 if (!UserRights::TokenIsAdmin(impersonation_token_.GetHandle())) { | |
| 144 ASSERT1(false); | |
| 145 return E_UNEXPECTED; | |
| 146 } | |
| 147 | |
| 148 if (primary_token_.GetHandle()) { | |
| 149 ::CloseHandle(primary_token_.Detach()); | |
| 150 } | |
| 151 | |
| 152 if (!impersonation_token_.CreatePrimaryToken(&primary_token_)) { | |
| 153 HRESULT hr = HRESULTFromLastError(); | |
| 154 CORE_LOG(LE, (_T("[CreatePrimaryToken failed][0x%x]"), hr)); | |
| 155 return hr; | |
| 156 } | |
| 157 | |
| 158 return S_OK; | |
| 159 } | |
| 160 | |
| 161 size_t AppBundle::GetNumberOfApps() const { | |
| 162 __mutexScope(model()->lock()); | |
| 163 return apps_.size(); | |
| 164 } | |
| 165 | |
| 166 App* AppBundle::GetApp(size_t index) { | |
| 167 __mutexScope(model()->lock()); | |
| 168 | |
| 169 if (index >= GetNumberOfApps()) { | |
| 170 ASSERT1(false); | |
| 171 return NULL; | |
| 172 } | |
| 173 | |
| 174 App* app = apps_[index]; | |
| 175 ASSERT1(app); | |
| 176 return app; | |
| 177 } | |
| 178 | |
| 179 CString AppBundle::FetchAndResetLogText() { | |
| 180 __mutexScope(model()->lock()); | |
| 181 | |
| 182 CString event_log_text; | |
| 183 for (size_t i = 0; i < apps_.size(); ++i) { | |
| 184 event_log_text += apps_[i]->FetchAndResetLogText(); | |
| 185 } | |
| 186 | |
| 187 return event_log_text; | |
| 188 } | |
| 189 | |
| 190 HRESULT AppBundle::SendPingEvents() { | |
| 191 CORE_LOG(L3, (_T("[AppBundle::SendPingEvents]"))); | |
| 192 | |
| 193 scoped_impersonation impersonate_user(impersonation_token()); | |
| 194 | |
| 195 if (!ConfigManager::Instance()->CanUseNetwork(is_machine_)) { | |
| 196 CORE_LOG(L1, (_T("[Ping not sent because network use prohibited]"))); | |
| 197 return S_OK; | |
| 198 } | |
| 199 | |
| 200 Ping ping(is_machine_, session_id_, install_source_); | |
| 201 | |
| 202 __mutexBlock(model()->lock()) { | |
| 203 for (size_t i = 0; i != apps_.size(); ++i) { | |
| 204 if (apps_[i]->is_eula_accepted()) { | |
| 205 ping.BuildRequest(apps_[i], false); | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 for (size_t i = 0; i != uninstalled_apps_.size(); ++i) { | |
| 210 if (uninstalled_apps_[i]->is_eula_accepted()) { | |
| 211 ping.BuildRequest(uninstalled_apps_[i], false); | |
| 212 } | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 CORE_LOG(L3, (_T("[AppBundle::SendPingEvents][sending ping events]") | |
| 217 _T("[%d uninstalled apps]"), uninstalled_apps_.size())); | |
| 218 | |
| 219 // TODO(Omaha): Add sample to metric_ping_succeeded_ms or | |
| 220 // metric_ping_failed_ms based on the result of Send(). | |
| 221 return ping.Send(false); | |
| 222 } | |
| 223 | |
| 224 // IAppBundle. | |
| 225 STDMETHODIMP AppBundle::get_displayName(BSTR* display_name) { | |
| 226 ASSERT1(display_name); | |
| 227 __mutexScope(model()->lock()); | |
| 228 *display_name = display_name_.AllocSysString(); | |
| 229 return S_OK; | |
| 230 } | |
| 231 | |
| 232 STDMETHODIMP AppBundle::put_displayName(BSTR display_name) { | |
| 233 __mutexScope(model()->lock()); | |
| 234 display_name_ = display_name; | |
| 235 return S_OK; | |
| 236 } | |
| 237 | |
| 238 STDMETHODIMP AppBundle::get_installSource(BSTR* install_source) { | |
| 239 ASSERT1(install_source); | |
| 240 __mutexScope(model()->lock()); | |
| 241 *install_source = install_source_.AllocSysString(); | |
| 242 return S_OK; | |
| 243 } | |
| 244 | |
| 245 STDMETHODIMP AppBundle::put_installSource(BSTR install_source) { | |
| 246 __mutexScope(model()->lock()); | |
| 247 install_source_ = install_source; | |
| 248 return S_OK; | |
| 249 } | |
| 250 | |
| 251 STDMETHODIMP AppBundle::get_originURL(BSTR* origin_url) { | |
| 252 ASSERT1(origin_url); | |
| 253 __mutexScope(model()->lock()); | |
| 254 *origin_url = origin_url_.AllocSysString(); | |
| 255 return S_OK; | |
| 256 } | |
| 257 | |
| 258 STDMETHODIMP AppBundle::put_originURL(BSTR origin_url) { | |
| 259 __mutexScope(model()->lock()); | |
| 260 origin_url_ = origin_url; | |
| 261 return S_OK; | |
| 262 } | |
| 263 | |
| 264 STDMETHODIMP AppBundle::get_offlineDirectory(BSTR* offline_dir) { | |
| 265 ASSERT1(offline_dir); | |
| 266 __mutexScope(model()->lock()); | |
| 267 *offline_dir = offline_dir_.AllocSysString(); | |
| 268 return S_OK; | |
| 269 } | |
| 270 | |
| 271 STDMETHODIMP AppBundle::put_offlineDirectory(BSTR offline_dir) { | |
| 272 CORE_LOG(L3, (_T("[AppBundle::put_offlineDirectory][%s]"), offline_dir)); | |
| 273 __mutexScope(model()->lock()); | |
| 274 offline_dir_ = offline_dir; | |
| 275 return S_OK; | |
| 276 } | |
| 277 | |
| 278 STDMETHODIMP AppBundle::get_sessionId(BSTR* session_id) { | |
| 279 ASSERT1(session_id); | |
| 280 __mutexScope(model()->lock()); | |
| 281 *session_id = session_id_.AllocSysString(); | |
| 282 return S_OK; | |
| 283 } | |
| 284 | |
| 285 STDMETHODIMP AppBundle::put_sessionId(BSTR session_id) { | |
| 286 CORE_LOG(L3, (_T("[AppBundle::put_sessionId][%s]"), session_id)); | |
| 287 __mutexScope(model()->lock()); | |
| 288 return app_bundle_state_->put_sessionId(this, session_id); | |
| 289 } | |
| 290 | |
| 291 STDMETHODIMP AppBundle::get_priority(long* priority) { // NOLINT | |
| 292 ASSERT1(priority); | |
| 293 __mutexScope(model()->lock()); | |
| 294 *priority = priority_; | |
| 295 return S_OK; | |
| 296 } | |
| 297 | |
| 298 STDMETHODIMP AppBundle::put_priority(long priority) { // NOLINT | |
| 299 if ((priority < INSTALL_PRIORITY_LOW) || (priority > INSTALL_PRIORITY_HIGH)) { | |
| 300 return E_INVALIDARG; | |
| 301 } | |
| 302 __mutexScope(model()->lock()); | |
| 303 priority_ = priority; | |
| 304 return S_OK; | |
| 305 } | |
| 306 | |
| 307 STDMETHODIMP AppBundle::put_altTokens(ULONG_PTR impersonation_token, | |
| 308 ULONG_PTR primary_token, | |
| 309 DWORD caller_proc_id) { | |
| 310 ASSERT1(impersonation_token); | |
| 311 ASSERT1(primary_token); | |
| 312 ASSERT1(caller_proc_id); | |
| 313 __mutexScope(model()->lock()); | |
| 314 | |
| 315 return app_bundle_state_->put_altTokens(this, | |
| 316 impersonation_token, | |
| 317 primary_token, | |
| 318 caller_proc_id); | |
| 319 } | |
| 320 | |
| 321 STDMETHODIMP AppBundle::put_parentHWND(ULONG_PTR hwnd) { | |
| 322 CORE_LOG(L3, (_T("[AppBundle::put_parentHWND][0x%x]"), hwnd)); | |
| 323 | |
| 324 __mutexScope(model()->lock()); | |
| 325 parent_hwnd_ = reinterpret_cast<HWND>(hwnd); | |
| 326 update_check_client_->set_proxy_auth_config(GetProxyAuthConfig()); | |
| 327 return S_OK; | |
| 328 } | |
| 329 | |
| 330 CString AppBundle::display_language() const { | |
| 331 __mutexScope(model()->lock()); | |
| 332 return display_language_; | |
| 333 } | |
| 334 | |
| 335 STDMETHODIMP AppBundle::get_displayLanguage(BSTR* language) { | |
| 336 ASSERT1(language); | |
| 337 __mutexScope(model()->lock()); | |
| 338 *language = display_language_.AllocSysString(); | |
| 339 return S_OK; | |
| 340 } | |
| 341 | |
| 342 STDMETHODIMP AppBundle::put_displayLanguage(BSTR language) { | |
| 343 __mutexScope(model()->lock()); | |
| 344 if (::SysStringLen(language) == 0) { | |
| 345 return E_INVALIDARG; | |
| 346 } | |
| 347 | |
| 348 if (!lang::IsLanguageSupported(language)) { | |
| 349 return E_INVALIDARG; | |
| 350 } | |
| 351 | |
| 352 display_language_ = language; | |
| 353 return S_OK; | |
| 354 } | |
| 355 | |
| 356 bool AppBundle::is_machine() const { | |
| 357 __mutexScope(model()->lock()); | |
| 358 return is_machine_; | |
| 359 } | |
| 360 | |
| 361 bool AppBundle::is_auto_update() const { | |
| 362 __mutexScope(model()->lock()); | |
| 363 return is_auto_update_; | |
| 364 } | |
| 365 | |
| 366 void AppBundle::set_is_auto_update(bool is_auto_update) { | |
| 367 __mutexScope(model()->lock()); | |
| 368 is_auto_update_ = is_auto_update; | |
| 369 } | |
| 370 | |
| 371 bool AppBundle::is_offline_install() const { | |
| 372 __mutexScope(model()->lock()); | |
| 373 return !offline_dir_.IsEmpty(); | |
| 374 } | |
| 375 | |
| 376 const CString& AppBundle::offline_dir() const { | |
| 377 __mutexScope(model()->lock()); | |
| 378 return offline_dir_; | |
| 379 } | |
| 380 | |
| 381 const CString& AppBundle::session_id() const { | |
| 382 __mutexScope(model()->lock()); | |
| 383 return session_id_; | |
| 384 } | |
| 385 | |
| 386 int AppBundle::priority() const { | |
| 387 __mutexScope(model()->lock()); | |
| 388 return priority_; | |
| 389 } | |
| 390 | |
| 391 ProxyAuthConfig AppBundle::GetProxyAuthConfig() const { | |
| 392 __mutexScope(model()->lock()); | |
| 393 return ProxyAuthConfig(parent_hwnd_, display_name_); | |
| 394 } | |
| 395 | |
| 396 STDMETHODIMP AppBundle::initialize() { | |
| 397 __mutexScope(model()->lock()); | |
| 398 | |
| 399 // Ensure that clients that run as Local System were designed with alt tokens | |
| 400 // in mind. The alt tokens might not always be a different user, but at least | |
| 401 // the client considered the need to set the alt tokens. | |
| 402 // TODO(omaha): The /ua process should not need to call put_altTokens() | |
| 403 // when there is no logged in user. This may be causing issues on Windows 7. | |
| 404 bool alt_tokens_set(alt_impersonation_token_.GetHandle() && | |
| 405 alt_primary_token_.GetHandle()); | |
| 406 ASSERT1(!is_machine_ || | |
| 407 alt_tokens_set || | |
| 408 !UserRights::VerifyCallerIsSystem()); | |
| 409 | |
| 410 return app_bundle_state_->Initialize(this); | |
| 411 } | |
| 412 | |
| 413 // App is created with is_update=false because the caller is not using | |
| 414 // information about any installed app. It is either a new or over-install. | |
| 415 STDMETHODIMP AppBundle::createApp(BSTR app_id, App** app) { | |
| 416 CORE_LOG(L1, (_T("[AppBundle::createApp][%s][0x%p]"), app_id, this)); | |
| 417 ASSERT1(app_id); | |
| 418 ASSERT1(app); | |
| 419 | |
| 420 __mutexScope(model()->lock()); | |
| 421 | |
| 422 scoped_impersonation impersonate_user(impersonation_token()); | |
| 423 HRESULT hr = impersonate_user.result(); | |
| 424 if (FAILED(hr)) { | |
| 425 CORE_LOG(LE, (_T("[Impersonation failed][0x%08x]"), hr)); | |
| 426 return hr; | |
| 427 } | |
| 428 | |
| 429 return app_bundle_state_->CreateApp(this, app_id, app); | |
| 430 } | |
| 431 | |
| 432 STDMETHODIMP AppBundle::createInstalledApp(BSTR app_id, App** app) { | |
| 433 CORE_LOG(L1, (_T("[AppBundle::createInstalledApp][%s][0x%p]"), app_id, this)); | |
| 434 ASSERT1(app); | |
| 435 | |
| 436 __mutexScope(model()->lock()); | |
| 437 | |
| 438 | |
| 439 scoped_impersonation impersonate_user(impersonation_token()); | |
| 440 HRESULT hr = impersonate_user.result(); | |
| 441 if (FAILED(hr)) { | |
| 442 CORE_LOG(LE, (_T("[Impersonation failed][0x%08x]"), hr)); | |
| 443 return hr; | |
| 444 } | |
| 445 | |
| 446 return app_bundle_state_->CreateInstalledApp(this, app_id, app); | |
| 447 } | |
| 448 | |
| 449 STDMETHODIMP AppBundle::createAllInstalledApps() { | |
| 450 CORE_LOG(L1, (_T("[AppBundle::createAllInstalledApps][0x%p]"), this)); | |
| 451 | |
| 452 __mutexScope(model()->lock()); | |
| 453 | |
| 454 scoped_impersonation impersonate_user(impersonation_token()); | |
| 455 HRESULT hr = impersonate_user.result(); | |
| 456 if (FAILED(hr)) { | |
| 457 CORE_LOG(LE, (_T("[Impersonation failed][0x%08x]"), hr)); | |
| 458 return hr; | |
| 459 } | |
| 460 | |
| 461 return app_bundle_state_->CreateAllInstalledApps(this); | |
| 462 } | |
| 463 | |
| 464 STDMETHODIMP AppBundle::get_Count(long* count) { // NOLINT | |
| 465 ASSERT1(count); | |
| 466 | |
| 467 __mutexScope(model()->lock()); | |
| 468 | |
| 469 *count = apps_.size(); | |
| 470 | |
| 471 return S_OK; | |
| 472 } | |
| 473 | |
| 474 STDMETHODIMP AppBundle::get_Item(long index, App** app) { // NOLINT | |
| 475 ASSERT1(app); | |
| 476 | |
| 477 __mutexScope(model()->lock()); | |
| 478 | |
| 479 if (index < 0 || static_cast<size_t>(index) >= apps_.size()) { | |
| 480 return HRESULT_FROM_WIN32(ERROR_INVALID_INDEX); | |
| 481 } | |
| 482 | |
| 483 *app = apps_[index]; | |
| 484 return S_OK; | |
| 485 } | |
| 486 | |
| 487 WebServicesClientInterface* AppBundle::update_check_client() { | |
| 488 __mutexScope(model()->lock()); | |
| 489 ASSERT1(update_check_client_.get()); | |
| 490 return update_check_client_.get(); | |
| 491 } | |
| 492 | |
| 493 STDMETHODIMP AppBundle::checkForUpdate() { | |
| 494 CORE_LOG(L1, (_T("[AppBundle::checkForUpdate][0x%p]"), this)); | |
| 495 | |
| 496 __mutexScope(model()->lock()); | |
| 497 | |
| 498 scoped_impersonation impersonate_user(impersonation_token()); | |
| 499 HRESULT hr = impersonate_user.result(); | |
| 500 if (FAILED(hr)) { | |
| 501 CORE_LOG(LE, (_T("[Impersonation failed][0x%08x]"), hr)); | |
| 502 return hr; | |
| 503 } | |
| 504 | |
| 505 return app_bundle_state_->CheckForUpdate(this); | |
| 506 } | |
| 507 | |
| 508 STDMETHODIMP AppBundle::download() { | |
| 509 CORE_LOG(L1, (_T("[AppBundle::download][0x%p]"), this)); | |
| 510 | |
| 511 __mutexScope(model()->lock()); | |
| 512 | |
| 513 scoped_impersonation impersonate_user(impersonation_token()); | |
| 514 HRESULT hr = impersonate_user.result(); | |
| 515 if (FAILED(hr)) { | |
| 516 CORE_LOG(LE, (_T("[Impersonation failed][0x%08x]"), hr)); | |
| 517 return hr; | |
| 518 } | |
| 519 | |
| 520 return app_bundle_state_->Download(this); | |
| 521 } | |
| 522 | |
| 523 // Captures the primary token since it is the only function that needs it, and | |
| 524 // to prevent any scenarios where one user sets up a bundle and another installs | |
| 525 // the app(s) with the other user's credentials. | |
| 526 STDMETHODIMP AppBundle::install() { | |
| 527 CORE_LOG(L1, (_T("[AppBundle::install][0x%p]"), this)); | |
| 528 | |
| 529 __mutexScope(model()->lock()); | |
| 530 | |
| 531 HRESULT hr = CaptureCallerPrimaryToken(); | |
| 532 if (FAILED(hr)) { | |
| 533 return hr; | |
| 534 } | |
| 535 | |
| 536 scoped_impersonation impersonate_user(impersonation_token()); | |
| 537 hr = impersonate_user.result(); | |
| 538 if (FAILED(hr)) { | |
| 539 CORE_LOG(LE, (_T("[Impersonation failed][0x%08x]"), hr)); | |
| 540 return hr; | |
| 541 } | |
| 542 | |
| 543 return app_bundle_state_->Install(this); | |
| 544 } | |
| 545 | |
| 546 STDMETHODIMP AppBundle::updateAllApps() { | |
| 547 CORE_LOG(L1, (_T("[AppBundle::updateAllApps][0x%p]"), this)); | |
| 548 | |
| 549 __mutexScope(model()->lock()); | |
| 550 | |
| 551 scoped_impersonation impersonate_user(impersonation_token()); | |
| 552 HRESULT hr = impersonate_user.result(); | |
| 553 if (FAILED(hr)) { | |
| 554 CORE_LOG(LE, (_T("[Impersonation failed][0x%08x]"), hr)); | |
| 555 return hr; | |
| 556 } | |
| 557 | |
| 558 return app_bundle_state_->UpdateAllApps(this); | |
| 559 } | |
| 560 | |
| 561 STDMETHODIMP AppBundle::stop() { | |
| 562 CORE_LOG(L1, (_T("[AppBundle::stop][0x%p]"), this)); | |
| 563 | |
| 564 __mutexScope(model()->lock()); | |
| 565 | |
| 566 return app_bundle_state_->Stop(this); | |
| 567 } | |
| 568 | |
| 569 STDMETHODIMP AppBundle::pause() { | |
| 570 CORE_LOG(L1, (_T("[AppBundle::pause][0x%p]"), this)); | |
| 571 | |
| 572 __mutexScope(model()->lock()); | |
| 573 | |
| 574 return app_bundle_state_->Pause(this); | |
| 575 } | |
| 576 | |
| 577 STDMETHODIMP AppBundle::resume() { | |
| 578 CORE_LOG(L1, (_T("[AppBundle::resume][0x%p]"), this)); | |
| 579 | |
| 580 __mutexScope(model()->lock()); | |
| 581 | |
| 582 return app_bundle_state_->Resume(this); | |
| 583 } | |
| 584 | |
| 585 STDMETHODIMP AppBundle::isBusy(VARIANT_BOOL* is_busy) { | |
| 586 CORE_LOG(L3, (_T("[AppBundle::isBusy][0x%p]"), this)); | |
| 587 ASSERT1(is_busy); | |
| 588 | |
| 589 __mutexScope(model()->lock()); | |
| 590 | |
| 591 *is_busy = IsBusy() ? VARIANT_TRUE : VARIANT_FALSE; | |
| 592 return S_OK; | |
| 593 } | |
| 594 | |
| 595 STDMETHODIMP AppBundle::downloadPackage(BSTR app_id, BSTR package_name) { | |
| 596 CORE_LOG(L1, (_T("[AppBundle::downloadPackage][%s][%s]"), | |
| 597 app_id, package_name)); | |
| 598 | |
| 599 __mutexScope(model()->lock()); | |
| 600 | |
| 601 scoped_impersonation impersonate_user(impersonation_token()); | |
| 602 HRESULT hr = impersonate_user.result(); | |
| 603 if (FAILED(hr)) { | |
| 604 CORE_LOG(LE, (_T("[Impersonation failed][0x%08x]"), hr)); | |
| 605 return hr; | |
| 606 } | |
| 607 | |
| 608 return app_bundle_state_->DownloadPackage(this, app_id, package_name); | |
| 609 } | |
| 610 | |
| 611 // TODO(omaha3): May need to provide aggregate status. See TODO in IDL file. | |
| 612 STDMETHODIMP AppBundle::get_currentState(VARIANT* current_state) { | |
| 613 CORE_LOG(L3, (_T("[AppBundle::get_currentState][0x%p]"), this)); | |
| 614 ASSERT1(current_state); | |
| 615 UNREFERENCED_PARAMETER(current_state); | |
| 616 ASSERT(false, (_T("Not implemented. Should not call at this time."))); | |
| 617 return E_NOTIMPL; | |
| 618 } | |
| 619 | |
| 620 // This function is only called internal to the COM server and affects a | |
| 621 // separate vector of Apps, so it can be called in any state. | |
| 622 // It assumes all calls have a unique app_id. | |
| 623 HRESULT AppBundle::CreateUninstalledApp(const CString& app_id, App** app) { | |
| 624 CORE_LOG(L1, (_T("[AppBundle::CreateUninstalledApp][%s][0x%p]"), | |
| 625 app_id, this)); | |
| 626 ASSERT1(app); | |
| 627 | |
| 628 __mutexScope(model()->lock()); | |
| 629 | |
| 630 GUID app_guid = {0}; | |
| 631 HRESULT hr = StringToGuidSafe(app_id, &app_guid); | |
| 632 if (FAILED(hr)) { | |
| 633 CORE_LOG(LE, (_T("[invalid app id][%s]"), app_id)); | |
| 634 return hr; | |
| 635 } | |
| 636 | |
| 637 scoped_ptr<App> local_app(new App(app_guid, true, this)); | |
| 638 | |
| 639 hr = AppManager::Instance()->ReadUninstalledAppPersistentData( | |
| 640 local_app.get()); | |
| 641 if (FAILED(hr)) { | |
| 642 CORE_LOG(LE, (_T("[ReadUninstalledAppPersistentData failed][0x%x][%s]"), | |
| 643 hr, app_id)); | |
| 644 return hr; | |
| 645 } | |
| 646 | |
| 647 uninstalled_apps_.push_back(local_app.get()); | |
| 648 | |
| 649 *app = local_app.release(); | |
| 650 return S_OK; | |
| 651 } | |
| 652 | |
| 653 void AppBundle::CompleteAsyncCall() { | |
| 654 __mutexScope(model()->lock()); | |
| 655 | |
| 656 ASSERT1(is_pending_non_blocking_call()); | |
| 657 | |
| 658 VERIFY1(SUCCEEDED(app_bundle_state_->CompleteAsyncCall(this))); | |
| 659 | |
| 660 user_work_item_ = NULL; | |
| 661 } | |
| 662 | |
| 663 bool AppBundle::IsBusy() const { | |
| 664 __mutexScope(model()->lock()); | |
| 665 const bool is_busy = app_bundle_state_->IsBusy(); | |
| 666 CORE_LOG(L3, (_T("[AppBundle::isBusy returned][0x%p][%u]"), this, is_busy)); | |
| 667 return is_busy; | |
| 668 } | |
| 669 | |
| 670 void AppBundle::ChangeState(fsm::AppBundleState* app_bundle_state) { | |
| 671 ASSERT1(app_bundle_state); | |
| 672 ASSERT1(model()->IsLockedByCaller()); | |
| 673 | |
| 674 app_bundle_state_.reset(app_bundle_state); | |
| 675 } | |
| 676 | |
| 677 | |
| 678 // | |
| 679 // AppBundleWrapper implementation. | |
| 680 // | |
| 681 | |
| 682 AppBundleWrapper::AppBundleWrapper() { | |
| 683 CORE_LOG(L3, (_T("[AppBundleWrapper::AppBundleWrapper][0x%p]"), this)); | |
| 684 } | |
| 685 | |
| 686 AppBundleWrapper::~AppBundleWrapper() { | |
| 687 CORE_LOG(L3, (_T("[AppBundleWrapper::~AppBundleWrapper][0x%p]"), this)); | |
| 688 } | |
| 689 | |
| 690 // | |
| 691 // IAppBundle. | |
| 692 // | |
| 693 | |
| 694 STDMETHODIMP AppBundleWrapper::get_displayName(BSTR* display_name) { | |
| 695 __mutexScope(model()->lock()); | |
| 696 return wrapped_obj()->get_displayName(display_name); | |
| 697 } | |
| 698 | |
| 699 STDMETHODIMP AppBundleWrapper::put_displayName(BSTR display_name) { | |
| 700 __mutexScope(model()->lock()); | |
| 701 return wrapped_obj()->put_displayName(display_name); | |
| 702 } | |
| 703 | |
| 704 STDMETHODIMP AppBundleWrapper::get_installSource(BSTR* install_source) { | |
| 705 __mutexScope(model()->lock()); | |
| 706 return wrapped_obj()->get_installSource(install_source); | |
| 707 } | |
| 708 | |
| 709 STDMETHODIMP AppBundleWrapper::put_installSource(BSTR install_source) { | |
| 710 __mutexScope(model()->lock()); | |
| 711 return wrapped_obj()->put_installSource(install_source); | |
| 712 } | |
| 713 | |
| 714 STDMETHODIMP AppBundleWrapper::get_originURL(BSTR* origin_url) { | |
| 715 __mutexScope(model()->lock()); | |
| 716 return wrapped_obj()->get_originURL(origin_url); | |
| 717 } | |
| 718 | |
| 719 STDMETHODIMP AppBundleWrapper::put_originURL(BSTR origin_url) { | |
| 720 __mutexScope(model()->lock()); | |
| 721 return wrapped_obj()->put_originURL(origin_url); | |
| 722 } | |
| 723 | |
| 724 STDMETHODIMP AppBundleWrapper::get_offlineDirectory(BSTR* offline_dir) { | |
| 725 __mutexScope(model()->lock()); | |
| 726 return wrapped_obj()->get_offlineDirectory(offline_dir); | |
| 727 } | |
| 728 | |
| 729 STDMETHODIMP AppBundleWrapper::put_offlineDirectory(BSTR offline_dir) { | |
| 730 __mutexScope(model()->lock()); | |
| 731 return wrapped_obj()->put_offlineDirectory(offline_dir); | |
| 732 } | |
| 733 | |
| 734 STDMETHODIMP AppBundleWrapper::get_sessionId(BSTR* session_id) { | |
| 735 __mutexScope(model()->lock()); | |
| 736 return wrapped_obj()->get_sessionId(session_id); | |
| 737 } | |
| 738 | |
| 739 STDMETHODIMP AppBundleWrapper::put_sessionId(BSTR session_id) { | |
| 740 __mutexScope(model()->lock()); | |
| 741 return wrapped_obj()->put_sessionId(session_id); | |
| 742 } | |
| 743 | |
| 744 STDMETHODIMP AppBundleWrapper::get_priority(long* priority) { // NOLINT | |
| 745 __mutexScope(model()->lock()); | |
| 746 return wrapped_obj()->get_priority(priority); | |
| 747 } | |
| 748 | |
| 749 STDMETHODIMP AppBundleWrapper::put_priority(long priority) { // NOLINT | |
| 750 __mutexScope(model()->lock()); | |
| 751 return wrapped_obj()->put_priority(priority); | |
| 752 } | |
| 753 | |
| 754 STDMETHODIMP AppBundleWrapper::put_altTokens(ULONG_PTR impersonation_token, | |
| 755 ULONG_PTR primary_token, | |
| 756 DWORD caller_proc_id) { | |
| 757 __mutexScope(model()->lock()); | |
| 758 return wrapped_obj()->put_altTokens(impersonation_token, | |
| 759 primary_token, | |
| 760 caller_proc_id); | |
| 761 } | |
| 762 | |
| 763 STDMETHODIMP AppBundleWrapper::put_parentHWND(ULONG_PTR hwnd) { | |
| 764 __mutexScope(model()->lock()); | |
| 765 return wrapped_obj()->put_parentHWND(hwnd); | |
| 766 } | |
| 767 | |
| 768 STDMETHODIMP AppBundleWrapper::get_displayLanguage(BSTR* language) { | |
| 769 __mutexScope(model()->lock()); | |
| 770 return wrapped_obj()->get_displayLanguage(language); | |
| 771 } | |
| 772 STDMETHODIMP AppBundleWrapper::put_displayLanguage(BSTR language) { | |
| 773 __mutexScope(model()->lock()); | |
| 774 return wrapped_obj()->put_displayLanguage(language); | |
| 775 } | |
| 776 | |
| 777 STDMETHODIMP AppBundleWrapper::initialize() { | |
| 778 __mutexScope(model()->lock()); | |
| 779 return wrapped_obj()->initialize(); | |
| 780 } | |
| 781 | |
| 782 STDMETHODIMP AppBundleWrapper::createApp(BSTR app_id, IDispatch** app_disp) { | |
| 783 __mutexScope(model()->lock()); | |
| 784 | |
| 785 App* app = NULL; | |
| 786 HRESULT hr = wrapped_obj()->createApp(app_id, &app); | |
| 787 if (FAILED(hr)) { | |
| 788 return hr; | |
| 789 } | |
| 790 | |
| 791 return AppWrapper::Create(controlling_ptr(), app, app_disp); | |
| 792 } | |
| 793 | |
| 794 STDMETHODIMP AppBundleWrapper::createInstalledApp(BSTR appId, | |
| 795 IDispatch** app_disp) { | |
| 796 __mutexScope(model()->lock()); | |
| 797 | |
| 798 App* app = NULL; | |
| 799 HRESULT hr = wrapped_obj()->createInstalledApp(appId, &app); | |
| 800 if (FAILED(hr)) { | |
| 801 return hr; | |
| 802 } | |
| 803 | |
| 804 return AppWrapper::Create(controlling_ptr(), app, app_disp); | |
| 805 } | |
| 806 | |
| 807 STDMETHODIMP AppBundleWrapper::createAllInstalledApps() { | |
| 808 __mutexScope(model()->lock()); | |
| 809 return wrapped_obj()->createAllInstalledApps(); | |
| 810 } | |
| 811 | |
| 812 STDMETHODIMP AppBundleWrapper::get_Count(long* count) { // NOLINT | |
| 813 __mutexScope(model()->lock()); | |
| 814 return wrapped_obj()->get_Count(count); | |
| 815 } | |
| 816 | |
| 817 STDMETHODIMP AppBundleWrapper::get_Item(long index, IDispatch** app_disp) { //
NOLINT | |
| 818 __mutexScope(model()->lock()); | |
| 819 | |
| 820 App* app = NULL; | |
| 821 HRESULT hr = wrapped_obj()->get_Item(index, &app); | |
| 822 if (FAILED(hr)) { | |
| 823 return hr; | |
| 824 } | |
| 825 | |
| 826 return AppWrapper::Create(controlling_ptr(), app, app_disp); | |
| 827 } | |
| 828 | |
| 829 STDMETHODIMP AppBundleWrapper::checkForUpdate() { | |
| 830 __mutexScope(model()->lock()); | |
| 831 return wrapped_obj()->checkForUpdate(); | |
| 832 } | |
| 833 | |
| 834 STDMETHODIMP AppBundleWrapper::download() { | |
| 835 __mutexScope(model()->lock()); | |
| 836 return wrapped_obj()->download(); | |
| 837 } | |
| 838 | |
| 839 STDMETHODIMP AppBundleWrapper::install() { | |
| 840 if (wrapped_obj()->is_machine() && !UserRights::VerifyCallerIsAdmin()) { | |
| 841 ASSERT(false, (_T("AppBundle::install - Caller not an admin"))); | |
| 842 return E_ACCESSDENIED; | |
| 843 } | |
| 844 | |
| 845 __mutexScope(model()->lock()); | |
| 846 return wrapped_obj()->install(); | |
| 847 } | |
| 848 | |
| 849 STDMETHODIMP AppBundleWrapper::updateAllApps() { | |
| 850 __mutexScope(model()->lock()); | |
| 851 return wrapped_obj()->updateAllApps(); | |
| 852 } | |
| 853 | |
| 854 STDMETHODIMP AppBundleWrapper::stop() { | |
| 855 __mutexScope(model()->lock()); | |
| 856 return wrapped_obj()->stop(); | |
| 857 } | |
| 858 | |
| 859 STDMETHODIMP AppBundleWrapper::pause() { | |
| 860 __mutexScope(model()->lock()); | |
| 861 return wrapped_obj()->pause(); | |
| 862 } | |
| 863 | |
| 864 STDMETHODIMP AppBundleWrapper::resume() { | |
| 865 __mutexScope(model()->lock()); | |
| 866 return wrapped_obj()->resume(); | |
| 867 } | |
| 868 | |
| 869 STDMETHODIMP AppBundleWrapper::isBusy(VARIANT_BOOL* is_busy) { | |
| 870 __mutexScope(model()->lock()); | |
| 871 return wrapped_obj()->isBusy(is_busy); | |
| 872 } | |
| 873 | |
| 874 STDMETHODIMP AppBundleWrapper::downloadPackage(BSTR app_id, BSTR package_name) { | |
| 875 __mutexScope(model()->lock()); | |
| 876 return wrapped_obj()->downloadPackage(app_id, package_name); | |
| 877 } | |
| 878 | |
| 879 STDMETHODIMP AppBundleWrapper::get_currentState(VARIANT* current_state) { | |
| 880 __mutexScope(model()->lock()); | |
| 881 return wrapped_obj()->get_currentState(current_state); | |
| 882 } | |
| 883 | |
| 884 | |
| 885 // Sets app bundle's app_state to state. Used by unit tests to set up the state | |
| 886 // to the correct precondition for the test case. AppBundle friends this | |
| 887 // function, allowing it to call the private member function. | |
| 888 void SetAppBundleStateForUnitTest(AppBundle* app_bundle, | |
| 889 fsm::AppBundleState* state) { | |
| 890 ASSERT1(app_bundle); | |
| 891 ASSERT1(state); | |
| 892 __mutexScope(app_bundle->model()->lock()); | |
| 893 app_bundle->ChangeState(state); | |
| 894 } | |
| 895 | |
| 896 } // namespace omaha | |
| OLD | NEW |