| 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 |