OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/crx_installer.h" | 5 #include "chrome/browser/extensions/crx_installer.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <set> | 8 #include <set> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 allow_silent_install_(false), | 101 allow_silent_install_(false), |
102 bypass_blacklist_for_test_(false), | 102 bypass_blacklist_for_test_(false), |
103 install_cause_(extension_misc::INSTALL_CAUSE_UNSET), | 103 install_cause_(extension_misc::INSTALL_CAUSE_UNSET), |
104 creation_flags_(Extension::NO_FLAGS), | 104 creation_flags_(Extension::NO_FLAGS), |
105 off_store_install_allow_reason_(OffStoreInstallDisallowed), | 105 off_store_install_allow_reason_(OffStoreInstallDisallowed), |
106 did_handle_successfully_(true), | 106 did_handle_successfully_(true), |
107 record_oauth2_grant_(false), | 107 record_oauth2_grant_(false), |
108 error_on_unsupported_requirements_(false), | 108 error_on_unsupported_requirements_(false), |
109 requirements_checker_(new extensions::RequirementsChecker()), | 109 requirements_checker_(new extensions::RequirementsChecker()), |
110 has_requirement_errors_(false), | 110 has_requirement_errors_(false), |
111 install_wait_for_idle_(true) { | 111 install_wait_for_idle_(true), |
| 112 update_from_settings_page_(false) { |
112 installer_task_runner_ = frontend_weak->GetFileTaskRunner(); | 113 installer_task_runner_ = frontend_weak->GetFileTaskRunner(); |
113 if (!approval) | 114 if (!approval) |
114 return; | 115 return; |
115 | 116 |
116 CHECK(profile_->IsSameProfile(approval->profile)); | 117 CHECK(profile_->IsSameProfile(approval->profile)); |
117 if (client_) { | 118 if (client_) { |
118 client_->install_ui()->SetUseAppInstalledBubble( | 119 client_->install_ui()->SetUseAppInstalledBubble( |
119 approval->use_app_installed_bubble); | 120 approval->use_app_installed_bubble); |
120 client_->install_ui()->SetSkipPostInstallUI(approval->skip_post_install_ui); | 121 client_->install_ui()->SetSkipPostInstallUI(approval->skip_post_install_ui); |
121 } | 122 } |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
421 } | 422 } |
422 | 423 |
423 ConfirmInstall(); | 424 ConfirmInstall(); |
424 } | 425 } |
425 | 426 |
426 void CrxInstaller::ConfirmInstall() { | 427 void CrxInstaller::ConfirmInstall() { |
427 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 428 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
428 if (!frontend_weak_.get() || frontend_weak_->browser_terminating()) | 429 if (!frontend_weak_.get() || frontend_weak_->browser_terminating()) |
429 return; | 430 return; |
430 | 431 |
| 432 // Check whether this install is initiated from the settings page to |
| 433 // update an existing extension or app. |
| 434 CheckUpdateFromSettingsPage(); |
| 435 |
431 string16 error; | 436 string16 error; |
432 if (!ExtensionSystem::Get(profile_)->management_policy()-> | 437 if (!ExtensionSystem::Get(profile_)->management_policy()-> |
433 UserMayLoad(extension_, &error)) { | 438 UserMayLoad(extension_, &error)) { |
434 ReportFailureFromUIThread(CrxInstallerError(error)); | 439 ReportFailureFromUIThread(CrxInstallerError(error)); |
435 return; | 440 return; |
436 } | 441 } |
437 | 442 |
438 GURL overlapping_url; | 443 GURL overlapping_url; |
439 const Extension* overlapping_extension = | 444 const Extension* overlapping_extension = |
440 frontend_weak_->extensions()-> | 445 frontend_weak_->extensions()-> |
441 GetHostedAppByOverlappingWebExtent(extension_->web_extent()); | 446 GetHostedAppByOverlappingWebExtent(extension_->web_extent()); |
442 if (overlapping_extension && | 447 if (overlapping_extension && |
443 overlapping_extension->id() != extension_->id()) { | 448 overlapping_extension->id() != extension_->id()) { |
444 ReportFailureFromUIThread( | 449 ReportFailureFromUIThread( |
445 CrxInstallerError( | 450 CrxInstallerError( |
446 l10n_util::GetStringFUTF16( | 451 l10n_util::GetStringFUTF16( |
447 IDS_EXTENSION_OVERLAPPING_WEB_EXTENT, | 452 IDS_EXTENSION_OVERLAPPING_WEB_EXTENT, |
448 UTF8ToUTF16(overlapping_extension->name())))); | 453 UTF8ToUTF16(overlapping_extension->name())))); |
449 return; | 454 return; |
450 } | 455 } |
451 | 456 |
452 current_version_ = | 457 current_version_ = |
453 frontend_weak_->extension_prefs()->GetVersionString(extension_->id()); | 458 frontend_weak_->extension_prefs()->GetVersionString(extension_->id()); |
454 | 459 |
455 if (client_ && (!allow_silent_install_ || !approved_)) { | 460 if (client_ && |
456 AddRef(); // Balanced in Proceed() and Abort(). | 461 (!allow_silent_install_ || !approved_) && |
| 462 !update_from_settings_page_) { |
| 463 AddRef(); // Balanced in InstallUIProceed() and InstallUIAbort(). |
457 client_->ConfirmInstall(this, extension_.get(), show_dialog_callback_); | 464 client_->ConfirmInstall(this, extension_.get(), show_dialog_callback_); |
458 } else { | 465 } else { |
459 if (!installer_task_runner_->PostTask( | 466 if (!installer_task_runner_->PostTask( |
460 FROM_HERE, | 467 FROM_HERE, |
461 base::Bind(&CrxInstaller::CompleteInstall, this))) | 468 base::Bind(&CrxInstaller::CompleteInstall, this))) |
462 NOTREACHED(); | 469 NOTREACHED(); |
463 } | 470 } |
464 return; | 471 return; |
465 } | 472 } |
466 | 473 |
467 void CrxInstaller::InstallUIProceed() { | 474 void CrxInstaller::InstallUIProceed() { |
468 if (!installer_task_runner_->PostTask( | 475 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
469 FROM_HERE, | |
470 base::Bind(&CrxInstaller::CompleteInstall, this))) | |
471 NOTREACHED(); | |
472 | 476 |
473 Release(); // balanced in ConfirmInstall(). | 477 if (!frontend_weak_.get() || frontend_weak_->browser_terminating()) |
| 478 return; |
| 479 |
| 480 // If update_from_settings_page_ boolean is true, this functions is |
| 481 // getting called in response to ExtensionInstallPrompt::ConfirmReEnable() |
| 482 // and if it is false, this function is called in response to |
| 483 // ExtensionInstallPrompt::ConfirmInstall(). |
| 484 if (update_from_settings_page_) { |
| 485 frontend_weak_->GrantPermissionsAndEnableExtension( |
| 486 extension_.get(), client_->record_oauth2_grant()); |
| 487 } else { |
| 488 if (!installer_task_runner_->PostTask( |
| 489 FROM_HERE, |
| 490 base::Bind(&CrxInstaller::CompleteInstall, this))) |
| 491 NOTREACHED(); |
| 492 } |
| 493 |
| 494 Release(); // balanced in ConfirmInstall() or ConfirmReEnable(). |
474 } | 495 } |
475 | 496 |
476 void CrxInstaller::InstallUIAbort(bool user_initiated) { | 497 void CrxInstaller::InstallUIAbort(bool user_initiated) { |
477 std::string histogram_name = user_initiated ? | 498 // If update_from_settings_page_ boolean is true, this functions is |
478 "Extensions.Permissions_InstallCancel" : | 499 // getting called in response to ExtensionInstallPrompt::ConfirmReEnable() |
479 "Extensions.Permissions_InstallAbort"; | 500 // and if it is false, this function is called in response to |
480 ExtensionService::RecordPermissionMessagesHistogram( | 501 // ExtensionInstallPrompt::ConfirmInstall(). |
481 extension_, histogram_name.c_str()); | 502 if (!update_from_settings_page_) { |
| 503 std::string histogram_name = user_initiated ? |
| 504 "Extensions.Permissions_InstallCancel" : |
| 505 "Extensions.Permissions_InstallAbort"; |
| 506 ExtensionService::RecordPermissionMessagesHistogram( |
| 507 extension_, histogram_name.c_str()); |
482 | 508 |
483 // Kill the theme loading bubble. | 509 // Kill the theme loading bubble. |
484 content::NotificationService* service = | 510 content::NotificationService* service = |
485 content::NotificationService::current(); | 511 content::NotificationService::current(); |
486 service->Notify(chrome::NOTIFICATION_NO_THEME_DETECTED, | 512 service->Notify(chrome::NOTIFICATION_NO_THEME_DETECTED, |
487 content::Source<CrxInstaller>(this), | 513 content::Source<CrxInstaller>(this), |
488 content::NotificationService::NoDetails()); | 514 content::NotificationService::NoDetails()); |
489 | 515 |
490 NotifyCrxInstallComplete(false); | 516 NotifyCrxInstallComplete(false); |
| 517 } |
491 | 518 |
492 Release(); // balanced in ConfirmInstall(). | 519 Release(); // balanced in ConfirmInstall() or ConfirmReEnable(). |
493 | 520 |
494 // We're done. Since we don't post any more tasks to ourself, our ref count | 521 // We're done. Since we don't post any more tasks to ourself, our ref count |
495 // should go to zero and we die. The destructor will clean up the temp dir. | 522 // should go to zero and we die. The destructor will clean up the temp dir. |
496 } | 523 } |
497 | 524 |
498 void CrxInstaller::CompleteInstall() { | 525 void CrxInstaller::CompleteInstall() { |
499 DCHECK(installer_task_runner_->RunsTasksOnCurrentThread()); | 526 DCHECK(installer_task_runner_->RunsTasksOnCurrentThread()); |
500 | 527 |
501 if (!current_version_.empty()) { | 528 if (!current_version_.empty()) { |
502 Version current_version(current_version_); | 529 Version current_version(current_version_); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
604 // Delete temporary files. | 631 // Delete temporary files. |
605 CleanupTempFiles(); | 632 CleanupTempFiles(); |
606 } | 633 } |
607 | 634 |
608 void CrxInstaller::ReportSuccessFromUIThread() { | 635 void CrxInstaller::ReportSuccessFromUIThread() { |
609 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 636 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
610 | 637 |
611 if (!frontend_weak_.get() || frontend_weak_->browser_terminating()) | 638 if (!frontend_weak_.get() || frontend_weak_->browser_terminating()) |
612 return; | 639 return; |
613 | 640 |
614 // If there is a client, tell the client about installation. | 641 if (!update_from_settings_page_) { |
615 if (client_) { | 642 // If there is a client, tell the client about installation. |
616 client_->OnInstallSuccess(extension_.get(), install_icon_.get()); | 643 if (client_) |
617 } | 644 client_->OnInstallSuccess(extension_.get(), install_icon_.get()); |
618 | 645 |
619 if (client_ && !approved_) | 646 if (client_ && !approved_) |
620 record_oauth2_grant_ = client_->record_oauth2_grant(); | 647 record_oauth2_grant_ = client_->record_oauth2_grant(); |
621 | 648 |
622 // We update the extension's granted permissions if the user already approved | 649 // We update the extension's granted permissions if the user already |
623 // the install (client_ is non NULL), or we are allowed to install this | 650 // approved the install (client_ is non NULL), or we are allowed to install |
624 // silently. | 651 // this silently. |
625 if (client_ || allow_silent_install_) { | 652 if (client_ || allow_silent_install_) { |
626 PermissionsUpdater perms_updater(profile()); | 653 PermissionsUpdater perms_updater(profile()); |
627 perms_updater.GrantActivePermissions(extension_, record_oauth2_grant_); | 654 perms_updater.GrantActivePermissions(extension_, record_oauth2_grant_); |
| 655 } |
628 } | 656 } |
629 | 657 |
630 // Install the extension if it's not blacklisted, but notify either way. | 658 // Install the extension if it's not blacklisted, but notify either way. |
631 base::Closure on_success = | 659 base::Closure on_success = |
632 base::Bind(&ExtensionService::OnExtensionInstalled, | 660 base::Bind(&ExtensionService::OnExtensionInstalled, |
633 frontend_weak_, | 661 frontend_weak_, |
634 extension_, | 662 extension_, |
635 page_ordinal_, | 663 page_ordinal_, |
636 has_requirement_errors_, | 664 has_requirement_errors_, |
637 install_wait_for_idle_); | 665 install_wait_for_idle_); |
(...skipping 29 matching lines...) Expand all Loading... |
667 // Some users (such as the download shelf) need to know when a | 695 // Some users (such as the download shelf) need to know when a |
668 // CRXInstaller is done. Listening for the EXTENSION_* events | 696 // CRXInstaller is done. Listening for the EXTENSION_* events |
669 // is problematic because they don't know anything about the | 697 // is problematic because they don't know anything about the |
670 // extension before it is unpacked, so they cannot filter based | 698 // extension before it is unpacked, so they cannot filter based |
671 // on the extension. | 699 // on the extension. |
672 content::NotificationService::current()->Notify( | 700 content::NotificationService::current()->Notify( |
673 chrome::NOTIFICATION_CRX_INSTALLER_DONE, | 701 chrome::NOTIFICATION_CRX_INSTALLER_DONE, |
674 content::Source<CrxInstaller>(this), | 702 content::Source<CrxInstaller>(this), |
675 content::Details<const Extension>(success ? extension_.get() : NULL)); | 703 content::Details<const Extension>(success ? extension_.get() : NULL)); |
676 | 704 |
677 // We're done. We don't post any more tasks to ourselves so we are deleted | 705 if (success) |
678 // soon. | 706 ConfirmReEnable(); |
679 extension_ = NULL; | 707 |
680 } | 708 } |
681 | 709 |
682 void CrxInstaller::CleanupTempFiles() { | 710 void CrxInstaller::CleanupTempFiles() { |
683 if (!installer_task_runner_->RunsTasksOnCurrentThread()) { | 711 if (!installer_task_runner_->RunsTasksOnCurrentThread()) { |
684 if (!installer_task_runner_->PostTask( | 712 if (!installer_task_runner_->PostTask( |
685 FROM_HERE, | 713 FROM_HERE, |
686 base::Bind(&CrxInstaller::CleanupTempFiles, this))) { | 714 base::Bind(&CrxInstaller::CleanupTempFiles, this))) { |
687 NOTREACHED(); | 715 NOTREACHED(); |
688 } | 716 } |
689 return; | 717 return; |
690 } | 718 } |
691 | 719 |
692 // Delete the temp directory and crx file as necessary. | 720 // Delete the temp directory and crx file as necessary. |
693 if (!temp_dir_.value().empty()) { | 721 if (!temp_dir_.value().empty()) { |
694 extension_file_util::DeleteFile(temp_dir_, true); | 722 extension_file_util::DeleteFile(temp_dir_, true); |
695 temp_dir_ = base::FilePath(); | 723 temp_dir_ = base::FilePath(); |
696 } | 724 } |
697 | 725 |
698 if (delete_source_ && !source_file_.value().empty()) { | 726 if (delete_source_ && !source_file_.value().empty()) { |
699 extension_file_util::DeleteFile(source_file_, false); | 727 extension_file_util::DeleteFile(source_file_, false); |
700 source_file_ = base::FilePath(); | 728 source_file_ = base::FilePath(); |
701 } | 729 } |
702 } | 730 } |
703 | 731 |
| 732 void CrxInstaller::CheckUpdateFromSettingsPage() { |
| 733 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 734 |
| 735 if (!frontend_weak_.get() || frontend_weak_->browser_terminating()) |
| 736 return; |
| 737 |
| 738 if (off_store_install_allow_reason_ != OffStoreInstallAllowedFromSettingsPage) |
| 739 return; |
| 740 |
| 741 const Extension* installed_extension = |
| 742 frontend_weak_->GetInstalledExtension(extension_->id()); |
| 743 if (installed_extension) { |
| 744 // Previous version of the extension exists. |
| 745 update_from_settings_page_ = true; |
| 746 expected_id_ = installed_extension->id(); |
| 747 install_source_ = installed_extension->location(); |
| 748 install_cause_ = extension_misc::INSTALL_CAUSE_UPDATE; |
| 749 } |
| 750 } |
| 751 |
| 752 void CrxInstaller::ConfirmReEnable() { |
| 753 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 754 |
| 755 if (!frontend_weak_.get() || frontend_weak_->browser_terminating()) |
| 756 return; |
| 757 |
| 758 if (!update_from_settings_page_) |
| 759 return; |
| 760 |
| 761 extensions::ExtensionPrefs* prefs = frontend_weak_->extension_prefs(); |
| 762 if (!prefs->DidExtensionEscalatePermissions(extension_->id())) |
| 763 return; |
| 764 |
| 765 if (client_) { |
| 766 AddRef(); // Balanced in InstallUIProceed() and InstallUIAbort(). |
| 767 client_->ConfirmReEnable(this, extension_.get()); |
| 768 } |
| 769 } |
| 770 |
704 } // namespace extensions | 771 } // namespace extensions |
OLD | NEW |