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 |