| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/extensions_service.h" | 5 #include "chrome/browser/extensions/extensions_service.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
| 10 #include "base/histogram.h" | 10 #include "base/histogram.h" |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 50 #if defined(OS_WIN) | 50 #if defined(OS_WIN) |
| 51 #include "chrome/browser/extensions/external_registry_extension_provider_win.h" | 51 #include "chrome/browser/extensions/external_registry_extension_provider_win.h" |
| 52 #endif | 52 #endif |
| 53 | 53 |
| 54 using base::Time; | 54 using base::Time; |
| 55 | 55 |
| 56 namespace errors = extension_manifest_errors; | 56 namespace errors = extension_manifest_errors; |
| 57 | 57 |
| 58 namespace { | 58 namespace { |
| 59 | 59 |
| 60 // Helper class to collect the IDs of every extension listed in the prefs. | |
| 61 class InstalledExtensionSet { | |
| 62 public: | |
| 63 explicit InstalledExtensionSet(ExtensionPrefs* prefs) { | |
| 64 scoped_ptr<ExtensionPrefs::ExtensionsInfo> info( | |
| 65 prefs->GetInstalledExtensionsInfo()); | |
| 66 | |
| 67 for (size_t i = 0; i < info->size(); ++i) { | |
| 68 std::string version; | |
| 69 const DictionaryValue* manifest = info->at(i)->extension_manifest.get(); | |
| 70 if (!manifest || | |
| 71 !manifest->GetString(extension_manifest_keys::kVersion, &version)) { | |
| 72 // Without a version, the extension is invalid. Ignoring it here will | |
| 73 // cause it to get garbage collected. | |
| 74 continue; | |
| 75 } | |
| 76 extensions_.insert(info->at(i)->extension_id); | |
| 77 versions_[info->at(i)->extension_id] = version; | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 const std::set<std::string>& extensions() { return extensions_; } | |
| 82 const std::map<std::string, std::string>& versions() { return versions_; } | |
| 83 | |
| 84 private: | |
| 85 std::set<std::string> extensions_; | |
| 86 std::map<std::string, std::string> versions_; | |
| 87 }; | |
| 88 | |
| 89 static bool ShouldReloadExtensionManifest(const ExtensionInfo& info) { | 60 static bool ShouldReloadExtensionManifest(const ExtensionInfo& info) { |
| 90 // Always reload LOAD extension manifests, because they can change on disk | 61 // Always reload LOAD extension manifests, because they can change on disk |
| 91 // independent of the manifest in our prefs. | 62 // independent of the manifest in our prefs. |
| 92 if (info.extension_location == Extension::LOAD) | 63 if (info.extension_location == Extension::LOAD) |
| 93 return true; | 64 return true; |
| 94 | 65 |
| 95 // Otherwise, reload the manifest it needs to be relocalized. | 66 // Otherwise, reload the manifest it needs to be relocalized. |
| 96 return extension_l10n_util::ShouldRelocalizeManifest(info); | 67 return extension_l10n_util::ShouldRelocalizeManifest(info); |
| 97 } | 68 } |
| 98 | 69 |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 358 UnloadExtension(extension_id); | 329 UnloadExtension(extension_id); |
| 359 | 330 |
| 360 extension_prefs_->OnExtensionUninstalled(extension_id_copy, location, | 331 extension_prefs_->OnExtensionUninstalled(extension_id_copy, location, |
| 361 external_uninstall); | 332 external_uninstall); |
| 362 | 333 |
| 363 // Tell the backend to start deleting installed extensions on the file thread. | 334 // Tell the backend to start deleting installed extensions on the file thread. |
| 364 if (Extension::LOAD != location) { | 335 if (Extension::LOAD != location) { |
| 365 ChromeThread::PostTask( | 336 ChromeThread::PostTask( |
| 366 ChromeThread::FILE, FROM_HERE, | 337 ChromeThread::FILE, FROM_HERE, |
| 367 NewRunnableFunction( | 338 NewRunnableFunction( |
| 368 &extension_file_util::UninstallExtension, extension_id_copy, | 339 &extension_file_util::UninstallExtension, |
| 369 install_directory_)); | 340 install_directory_, |
| 341 extension_id_copy)); |
| 370 } | 342 } |
| 371 | 343 |
| 372 ClearExtensionData(extension_url); | 344 ClearExtensionData(extension_url); |
| 373 } | 345 } |
| 374 | 346 |
| 375 void ExtensionsService::ClearExtensionData(const GURL& extension_url) { | 347 void ExtensionsService::ClearExtensionData(const GURL& extension_url) { |
| 376 scoped_refptr<ExtensionDataDeleter> deleter( | 348 scoped_refptr<ExtensionDataDeleter> deleter( |
| 377 new ExtensionDataDeleter(profile_, extension_url)); | 349 new ExtensionDataDeleter(profile_, extension_url)); |
| 378 deleter->StartDeleting(); | 350 deleter->StartDeleting(); |
| 379 } | 351 } |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 759 | 731 |
| 760 void ExtensionsService::ReloadExtensions() { | 732 void ExtensionsService::ReloadExtensions() { |
| 761 UnloadAllExtensions(); | 733 UnloadAllExtensions(); |
| 762 LoadAllExtensions(); | 734 LoadAllExtensions(); |
| 763 } | 735 } |
| 764 | 736 |
| 765 void ExtensionsService::GarbageCollectExtensions() { | 737 void ExtensionsService::GarbageCollectExtensions() { |
| 766 if (extension_prefs_->pref_service()->read_only()) | 738 if (extension_prefs_->pref_service()->read_only()) |
| 767 return; | 739 return; |
| 768 | 740 |
| 769 InstalledExtensionSet installed(extension_prefs_.get()); | 741 scoped_ptr<ExtensionPrefs::ExtensionsInfo> info( |
| 742 extension_prefs_->GetInstalledExtensionsInfo()); |
| 743 |
| 744 std::map<std::string, FilePath> extension_paths; |
| 745 for (size_t i = 0; i < info->size(); ++i) |
| 746 extension_paths[info->at(i)->extension_id] = info->at(i)->extension_path; |
| 747 |
| 770 ChromeThread::PostTask( | 748 ChromeThread::PostTask( |
| 771 ChromeThread::FILE, FROM_HERE, | 749 ChromeThread::FILE, FROM_HERE, |
| 772 NewRunnableFunction( | 750 NewRunnableFunction( |
| 773 &extension_file_util::GarbageCollectExtensions, install_directory_, | 751 &extension_file_util::GarbageCollectExtensions, install_directory_, |
| 774 installed.extensions(), installed.versions())); | 752 extension_paths)); |
| 775 } | 753 } |
| 776 | 754 |
| 777 void ExtensionsService::OnLoadedInstalledExtensions() { | 755 void ExtensionsService::OnLoadedInstalledExtensions() { |
| 778 ready_ = true; | 756 ready_ = true; |
| 779 if (updater_.get()) { | 757 if (updater_.get()) { |
| 780 updater_->Start(); | 758 updater_->Start(); |
| 781 } | 759 } |
| 782 NotificationService::current()->Notify( | 760 NotificationService::current()->Notify( |
| 783 NotificationType::EXTENSIONS_READY, | 761 NotificationType::EXTENSIONS_READY, |
| 784 Source<Profile>(profile_), | 762 Source<Profile>(profile_), |
| 785 NotificationService::NoDetails()); | 763 NotificationService::NoDetails()); |
| 786 } | 764 } |
| 787 | 765 |
| 788 void ExtensionsService::OnExtensionLoaded(Extension* extension, | 766 void ExtensionsService::OnExtensionLoaded(Extension* extension, |
| 789 bool allow_privilege_increase) { | 767 bool allow_privilege_increase) { |
| 790 // Ensure extension is deleted unless we transfer ownership. | 768 // Ensure extension is deleted unless we transfer ownership. |
| 791 scoped_ptr<Extension> scoped_extension(extension); | 769 scoped_ptr<Extension> scoped_extension(extension); |
| 792 | 770 |
| 793 // The extension is now loaded, remove its data from unloaded extension map. | 771 // The extension is now loaded, remove its data from unloaded extension map. |
| 794 unloaded_extension_paths_.erase(extension->id()); | 772 unloaded_extension_paths_.erase(extension->id()); |
| 795 | 773 |
| 796 // TODO(aa): Need to re-evaluate this branch. Does this still make sense now | 774 // TODO(aa): Need to re-evaluate this branch. Does this still make sense now |
| 797 // that extensions are enabled by default? | 775 // that extensions are enabled by default? |
| 798 if (extensions_enabled() || | 776 if (extensions_enabled() || |
| 799 extension->IsTheme() || | 777 extension->IsTheme() || |
| 800 extension->location() == Extension::LOAD || | 778 extension->location() == Extension::LOAD || |
| 801 Extension::IsExternalLocation(extension->location())) { | 779 Extension::IsExternalLocation(extension->location())) { |
| 802 Extension* old = GetExtensionByIdInternal(extension->id(), true, true); | 780 Extension* old = GetExtensionByIdInternal(extension->id(), true, true); |
| 803 if (old) { | 781 if (old) { |
| 804 if (extension->version()->CompareTo(*(old->version())) > 0) { | 782 // CrxInstaller should have guaranteed that we aren't downgrading. |
| 805 bool allow_silent_upgrade = | 783 CHECK(extension->version()->CompareTo(*(old->version())) >= 0); |
| 806 allow_privilege_increase || !Extension::IsPrivilegeIncrease( | |
| 807 old, extension); | |
| 808 | 784 |
| 809 // Extensions get upgraded if silent upgrades are allowed, otherwise | 785 bool allow_silent_upgrade = |
| 810 // they get disabled. | 786 allow_privilege_increase || !Extension::IsPrivilegeIncrease( |
| 811 if (allow_silent_upgrade) { | 787 old, extension); |
| 812 old->set_being_upgraded(true); | |
| 813 extension->set_being_upgraded(true); | |
| 814 } | |
| 815 | 788 |
| 816 // To upgrade an extension in place, unload the old one and | 789 // Extensions get upgraded if silent upgrades are allowed, otherwise |
| 817 // then load the new one. | 790 // they get disabled. |
| 818 UnloadExtension(old->id()); | 791 if (allow_silent_upgrade) { |
| 819 old = NULL; | 792 old->set_being_upgraded(true); |
| 793 extension->set_being_upgraded(true); |
| 794 } |
| 820 | 795 |
| 821 if (!allow_silent_upgrade) { | 796 // To upgrade an extension in place, unload the old one and |
| 822 // Extension has changed permissions significantly. Disable it. We | 797 // then load the new one. |
| 823 // send a notification below. | 798 UnloadExtension(old->id()); |
| 824 extension_prefs_->SetExtensionState(extension, Extension::DISABLED); | 799 old = NULL; |
| 825 extension_prefs_->SetDidExtensionEscalatePermissions(extension, true); | 800 |
| 826 } | 801 if (!allow_silent_upgrade) { |
| 827 } else { | 802 // Extension has changed permissions significantly. Disable it. We |
| 828 // We already have the extension of the same or older version. | 803 // send a notification below. |
| 829 std::string error_message("Duplicate extension load attempt: "); | 804 extension_prefs_->SetExtensionState(extension, Extension::DISABLED); |
| 830 error_message += extension->id(); | 805 extension_prefs_->SetDidExtensionEscalatePermissions(extension, true); |
| 831 LOG(WARNING) << error_message; | |
| 832 ReportExtensionLoadError(extension->path(), | |
| 833 error_message, | |
| 834 NotificationType::EXTENSION_OVERINSTALL_ERROR, | |
| 835 false); | |
| 836 return; | |
| 837 } | 806 } |
| 838 } | 807 } |
| 839 | 808 |
| 840 switch (extension_prefs_->GetExtensionState(extension->id())) { | 809 switch (extension_prefs_->GetExtensionState(extension->id())) { |
| 841 case Extension::ENABLED: | 810 case Extension::ENABLED: |
| 842 extensions_.push_back(scoped_extension.release()); | 811 extensions_.push_back(scoped_extension.release()); |
| 843 | 812 |
| 844 NotifyExtensionLoaded(extension); | 813 NotifyExtensionLoaded(extension); |
| 845 | 814 |
| 846 ExtensionDOMUI::RegisterChromeURLOverrides(profile_, | 815 ExtensionDOMUI::RegisterChromeURLOverrides(profile_, |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 910 | 879 |
| 911 // Also load the extension. | 880 // Also load the extension. |
| 912 OnExtensionLoaded(extension, allow_privilege_increase); | 881 OnExtensionLoaded(extension, allow_privilege_increase); |
| 913 | 882 |
| 914 // Erase any pending extension. | 883 // Erase any pending extension. |
| 915 if (it != pending_extensions_.end()) { | 884 if (it != pending_extensions_.end()) { |
| 916 pending_extensions_.erase(it); | 885 pending_extensions_.erase(it); |
| 917 } | 886 } |
| 918 } | 887 } |
| 919 | 888 |
| 920 void ExtensionsService::OnExtensionOverinstallAttempted(const std::string& id) { | |
| 921 Extension* extension = GetExtensionById(id, false); | |
| 922 if (extension && extension->IsTheme()) { | |
| 923 NotificationService::current()->Notify( | |
| 924 NotificationType::THEME_INSTALLED, | |
| 925 Source<Profile>(profile_), | |
| 926 Details<Extension>(extension)); | |
| 927 } else { | |
| 928 NotificationService::current()->Notify( | |
| 929 NotificationType::NO_THEME_DETECTED, | |
| 930 Source<Profile>(profile_), | |
| 931 NotificationService::NoDetails()); | |
| 932 } | |
| 933 } | |
| 934 | |
| 935 Extension* ExtensionsService::GetExtensionByIdInternal(const std::string& id, | 889 Extension* ExtensionsService::GetExtensionByIdInternal(const std::string& id, |
| 936 bool include_enabled, | 890 bool include_enabled, |
| 937 bool include_disabled) { | 891 bool include_disabled) { |
| 938 std::string lowercase_id = StringToLowerASCII(id); | 892 std::string lowercase_id = StringToLowerASCII(id); |
| 939 if (include_enabled) { | 893 if (include_enabled) { |
| 940 for (ExtensionList::const_iterator iter = extensions_.begin(); | 894 for (ExtensionList::const_iterator iter = extensions_.begin(); |
| 941 iter != extensions_.end(); ++iter) { | 895 iter != extensions_.end(); ++iter) { |
| 942 if ((*iter)->id() == lowercase_id) | 896 if ((*iter)->id() == lowercase_id) |
| 943 return *iter; | 897 return *iter; |
| 944 } | 898 } |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1244 // Finish installing on UI thread. | 1198 // Finish installing on UI thread. |
| 1245 ChromeThread::PostTask( | 1199 ChromeThread::PostTask( |
| 1246 ChromeThread::UI, FROM_HERE, | 1200 ChromeThread::UI, FROM_HERE, |
| 1247 NewRunnableMethod( | 1201 NewRunnableMethod( |
| 1248 frontend_, | 1202 frontend_, |
| 1249 &ExtensionsService::ContinueLoadAllExtensions, | 1203 &ExtensionsService::ContinueLoadAllExtensions, |
| 1250 extensions_to_reload, | 1204 extensions_to_reload, |
| 1251 start_time, | 1205 start_time, |
| 1252 true)); | 1206 true)); |
| 1253 } | 1207 } |
| OLD | NEW |