OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/extension_service.h" | 5 #include "chrome/browser/extensions/extension_service.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <iterator> | 8 #include <iterator> |
9 #include <set> | 9 #include <set> |
10 | 10 |
(...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
588 installer->set_delete_source(file_ownership_passed); | 588 installer->set_delete_source(file_ownership_passed); |
589 installer->set_install_cause(extension_misc::INSTALL_CAUSE_UPDATE); | 589 installer->set_install_cause(extension_misc::INSTALL_CAUSE_UPDATE); |
590 installer->InstallCrx(extension_path); | 590 installer->InstallCrx(extension_path); |
591 | 591 |
592 if (out_crx_installer) | 592 if (out_crx_installer) |
593 *out_crx_installer = installer.get(); | 593 *out_crx_installer = installer.get(); |
594 | 594 |
595 return true; | 595 return true; |
596 } | 596 } |
597 | 597 |
598 void ExtensionService::ReloadExtension(const std::string extension_id) { | 598 void ExtensionService::ReloadExtension( |
| 599 // "transient" because the process of reloading may cause the reference |
| 600 // to become invalid. Instead, use |extension_id|, a copy. |
| 601 const std::string& transient_extension_id) { |
599 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 602 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
600 | 603 |
601 // If the extension is already reloading, don't reload again. | 604 // If the extension is already reloading, don't reload again. |
602 if (extension_prefs_->GetDisableReasons(extension_id) & | 605 if (extension_prefs_->GetDisableReasons(transient_extension_id) & |
603 Extension::DISABLE_RELOAD) { | 606 Extension::DISABLE_RELOAD) { |
604 return; | 607 return; |
605 } | 608 } |
606 | 609 |
| 610 // Ignore attempts to reload a blacklisted extension. Sometimes this can |
| 611 // happen in a convoluted reload sequence triggered by the termination of a |
| 612 // blacklisted extension and a naive attempt to reload it. For an example see |
| 613 // http://crbug.com/373842. |
| 614 if (registry_->blacklisted_extensions().Contains(transient_extension_id)) |
| 615 return; |
| 616 |
607 base::FilePath path; | 617 base::FilePath path; |
608 const Extension* current_extension = GetExtensionById(extension_id, false); | 618 |
| 619 std::string extension_id = transient_extension_id; |
| 620 const Extension* transient_current_extension = |
| 621 GetExtensionById(extension_id, false); |
609 | 622 |
610 // Disable the extension if it's loaded. It might not be loaded if it crashed. | 623 // Disable the extension if it's loaded. It might not be loaded if it crashed. |
611 if (current_extension) { | 624 if (transient_current_extension) { |
612 // If the extension has an inspector open for its background page, detach | 625 // If the extension has an inspector open for its background page, detach |
613 // the inspector and hang onto a cookie for it, so that we can reattach | 626 // the inspector and hang onto a cookie for it, so that we can reattach |
614 // later. | 627 // later. |
615 // TODO(yoz): this is not incognito-safe! | 628 // TODO(yoz): this is not incognito-safe! |
616 extensions::ProcessManager* manager = system_->process_manager(); | 629 extensions::ProcessManager* manager = system_->process_manager(); |
617 extensions::ExtensionHost* host = | 630 extensions::ExtensionHost* host = |
618 manager->GetBackgroundHostForExtension(extension_id); | 631 manager->GetBackgroundHostForExtension(extension_id); |
619 if (host && DevToolsAgentHost::HasFor(host->render_view_host())) { | 632 if (host && DevToolsAgentHost::HasFor(host->render_view_host())) { |
620 // Look for an open inspector for the background page. | 633 // Look for an open inspector for the background page. |
621 scoped_refptr<DevToolsAgentHost> agent_host = | 634 scoped_refptr<DevToolsAgentHost> agent_host = |
622 DevToolsAgentHost::GetOrCreateFor(host->render_view_host()); | 635 DevToolsAgentHost::GetOrCreateFor(host->render_view_host()); |
623 agent_host->DisconnectRenderViewHost(); | 636 agent_host->DisconnectRenderViewHost(); |
624 orphaned_dev_tools_[extension_id] = agent_host; | 637 orphaned_dev_tools_[extension_id] = agent_host; |
625 } | 638 } |
626 | 639 |
627 path = current_extension->path(); | 640 path = transient_current_extension->path(); |
628 // BeingUpgraded is set back to false when the extension is added. | 641 // BeingUpgraded is set back to false when the extension is added. |
629 system_->runtime_data()->SetBeingUpgraded(current_extension, true); | 642 system_->runtime_data()->SetBeingUpgraded(transient_current_extension, |
| 643 true); |
630 DisableExtension(extension_id, Extension::DISABLE_RELOAD); | 644 DisableExtension(extension_id, Extension::DISABLE_RELOAD); |
631 reloading_extensions_.insert(extension_id); | 645 reloading_extensions_.insert(extension_id); |
632 } else { | 646 } else { |
633 path = unloaded_extension_paths_[extension_id]; | 647 path = unloaded_extension_paths_[extension_id]; |
634 } | 648 } |
635 | 649 |
| 650 transient_current_extension = NULL; |
| 651 |
636 if (delayed_installs_.Contains(extension_id)) { | 652 if (delayed_installs_.Contains(extension_id)) { |
637 FinishDelayedInstallation(extension_id); | 653 FinishDelayedInstallation(extension_id); |
638 return; | 654 return; |
639 } | 655 } |
640 | 656 |
641 // If we're reloading a component extension, use the component extension | 657 // If we're reloading a component extension, use the component extension |
642 // loader's reloader. | 658 // loader's reloader. |
643 if (component_loader_->Exists(extension_id)) { | 659 if (component_loader_->Exists(extension_id)) { |
644 SetBeingReloaded(extension_id, true); | 660 SetBeingReloaded(extension_id, true); |
645 component_loader_->Reload(extension_id); | 661 component_loader_->Reload(extension_id); |
(...skipping 13 matching lines...) Expand all Loading... |
659 // Otherwise, the extension is unpacked (location LOAD). | 675 // Otherwise, the extension is unpacked (location LOAD). |
660 // We should always be able to remember the extension's path. If it's not in | 676 // We should always be able to remember the extension's path. If it's not in |
661 // the map, someone failed to update |unloaded_extension_paths_|. | 677 // the map, someone failed to update |unloaded_extension_paths_|. |
662 CHECK(!path.empty()); | 678 CHECK(!path.empty()); |
663 extensions::UnpackedInstaller::Create(this)->Load(path); | 679 extensions::UnpackedInstaller::Create(this)->Load(path); |
664 } | 680 } |
665 // When reloading is done, mark this extension as done reloading. | 681 // When reloading is done, mark this extension as done reloading. |
666 SetBeingReloaded(extension_id, false); | 682 SetBeingReloaded(extension_id, false); |
667 } | 683 } |
668 | 684 |
669 bool ExtensionService::UninstallExtension(const std::string& extension_id, | 685 bool ExtensionService::UninstallExtension( |
670 bool external_uninstall, | 686 // "transient" because the process of uninstalling may cause the reference |
671 base::string16* error) { | 687 // to become invalid. Instead, use |extenson->id()|. |
| 688 const std::string& transient_extension_id, |
| 689 bool external_uninstall, |
| 690 base::string16* error) { |
672 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 691 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
673 | 692 |
674 scoped_refptr<const Extension> extension(GetInstalledExtension(extension_id)); | 693 scoped_refptr<const Extension> extension = |
| 694 GetInstalledExtension(transient_extension_id); |
675 | 695 |
676 // Callers should not send us nonexistent extensions. | 696 // Callers should not send us nonexistent extensions. |
677 CHECK(extension.get()); | 697 CHECK(extension.get()); |
678 | 698 |
679 // Policy change which triggers an uninstall will always set | 699 // Policy change which triggers an uninstall will always set |
680 // |external_uninstall| to true so this is the only way to uninstall | 700 // |external_uninstall| to true so this is the only way to uninstall |
681 // managed extensions. | 701 // managed extensions. |
682 // Shared modules being uninstalled will also set |external_uninstall| to true | 702 // Shared modules being uninstalled will also set |external_uninstall| to true |
683 // so that we can guarantee users don't uninstall a shared module. | 703 // so that we can guarantee users don't uninstall a shared module. |
684 // (crbug.com/273300) | 704 // (crbug.com/273300) |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 EXTERNAL_EXTENSION_BUCKET_BOUNDARY); | 737 EXTERNAL_EXTENSION_BUCKET_BOUNDARY); |
718 } | 738 } |
719 } | 739 } |
720 UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallType", | 740 UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallType", |
721 extension->GetType(), 100); | 741 extension->GetType(), 100); |
722 RecordPermissionMessagesHistogram(extension.get(), | 742 RecordPermissionMessagesHistogram(extension.get(), |
723 "Extensions.Permissions_Uninstall"); | 743 "Extensions.Permissions_Uninstall"); |
724 | 744 |
725 // Unload before doing more cleanup to ensure that nothing is hanging on to | 745 // Unload before doing more cleanup to ensure that nothing is hanging on to |
726 // any of these resources. | 746 // any of these resources. |
727 UnloadExtension(extension_id, UnloadedExtensionInfo::REASON_UNINSTALL); | 747 UnloadExtension(extension->id(), UnloadedExtensionInfo::REASON_UNINSTALL); |
728 | 748 |
729 // Tell the backend to start deleting installed extensions on the file thread. | 749 // Tell the backend to start deleting installed extensions on the file thread. |
730 if (!Manifest::IsUnpackedLocation(extension->location())) { | 750 if (!Manifest::IsUnpackedLocation(extension->location())) { |
731 if (!GetFileTaskRunner()->PostTask( | 751 if (!GetFileTaskRunner()->PostTask( |
732 FROM_HERE, | 752 FROM_HERE, |
733 base::Bind(&extensions::file_util::UninstallExtension, | 753 base::Bind(&extensions::file_util::UninstallExtension, |
734 install_directory_, | 754 install_directory_, |
735 extension_id))) | 755 extension->id()))) |
736 NOTREACHED(); | 756 NOTREACHED(); |
737 } | 757 } |
738 | 758 |
739 // Do not remove the data of ephemeral apps. They will be garbage collected by | 759 // Do not remove the data of ephemeral apps. They will be garbage collected by |
740 // EphemeralAppService. | 760 // EphemeralAppService. |
741 if (!extension_prefs_->IsEphemeralApp(extension_id)) | 761 if (!extension_prefs_->IsEphemeralApp(extension->id())) |
742 extensions::DataDeleter::StartDeleting(profile_, extension.get()); | 762 extensions::DataDeleter::StartDeleting(profile_, extension.get()); |
743 | 763 |
744 UntrackTerminatedExtension(extension_id); | 764 UntrackTerminatedExtension(extension->id()); |
745 | 765 |
746 // Notify interested parties that we've uninstalled this extension. | 766 // Notify interested parties that we've uninstalled this extension. |
747 content::NotificationService::current()->Notify( | 767 content::NotificationService::current()->Notify( |
748 chrome::NOTIFICATION_EXTENSION_UNINSTALLED, | 768 chrome::NOTIFICATION_EXTENSION_UNINSTALLED, |
749 content::Source<Profile>(profile_), | 769 content::Source<Profile>(profile_), |
750 content::Details<const Extension>(extension.get())); | 770 content::Details<const Extension>(extension.get())); |
751 | 771 |
752 if (extension_sync_service_) { | 772 if (extension_sync_service_) { |
753 extension_sync_service_->ProcessSyncUninstallExtension(extension_id, | 773 extension_sync_service_->ProcessSyncUninstallExtension(extension->id(), |
754 sync_change); | 774 sync_change); |
755 } | 775 } |
756 | 776 |
757 delayed_installs_.Remove(extension_id); | 777 delayed_installs_.Remove(extension->id()); |
758 | 778 |
759 extension_prefs_->OnExtensionUninstalled(extension_id, extension->location(), | 779 extension_prefs_->OnExtensionUninstalled( |
760 external_uninstall); | 780 extension->id(), extension->location(), external_uninstall); |
761 | 781 |
762 // Track the uninstallation. | 782 // Track the uninstallation. |
763 UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionUninstalled", 1, 2); | 783 UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionUninstalled", 1, 2); |
764 | 784 |
765 return true; | 785 return true; |
766 } | 786 } |
767 | 787 |
768 bool ExtensionService::IsExtensionEnabled( | 788 bool ExtensionService::IsExtensionEnabled( |
769 const std::string& extension_id) const { | 789 const std::string& extension_id) const { |
770 if (registry_->enabled_extensions().Contains(extension_id) || | 790 if (registry_->enabled_extensions().Contains(extension_id) || |
(...skipping 1679 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2450 } | 2470 } |
2451 | 2471 |
2452 void ExtensionService::OnProfileDestructionStarted() { | 2472 void ExtensionService::OnProfileDestructionStarted() { |
2453 ExtensionIdSet ids_to_unload = registry_->enabled_extensions().GetIDs(); | 2473 ExtensionIdSet ids_to_unload = registry_->enabled_extensions().GetIDs(); |
2454 for (ExtensionIdSet::iterator it = ids_to_unload.begin(); | 2474 for (ExtensionIdSet::iterator it = ids_to_unload.begin(); |
2455 it != ids_to_unload.end(); | 2475 it != ids_to_unload.end(); |
2456 ++it) { | 2476 ++it) { |
2457 UnloadExtension(*it, UnloadedExtensionInfo::REASON_PROFILE_SHUTDOWN); | 2477 UnloadExtension(*it, UnloadedExtensionInfo::REASON_PROFILE_SHUTDOWN); |
2458 } | 2478 } |
2459 } | 2479 } |
OLD | NEW |