diff options
author | scheib@chromium.org <scheib@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-09 17:03:05 +0000 |
---|---|---|
committer | scheib@chromium.org <scheib@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-09 17:03:05 +0000 |
commit | f8e46614369594c29c72b0ae1a4b53ad259ed4af (patch) | |
tree | cbc40ffedb2a18b0c7f4d664dfbe80f031d923c8 /chrome/browser | |
parent | 68e301f49a64e5fa5cce8cb3a8dd6e6ffbfcc173 (diff) | |
download | chromium_src-f8e46614369594c29c72b0ae1a4b53ad259ed4af.zip chromium_src-f8e46614369594c29c72b0ae1a4b53ad259ed4af.tar.gz chromium_src-f8e46614369594c29c72b0ae1a4b53ad259ed4af.tar.bz2 |
Unload all apps / extensions immediately when deleting a profile.
Previously apps could remain running with references to profiles that had been deleted by users, but before the browser shut down and profiles were fully removed. Problems included E.g. opening a link in an app would open a tab in the deleted profile.
BUG=368684
TEST=Manual testing as described on http://crbug.com/368684#c1
Review URL: https://codereview.chromium.org/266343002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@269343 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/background/background_contents_service.cc | 3 | ||||
-rw-r--r-- | chrome/browser/chrome_notification_types.h | 6 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_service.cc | 16 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_service.h | 5 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_service_unittest.cc | 40 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_manager.cc | 7 | ||||
-rw-r--r-- | chrome/browser/ui/browser.cc | 5 |
7 files changed, 76 insertions, 6 deletions
diff --git a/chrome/browser/background/background_contents_service.cc b/chrome/browser/background/background_contents_service.cc index 0d21871..b83decd 100644 --- a/chrome/browser/background/background_contents_service.cc +++ b/chrome/browser/background/background_contents_service.cc @@ -468,7 +468,8 @@ void BackgroundContentsService::Observe( case UnloadedExtensionInfo::REASON_DISABLE: // Fall through. case UnloadedExtensionInfo::REASON_TERMINATE: // Fall through. case UnloadedExtensionInfo::REASON_UNINSTALL: // Fall through. - case UnloadedExtensionInfo::REASON_BLACKLIST: + case UnloadedExtensionInfo::REASON_BLACKLIST: // Fall through. + case UnloadedExtensionInfo::REASON_PROFILE_SHUTDOWN: ShutdownAssociatedBackgroundContents(base::ASCIIToUTF16( content::Details<UnloadedExtensionInfo>(details)-> extension->id())); diff --git a/chrome/browser/chrome_notification_types.h b/chrome/browser/chrome_notification_types.h index eb5ed40..d0490ed 100644 --- a/chrome/browser/chrome_notification_types.h +++ b/chrome/browser/chrome_notification_types.h @@ -293,6 +293,12 @@ enum NotificationType { // The details are none and the source is the new profile. NOTIFICATION_PROFILE_ADDED, + // Sent early in the process of destroying a Profile, at the time a user + // initiates the deletion of a profile versus the much later time when the + // profile object is actually destroyed (use NOTIFICATION_PROFILE_DESTROYED). + // The details are none and the source is a Profile*. + NOTIFICATION_PROFILE_DESTRUCTION_STARTED, + // Sent before a Profile is destroyed. This notification is sent both for // normal and OTR profiles. // The details are none and the source is a Profile*. diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index fd12b351..884edb7 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc @@ -301,6 +301,9 @@ ExtensionService::ExtensionService(Profile* profile, content::NotificationService::AllBrowserContextsAndSources()); registrar_.Add(this, chrome::NOTIFICATION_UPGRADE_RECOMMENDED, content::NotificationService::AllBrowserContextsAndSources()); + registrar_.Add(this, + chrome::NOTIFICATION_PROFILE_DESTRUCTION_STARTED, + content::Source<Profile>(profile_)); pref_change_registrar_.Init(profile->GetPrefs()); base::Closure callback = base::Bind(&ExtensionService::OnExtensionInstallPrefChanged, @@ -2152,6 +2155,10 @@ void ExtensionService::Observe(int type, OnChromeUpdateAvailable()); break; } + case chrome::NOTIFICATION_PROFILE_DESTRUCTION_STARTED: { + OnProfileDestructionStarted(); + break; + } default: NOTREACHED() << "Unexpected notification type."; @@ -2419,3 +2426,12 @@ void ExtensionService::UnloadAllExtensionsInternal() { // EXTENSION_UNLOADED since that implies that the extension has been disabled // or uninstalled. } + +void ExtensionService::OnProfileDestructionStarted() { + ExtensionIdSet ids_to_unload = registry_->enabled_extensions().GetIDs(); + for (ExtensionIdSet::iterator it = ids_to_unload.begin(); + it != ids_to_unload.end(); + ++it) { + UnloadExtension(*it, UnloadedExtensionInfo::REASON_PROFILE_SHUTDOWN); + } +} diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h index ca80400..5e239cb 100644 --- a/chrome/browser/extensions/extension_service.h +++ b/chrome/browser/extensions/extension_service.h @@ -562,6 +562,11 @@ class ExtensionService // Used only by test code. void UnloadAllExtensionsInternal(); + // Disable apps & extensions now to stop them from running after a profile + // has been conceptually deleted. Don't wait for full browser shutdown and + // the actual profile objects to be destroyed. + void OnProfileDestructionStarted(); + // The normal profile associated with this ExtensionService. Profile* profile_; diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index bbbff27..58933ef 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc @@ -165,6 +165,7 @@ using extensions::FeatureSwitch; using extensions::Manifest; using extensions::PermissionSet; using extensions::TestExtensionSystem; +using extensions::UnloadedExtensionInfo; using extensions::URLPatternSet; namespace keys = extensions::manifest_keys; @@ -666,10 +667,12 @@ class ExtensionServiceTest : public ExtensionServiceTestBase, public content::NotificationObserver { public: ExtensionServiceTest() - : installed_(NULL), + : unloaded_reason_(UnloadedExtensionInfo::REASON_UNDEFINED), + installed_(NULL), was_update_(false), override_external_install_prompt_( - FeatureSwitch::prompt_for_external_extensions(), false) { + FeatureSwitch::prompt_for_external_extensions(), + false) { registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, content::NotificationService::AllSources()); @@ -694,10 +697,11 @@ class ExtensionServiceTest } case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: { - const Extension* e = - content::Details<extensions::UnloadedExtensionInfo>( - details)->extension; + UnloadedExtensionInfo* unloaded_info = + content::Details<UnloadedExtensionInfo>(details).ptr(); + const Extension* e = unloaded_info->extension; unloaded_id_ = e->id(); + unloaded_reason_ = unloaded_info->reason; extensions::ExtensionList::iterator i = std::find(loaded_.begin(), loaded_.end(), e); // TODO(erikkay) fix so this can be an assert. Right now the tests @@ -1250,6 +1254,7 @@ class ExtensionServiceTest protected: extensions::ExtensionList loaded_; std::string unloaded_id_; + UnloadedExtensionInfo::Reason unloaded_reason_; const Extension* installed_; bool was_update_; std::string old_name_; @@ -4167,6 +4172,7 @@ TEST_F(ExtensionServiceTest, UninstallExtension) { EXPECT_EQ(1u, registry_->enabled_extensions().size()); UninstallExtension(good_crx, false); EXPECT_EQ(0u, registry_->enabled_extensions().size()); + EXPECT_EQ(UnloadedExtensionInfo::REASON_UNINSTALL, unloaded_reason_); } TEST_F(ExtensionServiceTest, UninstallTerminatedExtension) { @@ -4174,6 +4180,7 @@ TEST_F(ExtensionServiceTest, UninstallTerminatedExtension) { InstallCRX(data_dir_.AppendASCII("good.crx"), INSTALL_NEW); TerminateExtension(good_crx); UninstallExtension(good_crx, false); + EXPECT_EQ(UnloadedExtensionInfo::REASON_TERMINATE, unloaded_reason_); } // Tests the uninstaller helper. @@ -4181,6 +4188,7 @@ TEST_F(ExtensionServiceTest, UninstallExtensionHelper) { InitializeEmptyExtensionService(); InstallCRX(data_dir_.AppendASCII("good.crx"), INSTALL_NEW); UninstallExtension(good_crx, true); + EXPECT_EQ(UnloadedExtensionInfo::REASON_UNINSTALL, unloaded_reason_); } TEST_F(ExtensionServiceTest, UninstallExtensionHelperTerminated) { @@ -4188,6 +4196,7 @@ TEST_F(ExtensionServiceTest, UninstallExtensionHelperTerminated) { InstallCRX(data_dir_.AppendASCII("good.crx"), INSTALL_NEW); TerminateExtension(good_crx); UninstallExtension(good_crx, true); + EXPECT_EQ(UnloadedExtensionInfo::REASON_TERMINATE, unloaded_reason_); } // An extension disabled because of unsupported requirements should re-enabled @@ -6917,3 +6926,24 @@ TEST_F(ExtensionServiceTest, ReconcileKnownDisabledWithSideEnable) { EXPECT_EQ(expected_disabled_extensions, registry_->disabled_extensions().GetIDs()); } + +// Tests a profile being destroyed correctly disables extensions. +TEST_F(ExtensionServiceTest, DestroyingProfileClearsExtensions) { + InitializeEmptyExtensionService(); + + InstallCRX(data_dir_.AppendASCII("good.crx"), INSTALL_NEW); + EXPECT_NE(UnloadedExtensionInfo::REASON_PROFILE_SHUTDOWN, unloaded_reason_); + EXPECT_EQ(1u, registry_->enabled_extensions().size()); + EXPECT_EQ(0u, registry_->disabled_extensions().size()); + EXPECT_EQ(0u, registry_->terminated_extensions().size()); + EXPECT_EQ(0u, registry_->blacklisted_extensions().size()); + + service_->Observe(chrome::NOTIFICATION_PROFILE_DESTRUCTION_STARTED, + content::Source<Profile>(profile_.get()), + content::NotificationService::NoDetails()); + EXPECT_EQ(UnloadedExtensionInfo::REASON_PROFILE_SHUTDOWN, unloaded_reason_); + EXPECT_EQ(0u, registry_->enabled_extensions().size()); + EXPECT_EQ(0u, registry_->disabled_extensions().size()); + EXPECT_EQ(0u, registry_->terminated_extensions().size()); + EXPECT_EQ(0u, registry_->blacklisted_extensions().size()); +} diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc index 9e25b1d..74c90ed 100644 --- a/chrome/browser/profiles/profile_manager.cc +++ b/chrome/browser/profiles/profile_manager.cc @@ -1085,6 +1085,13 @@ void ProfileManager::FinishDeletingProfile(const base::FilePath& profile_dir) { Profile* profile = GetProfileByPath(profile_dir); if (profile) { + // TODO: Migrate additional code in this block to observe this notification + // instead of being implemented here. + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_PROFILE_DESTRUCTION_STARTED, + content::Source<Profile>(profile), + content::NotificationService::NoDetails()); + // By this point, all in-progress downloads for the profile being deleted // must have been canceled (crbug.com/336725). DCHECK(DownloadServiceFactory::GetForBrowserContext(profile)-> diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 1411716..ff7eabe 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc @@ -447,6 +447,11 @@ Browser::Browser(const CreateParams& params) } Browser::~Browser() { + // Stop observing notifications before continuing with destruction. Profile + // destruction will unload extensions and reentrant calls to Browser:: should + // be avoided while it is being torn down. + registrar_.RemoveAll(); + // The tab strip should not have any tabs at this point. DCHECK(tab_strip_model_->empty()); tab_strip_model_->RemoveObserver(this); |