OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <set> | 8 #include <set> |
9 | 9 |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
(...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 omnibox_popup_icon_manager_.set_monochrome(true); | 437 omnibox_popup_icon_manager_.set_monochrome(true); |
438 omnibox_icon_manager_.set_monochrome(true); | 438 omnibox_icon_manager_.set_monochrome(true); |
439 omnibox_icon_manager_.set_padding(gfx::Insets(0, kOmniboxIconPaddingLeft, | 439 omnibox_icon_manager_.set_padding(gfx::Insets(0, kOmniboxIconPaddingLeft, |
440 0, kOmniboxIconPaddingRight)); | 440 0, kOmniboxIconPaddingRight)); |
441 | 441 |
442 // How long is the path to the Extensions directory? | 442 // How long is the path to the Extensions directory? |
443 UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.ExtensionRootPathLength", | 443 UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.ExtensionRootPathLength", |
444 install_directory_.value().length(), 0, 500, 100); | 444 install_directory_.value().length(), 0, 500, 100); |
445 } | 445 } |
446 | 446 |
447 const ExtensionList* ExtensionService::extensions() const { | 447 const ExtensionSet* ExtensionService::extensions() const { |
448 return &extensions_; | 448 return &extensions_; |
449 } | 449 } |
450 | 450 |
451 const ExtensionList* ExtensionService::disabled_extensions() const { | 451 const ExtensionSet* ExtensionService::disabled_extensions() const { |
452 return &disabled_extensions_; | 452 return &disabled_extensions_; |
453 } | 453 } |
454 | 454 |
455 const ExtensionList* ExtensionService::terminated_extensions() const { | 455 const ExtensionSet* ExtensionService::terminated_extensions() const { |
456 return &terminated_extensions_; | 456 return &terminated_extensions_; |
457 } | 457 } |
458 | 458 |
459 PendingExtensionManager* ExtensionService::pending_extension_manager() { | 459 PendingExtensionManager* ExtensionService::pending_extension_manager() { |
460 return &pending_extension_manager_; | 460 return &pending_extension_manager_; |
461 } | 461 } |
462 | 462 |
463 ExtensionService::~ExtensionService() { | 463 ExtensionService::~ExtensionService() { |
464 // No need to unload extensions here because they are profile-scoped, and the | 464 // No need to unload extensions here because they are profile-scoped, and the |
465 // profile is in the process of being deleted. | 465 // profile is in the process of being deleted. |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
759 // Therefore, we clear warnings of this type for all extensions. | 759 // Therefore, we clear warnings of this type for all extensions. |
760 std::set<ExtensionWarningSet::WarningType> warnings; | 760 std::set<ExtensionWarningSet::WarningType> warnings; |
761 extension_warnings_.GetWarningsAffectingExtension(extension_id, &warnings); | 761 extension_warnings_.GetWarningsAffectingExtension(extension_id, &warnings); |
762 extension_warnings_.ClearWarnings(warnings); | 762 extension_warnings_.ClearWarnings(warnings); |
763 | 763 |
764 return true; | 764 return true; |
765 } | 765 } |
766 | 766 |
767 bool ExtensionService::IsExtensionEnabled( | 767 bool ExtensionService::IsExtensionEnabled( |
768 const std::string& extension_id) const { | 768 const std::string& extension_id) const { |
769 const Extension* extension = | 769 if (extensions_.Contains(extension_id) || |
770 GetExtensionByIdInternal(extension_id, true, false, true); | 770 terminated_extensions_.Contains(extension_id)) |
771 if (extension) | |
772 return true; | 771 return true; |
773 | 772 |
774 extension = | 773 if (disabled_extensions_.Contains(extension_id)) |
775 GetExtensionByIdInternal(extension_id, false, true, false); | |
776 if (extension) | |
777 return false; | 774 return false; |
778 | 775 |
779 // If the extension hasn't been loaded yet, check the prefs for it. Assume | 776 // If the extension hasn't been loaded yet, check the prefs for it. Assume |
780 // enabled unless otherwise noted. | 777 // enabled unless otherwise noted. |
781 return !extension_prefs_->IsExtensionDisabled(extension_id) && | 778 return !extension_prefs_->IsExtensionDisabled(extension_id) && |
782 !extension_prefs_->IsExternalExtensionUninstalled(extension_id); | 779 !extension_prefs_->IsExternalExtensionUninstalled(extension_id); |
783 } | 780 } |
784 | 781 |
785 bool ExtensionService::IsExternalExtensionUninstalled( | 782 bool ExtensionService::IsExternalExtensionUninstalled( |
786 const std::string& extension_id) const { | 783 const std::string& extension_id) const { |
787 return extension_prefs_->IsExternalExtensionUninstalled(extension_id); | 784 return extension_prefs_->IsExternalExtensionUninstalled(extension_id); |
788 } | 785 } |
789 | 786 |
790 void ExtensionService::EnableExtension(const std::string& extension_id) { | 787 void ExtensionService::EnableExtension(const std::string& extension_id) { |
791 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 788 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
792 | 789 |
793 if (IsExtensionEnabled(extension_id)) | 790 if (IsExtensionEnabled(extension_id)) |
794 return; | 791 return; |
795 | 792 |
796 extension_prefs_->SetExtensionState(extension_id, Extension::ENABLED); | 793 extension_prefs_->SetExtensionState(extension_id, Extension::ENABLED); |
797 | 794 |
798 const Extension* extension = | 795 const Extension* extension = |
799 GetExtensionByIdInternal(extension_id, false, true, false); | 796 GetExtensionByIdInternal(extension_id, false, true, false); |
800 // This can happen if sync enables an extension that is not | 797 // This can happen if sync enables an extension that is not |
801 // installed yet. | 798 // installed yet. |
802 if (!extension) | 799 if (!extension) |
803 return; | 800 return; |
804 | 801 |
805 // Move it over to the enabled list. | 802 // Move it over to the enabled list. |
806 extensions_.push_back(make_scoped_refptr(extension)); | 803 extensions_.Insert(make_scoped_refptr(extension)); |
807 ExtensionList::iterator iter = std::find(disabled_extensions_.begin(), | 804 disabled_extensions_.Remove(extension->id()); |
808 disabled_extensions_.end(), | |
809 extension); | |
810 disabled_extensions_.erase(iter); | |
811 | 805 |
812 // Make sure any browser action contained within it is not hidden. | 806 // Make sure any browser action contained within it is not hidden. |
813 extension_prefs_->SetBrowserActionVisibility(extension, true); | 807 extension_prefs_->SetBrowserActionVisibility(extension, true); |
814 | 808 |
815 NotifyExtensionLoaded(extension); | 809 NotifyExtensionLoaded(extension); |
816 | 810 |
817 SyncExtensionChangeIfNeeded(*extension); | 811 SyncExtensionChangeIfNeeded(*extension); |
818 } | 812 } |
819 | 813 |
820 void ExtensionService::DisableExtension(const std::string& extension_id) { | 814 void ExtensionService::DisableExtension(const std::string& extension_id) { |
821 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 815 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
822 | 816 |
823 // The extension may have been disabled already. | 817 // The extension may have been disabled already. |
824 if (!IsExtensionEnabled(extension_id)) | 818 if (!IsExtensionEnabled(extension_id)) |
825 return; | 819 return; |
826 | 820 |
827 const Extension* extension = GetInstalledExtension(extension_id); | 821 const Extension* extension = GetInstalledExtension(extension_id); |
828 // |extension| can be NULL if sync disables an extension that is not | 822 // |extension| can be NULL if sync disables an extension that is not |
829 // installed yet. | 823 // installed yet. |
830 if (extension && !Extension::UserMayDisable(extension->location())) | 824 if (extension && !Extension::UserMayDisable(extension->location())) |
831 return; | 825 return; |
832 | 826 |
833 extension_prefs_->SetExtensionState(extension_id, Extension::DISABLED); | 827 extension_prefs_->SetExtensionState(extension_id, Extension::DISABLED); |
834 | 828 |
835 extension = GetExtensionByIdInternal(extension_id, true, false, true); | 829 extension = GetExtensionByIdInternal(extension_id, true, false, true); |
836 if (!extension) | 830 if (!extension) |
837 return; | 831 return; |
838 | 832 |
839 // Move it over to the disabled list. | 833 // Move it over to the disabled list. |
840 disabled_extensions_.push_back(make_scoped_refptr(extension)); | 834 disabled_extensions_.Insert(make_scoped_refptr(extension)); |
841 ExtensionList::iterator iter = std::find(extensions_.begin(), | 835 if (extensions_.Contains(extension->id())) |
842 extensions_.end(), | 836 extensions_.Remove(extension->id()); |
843 extension); | 837 else |
844 if (iter != extensions_.end()) { | 838 terminated_extensions_.Remove(extension->id()); |
845 extensions_.erase(iter); | |
846 } else { | |
847 iter = std::find(terminated_extensions_.begin(), | |
848 terminated_extensions_.end(), | |
849 extension); | |
850 terminated_extensions_.erase(iter); | |
851 } | |
852 | 839 |
853 NotifyExtensionUnloaded(extension, extension_misc::UNLOAD_REASON_DISABLE); | 840 NotifyExtensionUnloaded(extension, extension_misc::UNLOAD_REASON_DISABLE); |
854 | 841 |
855 SyncExtensionChangeIfNeeded(*extension); | 842 SyncExtensionChangeIfNeeded(*extension); |
856 | 843 |
857 // Deactivating one extension might have solved the problems of others. | 844 // Deactivating one extension might have solved the problems of others. |
858 // Therefore, we clear warnings of this type for all extensions. | 845 // Therefore, we clear warnings of this type for all extensions. |
859 std::set<ExtensionWarningSet::WarningType> warnings; | 846 std::set<ExtensionWarningSet::WarningType> warnings; |
860 extension_warnings_.GetWarningsAffectingExtension(extension_id, &warnings); | 847 extension_warnings_.GetWarningsAffectingExtension(extension_id, &warnings); |
861 extension_warnings_.ClearWarnings(warnings); | 848 extension_warnings_.ClearWarnings(warnings); |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1108 // Use this set to indicate if an extension in the blacklist has been used. | 1095 // Use this set to indicate if an extension in the blacklist has been used. |
1109 std::set<std::string> blacklist_set; | 1096 std::set<std::string> blacklist_set; |
1110 for (unsigned int i = 0; i < blacklist.size(); ++i) { | 1097 for (unsigned int i = 0; i < blacklist.size(); ++i) { |
1111 if (Extension::IdIsValid(blacklist[i])) { | 1098 if (Extension::IdIsValid(blacklist[i])) { |
1112 blacklist_set.insert(blacklist[i]); | 1099 blacklist_set.insert(blacklist[i]); |
1113 } | 1100 } |
1114 } | 1101 } |
1115 extension_prefs_->UpdateBlacklist(blacklist_set); | 1102 extension_prefs_->UpdateBlacklist(blacklist_set); |
1116 std::vector<std::string> to_be_removed; | 1103 std::vector<std::string> to_be_removed; |
1117 // Loop current extensions, unload installed extensions. | 1104 // Loop current extensions, unload installed extensions. |
1118 for (ExtensionList::const_iterator iter = extensions_.begin(); | 1105 for (ExtensionSet::const_iterator iter = extensions_.begin(); |
1119 iter != extensions_.end(); ++iter) { | 1106 iter != extensions_.end(); ++iter) { |
1120 const Extension* extension = (*iter); | 1107 const Extension* extension = (*iter); |
1121 if (blacklist_set.find(extension->id()) != blacklist_set.end()) { | 1108 if (blacklist_set.find(extension->id()) != blacklist_set.end()) { |
1122 to_be_removed.push_back(extension->id()); | 1109 to_be_removed.push_back(extension->id()); |
1123 } | 1110 } |
1124 } | 1111 } |
1125 | 1112 |
1126 // UnloadExtension will change the extensions_ list. So, we should | 1113 // UnloadExtension will change the extensions_ list. So, we should |
1127 // call it outside the iterator loop. | 1114 // call it outside the iterator loop. |
1128 for (unsigned int i = 0; i < to_be_removed.size(); ++i) { | 1115 for (unsigned int i = 0; i < to_be_removed.size(); ++i) { |
(...skipping 22 matching lines...) Expand all Loading... |
1151 return ready_; | 1138 return ready_; |
1152 } | 1139 } |
1153 | 1140 |
1154 ExtensionUpdater* ExtensionService::updater() { | 1141 ExtensionUpdater* ExtensionService::updater() { |
1155 return updater_.get(); | 1142 return updater_.get(); |
1156 } | 1143 } |
1157 | 1144 |
1158 void ExtensionService::CheckAdminBlacklist() { | 1145 void ExtensionService::CheckAdminBlacklist() { |
1159 std::vector<std::string> to_be_removed; | 1146 std::vector<std::string> to_be_removed; |
1160 // Loop through extensions list, unload installed extensions. | 1147 // Loop through extensions list, unload installed extensions. |
1161 for (ExtensionList::const_iterator iter = extensions_.begin(); | 1148 for (ExtensionSet::const_iterator iter = extensions_.begin(); |
1162 iter != extensions_.end(); ++iter) { | 1149 iter != extensions_.end(); ++iter) { |
1163 const Extension* extension = (*iter); | 1150 const Extension* extension = (*iter); |
1164 if (!extension_prefs_->IsExtensionAllowedByPolicy(extension->id(), | 1151 if (!extension_prefs_->IsExtensionAllowedByPolicy(extension->id(), |
1165 extension->location())) { | 1152 extension->location())) { |
1166 to_be_removed.push_back(extension->id()); | 1153 to_be_removed.push_back(extension->id()); |
1167 } | 1154 } |
1168 } | 1155 } |
1169 | 1156 |
1170 // UnloadExtension will change the extensions_ list. So, we should | 1157 // UnloadExtension will change the extensions_ list. So, we should |
1171 // call it outside the iterator loop. | 1158 // call it outside the iterator loop. |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1352 bundle->synced_extensions.erase(extension_sync_data.id()); | 1339 bundle->synced_extensions.erase(extension_sync_data.id()); |
1353 else | 1340 else |
1354 bundle->synced_extensions.insert(extension_sync_data.id()); | 1341 bundle->synced_extensions.insert(extension_sync_data.id()); |
1355 ProcessExtensionSyncData(extension_sync_data, *bundle); | 1342 ProcessExtensionSyncData(extension_sync_data, *bundle); |
1356 } | 1343 } |
1357 | 1344 |
1358 return SyncError(); | 1345 return SyncError(); |
1359 } | 1346 } |
1360 | 1347 |
1361 void ExtensionService::GetSyncDataListHelper( | 1348 void ExtensionService::GetSyncDataListHelper( |
1362 const ExtensionList& extensions, | 1349 const ExtensionSet& extensions, |
1363 const SyncBundle& bundle, | 1350 const SyncBundle& bundle, |
1364 std::vector<ExtensionSyncData>* sync_data_list) const { | 1351 std::vector<ExtensionSyncData>* sync_data_list) const { |
1365 for (ExtensionList::const_iterator it = extensions.begin(); | 1352 for (ExtensionSet::const_iterator it = extensions.begin(); |
1366 it != extensions.end(); ++it) { | 1353 it != extensions.end(); ++it) { |
1367 const Extension& extension = **it; | 1354 const Extension& extension = **it; |
1368 if (bundle.filter(extension) && | 1355 if (bundle.filter(extension) && |
1369 // If we have pending extension data for this extension, then this | 1356 // If we have pending extension data for this extension, then this |
1370 // version is out of date. We'll sync back the version we got from | 1357 // version is out of date. We'll sync back the version we got from |
1371 // sync. | 1358 // sync. |
1372 !bundle.HasPendingExtensionId(extension.id())) { | 1359 !bundle.HasPendingExtensionId(extension.id())) { |
1373 sync_data_list->push_back(ExtensionSyncData( | 1360 sync_data_list->push_back(ExtensionSyncData( |
1374 extension, | 1361 extension, |
1375 IsExtensionEnabled(extension.id()), | 1362 IsExtensionEnabled(extension.id()), |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1491 | 1478 |
1492 // Broadcast unloaded and loaded events to update browser state. Only bother | 1479 // Broadcast unloaded and loaded events to update browser state. Only bother |
1493 // if the value changed and the extension is actually enabled, since there is | 1480 // if the value changed and the extension is actually enabled, since there is |
1494 // no UI otherwise. | 1481 // no UI otherwise. |
1495 bool old_enabled = extension_prefs_->IsIncognitoEnabled(extension_id); | 1482 bool old_enabled = extension_prefs_->IsIncognitoEnabled(extension_id); |
1496 if (enabled == old_enabled) | 1483 if (enabled == old_enabled) |
1497 return; | 1484 return; |
1498 | 1485 |
1499 extension_prefs_->SetIsIncognitoEnabled(extension_id, enabled); | 1486 extension_prefs_->SetIsIncognitoEnabled(extension_id, enabled); |
1500 | 1487 |
1501 bool extension_is_enabled = std::find(extensions_.begin(), extensions_.end(), | 1488 bool extension_is_enabled = extensions_.Contains(extension->id()); |
1502 extension) != extensions_.end(); | |
1503 | 1489 |
1504 // When we reload the extension the ID may be invalidated if we've passed it | 1490 // When we reload the extension the ID may be invalidated if we've passed it |
1505 // by const ref everywhere. Make a copy to be safe. | 1491 // by const ref everywhere. Make a copy to be safe. |
1506 std::string id = extension_id; | 1492 std::string id = extension_id; |
1507 if (extension_is_enabled) | 1493 if (extension_is_enabled) |
1508 ReloadExtension(extension->id()); | 1494 ReloadExtension(extension->id()); |
1509 | 1495 |
1510 // Reloading the extension invalidates the |extension| pointer. | 1496 // Reloading the extension invalidates the |extension| pointer. |
1511 extension = GetInstalledExtension(id); | 1497 extension = GetInstalledExtension(id); |
1512 if (extension) | 1498 if (extension) |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1569 void ExtensionService::SetAllowFileAccess(const Extension* extension, | 1555 void ExtensionService::SetAllowFileAccess(const Extension* extension, |
1570 bool allow) { | 1556 bool allow) { |
1571 // Reload to update browser state. Only bother if the value changed and the | 1557 // Reload to update browser state. Only bother if the value changed and the |
1572 // extension is actually enabled, since there is no UI otherwise. | 1558 // extension is actually enabled, since there is no UI otherwise. |
1573 bool old_allow = AllowFileAccess(extension); | 1559 bool old_allow = AllowFileAccess(extension); |
1574 if (allow == old_allow) | 1560 if (allow == old_allow) |
1575 return; | 1561 return; |
1576 | 1562 |
1577 extension_prefs_->SetAllowFileAccess(extension->id(), allow); | 1563 extension_prefs_->SetAllowFileAccess(extension->id(), allow); |
1578 | 1564 |
1579 bool extension_is_enabled = std::find(extensions_.begin(), extensions_.end(), | 1565 bool extension_is_enabled = extensions_.Contains(extension->id()); |
1580 extension) != extensions_.end(); | |
1581 if (extension_is_enabled) | 1566 if (extension_is_enabled) |
1582 ReloadExtension(extension->id()); | 1567 ReloadExtension(extension->id()); |
1583 } | 1568 } |
1584 | 1569 |
1585 bool ExtensionService::GetBrowserActionVisibility(const Extension* extension) { | 1570 bool ExtensionService::GetBrowserActionVisibility(const Extension* extension) { |
1586 return extension_prefs_->GetBrowserActionVisibility(extension); | 1571 return extension_prefs_->GetBrowserActionVisibility(extension); |
1587 } | 1572 } |
1588 | 1573 |
1589 void ExtensionService::SetBrowserActionVisibility(const Extension* extension, | 1574 void ExtensionService::SetBrowserActionVisibility(const Extension* extension, |
1590 bool visible) { | 1575 bool visible) { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1674 switches::kEnableExtensionAlerts)) { | 1659 switches::kEnableExtensionAlerts)) { |
1675 return; // TODO(miket): enable unconditionally when done. | 1660 return; // TODO(miket): enable unconditionally when done. |
1676 } | 1661 } |
1677 | 1662 |
1678 // Build up the lists of extensions that require acknowledgment. | 1663 // Build up the lists of extensions that require acknowledgment. |
1679 // If this is the first time, grandfather extensions that would have | 1664 // If this is the first time, grandfather extensions that would have |
1680 // caused notification. | 1665 // caused notification. |
1681 scoped_ptr<ExtensionGlobalError> global_error( | 1666 scoped_ptr<ExtensionGlobalError> global_error( |
1682 new ExtensionGlobalError(AsWeakPtr())); | 1667 new ExtensionGlobalError(AsWeakPtr())); |
1683 bool needs_alert = false; | 1668 bool needs_alert = false; |
1684 for (ExtensionList::const_iterator iter = extensions_.begin(); | 1669 for (ExtensionSet::const_iterator iter = extensions_.begin(); |
1685 iter != extensions_.end(); ++iter) { | 1670 iter != extensions_.end(); ++iter) { |
1686 const Extension* e = *iter; | 1671 const Extension* e = *iter; |
1687 if (!IsExtensionEnabled(e->id())) { | |
1688 continue; | |
1689 } | |
1690 if (Extension::IsExternalLocation(e->location())) { | 1672 if (Extension::IsExternalLocation(e->location())) { |
1691 if (!extension_prefs_->IsExternalExtensionAcknowledged(e->id())) { | 1673 if (!extension_prefs_->IsExternalExtensionAcknowledged(e->id())) { |
1692 global_error->AddExternalExtension(e->id()); | 1674 global_error->AddExternalExtension(e->id()); |
1693 needs_alert = true; | 1675 needs_alert = true; |
1694 } | 1676 } |
1695 } | 1677 } |
1696 if (extension_prefs_->IsExtensionBlacklisted(e->id())) { | 1678 if (extension_prefs_->IsExtensionBlacklisted(e->id())) { |
1697 if (!extension_prefs_->IsBlacklistedExtensionAcknowledged(e->id())) { | 1679 if (!extension_prefs_->IsBlacklistedExtensionAcknowledged(e->id())) { |
1698 global_error->AddBlacklistedExtension(e->id()); | 1680 global_error->AddBlacklistedExtension(e->id()); |
1699 needs_alert = true; | 1681 needs_alert = true; |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1783 // Keep information about the extension so that we can reload it later | 1765 // Keep information about the extension so that we can reload it later |
1784 // even if it's not permanently installed. | 1766 // even if it's not permanently installed. |
1785 unloaded_extension_paths_[extension->id()] = extension->path(); | 1767 unloaded_extension_paths_[extension->id()] = extension->path(); |
1786 | 1768 |
1787 // Clean up if the extension is meant to be enabled after a reload. | 1769 // Clean up if the extension is meant to be enabled after a reload. |
1788 disabled_extension_paths_.erase(extension->id()); | 1770 disabled_extension_paths_.erase(extension->id()); |
1789 | 1771 |
1790 // Clean up runtime data. | 1772 // Clean up runtime data. |
1791 extension_runtime_data_.erase(extension_id); | 1773 extension_runtime_data_.erase(extension_id); |
1792 | 1774 |
1793 ExtensionList::iterator iter = std::find(disabled_extensions_.begin(), | 1775 if (disabled_extensions_.Contains(extension->id())) { |
1794 disabled_extensions_.end(), | |
1795 extension.get()); | |
1796 if (iter != disabled_extensions_.end()) { | |
1797 UnloadedExtensionInfo details(extension, reason); | 1776 UnloadedExtensionInfo details(extension, reason); |
1798 details.already_disabled = true; | 1777 details.already_disabled = true; |
1799 disabled_extensions_.erase(iter); | 1778 disabled_extensions_.Remove(extension->id()); |
1800 content::NotificationService::current()->Notify( | 1779 content::NotificationService::current()->Notify( |
1801 chrome::NOTIFICATION_EXTENSION_UNLOADED, | 1780 chrome::NOTIFICATION_EXTENSION_UNLOADED, |
1802 content::Source<Profile>(profile_), | 1781 content::Source<Profile>(profile_), |
1803 content::Details<UnloadedExtensionInfo>(&details)); | 1782 content::Details<UnloadedExtensionInfo>(&details)); |
1804 // Make sure the profile cleans up its RequestContexts when an already | 1783 // Make sure the profile cleans up its RequestContexts when an already |
1805 // disabled extension is unloaded (since they are also tracking the disabled | 1784 // disabled extension is unloaded (since they are also tracking the disabled |
1806 // extensions). | 1785 // extensions). |
1807 profile_->UnregisterExtensionWithRequestContexts(extension_id, reason); | 1786 profile_->UnregisterExtensionWithRequestContexts(extension_id, reason); |
1808 return; | 1787 return; |
1809 } | 1788 } |
1810 | 1789 |
1811 iter = std::find(extensions_.begin(), extensions_.end(), extension.get()); | 1790 // Remove the extension from our list. |
1812 | 1791 extensions_.Remove(extension->id()); |
1813 // Remove the extension from our list. | |
1814 extensions_.erase(iter); | |
1815 | 1792 |
1816 NotifyExtensionUnloaded(extension.get(), reason); | 1793 NotifyExtensionUnloaded(extension.get(), reason); |
1817 } | 1794 } |
1818 | 1795 |
1819 void ExtensionService::UnloadAllExtensions() { | 1796 void ExtensionService::UnloadAllExtensions() { |
1820 profile_->GetExtensionSpecialStoragePolicy()-> | 1797 profile_->GetExtensionSpecialStoragePolicy()-> |
1821 RevokeRightsForAllExtensions(); | 1798 RevokeRightsForAllExtensions(); |
1822 | 1799 |
1823 extensions_.clear(); | 1800 extensions_.Clear(); |
1824 disabled_extensions_.clear(); | 1801 disabled_extensions_.Clear(); |
1825 terminated_extension_ids_.clear(); | 1802 terminated_extensions_.Clear(); |
1826 terminated_extensions_.clear(); | |
1827 extension_runtime_data_.clear(); | 1803 extension_runtime_data_.clear(); |
1828 | 1804 |
1829 // TODO(erikkay) should there be a notification for this? We can't use | 1805 // TODO(erikkay) should there be a notification for this? We can't use |
1830 // EXTENSION_UNLOADED since that implies that the extension has been disabled | 1806 // EXTENSION_UNLOADED since that implies that the extension has been disabled |
1831 // or uninstalled, and UnloadAll is just part of shutdown. | 1807 // or uninstalled, and UnloadAll is just part of shutdown. |
1832 } | 1808 } |
1833 | 1809 |
1834 void ExtensionService::ReloadExtensions() { | 1810 void ExtensionService::ReloadExtensions() { |
1835 UnloadAllExtensions(); | 1811 UnloadAllExtensions(); |
1836 component_loader_->LoadAll(); | 1812 component_loader_->LoadAll(); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1900 // If the extension was disabled for a reload, then enable it. | 1876 // If the extension was disabled for a reload, then enable it. |
1901 if (disabled_extension_paths_.erase(extension->id()) > 0) | 1877 if (disabled_extension_paths_.erase(extension->id()) > 0) |
1902 EnableExtension(extension->id()); | 1878 EnableExtension(extension->id()); |
1903 | 1879 |
1904 // Check if the extension's privileges have changed and disable the | 1880 // Check if the extension's privileges have changed and disable the |
1905 // extension if necessary. | 1881 // extension if necessary. |
1906 InitializePermissions(extension); | 1882 InitializePermissions(extension); |
1907 | 1883 |
1908 bool disabled = extension_prefs_->IsExtensionDisabled(extension->id()); | 1884 bool disabled = extension_prefs_->IsExtensionDisabled(extension->id()); |
1909 if (disabled) { | 1885 if (disabled) { |
1910 disabled_extensions_.push_back(scoped_extension); | 1886 disabled_extensions_.Insert(scoped_extension); |
1911 // TODO(aa): This seems dodgy. It seems that AddExtension() could get called | 1887 // TODO(aa): This seems dodgy. AddExtension() could get called with a |
1912 // with a disabled extension for other reasons other than that an update was | 1888 // disabled extension for other reasons other than that an update was |
1913 // disabled. | 1889 // disabled, e.g. as in ExtensionManagementTest.InstallRequiresConfirm. |
1914 content::NotificationService::current()->Notify( | 1890 content::NotificationService::current()->Notify( |
1915 chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED, | 1891 chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED, |
1916 content::Source<Profile>(profile_), | 1892 content::Source<Profile>(profile_), |
1917 content::Details<const Extension>(extension)); | 1893 content::Details<const Extension>(extension)); |
1918 SyncExtensionChangeIfNeeded(*extension); | 1894 SyncExtensionChangeIfNeeded(*extension); |
1919 return; | 1895 return; |
1920 } | 1896 } |
1921 | 1897 |
1922 extensions_.push_back(scoped_extension); | 1898 extensions_.Insert(scoped_extension); |
1923 SyncExtensionChangeIfNeeded(*extension); | 1899 SyncExtensionChangeIfNeeded(*extension); |
1924 NotifyExtensionLoaded(extension); | 1900 NotifyExtensionLoaded(extension); |
1925 IdentifyAlertableExtensions(); | 1901 IdentifyAlertableExtensions(); |
1926 } | 1902 } |
1927 | 1903 |
1928 void ExtensionService::InitializePermissions(const Extension* extension) { | 1904 void ExtensionService::InitializePermissions(const Extension* extension) { |
1929 // If the extension has used the optional permissions API, it will have a | 1905 // If the extension has used the optional permissions API, it will have a |
1930 // custom set of active permissions defined in the extension prefs. Here, | 1906 // custom set of active permissions defined in the extension prefs. Here, |
1931 // we update the extension's active permissions based on the prefs. | 1907 // we update the extension's active permissions based on the prefs. |
1932 scoped_refptr<ExtensionPermissionSet> active_permissions = | 1908 scoped_refptr<ExtensionPermissionSet> active_permissions = |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2024 RecordPermissionMessagesHistogram( | 2000 RecordPermissionMessagesHistogram( |
2025 extension, "Extensions.Permissions_AutoDisable"); | 2001 extension, "Extensions.Permissions_AutoDisable"); |
2026 } | 2002 } |
2027 extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED); | 2003 extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED); |
2028 extension_prefs_->SetDidExtensionEscalatePermissions(extension, true); | 2004 extension_prefs_->SetDidExtensionEscalatePermissions(extension, true); |
2029 } | 2005 } |
2030 } | 2006 } |
2031 | 2007 |
2032 void ExtensionService::UpdateActiveExtensionsInCrashReporter() { | 2008 void ExtensionService::UpdateActiveExtensionsInCrashReporter() { |
2033 std::set<std::string> extension_ids; | 2009 std::set<std::string> extension_ids; |
2034 for (size_t i = 0; i < extensions_.size(); ++i) { | 2010 for (ExtensionSet::const_iterator iter = extensions_.begin(); |
2035 if (!extensions_[i]->is_theme() && | 2011 iter != extensions_.end(); ++iter) { |
2036 extensions_[i]->location() != Extension::COMPONENT) | 2012 const Extension* extension = *iter; |
2037 extension_ids.insert(extensions_[i]->id()); | 2013 if (!extension->is_theme() && extension->location() != Extension::COMPONENT) |
| 2014 extension_ids.insert(extension->id()); |
2038 } | 2015 } |
2039 | 2016 |
2040 child_process_logging::SetActiveExtensions(extension_ids); | 2017 child_process_logging::SetActiveExtensions(extension_ids); |
2041 } | 2018 } |
2042 | 2019 |
2043 void ExtensionService::OnExtensionInstalled( | 2020 void ExtensionService::OnExtensionInstalled( |
2044 const Extension* extension, bool from_webstore, int page_index) { | 2021 const Extension* extension, bool from_webstore, int page_index) { |
2045 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 2022 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
2046 | 2023 |
2047 // Ensure extension is deleted unless we transfer ownership. | 2024 // Ensure extension is deleted unless we transfer ownership. |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2120 | 2097 |
2121 // Transfer ownership of |extension| to AddExtension. | 2098 // Transfer ownership of |extension| to AddExtension. |
2122 AddExtension(scoped_extension); | 2099 AddExtension(scoped_extension); |
2123 } | 2100 } |
2124 | 2101 |
2125 const Extension* ExtensionService::GetExtensionByIdInternal( | 2102 const Extension* ExtensionService::GetExtensionByIdInternal( |
2126 const std::string& id, bool include_enabled, bool include_disabled, | 2103 const std::string& id, bool include_enabled, bool include_disabled, |
2127 bool include_terminated) const { | 2104 bool include_terminated) const { |
2128 std::string lowercase_id = StringToLowerASCII(id); | 2105 std::string lowercase_id = StringToLowerASCII(id); |
2129 if (include_enabled) { | 2106 if (include_enabled) { |
2130 for (ExtensionList::const_iterator iter = extensions_.begin(); | 2107 const Extension* extension = extensions_.GetByID(lowercase_id); |
2131 iter != extensions_.end(); ++iter) { | 2108 if (extension) |
2132 if ((*iter)->id() == lowercase_id) | 2109 return extension; |
2133 return *iter; | |
2134 } | |
2135 } | 2110 } |
2136 if (include_disabled) { | 2111 if (include_disabled) { |
2137 for (ExtensionList::const_iterator iter = disabled_extensions_.begin(); | 2112 const Extension* extension = disabled_extensions_.GetByID(lowercase_id); |
2138 iter != disabled_extensions_.end(); ++iter) { | 2113 if (extension) |
2139 if ((*iter)->id() == lowercase_id) | 2114 return extension; |
2140 return *iter; | |
2141 } | |
2142 } | 2115 } |
2143 if (include_terminated) { | 2116 if (include_terminated) { |
2144 for (ExtensionList::const_iterator iter = terminated_extensions_.begin(); | 2117 const Extension* extension = terminated_extensions_.GetByID(lowercase_id); |
2145 iter != terminated_extensions_.end(); ++iter) { | 2118 if (extension) |
2146 if ((*iter)->id() == lowercase_id) | 2119 return extension; |
2147 return *iter; | |
2148 } | |
2149 } | 2120 } |
2150 return NULL; | 2121 return NULL; |
2151 } | 2122 } |
2152 | 2123 |
2153 void ExtensionService::TrackTerminatedExtension(const Extension* extension) { | 2124 void ExtensionService::TrackTerminatedExtension(const Extension* extension) { |
2154 if (terminated_extension_ids_.insert(extension->id()).second) | 2125 if (!terminated_extensions_.Contains(extension->id())) |
2155 terminated_extensions_.push_back(make_scoped_refptr(extension)); | 2126 terminated_extensions_.Insert(make_scoped_refptr(extension)); |
2156 | 2127 |
2157 // TODO(yoz): Listen to navcontrollers for that extension. Is this a todo? | |
2158 | |
2159 // TODO(yoz): make sure this is okay in *ALL* the listeners! | |
2160 UnloadExtension(extension->id(), extension_misc::UNLOAD_REASON_TERMINATE); | 2128 UnloadExtension(extension->id(), extension_misc::UNLOAD_REASON_TERMINATE); |
2161 } | 2129 } |
2162 | 2130 |
2163 void ExtensionService::UntrackTerminatedExtension(const std::string& id) { | 2131 void ExtensionService::UntrackTerminatedExtension(const std::string& id) { |
2164 std::string lowercase_id = StringToLowerASCII(id); | 2132 std::string lowercase_id = StringToLowerASCII(id); |
2165 if (terminated_extension_ids_.erase(lowercase_id) <= 0) | 2133 terminated_extensions_.Remove(lowercase_id); |
2166 return; | |
2167 | |
2168 for (ExtensionList::iterator iter = terminated_extensions_.begin(); | |
2169 iter != terminated_extensions_.end(); ++iter) { | |
2170 if ((*iter)->id() == lowercase_id) { | |
2171 terminated_extensions_.erase(iter); | |
2172 return; | |
2173 } | |
2174 } | |
2175 } | 2134 } |
2176 | 2135 |
2177 const Extension* ExtensionService::GetTerminatedExtension( | 2136 const Extension* ExtensionService::GetTerminatedExtension( |
2178 const std::string& id) const { | 2137 const std::string& id) const { |
2179 return GetExtensionByIdInternal(id, false, false, true); | 2138 return GetExtensionByIdInternal(id, false, false, true); |
2180 } | 2139 } |
2181 | 2140 |
2182 const Extension* ExtensionService::GetInstalledExtension( | 2141 const Extension* ExtensionService::GetInstalledExtension( |
2183 const std::string& id) const { | 2142 const std::string& id) const { |
2184 return GetExtensionByIdInternal(id, true, true, true); | 2143 return GetExtensionByIdInternal(id, true, true, true); |
2185 } | 2144 } |
2186 | 2145 |
2187 const Extension* ExtensionService::GetWebStoreApp() { | 2146 const Extension* ExtensionService::GetWebStoreApp() { |
2188 return GetExtensionById(extension_misc::kWebStoreAppId, false); | 2147 return GetExtensionById(extension_misc::kWebStoreAppId, false); |
2189 } | 2148 } |
2190 | 2149 |
2191 const Extension* ExtensionService::GetExtensionByURL(const GURL& url) { | 2150 const Extension* ExtensionService::GetExtensionByURL(const GURL& url) { |
2192 return url.scheme() != chrome::kExtensionScheme ? NULL : | 2151 return url.scheme() != chrome::kExtensionScheme ? NULL : |
2193 GetExtensionById(url.host(), false); | 2152 GetExtensionById(url.host(), false); |
2194 } | 2153 } |
2195 | 2154 |
2196 const Extension* ExtensionService::GetExtensionByWebExtent(const GURL& url) { | 2155 const Extension* ExtensionService::GetExtensionByWebExtent(const GURL& url) { |
2197 for (size_t i = 0; i < extensions_.size(); ++i) { | 2156 // TODO(yoz): Should be ExtensionSet::GetByURL. |
2198 if (extensions_[i]->web_extent().MatchesURL(url)) | 2157 for (ExtensionSet::const_iterator iter = extensions_.begin(); |
2199 return extensions_[i]; | 2158 iter != extensions_.end(); ++iter) { |
| 2159 if ((*iter)->web_extent().MatchesURL(url)) |
| 2160 return *iter; |
2200 } | 2161 } |
2201 return NULL; | 2162 return NULL; |
2202 } | 2163 } |
2203 | 2164 |
2204 const Extension* ExtensionService::GetDisabledExtensionByWebExtent( | 2165 const Extension* ExtensionService::GetDisabledExtensionByWebExtent( |
2205 const GURL& url) { | 2166 const GURL& url) { |
2206 for (size_t i = 0; i < disabled_extensions_.size(); ++i) { | 2167 // TODO(yoz): Should be ExtensionSet::GetByURL. |
2207 if (disabled_extensions_[i]->web_extent().MatchesURL(url)) | 2168 for (ExtensionSet::const_iterator iter = disabled_extensions_.begin(); |
2208 return disabled_extensions_[i]; | 2169 iter != disabled_extensions_.end(); ++iter) { |
| 2170 if ((*iter)->web_extent().MatchesURL(url)) |
| 2171 return *iter; |
2209 } | 2172 } |
2210 return NULL; | 2173 return NULL; |
2211 } | 2174 } |
2212 | 2175 |
2213 bool ExtensionService::ExtensionBindingsAllowed(const GURL& url) { | 2176 bool ExtensionService::ExtensionBindingsAllowed(const GURL& url) { |
2214 // Allow bindings for all packaged extensions. | 2177 // Allow bindings for all packaged extensions. |
2215 // Note that GetExtensionByURL may return an Extension for hosted apps | 2178 // Note that GetExtensionByURL may return an Extension for hosted apps |
2216 // (excluding bookmark apps) if the URL came from GetEffectiveURL. | 2179 // (excluding bookmark apps) if the URL came from GetEffectiveURL. |
2217 const Extension* extension = GetExtensionByURL(url); | 2180 const Extension* extension = GetExtensionByURL(url); |
2218 if (extension && extension->GetType() != Extension::TYPE_HOSTED_APP) | 2181 if (extension && extension->GetType() != Extension::TYPE_HOSTED_APP) |
2219 return true; | 2182 return true; |
2220 | 2183 |
2221 // Allow bindings for all component, hosted apps. | 2184 // Allow bindings for all component, hosted apps. |
2222 if (!extension) | 2185 if (!extension) |
2223 extension = GetExtensionByWebExtent(url); | 2186 extension = GetExtensionByWebExtent(url); |
2224 return (extension && extension->location() == Extension::COMPONENT); | 2187 return (extension && extension->location() == Extension::COMPONENT); |
2225 } | 2188 } |
2226 | 2189 |
2227 const Extension* ExtensionService::GetExtensionByOverlappingWebExtent( | 2190 const Extension* ExtensionService::GetExtensionByOverlappingWebExtent( |
2228 const URLPatternSet& extent) { | 2191 const URLPatternSet& extent) { |
2229 for (size_t i = 0; i < extensions_.size(); ++i) { | 2192 // TODO(yoz): Should be in ExtensionSet. |
2230 if (extensions_[i]->web_extent().OverlapsWith(extent)) | 2193 for (ExtensionSet::const_iterator iter = extensions_.begin(); |
2231 return extensions_[i]; | 2194 iter != extensions_.end(); ++iter) { |
| 2195 if ((*iter)->web_extent().OverlapsWith(extent)) |
| 2196 return *iter; |
2232 } | 2197 } |
2233 | 2198 |
2234 return NULL; | 2199 return NULL; |
2235 } | 2200 } |
2236 | 2201 |
2237 const SkBitmap& ExtensionService::GetOmniboxIcon( | 2202 const SkBitmap& ExtensionService::GetOmniboxIcon( |
2238 const std::string& extension_id) { | 2203 const std::string& extension_id) { |
2239 return omnibox_icon_manager_.GetIcon(extension_id); | 2204 return omnibox_icon_manager_.GetIcon(extension_id); |
2240 } | 2205 } |
2241 | 2206 |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2363 ExtensionFunctionDispatcher::GetAllFunctionNames(&function_names); | 2328 ExtensionFunctionDispatcher::GetAllFunctionNames(&function_names); |
2364 process->Send(new ExtensionMsg_SetFunctionNames(function_names)); | 2329 process->Send(new ExtensionMsg_SetFunctionNames(function_names)); |
2365 | 2330 |
2366 // Scripting whitelist. This is modified by tests and must be communicated | 2331 // Scripting whitelist. This is modified by tests and must be communicated |
2367 // to renderers. | 2332 // to renderers. |
2368 process->Send(new ExtensionMsg_SetScriptingWhitelist( | 2333 process->Send(new ExtensionMsg_SetScriptingWhitelist( |
2369 *Extension::GetScriptingWhitelist())); | 2334 *Extension::GetScriptingWhitelist())); |
2370 | 2335 |
2371 // Loaded extensions. | 2336 // Loaded extensions. |
2372 std::vector<ExtensionMsg_Loaded_Params> loaded_extensions; | 2337 std::vector<ExtensionMsg_Loaded_Params> loaded_extensions; |
2373 for (size_t i = 0; i < extensions_.size(); ++i) { | 2338 for (ExtensionSet::const_iterator iter = extensions_.begin(); |
2374 loaded_extensions.push_back( | 2339 iter != extensions_.end(); ++iter) { |
2375 ExtensionMsg_Loaded_Params(extensions_[i])); | 2340 loaded_extensions.push_back(ExtensionMsg_Loaded_Params(*iter)); |
2376 } | 2341 } |
2377 process->Send(new ExtensionMsg_Loaded(loaded_extensions)); | 2342 process->Send(new ExtensionMsg_Loaded(loaded_extensions)); |
2378 break; | 2343 break; |
2379 } | 2344 } |
2380 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: { | 2345 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: { |
2381 content::RenderProcessHost* process = | 2346 content::RenderProcessHost* process = |
2382 content::Source<content::RenderProcessHost>(source).ptr(); | 2347 content::Source<content::RenderProcessHost>(source).ptr(); |
2383 Profile* host_profile = | 2348 Profile* host_profile = |
2384 Profile::FromBrowserContext(process->GetBrowserContext()); | 2349 Profile::FromBrowserContext(process->GetBrowserContext()); |
2385 if (!profile_->IsSameProfile(host_profile->GetOriginalProfile())) | 2350 if (!profile_->IsSameProfile(host_profile->GetOriginalProfile())) |
(...skipping 30 matching lines...) Expand all Loading... |
2416 NOTREACHED() << "Unexpected notification type."; | 2381 NOTREACHED() << "Unexpected notification type."; |
2417 } | 2382 } |
2418 } | 2383 } |
2419 | 2384 |
2420 bool ExtensionService::HasApps() const { | 2385 bool ExtensionService::HasApps() const { |
2421 return !GetAppIds().empty(); | 2386 return !GetAppIds().empty(); |
2422 } | 2387 } |
2423 | 2388 |
2424 ExtensionIdSet ExtensionService::GetAppIds() const { | 2389 ExtensionIdSet ExtensionService::GetAppIds() const { |
2425 ExtensionIdSet result; | 2390 ExtensionIdSet result; |
2426 for (ExtensionList::const_iterator it = extensions_.begin(); | 2391 for (ExtensionSet::const_iterator it = extensions_.begin(); |
2427 it != extensions_.end(); ++it) { | 2392 it != extensions_.end(); ++it) { |
2428 if ((*it)->is_app() && (*it)->location() != Extension::COMPONENT) | 2393 if ((*it)->is_app() && (*it)->location() != Extension::COMPONENT) |
2429 result.insert((*it)->id()); | 2394 result.insert((*it)->id()); |
2430 } | 2395 } |
2431 | 2396 |
2432 return result; | 2397 return result; |
2433 } | 2398 } |
2434 | 2399 |
2435 bool ExtensionService::IsBackgroundPageReady(const Extension* extension) { | 2400 bool ExtensionService::IsBackgroundPageReady(const Extension* extension) { |
2436 return (extension->background_url().is_empty() || | 2401 return (extension->background_url().is_empty() || |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2535 | 2500 |
2536 ExtensionService::NaClModuleInfoList::iterator | 2501 ExtensionService::NaClModuleInfoList::iterator |
2537 ExtensionService::FindNaClModule(const GURL& url) { | 2502 ExtensionService::FindNaClModule(const GURL& url) { |
2538 for (NaClModuleInfoList::iterator iter = nacl_module_list_.begin(); | 2503 for (NaClModuleInfoList::iterator iter = nacl_module_list_.begin(); |
2539 iter != nacl_module_list_.end(); ++iter) { | 2504 iter != nacl_module_list_.end(); ++iter) { |
2540 if (iter->url == url) | 2505 if (iter->url == url) |
2541 return iter; | 2506 return iter; |
2542 } | 2507 } |
2543 return nacl_module_list_.end(); | 2508 return nacl_module_list_.end(); |
2544 } | 2509 } |
OLD | NEW |